diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index 1ed453a3..00000000 --- a/.editorconfig +++ /dev/null @@ -1,10 +0,0 @@ -root = true - -[*] -end_of_line = lf -insert_final_newline = true - -[*.{js,json,yml}] -charset = utf-8 -indent_style = space -indent_size = 2 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/.gitignore b/.gitignore deleted file mode 100644 index 44b27430..00000000 --- a/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -node_modules -.yarn diff --git a/.pnp.cjs b/.pnp.cjs deleted file mode 100644 index e5663137..00000000 --- a/.pnp.cjs +++ /dev/null @@ -1,12643 +0,0 @@ -#!/usr/bin/env node -/* eslint-disable */ -"use strict"; - -function $$SETUP_STATE(hydrateRuntimeState, basePath) { - return hydrateRuntimeState(JSON.parse('{\ - "__info": [\ - "This file is automatically generated. Do not touch it, or risk",\ - "your modifications being lost. We also recommend you not to read",\ - "it either without using the @yarnpkg/pnp package, as the data layout",\ - "is entirely unspecified and WILL change from a version to another."\ - ],\ - "dependencyTreeRoots": [\ - {\ - "name": "temml",\ - "reference": "workspace:."\ - }\ - ],\ - "enableTopLevelFallback": true,\ - "ignorePatternData": "(^(?:\\\\.yarn\\\\/sdks(?:\\\\/(?!\\\\.{1,2}(?:\\\\/|$))(?:(?:(?!(?:^|\\\\/)\\\\.{1,2}(?:\\\\/|$)).)*?)|$))$)",\ - "fallbackExclusionList": [\ - ["temml", ["workspace:."]]\ - ],\ - "fallbackPool": [\ - ],\ - "packageRegistryData": [\ - [null, [\ - [null, {\ - "packageLocation": "./",\ - "packageDependencies": [\ - ["eslint", "npm:8.52.0"],\ - ["esm", "npm:3.2.25"],\ - ["rollup", "npm:2.79.1"],\ - ["terser", "npm:5.22.0"]\ - ],\ - "linkType": "SOFT"\ - }]\ - ]],\ - ["@aashutoshrathi/word-wrap", [\ - ["npm:1.2.6", {\ - "packageLocation": "./.yarn/cache/@aashutoshrathi-word-wrap-npm-1.2.6-5b1d95e487-ada901b9e7.zip/node_modules/@aashutoshrathi/word-wrap/",\ - "packageDependencies": [\ - ["@aashutoshrathi/word-wrap", "npm:1.2.6"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["@eslint-community/eslint-utils", [\ - ["npm:4.4.0", {\ - "packageLocation": "./.yarn/cache/@eslint-community-eslint-utils-npm-4.4.0-d1791bd5a3-cdfe3ae42b.zip/node_modules/@eslint-community/eslint-utils/",\ - "packageDependencies": [\ - ["@eslint-community/eslint-utils", "npm:4.4.0"]\ - ],\ - "linkType": "SOFT"\ - }],\ - ["virtual:e7f048a4398cf12bbd1cde95eff45a3327b9fe42e04c31ed99d0e926830d0b78ff78b511118c2bd3bc6add84782ab97a5b001e972071d6fdbfe85a86c150922a#npm:4.4.0", {\ - "packageLocation": "./.yarn/__virtual__/@eslint-community-eslint-utils-virtual-a282c466c0/0/cache/@eslint-community-eslint-utils-npm-4.4.0-d1791bd5a3-cdfe3ae42b.zip/node_modules/@eslint-community/eslint-utils/",\ - "packageDependencies": [\ - ["@eslint-community/eslint-utils", "virtual:e7f048a4398cf12bbd1cde95eff45a3327b9fe42e04c31ed99d0e926830d0b78ff78b511118c2bd3bc6add84782ab97a5b001e972071d6fdbfe85a86c150922a#npm:4.4.0"],\ - ["@types/eslint", null],\ - ["eslint", "npm:8.52.0"],\ - ["eslint-visitor-keys", "npm:3.4.3"]\ - ],\ - "packagePeers": [\ - "@types/eslint",\ - "eslint"\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["@eslint-community/regexpp", [\ - ["npm:4.10.0", {\ - "packageLocation": "./.yarn/cache/@eslint-community-regexpp-npm-4.10.0-6bfb984c81-2a6e345429.zip/node_modules/@eslint-community/regexpp/",\ - "packageDependencies": [\ - ["@eslint-community/regexpp", "npm:4.10.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["@eslint/eslintrc", [\ - ["npm:2.1.2", {\ - "packageLocation": "./.yarn/cache/@eslint-eslintrc-npm-2.1.2-feb0771c9f-bc742a1e3b.zip/node_modules/@eslint/eslintrc/",\ - "packageDependencies": [\ - ["@eslint/eslintrc", "npm:2.1.2"],\ - ["ajv", "npm:6.12.6"],\ - ["debug", "virtual:feb0771c9f8eadaf509cfed41e14a8bebbea5442233275c1c87085111077a08ef71eb773b899665b154d8203a55a489610a54117ae059fce5f5b8b844493b1b1#npm:4.3.4"],\ - ["espree", "npm:9.6.1"],\ - ["globals", "npm:13.23.0"],\ - ["ignore", "npm:5.2.4"],\ - ["import-fresh", "npm:3.3.0"],\ - ["js-yaml", "npm:4.1.0"],\ - ["minimatch", "npm:3.1.2"],\ - ["strip-json-comments", "npm:3.1.1"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["@eslint/js", [\ - ["npm:8.52.0", {\ - "packageLocation": "./.yarn/cache/@eslint-js-npm-8.52.0-801dbdf7b0-490893b809.zip/node_modules/@eslint/js/",\ - "packageDependencies": [\ - ["@eslint/js", "npm:8.52.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["@humanwhocodes/config-array", [\ - ["npm:0.11.13", {\ - "packageLocation": "./.yarn/cache/@humanwhocodes-config-array-npm-0.11.13-12314014f2-f8ea57b0d7.zip/node_modules/@humanwhocodes/config-array/",\ - "packageDependencies": [\ - ["@humanwhocodes/config-array", "npm:0.11.13"],\ - ["@humanwhocodes/object-schema", "npm:2.0.1"],\ - ["debug", "virtual:feb0771c9f8eadaf509cfed41e14a8bebbea5442233275c1c87085111077a08ef71eb773b899665b154d8203a55a489610a54117ae059fce5f5b8b844493b1b1#npm:4.3.4"],\ - ["minimatch", "npm:3.1.2"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["@humanwhocodes/module-importer", [\ - ["npm:1.0.1", {\ - "packageLocation": "./.yarn/cache/@humanwhocodes-module-importer-npm-1.0.1-9d07ed2e4a-0fd22007db.zip/node_modules/@humanwhocodes/module-importer/",\ - "packageDependencies": [\ - ["@humanwhocodes/module-importer", "npm:1.0.1"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["@humanwhocodes/object-schema", [\ - ["npm:2.0.1", {\ - "packageLocation": "./.yarn/cache/@humanwhocodes-object-schema-npm-2.0.1-c23364bbfc-24929487b1.zip/node_modules/@humanwhocodes/object-schema/",\ - "packageDependencies": [\ - ["@humanwhocodes/object-schema", "npm:2.0.1"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["@isaacs/cliui", [\ - ["npm:8.0.2", {\ - "packageLocation": "./.yarn/cache/@isaacs-cliui-npm-8.0.2-f4364666d5-4a473b9b32.zip/node_modules/@isaacs/cliui/",\ - "packageDependencies": [\ - ["@isaacs/cliui", "npm:8.0.2"],\ - ["string-width", "npm:5.1.2"],\ - ["string-width-cjs", [\ - "string-width",\ - "npm:4.2.3"\ - ]],\ - ["strip-ansi", "npm:7.1.0"],\ - ["strip-ansi-cjs", [\ - "strip-ansi",\ - "npm:6.0.1"\ - ]],\ - ["wrap-ansi", "npm:8.1.0"],\ - ["wrap-ansi-cjs", [\ - "wrap-ansi",\ - "npm:7.0.0"\ - ]]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["@jridgewell/gen-mapping", [\ - ["npm:0.3.3", {\ - "packageLocation": "./.yarn/cache/@jridgewell-gen-mapping-npm-0.3.3-1815eba94c-4a74944bd3.zip/node_modules/@jridgewell/gen-mapping/",\ - "packageDependencies": [\ - ["@jridgewell/gen-mapping", "npm:0.3.3"],\ - ["@jridgewell/set-array", "npm:1.1.2"],\ - ["@jridgewell/sourcemap-codec", "npm:1.4.15"],\ - ["@jridgewell/trace-mapping", "npm:0.3.20"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["@jridgewell/resolve-uri", [\ - ["npm:3.1.1", {\ - "packageLocation": "./.yarn/cache/@jridgewell-resolve-uri-npm-3.1.1-aa2de3f210-f5b441fe79.zip/node_modules/@jridgewell/resolve-uri/",\ - "packageDependencies": [\ - ["@jridgewell/resolve-uri", "npm:3.1.1"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["@jridgewell/set-array", [\ - ["npm:1.1.2", {\ - "packageLocation": "./.yarn/cache/@jridgewell-set-array-npm-1.1.2-45b82d7fb6-69a84d5980.zip/node_modules/@jridgewell/set-array/",\ - "packageDependencies": [\ - ["@jridgewell/set-array", "npm:1.1.2"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["@jridgewell/source-map", [\ - ["npm:0.3.5", {\ - "packageLocation": "./.yarn/cache/@jridgewell-source-map-npm-0.3.5-9f964eaf44-1ad4dec0bd.zip/node_modules/@jridgewell/source-map/",\ - "packageDependencies": [\ - ["@jridgewell/source-map", "npm:0.3.5"],\ - ["@jridgewell/gen-mapping", "npm:0.3.3"],\ - ["@jridgewell/trace-mapping", "npm:0.3.20"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["@jridgewell/sourcemap-codec", [\ - ["npm:1.4.15", {\ - "packageLocation": "./.yarn/cache/@jridgewell-sourcemap-codec-npm-1.4.15-a055fb62cf-b881c7e503.zip/node_modules/@jridgewell/sourcemap-codec/",\ - "packageDependencies": [\ - ["@jridgewell/sourcemap-codec", "npm:1.4.15"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["@jridgewell/trace-mapping", [\ - ["npm:0.3.20", {\ - "packageLocation": "./.yarn/cache/@jridgewell-trace-mapping-npm-0.3.20-d90f282910-cd1a735313.zip/node_modules/@jridgewell/trace-mapping/",\ - "packageDependencies": [\ - ["@jridgewell/trace-mapping", "npm:0.3.20"],\ - ["@jridgewell/resolve-uri", "npm:3.1.1"],\ - ["@jridgewell/sourcemap-codec", "npm:1.4.15"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["@nodelib/fs.scandir", [\ - ["npm:2.1.5", {\ - "packageLocation": "./.yarn/cache/@nodelib-fs.scandir-npm-2.1.5-89c67370dd-a970d595bd.zip/node_modules/@nodelib/fs.scandir/",\ - "packageDependencies": [\ - ["@nodelib/fs.scandir", "npm:2.1.5"],\ - ["@nodelib/fs.stat", "npm:2.0.5"],\ - ["run-parallel", "npm:1.2.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["@nodelib/fs.stat", [\ - ["npm:2.0.5", {\ - "packageLocation": "./.yarn/cache/@nodelib-fs.stat-npm-2.0.5-01f4dd3030-012480b5ca.zip/node_modules/@nodelib/fs.stat/",\ - "packageDependencies": [\ - ["@nodelib/fs.stat", "npm:2.0.5"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["@nodelib/fs.walk", [\ - ["npm:1.2.8", {\ - "packageLocation": "./.yarn/cache/@nodelib-fs.walk-npm-1.2.8-b4a89da548-190c643f15.zip/node_modules/@nodelib/fs.walk/",\ - "packageDependencies": [\ - ["@nodelib/fs.walk", "npm:1.2.8"],\ - ["@nodelib/fs.scandir", "npm:2.1.5"],\ - ["fastq", "npm:1.15.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["@npmcli/fs", [\ - ["npm:3.1.0", {\ - "packageLocation": "./.yarn/cache/@npmcli-fs-npm-3.1.0-0844a57978-a50a6818de.zip/node_modules/@npmcli/fs/",\ - "packageDependencies": [\ - ["@npmcli/fs", "npm:3.1.0"],\ - ["semver", "npm:7.5.4"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["@pkgjs/parseargs", [\ - ["npm:0.11.0", {\ - "packageLocation": "./.yarn/cache/@pkgjs-parseargs-npm-0.11.0-cd2a3fe948-6ad6a00fc4.zip/node_modules/@pkgjs/parseargs/",\ - "packageDependencies": [\ - ["@pkgjs/parseargs", "npm:0.11.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["@tootallnate/once", [\ - ["npm:2.0.0", {\ - "packageLocation": "./.yarn/cache/@tootallnate-once-npm-2.0.0-e36cf4f140-ad87447820.zip/node_modules/@tootallnate/once/",\ - "packageDependencies": [\ - ["@tootallnate/once", "npm:2.0.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["@ungap/structured-clone", [\ - ["npm:1.2.0", {\ - "packageLocation": "./.yarn/cache/@ungap-structured-clone-npm-1.2.0-648f0b82e0-4f656b7b46.zip/node_modules/@ungap/structured-clone/",\ - "packageDependencies": [\ - ["@ungap/structured-clone", "npm:1.2.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["abbrev", [\ - ["npm:1.1.1", {\ - "packageLocation": "./.yarn/cache/abbrev-npm-1.1.1-3659247eab-a4a97ec07d.zip/node_modules/abbrev/",\ - "packageDependencies": [\ - ["abbrev", "npm:1.1.1"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["acorn", [\ - ["npm:8.10.0", {\ - "packageLocation": "./.yarn/cache/acorn-npm-8.10.0-2230c9e83e-538ba38af0.zip/node_modules/acorn/",\ - "packageDependencies": [\ - ["acorn", "npm:8.10.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["acorn-jsx", [\ - ["npm:5.3.2", {\ - "packageLocation": "./.yarn/cache/acorn-jsx-npm-5.3.2-d7594599ea-c3d3b2a89c.zip/node_modules/acorn-jsx/",\ - "packageDependencies": [\ - ["acorn-jsx", "npm:5.3.2"]\ - ],\ - "linkType": "SOFT"\ - }],\ - ["virtual:a50722a5a9326b6a5f12350c494c4db3aa0f4caeac45e3e9e5fe071da20014ecfe738fe2ebe2c9c98abae81a4ea86b42f56d776b3bd5ec37f9ad3670c242b242#npm:5.3.2", {\ - "packageLocation": "./.yarn/__virtual__/acorn-jsx-virtual-834321b202/0/cache/acorn-jsx-npm-5.3.2-d7594599ea-c3d3b2a89c.zip/node_modules/acorn-jsx/",\ - "packageDependencies": [\ - ["acorn-jsx", "virtual:a50722a5a9326b6a5f12350c494c4db3aa0f4caeac45e3e9e5fe071da20014ecfe738fe2ebe2c9c98abae81a4ea86b42f56d776b3bd5ec37f9ad3670c242b242#npm:5.3.2"],\ - ["@types/acorn", null],\ - ["acorn", "npm:8.10.0"]\ - ],\ - "packagePeers": [\ - "@types/acorn",\ - "acorn"\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["agent-base", [\ - ["npm:6.0.2", {\ - "packageLocation": "./.yarn/cache/agent-base-npm-6.0.2-428f325a93-f52b6872cc.zip/node_modules/agent-base/",\ - "packageDependencies": [\ - ["agent-base", "npm:6.0.2"],\ - ["debug", "virtual:feb0771c9f8eadaf509cfed41e14a8bebbea5442233275c1c87085111077a08ef71eb773b899665b154d8203a55a489610a54117ae059fce5f5b8b844493b1b1#npm:4.3.4"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["agentkeepalive", [\ - ["npm:4.5.0", {\ - "packageLocation": "./.yarn/cache/agentkeepalive-npm-4.5.0-f237b580b2-13278cd5b1.zip/node_modules/agentkeepalive/",\ - "packageDependencies": [\ - ["agentkeepalive", "npm:4.5.0"],\ - ["humanize-ms", "npm:1.2.1"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["aggregate-error", [\ - ["npm:3.1.0", {\ - "packageLocation": "./.yarn/cache/aggregate-error-npm-3.1.0-415a406f4e-1101a33f21.zip/node_modules/aggregate-error/",\ - "packageDependencies": [\ - ["aggregate-error", "npm:3.1.0"],\ - ["clean-stack", "npm:2.2.0"],\ - ["indent-string", "npm:4.0.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["ajv", [\ - ["npm:6.12.6", {\ - "packageLocation": "./.yarn/cache/ajv-npm-6.12.6-4b5105e2b2-874972efe5.zip/node_modules/ajv/",\ - "packageDependencies": [\ - ["ajv", "npm:6.12.6"],\ - ["fast-deep-equal", "npm:3.1.3"],\ - ["fast-json-stable-stringify", "npm:2.1.0"],\ - ["json-schema-traverse", "npm:0.4.1"],\ - ["uri-js", "npm:4.4.1"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["ansi-regex", [\ - ["npm:5.0.1", {\ - "packageLocation": "./.yarn/cache/ansi-regex-npm-5.0.1-c963a48615-2aa4bb54ca.zip/node_modules/ansi-regex/",\ - "packageDependencies": [\ - ["ansi-regex", "npm:5.0.1"]\ - ],\ - "linkType": "HARD"\ - }],\ - ["npm:6.0.1", {\ - "packageLocation": "./.yarn/cache/ansi-regex-npm-6.0.1-8d663a607d-1ff8b7667c.zip/node_modules/ansi-regex/",\ - "packageDependencies": [\ - ["ansi-regex", "npm:6.0.1"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["ansi-styles", [\ - ["npm:4.3.0", {\ - "packageLocation": "./.yarn/cache/ansi-styles-npm-4.3.0-245c7d42c7-513b44c3b2.zip/node_modules/ansi-styles/",\ - "packageDependencies": [\ - ["ansi-styles", "npm:4.3.0"],\ - ["color-convert", "npm:2.0.1"]\ - ],\ - "linkType": "HARD"\ - }],\ - ["npm:6.2.1", {\ - "packageLocation": "./.yarn/cache/ansi-styles-npm-6.2.1-d43647018c-ef940f2f0c.zip/node_modules/ansi-styles/",\ - "packageDependencies": [\ - ["ansi-styles", "npm:6.2.1"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["aproba", [\ - ["npm:2.0.0", {\ - "packageLocation": "./.yarn/cache/aproba-npm-2.0.0-8716bcfde6-5615cadcfb.zip/node_modules/aproba/",\ - "packageDependencies": [\ - ["aproba", "npm:2.0.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["are-we-there-yet", [\ - ["npm:3.0.1", {\ - "packageLocation": "./.yarn/cache/are-we-there-yet-npm-3.0.1-3395b1512f-52590c2486.zip/node_modules/are-we-there-yet/",\ - "packageDependencies": [\ - ["are-we-there-yet", "npm:3.0.1"],\ - ["delegates", "npm:1.0.0"],\ - ["readable-stream", "npm:3.6.2"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["argparse", [\ - ["npm:2.0.1", {\ - "packageLocation": "./.yarn/cache/argparse-npm-2.0.1-faff7999e6-83644b5649.zip/node_modules/argparse/",\ - "packageDependencies": [\ - ["argparse", "npm:2.0.1"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["balanced-match", [\ - ["npm:1.0.2", {\ - "packageLocation": "./.yarn/cache/balanced-match-npm-1.0.2-a53c126459-9706c088a2.zip/node_modules/balanced-match/",\ - "packageDependencies": [\ - ["balanced-match", "npm:1.0.2"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["brace-expansion", [\ - ["npm:1.1.11", {\ - "packageLocation": "./.yarn/cache/brace-expansion-npm-1.1.11-fb95eb05ad-faf34a7bb0.zip/node_modules/brace-expansion/",\ - "packageDependencies": [\ - ["brace-expansion", "npm:1.1.11"],\ - ["balanced-match", "npm:1.0.2"],\ - ["concat-map", "npm:0.0.1"]\ - ],\ - "linkType": "HARD"\ - }],\ - ["npm:2.0.1", {\ - "packageLocation": "./.yarn/cache/brace-expansion-npm-2.0.1-17aa2616f9-a61e7cd2e8.zip/node_modules/brace-expansion/",\ - "packageDependencies": [\ - ["brace-expansion", "npm:2.0.1"],\ - ["balanced-match", "npm:1.0.2"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["buffer-from", [\ - ["npm:1.1.2", {\ - "packageLocation": "./.yarn/cache/buffer-from-npm-1.1.2-03d2f20d7e-0448524a56.zip/node_modules/buffer-from/",\ - "packageDependencies": [\ - ["buffer-from", "npm:1.1.2"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["cacache", [\ - ["npm:17.1.4", {\ - "packageLocation": "./.yarn/cache/cacache-npm-17.1.4-51ef53d0a8-b7751df756.zip/node_modules/cacache/",\ - "packageDependencies": [\ - ["cacache", "npm:17.1.4"],\ - ["@npmcli/fs", "npm:3.1.0"],\ - ["fs-minipass", "npm:3.0.3"],\ - ["glob", "npm:10.3.10"],\ - ["lru-cache", "npm:7.18.3"],\ - ["minipass", "npm:7.0.4"],\ - ["minipass-collect", "npm:1.0.2"],\ - ["minipass-flush", "npm:1.0.5"],\ - ["minipass-pipeline", "npm:1.2.4"],\ - ["p-map", "npm:4.0.0"],\ - ["ssri", "npm:10.0.5"],\ - ["tar", "npm:6.2.0"],\ - ["unique-filename", "npm:3.0.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["callsites", [\ - ["npm:3.1.0", {\ - "packageLocation": "./.yarn/cache/callsites-npm-3.1.0-268f989910-072d17b6ab.zip/node_modules/callsites/",\ - "packageDependencies": [\ - ["callsites", "npm:3.1.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["chalk", [\ - ["npm:4.1.2", {\ - "packageLocation": "./.yarn/cache/chalk-npm-4.1.2-ba8b67ab80-fe75c9d5c7.zip/node_modules/chalk/",\ - "packageDependencies": [\ - ["chalk", "npm:4.1.2"],\ - ["ansi-styles", "npm:4.3.0"],\ - ["supports-color", "npm:7.2.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["chownr", [\ - ["npm:2.0.0", {\ - "packageLocation": "./.yarn/cache/chownr-npm-2.0.0-638f1c9c61-c57cf9dd07.zip/node_modules/chownr/",\ - "packageDependencies": [\ - ["chownr", "npm:2.0.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["clean-stack", [\ - ["npm:2.2.0", {\ - "packageLocation": "./.yarn/cache/clean-stack-npm-2.2.0-a8ce435a5c-2ac8cd2b2f.zip/node_modules/clean-stack/",\ - "packageDependencies": [\ - ["clean-stack", "npm:2.2.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["color-convert", [\ - ["npm:2.0.1", {\ - "packageLocation": "./.yarn/cache/color-convert-npm-2.0.1-79730e935b-79e6bdb9fd.zip/node_modules/color-convert/",\ - "packageDependencies": [\ - ["color-convert", "npm:2.0.1"],\ - ["color-name", "npm:1.1.4"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["color-name", [\ - ["npm:1.1.4", {\ - "packageLocation": "./.yarn/cache/color-name-npm-1.1.4-025792b0ea-b044585952.zip/node_modules/color-name/",\ - "packageDependencies": [\ - ["color-name", "npm:1.1.4"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["color-support", [\ - ["npm:1.1.3", {\ - "packageLocation": "./.yarn/cache/color-support-npm-1.1.3-3be5c53455-9b73568176.zip/node_modules/color-support/",\ - "packageDependencies": [\ - ["color-support", "npm:1.1.3"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["commander", [\ - ["npm:2.20.3", {\ - "packageLocation": "./.yarn/cache/commander-npm-2.20.3-d8dcbaa39b-ab8c07884e.zip/node_modules/commander/",\ - "packageDependencies": [\ - ["commander", "npm:2.20.3"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["concat-map", [\ - ["npm:0.0.1", {\ - "packageLocation": "./.yarn/cache/concat-map-npm-0.0.1-85a921b7ee-902a9f5d89.zip/node_modules/concat-map/",\ - "packageDependencies": [\ - ["concat-map", "npm:0.0.1"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["console-control-strings", [\ - ["npm:1.1.0", {\ - "packageLocation": "./.yarn/cache/console-control-strings-npm-1.1.0-e3160e5275-8755d76787.zip/node_modules/console-control-strings/",\ - "packageDependencies": [\ - ["console-control-strings", "npm:1.1.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["cross-spawn", [\ - ["npm:7.0.3", {\ - "packageLocation": "./.yarn/cache/cross-spawn-npm-7.0.3-e4ff3e65b3-671cc7c728.zip/node_modules/cross-spawn/",\ - "packageDependencies": [\ - ["cross-spawn", "npm:7.0.3"],\ - ["path-key", "npm:3.1.1"],\ - ["shebang-command", "npm:2.0.0"],\ - ["which", "npm:2.0.2"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["debug", [\ - ["npm:4.3.4", {\ - "packageLocation": "./.yarn/cache/debug-npm-4.3.4-4513954577-3dbad3f94e.zip/node_modules/debug/",\ - "packageDependencies": [\ - ["debug", "npm:4.3.4"]\ - ],\ - "linkType": "SOFT"\ - }],\ - ["virtual:feb0771c9f8eadaf509cfed41e14a8bebbea5442233275c1c87085111077a08ef71eb773b899665b154d8203a55a489610a54117ae059fce5f5b8b844493b1b1#npm:4.3.4", {\ - "packageLocation": "./.yarn/__virtual__/debug-virtual-954df360d3/0/cache/debug-npm-4.3.4-4513954577-3dbad3f94e.zip/node_modules/debug/",\ - "packageDependencies": [\ - ["debug", "virtual:feb0771c9f8eadaf509cfed41e14a8bebbea5442233275c1c87085111077a08ef71eb773b899665b154d8203a55a489610a54117ae059fce5f5b8b844493b1b1#npm:4.3.4"],\ - ["@types/supports-color", null],\ - ["ms", "npm:2.1.2"],\ - ["supports-color", null]\ - ],\ - "packagePeers": [\ - "@types/supports-color",\ - "supports-color"\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["deep-is", [\ - ["npm:0.1.4", {\ - "packageLocation": "./.yarn/cache/deep-is-npm-0.1.4-88938b5a67-edb65dd0d7.zip/node_modules/deep-is/",\ - "packageDependencies": [\ - ["deep-is", "npm:0.1.4"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["delegates", [\ - ["npm:1.0.0", {\ - "packageLocation": "./.yarn/cache/delegates-npm-1.0.0-9b1942d75f-a51744d9b5.zip/node_modules/delegates/",\ - "packageDependencies": [\ - ["delegates", "npm:1.0.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["doctrine", [\ - ["npm:3.0.0", {\ - "packageLocation": "./.yarn/cache/doctrine-npm-3.0.0-c6f1615f04-fd7673ca77.zip/node_modules/doctrine/",\ - "packageDependencies": [\ - ["doctrine", "npm:3.0.0"],\ - ["esutils", "npm:2.0.3"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["eastasianwidth", [\ - ["npm:0.2.0", {\ - "packageLocation": "./.yarn/cache/eastasianwidth-npm-0.2.0-c37eb16bd1-7d00d7cd8e.zip/node_modules/eastasianwidth/",\ - "packageDependencies": [\ - ["eastasianwidth", "npm:0.2.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["emoji-regex", [\ - ["npm:8.0.0", {\ - "packageLocation": "./.yarn/cache/emoji-regex-npm-8.0.0-213764015c-d4c5c39d5a.zip/node_modules/emoji-regex/",\ - "packageDependencies": [\ - ["emoji-regex", "npm:8.0.0"]\ - ],\ - "linkType": "HARD"\ - }],\ - ["npm:9.2.2", {\ - "packageLocation": "./.yarn/cache/emoji-regex-npm-9.2.2-e6fac8d058-8487182da7.zip/node_modules/emoji-regex/",\ - "packageDependencies": [\ - ["emoji-regex", "npm:9.2.2"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["encoding", [\ - ["npm:0.1.13", {\ - "packageLocation": "./.yarn/cache/encoding-npm-0.1.13-82a1837d30-bb98632f8f.zip/node_modules/encoding/",\ - "packageDependencies": [\ - ["encoding", "npm:0.1.13"],\ - ["iconv-lite", "npm:0.6.3"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["env-paths", [\ - ["npm:2.2.1", {\ - "packageLocation": "./.yarn/cache/env-paths-npm-2.2.1-7c7577428c-65b5df55a8.zip/node_modules/env-paths/",\ - "packageDependencies": [\ - ["env-paths", "npm:2.2.1"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["err-code", [\ - ["npm:2.0.3", {\ - "packageLocation": "./.yarn/cache/err-code-npm-2.0.3-082e0ff9a7-8b7b1be20d.zip/node_modules/err-code/",\ - "packageDependencies": [\ - ["err-code", "npm:2.0.3"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["escape-string-regexp", [\ - ["npm:4.0.0", {\ - "packageLocation": "./.yarn/cache/escape-string-regexp-npm-4.0.0-4b531d8d59-98b48897d9.zip/node_modules/escape-string-regexp/",\ - "packageDependencies": [\ - ["escape-string-regexp", "npm:4.0.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["eslint", [\ - ["npm:8.52.0", {\ - "packageLocation": "./.yarn/cache/eslint-npm-8.52.0-e7f048a439-fd22d1e9bd.zip/node_modules/eslint/",\ - "packageDependencies": [\ - ["eslint", "npm:8.52.0"],\ - ["@eslint-community/eslint-utils", "virtual:e7f048a4398cf12bbd1cde95eff45a3327b9fe42e04c31ed99d0e926830d0b78ff78b511118c2bd3bc6add84782ab97a5b001e972071d6fdbfe85a86c150922a#npm:4.4.0"],\ - ["@eslint-community/regexpp", "npm:4.10.0"],\ - ["@eslint/eslintrc", "npm:2.1.2"],\ - ["@eslint/js", "npm:8.52.0"],\ - ["@humanwhocodes/config-array", "npm:0.11.13"],\ - ["@humanwhocodes/module-importer", "npm:1.0.1"],\ - ["@nodelib/fs.walk", "npm:1.2.8"],\ - ["@ungap/structured-clone", "npm:1.2.0"],\ - ["ajv", "npm:6.12.6"],\ - ["chalk", "npm:4.1.2"],\ - ["cross-spawn", "npm:7.0.3"],\ - ["debug", "virtual:feb0771c9f8eadaf509cfed41e14a8bebbea5442233275c1c87085111077a08ef71eb773b899665b154d8203a55a489610a54117ae059fce5f5b8b844493b1b1#npm:4.3.4"],\ - ["doctrine", "npm:3.0.0"],\ - ["escape-string-regexp", "npm:4.0.0"],\ - ["eslint-scope", "npm:7.2.2"],\ - ["eslint-visitor-keys", "npm:3.4.3"],\ - ["espree", "npm:9.6.1"],\ - ["esquery", "npm:1.5.0"],\ - ["esutils", "npm:2.0.3"],\ - ["fast-deep-equal", "npm:3.1.3"],\ - ["file-entry-cache", "npm:6.0.1"],\ - ["find-up", "npm:5.0.0"],\ - ["glob-parent", "npm:6.0.2"],\ - ["globals", "npm:13.23.0"],\ - ["graphemer", "npm:1.4.0"],\ - ["ignore", "npm:5.2.4"],\ - ["imurmurhash", "npm:0.1.4"],\ - ["is-glob", "npm:4.0.3"],\ - ["is-path-inside", "npm:3.0.3"],\ - ["js-yaml", "npm:4.1.0"],\ - ["json-stable-stringify-without-jsonify", "npm:1.0.1"],\ - ["levn", "npm:0.4.1"],\ - ["lodash.merge", "npm:4.6.2"],\ - ["minimatch", "npm:3.1.2"],\ - ["natural-compare", "npm:1.4.0"],\ - ["optionator", "npm:0.9.3"],\ - ["strip-ansi", "npm:6.0.1"],\ - ["text-table", "npm:0.2.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["eslint-scope", [\ - ["npm:7.2.2", {\ - "packageLocation": "./.yarn/cache/eslint-scope-npm-7.2.2-53cb0df8e8-ec97dbf5fb.zip/node_modules/eslint-scope/",\ - "packageDependencies": [\ - ["eslint-scope", "npm:7.2.2"],\ - ["esrecurse", "npm:4.3.0"],\ - ["estraverse", "npm:5.3.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["eslint-visitor-keys", [\ - ["npm:3.4.3", {\ - "packageLocation": "./.yarn/cache/eslint-visitor-keys-npm-3.4.3-a356ac7e46-36e9ef87fc.zip/node_modules/eslint-visitor-keys/",\ - "packageDependencies": [\ - ["eslint-visitor-keys", "npm:3.4.3"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["esm", [\ - ["npm:3.2.25", {\ - "packageLocation": "./.yarn/cache/esm-npm-3.2.25-762b3ebd40-978aabe2de.zip/node_modules/esm/",\ - "packageDependencies": [\ - ["esm", "npm:3.2.25"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["espree", [\ - ["npm:9.6.1", {\ - "packageLocation": "./.yarn/cache/espree-npm-9.6.1-a50722a5a9-eb8c149c7a.zip/node_modules/espree/",\ - "packageDependencies": [\ - ["espree", "npm:9.6.1"],\ - ["acorn", "npm:8.10.0"],\ - ["acorn-jsx", "virtual:a50722a5a9326b6a5f12350c494c4db3aa0f4caeac45e3e9e5fe071da20014ecfe738fe2ebe2c9c98abae81a4ea86b42f56d776b3bd5ec37f9ad3670c242b242#npm:5.3.2"],\ - ["eslint-visitor-keys", "npm:3.4.3"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["esquery", [\ - ["npm:1.5.0", {\ - "packageLocation": "./.yarn/cache/esquery-npm-1.5.0-d8f8a06879-aefb0d2596.zip/node_modules/esquery/",\ - "packageDependencies": [\ - ["esquery", "npm:1.5.0"],\ - ["estraverse", "npm:5.3.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["esrecurse", [\ - ["npm:4.3.0", {\ - "packageLocation": "./.yarn/cache/esrecurse-npm-4.3.0-10b86a887a-ebc17b1a33.zip/node_modules/esrecurse/",\ - "packageDependencies": [\ - ["esrecurse", "npm:4.3.0"],\ - ["estraverse", "npm:5.3.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["estraverse", [\ - ["npm:5.3.0", {\ - "packageLocation": "./.yarn/cache/estraverse-npm-5.3.0-03284f8f63-072780882d.zip/node_modules/estraverse/",\ - "packageDependencies": [\ - ["estraverse", "npm:5.3.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["esutils", [\ - ["npm:2.0.3", {\ - "packageLocation": "./.yarn/cache/esutils-npm-2.0.3-f865beafd5-22b5b08f74.zip/node_modules/esutils/",\ - "packageDependencies": [\ - ["esutils", "npm:2.0.3"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["exponential-backoff", [\ - ["npm:3.1.1", {\ - "packageLocation": "./.yarn/cache/exponential-backoff-npm-3.1.1-04df458b30-3d21519a4f.zip/node_modules/exponential-backoff/",\ - "packageDependencies": [\ - ["exponential-backoff", "npm:3.1.1"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["fast-deep-equal", [\ - ["npm:3.1.3", {\ - "packageLocation": "./.yarn/cache/fast-deep-equal-npm-3.1.3-790edcfcf5-e21a9d8d84.zip/node_modules/fast-deep-equal/",\ - "packageDependencies": [\ - ["fast-deep-equal", "npm:3.1.3"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["fast-json-stable-stringify", [\ - ["npm:2.1.0", {\ - "packageLocation": "./.yarn/cache/fast-json-stable-stringify-npm-2.1.0-02e8905fda-b191531e36.zip/node_modules/fast-json-stable-stringify/",\ - "packageDependencies": [\ - ["fast-json-stable-stringify", "npm:2.1.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["fast-levenshtein", [\ - ["npm:2.0.6", {\ - "packageLocation": "./.yarn/cache/fast-levenshtein-npm-2.0.6-fcd74b8df5-92cfec0a8d.zip/node_modules/fast-levenshtein/",\ - "packageDependencies": [\ - ["fast-levenshtein", "npm:2.0.6"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["fastq", [\ - ["npm:1.15.0", {\ - "packageLocation": "./.yarn/cache/fastq-npm-1.15.0-1013f6514e-0170e6bfcd.zip/node_modules/fastq/",\ - "packageDependencies": [\ - ["fastq", "npm:1.15.0"],\ - ["reusify", "npm:1.0.4"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["file-entry-cache", [\ - ["npm:6.0.1", {\ - "packageLocation": "./.yarn/cache/file-entry-cache-npm-6.0.1-31965cf0af-f49701feaa.zip/node_modules/file-entry-cache/",\ - "packageDependencies": [\ - ["file-entry-cache", "npm:6.0.1"],\ - ["flat-cache", "npm:3.1.1"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["find-up", [\ - ["npm:5.0.0", {\ - "packageLocation": "./.yarn/cache/find-up-npm-5.0.0-e03e9b796d-07955e3573.zip/node_modules/find-up/",\ - "packageDependencies": [\ - ["find-up", "npm:5.0.0"],\ - ["locate-path", "npm:6.0.0"],\ - ["path-exists", "npm:4.0.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["flat-cache", [\ - ["npm:3.1.1", {\ - "packageLocation": "./.yarn/cache/flat-cache-npm-3.1.1-b79e22b54f-4958cfe0f4.zip/node_modules/flat-cache/",\ - "packageDependencies": [\ - ["flat-cache", "npm:3.1.1"],\ - ["flatted", "npm:3.2.9"],\ - ["keyv", "npm:4.5.4"],\ - ["rimraf", "npm:3.0.2"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["flatted", [\ - ["npm:3.2.9", {\ - "packageLocation": "./.yarn/cache/flatted-npm-3.2.9-0462256d3c-f14167fbe2.zip/node_modules/flatted/",\ - "packageDependencies": [\ - ["flatted", "npm:3.2.9"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["foreground-child", [\ - ["npm:3.1.1", {\ - "packageLocation": "./.yarn/cache/foreground-child-npm-3.1.1-77e78ed774-139d270bc8.zip/node_modules/foreground-child/",\ - "packageDependencies": [\ - ["foreground-child", "npm:3.1.1"],\ - ["cross-spawn", "npm:7.0.3"],\ - ["signal-exit", "npm:4.1.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["fs-minipass", [\ - ["npm:2.1.0", {\ - "packageLocation": "./.yarn/cache/fs-minipass-npm-2.1.0-501ef87306-1b8d128dae.zip/node_modules/fs-minipass/",\ - "packageDependencies": [\ - ["fs-minipass", "npm:2.1.0"],\ - ["minipass", "npm:3.3.6"]\ - ],\ - "linkType": "HARD"\ - }],\ - ["npm:3.0.3", {\ - "packageLocation": "./.yarn/cache/fs-minipass-npm-3.0.3-d148d6ac19-8722a41109.zip/node_modules/fs-minipass/",\ - "packageDependencies": [\ - ["fs-minipass", "npm:3.0.3"],\ - ["minipass", "npm:7.0.4"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["fs.realpath", [\ - ["npm:1.0.0", {\ - "packageLocation": "./.yarn/cache/fs.realpath-npm-1.0.0-c8f05d8126-99ddea01a7.zip/node_modules/fs.realpath/",\ - "packageDependencies": [\ - ["fs.realpath", "npm:1.0.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["fsevents", [\ - ["patch:fsevents@npm%3A2.3.3#~builtin::version=2.3.3&hash=df0bf1", {\ - "packageLocation": "./.yarn/unplugged/fsevents-patch-21ad2b1333/node_modules/fsevents/",\ - "packageDependencies": [\ - ["fsevents", "patch:fsevents@npm%3A2.3.3#~builtin::version=2.3.3&hash=df0bf1"],\ - ["node-gyp", "npm:9.4.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["gauge", [\ - ["npm:4.0.4", {\ - "packageLocation": "./.yarn/cache/gauge-npm-4.0.4-8f878385e9-788b6bfe52.zip/node_modules/gauge/",\ - "packageDependencies": [\ - ["gauge", "npm:4.0.4"],\ - ["aproba", "npm:2.0.0"],\ - ["color-support", "npm:1.1.3"],\ - ["console-control-strings", "npm:1.1.0"],\ - ["has-unicode", "npm:2.0.1"],\ - ["signal-exit", "npm:3.0.7"],\ - ["string-width", "npm:4.2.3"],\ - ["strip-ansi", "npm:6.0.1"],\ - ["wide-align", "npm:1.1.5"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["glob", [\ - ["npm:10.3.10", {\ - "packageLocation": "./.yarn/cache/glob-npm-10.3.10-da1ef8b112-4f2fe2511e.zip/node_modules/glob/",\ - "packageDependencies": [\ - ["glob", "npm:10.3.10"],\ - ["foreground-child", "npm:3.1.1"],\ - ["jackspeak", "npm:2.3.6"],\ - ["minimatch", "npm:9.0.3"],\ - ["minipass", "npm:7.0.4"],\ - ["path-scurry", "npm:1.10.1"]\ - ],\ - "linkType": "HARD"\ - }],\ - ["npm:7.2.3", {\ - "packageLocation": "./.yarn/cache/glob-npm-7.2.3-2d866d17a5-29452e97b3.zip/node_modules/glob/",\ - "packageDependencies": [\ - ["glob", "npm:7.2.3"],\ - ["fs.realpath", "npm:1.0.0"],\ - ["inflight", "npm:1.0.6"],\ - ["inherits", "npm:2.0.4"],\ - ["minimatch", "npm:3.1.2"],\ - ["once", "npm:1.4.0"],\ - ["path-is-absolute", "npm:1.0.1"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["glob-parent", [\ - ["npm:6.0.2", {\ - "packageLocation": "./.yarn/cache/glob-parent-npm-6.0.2-2cbef12738-c13ee97978.zip/node_modules/glob-parent/",\ - "packageDependencies": [\ - ["glob-parent", "npm:6.0.2"],\ - ["is-glob", "npm:4.0.3"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["globals", [\ - ["npm:13.23.0", {\ - "packageLocation": "./.yarn/cache/globals-npm-13.23.0-7f02426fd5-194c97cf8d.zip/node_modules/globals/",\ - "packageDependencies": [\ - ["globals", "npm:13.23.0"],\ - ["type-fest", "npm:0.20.2"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["graceful-fs", [\ - ["npm:4.2.11", {\ - "packageLocation": "./.yarn/cache/graceful-fs-npm-4.2.11-24bb648a68-ac85f94da9.zip/node_modules/graceful-fs/",\ - "packageDependencies": [\ - ["graceful-fs", "npm:4.2.11"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["graphemer", [\ - ["npm:1.4.0", {\ - "packageLocation": "./.yarn/cache/graphemer-npm-1.4.0-0627732d35-bab8f0be9b.zip/node_modules/graphemer/",\ - "packageDependencies": [\ - ["graphemer", "npm:1.4.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["has-flag", [\ - ["npm:4.0.0", {\ - "packageLocation": "./.yarn/cache/has-flag-npm-4.0.0-32af9f0536-261a135703.zip/node_modules/has-flag/",\ - "packageDependencies": [\ - ["has-flag", "npm:4.0.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["has-unicode", [\ - ["npm:2.0.1", {\ - "packageLocation": "./.yarn/cache/has-unicode-npm-2.0.1-893adb4747-1eab07a743.zip/node_modules/has-unicode/",\ - "packageDependencies": [\ - ["has-unicode", "npm:2.0.1"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["http-cache-semantics", [\ - ["npm:4.1.1", {\ - "packageLocation": "./.yarn/cache/http-cache-semantics-npm-4.1.1-1120131375-83ac0bc60b.zip/node_modules/http-cache-semantics/",\ - "packageDependencies": [\ - ["http-cache-semantics", "npm:4.1.1"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["http-proxy-agent", [\ - ["npm:5.0.0", {\ - "packageLocation": "./.yarn/cache/http-proxy-agent-npm-5.0.0-7f1f121b83-e2ee1ff165.zip/node_modules/http-proxy-agent/",\ - "packageDependencies": [\ - ["http-proxy-agent", "npm:5.0.0"],\ - ["@tootallnate/once", "npm:2.0.0"],\ - ["agent-base", "npm:6.0.2"],\ - ["debug", "virtual:feb0771c9f8eadaf509cfed41e14a8bebbea5442233275c1c87085111077a08ef71eb773b899665b154d8203a55a489610a54117ae059fce5f5b8b844493b1b1#npm:4.3.4"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["https-proxy-agent", [\ - ["npm:5.0.1", {\ - "packageLocation": "./.yarn/cache/https-proxy-agent-npm-5.0.1-42d65f358e-571fccdf38.zip/node_modules/https-proxy-agent/",\ - "packageDependencies": [\ - ["https-proxy-agent", "npm:5.0.1"],\ - ["agent-base", "npm:6.0.2"],\ - ["debug", "virtual:feb0771c9f8eadaf509cfed41e14a8bebbea5442233275c1c87085111077a08ef71eb773b899665b154d8203a55a489610a54117ae059fce5f5b8b844493b1b1#npm:4.3.4"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["humanize-ms", [\ - ["npm:1.2.1", {\ - "packageLocation": "./.yarn/cache/humanize-ms-npm-1.2.1-e942bd7329-9c7a74a282.zip/node_modules/humanize-ms/",\ - "packageDependencies": [\ - ["humanize-ms", "npm:1.2.1"],\ - ["ms", "npm:2.1.3"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["iconv-lite", [\ - ["npm:0.6.3", {\ - "packageLocation": "./.yarn/cache/iconv-lite-npm-0.6.3-24b8aae27e-3f60d47a5c.zip/node_modules/iconv-lite/",\ - "packageDependencies": [\ - ["iconv-lite", "npm:0.6.3"],\ - ["safer-buffer", "npm:2.1.2"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["ignore", [\ - ["npm:5.2.4", {\ - "packageLocation": "./.yarn/cache/ignore-npm-5.2.4-fbe6e989e5-3d4c309c60.zip/node_modules/ignore/",\ - "packageDependencies": [\ - ["ignore", "npm:5.2.4"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["import-fresh", [\ - ["npm:3.3.0", {\ - "packageLocation": "./.yarn/cache/import-fresh-npm-3.3.0-3e34265ca9-2cacfad06e.zip/node_modules/import-fresh/",\ - "packageDependencies": [\ - ["import-fresh", "npm:3.3.0"],\ - ["parent-module", "npm:1.0.1"],\ - ["resolve-from", "npm:4.0.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["imurmurhash", [\ - ["npm:0.1.4", {\ - "packageLocation": "./.yarn/cache/imurmurhash-npm-0.1.4-610c5068a0-7cae75c8cd.zip/node_modules/imurmurhash/",\ - "packageDependencies": [\ - ["imurmurhash", "npm:0.1.4"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["indent-string", [\ - ["npm:4.0.0", {\ - "packageLocation": "./.yarn/cache/indent-string-npm-4.0.0-7b717435b2-824cfb9929.zip/node_modules/indent-string/",\ - "packageDependencies": [\ - ["indent-string", "npm:4.0.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["inflight", [\ - ["npm:1.0.6", {\ - "packageLocation": "./.yarn/cache/inflight-npm-1.0.6-ccedb4b908-f4f76aa072.zip/node_modules/inflight/",\ - "packageDependencies": [\ - ["inflight", "npm:1.0.6"],\ - ["once", "npm:1.4.0"],\ - ["wrappy", "npm:1.0.2"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["inherits", [\ - ["npm:2.0.4", {\ - "packageLocation": "./.yarn/cache/inherits-npm-2.0.4-c66b3957a0-4a48a73384.zip/node_modules/inherits/",\ - "packageDependencies": [\ - ["inherits", "npm:2.0.4"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["ip", [\ - ["npm:2.0.0", {\ - "packageLocation": "./.yarn/cache/ip-npm-2.0.0-204facb3cc-cfcfac6b87.zip/node_modules/ip/",\ - "packageDependencies": [\ - ["ip", "npm:2.0.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["is-extglob", [\ - ["npm:2.1.1", {\ - "packageLocation": "./.yarn/cache/is-extglob-npm-2.1.1-0870ea68b5-df033653d0.zip/node_modules/is-extglob/",\ - "packageDependencies": [\ - ["is-extglob", "npm:2.1.1"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["is-fullwidth-code-point", [\ - ["npm:3.0.0", {\ - "packageLocation": "./.yarn/cache/is-fullwidth-code-point-npm-3.0.0-1ecf4ebee5-44a30c2945.zip/node_modules/is-fullwidth-code-point/",\ - "packageDependencies": [\ - ["is-fullwidth-code-point", "npm:3.0.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["is-glob", [\ - ["npm:4.0.3", {\ - "packageLocation": "./.yarn/cache/is-glob-npm-4.0.3-cb87bf1bdb-d381c1319f.zip/node_modules/is-glob/",\ - "packageDependencies": [\ - ["is-glob", "npm:4.0.3"],\ - ["is-extglob", "npm:2.1.1"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["is-lambda", [\ - ["npm:1.0.1", {\ - "packageLocation": "./.yarn/cache/is-lambda-npm-1.0.1-7ab55bc8a8-93a32f0194.zip/node_modules/is-lambda/",\ - "packageDependencies": [\ - ["is-lambda", "npm:1.0.1"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["is-path-inside", [\ - ["npm:3.0.3", {\ - "packageLocation": "./.yarn/cache/is-path-inside-npm-3.0.3-2ea0ef44fd-abd50f0618.zip/node_modules/is-path-inside/",\ - "packageDependencies": [\ - ["is-path-inside", "npm:3.0.3"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["isexe", [\ - ["npm:2.0.0", {\ - "packageLocation": "./.yarn/cache/isexe-npm-2.0.0-b58870bd2e-26bf6c5480.zip/node_modules/isexe/",\ - "packageDependencies": [\ - ["isexe", "npm:2.0.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["jackspeak", [\ - ["npm:2.3.6", {\ - "packageLocation": "./.yarn/cache/jackspeak-npm-2.3.6-42e1233172-57d43ad11e.zip/node_modules/jackspeak/",\ - "packageDependencies": [\ - ["jackspeak", "npm:2.3.6"],\ - ["@isaacs/cliui", "npm:8.0.2"],\ - ["@pkgjs/parseargs", "npm:0.11.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["js-yaml", [\ - ["npm:4.1.0", {\ - "packageLocation": "./.yarn/cache/js-yaml-npm-4.1.0-3606f32312-c7830dfd45.zip/node_modules/js-yaml/",\ - "packageDependencies": [\ - ["js-yaml", "npm:4.1.0"],\ - ["argparse", "npm:2.0.1"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["json-buffer", [\ - ["npm:3.0.1", {\ - "packageLocation": "./.yarn/cache/json-buffer-npm-3.0.1-f8f6d20603-9026b03edc.zip/node_modules/json-buffer/",\ - "packageDependencies": [\ - ["json-buffer", "npm:3.0.1"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["json-schema-traverse", [\ - ["npm:0.4.1", {\ - "packageLocation": "./.yarn/cache/json-schema-traverse-npm-0.4.1-4759091693-7486074d3b.zip/node_modules/json-schema-traverse/",\ - "packageDependencies": [\ - ["json-schema-traverse", "npm:0.4.1"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["json-stable-stringify-without-jsonify", [\ - ["npm:1.0.1", {\ - "packageLocation": "./.yarn/cache/json-stable-stringify-without-jsonify-npm-1.0.1-b65772b28b-cff44156dd.zip/node_modules/json-stable-stringify-without-jsonify/",\ - "packageDependencies": [\ - ["json-stable-stringify-without-jsonify", "npm:1.0.1"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["keyv", [\ - ["npm:4.5.4", {\ - "packageLocation": "./.yarn/cache/keyv-npm-4.5.4-4c8e2cf7f7-74a24395b1.zip/node_modules/keyv/",\ - "packageDependencies": [\ - ["keyv", "npm:4.5.4"],\ - ["json-buffer", "npm:3.0.1"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["levn", [\ - ["npm:0.4.1", {\ - "packageLocation": "./.yarn/cache/levn-npm-0.4.1-d183b2d7bb-12c5021c85.zip/node_modules/levn/",\ - "packageDependencies": [\ - ["levn", "npm:0.4.1"],\ - ["prelude-ls", "npm:1.2.1"],\ - ["type-check", "npm:0.4.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["locate-path", [\ - ["npm:6.0.0", {\ - "packageLocation": "./.yarn/cache/locate-path-npm-6.0.0-06a1e4c528-72eb661788.zip/node_modules/locate-path/",\ - "packageDependencies": [\ - ["locate-path", "npm:6.0.0"],\ - ["p-locate", "npm:5.0.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["lodash.merge", [\ - ["npm:4.6.2", {\ - "packageLocation": "./.yarn/cache/lodash.merge-npm-4.6.2-77cb4416bf-ad580b4bdb.zip/node_modules/lodash.merge/",\ - "packageDependencies": [\ - ["lodash.merge", "npm:4.6.2"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["lru-cache", [\ - ["npm:10.0.1", {\ - "packageLocation": "./.yarn/cache/lru-cache-npm-10.0.1-0e1abf4c13-06f8d0e1ce.zip/node_modules/lru-cache/",\ - "packageDependencies": [\ - ["lru-cache", "npm:10.0.1"]\ - ],\ - "linkType": "HARD"\ - }],\ - ["npm:6.0.0", {\ - "packageLocation": "./.yarn/cache/lru-cache-npm-6.0.0-b4c8668fe1-f97f499f89.zip/node_modules/lru-cache/",\ - "packageDependencies": [\ - ["lru-cache", "npm:6.0.0"],\ - ["yallist", "npm:4.0.0"]\ - ],\ - "linkType": "HARD"\ - }],\ - ["npm:7.18.3", {\ - "packageLocation": "./.yarn/cache/lru-cache-npm-7.18.3-e68be5b11c-e550d77238.zip/node_modules/lru-cache/",\ - "packageDependencies": [\ - ["lru-cache", "npm:7.18.3"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["make-fetch-happen", [\ - ["npm:11.1.1", {\ - "packageLocation": "./.yarn/cache/make-fetch-happen-npm-11.1.1-f32b79aaaa-7268bf274a.zip/node_modules/make-fetch-happen/",\ - "packageDependencies": [\ - ["make-fetch-happen", "npm:11.1.1"],\ - ["agentkeepalive", "npm:4.5.0"],\ - ["cacache", "npm:17.1.4"],\ - ["http-cache-semantics", "npm:4.1.1"],\ - ["http-proxy-agent", "npm:5.0.0"],\ - ["https-proxy-agent", "npm:5.0.1"],\ - ["is-lambda", "npm:1.0.1"],\ - ["lru-cache", "npm:7.18.3"],\ - ["minipass", "npm:5.0.0"],\ - ["minipass-fetch", "npm:3.0.4"],\ - ["minipass-flush", "npm:1.0.5"],\ - ["minipass-pipeline", "npm:1.2.4"],\ - ["negotiator", "npm:0.6.3"],\ - ["promise-retry", "npm:2.0.1"],\ - ["socks-proxy-agent", "npm:7.0.0"],\ - ["ssri", "npm:10.0.5"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["minimatch", [\ - ["npm:3.1.2", {\ - "packageLocation": "./.yarn/cache/minimatch-npm-3.1.2-9405269906-c154e56640.zip/node_modules/minimatch/",\ - "packageDependencies": [\ - ["minimatch", "npm:3.1.2"],\ - ["brace-expansion", "npm:1.1.11"]\ - ],\ - "linkType": "HARD"\ - }],\ - ["npm:9.0.3", {\ - "packageLocation": "./.yarn/cache/minimatch-npm-9.0.3-69d7d6fad5-253487976b.zip/node_modules/minimatch/",\ - "packageDependencies": [\ - ["minimatch", "npm:9.0.3"],\ - ["brace-expansion", "npm:2.0.1"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["minipass", [\ - ["npm:3.3.6", {\ - "packageLocation": "./.yarn/cache/minipass-npm-3.3.6-b8d93a945b-a30d083c80.zip/node_modules/minipass/",\ - "packageDependencies": [\ - ["minipass", "npm:3.3.6"],\ - ["yallist", "npm:4.0.0"]\ - ],\ - "linkType": "HARD"\ - }],\ - ["npm:5.0.0", {\ - "packageLocation": "./.yarn/cache/minipass-npm-5.0.0-c64fb63c92-425dab2887.zip/node_modules/minipass/",\ - "packageDependencies": [\ - ["minipass", "npm:5.0.0"]\ - ],\ - "linkType": "HARD"\ - }],\ - ["npm:7.0.4", {\ - "packageLocation": "./.yarn/cache/minipass-npm-7.0.4-eacb4e042e-87585e258b.zip/node_modules/minipass/",\ - "packageDependencies": [\ - ["minipass", "npm:7.0.4"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["minipass-collect", [\ - ["npm:1.0.2", {\ - "packageLocation": "./.yarn/cache/minipass-collect-npm-1.0.2-3b4676eab5-14df761028.zip/node_modules/minipass-collect/",\ - "packageDependencies": [\ - ["minipass-collect", "npm:1.0.2"],\ - ["minipass", "npm:3.3.6"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["minipass-fetch", [\ - ["npm:3.0.4", {\ - "packageLocation": "./.yarn/cache/minipass-fetch-npm-3.0.4-200ac7c66d-af7aad15d5.zip/node_modules/minipass-fetch/",\ - "packageDependencies": [\ - ["minipass-fetch", "npm:3.0.4"],\ - ["encoding", "npm:0.1.13"],\ - ["minipass", "npm:7.0.4"],\ - ["minipass-sized", "npm:1.0.3"],\ - ["minizlib", "npm:2.1.2"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["minipass-flush", [\ - ["npm:1.0.5", {\ - "packageLocation": "./.yarn/cache/minipass-flush-npm-1.0.5-efe79d9826-56269a0b22.zip/node_modules/minipass-flush/",\ - "packageDependencies": [\ - ["minipass-flush", "npm:1.0.5"],\ - ["minipass", "npm:3.3.6"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["minipass-pipeline", [\ - ["npm:1.2.4", {\ - "packageLocation": "./.yarn/cache/minipass-pipeline-npm-1.2.4-5924cb077f-b14240dac0.zip/node_modules/minipass-pipeline/",\ - "packageDependencies": [\ - ["minipass-pipeline", "npm:1.2.4"],\ - ["minipass", "npm:3.3.6"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["minipass-sized", [\ - ["npm:1.0.3", {\ - "packageLocation": "./.yarn/cache/minipass-sized-npm-1.0.3-306d86f432-79076749fc.zip/node_modules/minipass-sized/",\ - "packageDependencies": [\ - ["minipass-sized", "npm:1.0.3"],\ - ["minipass", "npm:3.3.6"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["minizlib", [\ - ["npm:2.1.2", {\ - "packageLocation": "./.yarn/cache/minizlib-npm-2.1.2-ea89cd0cfb-f1fdeac0b0.zip/node_modules/minizlib/",\ - "packageDependencies": [\ - ["minizlib", "npm:2.1.2"],\ - ["minipass", "npm:3.3.6"],\ - ["yallist", "npm:4.0.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["mkdirp", [\ - ["npm:1.0.4", {\ - "packageLocation": "./.yarn/cache/mkdirp-npm-1.0.4-37f6ef56b9-a96865108c.zip/node_modules/mkdirp/",\ - "packageDependencies": [\ - ["mkdirp", "npm:1.0.4"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["ms", [\ - ["npm:2.1.2", {\ - "packageLocation": "./.yarn/cache/ms-npm-2.1.2-ec0c1512ff-673cdb2c31.zip/node_modules/ms/",\ - "packageDependencies": [\ - ["ms", "npm:2.1.2"]\ - ],\ - "linkType": "HARD"\ - }],\ - ["npm:2.1.3", {\ - "packageLocation": "./.yarn/cache/ms-npm-2.1.3-81ff3cfac1-aa92de6080.zip/node_modules/ms/",\ - "packageDependencies": [\ - ["ms", "npm:2.1.3"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["natural-compare", [\ - ["npm:1.4.0", {\ - "packageLocation": "./.yarn/cache/natural-compare-npm-1.4.0-97b75b362d-23ad088b08.zip/node_modules/natural-compare/",\ - "packageDependencies": [\ - ["natural-compare", "npm:1.4.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["negotiator", [\ - ["npm:0.6.3", {\ - "packageLocation": "./.yarn/cache/negotiator-npm-0.6.3-9d50e36171-b8ffeb1e26.zip/node_modules/negotiator/",\ - "packageDependencies": [\ - ["negotiator", "npm:0.6.3"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["node-gyp", [\ - ["npm:9.4.0", {\ - "packageLocation": "./.yarn/unplugged/node-gyp-npm-9.4.0-ebf5f5573e/node_modules/node-gyp/",\ - "packageDependencies": [\ - ["node-gyp", "npm:9.4.0"],\ - ["env-paths", "npm:2.2.1"],\ - ["exponential-backoff", "npm:3.1.1"],\ - ["glob", "npm:7.2.3"],\ - ["graceful-fs", "npm:4.2.11"],\ - ["make-fetch-happen", "npm:11.1.1"],\ - ["nopt", "npm:6.0.0"],\ - ["npmlog", "npm:6.0.2"],\ - ["rimraf", "npm:3.0.2"],\ - ["semver", "npm:7.5.4"],\ - ["tar", "npm:6.2.0"],\ - ["which", "npm:2.0.2"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["nopt", [\ - ["npm:6.0.0", {\ - "packageLocation": "./.yarn/cache/nopt-npm-6.0.0-5ea8050815-82149371f8.zip/node_modules/nopt/",\ - "packageDependencies": [\ - ["nopt", "npm:6.0.0"],\ - ["abbrev", "npm:1.1.1"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["npmlog", [\ - ["npm:6.0.2", {\ - "packageLocation": "./.yarn/cache/npmlog-npm-6.0.2-e0e69455c7-ae238cd264.zip/node_modules/npmlog/",\ - "packageDependencies": [\ - ["npmlog", "npm:6.0.2"],\ - ["are-we-there-yet", "npm:3.0.1"],\ - ["console-control-strings", "npm:1.1.0"],\ - ["gauge", "npm:4.0.4"],\ - ["set-blocking", "npm:2.0.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["once", [\ - ["npm:1.4.0", {\ - "packageLocation": "./.yarn/cache/once-npm-1.4.0-ccf03ef07a-cd0a885013.zip/node_modules/once/",\ - "packageDependencies": [\ - ["once", "npm:1.4.0"],\ - ["wrappy", "npm:1.0.2"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["optionator", [\ - ["npm:0.9.3", {\ - "packageLocation": "./.yarn/cache/optionator-npm-0.9.3-56c3a4bf80-0928199944.zip/node_modules/optionator/",\ - "packageDependencies": [\ - ["optionator", "npm:0.9.3"],\ - ["@aashutoshrathi/word-wrap", "npm:1.2.6"],\ - ["deep-is", "npm:0.1.4"],\ - ["fast-levenshtein", "npm:2.0.6"],\ - ["levn", "npm:0.4.1"],\ - ["prelude-ls", "npm:1.2.1"],\ - ["type-check", "npm:0.4.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["p-limit", [\ - ["npm:3.1.0", {\ - "packageLocation": "./.yarn/cache/p-limit-npm-3.1.0-05d2ede37f-7c3690c4db.zip/node_modules/p-limit/",\ - "packageDependencies": [\ - ["p-limit", "npm:3.1.0"],\ - ["yocto-queue", "npm:0.1.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["p-locate", [\ - ["npm:5.0.0", {\ - "packageLocation": "./.yarn/cache/p-locate-npm-5.0.0-92cc7c7a3e-1623088f36.zip/node_modules/p-locate/",\ - "packageDependencies": [\ - ["p-locate", "npm:5.0.0"],\ - ["p-limit", "npm:3.1.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["p-map", [\ - ["npm:4.0.0", {\ - "packageLocation": "./.yarn/cache/p-map-npm-4.0.0-4677ae07c7-cb0ab21ec0.zip/node_modules/p-map/",\ - "packageDependencies": [\ - ["p-map", "npm:4.0.0"],\ - ["aggregate-error", "npm:3.1.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["parent-module", [\ - ["npm:1.0.1", {\ - "packageLocation": "./.yarn/cache/parent-module-npm-1.0.1-1fae11b095-6ba8b25514.zip/node_modules/parent-module/",\ - "packageDependencies": [\ - ["parent-module", "npm:1.0.1"],\ - ["callsites", "npm:3.1.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["path-exists", [\ - ["npm:4.0.0", {\ - "packageLocation": "./.yarn/cache/path-exists-npm-4.0.0-e9e4f63eb0-505807199d.zip/node_modules/path-exists/",\ - "packageDependencies": [\ - ["path-exists", "npm:4.0.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["path-is-absolute", [\ - ["npm:1.0.1", {\ - "packageLocation": "./.yarn/cache/path-is-absolute-npm-1.0.1-31bc695ffd-060840f92c.zip/node_modules/path-is-absolute/",\ - "packageDependencies": [\ - ["path-is-absolute", "npm:1.0.1"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["path-key", [\ - ["npm:3.1.1", {\ - "packageLocation": "./.yarn/cache/path-key-npm-3.1.1-0e66ea8321-55cd7a9dd4.zip/node_modules/path-key/",\ - "packageDependencies": [\ - ["path-key", "npm:3.1.1"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["path-scurry", [\ - ["npm:1.10.1", {\ - "packageLocation": "./.yarn/cache/path-scurry-npm-1.10.1-52bd946f2e-e2557cff3a.zip/node_modules/path-scurry/",\ - "packageDependencies": [\ - ["path-scurry", "npm:1.10.1"],\ - ["lru-cache", "npm:10.0.1"],\ - ["minipass", "npm:7.0.4"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["prelude-ls", [\ - ["npm:1.2.1", {\ - "packageLocation": "./.yarn/cache/prelude-ls-npm-1.2.1-3e4d272a55-cd192ec0d0.zip/node_modules/prelude-ls/",\ - "packageDependencies": [\ - ["prelude-ls", "npm:1.2.1"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["promise-retry", [\ - ["npm:2.0.1", {\ - "packageLocation": "./.yarn/cache/promise-retry-npm-2.0.1-871f0b01b7-f96a3f6d90.zip/node_modules/promise-retry/",\ - "packageDependencies": [\ - ["promise-retry", "npm:2.0.1"],\ - ["err-code", "npm:2.0.3"],\ - ["retry", "npm:0.12.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["punycode", [\ - ["npm:2.3.0", {\ - "packageLocation": "./.yarn/cache/punycode-npm-2.3.0-df4bdce06b-39f760e09a.zip/node_modules/punycode/",\ - "packageDependencies": [\ - ["punycode", "npm:2.3.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["queue-microtask", [\ - ["npm:1.2.3", {\ - "packageLocation": "./.yarn/cache/queue-microtask-npm-1.2.3-fcc98e4e2d-b676f8c040.zip/node_modules/queue-microtask/",\ - "packageDependencies": [\ - ["queue-microtask", "npm:1.2.3"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["readable-stream", [\ - ["npm:3.6.2", {\ - "packageLocation": "./.yarn/cache/readable-stream-npm-3.6.2-d2a6069158-bdcbe6c22e.zip/node_modules/readable-stream/",\ - "packageDependencies": [\ - ["readable-stream", "npm:3.6.2"],\ - ["inherits", "npm:2.0.4"],\ - ["string_decoder", "npm:1.3.0"],\ - ["util-deprecate", "npm:1.0.2"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["resolve-from", [\ - ["npm:4.0.0", {\ - "packageLocation": "./.yarn/cache/resolve-from-npm-4.0.0-f758ec21bf-f4ba0b8494.zip/node_modules/resolve-from/",\ - "packageDependencies": [\ - ["resolve-from", "npm:4.0.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["retry", [\ - ["npm:0.12.0", {\ - "packageLocation": "./.yarn/cache/retry-npm-0.12.0-72ac7fb4cc-623bd7d2e5.zip/node_modules/retry/",\ - "packageDependencies": [\ - ["retry", "npm:0.12.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["reusify", [\ - ["npm:1.0.4", {\ - "packageLocation": "./.yarn/cache/reusify-npm-1.0.4-95ac4aec11-c3076ebcc2.zip/node_modules/reusify/",\ - "packageDependencies": [\ - ["reusify", "npm:1.0.4"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["rimraf", [\ - ["npm:3.0.2", {\ - "packageLocation": "./.yarn/cache/rimraf-npm-3.0.2-2cb7dac69a-87f4164e39.zip/node_modules/rimraf/",\ - "packageDependencies": [\ - ["rimraf", "npm:3.0.2"],\ - ["glob", "npm:7.2.3"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["rollup", [\ - ["npm:2.79.1", {\ - "packageLocation": "./.yarn/cache/rollup-npm-2.79.1-94e707a9a3-6a2bf167b3.zip/node_modules/rollup/",\ - "packageDependencies": [\ - ["rollup", "npm:2.79.1"],\ - ["fsevents", "patch:fsevents@npm%3A2.3.3#~builtin::version=2.3.3&hash=df0bf1"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["run-parallel", [\ - ["npm:1.2.0", {\ - "packageLocation": "./.yarn/cache/run-parallel-npm-1.2.0-3f47ff2034-cb4f97ad25.zip/node_modules/run-parallel/",\ - "packageDependencies": [\ - ["run-parallel", "npm:1.2.0"],\ - ["queue-microtask", "npm:1.2.3"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["safe-buffer", [\ - ["npm:5.2.1", {\ - "packageLocation": "./.yarn/cache/safe-buffer-npm-5.2.1-3481c8aa9b-b99c4b41fd.zip/node_modules/safe-buffer/",\ - "packageDependencies": [\ - ["safe-buffer", "npm:5.2.1"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["safer-buffer", [\ - ["npm:2.1.2", {\ - "packageLocation": "./.yarn/cache/safer-buffer-npm-2.1.2-8d5c0b705e-cab8f25ae6.zip/node_modules/safer-buffer/",\ - "packageDependencies": [\ - ["safer-buffer", "npm:2.1.2"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["semver", [\ - ["npm:7.5.4", {\ - "packageLocation": "./.yarn/cache/semver-npm-7.5.4-c4ad957fcd-12d8ad952f.zip/node_modules/semver/",\ - "packageDependencies": [\ - ["semver", "npm:7.5.4"],\ - ["lru-cache", "npm:6.0.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["set-blocking", [\ - ["npm:2.0.0", {\ - "packageLocation": "./.yarn/cache/set-blocking-npm-2.0.0-49e2cffa24-6e65a05f7c.zip/node_modules/set-blocking/",\ - "packageDependencies": [\ - ["set-blocking", "npm:2.0.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["shebang-command", [\ - ["npm:2.0.0", {\ - "packageLocation": "./.yarn/cache/shebang-command-npm-2.0.0-eb2b01921d-6b52fe8727.zip/node_modules/shebang-command/",\ - "packageDependencies": [\ - ["shebang-command", "npm:2.0.0"],\ - ["shebang-regex", "npm:3.0.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["shebang-regex", [\ - ["npm:3.0.0", {\ - "packageLocation": "./.yarn/cache/shebang-regex-npm-3.0.0-899a0cd65e-1a2bcae50d.zip/node_modules/shebang-regex/",\ - "packageDependencies": [\ - ["shebang-regex", "npm:3.0.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["signal-exit", [\ - ["npm:3.0.7", {\ - "packageLocation": "./.yarn/cache/signal-exit-npm-3.0.7-bd270458a3-a2f098f247.zip/node_modules/signal-exit/",\ - "packageDependencies": [\ - ["signal-exit", "npm:3.0.7"]\ - ],\ - "linkType": "HARD"\ - }],\ - ["npm:4.1.0", {\ - "packageLocation": "./.yarn/cache/signal-exit-npm-4.1.0-61fb957687-64c757b498.zip/node_modules/signal-exit/",\ - "packageDependencies": [\ - ["signal-exit", "npm:4.1.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["smart-buffer", [\ - ["npm:4.2.0", {\ - "packageLocation": "./.yarn/cache/smart-buffer-npm-4.2.0-5ac3f668bb-b5167a7142.zip/node_modules/smart-buffer/",\ - "packageDependencies": [\ - ["smart-buffer", "npm:4.2.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["socks", [\ - ["npm:2.7.1", {\ - "packageLocation": "./.yarn/cache/socks-npm-2.7.1-17f2b53052-259d9e3e8e.zip/node_modules/socks/",\ - "packageDependencies": [\ - ["socks", "npm:2.7.1"],\ - ["ip", "npm:2.0.0"],\ - ["smart-buffer", "npm:4.2.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["socks-proxy-agent", [\ - ["npm:7.0.0", {\ - "packageLocation": "./.yarn/cache/socks-proxy-agent-npm-7.0.0-7aacf32ea0-7205543701.zip/node_modules/socks-proxy-agent/",\ - "packageDependencies": [\ - ["socks-proxy-agent", "npm:7.0.0"],\ - ["agent-base", "npm:6.0.2"],\ - ["debug", "virtual:feb0771c9f8eadaf509cfed41e14a8bebbea5442233275c1c87085111077a08ef71eb773b899665b154d8203a55a489610a54117ae059fce5f5b8b844493b1b1#npm:4.3.4"],\ - ["socks", "npm:2.7.1"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["source-map", [\ - ["npm:0.6.1", {\ - "packageLocation": "./.yarn/cache/source-map-npm-0.6.1-1a3621db16-59ce8640cf.zip/node_modules/source-map/",\ - "packageDependencies": [\ - ["source-map", "npm:0.6.1"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["source-map-support", [\ - ["npm:0.5.21", {\ - "packageLocation": "./.yarn/cache/source-map-support-npm-0.5.21-09ca99e250-43e98d700d.zip/node_modules/source-map-support/",\ - "packageDependencies": [\ - ["source-map-support", "npm:0.5.21"],\ - ["buffer-from", "npm:1.1.2"],\ - ["source-map", "npm:0.6.1"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["ssri", [\ - ["npm:10.0.5", {\ - "packageLocation": "./.yarn/cache/ssri-npm-10.0.5-1a7557d04d-0a31b65f21.zip/node_modules/ssri/",\ - "packageDependencies": [\ - ["ssri", "npm:10.0.5"],\ - ["minipass", "npm:7.0.4"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["string-width", [\ - ["npm:4.2.3", {\ - "packageLocation": "./.yarn/cache/string-width-npm-4.2.3-2c27177bae-e52c10dc3f.zip/node_modules/string-width/",\ - "packageDependencies": [\ - ["string-width", "npm:4.2.3"],\ - ["emoji-regex", "npm:8.0.0"],\ - ["is-fullwidth-code-point", "npm:3.0.0"],\ - ["strip-ansi", "npm:6.0.1"]\ - ],\ - "linkType": "HARD"\ - }],\ - ["npm:5.1.2", {\ - "packageLocation": "./.yarn/cache/string-width-npm-5.1.2-bf60531341-7369deaa29.zip/node_modules/string-width/",\ - "packageDependencies": [\ - ["string-width", "npm:5.1.2"],\ - ["eastasianwidth", "npm:0.2.0"],\ - ["emoji-regex", "npm:9.2.2"],\ - ["strip-ansi", "npm:7.1.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["string_decoder", [\ - ["npm:1.3.0", {\ - "packageLocation": "./.yarn/cache/string_decoder-npm-1.3.0-2422117fd0-8417646695.zip/node_modules/string_decoder/",\ - "packageDependencies": [\ - ["string_decoder", "npm:1.3.0"],\ - ["safe-buffer", "npm:5.2.1"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["strip-ansi", [\ - ["npm:6.0.1", {\ - "packageLocation": "./.yarn/cache/strip-ansi-npm-6.0.1-caddc7cb40-f3cd25890a.zip/node_modules/strip-ansi/",\ - "packageDependencies": [\ - ["strip-ansi", "npm:6.0.1"],\ - ["ansi-regex", "npm:5.0.1"]\ - ],\ - "linkType": "HARD"\ - }],\ - ["npm:7.1.0", {\ - "packageLocation": "./.yarn/cache/strip-ansi-npm-7.1.0-7453b80b79-859c73fcf2.zip/node_modules/strip-ansi/",\ - "packageDependencies": [\ - ["strip-ansi", "npm:7.1.0"],\ - ["ansi-regex", "npm:6.0.1"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["strip-json-comments", [\ - ["npm:3.1.1", {\ - "packageLocation": "./.yarn/cache/strip-json-comments-npm-3.1.1-dcb2324823-492f73e272.zip/node_modules/strip-json-comments/",\ - "packageDependencies": [\ - ["strip-json-comments", "npm:3.1.1"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["supports-color", [\ - ["npm:7.2.0", {\ - "packageLocation": "./.yarn/cache/supports-color-npm-7.2.0-606bfcf7da-3dda818de0.zip/node_modules/supports-color/",\ - "packageDependencies": [\ - ["supports-color", "npm:7.2.0"],\ - ["has-flag", "npm:4.0.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["tar", [\ - ["npm:6.2.0", {\ - "packageLocation": "./.yarn/cache/tar-npm-6.2.0-3eb25205a7-db4d9fe74a.zip/node_modules/tar/",\ - "packageDependencies": [\ - ["tar", "npm:6.2.0"],\ - ["chownr", "npm:2.0.0"],\ - ["fs-minipass", "npm:2.1.0"],\ - ["minipass", "npm:5.0.0"],\ - ["minizlib", "npm:2.1.2"],\ - ["mkdirp", "npm:1.0.4"],\ - ["yallist", "npm:4.0.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["temml", [\ - ["workspace:.", {\ - "packageLocation": "./",\ - "packageDependencies": [\ - ["temml", "workspace:."],\ - ["eslint", "npm:8.52.0"],\ - ["esm", "npm:3.2.25"],\ - ["rollup", "npm:2.79.1"],\ - ["terser", "npm:5.22.0"]\ - ],\ - "linkType": "SOFT"\ - }]\ - ]],\ - ["terser", [\ - ["npm:5.22.0", {\ - "packageLocation": "./.yarn/cache/terser-npm-5.22.0-e83cb45628-ee95981c54.zip/node_modules/terser/",\ - "packageDependencies": [\ - ["terser", "npm:5.22.0"],\ - ["@jridgewell/source-map", "npm:0.3.5"],\ - ["acorn", "npm:8.10.0"],\ - ["commander", "npm:2.20.3"],\ - ["source-map-support", "npm:0.5.21"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["text-table", [\ - ["npm:0.2.0", {\ - "packageLocation": "./.yarn/cache/text-table-npm-0.2.0-d92a778b59-b6937a38c8.zip/node_modules/text-table/",\ - "packageDependencies": [\ - ["text-table", "npm:0.2.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["type-check", [\ - ["npm:0.4.0", {\ - "packageLocation": "./.yarn/cache/type-check-npm-0.4.0-60565800ce-ec688ebfc9.zip/node_modules/type-check/",\ - "packageDependencies": [\ - ["type-check", "npm:0.4.0"],\ - ["prelude-ls", "npm:1.2.1"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["type-fest", [\ - ["npm:0.20.2", {\ - "packageLocation": "./.yarn/cache/type-fest-npm-0.20.2-b36432617f-4fb3272df2.zip/node_modules/type-fest/",\ - "packageDependencies": [\ - ["type-fest", "npm:0.20.2"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["unique-filename", [\ - ["npm:3.0.0", {\ - "packageLocation": "./.yarn/cache/unique-filename-npm-3.0.0-77d68e0a45-8e2f59b356.zip/node_modules/unique-filename/",\ - "packageDependencies": [\ - ["unique-filename", "npm:3.0.0"],\ - ["unique-slug", "npm:4.0.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["unique-slug", [\ - ["npm:4.0.0", {\ - "packageLocation": "./.yarn/cache/unique-slug-npm-4.0.0-e6b08f28aa-0884b58365.zip/node_modules/unique-slug/",\ - "packageDependencies": [\ - ["unique-slug", "npm:4.0.0"],\ - ["imurmurhash", "npm:0.1.4"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["uri-js", [\ - ["npm:4.4.1", {\ - "packageLocation": "./.yarn/cache/uri-js-npm-4.4.1-66d11cbcaf-7167432de6.zip/node_modules/uri-js/",\ - "packageDependencies": [\ - ["uri-js", "npm:4.4.1"],\ - ["punycode", "npm:2.3.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["util-deprecate", [\ - ["npm:1.0.2", {\ - "packageLocation": "./.yarn/cache/util-deprecate-npm-1.0.2-e3fe1a219c-474acf1146.zip/node_modules/util-deprecate/",\ - "packageDependencies": [\ - ["util-deprecate", "npm:1.0.2"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["which", [\ - ["npm:2.0.2", {\ - "packageLocation": "./.yarn/cache/which-npm-2.0.2-320ddf72f7-1a5c563d3c.zip/node_modules/which/",\ - "packageDependencies": [\ - ["which", "npm:2.0.2"],\ - ["isexe", "npm:2.0.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["wide-align", [\ - ["npm:1.1.5", {\ - "packageLocation": "./.yarn/cache/wide-align-npm-1.1.5-889d77e592-d5fc37cd56.zip/node_modules/wide-align/",\ - "packageDependencies": [\ - ["wide-align", "npm:1.1.5"],\ - ["string-width", "npm:4.2.3"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["wrap-ansi", [\ - ["npm:7.0.0", {\ - "packageLocation": "./.yarn/cache/wrap-ansi-npm-7.0.0-ad6e1a0554-a790b846fd.zip/node_modules/wrap-ansi/",\ - "packageDependencies": [\ - ["wrap-ansi", "npm:7.0.0"],\ - ["ansi-styles", "npm:4.3.0"],\ - ["string-width", "npm:4.2.3"],\ - ["strip-ansi", "npm:6.0.1"]\ - ],\ - "linkType": "HARD"\ - }],\ - ["npm:8.1.0", {\ - "packageLocation": "./.yarn/cache/wrap-ansi-npm-8.1.0-26a4e6ae28-371733296d.zip/node_modules/wrap-ansi/",\ - "packageDependencies": [\ - ["wrap-ansi", "npm:8.1.0"],\ - ["ansi-styles", "npm:6.2.1"],\ - ["string-width", "npm:5.1.2"],\ - ["strip-ansi", "npm:7.1.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["wrappy", [\ - ["npm:1.0.2", {\ - "packageLocation": "./.yarn/cache/wrappy-npm-1.0.2-916de4d4b3-159da4805f.zip/node_modules/wrappy/",\ - "packageDependencies": [\ - ["wrappy", "npm:1.0.2"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["yallist", [\ - ["npm:4.0.0", {\ - "packageLocation": "./.yarn/cache/yallist-npm-4.0.0-b493d9e907-343617202a.zip/node_modules/yallist/",\ - "packageDependencies": [\ - ["yallist", "npm:4.0.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["yocto-queue", [\ - ["npm:0.1.0", {\ - "packageLocation": "./.yarn/cache/yocto-queue-npm-0.1.0-c6c9a7db29-f77b3d8d00.zip/node_modules/yocto-queue/",\ - "packageDependencies": [\ - ["yocto-queue", "npm:0.1.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]]\ - ]\ - }'), {basePath: basePath || __dirname}); - } - -const fs = require('fs'); -const path = require('path'); -const require$$0 = require('module'); -const StringDecoder = require('string_decoder'); -const url = require('url'); -const os = require('os'); -const nodeUtils = require('util'); -const readline = require('readline'); -const assert = require('assert'); -const stream = require('stream'); -const zlib = require('zlib'); -const events = require('events'); - -const _interopDefaultLegacy = e => e && typeof e === 'object' && 'default' in e ? e : { default: e }; - -function _interopNamespace(e) { - if (e && e.__esModule) return e; - const n = Object.create(null); - if (e) { - for (const k in e) { - if (k !== 'default') { - const d = Object.getOwnPropertyDescriptor(e, k); - Object.defineProperty(n, k, d.get ? d : { - enumerable: true, - get: () => e[k] - }); - } - } - } - n.default = e; - return Object.freeze(n); -} - -const fs__default = /*#__PURE__*/_interopDefaultLegacy(fs); -const path__default = /*#__PURE__*/_interopDefaultLegacy(path); -const require$$0__default = /*#__PURE__*/_interopDefaultLegacy(require$$0); -const StringDecoder__default = /*#__PURE__*/_interopDefaultLegacy(StringDecoder); -const nodeUtils__namespace = /*#__PURE__*/_interopNamespace(nodeUtils); -const assert__default = /*#__PURE__*/_interopDefaultLegacy(assert); -const zlib__default = /*#__PURE__*/_interopDefaultLegacy(zlib); - -const S_IFMT = 61440; -const S_IFDIR = 16384; -const S_IFREG = 32768; -const S_IFLNK = 40960; -const SAFE_TIME = 456789e3; - -const DEFAULT_MODE = S_IFREG | 420; -class StatEntry { - constructor() { - this.uid = 0; - this.gid = 0; - this.size = 0; - this.blksize = 0; - this.atimeMs = 0; - this.mtimeMs = 0; - this.ctimeMs = 0; - this.birthtimeMs = 0; - this.atime = new Date(0); - this.mtime = new Date(0); - this.ctime = new Date(0); - this.birthtime = new Date(0); - this.dev = 0; - this.ino = 0; - this.mode = DEFAULT_MODE; - this.nlink = 1; - this.rdev = 0; - this.blocks = 1; - } - isBlockDevice() { - return false; - } - isCharacterDevice() { - return false; - } - isDirectory() { - return (this.mode & S_IFMT) === S_IFDIR; - } - isFIFO() { - return false; - } - isFile() { - return (this.mode & S_IFMT) === S_IFREG; - } - isSocket() { - return false; - } - isSymbolicLink() { - return (this.mode & S_IFMT) === S_IFLNK; - } -} -class BigIntStatsEntry { - constructor() { - this.uid = BigInt(0); - this.gid = BigInt(0); - this.size = BigInt(0); - this.blksize = BigInt(0); - this.atimeMs = BigInt(0); - this.mtimeMs = BigInt(0); - this.ctimeMs = BigInt(0); - this.birthtimeMs = BigInt(0); - this.atimeNs = BigInt(0); - this.mtimeNs = BigInt(0); - this.ctimeNs = BigInt(0); - this.birthtimeNs = BigInt(0); - this.atime = new Date(0); - this.mtime = new Date(0); - this.ctime = new Date(0); - this.birthtime = new Date(0); - this.dev = BigInt(0); - this.ino = BigInt(0); - this.mode = BigInt(DEFAULT_MODE); - this.nlink = BigInt(1); - this.rdev = BigInt(0); - this.blocks = BigInt(1); - } - isBlockDevice() { - return false; - } - isCharacterDevice() { - return false; - } - isDirectory() { - return (this.mode & BigInt(S_IFMT)) === BigInt(S_IFDIR); - } - isFIFO() { - return false; - } - isFile() { - return (this.mode & BigInt(S_IFMT)) === BigInt(S_IFREG); - } - isSocket() { - return false; - } - isSymbolicLink() { - return (this.mode & BigInt(S_IFMT)) === BigInt(S_IFLNK); - } -} -function makeDefaultStats() { - return new StatEntry(); -} -function clearStats(stats) { - for (const key in stats) { - if (Object.prototype.hasOwnProperty.call(stats, key)) { - const element = stats[key]; - if (typeof element === `number`) { - stats[key] = 0; - } else if (typeof element === `bigint`) { - stats[key] = BigInt(0); - } else if (nodeUtils__namespace.types.isDate(element)) { - stats[key] = new Date(0); - } - } - } - return stats; -} -function convertToBigIntStats(stats) { - const bigintStats = new BigIntStatsEntry(); - for (const key in stats) { - if (Object.prototype.hasOwnProperty.call(stats, key)) { - const element = stats[key]; - if (typeof element === `number`) { - bigintStats[key] = BigInt(element); - } else if (nodeUtils__namespace.types.isDate(element)) { - bigintStats[key] = new Date(element); - } - } - } - bigintStats.atimeNs = bigintStats.atimeMs * BigInt(1e6); - bigintStats.mtimeNs = bigintStats.mtimeMs * BigInt(1e6); - bigintStats.ctimeNs = bigintStats.ctimeMs * BigInt(1e6); - bigintStats.birthtimeNs = bigintStats.birthtimeMs * BigInt(1e6); - return bigintStats; -} -function areStatsEqual(a, b) { - if (a.atimeMs !== b.atimeMs) - return false; - if (a.birthtimeMs !== b.birthtimeMs) - return false; - if (a.blksize !== b.blksize) - return false; - if (a.blocks !== b.blocks) - return false; - if (a.ctimeMs !== b.ctimeMs) - return false; - if (a.dev !== b.dev) - return false; - if (a.gid !== b.gid) - return false; - if (a.ino !== b.ino) - return false; - if (a.isBlockDevice() !== b.isBlockDevice()) - return false; - if (a.isCharacterDevice() !== b.isCharacterDevice()) - return false; - if (a.isDirectory() !== b.isDirectory()) - return false; - if (a.isFIFO() !== b.isFIFO()) - return false; - if (a.isFile() !== b.isFile()) - return false; - if (a.isSocket() !== b.isSocket()) - return false; - if (a.isSymbolicLink() !== b.isSymbolicLink()) - return false; - if (a.mode !== b.mode) - return false; - if (a.mtimeMs !== b.mtimeMs) - return false; - if (a.nlink !== b.nlink) - return false; - if (a.rdev !== b.rdev) - return false; - if (a.size !== b.size) - return false; - if (a.uid !== b.uid) - return false; - const aN = a; - const bN = b; - if (aN.atimeNs !== bN.atimeNs) - return false; - if (aN.mtimeNs !== bN.mtimeNs) - return false; - if (aN.ctimeNs !== bN.ctimeNs) - return false; - if (aN.birthtimeNs !== bN.birthtimeNs) - return false; - return true; -} - -const PortablePath = { - root: `/`, - dot: `.`, - parent: `..` -}; -const Filename = { - nodeModules: `node_modules`, - manifest: `package.json`, - lockfile: `yarn.lock`, - virtual: `__virtual__`, - pnpJs: `.pnp.js`, - pnpCjs: `.pnp.cjs`, - rc: `.yarnrc.yml` -}; -const npath = Object.create(path__default.default); -const ppath = Object.create(path__default.default.posix); -npath.cwd = () => process.cwd(); -ppath.cwd = () => toPortablePath(process.cwd()); -ppath.resolve = (...segments) => { - if (segments.length > 0 && ppath.isAbsolute(segments[0])) { - return path__default.default.posix.resolve(...segments); - } else { - return path__default.default.posix.resolve(ppath.cwd(), ...segments); - } -}; -const contains = function(pathUtils, from, to) { - from = pathUtils.normalize(from); - to = pathUtils.normalize(to); - if (from === to) - return `.`; - if (!from.endsWith(pathUtils.sep)) - from = from + pathUtils.sep; - if (to.startsWith(from)) { - return to.slice(from.length); - } else { - return null; - } -}; -npath.fromPortablePath = fromPortablePath; -npath.toPortablePath = toPortablePath; -npath.contains = (from, to) => contains(npath, from, to); -ppath.contains = (from, to) => contains(ppath, from, to); -const WINDOWS_PATH_REGEXP = /^([a-zA-Z]:.*)$/; -const UNC_WINDOWS_PATH_REGEXP = /^\/\/(\.\/)?(.*)$/; -const PORTABLE_PATH_REGEXP = /^\/([a-zA-Z]:.*)$/; -const UNC_PORTABLE_PATH_REGEXP = /^\/unc\/(\.dot\/)?(.*)$/; -function fromPortablePath(p) { - if (process.platform !== `win32`) - return p; - let portablePathMatch, uncPortablePathMatch; - if (portablePathMatch = p.match(PORTABLE_PATH_REGEXP)) - p = portablePathMatch[1]; - else if (uncPortablePathMatch = p.match(UNC_PORTABLE_PATH_REGEXP)) - p = `\\\\${uncPortablePathMatch[1] ? `.\\` : ``}${uncPortablePathMatch[2]}`; - else - return p; - return p.replace(/\//g, `\\`); -} -function toPortablePath(p) { - if (process.platform !== `win32`) - return p; - p = p.replace(/\\/g, `/`); - let windowsPathMatch, uncWindowsPathMatch; - if (windowsPathMatch = p.match(WINDOWS_PATH_REGEXP)) - p = `/${windowsPathMatch[1]}`; - else if (uncWindowsPathMatch = p.match(UNC_WINDOWS_PATH_REGEXP)) - p = `/unc/${uncWindowsPathMatch[1] ? `.dot/` : ``}${uncWindowsPathMatch[2]}`; - return p; -} -function convertPath(targetPathUtils, sourcePath) { - return targetPathUtils === npath ? fromPortablePath(sourcePath) : toPortablePath(sourcePath); -} - -const defaultTime = new Date(SAFE_TIME * 1e3); -async function copyPromise(destinationFs, destination, sourceFs, source, opts) { - const normalizedDestination = destinationFs.pathUtils.normalize(destination); - const normalizedSource = sourceFs.pathUtils.normalize(source); - const prelayout = []; - const postlayout = []; - const { atime, mtime } = opts.stableTime ? { atime: defaultTime, mtime: defaultTime } : await sourceFs.lstatPromise(normalizedSource); - await destinationFs.mkdirpPromise(destinationFs.pathUtils.dirname(destination), { utimes: [atime, mtime] }); - const updateTime = typeof destinationFs.lutimesPromise === `function` ? destinationFs.lutimesPromise.bind(destinationFs) : destinationFs.utimesPromise.bind(destinationFs); - await copyImpl(prelayout, postlayout, updateTime, destinationFs, normalizedDestination, sourceFs, normalizedSource, { ...opts, didParentExist: true }); - for (const operation of prelayout) - await operation(); - await Promise.all(postlayout.map((operation) => { - return operation(); - })); -} -async function copyImpl(prelayout, postlayout, updateTime, destinationFs, destination, sourceFs, source, opts) { - var _a, _b; - const destinationStat = opts.didParentExist ? await maybeLStat(destinationFs, destination) : null; - const sourceStat = await sourceFs.lstatPromise(source); - const { atime, mtime } = opts.stableTime ? { atime: defaultTime, mtime: defaultTime } : sourceStat; - let updated; - switch (true) { - case sourceStat.isDirectory(): - { - updated = await copyFolder(prelayout, postlayout, updateTime, destinationFs, destination, destinationStat, sourceFs, source, sourceStat, opts); - } - break; - case sourceStat.isFile(): - { - updated = await copyFile(prelayout, postlayout, updateTime, destinationFs, destination, destinationStat, sourceFs, source, sourceStat, opts); - } - break; - case sourceStat.isSymbolicLink(): - { - updated = await copySymlink(prelayout, postlayout, updateTime, destinationFs, destination, destinationStat, sourceFs, source, sourceStat, opts); - } - break; - default: - { - throw new Error(`Unsupported file type (${sourceStat.mode})`); - } - } - if (updated || ((_a = destinationStat == null ? void 0 : destinationStat.mtime) == null ? void 0 : _a.getTime()) !== mtime.getTime() || ((_b = destinationStat == null ? void 0 : destinationStat.atime) == null ? void 0 : _b.getTime()) !== atime.getTime()) { - postlayout.push(() => updateTime(destination, atime, mtime)); - updated = true; - } - if (destinationStat === null || (destinationStat.mode & 511) !== (sourceStat.mode & 511)) { - postlayout.push(() => destinationFs.chmodPromise(destination, sourceStat.mode & 511)); - updated = true; - } - return updated; -} -async function maybeLStat(baseFs, p) { - try { - return await baseFs.lstatPromise(p); - } catch (e) { - return null; - } -} -async function copyFolder(prelayout, postlayout, updateTime, destinationFs, destination, destinationStat, sourceFs, source, sourceStat, opts) { - if (destinationStat !== null && !destinationStat.isDirectory()) { - if (opts.overwrite) { - prelayout.push(async () => destinationFs.removePromise(destination)); - destinationStat = null; - } else { - return false; - } - } - let updated = false; - if (destinationStat === null) { - prelayout.push(async () => { - try { - await destinationFs.mkdirPromise(destination, { mode: sourceStat.mode }); - } catch (err) { - if (err.code !== `EEXIST`) { - throw err; - } - } - }); - updated = true; - } - const entries = await sourceFs.readdirPromise(source); - const nextOpts = opts.didParentExist && !destinationStat ? { ...opts, didParentExist: false } : opts; - if (opts.stableSort) { - for (const entry of entries.sort()) { - if (await copyImpl(prelayout, postlayout, updateTime, destinationFs, destinationFs.pathUtils.join(destination, entry), sourceFs, sourceFs.pathUtils.join(source, entry), nextOpts)) { - updated = true; - } - } - } else { - const entriesUpdateStatus = await Promise.all(entries.map(async (entry) => { - await copyImpl(prelayout, postlayout, updateTime, destinationFs, destinationFs.pathUtils.join(destination, entry), sourceFs, sourceFs.pathUtils.join(source, entry), nextOpts); - })); - if (entriesUpdateStatus.some((status) => status)) { - updated = true; - } - } - return updated; -} -const isCloneSupportedCache = /* @__PURE__ */ new WeakMap(); -function makeLinkOperation(opFs, destination, source, sourceStat, linkStrategy) { - return async () => { - await opFs.linkPromise(source, destination); - if (linkStrategy === "readOnly" /* ReadOnly */) { - sourceStat.mode &= ~146; - await opFs.chmodPromise(destination, sourceStat.mode); - } - }; -} -function makeCloneLinkOperation(opFs, destination, source, sourceStat, linkStrategy) { - const isCloneSupported = isCloneSupportedCache.get(opFs); - if (typeof isCloneSupported === `undefined`) { - return async () => { - try { - await opFs.copyFilePromise(source, destination, fs__default.default.constants.COPYFILE_FICLONE_FORCE); - isCloneSupportedCache.set(opFs, true); - } catch (err) { - if (err.code === `ENOSYS` || err.code === `ENOTSUP`) { - isCloneSupportedCache.set(opFs, false); - await makeLinkOperation(opFs, destination, source, sourceStat, linkStrategy)(); - } else { - throw err; - } - } - }; - } else { - if (isCloneSupported) { - return async () => opFs.copyFilePromise(source, destination, fs__default.default.constants.COPYFILE_FICLONE_FORCE); - } else { - return makeLinkOperation(opFs, destination, source, sourceStat, linkStrategy); - } - } -} -async function copyFile(prelayout, postlayout, updateTime, destinationFs, destination, destinationStat, sourceFs, source, sourceStat, opts) { - var _a; - if (destinationStat !== null) { - if (opts.overwrite) { - prelayout.push(async () => destinationFs.removePromise(destination)); - destinationStat = null; - } else { - return false; - } - } - const linkStrategy = (_a = opts.linkStrategy) != null ? _a : null; - const op = destinationFs === sourceFs ? linkStrategy !== null ? makeCloneLinkOperation(destinationFs, destination, source, sourceStat, linkStrategy) : async () => destinationFs.copyFilePromise(source, destination, fs__default.default.constants.COPYFILE_FICLONE) : linkStrategy !== null ? makeLinkOperation(destinationFs, destination, source, sourceStat, linkStrategy) : async () => destinationFs.writeFilePromise(destination, await sourceFs.readFilePromise(source)); - prelayout.push(async () => op()); - return true; -} -async function copySymlink(prelayout, postlayout, updateTime, destinationFs, destination, destinationStat, sourceFs, source, sourceStat, opts) { - if (destinationStat !== null) { - if (opts.overwrite) { - prelayout.push(async () => destinationFs.removePromise(destination)); - destinationStat = null; - } else { - return false; - } - } - prelayout.push(async () => { - await destinationFs.symlinkPromise(convertPath(destinationFs.pathUtils, await sourceFs.readlinkPromise(source)), destination); - }); - return true; -} - -function makeError$1(code, message) { - return Object.assign(new Error(`${code}: ${message}`), { code }); -} -function EBUSY(message) { - return makeError$1(`EBUSY`, message); -} -function ENOSYS(message, reason) { - return makeError$1(`ENOSYS`, `${message}, ${reason}`); -} -function EINVAL(reason) { - return makeError$1(`EINVAL`, `invalid argument, ${reason}`); -} -function EBADF(reason) { - return makeError$1(`EBADF`, `bad file descriptor, ${reason}`); -} -function ENOENT(reason) { - return makeError$1(`ENOENT`, `no such file or directory, ${reason}`); -} -function ENOTDIR(reason) { - return makeError$1(`ENOTDIR`, `not a directory, ${reason}`); -} -function EISDIR(reason) { - return makeError$1(`EISDIR`, `illegal operation on a directory, ${reason}`); -} -function EEXIST(reason) { - return makeError$1(`EEXIST`, `file already exists, ${reason}`); -} -function EROFS(reason) { - return makeError$1(`EROFS`, `read-only filesystem, ${reason}`); -} -function ENOTEMPTY(reason) { - return makeError$1(`ENOTEMPTY`, `directory not empty, ${reason}`); -} -function EOPNOTSUPP(reason) { - return makeError$1(`EOPNOTSUPP`, `operation not supported, ${reason}`); -} -function ERR_DIR_CLOSED() { - return makeError$1(`ERR_DIR_CLOSED`, `Directory handle was closed`); -} -class LibzipError extends Error { - constructor(message, code) { - super(message); - this.name = `Libzip Error`; - this.code = code; - } -} - -class CustomDir { - constructor(path, nextDirent, opts = {}) { - this.path = path; - this.nextDirent = nextDirent; - this.opts = opts; - this.closed = false; - } - throwIfClosed() { - if (this.closed) { - throw ERR_DIR_CLOSED(); - } - } - async *[Symbol.asyncIterator]() { - try { - let dirent; - while ((dirent = await this.read()) !== null) { - yield dirent; - } - } finally { - await this.close(); - } - } - read(cb) { - const dirent = this.readSync(); - if (typeof cb !== `undefined`) - return cb(null, dirent); - return Promise.resolve(dirent); - } - readSync() { - this.throwIfClosed(); - return this.nextDirent(); - } - close(cb) { - this.closeSync(); - if (typeof cb !== `undefined`) - return cb(null); - return Promise.resolve(); - } - closeSync() { - var _a, _b; - this.throwIfClosed(); - (_b = (_a = this.opts).onClose) == null ? void 0 : _b.call(_a); - this.closed = true; - } -} -function opendir(fakeFs, path, entries, opts) { - const nextDirent = () => { - const filename = entries.shift(); - if (typeof filename === `undefined`) - return null; - return Object.assign(fakeFs.statSync(fakeFs.pathUtils.join(path, filename)), { - name: filename - }); - }; - return new CustomDir(path, nextDirent, opts); -} - -class FakeFS { - constructor(pathUtils) { - this.pathUtils = pathUtils; - } - async *genTraversePromise(init, { stableSort = false } = {}) { - const stack = [init]; - while (stack.length > 0) { - const p = stack.shift(); - const entry = await this.lstatPromise(p); - if (entry.isDirectory()) { - const entries = await this.readdirPromise(p); - if (stableSort) { - for (const entry2 of entries.sort()) { - stack.push(this.pathUtils.join(p, entry2)); - } - } else { - throw new Error(`Not supported`); - } - } else { - yield p; - } - } - } - async removePromise(p, { recursive = true, maxRetries = 5 } = {}) { - let stat; - try { - stat = await this.lstatPromise(p); - } catch (error) { - if (error.code === `ENOENT`) { - return; - } else { - throw error; - } - } - if (stat.isDirectory()) { - if (recursive) { - const entries = await this.readdirPromise(p); - await Promise.all(entries.map((entry) => { - return this.removePromise(this.pathUtils.resolve(p, entry)); - })); - } - for (let t = 0; t <= maxRetries; t++) { - try { - await this.rmdirPromise(p); - break; - } catch (error) { - if (error.code !== `EBUSY` && error.code !== `ENOTEMPTY`) { - throw error; - } else if (t < maxRetries) { - await new Promise((resolve) => setTimeout(resolve, t * 100)); - } - } - } - } else { - await this.unlinkPromise(p); - } - } - removeSync(p, { recursive = true } = {}) { - let stat; - try { - stat = this.lstatSync(p); - } catch (error) { - if (error.code === `ENOENT`) { - return; - } else { - throw error; - } - } - if (stat.isDirectory()) { - if (recursive) - for (const entry of this.readdirSync(p)) - this.removeSync(this.pathUtils.resolve(p, entry)); - this.rmdirSync(p); - } else { - this.unlinkSync(p); - } - } - async mkdirpPromise(p, { chmod, utimes } = {}) { - p = this.resolve(p); - if (p === this.pathUtils.dirname(p)) - return void 0; - const parts = p.split(this.pathUtils.sep); - let createdDirectory; - for (let u = 2; u <= parts.length; ++u) { - const subPath = parts.slice(0, u).join(this.pathUtils.sep); - if (!this.existsSync(subPath)) { - try { - await this.mkdirPromise(subPath); - } catch (error) { - if (error.code === `EEXIST`) { - continue; - } else { - throw error; - } - } - createdDirectory != null ? createdDirectory : createdDirectory = subPath; - if (chmod != null) - await this.chmodPromise(subPath, chmod); - if (utimes != null) { - await this.utimesPromise(subPath, utimes[0], utimes[1]); - } else { - const parentStat = await this.statPromise(this.pathUtils.dirname(subPath)); - await this.utimesPromise(subPath, parentStat.atime, parentStat.mtime); - } - } - } - return createdDirectory; - } - mkdirpSync(p, { chmod, utimes } = {}) { - p = this.resolve(p); - if (p === this.pathUtils.dirname(p)) - return void 0; - const parts = p.split(this.pathUtils.sep); - let createdDirectory; - for (let u = 2; u <= parts.length; ++u) { - const subPath = parts.slice(0, u).join(this.pathUtils.sep); - if (!this.existsSync(subPath)) { - try { - this.mkdirSync(subPath); - } catch (error) { - if (error.code === `EEXIST`) { - continue; - } else { - throw error; - } - } - createdDirectory != null ? createdDirectory : createdDirectory = subPath; - if (chmod != null) - this.chmodSync(subPath, chmod); - if (utimes != null) { - this.utimesSync(subPath, utimes[0], utimes[1]); - } else { - const parentStat = this.statSync(this.pathUtils.dirname(subPath)); - this.utimesSync(subPath, parentStat.atime, parentStat.mtime); - } - } - } - return createdDirectory; - } - async copyPromise(destination, source, { baseFs = this, overwrite = true, stableSort = false, stableTime = false, linkStrategy = null } = {}) { - return await copyPromise(this, destination, baseFs, source, { overwrite, stableSort, stableTime, linkStrategy }); - } - copySync(destination, source, { baseFs = this, overwrite = true } = {}) { - const stat = baseFs.lstatSync(source); - const exists = this.existsSync(destination); - if (stat.isDirectory()) { - this.mkdirpSync(destination); - const directoryListing = baseFs.readdirSync(source); - for (const entry of directoryListing) { - this.copySync(this.pathUtils.join(destination, entry), baseFs.pathUtils.join(source, entry), { baseFs, overwrite }); - } - } else if (stat.isFile()) { - if (!exists || overwrite) { - if (exists) - this.removeSync(destination); - const content = baseFs.readFileSync(source); - this.writeFileSync(destination, content); - } - } else if (stat.isSymbolicLink()) { - if (!exists || overwrite) { - if (exists) - this.removeSync(destination); - const target = baseFs.readlinkSync(source); - this.symlinkSync(convertPath(this.pathUtils, target), destination); - } - } else { - throw new Error(`Unsupported file type (file: ${source}, mode: 0o${stat.mode.toString(8).padStart(6, `0`)})`); - } - const mode = stat.mode & 511; - this.chmodSync(destination, mode); - } - async changeFilePromise(p, content, opts = {}) { - if (Buffer.isBuffer(content)) { - return this.changeFileBufferPromise(p, content, opts); - } else { - return this.changeFileTextPromise(p, content, opts); - } - } - async changeFileBufferPromise(p, content, { mode } = {}) { - let current = Buffer.alloc(0); - try { - current = await this.readFilePromise(p); - } catch (error) { - } - if (Buffer.compare(current, content) === 0) - return; - await this.writeFilePromise(p, content, { mode }); - } - async changeFileTextPromise(p, content, { automaticNewlines, mode } = {}) { - let current = ``; - try { - current = await this.readFilePromise(p, `utf8`); - } catch (error) { - } - const normalizedContent = automaticNewlines ? normalizeLineEndings(current, content) : content; - if (current === normalizedContent) - return; - await this.writeFilePromise(p, normalizedContent, { mode }); - } - changeFileSync(p, content, opts = {}) { - if (Buffer.isBuffer(content)) { - return this.changeFileBufferSync(p, content, opts); - } else { - return this.changeFileTextSync(p, content, opts); - } - } - changeFileBufferSync(p, content, { mode } = {}) { - let current = Buffer.alloc(0); - try { - current = this.readFileSync(p); - } catch (error) { - } - if (Buffer.compare(current, content) === 0) - return; - this.writeFileSync(p, content, { mode }); - } - changeFileTextSync(p, content, { automaticNewlines = false, mode } = {}) { - let current = ``; - try { - current = this.readFileSync(p, `utf8`); - } catch (error) { - } - const normalizedContent = automaticNewlines ? normalizeLineEndings(current, content) : content; - if (current === normalizedContent) - return; - this.writeFileSync(p, normalizedContent, { mode }); - } - async movePromise(fromP, toP) { - try { - await this.renamePromise(fromP, toP); - } catch (error) { - if (error.code === `EXDEV`) { - await this.copyPromise(toP, fromP); - await this.removePromise(fromP); - } else { - throw error; - } - } - } - moveSync(fromP, toP) { - try { - this.renameSync(fromP, toP); - } catch (error) { - if (error.code === `EXDEV`) { - this.copySync(toP, fromP); - this.removeSync(fromP); - } else { - throw error; - } - } - } - async lockPromise(affectedPath, callback) { - const lockPath = `${affectedPath}.flock`; - const interval = 1e3 / 60; - const startTime = Date.now(); - let fd = null; - const isAlive = async () => { - let pid; - try { - [pid] = await this.readJsonPromise(lockPath); - } catch (error) { - return Date.now() - startTime < 500; - } - try { - process.kill(pid, 0); - return true; - } catch (error) { - return false; - } - }; - while (fd === null) { - try { - fd = await this.openPromise(lockPath, `wx`); - } catch (error) { - if (error.code === `EEXIST`) { - if (!await isAlive()) { - try { - await this.unlinkPromise(lockPath); - continue; - } catch (error2) { - } - } - if (Date.now() - startTime < 60 * 1e3) { - await new Promise((resolve) => setTimeout(resolve, interval)); - } else { - throw new Error(`Couldn't acquire a lock in a reasonable time (via ${lockPath})`); - } - } else { - throw error; - } - } - } - await this.writePromise(fd, JSON.stringify([process.pid])); - try { - return await callback(); - } finally { - try { - await this.closePromise(fd); - await this.unlinkPromise(lockPath); - } catch (error) { - } - } - } - async readJsonPromise(p) { - const content = await this.readFilePromise(p, `utf8`); - try { - return JSON.parse(content); - } catch (error) { - error.message += ` (in ${p})`; - throw error; - } - } - readJsonSync(p) { - const content = this.readFileSync(p, `utf8`); - try { - return JSON.parse(content); - } catch (error) { - error.message += ` (in ${p})`; - throw error; - } - } - async writeJsonPromise(p, data) { - return await this.writeFilePromise(p, `${JSON.stringify(data, null, 2)} -`); - } - writeJsonSync(p, data) { - return this.writeFileSync(p, `${JSON.stringify(data, null, 2)} -`); - } - async preserveTimePromise(p, cb) { - const stat = await this.lstatPromise(p); - const result = await cb(); - if (typeof result !== `undefined`) - p = result; - if (this.lutimesPromise) { - await this.lutimesPromise(p, stat.atime, stat.mtime); - } else if (!stat.isSymbolicLink()) { - await this.utimesPromise(p, stat.atime, stat.mtime); - } - } - async preserveTimeSync(p, cb) { - const stat = this.lstatSync(p); - const result = cb(); - if (typeof result !== `undefined`) - p = result; - if (this.lutimesSync) { - this.lutimesSync(p, stat.atime, stat.mtime); - } else if (!stat.isSymbolicLink()) { - this.utimesSync(p, stat.atime, stat.mtime); - } - } -} -class BasePortableFakeFS extends FakeFS { - constructor() { - super(ppath); - } -} -function getEndOfLine(content) { - const matches = content.match(/\r?\n/g); - if (matches === null) - return os.EOL; - const crlf = matches.filter((nl) => nl === `\r -`).length; - const lf = matches.length - crlf; - return crlf > lf ? `\r -` : ` -`; -} -function normalizeLineEndings(originalContent, newContent) { - return newContent.replace(/\r?\n/g, getEndOfLine(originalContent)); -} - -class NodeFS extends BasePortableFakeFS { - constructor(realFs = fs__default.default) { - super(); - this.realFs = realFs; - if (typeof this.realFs.lutimes !== `undefined`) { - this.lutimesPromise = this.lutimesPromiseImpl; - this.lutimesSync = this.lutimesSyncImpl; - } - } - getExtractHint() { - return false; - } - getRealPath() { - return PortablePath.root; - } - resolve(p) { - return ppath.resolve(p); - } - async openPromise(p, flags, mode) { - return await new Promise((resolve, reject) => { - this.realFs.open(npath.fromPortablePath(p), flags, mode, this.makeCallback(resolve, reject)); - }); - } - openSync(p, flags, mode) { - return this.realFs.openSync(npath.fromPortablePath(p), flags, mode); - } - async opendirPromise(p, opts) { - return await new Promise((resolve, reject) => { - if (typeof opts !== `undefined`) { - this.realFs.opendir(npath.fromPortablePath(p), opts, this.makeCallback(resolve, reject)); - } else { - this.realFs.opendir(npath.fromPortablePath(p), this.makeCallback(resolve, reject)); - } - }).then((dir) => { - return Object.defineProperty(dir, `path`, { value: p, configurable: true, writable: true }); - }); - } - opendirSync(p, opts) { - const dir = typeof opts !== `undefined` ? this.realFs.opendirSync(npath.fromPortablePath(p), opts) : this.realFs.opendirSync(npath.fromPortablePath(p)); - return Object.defineProperty(dir, `path`, { value: p, configurable: true, writable: true }); - } - async readPromise(fd, buffer, offset = 0, length = 0, position = -1) { - return await new Promise((resolve, reject) => { - this.realFs.read(fd, buffer, offset, length, position, (error, bytesRead) => { - if (error) { - reject(error); - } else { - resolve(bytesRead); - } - }); - }); - } - readSync(fd, buffer, offset, length, position) { - return this.realFs.readSync(fd, buffer, offset, length, position); - } - async writePromise(fd, buffer, offset, length, position) { - return await new Promise((resolve, reject) => { - if (typeof buffer === `string`) { - return this.realFs.write(fd, buffer, offset, this.makeCallback(resolve, reject)); - } else { - return this.realFs.write(fd, buffer, offset, length, position, this.makeCallback(resolve, reject)); - } - }); - } - writeSync(fd, buffer, offset, length, position) { - if (typeof buffer === `string`) { - return this.realFs.writeSync(fd, buffer, offset); - } else { - return this.realFs.writeSync(fd, buffer, offset, length, position); - } - } - async closePromise(fd) { - await new Promise((resolve, reject) => { - this.realFs.close(fd, this.makeCallback(resolve, reject)); - }); - } - closeSync(fd) { - this.realFs.closeSync(fd); - } - createReadStream(p, opts) { - const realPath = p !== null ? npath.fromPortablePath(p) : p; - return this.realFs.createReadStream(realPath, opts); - } - createWriteStream(p, opts) { - const realPath = p !== null ? npath.fromPortablePath(p) : p; - return this.realFs.createWriteStream(realPath, opts); - } - async realpathPromise(p) { - return await new Promise((resolve, reject) => { - this.realFs.realpath(npath.fromPortablePath(p), {}, this.makeCallback(resolve, reject)); - }).then((path) => { - return npath.toPortablePath(path); - }); - } - realpathSync(p) { - return npath.toPortablePath(this.realFs.realpathSync(npath.fromPortablePath(p), {})); - } - async existsPromise(p) { - return await new Promise((resolve) => { - this.realFs.exists(npath.fromPortablePath(p), resolve); - }); - } - accessSync(p, mode) { - return this.realFs.accessSync(npath.fromPortablePath(p), mode); - } - async accessPromise(p, mode) { - return await new Promise((resolve, reject) => { - this.realFs.access(npath.fromPortablePath(p), mode, this.makeCallback(resolve, reject)); - }); - } - existsSync(p) { - return this.realFs.existsSync(npath.fromPortablePath(p)); - } - async statPromise(p, opts) { - return await new Promise((resolve, reject) => { - if (opts) { - this.realFs.stat(npath.fromPortablePath(p), opts, this.makeCallback(resolve, reject)); - } else { - this.realFs.stat(npath.fromPortablePath(p), this.makeCallback(resolve, reject)); - } - }); - } - statSync(p, opts) { - if (opts) { - return this.realFs.statSync(npath.fromPortablePath(p), opts); - } else { - return this.realFs.statSync(npath.fromPortablePath(p)); - } - } - async fstatPromise(fd, opts) { - return await new Promise((resolve, reject) => { - if (opts) { - this.realFs.fstat(fd, opts, this.makeCallback(resolve, reject)); - } else { - this.realFs.fstat(fd, this.makeCallback(resolve, reject)); - } - }); - } - fstatSync(fd, opts) { - if (opts) { - return this.realFs.fstatSync(fd, opts); - } else { - return this.realFs.fstatSync(fd); - } - } - async lstatPromise(p, opts) { - return await new Promise((resolve, reject) => { - if (opts) { - this.realFs.lstat(npath.fromPortablePath(p), opts, this.makeCallback(resolve, reject)); - } else { - this.realFs.lstat(npath.fromPortablePath(p), this.makeCallback(resolve, reject)); - } - }); - } - lstatSync(p, opts) { - if (opts) { - return this.realFs.lstatSync(npath.fromPortablePath(p), opts); - } else { - return this.realFs.lstatSync(npath.fromPortablePath(p)); - } - } - async fchmodPromise(fd, mask) { - return await new Promise((resolve, reject) => { - this.realFs.fchmod(fd, mask, this.makeCallback(resolve, reject)); - }); - } - fchmodSync(fd, mask) { - return this.realFs.fchmodSync(fd, mask); - } - async chmodPromise(p, mask) { - return await new Promise((resolve, reject) => { - this.realFs.chmod(npath.fromPortablePath(p), mask, this.makeCallback(resolve, reject)); - }); - } - chmodSync(p, mask) { - return this.realFs.chmodSync(npath.fromPortablePath(p), mask); - } - async fchownPromise(fd, uid, gid) { - return await new Promise((resolve, reject) => { - this.realFs.fchown(fd, uid, gid, this.makeCallback(resolve, reject)); - }); - } - fchownSync(fd, uid, gid) { - return this.realFs.fchownSync(fd, uid, gid); - } - async chownPromise(p, uid, gid) { - return await new Promise((resolve, reject) => { - this.realFs.chown(npath.fromPortablePath(p), uid, gid, this.makeCallback(resolve, reject)); - }); - } - chownSync(p, uid, gid) { - return this.realFs.chownSync(npath.fromPortablePath(p), uid, gid); - } - async renamePromise(oldP, newP) { - return await new Promise((resolve, reject) => { - this.realFs.rename(npath.fromPortablePath(oldP), npath.fromPortablePath(newP), this.makeCallback(resolve, reject)); - }); - } - renameSync(oldP, newP) { - return this.realFs.renameSync(npath.fromPortablePath(oldP), npath.fromPortablePath(newP)); - } - async copyFilePromise(sourceP, destP, flags = 0) { - return await new Promise((resolve, reject) => { - this.realFs.copyFile(npath.fromPortablePath(sourceP), npath.fromPortablePath(destP), flags, this.makeCallback(resolve, reject)); - }); - } - copyFileSync(sourceP, destP, flags = 0) { - return this.realFs.copyFileSync(npath.fromPortablePath(sourceP), npath.fromPortablePath(destP), flags); - } - async appendFilePromise(p, content, opts) { - return await new Promise((resolve, reject) => { - const fsNativePath = typeof p === `string` ? npath.fromPortablePath(p) : p; - if (opts) { - this.realFs.appendFile(fsNativePath, content, opts, this.makeCallback(resolve, reject)); - } else { - this.realFs.appendFile(fsNativePath, content, this.makeCallback(resolve, reject)); - } - }); - } - appendFileSync(p, content, opts) { - const fsNativePath = typeof p === `string` ? npath.fromPortablePath(p) : p; - if (opts) { - this.realFs.appendFileSync(fsNativePath, content, opts); - } else { - this.realFs.appendFileSync(fsNativePath, content); - } - } - async writeFilePromise(p, content, opts) { - return await new Promise((resolve, reject) => { - const fsNativePath = typeof p === `string` ? npath.fromPortablePath(p) : p; - if (opts) { - this.realFs.writeFile(fsNativePath, content, opts, this.makeCallback(resolve, reject)); - } else { - this.realFs.writeFile(fsNativePath, content, this.makeCallback(resolve, reject)); - } - }); - } - writeFileSync(p, content, opts) { - const fsNativePath = typeof p === `string` ? npath.fromPortablePath(p) : p; - if (opts) { - this.realFs.writeFileSync(fsNativePath, content, opts); - } else { - this.realFs.writeFileSync(fsNativePath, content); - } - } - async unlinkPromise(p) { - return await new Promise((resolve, reject) => { - this.realFs.unlink(npath.fromPortablePath(p), this.makeCallback(resolve, reject)); - }); - } - unlinkSync(p) { - return this.realFs.unlinkSync(npath.fromPortablePath(p)); - } - async utimesPromise(p, atime, mtime) { - return await new Promise((resolve, reject) => { - this.realFs.utimes(npath.fromPortablePath(p), atime, mtime, this.makeCallback(resolve, reject)); - }); - } - utimesSync(p, atime, mtime) { - this.realFs.utimesSync(npath.fromPortablePath(p), atime, mtime); - } - async lutimesPromiseImpl(p, atime, mtime) { - const lutimes = this.realFs.lutimes; - if (typeof lutimes === `undefined`) - throw ENOSYS(`unavailable Node binding`, `lutimes '${p}'`); - return await new Promise((resolve, reject) => { - lutimes.call(this.realFs, npath.fromPortablePath(p), atime, mtime, this.makeCallback(resolve, reject)); - }); - } - lutimesSyncImpl(p, atime, mtime) { - const lutimesSync = this.realFs.lutimesSync; - if (typeof lutimesSync === `undefined`) - throw ENOSYS(`unavailable Node binding`, `lutimes '${p}'`); - lutimesSync.call(this.realFs, npath.fromPortablePath(p), atime, mtime); - } - async mkdirPromise(p, opts) { - return await new Promise((resolve, reject) => { - this.realFs.mkdir(npath.fromPortablePath(p), opts, this.makeCallback(resolve, reject)); - }); - } - mkdirSync(p, opts) { - return this.realFs.mkdirSync(npath.fromPortablePath(p), opts); - } - async rmdirPromise(p, opts) { - return await new Promise((resolve, reject) => { - if (opts) { - this.realFs.rmdir(npath.fromPortablePath(p), opts, this.makeCallback(resolve, reject)); - } else { - this.realFs.rmdir(npath.fromPortablePath(p), this.makeCallback(resolve, reject)); - } - }); - } - rmdirSync(p, opts) { - return this.realFs.rmdirSync(npath.fromPortablePath(p), opts); - } - async linkPromise(existingP, newP) { - return await new Promise((resolve, reject) => { - this.realFs.link(npath.fromPortablePath(existingP), npath.fromPortablePath(newP), this.makeCallback(resolve, reject)); - }); - } - linkSync(existingP, newP) { - return this.realFs.linkSync(npath.fromPortablePath(existingP), npath.fromPortablePath(newP)); - } - async symlinkPromise(target, p, type) { - return await new Promise((resolve, reject) => { - this.realFs.symlink(npath.fromPortablePath(target.replace(/\/+$/, ``)), npath.fromPortablePath(p), type, this.makeCallback(resolve, reject)); - }); - } - symlinkSync(target, p, type) { - return this.realFs.symlinkSync(npath.fromPortablePath(target.replace(/\/+$/, ``)), npath.fromPortablePath(p), type); - } - async readFilePromise(p, encoding) { - return await new Promise((resolve, reject) => { - const fsNativePath = typeof p === `string` ? npath.fromPortablePath(p) : p; - this.realFs.readFile(fsNativePath, encoding, this.makeCallback(resolve, reject)); - }); - } - readFileSync(p, encoding) { - const fsNativePath = typeof p === `string` ? npath.fromPortablePath(p) : p; - return this.realFs.readFileSync(fsNativePath, encoding); - } - async readdirPromise(p, opts) { - return await new Promise((resolve, reject) => { - if (opts == null ? void 0 : opts.withFileTypes) { - this.realFs.readdir(npath.fromPortablePath(p), { withFileTypes: true }, this.makeCallback(resolve, reject)); - } else { - this.realFs.readdir(npath.fromPortablePath(p), this.makeCallback((value) => resolve(value), reject)); - } - }); - } - readdirSync(p, opts) { - if (opts == null ? void 0 : opts.withFileTypes) { - return this.realFs.readdirSync(npath.fromPortablePath(p), { withFileTypes: true }); - } else { - return this.realFs.readdirSync(npath.fromPortablePath(p)); - } - } - async readlinkPromise(p) { - return await new Promise((resolve, reject) => { - this.realFs.readlink(npath.fromPortablePath(p), this.makeCallback(resolve, reject)); - }).then((path) => { - return npath.toPortablePath(path); - }); - } - readlinkSync(p) { - return npath.toPortablePath(this.realFs.readlinkSync(npath.fromPortablePath(p))); - } - async truncatePromise(p, len) { - return await new Promise((resolve, reject) => { - this.realFs.truncate(npath.fromPortablePath(p), len, this.makeCallback(resolve, reject)); - }); - } - truncateSync(p, len) { - return this.realFs.truncateSync(npath.fromPortablePath(p), len); - } - async ftruncatePromise(fd, len) { - return await new Promise((resolve, reject) => { - this.realFs.ftruncate(fd, len, this.makeCallback(resolve, reject)); - }); - } - ftruncateSync(fd, len) { - return this.realFs.ftruncateSync(fd, len); - } - watch(p, a, b) { - return this.realFs.watch( - npath.fromPortablePath(p), - a, - b - ); - } - watchFile(p, a, b) { - return this.realFs.watchFile( - npath.fromPortablePath(p), - a, - b - ); - } - unwatchFile(p, cb) { - return this.realFs.unwatchFile(npath.fromPortablePath(p), cb); - } - makeCallback(resolve, reject) { - return (err, result) => { - if (err) { - reject(err); - } else { - resolve(result); - } - }; - } -} - -function assertStatus(current, expected) { - if (current !== expected) { - throw new Error(`Invalid StatWatcher status: expected '${expected}', got '${current}'`); - } -} -class CustomStatWatcher extends events.EventEmitter { - constructor(fakeFs, path, { bigint = false } = {}) { - super(); - this.status = "ready" /* Ready */; - this.changeListeners = /* @__PURE__ */ new Map(); - this.startTimeout = null; - this.fakeFs = fakeFs; - this.path = path; - this.bigint = bigint; - this.lastStats = this.stat(); - } - static create(fakeFs, path, opts) { - const statWatcher = new CustomStatWatcher(fakeFs, path, opts); - statWatcher.start(); - return statWatcher; - } - start() { - assertStatus(this.status, "ready" /* Ready */); - this.status = "running" /* Running */; - this.startTimeout = setTimeout(() => { - this.startTimeout = null; - if (!this.fakeFs.existsSync(this.path)) { - this.emit("change" /* Change */, this.lastStats, this.lastStats); - } - }, 3); - } - stop() { - assertStatus(this.status, "running" /* Running */); - this.status = "stopped" /* Stopped */; - if (this.startTimeout !== null) { - clearTimeout(this.startTimeout); - this.startTimeout = null; - } - this.emit("stop" /* Stop */); - } - stat() { - try { - return this.fakeFs.statSync(this.path, { bigint: this.bigint }); - } catch (error) { - const statInstance = this.bigint ? new BigIntStatsEntry() : new StatEntry(); - return clearStats(statInstance); - } - } - makeInterval(opts) { - const interval = setInterval(() => { - const currentStats = this.stat(); - const previousStats = this.lastStats; - if (areStatsEqual(currentStats, previousStats)) - return; - this.lastStats = currentStats; - this.emit("change" /* Change */, currentStats, previousStats); - }, opts.interval); - return opts.persistent ? interval : interval.unref(); - } - registerChangeListener(listener, opts) { - this.addListener("change" /* Change */, listener); - this.changeListeners.set(listener, this.makeInterval(opts)); - } - unregisterChangeListener(listener) { - this.removeListener("change" /* Change */, listener); - const interval = this.changeListeners.get(listener); - if (typeof interval !== `undefined`) - clearInterval(interval); - this.changeListeners.delete(listener); - } - unregisterAllChangeListeners() { - for (const listener of this.changeListeners.keys()) { - this.unregisterChangeListener(listener); - } - } - hasChangeListeners() { - return this.changeListeners.size > 0; - } - ref() { - for (const interval of this.changeListeners.values()) - interval.ref(); - return this; - } - unref() { - for (const interval of this.changeListeners.values()) - interval.unref(); - return this; - } -} - -const statWatchersByFakeFS = /* @__PURE__ */ new WeakMap(); -function watchFile(fakeFs, path, a, b) { - let bigint; - let persistent; - let interval; - let listener; - switch (typeof a) { - case `function`: - { - bigint = false; - persistent = true; - interval = 5007; - listener = a; - } - break; - default: - { - ({ - bigint = false, - persistent = true, - interval = 5007 - } = a); - listener = b; - } - break; - } - let statWatchers = statWatchersByFakeFS.get(fakeFs); - if (typeof statWatchers === `undefined`) - statWatchersByFakeFS.set(fakeFs, statWatchers = /* @__PURE__ */ new Map()); - let statWatcher = statWatchers.get(path); - if (typeof statWatcher === `undefined`) { - statWatcher = CustomStatWatcher.create(fakeFs, path, { bigint }); - statWatchers.set(path, statWatcher); - } - statWatcher.registerChangeListener(listener, { persistent, interval }); - return statWatcher; -} -function unwatchFile(fakeFs, path, cb) { - const statWatchers = statWatchersByFakeFS.get(fakeFs); - if (typeof statWatchers === `undefined`) - return; - const statWatcher = statWatchers.get(path); - if (typeof statWatcher === `undefined`) - return; - if (typeof cb === `undefined`) - statWatcher.unregisterAllChangeListeners(); - else - statWatcher.unregisterChangeListener(cb); - if (!statWatcher.hasChangeListeners()) { - statWatcher.stop(); - statWatchers.delete(path); - } -} -function unwatchAllFiles(fakeFs) { - const statWatchers = statWatchersByFakeFS.get(fakeFs); - if (typeof statWatchers === `undefined`) - return; - for (const path of statWatchers.keys()) { - unwatchFile(fakeFs, path); - } -} - -const DEFAULT_COMPRESSION_LEVEL = `mixed`; -function toUnixTimestamp(time) { - if (typeof time === `string` && String(+time) === time) - return +time; - if (Number.isFinite(time)) { - if (time < 0) { - return Date.now() / 1e3; - } else { - return time; - } - } - if (nodeUtils.types.isDate(time)) - return time.getTime() / 1e3; - throw new Error(`Invalid time`); -} -function makeEmptyArchive() { - return Buffer.from([ - 80, - 75, - 5, - 6, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0 - ]); -} -class ZipFS extends BasePortableFakeFS { - constructor(source, opts) { - super(); - this.lzSource = null; - this.listings = /* @__PURE__ */ new Map(); - this.entries = /* @__PURE__ */ new Map(); - this.fileSources = /* @__PURE__ */ new Map(); - this.fds = /* @__PURE__ */ new Map(); - this.nextFd = 0; - this.ready = false; - this.readOnly = false; - this.libzip = opts.libzip; - const pathOptions = opts; - this.level = typeof pathOptions.level !== `undefined` ? pathOptions.level : DEFAULT_COMPRESSION_LEVEL; - source != null ? source : source = makeEmptyArchive(); - if (typeof source === `string`) { - const { baseFs = new NodeFS() } = pathOptions; - this.baseFs = baseFs; - this.path = source; - } else { - this.path = null; - this.baseFs = null; - } - if (opts.stats) { - this.stats = opts.stats; - } else { - if (typeof source === `string`) { - try { - this.stats = this.baseFs.statSync(source); - } catch (error) { - if (error.code === `ENOENT` && pathOptions.create) { - this.stats = makeDefaultStats(); - } else { - throw error; - } - } - } else { - this.stats = makeDefaultStats(); - } - } - const errPtr = this.libzip.malloc(4); - try { - let flags = 0; - if (typeof source === `string` && pathOptions.create) - flags |= this.libzip.ZIP_CREATE | this.libzip.ZIP_TRUNCATE; - if (opts.readOnly) { - flags |= this.libzip.ZIP_RDONLY; - this.readOnly = true; - } - if (typeof source === `string`) { - this.zip = this.libzip.open(npath.fromPortablePath(source), flags, errPtr); - } else { - const lzSource = this.allocateUnattachedSource(source); - try { - this.zip = this.libzip.openFromSource(lzSource, flags, errPtr); - this.lzSource = lzSource; - } catch (error) { - this.libzip.source.free(lzSource); - throw error; - } - } - if (this.zip === 0) { - const error = this.libzip.struct.errorS(); - this.libzip.error.initWithCode(error, this.libzip.getValue(errPtr, `i32`)); - throw this.makeLibzipError(error); - } - } finally { - this.libzip.free(errPtr); - } - this.listings.set(PortablePath.root, /* @__PURE__ */ new Set()); - const entryCount = this.libzip.getNumEntries(this.zip, 0); - for (let t = 0; t < entryCount; ++t) { - const raw = this.libzip.getName(this.zip, t, 0); - if (ppath.isAbsolute(raw)) - continue; - const p = ppath.resolve(PortablePath.root, raw); - this.registerEntry(p, t); - if (raw.endsWith(`/`)) { - this.registerListing(p); - } - } - this.symlinkCount = this.libzip.ext.countSymlinks(this.zip); - if (this.symlinkCount === -1) - throw this.makeLibzipError(this.libzip.getError(this.zip)); - this.ready = true; - } - makeLibzipError(error) { - const errorCode = this.libzip.struct.errorCodeZip(error); - const strerror = this.libzip.error.strerror(error); - const libzipError = new LibzipError(strerror, this.libzip.errors[errorCode]); - if (errorCode === this.libzip.errors.ZIP_ER_CHANGED) - throw new Error(`Assertion failed: Unexpected libzip error: ${libzipError.message}`); - return libzipError; - } - getExtractHint(hints) { - for (const fileName of this.entries.keys()) { - const ext = this.pathUtils.extname(fileName); - if (hints.relevantExtensions.has(ext)) { - return true; - } - } - return false; - } - getAllFiles() { - return Array.from(this.entries.keys()); - } - getRealPath() { - if (!this.path) - throw new Error(`ZipFS don't have real paths when loaded from a buffer`); - return this.path; - } - getBufferAndClose() { - this.prepareClose(); - if (!this.lzSource) - throw new Error(`ZipFS was not created from a Buffer`); - try { - this.libzip.source.keep(this.lzSource); - if (this.libzip.close(this.zip) === -1) - throw this.makeLibzipError(this.libzip.getError(this.zip)); - if (this.libzip.source.open(this.lzSource) === -1) - throw this.makeLibzipError(this.libzip.source.error(this.lzSource)); - if (this.libzip.source.seek(this.lzSource, 0, 0, this.libzip.SEEK_END) === -1) - throw this.makeLibzipError(this.libzip.source.error(this.lzSource)); - const size = this.libzip.source.tell(this.lzSource); - if (size === -1) - throw this.makeLibzipError(this.libzip.source.error(this.lzSource)); - if (this.libzip.source.seek(this.lzSource, 0, 0, this.libzip.SEEK_SET) === -1) - throw this.makeLibzipError(this.libzip.source.error(this.lzSource)); - const buffer = this.libzip.malloc(size); - if (!buffer) - throw new Error(`Couldn't allocate enough memory`); - try { - const rc = this.libzip.source.read(this.lzSource, buffer, size); - if (rc === -1) - throw this.makeLibzipError(this.libzip.source.error(this.lzSource)); - else if (rc < size) - throw new Error(`Incomplete read`); - else if (rc > size) - throw new Error(`Overread`); - const memory = this.libzip.HEAPU8.subarray(buffer, buffer + size); - return Buffer.from(memory); - } finally { - this.libzip.free(buffer); - } - } finally { - this.libzip.source.close(this.lzSource); - this.libzip.source.free(this.lzSource); - this.ready = false; - } - } - prepareClose() { - if (!this.ready) - throw EBUSY(`archive closed, close`); - unwatchAllFiles(this); - } - saveAndClose() { - if (!this.path || !this.baseFs) - throw new Error(`ZipFS cannot be saved and must be discarded when loaded from a buffer`); - this.prepareClose(); - if (this.readOnly) { - this.discardAndClose(); - return; - } - const newMode = this.baseFs.existsSync(this.path) || this.stats.mode === DEFAULT_MODE ? void 0 : this.stats.mode; - if (this.entries.size === 0) { - this.discardAndClose(); - this.baseFs.writeFileSync(this.path, makeEmptyArchive(), { mode: newMode }); - } else { - const rc = this.libzip.close(this.zip); - if (rc === -1) - throw this.makeLibzipError(this.libzip.getError(this.zip)); - if (typeof newMode !== `undefined`) { - this.baseFs.chmodSync(this.path, newMode); - } - } - this.ready = false; - } - discardAndClose() { - this.prepareClose(); - this.libzip.discard(this.zip); - this.ready = false; - } - resolve(p) { - return ppath.resolve(PortablePath.root, p); - } - async openPromise(p, flags, mode) { - return this.openSync(p, flags, mode); - } - openSync(p, flags, mode) { - const fd = this.nextFd++; - this.fds.set(fd, { cursor: 0, p }); - return fd; - } - hasOpenFileHandles() { - return !!this.fds.size; - } - async opendirPromise(p, opts) { - return this.opendirSync(p, opts); - } - opendirSync(p, opts = {}) { - const resolvedP = this.resolveFilename(`opendir '${p}'`, p); - if (!this.entries.has(resolvedP) && !this.listings.has(resolvedP)) - throw ENOENT(`opendir '${p}'`); - const directoryListing = this.listings.get(resolvedP); - if (!directoryListing) - throw ENOTDIR(`opendir '${p}'`); - const entries = [...directoryListing]; - const fd = this.openSync(resolvedP, `r`); - const onClose = () => { - this.closeSync(fd); - }; - return opendir(this, resolvedP, entries, { onClose }); - } - async readPromise(fd, buffer, offset, length, position) { - return this.readSync(fd, buffer, offset, length, position); - } - readSync(fd, buffer, offset = 0, length = buffer.byteLength, position = -1) { - const entry = this.fds.get(fd); - if (typeof entry === `undefined`) - throw EBADF(`read`); - const realPosition = position === -1 || position === null ? entry.cursor : position; - const source = this.readFileSync(entry.p); - source.copy(buffer, offset, realPosition, realPosition + length); - const bytesRead = Math.max(0, Math.min(source.length - realPosition, length)); - if (position === -1 || position === null) - entry.cursor += bytesRead; - return bytesRead; - } - async writePromise(fd, buffer, offset, length, position) { - if (typeof buffer === `string`) { - return this.writeSync(fd, buffer, position); - } else { - return this.writeSync(fd, buffer, offset, length, position); - } - } - writeSync(fd, buffer, offset, length, position) { - const entry = this.fds.get(fd); - if (typeof entry === `undefined`) - throw EBADF(`read`); - throw new Error(`Unimplemented`); - } - async closePromise(fd) { - return this.closeSync(fd); - } - closeSync(fd) { - const entry = this.fds.get(fd); - if (typeof entry === `undefined`) - throw EBADF(`read`); - this.fds.delete(fd); - } - createReadStream(p, { encoding } = {}) { - if (p === null) - throw new Error(`Unimplemented`); - const fd = this.openSync(p, `r`); - const stream$1 = Object.assign( - new stream.PassThrough({ - emitClose: true, - autoDestroy: true, - destroy: (error, callback) => { - clearImmediate(immediate); - this.closeSync(fd); - callback(error); - } - }), - { - close() { - stream$1.destroy(); - }, - bytesRead: 0, - path: p - } - ); - const immediate = setImmediate(async () => { - try { - const data = await this.readFilePromise(p, encoding); - stream$1.bytesRead = data.length; - stream$1.end(data); - } catch (error) { - stream$1.destroy(error); - } - }); - return stream$1; - } - createWriteStream(p, { encoding } = {}) { - if (this.readOnly) - throw EROFS(`open '${p}'`); - if (p === null) - throw new Error(`Unimplemented`); - const chunks = []; - const fd = this.openSync(p, `w`); - const stream$1 = Object.assign( - new stream.PassThrough({ - autoDestroy: true, - emitClose: true, - destroy: (error, callback) => { - try { - if (error) { - callback(error); - } else { - this.writeFileSync(p, Buffer.concat(chunks), encoding); - callback(null); - } - } catch (err) { - callback(err); - } finally { - this.closeSync(fd); - } - } - }), - { - bytesWritten: 0, - path: p, - close() { - stream$1.destroy(); - } - } - ); - stream$1.on(`data`, (chunk) => { - const chunkBuffer = Buffer.from(chunk); - stream$1.bytesWritten += chunkBuffer.length; - chunks.push(chunkBuffer); - }); - return stream$1; - } - async realpathPromise(p) { - return this.realpathSync(p); - } - realpathSync(p) { - const resolvedP = this.resolveFilename(`lstat '${p}'`, p); - if (!this.entries.has(resolvedP) && !this.listings.has(resolvedP)) - throw ENOENT(`lstat '${p}'`); - return resolvedP; - } - async existsPromise(p) { - return this.existsSync(p); - } - existsSync(p) { - if (!this.ready) - throw EBUSY(`archive closed, existsSync '${p}'`); - if (this.symlinkCount === 0) { - const resolvedP2 = ppath.resolve(PortablePath.root, p); - return this.entries.has(resolvedP2) || this.listings.has(resolvedP2); - } - let resolvedP; - try { - resolvedP = this.resolveFilename(`stat '${p}'`, p, void 0, false); - } catch (error) { - return false; - } - if (resolvedP === void 0) - return false; - return this.entries.has(resolvedP) || this.listings.has(resolvedP); - } - async accessPromise(p, mode) { - return this.accessSync(p, mode); - } - accessSync(p, mode = fs.constants.F_OK) { - const resolvedP = this.resolveFilename(`access '${p}'`, p); - if (!this.entries.has(resolvedP) && !this.listings.has(resolvedP)) - throw ENOENT(`access '${p}'`); - if (this.readOnly && mode & fs.constants.W_OK) { - throw EROFS(`access '${p}'`); - } - } - async statPromise(p, opts = { bigint: false }) { - if (opts.bigint) - return this.statSync(p, { bigint: true }); - return this.statSync(p); - } - statSync(p, opts = { bigint: false, throwIfNoEntry: true }) { - const resolvedP = this.resolveFilename(`stat '${p}'`, p, void 0, opts.throwIfNoEntry); - if (resolvedP === void 0) - return void 0; - if (!this.entries.has(resolvedP) && !this.listings.has(resolvedP)) { - if (opts.throwIfNoEntry === false) - return void 0; - throw ENOENT(`stat '${p}'`); - } - if (p[p.length - 1] === `/` && !this.listings.has(resolvedP)) - throw ENOTDIR(`stat '${p}'`); - return this.statImpl(`stat '${p}'`, resolvedP, opts); - } - async fstatPromise(fd, opts) { - return this.fstatSync(fd, opts); - } - fstatSync(fd, opts) { - const entry = this.fds.get(fd); - if (typeof entry === `undefined`) - throw EBADF(`fstatSync`); - const { p } = entry; - const resolvedP = this.resolveFilename(`stat '${p}'`, p); - if (!this.entries.has(resolvedP) && !this.listings.has(resolvedP)) - throw ENOENT(`stat '${p}'`); - if (p[p.length - 1] === `/` && !this.listings.has(resolvedP)) - throw ENOTDIR(`stat '${p}'`); - return this.statImpl(`fstat '${p}'`, resolvedP, opts); - } - async lstatPromise(p, opts = { bigint: false }) { - if (opts.bigint) - return this.lstatSync(p, { bigint: true }); - return this.lstatSync(p); - } - lstatSync(p, opts = { bigint: false, throwIfNoEntry: true }) { - const resolvedP = this.resolveFilename(`lstat '${p}'`, p, false, opts.throwIfNoEntry); - if (resolvedP === void 0) - return void 0; - if (!this.entries.has(resolvedP) && !this.listings.has(resolvedP)) { - if (opts.throwIfNoEntry === false) - return void 0; - throw ENOENT(`lstat '${p}'`); - } - if (p[p.length - 1] === `/` && !this.listings.has(resolvedP)) - throw ENOTDIR(`lstat '${p}'`); - return this.statImpl(`lstat '${p}'`, resolvedP, opts); - } - statImpl(reason, p, opts = {}) { - const entry = this.entries.get(p); - if (typeof entry !== `undefined`) { - const stat = this.libzip.struct.statS(); - const rc = this.libzip.statIndex(this.zip, entry, 0, 0, stat); - if (rc === -1) - throw this.makeLibzipError(this.libzip.getError(this.zip)); - const uid = this.stats.uid; - const gid = this.stats.gid; - const size = this.libzip.struct.statSize(stat) >>> 0; - const blksize = 512; - const blocks = Math.ceil(size / blksize); - const mtimeMs = (this.libzip.struct.statMtime(stat) >>> 0) * 1e3; - const atimeMs = mtimeMs; - const birthtimeMs = mtimeMs; - const ctimeMs = mtimeMs; - const atime = new Date(atimeMs); - const birthtime = new Date(birthtimeMs); - const ctime = new Date(ctimeMs); - const mtime = new Date(mtimeMs); - const type = this.listings.has(p) ? S_IFDIR : this.isSymbolicLink(entry) ? S_IFLNK : S_IFREG; - const defaultMode = type === S_IFDIR ? 493 : 420; - const mode = type | this.getUnixMode(entry, defaultMode) & 511; - const crc = this.libzip.struct.statCrc(stat); - const statInstance = Object.assign(new StatEntry(), { uid, gid, size, blksize, blocks, atime, birthtime, ctime, mtime, atimeMs, birthtimeMs, ctimeMs, mtimeMs, mode, crc }); - return opts.bigint === true ? convertToBigIntStats(statInstance) : statInstance; - } - if (this.listings.has(p)) { - const uid = this.stats.uid; - const gid = this.stats.gid; - const size = 0; - const blksize = 512; - const blocks = 0; - const atimeMs = this.stats.mtimeMs; - const birthtimeMs = this.stats.mtimeMs; - const ctimeMs = this.stats.mtimeMs; - const mtimeMs = this.stats.mtimeMs; - const atime = new Date(atimeMs); - const birthtime = new Date(birthtimeMs); - const ctime = new Date(ctimeMs); - const mtime = new Date(mtimeMs); - const mode = S_IFDIR | 493; - const crc = 0; - const statInstance = Object.assign(new StatEntry(), { uid, gid, size, blksize, blocks, atime, birthtime, ctime, mtime, atimeMs, birthtimeMs, ctimeMs, mtimeMs, mode, crc }); - return opts.bigint === true ? convertToBigIntStats(statInstance) : statInstance; - } - throw new Error(`Unreachable`); - } - getUnixMode(index, defaultMode) { - const rc = this.libzip.file.getExternalAttributes(this.zip, index, 0, 0, this.libzip.uint08S, this.libzip.uint32S); - if (rc === -1) - throw this.makeLibzipError(this.libzip.getError(this.zip)); - const opsys = this.libzip.getValue(this.libzip.uint08S, `i8`) >>> 0; - if (opsys !== this.libzip.ZIP_OPSYS_UNIX) - return defaultMode; - return this.libzip.getValue(this.libzip.uint32S, `i32`) >>> 16; - } - registerListing(p) { - const existingListing = this.listings.get(p); - if (existingListing) - return existingListing; - const parentListing = this.registerListing(ppath.dirname(p)); - parentListing.add(ppath.basename(p)); - const newListing = /* @__PURE__ */ new Set(); - this.listings.set(p, newListing); - return newListing; - } - registerEntry(p, index) { - const parentListing = this.registerListing(ppath.dirname(p)); - parentListing.add(ppath.basename(p)); - this.entries.set(p, index); - } - unregisterListing(p) { - this.listings.delete(p); - const parentListing = this.listings.get(ppath.dirname(p)); - parentListing == null ? void 0 : parentListing.delete(ppath.basename(p)); - } - unregisterEntry(p) { - this.unregisterListing(p); - const entry = this.entries.get(p); - this.entries.delete(p); - if (typeof entry === `undefined`) - return; - this.fileSources.delete(entry); - if (this.isSymbolicLink(entry)) { - this.symlinkCount--; - } - } - deleteEntry(p, index) { - this.unregisterEntry(p); - const rc = this.libzip.delete(this.zip, index); - if (rc === -1) { - throw this.makeLibzipError(this.libzip.getError(this.zip)); - } - } - resolveFilename(reason, p, resolveLastComponent = true, throwIfNoEntry = true) { - if (!this.ready) - throw EBUSY(`archive closed, ${reason}`); - let resolvedP = ppath.resolve(PortablePath.root, p); - if (resolvedP === `/`) - return PortablePath.root; - const fileIndex = this.entries.get(resolvedP); - if (resolveLastComponent && fileIndex !== void 0) { - if (this.symlinkCount !== 0 && this.isSymbolicLink(fileIndex)) { - const target = this.getFileSource(fileIndex).toString(); - return this.resolveFilename(reason, ppath.resolve(ppath.dirname(resolvedP), target), true, throwIfNoEntry); - } else { - return resolvedP; - } - } - while (true) { - const parentP = this.resolveFilename(reason, ppath.dirname(resolvedP), true, throwIfNoEntry); - if (parentP === void 0) - return parentP; - const isDir = this.listings.has(parentP); - const doesExist = this.entries.has(parentP); - if (!isDir && !doesExist) { - if (throwIfNoEntry === false) - return void 0; - throw ENOENT(reason); - } - if (!isDir) - throw ENOTDIR(reason); - resolvedP = ppath.resolve(parentP, ppath.basename(resolvedP)); - if (!resolveLastComponent || this.symlinkCount === 0) - break; - const index = this.libzip.name.locate(this.zip, resolvedP.slice(1)); - if (index === -1) - break; - if (this.isSymbolicLink(index)) { - const target = this.getFileSource(index).toString(); - resolvedP = ppath.resolve(ppath.dirname(resolvedP), target); - } else { - break; - } - } - return resolvedP; - } - allocateBuffer(content) { - if (!Buffer.isBuffer(content)) - content = Buffer.from(content); - const buffer = this.libzip.malloc(content.byteLength); - if (!buffer) - throw new Error(`Couldn't allocate enough memory`); - const heap = new Uint8Array(this.libzip.HEAPU8.buffer, buffer, content.byteLength); - heap.set(content); - return { buffer, byteLength: content.byteLength }; - } - allocateUnattachedSource(content) { - const error = this.libzip.struct.errorS(); - const { buffer, byteLength } = this.allocateBuffer(content); - const source = this.libzip.source.fromUnattachedBuffer(buffer, byteLength, 0, true, error); - if (source === 0) { - this.libzip.free(error); - throw this.makeLibzipError(error); - } - return source; - } - allocateSource(content) { - const { buffer, byteLength } = this.allocateBuffer(content); - const source = this.libzip.source.fromBuffer(this.zip, buffer, byteLength, 0, true); - if (source === 0) { - this.libzip.free(buffer); - throw this.makeLibzipError(this.libzip.getError(this.zip)); - } - return source; - } - setFileSource(p, content) { - const buffer = Buffer.isBuffer(content) ? content : Buffer.from(content); - const target = ppath.relative(PortablePath.root, p); - const lzSource = this.allocateSource(content); - try { - const newIndex = this.libzip.file.add(this.zip, target, lzSource, this.libzip.ZIP_FL_OVERWRITE); - if (newIndex === -1) - throw this.makeLibzipError(this.libzip.getError(this.zip)); - if (this.level !== `mixed`) { - const method = this.level === 0 ? this.libzip.ZIP_CM_STORE : this.libzip.ZIP_CM_DEFLATE; - const rc = this.libzip.file.setCompression(this.zip, newIndex, 0, method, this.level); - if (rc === -1) { - throw this.makeLibzipError(this.libzip.getError(this.zip)); - } - } - this.fileSources.set(newIndex, buffer); - return newIndex; - } catch (error) { - this.libzip.source.free(lzSource); - throw error; - } - } - isSymbolicLink(index) { - if (this.symlinkCount === 0) - return false; - const attrs = this.libzip.file.getExternalAttributes(this.zip, index, 0, 0, this.libzip.uint08S, this.libzip.uint32S); - if (attrs === -1) - throw this.makeLibzipError(this.libzip.getError(this.zip)); - const opsys = this.libzip.getValue(this.libzip.uint08S, `i8`) >>> 0; - if (opsys !== this.libzip.ZIP_OPSYS_UNIX) - return false; - const attributes = this.libzip.getValue(this.libzip.uint32S, `i32`) >>> 16; - return (attributes & S_IFMT) === S_IFLNK; - } - getFileSource(index, opts = { asyncDecompress: false }) { - const cachedFileSource = this.fileSources.get(index); - if (typeof cachedFileSource !== `undefined`) - return cachedFileSource; - const stat = this.libzip.struct.statS(); - const rc = this.libzip.statIndex(this.zip, index, 0, 0, stat); - if (rc === -1) - throw this.makeLibzipError(this.libzip.getError(this.zip)); - const size = this.libzip.struct.statCompSize(stat); - const compressionMethod = this.libzip.struct.statCompMethod(stat); - const buffer = this.libzip.malloc(size); - try { - const file = this.libzip.fopenIndex(this.zip, index, 0, this.libzip.ZIP_FL_COMPRESSED); - if (file === 0) - throw this.makeLibzipError(this.libzip.getError(this.zip)); - try { - const rc2 = this.libzip.fread(file, buffer, size, 0); - if (rc2 === -1) - throw this.makeLibzipError(this.libzip.file.getError(file)); - else if (rc2 < size) - throw new Error(`Incomplete read`); - else if (rc2 > size) - throw new Error(`Overread`); - const memory = this.libzip.HEAPU8.subarray(buffer, buffer + size); - const data = Buffer.from(memory); - if (compressionMethod === 0) { - this.fileSources.set(index, data); - return data; - } else if (opts.asyncDecompress) { - return new Promise((resolve, reject) => { - zlib__default.default.inflateRaw(data, (error, result) => { - if (error) { - reject(error); - } else { - this.fileSources.set(index, result); - resolve(result); - } - }); - }); - } else { - const decompressedData = zlib__default.default.inflateRawSync(data); - this.fileSources.set(index, decompressedData); - return decompressedData; - } - } finally { - this.libzip.fclose(file); - } - } finally { - this.libzip.free(buffer); - } - } - async fchmodPromise(fd, mask) { - return this.chmodPromise(this.fdToPath(fd, `fchmod`), mask); - } - fchmodSync(fd, mask) { - return this.chmodSync(this.fdToPath(fd, `fchmodSync`), mask); - } - async chmodPromise(p, mask) { - return this.chmodSync(p, mask); - } - chmodSync(p, mask) { - if (this.readOnly) - throw EROFS(`chmod '${p}'`); - mask &= 493; - const resolvedP = this.resolveFilename(`chmod '${p}'`, p, false); - const entry = this.entries.get(resolvedP); - if (typeof entry === `undefined`) - throw new Error(`Assertion failed: The entry should have been registered (${resolvedP})`); - const oldMod = this.getUnixMode(entry, S_IFREG | 0); - const newMod = oldMod & ~511 | mask; - const rc = this.libzip.file.setExternalAttributes(this.zip, entry, 0, 0, this.libzip.ZIP_OPSYS_UNIX, newMod << 16); - if (rc === -1) { - throw this.makeLibzipError(this.libzip.getError(this.zip)); - } - } - async fchownPromise(fd, uid, gid) { - return this.chownPromise(this.fdToPath(fd, `fchown`), uid, gid); - } - fchownSync(fd, uid, gid) { - return this.chownSync(this.fdToPath(fd, `fchownSync`), uid, gid); - } - async chownPromise(p, uid, gid) { - return this.chownSync(p, uid, gid); - } - chownSync(p, uid, gid) { - throw new Error(`Unimplemented`); - } - async renamePromise(oldP, newP) { - return this.renameSync(oldP, newP); - } - renameSync(oldP, newP) { - throw new Error(`Unimplemented`); - } - async copyFilePromise(sourceP, destP, flags) { - const { indexSource, indexDest, resolvedDestP } = this.prepareCopyFile(sourceP, destP, flags); - const source = await this.getFileSource(indexSource, { asyncDecompress: true }); - const newIndex = this.setFileSource(resolvedDestP, source); - if (newIndex !== indexDest) { - this.registerEntry(resolvedDestP, newIndex); - } - } - copyFileSync(sourceP, destP, flags = 0) { - const { indexSource, indexDest, resolvedDestP } = this.prepareCopyFile(sourceP, destP, flags); - const source = this.getFileSource(indexSource); - const newIndex = this.setFileSource(resolvedDestP, source); - if (newIndex !== indexDest) { - this.registerEntry(resolvedDestP, newIndex); - } - } - prepareCopyFile(sourceP, destP, flags = 0) { - if (this.readOnly) - throw EROFS(`copyfile '${sourceP} -> '${destP}'`); - if ((flags & fs.constants.COPYFILE_FICLONE_FORCE) !== 0) - throw ENOSYS(`unsupported clone operation`, `copyfile '${sourceP}' -> ${destP}'`); - const resolvedSourceP = this.resolveFilename(`copyfile '${sourceP} -> ${destP}'`, sourceP); - const indexSource = this.entries.get(resolvedSourceP); - if (typeof indexSource === `undefined`) - throw EINVAL(`copyfile '${sourceP}' -> '${destP}'`); - const resolvedDestP = this.resolveFilename(`copyfile '${sourceP}' -> ${destP}'`, destP); - const indexDest = this.entries.get(resolvedDestP); - if ((flags & (fs.constants.COPYFILE_EXCL | fs.constants.COPYFILE_FICLONE_FORCE)) !== 0 && typeof indexDest !== `undefined`) - throw EEXIST(`copyfile '${sourceP}' -> '${destP}'`); - return { - indexSource, - resolvedDestP, - indexDest - }; - } - async appendFilePromise(p, content, opts) { - if (this.readOnly) - throw EROFS(`open '${p}'`); - if (typeof opts === `undefined`) - opts = { flag: `a` }; - else if (typeof opts === `string`) - opts = { flag: `a`, encoding: opts }; - else if (typeof opts.flag === `undefined`) - opts = { flag: `a`, ...opts }; - return this.writeFilePromise(p, content, opts); - } - appendFileSync(p, content, opts = {}) { - if (this.readOnly) - throw EROFS(`open '${p}'`); - if (typeof opts === `undefined`) - opts = { flag: `a` }; - else if (typeof opts === `string`) - opts = { flag: `a`, encoding: opts }; - else if (typeof opts.flag === `undefined`) - opts = { flag: `a`, ...opts }; - return this.writeFileSync(p, content, opts); - } - fdToPath(fd, reason) { - var _a; - const path = (_a = this.fds.get(fd)) == null ? void 0 : _a.p; - if (typeof path === `undefined`) - throw EBADF(reason); - return path; - } - async writeFilePromise(p, content, opts) { - const { encoding, mode, index, resolvedP } = this.prepareWriteFile(p, opts); - if (index !== void 0 && typeof opts === `object` && opts.flag && opts.flag.includes(`a`)) - content = Buffer.concat([await this.getFileSource(index, { asyncDecompress: true }), Buffer.from(content)]); - if (encoding !== null) - content = content.toString(encoding); - const newIndex = this.setFileSource(resolvedP, content); - if (newIndex !== index) - this.registerEntry(resolvedP, newIndex); - if (mode !== null) { - await this.chmodPromise(resolvedP, mode); - } - } - writeFileSync(p, content, opts) { - const { encoding, mode, index, resolvedP } = this.prepareWriteFile(p, opts); - if (index !== void 0 && typeof opts === `object` && opts.flag && opts.flag.includes(`a`)) - content = Buffer.concat([this.getFileSource(index), Buffer.from(content)]); - if (encoding !== null) - content = content.toString(encoding); - const newIndex = this.setFileSource(resolvedP, content); - if (newIndex !== index) - this.registerEntry(resolvedP, newIndex); - if (mode !== null) { - this.chmodSync(resolvedP, mode); - } - } - prepareWriteFile(p, opts) { - if (typeof p === `number`) - p = this.fdToPath(p, `read`); - if (this.readOnly) - throw EROFS(`open '${p}'`); - const resolvedP = this.resolveFilename(`open '${p}'`, p); - if (this.listings.has(resolvedP)) - throw EISDIR(`open '${p}'`); - let encoding = null, mode = null; - if (typeof opts === `string`) { - encoding = opts; - } else if (typeof opts === `object`) { - ({ - encoding = null, - mode = null - } = opts); - } - const index = this.entries.get(resolvedP); - return { - encoding, - mode, - resolvedP, - index - }; - } - async unlinkPromise(p) { - return this.unlinkSync(p); - } - unlinkSync(p) { - if (this.readOnly) - throw EROFS(`unlink '${p}'`); - const resolvedP = this.resolveFilename(`unlink '${p}'`, p); - if (this.listings.has(resolvedP)) - throw EISDIR(`unlink '${p}'`); - const index = this.entries.get(resolvedP); - if (typeof index === `undefined`) - throw EINVAL(`unlink '${p}'`); - this.deleteEntry(resolvedP, index); - } - async utimesPromise(p, atime, mtime) { - return this.utimesSync(p, atime, mtime); - } - utimesSync(p, atime, mtime) { - if (this.readOnly) - throw EROFS(`utimes '${p}'`); - const resolvedP = this.resolveFilename(`utimes '${p}'`, p); - this.utimesImpl(resolvedP, mtime); - } - async lutimesPromise(p, atime, mtime) { - return this.lutimesSync(p, atime, mtime); - } - lutimesSync(p, atime, mtime) { - if (this.readOnly) - throw EROFS(`lutimes '${p}'`); - const resolvedP = this.resolveFilename(`utimes '${p}'`, p, false); - this.utimesImpl(resolvedP, mtime); - } - utimesImpl(resolvedP, mtime) { - if (this.listings.has(resolvedP)) { - if (!this.entries.has(resolvedP)) - this.hydrateDirectory(resolvedP); - } - const entry = this.entries.get(resolvedP); - if (entry === void 0) - throw new Error(`Unreachable`); - const rc = this.libzip.file.setMtime(this.zip, entry, 0, toUnixTimestamp(mtime), 0); - if (rc === -1) { - throw this.makeLibzipError(this.libzip.getError(this.zip)); - } - } - async mkdirPromise(p, opts) { - return this.mkdirSync(p, opts); - } - mkdirSync(p, { mode = 493, recursive = false } = {}) { - if (recursive) - return this.mkdirpSync(p, { chmod: mode }); - if (this.readOnly) - throw EROFS(`mkdir '${p}'`); - const resolvedP = this.resolveFilename(`mkdir '${p}'`, p); - if (this.entries.has(resolvedP) || this.listings.has(resolvedP)) - throw EEXIST(`mkdir '${p}'`); - this.hydrateDirectory(resolvedP); - this.chmodSync(resolvedP, mode); - return void 0; - } - async rmdirPromise(p, opts) { - return this.rmdirSync(p, opts); - } - rmdirSync(p, { recursive = false } = {}) { - if (this.readOnly) - throw EROFS(`rmdir '${p}'`); - if (recursive) { - this.removeSync(p); - return; - } - const resolvedP = this.resolveFilename(`rmdir '${p}'`, p); - const directoryListing = this.listings.get(resolvedP); - if (!directoryListing) - throw ENOTDIR(`rmdir '${p}'`); - if (directoryListing.size > 0) - throw ENOTEMPTY(`rmdir '${p}'`); - const index = this.entries.get(resolvedP); - if (typeof index === `undefined`) - throw EINVAL(`rmdir '${p}'`); - this.deleteEntry(p, index); - } - hydrateDirectory(resolvedP) { - const index = this.libzip.dir.add(this.zip, ppath.relative(PortablePath.root, resolvedP)); - if (index === -1) - throw this.makeLibzipError(this.libzip.getError(this.zip)); - this.registerListing(resolvedP); - this.registerEntry(resolvedP, index); - return index; - } - async linkPromise(existingP, newP) { - return this.linkSync(existingP, newP); - } - linkSync(existingP, newP) { - throw EOPNOTSUPP(`link '${existingP}' -> '${newP}'`); - } - async symlinkPromise(target, p) { - return this.symlinkSync(target, p); - } - symlinkSync(target, p) { - if (this.readOnly) - throw EROFS(`symlink '${target}' -> '${p}'`); - const resolvedP = this.resolveFilename(`symlink '${target}' -> '${p}'`, p); - if (this.listings.has(resolvedP)) - throw EISDIR(`symlink '${target}' -> '${p}'`); - if (this.entries.has(resolvedP)) - throw EEXIST(`symlink '${target}' -> '${p}'`); - const index = this.setFileSource(resolvedP, target); - this.registerEntry(resolvedP, index); - const rc = this.libzip.file.setExternalAttributes(this.zip, index, 0, 0, this.libzip.ZIP_OPSYS_UNIX, (S_IFLNK | 511) << 16); - if (rc === -1) - throw this.makeLibzipError(this.libzip.getError(this.zip)); - this.symlinkCount += 1; - } - async readFilePromise(p, encoding) { - if (typeof encoding === `object`) - encoding = encoding ? encoding.encoding : void 0; - const data = await this.readFileBuffer(p, { asyncDecompress: true }); - return encoding ? data.toString(encoding) : data; - } - readFileSync(p, encoding) { - if (typeof encoding === `object`) - encoding = encoding ? encoding.encoding : void 0; - const data = this.readFileBuffer(p); - return encoding ? data.toString(encoding) : data; - } - readFileBuffer(p, opts = { asyncDecompress: false }) { - if (typeof p === `number`) - p = this.fdToPath(p, `read`); - const resolvedP = this.resolveFilename(`open '${p}'`, p); - if (!this.entries.has(resolvedP) && !this.listings.has(resolvedP)) - throw ENOENT(`open '${p}'`); - if (p[p.length - 1] === `/` && !this.listings.has(resolvedP)) - throw ENOTDIR(`open '${p}'`); - if (this.listings.has(resolvedP)) - throw EISDIR(`read`); - const entry = this.entries.get(resolvedP); - if (entry === void 0) - throw new Error(`Unreachable`); - return this.getFileSource(entry, opts); - } - async readdirPromise(p, opts) { - return this.readdirSync(p, opts); - } - readdirSync(p, opts) { - const resolvedP = this.resolveFilename(`scandir '${p}'`, p); - if (!this.entries.has(resolvedP) && !this.listings.has(resolvedP)) - throw ENOENT(`scandir '${p}'`); - const directoryListing = this.listings.get(resolvedP); - if (!directoryListing) - throw ENOTDIR(`scandir '${p}'`); - const entries = [...directoryListing]; - if (!(opts == null ? void 0 : opts.withFileTypes)) - return entries; - return entries.map((name) => { - return Object.assign(this.statImpl(`lstat`, ppath.join(p, name)), { - name - }); - }); - } - async readlinkPromise(p) { - const entry = this.prepareReadlink(p); - return (await this.getFileSource(entry, { asyncDecompress: true })).toString(); - } - readlinkSync(p) { - const entry = this.prepareReadlink(p); - return this.getFileSource(entry).toString(); - } - prepareReadlink(p) { - const resolvedP = this.resolveFilename(`readlink '${p}'`, p, false); - if (!this.entries.has(resolvedP) && !this.listings.has(resolvedP)) - throw ENOENT(`readlink '${p}'`); - if (p[p.length - 1] === `/` && !this.listings.has(resolvedP)) - throw ENOTDIR(`open '${p}'`); - if (this.listings.has(resolvedP)) - throw EINVAL(`readlink '${p}'`); - const entry = this.entries.get(resolvedP); - if (entry === void 0) - throw new Error(`Unreachable`); - if (!this.isSymbolicLink(entry)) - throw EINVAL(`readlink '${p}'`); - return entry; - } - async truncatePromise(p, len = 0) { - const resolvedP = this.resolveFilename(`open '${p}'`, p); - const index = this.entries.get(resolvedP); - if (typeof index === `undefined`) - throw EINVAL(`open '${p}'`); - const source = await this.getFileSource(index, { asyncDecompress: true }); - const truncated = Buffer.alloc(len, 0); - source.copy(truncated); - return await this.writeFilePromise(p, truncated); - } - truncateSync(p, len = 0) { - const resolvedP = this.resolveFilename(`open '${p}'`, p); - const index = this.entries.get(resolvedP); - if (typeof index === `undefined`) - throw EINVAL(`open '${p}'`); - const source = this.getFileSource(index); - const truncated = Buffer.alloc(len, 0); - source.copy(truncated); - return this.writeFileSync(p, truncated); - } - async ftruncatePromise(fd, len) { - return this.truncatePromise(this.fdToPath(fd, `ftruncate`), len); - } - ftruncateSync(fd, len) { - return this.truncateSync(this.fdToPath(fd, `ftruncateSync`), len); - } - watch(p, a, b) { - let persistent; - switch (typeof a) { - case `function`: - case `string`: - case `undefined`: - { - persistent = true; - } - break; - default: - { - ({ persistent = true } = a); - } - break; - } - if (!persistent) - return { on: () => { - }, close: () => { - } }; - const interval = setInterval(() => { - }, 24 * 60 * 60 * 1e3); - return { on: () => { - }, close: () => { - clearInterval(interval); - } }; - } - watchFile(p, a, b) { - const resolvedP = ppath.resolve(PortablePath.root, p); - return watchFile(this, resolvedP, a, b); - } - unwatchFile(p, cb) { - const resolvedP = ppath.resolve(PortablePath.root, p); - return unwatchFile(this, resolvedP, cb); - } -} - -class ProxiedFS extends FakeFS { - getExtractHint(hints) { - return this.baseFs.getExtractHint(hints); - } - resolve(path) { - return this.mapFromBase(this.baseFs.resolve(this.mapToBase(path))); - } - getRealPath() { - return this.mapFromBase(this.baseFs.getRealPath()); - } - async openPromise(p, flags, mode) { - return this.baseFs.openPromise(this.mapToBase(p), flags, mode); - } - openSync(p, flags, mode) { - return this.baseFs.openSync(this.mapToBase(p), flags, mode); - } - async opendirPromise(p, opts) { - return Object.assign(await this.baseFs.opendirPromise(this.mapToBase(p), opts), { path: p }); - } - opendirSync(p, opts) { - return Object.assign(this.baseFs.opendirSync(this.mapToBase(p), opts), { path: p }); - } - async readPromise(fd, buffer, offset, length, position) { - return await this.baseFs.readPromise(fd, buffer, offset, length, position); - } - readSync(fd, buffer, offset, length, position) { - return this.baseFs.readSync(fd, buffer, offset, length, position); - } - async writePromise(fd, buffer, offset, length, position) { - if (typeof buffer === `string`) { - return await this.baseFs.writePromise(fd, buffer, offset); - } else { - return await this.baseFs.writePromise(fd, buffer, offset, length, position); - } - } - writeSync(fd, buffer, offset, length, position) { - if (typeof buffer === `string`) { - return this.baseFs.writeSync(fd, buffer, offset); - } else { - return this.baseFs.writeSync(fd, buffer, offset, length, position); - } - } - async closePromise(fd) { - return this.baseFs.closePromise(fd); - } - closeSync(fd) { - this.baseFs.closeSync(fd); - } - createReadStream(p, opts) { - return this.baseFs.createReadStream(p !== null ? this.mapToBase(p) : p, opts); - } - createWriteStream(p, opts) { - return this.baseFs.createWriteStream(p !== null ? this.mapToBase(p) : p, opts); - } - async realpathPromise(p) { - return this.mapFromBase(await this.baseFs.realpathPromise(this.mapToBase(p))); - } - realpathSync(p) { - return this.mapFromBase(this.baseFs.realpathSync(this.mapToBase(p))); - } - async existsPromise(p) { - return this.baseFs.existsPromise(this.mapToBase(p)); - } - existsSync(p) { - return this.baseFs.existsSync(this.mapToBase(p)); - } - accessSync(p, mode) { - return this.baseFs.accessSync(this.mapToBase(p), mode); - } - async accessPromise(p, mode) { - return this.baseFs.accessPromise(this.mapToBase(p), mode); - } - async statPromise(p, opts) { - return this.baseFs.statPromise(this.mapToBase(p), opts); - } - statSync(p, opts) { - return this.baseFs.statSync(this.mapToBase(p), opts); - } - async fstatPromise(fd, opts) { - return this.baseFs.fstatPromise(fd, opts); - } - fstatSync(fd, opts) { - return this.baseFs.fstatSync(fd, opts); - } - lstatPromise(p, opts) { - return this.baseFs.lstatPromise(this.mapToBase(p), opts); - } - lstatSync(p, opts) { - return this.baseFs.lstatSync(this.mapToBase(p), opts); - } - async fchmodPromise(fd, mask) { - return this.baseFs.fchmodPromise(fd, mask); - } - fchmodSync(fd, mask) { - return this.baseFs.fchmodSync(fd, mask); - } - async chmodPromise(p, mask) { - return this.baseFs.chmodPromise(this.mapToBase(p), mask); - } - chmodSync(p, mask) { - return this.baseFs.chmodSync(this.mapToBase(p), mask); - } - async fchownPromise(fd, uid, gid) { - return this.baseFs.fchownPromise(fd, uid, gid); - } - fchownSync(fd, uid, gid) { - return this.baseFs.fchownSync(fd, uid, gid); - } - async chownPromise(p, uid, gid) { - return this.baseFs.chownPromise(this.mapToBase(p), uid, gid); - } - chownSync(p, uid, gid) { - return this.baseFs.chownSync(this.mapToBase(p), uid, gid); - } - async renamePromise(oldP, newP) { - return this.baseFs.renamePromise(this.mapToBase(oldP), this.mapToBase(newP)); - } - renameSync(oldP, newP) { - return this.baseFs.renameSync(this.mapToBase(oldP), this.mapToBase(newP)); - } - async copyFilePromise(sourceP, destP, flags = 0) { - return this.baseFs.copyFilePromise(this.mapToBase(sourceP), this.mapToBase(destP), flags); - } - copyFileSync(sourceP, destP, flags = 0) { - return this.baseFs.copyFileSync(this.mapToBase(sourceP), this.mapToBase(destP), flags); - } - async appendFilePromise(p, content, opts) { - return this.baseFs.appendFilePromise(this.fsMapToBase(p), content, opts); - } - appendFileSync(p, content, opts) { - return this.baseFs.appendFileSync(this.fsMapToBase(p), content, opts); - } - async writeFilePromise(p, content, opts) { - return this.baseFs.writeFilePromise(this.fsMapToBase(p), content, opts); - } - writeFileSync(p, content, opts) { - return this.baseFs.writeFileSync(this.fsMapToBase(p), content, opts); - } - async unlinkPromise(p) { - return this.baseFs.unlinkPromise(this.mapToBase(p)); - } - unlinkSync(p) { - return this.baseFs.unlinkSync(this.mapToBase(p)); - } - async utimesPromise(p, atime, mtime) { - return this.baseFs.utimesPromise(this.mapToBase(p), atime, mtime); - } - utimesSync(p, atime, mtime) { - return this.baseFs.utimesSync(this.mapToBase(p), atime, mtime); - } - async mkdirPromise(p, opts) { - return this.baseFs.mkdirPromise(this.mapToBase(p), opts); - } - mkdirSync(p, opts) { - return this.baseFs.mkdirSync(this.mapToBase(p), opts); - } - async rmdirPromise(p, opts) { - return this.baseFs.rmdirPromise(this.mapToBase(p), opts); - } - rmdirSync(p, opts) { - return this.baseFs.rmdirSync(this.mapToBase(p), opts); - } - async linkPromise(existingP, newP) { - return this.baseFs.linkPromise(this.mapToBase(existingP), this.mapToBase(newP)); - } - linkSync(existingP, newP) { - return this.baseFs.linkSync(this.mapToBase(existingP), this.mapToBase(newP)); - } - async symlinkPromise(target, p, type) { - const mappedP = this.mapToBase(p); - if (this.pathUtils.isAbsolute(target)) - return this.baseFs.symlinkPromise(this.mapToBase(target), mappedP, type); - const mappedAbsoluteTarget = this.mapToBase(this.pathUtils.join(this.pathUtils.dirname(p), target)); - const mappedTarget = this.baseFs.pathUtils.relative(this.baseFs.pathUtils.dirname(mappedP), mappedAbsoluteTarget); - return this.baseFs.symlinkPromise(mappedTarget, mappedP, type); - } - symlinkSync(target, p, type) { - const mappedP = this.mapToBase(p); - if (this.pathUtils.isAbsolute(target)) - return this.baseFs.symlinkSync(this.mapToBase(target), mappedP, type); - const mappedAbsoluteTarget = this.mapToBase(this.pathUtils.join(this.pathUtils.dirname(p), target)); - const mappedTarget = this.baseFs.pathUtils.relative(this.baseFs.pathUtils.dirname(mappedP), mappedAbsoluteTarget); - return this.baseFs.symlinkSync(mappedTarget, mappedP, type); - } - async readFilePromise(p, encoding) { - if (encoding === `utf8`) { - return this.baseFs.readFilePromise(this.fsMapToBase(p), encoding); - } else { - return this.baseFs.readFilePromise(this.fsMapToBase(p), encoding); - } - } - readFileSync(p, encoding) { - if (encoding === `utf8`) { - return this.baseFs.readFileSync(this.fsMapToBase(p), encoding); - } else { - return this.baseFs.readFileSync(this.fsMapToBase(p), encoding); - } - } - async readdirPromise(p, opts) { - return this.baseFs.readdirPromise(this.mapToBase(p), opts); - } - readdirSync(p, opts) { - return this.baseFs.readdirSync(this.mapToBase(p), opts); - } - async readlinkPromise(p) { - return this.mapFromBase(await this.baseFs.readlinkPromise(this.mapToBase(p))); - } - readlinkSync(p) { - return this.mapFromBase(this.baseFs.readlinkSync(this.mapToBase(p))); - } - async truncatePromise(p, len) { - return this.baseFs.truncatePromise(this.mapToBase(p), len); - } - truncateSync(p, len) { - return this.baseFs.truncateSync(this.mapToBase(p), len); - } - async ftruncatePromise(fd, len) { - return this.baseFs.ftruncatePromise(fd, len); - } - ftruncateSync(fd, len) { - return this.baseFs.ftruncateSync(fd, len); - } - watch(p, a, b) { - return this.baseFs.watch( - this.mapToBase(p), - a, - b - ); - } - watchFile(p, a, b) { - return this.baseFs.watchFile( - this.mapToBase(p), - a, - b - ); - } - unwatchFile(p, cb) { - return this.baseFs.unwatchFile(this.mapToBase(p), cb); - } - fsMapToBase(p) { - if (typeof p === `number`) { - return p; - } else { - return this.mapToBase(p); - } - } -} - -class PosixFS extends ProxiedFS { - constructor(baseFs) { - super(npath); - this.baseFs = baseFs; - } - mapFromBase(path) { - return npath.fromPortablePath(path); - } - mapToBase(path) { - return npath.toPortablePath(path); - } -} - -const NUMBER_REGEXP = /^[0-9]+$/; -const VIRTUAL_REGEXP = /^(\/(?:[^/]+\/)*?(?:\$\$virtual|__virtual__))((?:\/((?:[^/]+-)?[a-f0-9]+)(?:\/([^/]+))?)?((?:\/.*)?))$/; -const VALID_COMPONENT = /^([^/]+-)?[a-f0-9]+$/; -class VirtualFS extends ProxiedFS { - constructor({ baseFs = new NodeFS() } = {}) { - super(ppath); - this.baseFs = baseFs; - } - static makeVirtualPath(base, component, to) { - if (ppath.basename(base) !== `__virtual__`) - throw new Error(`Assertion failed: Virtual folders must be named "__virtual__"`); - if (!ppath.basename(component).match(VALID_COMPONENT)) - throw new Error(`Assertion failed: Virtual components must be ended by an hexadecimal hash`); - const target = ppath.relative(ppath.dirname(base), to); - const segments = target.split(`/`); - let depth = 0; - while (depth < segments.length && segments[depth] === `..`) - depth += 1; - const finalSegments = segments.slice(depth); - const fullVirtualPath = ppath.join(base, component, String(depth), ...finalSegments); - return fullVirtualPath; - } - static resolveVirtual(p) { - const match = p.match(VIRTUAL_REGEXP); - if (!match || !match[3] && match[5]) - return p; - const target = ppath.dirname(match[1]); - if (!match[3] || !match[4]) - return target; - const isnum = NUMBER_REGEXP.test(match[4]); - if (!isnum) - return p; - const depth = Number(match[4]); - const backstep = `../`.repeat(depth); - const subpath = match[5] || `.`; - return VirtualFS.resolveVirtual(ppath.join(target, backstep, subpath)); - } - getExtractHint(hints) { - return this.baseFs.getExtractHint(hints); - } - getRealPath() { - return this.baseFs.getRealPath(); - } - realpathSync(p) { - const match = p.match(VIRTUAL_REGEXP); - if (!match) - return this.baseFs.realpathSync(p); - if (!match[5]) - return p; - const realpath = this.baseFs.realpathSync(this.mapToBase(p)); - return VirtualFS.makeVirtualPath(match[1], match[3], realpath); - } - async realpathPromise(p) { - const match = p.match(VIRTUAL_REGEXP); - if (!match) - return await this.baseFs.realpathPromise(p); - if (!match[5]) - return p; - const realpath = await this.baseFs.realpathPromise(this.mapToBase(p)); - return VirtualFS.makeVirtualPath(match[1], match[3], realpath); - } - mapToBase(p) { - if (p === ``) - return p; - if (this.pathUtils.isAbsolute(p)) - return VirtualFS.resolveVirtual(p); - const resolvedRoot = VirtualFS.resolveVirtual(this.baseFs.resolve(PortablePath.dot)); - const resolvedP = VirtualFS.resolveVirtual(this.baseFs.resolve(p)); - return ppath.relative(resolvedRoot, resolvedP) || PortablePath.dot; - } - mapFromBase(p) { - return p; - } -} - -const ZIP_MASK = 4278190080; -const ZIP_MAGIC = 704643072; -const getArchivePart = (path, extension) => { - let idx = path.indexOf(extension); - if (idx <= 0) - return null; - let nextCharIdx = idx; - while (idx >= 0) { - nextCharIdx = idx + extension.length; - if (path[nextCharIdx] === ppath.sep) - break; - if (path[idx - 1] === ppath.sep) - return null; - idx = path.indexOf(extension, nextCharIdx); - } - if (path.length > nextCharIdx && path[nextCharIdx] !== ppath.sep) - return null; - return path.slice(0, nextCharIdx); -}; -class ZipOpenFS extends BasePortableFakeFS { - constructor({ libzip, baseFs = new NodeFS(), filter = null, maxOpenFiles = Infinity, readOnlyArchives = false, useCache = true, maxAge = 5e3, fileExtensions = null }) { - super(); - this.fdMap = /* @__PURE__ */ new Map(); - this.nextFd = 3; - this.isZip = /* @__PURE__ */ new Set(); - this.notZip = /* @__PURE__ */ new Set(); - this.realPaths = /* @__PURE__ */ new Map(); - this.limitOpenFilesTimeout = null; - this.libzipFactory = typeof libzip !== `function` ? () => libzip : libzip; - this.baseFs = baseFs; - this.zipInstances = useCache ? /* @__PURE__ */ new Map() : null; - this.filter = filter; - this.maxOpenFiles = maxOpenFiles; - this.readOnlyArchives = readOnlyArchives; - this.maxAge = maxAge; - this.fileExtensions = fileExtensions; - } - static async openPromise(fn, opts) { - const zipOpenFs = new ZipOpenFS(opts); - try { - return await fn(zipOpenFs); - } finally { - zipOpenFs.saveAndClose(); - } - } - get libzip() { - if (typeof this.libzipInstance === `undefined`) - this.libzipInstance = this.libzipFactory(); - return this.libzipInstance; - } - getExtractHint(hints) { - return this.baseFs.getExtractHint(hints); - } - getRealPath() { - return this.baseFs.getRealPath(); - } - saveAndClose() { - unwatchAllFiles(this); - if (this.zipInstances) { - for (const [path, { zipFs }] of this.zipInstances.entries()) { - zipFs.saveAndClose(); - this.zipInstances.delete(path); - } - } - } - discardAndClose() { - unwatchAllFiles(this); - if (this.zipInstances) { - for (const [path, { zipFs }] of this.zipInstances.entries()) { - zipFs.discardAndClose(); - this.zipInstances.delete(path); - } - } - } - resolve(p) { - return this.baseFs.resolve(p); - } - remapFd(zipFs, fd) { - const remappedFd = this.nextFd++ | ZIP_MAGIC; - this.fdMap.set(remappedFd, [zipFs, fd]); - return remappedFd; - } - async openPromise(p, flags, mode) { - return await this.makeCallPromise(p, async () => { - return await this.baseFs.openPromise(p, flags, mode); - }, async (zipFs, { subPath }) => { - return this.remapFd(zipFs, await zipFs.openPromise(subPath, flags, mode)); - }); - } - openSync(p, flags, mode) { - return this.makeCallSync(p, () => { - return this.baseFs.openSync(p, flags, mode); - }, (zipFs, { subPath }) => { - return this.remapFd(zipFs, zipFs.openSync(subPath, flags, mode)); - }); - } - async opendirPromise(p, opts) { - return await this.makeCallPromise(p, async () => { - return await this.baseFs.opendirPromise(p, opts); - }, async (zipFs, { subPath }) => { - return await zipFs.opendirPromise(subPath, opts); - }, { - requireSubpath: false - }); - } - opendirSync(p, opts) { - return this.makeCallSync(p, () => { - return this.baseFs.opendirSync(p, opts); - }, (zipFs, { subPath }) => { - return zipFs.opendirSync(subPath, opts); - }, { - requireSubpath: false - }); - } - async readPromise(fd, buffer, offset, length, position) { - if ((fd & ZIP_MASK) !== ZIP_MAGIC) - return await this.baseFs.readPromise(fd, buffer, offset, length, position); - const entry = this.fdMap.get(fd); - if (typeof entry === `undefined`) - throw EBADF(`read`); - const [zipFs, realFd] = entry; - return await zipFs.readPromise(realFd, buffer, offset, length, position); - } - readSync(fd, buffer, offset, length, position) { - if ((fd & ZIP_MASK) !== ZIP_MAGIC) - return this.baseFs.readSync(fd, buffer, offset, length, position); - const entry = this.fdMap.get(fd); - if (typeof entry === `undefined`) - throw EBADF(`readSync`); - const [zipFs, realFd] = entry; - return zipFs.readSync(realFd, buffer, offset, length, position); - } - async writePromise(fd, buffer, offset, length, position) { - if ((fd & ZIP_MASK) !== ZIP_MAGIC) { - if (typeof buffer === `string`) { - return await this.baseFs.writePromise(fd, buffer, offset); - } else { - return await this.baseFs.writePromise(fd, buffer, offset, length, position); - } - } - const entry = this.fdMap.get(fd); - if (typeof entry === `undefined`) - throw EBADF(`write`); - const [zipFs, realFd] = entry; - if (typeof buffer === `string`) { - return await zipFs.writePromise(realFd, buffer, offset); - } else { - return await zipFs.writePromise(realFd, buffer, offset, length, position); - } - } - writeSync(fd, buffer, offset, length, position) { - if ((fd & ZIP_MASK) !== ZIP_MAGIC) { - if (typeof buffer === `string`) { - return this.baseFs.writeSync(fd, buffer, offset); - } else { - return this.baseFs.writeSync(fd, buffer, offset, length, position); - } - } - const entry = this.fdMap.get(fd); - if (typeof entry === `undefined`) - throw EBADF(`writeSync`); - const [zipFs, realFd] = entry; - if (typeof buffer === `string`) { - return zipFs.writeSync(realFd, buffer, offset); - } else { - return zipFs.writeSync(realFd, buffer, offset, length, position); - } - } - async closePromise(fd) { - if ((fd & ZIP_MASK) !== ZIP_MAGIC) - return await this.baseFs.closePromise(fd); - const entry = this.fdMap.get(fd); - if (typeof entry === `undefined`) - throw EBADF(`close`); - this.fdMap.delete(fd); - const [zipFs, realFd] = entry; - return await zipFs.closePromise(realFd); - } - closeSync(fd) { - if ((fd & ZIP_MASK) !== ZIP_MAGIC) - return this.baseFs.closeSync(fd); - const entry = this.fdMap.get(fd); - if (typeof entry === `undefined`) - throw EBADF(`closeSync`); - this.fdMap.delete(fd); - const [zipFs, realFd] = entry; - return zipFs.closeSync(realFd); - } - createReadStream(p, opts) { - if (p === null) - return this.baseFs.createReadStream(p, opts); - return this.makeCallSync(p, () => { - return this.baseFs.createReadStream(p, opts); - }, (zipFs, { archivePath, subPath }) => { - const stream = zipFs.createReadStream(subPath, opts); - stream.path = npath.fromPortablePath(this.pathUtils.join(archivePath, subPath)); - return stream; - }); - } - createWriteStream(p, opts) { - if (p === null) - return this.baseFs.createWriteStream(p, opts); - return this.makeCallSync(p, () => { - return this.baseFs.createWriteStream(p, opts); - }, (zipFs, { subPath }) => { - return zipFs.createWriteStream(subPath, opts); - }); - } - async realpathPromise(p) { - return await this.makeCallPromise(p, async () => { - return await this.baseFs.realpathPromise(p); - }, async (zipFs, { archivePath, subPath }) => { - let realArchivePath = this.realPaths.get(archivePath); - if (typeof realArchivePath === `undefined`) { - realArchivePath = await this.baseFs.realpathPromise(archivePath); - this.realPaths.set(archivePath, realArchivePath); - } - return this.pathUtils.join(realArchivePath, this.pathUtils.relative(PortablePath.root, await zipFs.realpathPromise(subPath))); - }); - } - realpathSync(p) { - return this.makeCallSync(p, () => { - return this.baseFs.realpathSync(p); - }, (zipFs, { archivePath, subPath }) => { - let realArchivePath = this.realPaths.get(archivePath); - if (typeof realArchivePath === `undefined`) { - realArchivePath = this.baseFs.realpathSync(archivePath); - this.realPaths.set(archivePath, realArchivePath); - } - return this.pathUtils.join(realArchivePath, this.pathUtils.relative(PortablePath.root, zipFs.realpathSync(subPath))); - }); - } - async existsPromise(p) { - return await this.makeCallPromise(p, async () => { - return await this.baseFs.existsPromise(p); - }, async (zipFs, { subPath }) => { - return await zipFs.existsPromise(subPath); - }); - } - existsSync(p) { - return this.makeCallSync(p, () => { - return this.baseFs.existsSync(p); - }, (zipFs, { subPath }) => { - return zipFs.existsSync(subPath); - }); - } - async accessPromise(p, mode) { - return await this.makeCallPromise(p, async () => { - return await this.baseFs.accessPromise(p, mode); - }, async (zipFs, { subPath }) => { - return await zipFs.accessPromise(subPath, mode); - }); - } - accessSync(p, mode) { - return this.makeCallSync(p, () => { - return this.baseFs.accessSync(p, mode); - }, (zipFs, { subPath }) => { - return zipFs.accessSync(subPath, mode); - }); - } - async statPromise(p, opts) { - return await this.makeCallPromise(p, async () => { - return await this.baseFs.statPromise(p, opts); - }, async (zipFs, { subPath }) => { - return await zipFs.statPromise(subPath, opts); - }); - } - statSync(p, opts) { - return this.makeCallSync(p, () => { - return this.baseFs.statSync(p, opts); - }, (zipFs, { subPath }) => { - return zipFs.statSync(subPath, opts); - }); - } - async fstatPromise(fd, opts) { - if ((fd & ZIP_MASK) !== ZIP_MAGIC) - return this.baseFs.fstatPromise(fd, opts); - const entry = this.fdMap.get(fd); - if (typeof entry === `undefined`) - throw EBADF(`fstat`); - const [zipFs, realFd] = entry; - return zipFs.fstatPromise(realFd, opts); - } - fstatSync(fd, opts) { - if ((fd & ZIP_MASK) !== ZIP_MAGIC) - return this.baseFs.fstatSync(fd, opts); - const entry = this.fdMap.get(fd); - if (typeof entry === `undefined`) - throw EBADF(`fstatSync`); - const [zipFs, realFd] = entry; - return zipFs.fstatSync(realFd, opts); - } - async lstatPromise(p, opts) { - return await this.makeCallPromise(p, async () => { - return await this.baseFs.lstatPromise(p, opts); - }, async (zipFs, { subPath }) => { - return await zipFs.lstatPromise(subPath, opts); - }); - } - lstatSync(p, opts) { - return this.makeCallSync(p, () => { - return this.baseFs.lstatSync(p, opts); - }, (zipFs, { subPath }) => { - return zipFs.lstatSync(subPath, opts); - }); - } - async fchmodPromise(fd, mask) { - if ((fd & ZIP_MASK) !== ZIP_MAGIC) - return this.baseFs.fchmodPromise(fd, mask); - const entry = this.fdMap.get(fd); - if (typeof entry === `undefined`) - throw EBADF(`fchmod`); - const [zipFs, realFd] = entry; - return zipFs.fchmodPromise(realFd, mask); - } - fchmodSync(fd, mask) { - if ((fd & ZIP_MASK) !== ZIP_MAGIC) - return this.baseFs.fchmodSync(fd, mask); - const entry = this.fdMap.get(fd); - if (typeof entry === `undefined`) - throw EBADF(`fchmodSync`); - const [zipFs, realFd] = entry; - return zipFs.fchmodSync(realFd, mask); - } - async chmodPromise(p, mask) { - return await this.makeCallPromise(p, async () => { - return await this.baseFs.chmodPromise(p, mask); - }, async (zipFs, { subPath }) => { - return await zipFs.chmodPromise(subPath, mask); - }); - } - chmodSync(p, mask) { - return this.makeCallSync(p, () => { - return this.baseFs.chmodSync(p, mask); - }, (zipFs, { subPath }) => { - return zipFs.chmodSync(subPath, mask); - }); - } - async fchownPromise(fd, uid, gid) { - if ((fd & ZIP_MASK) !== ZIP_MAGIC) - return this.baseFs.fchownPromise(fd, uid, gid); - const entry = this.fdMap.get(fd); - if (typeof entry === `undefined`) - throw EBADF(`fchown`); - const [zipFs, realFd] = entry; - return zipFs.fchownPromise(realFd, uid, gid); - } - fchownSync(fd, uid, gid) { - if ((fd & ZIP_MASK) !== ZIP_MAGIC) - return this.baseFs.fchownSync(fd, uid, gid); - const entry = this.fdMap.get(fd); - if (typeof entry === `undefined`) - throw EBADF(`fchownSync`); - const [zipFs, realFd] = entry; - return zipFs.fchownSync(realFd, uid, gid); - } - async chownPromise(p, uid, gid) { - return await this.makeCallPromise(p, async () => { - return await this.baseFs.chownPromise(p, uid, gid); - }, async (zipFs, { subPath }) => { - return await zipFs.chownPromise(subPath, uid, gid); - }); - } - chownSync(p, uid, gid) { - return this.makeCallSync(p, () => { - return this.baseFs.chownSync(p, uid, gid); - }, (zipFs, { subPath }) => { - return zipFs.chownSync(subPath, uid, gid); - }); - } - async renamePromise(oldP, newP) { - return await this.makeCallPromise(oldP, async () => { - return await this.makeCallPromise(newP, async () => { - return await this.baseFs.renamePromise(oldP, newP); - }, async () => { - throw Object.assign(new Error(`EEXDEV: cross-device link not permitted`), { code: `EEXDEV` }); - }); - }, async (zipFsO, { subPath: subPathO }) => { - return await this.makeCallPromise(newP, async () => { - throw Object.assign(new Error(`EEXDEV: cross-device link not permitted`), { code: `EEXDEV` }); - }, async (zipFsN, { subPath: subPathN }) => { - if (zipFsO !== zipFsN) { - throw Object.assign(new Error(`EEXDEV: cross-device link not permitted`), { code: `EEXDEV` }); - } else { - return await zipFsO.renamePromise(subPathO, subPathN); - } - }); - }); - } - renameSync(oldP, newP) { - return this.makeCallSync(oldP, () => { - return this.makeCallSync(newP, () => { - return this.baseFs.renameSync(oldP, newP); - }, () => { - throw Object.assign(new Error(`EEXDEV: cross-device link not permitted`), { code: `EEXDEV` }); - }); - }, (zipFsO, { subPath: subPathO }) => { - return this.makeCallSync(newP, () => { - throw Object.assign(new Error(`EEXDEV: cross-device link not permitted`), { code: `EEXDEV` }); - }, (zipFsN, { subPath: subPathN }) => { - if (zipFsO !== zipFsN) { - throw Object.assign(new Error(`EEXDEV: cross-device link not permitted`), { code: `EEXDEV` }); - } else { - return zipFsO.renameSync(subPathO, subPathN); - } - }); - }); - } - async copyFilePromise(sourceP, destP, flags = 0) { - const fallback = async (sourceFs, sourceP2, destFs, destP2) => { - if ((flags & fs.constants.COPYFILE_FICLONE_FORCE) !== 0) - throw Object.assign(new Error(`EXDEV: cross-device clone not permitted, copyfile '${sourceP2}' -> ${destP2}'`), { code: `EXDEV` }); - if (flags & fs.constants.COPYFILE_EXCL && await this.existsPromise(sourceP2)) - throw Object.assign(new Error(`EEXIST: file already exists, copyfile '${sourceP2}' -> '${destP2}'`), { code: `EEXIST` }); - let content; - try { - content = await sourceFs.readFilePromise(sourceP2); - } catch (error) { - throw Object.assign(new Error(`EINVAL: invalid argument, copyfile '${sourceP2}' -> '${destP2}'`), { code: `EINVAL` }); - } - await destFs.writeFilePromise(destP2, content); - }; - return await this.makeCallPromise(sourceP, async () => { - return await this.makeCallPromise(destP, async () => { - return await this.baseFs.copyFilePromise(sourceP, destP, flags); - }, async (zipFsD, { subPath: subPathD }) => { - return await fallback(this.baseFs, sourceP, zipFsD, subPathD); - }); - }, async (zipFsS, { subPath: subPathS }) => { - return await this.makeCallPromise(destP, async () => { - return await fallback(zipFsS, subPathS, this.baseFs, destP); - }, async (zipFsD, { subPath: subPathD }) => { - if (zipFsS !== zipFsD) { - return await fallback(zipFsS, subPathS, zipFsD, subPathD); - } else { - return await zipFsS.copyFilePromise(subPathS, subPathD, flags); - } - }); - }); - } - copyFileSync(sourceP, destP, flags = 0) { - const fallback = (sourceFs, sourceP2, destFs, destP2) => { - if ((flags & fs.constants.COPYFILE_FICLONE_FORCE) !== 0) - throw Object.assign(new Error(`EXDEV: cross-device clone not permitted, copyfile '${sourceP2}' -> ${destP2}'`), { code: `EXDEV` }); - if (flags & fs.constants.COPYFILE_EXCL && this.existsSync(sourceP2)) - throw Object.assign(new Error(`EEXIST: file already exists, copyfile '${sourceP2}' -> '${destP2}'`), { code: `EEXIST` }); - let content; - try { - content = sourceFs.readFileSync(sourceP2); - } catch (error) { - throw Object.assign(new Error(`EINVAL: invalid argument, copyfile '${sourceP2}' -> '${destP2}'`), { code: `EINVAL` }); - } - destFs.writeFileSync(destP2, content); - }; - return this.makeCallSync(sourceP, () => { - return this.makeCallSync(destP, () => { - return this.baseFs.copyFileSync(sourceP, destP, flags); - }, (zipFsD, { subPath: subPathD }) => { - return fallback(this.baseFs, sourceP, zipFsD, subPathD); - }); - }, (zipFsS, { subPath: subPathS }) => { - return this.makeCallSync(destP, () => { - return fallback(zipFsS, subPathS, this.baseFs, destP); - }, (zipFsD, { subPath: subPathD }) => { - if (zipFsS !== zipFsD) { - return fallback(zipFsS, subPathS, zipFsD, subPathD); - } else { - return zipFsS.copyFileSync(subPathS, subPathD, flags); - } - }); - }); - } - async appendFilePromise(p, content, opts) { - return await this.makeCallPromise(p, async () => { - return await this.baseFs.appendFilePromise(p, content, opts); - }, async (zipFs, { subPath }) => { - return await zipFs.appendFilePromise(subPath, content, opts); - }); - } - appendFileSync(p, content, opts) { - return this.makeCallSync(p, () => { - return this.baseFs.appendFileSync(p, content, opts); - }, (zipFs, { subPath }) => { - return zipFs.appendFileSync(subPath, content, opts); - }); - } - async writeFilePromise(p, content, opts) { - return await this.makeCallPromise(p, async () => { - return await this.baseFs.writeFilePromise(p, content, opts); - }, async (zipFs, { subPath }) => { - return await zipFs.writeFilePromise(subPath, content, opts); - }); - } - writeFileSync(p, content, opts) { - return this.makeCallSync(p, () => { - return this.baseFs.writeFileSync(p, content, opts); - }, (zipFs, { subPath }) => { - return zipFs.writeFileSync(subPath, content, opts); - }); - } - async unlinkPromise(p) { - return await this.makeCallPromise(p, async () => { - return await this.baseFs.unlinkPromise(p); - }, async (zipFs, { subPath }) => { - return await zipFs.unlinkPromise(subPath); - }); - } - unlinkSync(p) { - return this.makeCallSync(p, () => { - return this.baseFs.unlinkSync(p); - }, (zipFs, { subPath }) => { - return zipFs.unlinkSync(subPath); - }); - } - async utimesPromise(p, atime, mtime) { - return await this.makeCallPromise(p, async () => { - return await this.baseFs.utimesPromise(p, atime, mtime); - }, async (zipFs, { subPath }) => { - return await zipFs.utimesPromise(subPath, atime, mtime); - }); - } - utimesSync(p, atime, mtime) { - return this.makeCallSync(p, () => { - return this.baseFs.utimesSync(p, atime, mtime); - }, (zipFs, { subPath }) => { - return zipFs.utimesSync(subPath, atime, mtime); - }); - } - async mkdirPromise(p, opts) { - return await this.makeCallPromise(p, async () => { - return await this.baseFs.mkdirPromise(p, opts); - }, async (zipFs, { subPath }) => { - return await zipFs.mkdirPromise(subPath, opts); - }); - } - mkdirSync(p, opts) { - return this.makeCallSync(p, () => { - return this.baseFs.mkdirSync(p, opts); - }, (zipFs, { subPath }) => { - return zipFs.mkdirSync(subPath, opts); - }); - } - async rmdirPromise(p, opts) { - return await this.makeCallPromise(p, async () => { - return await this.baseFs.rmdirPromise(p, opts); - }, async (zipFs, { subPath }) => { - return await zipFs.rmdirPromise(subPath, opts); - }); - } - rmdirSync(p, opts) { - return this.makeCallSync(p, () => { - return this.baseFs.rmdirSync(p, opts); - }, (zipFs, { subPath }) => { - return zipFs.rmdirSync(subPath, opts); - }); - } - async linkPromise(existingP, newP) { - return await this.makeCallPromise(newP, async () => { - return await this.baseFs.linkPromise(existingP, newP); - }, async (zipFs, { subPath }) => { - return await zipFs.linkPromise(existingP, subPath); - }); - } - linkSync(existingP, newP) { - return this.makeCallSync(newP, () => { - return this.baseFs.linkSync(existingP, newP); - }, (zipFs, { subPath }) => { - return zipFs.linkSync(existingP, subPath); - }); - } - async symlinkPromise(target, p, type) { - return await this.makeCallPromise(p, async () => { - return await this.baseFs.symlinkPromise(target, p, type); - }, async (zipFs, { subPath }) => { - return await zipFs.symlinkPromise(target, subPath); - }); - } - symlinkSync(target, p, type) { - return this.makeCallSync(p, () => { - return this.baseFs.symlinkSync(target, p, type); - }, (zipFs, { subPath }) => { - return zipFs.symlinkSync(target, subPath); - }); - } - async readFilePromise(p, encoding) { - return this.makeCallPromise(p, async () => { - switch (encoding) { - case `utf8`: - return await this.baseFs.readFilePromise(p, encoding); - default: - return await this.baseFs.readFilePromise(p, encoding); - } - }, async (zipFs, { subPath }) => { - return await zipFs.readFilePromise(subPath, encoding); - }); - } - readFileSync(p, encoding) { - return this.makeCallSync(p, () => { - switch (encoding) { - case `utf8`: - return this.baseFs.readFileSync(p, encoding); - default: - return this.baseFs.readFileSync(p, encoding); - } - }, (zipFs, { subPath }) => { - return zipFs.readFileSync(subPath, encoding); - }); - } - async readdirPromise(p, opts) { - return await this.makeCallPromise(p, async () => { - return await this.baseFs.readdirPromise(p, opts); - }, async (zipFs, { subPath }) => { - return await zipFs.readdirPromise(subPath, opts); - }, { - requireSubpath: false - }); - } - readdirSync(p, opts) { - return this.makeCallSync(p, () => { - return this.baseFs.readdirSync(p, opts); - }, (zipFs, { subPath }) => { - return zipFs.readdirSync(subPath, opts); - }, { - requireSubpath: false - }); - } - async readlinkPromise(p) { - return await this.makeCallPromise(p, async () => { - return await this.baseFs.readlinkPromise(p); - }, async (zipFs, { subPath }) => { - return await zipFs.readlinkPromise(subPath); - }); - } - readlinkSync(p) { - return this.makeCallSync(p, () => { - return this.baseFs.readlinkSync(p); - }, (zipFs, { subPath }) => { - return zipFs.readlinkSync(subPath); - }); - } - async truncatePromise(p, len) { - return await this.makeCallPromise(p, async () => { - return await this.baseFs.truncatePromise(p, len); - }, async (zipFs, { subPath }) => { - return await zipFs.truncatePromise(subPath, len); - }); - } - truncateSync(p, len) { - return this.makeCallSync(p, () => { - return this.baseFs.truncateSync(p, len); - }, (zipFs, { subPath }) => { - return zipFs.truncateSync(subPath, len); - }); - } - async ftruncatePromise(fd, len) { - if ((fd & ZIP_MASK) !== ZIP_MAGIC) - return this.baseFs.ftruncatePromise(fd, len); - const entry = this.fdMap.get(fd); - if (typeof entry === `undefined`) - throw EBADF(`ftruncate`); - const [zipFs, realFd] = entry; - return zipFs.ftruncatePromise(realFd, len); - } - ftruncateSync(fd, len) { - if ((fd & ZIP_MASK) !== ZIP_MAGIC) - return this.baseFs.ftruncateSync(fd, len); - const entry = this.fdMap.get(fd); - if (typeof entry === `undefined`) - throw EBADF(`ftruncateSync`); - const [zipFs, realFd] = entry; - return zipFs.ftruncateSync(realFd, len); - } - watch(p, a, b) { - return this.makeCallSync(p, () => { - return this.baseFs.watch( - p, - a, - b - ); - }, (zipFs, { subPath }) => { - return zipFs.watch( - subPath, - a, - b - ); - }); - } - watchFile(p, a, b) { - return this.makeCallSync(p, () => { - return this.baseFs.watchFile( - p, - a, - b - ); - }, () => { - return watchFile(this, p, a, b); - }); - } - unwatchFile(p, cb) { - return this.makeCallSync(p, () => { - return this.baseFs.unwatchFile(p, cb); - }, () => { - return unwatchFile(this, p, cb); - }); - } - async makeCallPromise(p, discard, accept, { requireSubpath = true } = {}) { - if (typeof p !== `string`) - return await discard(); - const normalizedP = this.resolve(p); - const zipInfo = this.findZip(normalizedP); - if (!zipInfo) - return await discard(); - if (requireSubpath && zipInfo.subPath === `/`) - return await discard(); - return await this.getZipPromise(zipInfo.archivePath, async (zipFs) => await accept(zipFs, zipInfo)); - } - makeCallSync(p, discard, accept, { requireSubpath = true } = {}) { - if (typeof p !== `string`) - return discard(); - const normalizedP = this.resolve(p); - const zipInfo = this.findZip(normalizedP); - if (!zipInfo) - return discard(); - if (requireSubpath && zipInfo.subPath === `/`) - return discard(); - return this.getZipSync(zipInfo.archivePath, (zipFs) => accept(zipFs, zipInfo)); - } - findZip(p) { - if (this.filter && !this.filter.test(p)) - return null; - let filePath = ``; - while (true) { - const pathPartWithArchive = p.substring(filePath.length); - let archivePart; - if (!this.fileExtensions) { - archivePart = getArchivePart(pathPartWithArchive, `.zip`); - } else { - for (const ext of this.fileExtensions) { - archivePart = getArchivePart(pathPartWithArchive, ext); - if (archivePart) { - break; - } - } - } - if (!archivePart) - return null; - filePath = this.pathUtils.join(filePath, archivePart); - if (this.isZip.has(filePath) === false) { - if (this.notZip.has(filePath)) - continue; - try { - if (!this.baseFs.lstatSync(filePath).isFile()) { - this.notZip.add(filePath); - continue; - } - } catch { - return null; - } - this.isZip.add(filePath); - } - return { - archivePath: filePath, - subPath: this.pathUtils.join(PortablePath.root, p.substring(filePath.length)) - }; - } - } - limitOpenFiles(max) { - if (this.zipInstances === null) - return; - const now = Date.now(); - let nextExpiresAt = now + this.maxAge; - let closeCount = max === null ? 0 : this.zipInstances.size - max; - for (const [path, { zipFs, expiresAt, refCount }] of this.zipInstances.entries()) { - if (refCount !== 0 || zipFs.hasOpenFileHandles()) { - continue; - } else if (now >= expiresAt) { - zipFs.saveAndClose(); - this.zipInstances.delete(path); - closeCount -= 1; - continue; - } else if (max === null || closeCount <= 0) { - nextExpiresAt = expiresAt; - break; - } - zipFs.saveAndClose(); - this.zipInstances.delete(path); - closeCount -= 1; - } - if (this.limitOpenFilesTimeout === null && (max === null && this.zipInstances.size > 0 || max !== null)) { - this.limitOpenFilesTimeout = setTimeout(() => { - this.limitOpenFilesTimeout = null; - this.limitOpenFiles(null); - }, nextExpiresAt - now).unref(); - } - } - async getZipPromise(p, accept) { - const getZipOptions = async () => ({ - baseFs: this.baseFs, - libzip: this.libzip, - readOnly: this.readOnlyArchives, - stats: await this.baseFs.statPromise(p) - }); - if (this.zipInstances) { - let cachedZipFs = this.zipInstances.get(p); - if (!cachedZipFs) { - const zipOptions = await getZipOptions(); - cachedZipFs = this.zipInstances.get(p); - if (!cachedZipFs) { - cachedZipFs = { - zipFs: new ZipFS(p, zipOptions), - expiresAt: 0, - refCount: 0 - }; - } - } - this.zipInstances.delete(p); - this.limitOpenFiles(this.maxOpenFiles - 1); - this.zipInstances.set(p, cachedZipFs); - cachedZipFs.expiresAt = Date.now() + this.maxAge; - cachedZipFs.refCount += 1; - try { - return await accept(cachedZipFs.zipFs); - } finally { - cachedZipFs.refCount -= 1; - } - } else { - const zipFs = new ZipFS(p, await getZipOptions()); - try { - return await accept(zipFs); - } finally { - zipFs.saveAndClose(); - } - } - } - getZipSync(p, accept) { - const getZipOptions = () => ({ - baseFs: this.baseFs, - libzip: this.libzip, - readOnly: this.readOnlyArchives, - stats: this.baseFs.statSync(p) - }); - if (this.zipInstances) { - let cachedZipFs = this.zipInstances.get(p); - if (!cachedZipFs) { - cachedZipFs = { - zipFs: new ZipFS(p, getZipOptions()), - expiresAt: 0, - refCount: 0 - }; - } - this.zipInstances.delete(p); - this.limitOpenFiles(this.maxOpenFiles - 1); - this.zipInstances.set(p, cachedZipFs); - cachedZipFs.expiresAt = Date.now() + this.maxAge; - return accept(cachedZipFs.zipFs); - } else { - const zipFs = new ZipFS(p, getZipOptions()); - try { - return accept(zipFs); - } finally { - zipFs.saveAndClose(); - } - } - } -} - -class NodePathFS extends ProxiedFS { - constructor(baseFs) { - super(npath); - this.baseFs = baseFs; - } - mapFromBase(path) { - return path; - } - mapToBase(path) { - if (typeof path === `string`) - return path; - if (path instanceof url.URL) - return url.fileURLToPath(path); - if (Buffer.isBuffer(path)) { - const str = path.toString(); - if (Buffer.byteLength(str) !== path.byteLength) - throw new Error(`Non-utf8 buffers are not supported at the moment. Please upvote the following issue if you encounter this error: https://github.com/yarnpkg/berry/issues/4942`); - return str; - } - throw new Error(`Unsupported path type: ${nodeUtils.inspect(path)}`); - } -} - -var _a, _b, _c, _d; -const kBaseFs = Symbol(`kBaseFs`); -const kFd = Symbol(`kFd`); -const kClosePromise = Symbol(`kClosePromise`); -const kCloseResolve = Symbol(`kCloseResolve`); -const kCloseReject = Symbol(`kCloseReject`); -const kRefs = Symbol(`kRefs`); -const kRef = Symbol(`kRef`); -const kUnref = Symbol(`kUnref`); -class FileHandle { - constructor(fd, baseFs) { - this[_a] = 1; - this[_b] = void 0; - this[_c] = void 0; - this[_d] = void 0; - this[kBaseFs] = baseFs; - this[kFd] = fd; - } - get fd() { - return this[kFd]; - } - async appendFile(data, options) { - var _a2; - try { - this[kRef](this.appendFile); - const encoding = (_a2 = typeof options === `string` ? options : options == null ? void 0 : options.encoding) != null ? _a2 : void 0; - return await this[kBaseFs].appendFilePromise(this.fd, data, encoding ? { encoding } : void 0); - } finally { - this[kUnref](); - } - } - async chown(uid, gid) { - try { - this[kRef](this.chown); - return await this[kBaseFs].fchownPromise(this.fd, uid, gid); - } finally { - this[kUnref](); - } - } - async chmod(mode) { - try { - this[kRef](this.chmod); - return await this[kBaseFs].fchmodPromise(this.fd, mode); - } finally { - this[kUnref](); - } - } - createReadStream(options) { - return this[kBaseFs].createReadStream(null, { ...options, fd: this.fd }); - } - createWriteStream(options) { - return this[kBaseFs].createWriteStream(null, { ...options, fd: this.fd }); - } - datasync() { - throw new Error(`Method not implemented.`); - } - sync() { - throw new Error(`Method not implemented.`); - } - async read(bufferOrOptions, offset, length, position) { - var _a2, _b2, _c2; - try { - this[kRef](this.read); - let buffer; - if (!Buffer.isBuffer(bufferOrOptions)) { - bufferOrOptions != null ? bufferOrOptions : bufferOrOptions = {}; - buffer = (_a2 = bufferOrOptions.buffer) != null ? _a2 : Buffer.alloc(16384); - offset = bufferOrOptions.offset || 0; - length = (_b2 = bufferOrOptions.length) != null ? _b2 : buffer.byteLength; - position = (_c2 = bufferOrOptions.position) != null ? _c2 : null; - } else { - buffer = bufferOrOptions; - } - offset != null ? offset : offset = 0; - length != null ? length : length = 0; - if (length === 0) { - return { - bytesRead: length, - buffer - }; - } - const bytesRead = await this[kBaseFs].readPromise(this.fd, buffer, offset, length, position); - return { - bytesRead, - buffer - }; - } finally { - this[kUnref](); - } - } - async readFile(options) { - var _a2; - try { - this[kRef](this.readFile); - const encoding = (_a2 = typeof options === `string` ? options : options == null ? void 0 : options.encoding) != null ? _a2 : void 0; - return await this[kBaseFs].readFilePromise(this.fd, encoding); - } finally { - this[kUnref](); - } - } - readLines(options) { - return readline.createInterface({ - input: this.createReadStream(options), - crlfDelay: Infinity - }); - } - async stat(opts) { - try { - this[kRef](this.stat); - return await this[kBaseFs].fstatPromise(this.fd, opts); - } finally { - this[kUnref](); - } - } - async truncate(len) { - try { - this[kRef](this.truncate); - return await this[kBaseFs].ftruncatePromise(this.fd, len); - } finally { - this[kUnref](); - } - } - utimes(atime, mtime) { - throw new Error(`Method not implemented.`); - } - async writeFile(data, options) { - var _a2; - try { - this[kRef](this.writeFile); - const encoding = (_a2 = typeof options === `string` ? options : options == null ? void 0 : options.encoding) != null ? _a2 : void 0; - await this[kBaseFs].writeFilePromise(this.fd, data, encoding); - } finally { - this[kUnref](); - } - } - async write(...args) { - try { - this[kRef](this.write); - if (ArrayBuffer.isView(args[0])) { - const [buffer, offset, length, position] = args; - const bytesWritten = await this[kBaseFs].writePromise(this.fd, buffer, offset != null ? offset : void 0, length != null ? length : void 0, position != null ? position : void 0); - return { bytesWritten, buffer }; - } else { - const [data, position, encoding] = args; - const bytesWritten = await this[kBaseFs].writePromise(this.fd, data, position, encoding); - return { bytesWritten, buffer: data }; - } - } finally { - this[kUnref](); - } - } - async writev(buffers, position) { - try { - this[kRef](this.writev); - let bytesWritten = 0; - if (typeof position !== `undefined`) { - for (const buffer of buffers) { - const writeResult = await this.write(buffer, void 0, void 0, position); - bytesWritten += writeResult.bytesWritten; - position += writeResult.bytesWritten; - } - } else { - for (const buffer of buffers) { - const writeResult = await this.write(buffer); - bytesWritten += writeResult.bytesWritten; - } - } - return { - buffers, - bytesWritten - }; - } finally { - this[kUnref](); - } - } - readv(buffers, position) { - throw new Error(`Method not implemented.`); - } - close() { - if (this[kFd] === -1) - return Promise.resolve(); - if (this[kClosePromise]) - return this[kClosePromise]; - this[kRefs]--; - if (this[kRefs] === 0) { - const fd = this[kFd]; - this[kFd] = -1; - this[kClosePromise] = this[kBaseFs].closePromise(fd).finally(() => { - this[kClosePromise] = void 0; - }); - } else { - this[kClosePromise] = new Promise((resolve, reject) => { - this[kCloseResolve] = resolve; - this[kCloseReject] = reject; - }).finally(() => { - this[kClosePromise] = void 0; - this[kCloseReject] = void 0; - this[kCloseResolve] = void 0; - }); - } - return this[kClosePromise]; - } - [(_a = kRefs, _b = kClosePromise, _c = kCloseResolve, _d = kCloseReject, kRef)](caller) { - if (this[kFd] === -1) { - const err = new Error(`file closed`); - err.code = `EBADF`; - err.syscall = caller.name; - throw err; - } - this[kRefs]++; - } - [kUnref]() { - this[kRefs]--; - if (this[kRefs] === 0) { - const fd = this[kFd]; - this[kFd] = -1; - this[kBaseFs].closePromise(fd).then(this[kCloseResolve], this[kCloseReject]); - } - } -} - -const SYNC_IMPLEMENTATIONS = /* @__PURE__ */ new Set([ - `accessSync`, - `appendFileSync`, - `createReadStream`, - `createWriteStream`, - `chmodSync`, - `fchmodSync`, - `chownSync`, - `fchownSync`, - `closeSync`, - `copyFileSync`, - `linkSync`, - `lstatSync`, - `fstatSync`, - `lutimesSync`, - `mkdirSync`, - `openSync`, - `opendirSync`, - `readlinkSync`, - `readFileSync`, - `readdirSync`, - `readlinkSync`, - `realpathSync`, - `renameSync`, - `rmdirSync`, - `statSync`, - `symlinkSync`, - `truncateSync`, - `ftruncateSync`, - `unlinkSync`, - `unwatchFile`, - `utimesSync`, - `watch`, - `watchFile`, - `writeFileSync`, - `writeSync` -]); -const ASYNC_IMPLEMENTATIONS = /* @__PURE__ */ new Set([ - `accessPromise`, - `appendFilePromise`, - `fchmodPromise`, - `chmodPromise`, - `fchownPromise`, - `chownPromise`, - `closePromise`, - `copyFilePromise`, - `linkPromise`, - `fstatPromise`, - `lstatPromise`, - `lutimesPromise`, - `mkdirPromise`, - `openPromise`, - `opendirPromise`, - `readdirPromise`, - `realpathPromise`, - `readFilePromise`, - `readdirPromise`, - `readlinkPromise`, - `renamePromise`, - `rmdirPromise`, - `statPromise`, - `symlinkPromise`, - `truncatePromise`, - `ftruncatePromise`, - `unlinkPromise`, - `utimesPromise`, - `writeFilePromise`, - `writeSync` -]); -function patchFs(patchedFs, fakeFs) { - fakeFs = new NodePathFS(fakeFs); - const setupFn = (target, name, replacement) => { - const orig = target[name]; - target[name] = replacement; - if (typeof (orig == null ? void 0 : orig[nodeUtils.promisify.custom]) !== `undefined`) { - replacement[nodeUtils.promisify.custom] = orig[nodeUtils.promisify.custom]; - } - }; - { - setupFn(patchedFs, `exists`, (p, ...args) => { - const hasCallback = typeof args[args.length - 1] === `function`; - const callback = hasCallback ? args.pop() : () => { - }; - process.nextTick(() => { - fakeFs.existsPromise(p).then((exists) => { - callback(exists); - }, () => { - callback(false); - }); - }); - }); - setupFn(patchedFs, `read`, (...args) => { - let [fd, buffer, offset, length, position, callback] = args; - if (args.length <= 3) { - let options = {}; - if (args.length < 3) { - callback = args[1]; - } else { - options = args[1]; - callback = args[2]; - } - ({ - buffer = Buffer.alloc(16384), - offset = 0, - length = buffer.byteLength, - position - } = options); - } - if (offset == null) - offset = 0; - length |= 0; - if (length === 0) { - process.nextTick(() => { - callback(null, 0, buffer); - }); - return; - } - if (position == null) - position = -1; - process.nextTick(() => { - fakeFs.readPromise(fd, buffer, offset, length, position).then((bytesRead) => { - callback(null, bytesRead, buffer); - }, (error) => { - callback(error, 0, buffer); - }); - }); - }); - for (const fnName of ASYNC_IMPLEMENTATIONS) { - const origName = fnName.replace(/Promise$/, ``); - if (typeof patchedFs[origName] === `undefined`) - continue; - const fakeImpl = fakeFs[fnName]; - if (typeof fakeImpl === `undefined`) - continue; - const wrapper = (...args) => { - const hasCallback = typeof args[args.length - 1] === `function`; - const callback = hasCallback ? args.pop() : () => { - }; - process.nextTick(() => { - fakeImpl.apply(fakeFs, args).then((result) => { - callback(null, result); - }, (error) => { - callback(error); - }); - }); - }; - setupFn(patchedFs, origName, wrapper); - } - patchedFs.realpath.native = patchedFs.realpath; - } - { - setupFn(patchedFs, `existsSync`, (p) => { - try { - return fakeFs.existsSync(p); - } catch (error) { - return false; - } - }); - setupFn(patchedFs, `readSync`, (...args) => { - let [fd, buffer, offset, length, position] = args; - if (args.length <= 3) { - const options = args[2] || {}; - ({ offset = 0, length = buffer.byteLength, position } = options); - } - if (offset == null) - offset = 0; - length |= 0; - if (length === 0) - return 0; - if (position == null) - position = -1; - return fakeFs.readSync(fd, buffer, offset, length, position); - }); - for (const fnName of SYNC_IMPLEMENTATIONS) { - const origName = fnName; - if (typeof patchedFs[origName] === `undefined`) - continue; - const fakeImpl = fakeFs[fnName]; - if (typeof fakeImpl === `undefined`) - continue; - setupFn(patchedFs, origName, fakeImpl.bind(fakeFs)); - } - patchedFs.realpathSync.native = patchedFs.realpathSync; - } - { - const origEmitWarning = process.emitWarning; - process.emitWarning = () => { - }; - let patchedFsPromises; - try { - patchedFsPromises = patchedFs.promises; - } finally { - process.emitWarning = origEmitWarning; - } - if (typeof patchedFsPromises !== `undefined`) { - for (const fnName of ASYNC_IMPLEMENTATIONS) { - const origName = fnName.replace(/Promise$/, ``); - if (typeof patchedFsPromises[origName] === `undefined`) - continue; - const fakeImpl = fakeFs[fnName]; - if (typeof fakeImpl === `undefined`) - continue; - if (fnName === `open`) - continue; - setupFn(patchedFsPromises, origName, (pathLike, ...args) => { - if (pathLike instanceof FileHandle) { - return pathLike[origName].apply(pathLike, args); - } else { - return fakeImpl.call(fakeFs, pathLike, ...args); - } - }); - } - setupFn(patchedFsPromises, `open`, async (...args) => { - const fd = await fakeFs.openPromise(...args); - return new FileHandle(fd, fakeFs); - }); - } - } - { - patchedFs.read[nodeUtils.promisify.custom] = async (fd, buffer, ...args) => { - const res = fakeFs.readPromise(fd, buffer, ...args); - return { bytesRead: await res, buffer }; - }; - patchedFs.write[nodeUtils.promisify.custom] = async (fd, buffer, ...args) => { - const res = fakeFs.writePromise(fd, buffer, ...args); - return { bytesWritten: await res, buffer }; - }; - } -} - -var libzipSync = {exports: {}}; - -(function (module, exports) { -var frozenFs = Object.assign({}, fs__default.default); -var createModule = function() { - var _scriptDir = void 0; - if (typeof __filename !== "undefined") - _scriptDir = _scriptDir || __filename; - return function(createModule2) { - createModule2 = createModule2 || {}; - var Module = typeof createModule2 !== "undefined" ? createModule2 : {}; - var readyPromiseResolve, readyPromiseReject; - Module["ready"] = new Promise(function(resolve, reject) { - readyPromiseResolve = resolve; - readyPromiseReject = reject; - }); - var moduleOverrides = {}; - var key; - for (key in Module) { - if (Module.hasOwnProperty(key)) { - moduleOverrides[key] = Module[key]; - } - } - var scriptDirectory = ""; - function locateFile(path) { - if (Module["locateFile"]) { - return Module["locateFile"](path, scriptDirectory); - } - return scriptDirectory + path; - } - var read_, readBinary; - var nodeFS; - var nodePath; - { - { - scriptDirectory = __dirname + "/"; - } - read_ = function shell_read(filename, binary) { - var ret = tryParseAsDataURI(filename); - if (ret) { - return binary ? ret : ret.toString(); - } - if (!nodeFS) - nodeFS = frozenFs; - if (!nodePath) - nodePath = path__default.default; - filename = nodePath["normalize"](filename); - return nodeFS["readFileSync"](filename, binary ? null : "utf8"); - }; - readBinary = function readBinary2(filename) { - var ret = read_(filename, true); - if (!ret.buffer) { - ret = new Uint8Array(ret); - } - assert(ret.buffer); - return ret; - }; - if (process["argv"].length > 1) { - process["argv"][1].replace(/\\/g, "/"); - } - process["argv"].slice(2); - Module["inspect"] = function() { - return "[Emscripten Module object]"; - }; - } - var out = Module["print"] || console.log.bind(console); - var err = Module["printErr"] || console.warn.bind(console); - for (key in moduleOverrides) { - if (moduleOverrides.hasOwnProperty(key)) { - Module[key] = moduleOverrides[key]; - } - } - moduleOverrides = null; - if (Module["arguments"]) - ; - if (Module["thisProgram"]) - ; - if (Module["quit"]) - ; - var STACK_ALIGN = 16; - function alignMemory(size, factor) { - if (!factor) - factor = STACK_ALIGN; - return Math.ceil(size / factor) * factor; - } - var wasmBinary; - if (Module["wasmBinary"]) - wasmBinary = Module["wasmBinary"]; - Module["noExitRuntime"] || true; - if (typeof WebAssembly !== "object") { - abort("no native wasm support detected"); - } - function getValue(ptr, type, noSafe) { - type = type || "i8"; - if (type.charAt(type.length - 1) === "*") - type = "i32"; - switch (type) { - case "i1": - return HEAP8[ptr >> 0]; - case "i8": - return HEAP8[ptr >> 0]; - case "i16": - return HEAP16[ptr >> 1]; - case "i32": - return HEAP32[ptr >> 2]; - case "i64": - return HEAP32[ptr >> 2]; - case "float": - return HEAPF32[ptr >> 2]; - case "double": - return HEAPF64[ptr >> 3]; - default: - abort("invalid type for getValue: " + type); - } - return null; - } - var wasmMemory; - var ABORT = false; - function assert(condition, text) { - if (!condition) { - abort("Assertion failed: " + text); - } - } - function getCFunc(ident) { - var func = Module["_" + ident]; - assert( - func, - "Cannot call unknown function " + ident + ", make sure it is exported" - ); - return func; - } - function ccall(ident, returnType, argTypes, args, opts) { - var toC = { - string: function(str) { - var ret2 = 0; - if (str !== null && str !== void 0 && str !== 0) { - var len = (str.length << 2) + 1; - ret2 = stackAlloc(len); - stringToUTF8(str, ret2, len); - } - return ret2; - }, - array: function(arr) { - var ret2 = stackAlloc(arr.length); - writeArrayToMemory(arr, ret2); - return ret2; - } - }; - function convertReturnValue(ret2) { - if (returnType === "string") - return UTF8ToString(ret2); - if (returnType === "boolean") - return Boolean(ret2); - return ret2; - } - var func = getCFunc(ident); - var cArgs = []; - var stack = 0; - if (args) { - for (var i = 0; i < args.length; i++) { - var converter = toC[argTypes[i]]; - if (converter) { - if (stack === 0) - stack = stackSave(); - cArgs[i] = converter(args[i]); - } else { - cArgs[i] = args[i]; - } - } - } - var ret = func.apply(null, cArgs); - ret = convertReturnValue(ret); - if (stack !== 0) - stackRestore(stack); - return ret; - } - function cwrap(ident, returnType, argTypes, opts) { - argTypes = argTypes || []; - var numericArgs = argTypes.every(function(type) { - return type === "number"; - }); - var numericRet = returnType !== "string"; - if (numericRet && numericArgs && !opts) { - return getCFunc(ident); - } - return function() { - return ccall(ident, returnType, argTypes, arguments); - }; - } - var UTF8Decoder = typeof TextDecoder !== "undefined" ? new TextDecoder("utf8") : void 0; - function UTF8ArrayToString(heap, idx, maxBytesToRead) { - var endIdx = idx + maxBytesToRead; - var endPtr = idx; - while (heap[endPtr] && !(endPtr >= endIdx)) - ++endPtr; - if (endPtr - idx > 16 && heap.subarray && UTF8Decoder) { - return UTF8Decoder.decode(heap.subarray(idx, endPtr)); - } else { - var str = ""; - while (idx < endPtr) { - var u0 = heap[idx++]; - if (!(u0 & 128)) { - str += String.fromCharCode(u0); - continue; - } - var u1 = heap[idx++] & 63; - if ((u0 & 224) == 192) { - str += String.fromCharCode((u0 & 31) << 6 | u1); - continue; - } - var u2 = heap[idx++] & 63; - if ((u0 & 240) == 224) { - u0 = (u0 & 15) << 12 | u1 << 6 | u2; - } else { - u0 = (u0 & 7) << 18 | u1 << 12 | u2 << 6 | heap[idx++] & 63; - } - if (u0 < 65536) { - str += String.fromCharCode(u0); - } else { - var ch = u0 - 65536; - str += String.fromCharCode(55296 | ch >> 10, 56320 | ch & 1023); - } - } - } - return str; - } - function UTF8ToString(ptr, maxBytesToRead) { - return ptr ? UTF8ArrayToString(HEAPU8, ptr, maxBytesToRead) : ""; - } - function stringToUTF8Array(str, heap, outIdx, maxBytesToWrite) { - if (!(maxBytesToWrite > 0)) - return 0; - var startIdx = outIdx; - var endIdx = outIdx + maxBytesToWrite - 1; - for (var i = 0; i < str.length; ++i) { - var u = str.charCodeAt(i); - if (u >= 55296 && u <= 57343) { - var u1 = str.charCodeAt(++i); - u = 65536 + ((u & 1023) << 10) | u1 & 1023; - } - if (u <= 127) { - if (outIdx >= endIdx) - break; - heap[outIdx++] = u; - } else if (u <= 2047) { - if (outIdx + 1 >= endIdx) - break; - heap[outIdx++] = 192 | u >> 6; - heap[outIdx++] = 128 | u & 63; - } else if (u <= 65535) { - if (outIdx + 2 >= endIdx) - break; - heap[outIdx++] = 224 | u >> 12; - heap[outIdx++] = 128 | u >> 6 & 63; - heap[outIdx++] = 128 | u & 63; - } else { - if (outIdx + 3 >= endIdx) - break; - heap[outIdx++] = 240 | u >> 18; - heap[outIdx++] = 128 | u >> 12 & 63; - heap[outIdx++] = 128 | u >> 6 & 63; - heap[outIdx++] = 128 | u & 63; - } - } - heap[outIdx] = 0; - return outIdx - startIdx; - } - function stringToUTF8(str, outPtr, maxBytesToWrite) { - return stringToUTF8Array(str, HEAPU8, outPtr, maxBytesToWrite); - } - function lengthBytesUTF8(str) { - var len = 0; - for (var i = 0; i < str.length; ++i) { - var u = str.charCodeAt(i); - if (u >= 55296 && u <= 57343) - u = 65536 + ((u & 1023) << 10) | str.charCodeAt(++i) & 1023; - if (u <= 127) - ++len; - else if (u <= 2047) - len += 2; - else if (u <= 65535) - len += 3; - else - len += 4; - } - return len; - } - function allocateUTF8(str) { - var size = lengthBytesUTF8(str) + 1; - var ret = _malloc(size); - if (ret) - stringToUTF8Array(str, HEAP8, ret, size); - return ret; - } - function writeArrayToMemory(array, buffer2) { - HEAP8.set(array, buffer2); - } - function alignUp(x, multiple) { - if (x % multiple > 0) { - x += multiple - x % multiple; - } - return x; - } - var buffer, HEAP8, HEAPU8, HEAP16, HEAP32, HEAPF32, HEAPF64; - function updateGlobalBufferAndViews(buf) { - buffer = buf; - Module["HEAP8"] = HEAP8 = new Int8Array(buf); - Module["HEAP16"] = HEAP16 = new Int16Array(buf); - Module["HEAP32"] = HEAP32 = new Int32Array(buf); - Module["HEAPU8"] = HEAPU8 = new Uint8Array(buf); - Module["HEAPU16"] = new Uint16Array(buf); - Module["HEAPU32"] = new Uint32Array(buf); - Module["HEAPF32"] = HEAPF32 = new Float32Array(buf); - Module["HEAPF64"] = HEAPF64 = new Float64Array(buf); - } - Module["INITIAL_MEMORY"] || 16777216; - var wasmTable; - var __ATPRERUN__ = []; - var __ATINIT__ = []; - var __ATPOSTRUN__ = []; - function preRun() { - if (Module["preRun"]) { - if (typeof Module["preRun"] == "function") - Module["preRun"] = [Module["preRun"]]; - while (Module["preRun"].length) { - addOnPreRun(Module["preRun"].shift()); - } - } - callRuntimeCallbacks(__ATPRERUN__); - } - function initRuntime() { - if (!Module["noFSInit"] && !FS.init.initialized) - FS.init(); - callRuntimeCallbacks(__ATINIT__); - } - function postRun() { - if (Module["postRun"]) { - if (typeof Module["postRun"] == "function") - Module["postRun"] = [Module["postRun"]]; - while (Module["postRun"].length) { - addOnPostRun(Module["postRun"].shift()); - } - } - callRuntimeCallbacks(__ATPOSTRUN__); - } - function addOnPreRun(cb) { - __ATPRERUN__.unshift(cb); - } - function addOnInit(cb) { - __ATINIT__.unshift(cb); - } - function addOnPostRun(cb) { - __ATPOSTRUN__.unshift(cb); - } - var runDependencies = 0; - var dependenciesFulfilled = null; - function addRunDependency(id) { - runDependencies++; - if (Module["monitorRunDependencies"]) { - Module["monitorRunDependencies"](runDependencies); - } - } - function removeRunDependency(id) { - runDependencies--; - if (Module["monitorRunDependencies"]) { - Module["monitorRunDependencies"](runDependencies); - } - if (runDependencies == 0) { - if (dependenciesFulfilled) { - var callback = dependenciesFulfilled; - dependenciesFulfilled = null; - callback(); - } - } - } - Module["preloadedImages"] = {}; - Module["preloadedAudios"] = {}; - function abort(what) { - if (Module["onAbort"]) { - Module["onAbort"](what); - } - what += ""; - err(what); - ABORT = true; - what = "abort(" + what + "). Build with -s ASSERTIONS=1 for more info."; - var e = new WebAssembly.RuntimeError(what); - readyPromiseReject(e); - throw e; - } - var dataURIPrefix = "data:application/octet-stream;base64,"; - function isDataURI(filename) { - return filename.startsWith(dataURIPrefix); - } - var wasmBinaryFile = "data:application/octet-stream;base64,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ACgCFC0AAiAAKAIYajYCGCAAIAAoAhggACgCDGo2AgwgACAAKAIULQADIAAoAhhqNgIYIAAgACgCGCAAKAIMajYCDCAAIAAoAhQtAAQgACgCGGo2AhggACAAKAIYIAAoAgxqNgIMIAAgACgCFC0ABSAAKAIYajYCGCAAIAAoAhggACgCDGo2AgwgACAAKAIULQAGIAAoAhhqNgIYIAAgACgCGCAAKAIMajYCDCAAIAAoAhQtAAcgACgCGGo2AhggACAAKAIYIAAoAgxqNgIMIAAgACgCFC0ACCAAKAIYajYCGCAAIAAoAhggACgCDGo2AgwgACAAKAIULQAJIAAoAhhqNgIYIAAgACgCGCAAKAIMajYCDCAAIAAoAhQtAAogACgCGGo2AhggACAAKAIYIAAoAgxqNgIMIAAgACgCFC0ACyAAKAIYajYCGCAAIAAoAhggACgCDGo2AgwgACAAKAIULQAMIAAoAhhqNgIYIAAgACgCGCAAKAIMajYCDCAAIAAoAhQtAA0gACgCGGo2AhggACAAKAIYIAAoAgxqNgIMIAAgACgCFC0ADiAAKAIYajYCGCAAIAAoAhggACgCDGo2AgwgACAAKAIULQAPIAAoAhhqNgIYIAAgACgCGCAAKAIMajYCDCAAIAAoAhRBEGo2AhQgACAAKAIIQQFrIgE2AgggAQ0ACyAAIAAoAhhB8f8DcDYCGCAAIAAoAgxB8f8DcDYCDAwBCwsgACgCEARAA0AgACgCEEEQTwRAIAAgACgCEEEQazYCECAAIAAoAhQtAAAgACgCGGo2AhggACAAKAIYIAAoAgxqNgIMIAAgACgCFC0AASAAKAIYajYCGCAAIAAoAhggACgCDGo2AgwgACAAKAIULQACIAAoAhhqNgIYIAAgACgCGCAAKAIMajYCDCAAIAAoAhQtAAMgACgCGGo2AhggACAAKAIYIAAoAgxqNgIMIAAgACgCFC0ABCAAKAIYajYCGCAAIAAoAhggACgCDGo2AgwgACAAKAIULQAFIAAoAhhqNgIYIAAgACgCGCAAKAIMajYCDCAAIAAoAhQtAAYgACgCGGo2AhggACAAKAIYIAAoAgxqNgIMIAAgACgCFC0AByAAKAIYajYCGCAAIAAoAhggACgCDGo2AgwgACAAKAIULQAIIAAoAhhqNgIYIAAgACgCGCAAKAIMajYC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NgIYIAEoAgxCADcDICABKAIMQgA3AyggASgCDEEANgIwIAEoAgxBADYCNCABKAIMQQA2AjggASgCDEEANgI8IAEoAgxBADsBQCABKAIMQYCA2I14NgJEIAEoAgxCADcDSCABKAIMQQA7AVAgASgCDEEAOwFSIAEoAgxBADYCVAvSEwEBfyMAQbABayIDJAAgAyAANgKoASADIAE2AqQBIAMgAjYCoAEgA0EANgKQASADIAMoAqQBKAIwQQAQOjYClAEgAyADKAKkASgCOEEAEDo2ApgBAkACQAJAAkAgAygClAFBAkYEQCADKAKYAUEBRg0BCyADKAKUAUEBRgRAIAMoApgBQQJGDQELIAMoApQBQQJHDQEgAygCmAFBAkcNAQsgAygCpAEiACAALwEMQYAQcjsBDAwBCyADKAKkASIAIAAvAQxB/+8DcTsBDCADKAKUAUECRgRAIANB9eABIAMoAqQBKAIwIAMoAqgBQQhqEI4BNgKQASADKAKQAUUEQCADQX82AqwBDAMLCwJAIAMoAqABQYACcQ0AIAMoApgBQQJHDQAgA0H1xgEgAygCpAEoAjggAygCqAFBCGoQjgE2AkggAygCSEUEQCADKAKQARAjIANBfzYCrAEMAwsgAygCSCADKAKQATYCACADIAMoAkg2ApABCwsCQCADKAKkAS8BUkUEQCADKAKkASIAIAAvAQxB/v8DcTsBDAwBCyADKAKkASIAIAAvAQxBAXI7AQwLIAMgAygCpAEgAygCoAEQZUEBcToAhgEgAyADKAKgAUGACnFBgApHBH8gAy0AhgEFQQELQQFxOgCHASADAn9BASADKAKkAS8BUkGBAkYNABpBASADKAKkAS8BUkGCAkYNABogAygCpAEvAVJBgwJGC0EBcToAhQEgAy0AhwFBAXEEQCADIANBIGpCHBApNgIcIAMoAhxFBEAgAygCqAFBCGpBDkEAEBQgAygCkAEQIyADQX82AqwBDAILAkAgAygCoAFBgAJxBEACQCADKAKgAUGACHENACADKAKkASkDIEL/////D1YNACADKAKkASkDKEL/////D1gNAgsgAygCHCADKAKkASkDKBAtIAMoAhwgAygCpAEpAyAQLQwBCwJAAkAgAygCoAFBgAhxDQAgAygCpAEpAyBC/////w9WDQAgAygCpAEpAyhC/////w9WDQAgAygCpAEpA0hC/////w9YDQELIAMoAqQBKQMoQv////8PWgRAIAMoAhwgAygCpAEpAygQLQsgAygCpAEpAyBC/////w9aBEAgAygCHCADKAKkASkDIBAtCyADKAKkASkDSEL/////D1oEQCADKAIcIAMoAqQBKQNIEC0LCwsCfyMAQRBrIgAgAygCHDYCDCAAKAIMLQAAQQFxRQsEQCADKAKoAUEIakEUQQAQFCADKAIcEBYgAygCkAEQIyADQX82AqwBDAILIANBAQJ/IwBBEGsiACADKAIcNgIMAn4gACgCDC0AAEEBcQRAIAAoAgwpAxAMAQtCAAunQf//A3ELIANBIGpBgAYQVTYCjAEgAygCHBAWIAMoAowBIAMoApABNgIAIAMgAygCjAE2ApABCyADLQCFAUEBcQRAIAMgA0EVakIHECk2AhAgAygCEEUEQCADKAKoAUEIakEOQQAQFCADKAKQARAjIANBfzYCrAEMAgsgAygCEEECEB8gAygCEEG9EkECEEEgAygCECADKAKkAS8BUkH/AXEQlgEgAygCECADKAKkASgCEEH//wNxEB8CfyMAQRBrIgAgAygCEDYCDCAAKAIMLQAAQQFxRQsEQCADKAKoAUEIakEUQQAQFCADKAIQEBYgAygCkAEQIyADQX82AqwBDAILIANBgbICQQcgA0EVakGABhBVNgIMIAMoAhAQFiADKAIMIAMoApABNgIAIAMgAygCDDYCkAELIAMgA0HQAGpCLhApIgA2AkwgAEUEQCADKAKoAUEIakEOQQAQFCADKAKQARAjIANBfzYCrAEMAQsgAygCTEHxEkH2EiADKAKgAUGAAnEbQQQQQSADKAKgAUGAAnFFBEAgAygCTCADLQCGAUEBcQR/QS0FIAMoAqQBLwEIC0H//wNxEB8LIAMoAkwgAy0AhgFBAXEEf0EtBSADKAKkAS8BCgtB//8DcRAfIAMoAkwgAygCpAEvAQwQHwJAIAMtAIUBQQFxBEAgAygCTEHjABAfDAELIAMoAkwgAygCpAEoAhBB//8DcRAfCyADKAKkASgCFCADQZ4BaiADQZwBahCNASADKAJMIAMvAZ4BEB8gAygCTCADLwGcARAfAkACQCADLQCFAUEBcUUNACADKAKkASkDKEIUWg0AIAMoAkxBABAhDAELIAMoAkwgAygCpAEoAhgQIQsCQAJAIAMoAqABQYACcUGAAkcNACADKAKkASkDIEL/////D1QEQCADKAKkASkDKEL/////D1QNAQsgAygCTEF/ECEgAygCTEF/ECEMAQsCQCADKAKkASkDIEL/////D1QEQCADKAJMIAMoAqQBKQMgpxAhDAELIAMoAkxBfxAhCwJAIAMoAqQBKQMoQv////8PVARAIAMoAkwgAygCpAEpAyinECEMAQsgAygCTEF/ECELCyADKAJMIAMoAqQBKAIwEFFB//8DcRAfIAMgAygCpAEoAjQgAygCoAEQkgFB//8DcSADKAKQAUGABhCSAUH//wNxajYCiAEgAygCTCADKAKIAUH//wNxEB8gAygCoAFBgAJxRQRAIAMoAkwgAygCpAEoAjgQUUH//wNxEB8gAygCTCADKAKkASgCPEH//wNxEB8gAygCTCADKAKkAS8BQBAfIAMoAkwgAygCpAEoAkQQIQJAIAMoAqQBKQNIQv////8PVARAIAMoAkwgAygCpAEpA0inECEMAQsgAygCTEF/ECELCwJ/IwBBEGsiACADKAJMNgIMIAAoAgwtAABBAXFFCwRAIAMoAqgBQQhqQRRBABAUIAMoAkwQFiADKAKQARAjIANBfzYCrAEMAQsgAygCqAEgA0HQAGoCfiMAQRBrIgAgAygCTDYCDAJ+IAAoAgwtAABBAXEEQCAAKAIMKQMQDAELQgALCxA2QQBIBEAgAygCTBAWIAMoApABECMgA0F/NgKsAQwBCyADKAJMEBYgAygCpAEoAjAEQCADKAKoASADKAKkASgCMBCFAUEASARAIAMoApABECMgA0F/NgKsAQwCCwsgAygCkAEEQCADKAKoASADKAKQAUGABhCRAUEASARAIAMoApABECMgA0F/NgKsAQwCCwsgAygCkAEQIyADKAKkASgCNARAIAMoAqgBIAMoAqQBKAI0IAMoAqABEJEBQQBIBEAgA0F/NgKsAQwCCwsgAygCoAFBgAJxRQRAIAMoAqQBKAI4BEAgAygCqAEgAygCpAEoAjgQhQFBAEgEQCADQX82AqwBDAMLCwsgAyADLQCHAUEBcTYCrAELIAMoAqwBIQAgA0GwAWokACAAC+ACAQF/IwBBIGsiBCQAIAQgADsBGiAEIAE7ARggBCACNgIUIAQgAzYCECAEQRAQGCIANgIMAkAgAEUEQCAEQQA2AhwMAQsgBCgCDEEANgIAIAQoAgwgBCgCEDYCBCAEKAIMIAQvARo7AQggBCgCDCAELwEYOwEKAkAgBC8BGARAIAQoAhQhASAELwEYIQIjAEEgayIAJAAgACABNgIYIAAgAjYCFCAAQQA2AhACQCAAKAIURQRAIABBADYCHAwBCyAAIAAoAhQQGDYCDCAAKAIMRQRAIAAoAhBBDkEAEBQgAEEANgIcDAELIAAoAgwgACgCGCAAKAIUEBkaIAAgACgCDDYCHAsgACgCHCEBIABBIGokACABIQAgBCgCDCAANgIMIABFBEAgBCgCDBAVIARBADYCHAwDCwwBCyAEKAIMQQA2AgwLIAQgBCgCDDYCHAsgBCgCHCEAIARBIGokACAAC5EBAQV/IAAoAkxBAE4hAyAAKAIAQQFxIgRFBEAgACgCNCIBBEAgASAAKAI4NgI4CyAAKAI4IgIEQCACIAE2AjQLIABBrKABKAIARgRAQaygASACNgIACwsgABClASEBIAAgACgCDBEAACECIAAoAmAiBQRAIAUQFQsCQCAERQRAIAAQFQwBCyADRQ0ACyABIAJyC/kBAQF/IwBBIGsiAiQAIAIgADYCHCACIAE5AxACQCACKAIcRQ0AIAICfAJ8IAIrAxBEAAAAAAAAAABkBEAgAisDEAwBC0QAAAAAAAAAAAtEAAAAAAAA8D9jBEACfCACKwMQRAAAAAAAAAAAZARAIAIrAxAMAQtEAAAAAAAAAAALDAELRAAAAAAAAPA/CyACKAIcKwMoIAIoAhwrAyChoiACKAIcKwMgoDkDCCACKAIcKwMQIAIrAwggAigCHCsDGKFjRQ0AIAIoAhwoAgAgAisDCCACKAIcKAIMIAIoAhwoAgQRFgAgAigCHCACKwMIOQMYCyACQSBqJAAL4QUCAn8BfiMAQTBrIgQkACAEIAA2AiQgBCABNgIgIAQgAjYCHCAEIAM2AhgCQCAEKAIkRQRAIARCfzcDKAwBCyAEKAIgRQRAIAQoAhhBEkEAEBQgBEJ/NwMoDAELIAQoAhxBgyBxBEAgBEEVQRYgBCgCHEEBcRs2AhQgBEIANwMAA0AgBCkDACAEKAIkKQMwVARAIAQgBCgCJCAEKQMAIAQoAhwgBCgCGBBNNgIQIAQoAhAEQCAEKAIcQQJxBEAgBAJ/IAQoAhAiARAuQQFqIQADQEEAIABFDQEaIAEgAEEBayIAaiICLQAAQS9HDQALIAILNgIMIAQoAgwEQCAEIAQoAgxBAWo2AhALCyAEKAIgIAQoAhAgBCgCFBEDAEUEQCMAQRBrIgAgBCgCGDYCDCAAKAIMBEAgACgCDEEANgIAIAAoAgxBADYCBAsgBCAEKQMANwMoDAULCyAEIAQpAwBCAXw3AwAMAQsLIAQoAhhBCUEAEBQgBEJ/NwMoDAELIAQoAiQoAlAhASAEKAIgIQIgBCgCHCEDIAQoAhghBSMAQTBrIgAkACAAIAE2AiQgACACNgIgIAAgAzYCHCAAIAU2AhgCQAJAIAAoAiQEQCAAKAIgDQELIAAoAhhBEkEAEBQgAEJ/NwMoDAELIAAoAiQpAwhCAFIEQCAAIAAoAiAQczYCFCAAIAAoAhQgACgCJCgCAHA2AhAgACAAKAIkKAIQIAAoAhBBAnRqKAIANgIMA0ACQCAAKAIMRQ0AIAAoAiAgACgCDCgCABBbBEAgACAAKAIMKAIYNgIMDAIFIAAoAhxBCHEEQCAAKAIMKQMIQn9SBEAgACAAKAIMKQMINwMoDAYLDAILIAAoAgwpAxBCf1IEQCAAIAAoAgwpAxA3AygMBQsLCwsLIAAoAhhBCUEAEBQgAEJ/NwMoCyAAKQMoIQYgAEEwaiQAIAQgBjcDKAsgBCkDKCEGIARBMGokACAGC9QDAQF/IwBBIGsiAyQAIAMgADYCGCADIAE2AhQgAyACNgIQAkACQCADKAIYBEAgAygCFA0BCyADKAIQQRJBABAUIANBADoAHwwBCyADKAIYKQMIQgBSBEAgAyADKAIUEHM2AgwgAyADKAIMIAMoAhgoAgBwNgIIIANBADYCACADIAMoAhgoAhAgAygCCEECdGooAgA2AgQDQCADKAIEBEACQCADKAIEKAIcIAMoAgxHDQAgAygCFCADKAIEKAIAEFsNAAJAIAMoAgQpAwhCf1EEQAJAIAMoAgAEQCADKAIAIAMoAgQoAhg2AhgMAQsgAygCGCgCECADKAIIQQJ0aiADKAIEKAIYNgIACyADKAIEEBUgAygCGCIAIAApAwhCAX03AwgCQCADKAIYIgApAwi6IAAoAgC4RHsUrkfheoQ/omNFDQAgAygCGCgCAEGAAk0NACADKAIYIAMoAhgoAgBBAXYgAygCEBBaQQFxRQRAIANBADoAHwwICwsMAQsgAygCBEJ/NwMQCyADQQE6AB8MBAsgAyADKAIENgIAIAMgAygCBCgCGDYCBAwBCwsLIAMoAhBBCUEAEBQgA0EAOgAfCyADLQAfQQFxIQAgA0EgaiQAIAAL3wIBAX8jAEEwayIDJAAgAyAANgIoIAMgATYCJCADIAI2AiACQCADKAIkIAMoAigoAgBGBEAgA0EBOgAvDAELIAMgAygCJEEEEH8iADYCHCAARQRAIAMoAiBBDkEAEBQgA0EAOgAvDAELIAMoAigpAwhCAFIEQCADQQA2AhgDQCADKAIYIAMoAigoAgBPRQRAIAMgAygCKCgCECADKAIYQQJ0aigCADYCFANAIAMoAhQEQCADIAMoAhQoAhg2AhAgAyADKAIUKAIcIAMoAiRwNgIMIAMoAhQgAygCHCADKAIMQQJ0aigCADYCGCADKAIcIAMoAgxBAnRqIAMoAhQ2AgAgAyADKAIQNgIUDAELCyADIAMoAhhBAWo2AhgMAQsLCyADKAIoKAIQEBUgAygCKCADKAIcNgIQIAMoAiggAygCJDYCACADQQE6AC8LIAMtAC9BAXEhACADQTBqJAAgAAtNAQJ/IAEtAAAhAgJAIAAtAAAiA0UNACACIANHDQADQCABLQABIQIgAC0AASIDRQ0BIAFBAWohASAAQQFqIQAgAiADRg0ACwsgAyACawvRCQECfyMAQSBrIgEkACABIAA2AhwgASABKAIcKAIsNgIQA0AgASABKAIcKAI8IAEoAhwoAnRrIAEoAhwoAmxrNgIUIAEoAhwoAmwgASgCECABKAIcKAIsQYYCa2pPBEAgASgCHCgCOCABKAIcKAI4IAEoAhBqIAEoAhAgASgCFGsQGRogASgCHCIAIAAoAnAgASgCEGs2AnAgASgCHCIAIAAoAmwgASgCEGs2AmwgASgCHCIAIAAoAlwgASgCEGs2AlwjAEEgayIAIAEoAhw2AhwgACAAKAIcKAIsNgIMIAAgACgCHCgCTDYCGCAAIAAoAhwoAkQgACgCGEEBdGo2AhADQCAAIAAoAhBBAmsiAjYCECAAIAIvAQA2AhQgACgCEAJ/IAAoAhQgACgCDE8EQCAAKAIUIAAoAgxrDAELQQALOwEAIAAgACgCGEEBayICNgIYIAINAAsgACAAKAIMNgIYIAAgACgCHCgCQCAAKAIYQQF0ajYCEANAIAAgACgCEEECayICNgIQIAAgAi8BADYCFCAAKAIQAn8gACgCFCAAKAIMTwRAIAAoAhQgACgCDGsMAQtBAAs7AQAgACAAKAIYQQFrIgI2AhggAg0ACyABIAEoAhAgASgCFGo2AhQLIAEoAhwoAgAoAgQEQCABIAEoAhwoAgAgASgCHCgCdCABKAIcKAI4IAEoAhwoAmxqaiABKAIUEHY2AhggASgCHCIAIAEoAhggACgCdGo2AnQgASgCHCgCdCABKAIcKAK0LWpBA08EQCABIAEoAhwoAmwgASgCHCgCtC1rNgIMIAEoAhwgASgCHCgCOCABKAIMai0AADYCSCABKAIcIAEoAhwoAlQgASgCHCgCOCABKAIMQQFqai0AACABKAIcKAJIIAEoAhwoAlh0c3E2AkgDQCABKAIcKAK0LQRAIAEoAhwgASgCHCgCVCABKAIcKAI4IAEoAgxBAmpqLQAAIAEoAhwoAkggASgCHCgCWHRzcTYCSCABKAIcKAJAIAEoAgwgASgCHCgCNHFBAXRqIAEoAhwoAkQgASgCHCgCSEEBdGovAQA7AQAgASgCHCgCRCABKAIcKAJIQQF0aiABKAIMOwEAIAEgASgCDEEBajYCDCABKAIcIgAgACgCtC1BAWs2ArQtIAEoAhwoAnQgASgCHCgCtC1qQQNPDQELCwsgASgCHCgCdEGGAkkEfyABKAIcKAIAKAIEQQBHBUEAC0EBcQ0BCwsgASgCHCgCwC0gASgCHCgCPEkEQCABIAEoAhwoAmwgASgCHCgCdGo2AggCQCABKAIcKALALSABKAIISQRAIAEgASgCHCgCPCABKAIIazYCBCABKAIEQYICSwRAIAFBggI2AgQLIAEoAhwoAjggASgCCGpBACABKAIEEDMgASgCHCABKAIIIAEoAgRqNgLALQwBCyABKAIcKALALSABKAIIQYICakkEQCABIAEoAghBggJqIAEoAhwoAsAtazYCBCABKAIEIAEoAhwoAjwgASgCHCgCwC1rSwRAIAEgASgCHCgCPCABKAIcKALALWs2AgQLIAEoAhwoAjggASgCHCgCwC1qQQAgASgCBBAzIAEoAhwiACABKAIEIAAoAsAtajYCwC0LCwsgAUEgaiQAC4YFAQF/IwBBIGsiBCQAIAQgADYCHCAEIAE2AhggBCACNgIUIAQgAzYCECAEQQM2AgwCQCAEKAIcKAK8LUEQIAQoAgxrSgRAIAQgBCgCEDYCCCAEKAIcIgAgAC8BuC0gBCgCCEH//wNxIAQoAhwoArwtdHI7AbgtIAQoAhwvAbgtQf8BcSEBIAQoAhwoAgghAiAEKAIcIgMoAhQhACADIABBAWo2AhQgACACaiABOgAAIAQoAhwvAbgtQQh2IQEgBCgCHCgCCCECIAQoAhwiAygCFCEAIAMgAEEBajYCFCAAIAJqIAE6AAAgBCgCHCAEKAIIQf//A3FBECAEKAIcKAK8LWt1OwG4LSAEKAIcIgAgACgCvC0gBCgCDEEQa2o2ArwtDAELIAQoAhwiACAALwG4LSAEKAIQQf//A3EgBCgCHCgCvC10cjsBuC0gBCgCHCIAIAQoAgwgACgCvC1qNgK8LQsgBCgCHBC9ASAEKAIUQf8BcSEBIAQoAhwoAgghAiAEKAIcIgMoAhQhACADIABBAWo2AhQgACACaiABOgAAIAQoAhRB//8DcUEIdiEBIAQoAhwoAgghAiAEKAIcIgMoAhQhACADIABBAWo2AhQgACACaiABOgAAIAQoAhRBf3NB/wFxIQEgBCgCHCgCCCECIAQoAhwiAygCFCEAIAMgAEEBajYCFCAAIAJqIAE6AAAgBCgCFEF/c0H//wNxQQh2IQEgBCgCHCgCCCECIAQoAhwiAygCFCEAIAMgAEEBajYCFCAAIAJqIAE6AAAgBCgCHCgCCCAEKAIcKAIUaiAEKAIYIAQoAhQQGRogBCgCHCIAIAQoAhQgACgCFGo2AhQgBEEgaiQAC6sBAQF/IwBBEGsiASQAIAEgADYCDCABKAIMKAIIBEAgASgCDCgCCBAbIAEoAgxBADYCCAsCQCABKAIMKAIERQ0AIAEoAgwoAgQoAgBBAXFFDQAgASgCDCgCBCgCEEF+Rw0AIAEoAgwoAgQiACAAKAIAQX5xNgIAIAEoAgwoAgQoAgBFBEAgASgCDCgCBBA3IAEoAgxBADYCBAsLIAEoAgxBADoADCABQRBqJAAL8QMBAX8jAEHQAGsiCCQAIAggADYCSCAIIAE3A0AgCCACNwM4IAggAzYCNCAIIAQ6ADMgCCAFNgIsIAggBjcDICAIIAc2AhwCQAJAAkAgCCgCSEUNACAIKQNAIAgpA0AgCCkDOHxWDQAgCCgCLA0BIAgpAyBQDQELIAgoAhxBEkEAEBQgCEEANgJMDAELIAhBgAEQGCIANgIYIABFBEAgCCgCHEEOQQAQFCAIQQA2AkwMAQsgCCgCGCAIKQNANwMAIAgoAhggCCkDQCAIKQM4fDcDCCAIKAIYQShqEDsgCCgCGCAILQAzOgBgIAgoAhggCCgCLDYCECAIKAIYIAgpAyA3AxgjAEEQayIAIAgoAhhB5ABqNgIMIAAoAgxBADYCACAAKAIMQQA2AgQgACgCDEEANgIIIwBBEGsiACAIKAJINgIMIAAoAgwpAxhC/4EBgyEBIAhBfzYCCCAIQQc2AgQgCEEONgIAQRAgCBA0IAGEIQEgCCgCGCABNwNwIAgoAhggCCgCGCkDcELAAINCAFI6AHggCCgCNARAIAgoAhhBKGogCCgCNCAIKAIcEIQBQQBIBEAgCCgCGBAVIAhBADYCTAwCCwsgCCAIKAJIQQEgCCgCGCAIKAIcEIEBNgJMCyAIKAJMIQAgCEHQAGokACAAC9MEAQJ/IwBBMGsiAyQAIAMgADYCJCADIAE3AxggAyACNgIUAkAgAygCJCgCQCADKQMYp0EEdGooAgBFBEAgAygCFEEUQQAQFCADQgA3AygMAQsgAyADKAIkKAJAIAMpAxinQQR0aigCACkDSDcDCCADKAIkKAIAIAMpAwhBABAnQQBIBEAgAygCFCADKAIkKAIAEBcgA0IANwMoDAELIAMoAiQoAgAhAiADKAIUIQQjAEEwayIAJAAgACACNgIoIABBgAI7ASYgACAENgIgIAAgAC8BJkGAAnFBAEc6ABsgAEEeQS4gAC0AG0EBcRs2AhwCQCAAKAIoQRpBHCAALQAbQQFxG6xBARAnQQBIBEAgACgCICAAKAIoEBcgAEF/NgIsDAELIAAgACgCKEEEQQYgAC0AG0EBcRusIABBDmogACgCIBBCIgI2AgggAkUEQCAAQX82AiwMAQsgAEEANgIUA0AgACgCFEECQQMgAC0AG0EBcRtIBEAgACAAKAIIEB1B//8DcSAAKAIcajYCHCAAIAAoAhRBAWo2AhQMAQsLIAAoAggQR0EBcUUEQCAAKAIgQRRBABAUIAAoAggQFiAAQX82AiwMAQsgACgCCBAWIAAgACgCHDYCLAsgACgCLCECIABBMGokACADIAIiADYCBCAAQQBIBEAgA0IANwMoDAELIAMpAwggAygCBK18Qv///////////wBWBEAgAygCFEEEQRYQFCADQgA3AygMAQsgAyADKQMIIAMoAgStfDcDKAsgAykDKCEBIANBMGokACABC20BAX8jAEEgayIEJAAgBCAANgIYIAQgATYCFCAEIAI2AhAgBCADNgIMAkAgBCgCGEUEQCAEQQA2AhwMAQsgBCAEKAIUIAQoAhAgBCgCDCAEKAIYQQhqEIEBNgIcCyAEKAIcIQAgBEEgaiQAIAALVQEBfyMAQRBrIgEkACABIAA2AgwCQAJAIAEoAgwoAiRBAUYNACABKAIMKAIkQQJGDQAMAQsgASgCDEEAQgBBChAgGiABKAIMQQA2AiQLIAFBEGokAAv/AgEBfyMAQTBrIgUkACAFIAA2AiggBSABNgIkIAUgAjYCICAFIAM6AB8gBSAENgIYAkACQCAFKAIgDQAgBS0AH0EBcQ0AIAVBADYCLAwBCyAFIAUoAiAgBS0AH0EBcWoQGDYCFCAFKAIURQRAIAUoAhhBDkEAEBQgBUEANgIsDAELAkAgBSgCKARAIAUgBSgCKCAFKAIgrRAeNgIQIAUoAhBFBEAgBSgCGEEOQQAQFCAFKAIUEBUgBUEANgIsDAMLIAUoAhQgBSgCECAFKAIgEBkaDAELIAUoAiQgBSgCFCAFKAIgrSAFKAIYEGRBAEgEQCAFKAIUEBUgBUEANgIsDAILCyAFLQAfQQFxBEAgBSgCFCAFKAIgakEAOgAAIAUgBSgCFDYCDANAIAUoAgwgBSgCFCAFKAIgakkEQCAFKAIMLQAARQRAIAUoAgxBIDoAAAsgBSAFKAIMQQFqNgIMDAELCwsgBSAFKAIUNgIsCyAFKAIsIQAgBUEwaiQAIAALwgEBAX8jAEEwayIEJAAgBCAANgIoIAQgATYCJCAEIAI3AxggBCADNgIUAkAgBCkDGEL///////////8AVgRAIAQoAhRBFEEAEBQgBEF/NgIsDAELIAQgBCgCKCAEKAIkIAQpAxgQKyICNwMIIAJCAFMEQCAEKAIUIAQoAigQFyAEQX82AiwMAQsgBCkDCCAEKQMYUwRAIAQoAhRBEUEAEBQgBEF/NgIsDAELIARBADYCLAsgBCgCLCEAIARBMGokACAAC3cBAX8jAEEQayICIAA2AgggAiABNgIEAkACQAJAIAIoAggpAyhC/////w9aDQAgAigCCCkDIEL/////D1oNACACKAIEQYAEcUUNASACKAIIKQNIQv////8PVA0BCyACQQE6AA8MAQsgAkEAOgAPCyACLQAPQQFxC/4BAQF/IwBBIGsiBSQAIAUgADYCGCAFIAE2AhQgBSACOwESIAVBADsBECAFIAM2AgwgBSAENgIIIAVBADYCBAJAA0AgBSgCGARAAkAgBSgCGC8BCCAFLwESRw0AIAUoAhgoAgQgBSgCDHFBgAZxRQ0AIAUoAgQgBS8BEEgEQCAFIAUoAgRBAWo2AgQMAQsgBSgCFARAIAUoAhQgBSgCGC8BCjsBAAsgBSgCGC8BCgRAIAUgBSgCGCgCDDYCHAwECyAFQZAVNgIcDAMLIAUgBSgCGCgCADYCGAwBCwsgBSgCCEEJQQAQFCAFQQA2AhwLIAUoAhwhACAFQSBqJAAgAAumAQEBfyMAQRBrIgIkACACIAA2AgggAiABNgIEAkAgAigCCC0AKEEBcQRAIAJBfzYCDAwBCyACKAIIKAIABEAgAigCCCgCACACKAIEEGdBAEgEQCACKAIIQQxqIAIoAggoAgAQFyACQX82AgwMAgsLIAIoAgggAkEEakIEQRMQIEIAUwRAIAJBfzYCDAwBCyACQQA2AgwLIAIoAgwhACACQRBqJAAgAAuNCAIBfwF+IwBBkAFrIgMkACADIAA2AoQBIAMgATYCgAEgAyACNgJ8IAMQUwJAIAMoAoABKQMIQgBSBEAgAyADKAKAASgCACgCACkDSDcDYCADIAMoAoABKAIAKAIAKQNINwNoDAELIANCADcDYCADQgA3A2gLIANCADcDcAJAA0AgAykDcCADKAKAASkDCFQEQCADKAKAASgCACADKQNwp0EEdGooAgApA0ggAykDaFQEQCADIAMoAoABKAIAIAMpA3CnQQR0aigCACkDSDcDaAsgAykDaCADKAKAASkDIFYEQCADKAJ8QRNBABAUIANCfzcDiAEMAwsgAyADKAKAASgCACADKQNwp0EEdGooAgApA0ggAygCgAEoAgAgAykDcKdBBHRqKAIAKQMgfCADKAKAASgCACADKQNwp0EEdGooAgAoAjAQUUH//wNxrXxCHnw3A1ggAykDWCADKQNgVgRAIAMgAykDWDcDYAsgAykDYCADKAKAASkDIFYEQCADKAJ8QRNBABAUIANCfzcDiAEMAwsgAygChAEoAgAgAygCgAEoAgAgAykDcKdBBHRqKAIAKQNIQQAQJ0EASARAIAMoAnwgAygChAEoAgAQFyADQn83A4gBDAMLIAMgAygChAEoAgBBAEEBIAMoAnwQjAFCf1EEQCADEFIgA0J/NwOIAQwDCwJ/IAMoAoABKAIAIAMpA3CnQQR0aigCACEBIwBBEGsiACQAIAAgATYCCCAAIAM2AgQCQAJAAkAgACgCCC8BCiAAKAIELwEKSA0AIAAoAggoAhAgACgCBCgCEEcNACAAKAIIKAIUIAAoAgQoAhRHDQAgACgCCCgCMCAAKAIEKAIwEIYBDQELIABBfzYCDAwBCwJAAkAgACgCCCgCGCAAKAIEKAIYRw0AIAAoAggpAyAgACgCBCkDIFINACAAKAIIKQMoIAAoAgQpAyhRDQELAkACQCAAKAIELwEMQQhxRQ0AIAAoAgQoAhgNACAAKAIEKQMgQgBSDQAgACgCBCkDKFANAQsgAEF/NgIMDAILCyAAQQA2AgwLIAAoAgwhASAAQRBqJAAgAQsEQCADKAJ8QRVBABAUIAMQUiADQn83A4gBDAMFIAMoAoABKAIAIAMpA3CnQQR0aigCACgCNCADKAI0EJUBIQAgAygCgAEoAgAgAykDcKdBBHRqKAIAIAA2AjQgAygCgAEoAgAgAykDcKdBBHRqKAIAQQE6AAQgA0EANgI0IAMQUiADIAMpA3BCAXw3A3AMAgsACwsgAwJ+IAMpA2AgAykDaH1C////////////AFQEQCADKQNgIAMpA2h9DAELQv///////////wALNwOIAQsgAykDiAEhBCADQZABaiQAIAQL1AQBAX8jAEEgayIDJAAgAyAANgIYIAMgATYCFCADIAI2AhAgAygCECEBIwBBEGsiACQAIAAgATYCCCAAQdgAEBg2AgQCQCAAKAIERQRAIAAoAghBDkEAEBQgAEEANgIMDAELIAAoAgghAiMAQRBrIgEkACABIAI2AgggAUEYEBgiAjYCBAJAIAJFBEAgASgCCEEOQQAQFCABQQA2AgwMAQsgASgCBEEANgIAIAEoAgRCADcDCCABKAIEQQA2AhAgASABKAIENgIMCyABKAIMIQIgAUEQaiQAIAAoAgQgAjYCUCACRQRAIAAoAgQQFSAAQQA2AgwMAQsgACgCBEEANgIAIAAoAgRBADYCBCMAQRBrIgEgACgCBEEIajYCDCABKAIMQQA2AgAgASgCDEEANgIEIAEoAgxBADYCCCAAKAIEQQA2AhggACgCBEEANgIUIAAoAgRBADYCHCAAKAIEQQA2AiQgACgCBEEANgIgIAAoAgRBADoAKCAAKAIEQgA3AzggACgCBEIANwMwIAAoAgRBADYCQCAAKAIEQQA2AkggACgCBEEANgJEIAAoAgRBADYCTCAAKAIEQQA2AlQgACAAKAIENgIMCyAAKAIMIQEgAEEQaiQAIAMgASIANgIMAkAgAEUEQCADQQA2AhwMAQsgAygCDCADKAIYNgIAIAMoAgwgAygCFDYCBCADKAIUQRBxBEAgAygCDCIAIAAoAhRBAnI2AhQgAygCDCIAIAAoAhhBAnI2AhgLIAMgAygCDDYCHAsgAygCHCEAIANBIGokACAAC9UBAQF/IwBBIGsiBCQAIAQgADYCGCAEIAE3AxAgBCACNgIMIAQgAzYCCAJAAkAgBCkDEEL///////////8AVwRAIAQpAxBCgICAgICAgICAf1kNAQsgBCgCCEEEQT0QFCAEQX82AhwMAQsCfyAEKQMQIQEgBCgCDCEAIAQoAhgiAigCTEF/TARAIAIgASAAEKABDAELIAIgASAAEKABC0EASARAIAQoAghBBEG0mwEoAgAQFCAEQX82AhwMAQsgBEEANgIcCyAEKAIcIQAgBEEgaiQAIAALJABBACAAEAUiACAAQRtGGyIABH9BtJsBIAA2AgBBAAVBAAsaC3ABAX8jAEEQayIDJAAgAwJ/IAFBwABxRQRAQQAgAUGAgIQCcUGAgIQCRw0BGgsgAyACQQRqNgIMIAIoAgALNgIAIAAgAUGAgAJyIAMQECIAQYFgTwRAQbSbAUEAIABrNgIAQX8hAAsgA0EQaiQAIAALMwEBfwJ/IAAQByIBQWFGBEAgABARIQELIAFBgWBPCwR/QbSbAUEAIAFrNgIAQX8FIAELC2kBAn8CQCAAKAIUIAAoAhxNDQAgAEEAQQAgACgCJBEBABogACgCFA0AQX8PCyAAKAIEIgEgACgCCCICSQRAIAAgASACa6xBASAAKAIoEQ8AGgsgAEEANgIcIABCADcDECAAQgA3AgRBAAvaAwEGfyMAQRBrIgUkACAFIAI2AgwjAEGgAWsiBCQAIARBCGpBkIcBQZABEBkaIAQgADYCNCAEIAA2AhwgBEF+IABrIgNB/////wcgA0H/////B0kbIgY2AjggBCAAIAZqIgA2AiQgBCAANgIYIARBCGohACMAQdABayIDJAAgAyACNgLMASADQaABakEAQSgQMyADIAMoAswBNgLIAQJAQQAgASADQcgBaiADQdAAaiADQaABahBwQQBIDQAgACgCTEEATiEHIAAoAgAhAiAALABKQQBMBEAgACACQV9xNgIACyACQSBxIQgCfyAAKAIwBEAgACABIANByAFqIANB0ABqIANBoAFqEHAMAQsgAEHQADYCMCAAIANB0ABqNgIQIAAgAzYCHCAAIAM2AhQgACgCLCECIAAgAzYCLCAAIAEgA0HIAWogA0HQAGogA0GgAWoQcCACRQ0AGiAAQQBBACAAKAIkEQEAGiAAQQA2AjAgACACNgIsIABBADYCHCAAQQA2AhAgACgCFBogAEEANgIUQQALGiAAIAAoAgAgCHI2AgAgB0UNAAsgA0HQAWokACAGBEAgBCgCHCIAIAAgBCgCGEZrQQA6AAALIARBoAFqJAAgBUEQaiQAC4wSAg9/AX4jAEHQAGsiBSQAIAUgATYCTCAFQTdqIRMgBUE4aiEQQQAhAQNAAkAgDUEASA0AQf////8HIA1rIAFIBEBBtJsBQT02AgBBfyENDAELIAEgDWohDQsgBSgCTCIHIQECQAJAAkACQAJAAkACQAJAIAUCfwJAIActAAAiBgRAA0ACQAJAIAZB/wFxIgZFBEAgASEGDAELIAZBJUcNASABIQYDQCABLQABQSVHDQEgBSABQQJqIgg2AkwgBkEBaiEGIAEtAAIhDiAIIQEgDkElRg0ACwsgBiAHayEBIAAEQCAAIAcgARAiCyABDQ0gBSgCTCEBIAUoAkwsAAFBMGtBCk8NAyABLQACQSRHDQMgASwAAUEwayEPQQEhESABQQNqDAQLIAUgAUEBaiIINgJMIAEtAAEhBiAIIQEMAAsACyANIQsgAA0IIBFFDQJBASEBA0AgBCABQQJ0aigCACIABEAgAyABQQN0aiAAIAIQqAFBASELIAFBAWoiAUEKRw0BDAoLC0EBIQsgAUEKTw0IA0AgBCABQQJ0aigCAA0IIAFBAWoiAUEKRw0ACwwIC0F/IQ8gAUEBagsiATYCTEEAIQgCQCABLAAAIgxBIGsiBkEfSw0AQQEgBnQiBkGJ0QRxRQ0AA0ACQCAFIAFBAWoiCDYCTCABLAABIgxBIGsiAUEgTw0AQQEgAXQiAUGJ0QRxRQ0AIAEgBnIhBiAIIQEMAQsLIAghASAGIQgLAkAgDEEqRgRAIAUCfwJAIAEsAAFBMGtBCk8NACAFKAJMIgEtAAJBJEcNACABLAABQQJ0IARqQcABa0EKNgIAIAEsAAFBA3QgA2pBgANrKAIAIQpBASERIAFBA2oMAQsgEQ0IQQAhEUEAIQogAARAIAIgAigCACIBQQRqNgIAIAEoAgAhCgsgBSgCTEEBagsiATYCTCAKQX9KDQFBACAKayEKIAhBgMAAciEIDAELIAVBzABqEKcBIgpBAEgNBiAFKAJMIQELQX8hCQJAIAEtAABBLkcNACABLQABQSpGBEACQCABLAACQTBrQQpPDQAgBSgCTCIBLQADQSRHDQAgASwAAkECdCAEakHAAWtBCjYCACABLAACQQN0IANqQYADaygCACEJIAUgAUEEaiIBNgJMDAILIBENByAABH8gAiACKAIAIgFBBGo2AgAgASgCAAVBAAshCSAFIAUoAkxBAmoiATYCTAwBCyAFIAFBAWo2AkwgBUHMAGoQpwEhCSAFKAJMIQELQQAhBgNAIAYhEkF/IQsgASwAAEHBAGtBOUsNByAFIAFBAWoiDDYCTCABLAAAIQYgDCEBIAYgEkE6bGpB74IBai0AACIGQQFrQQhJDQALIAZBE0YNAiAGRQ0GIA9BAE4EQCAEIA9BAnRqIAY2AgAgBSADIA9BA3RqKQMANwNADAQLIAANAQtBACELDAULIAVBQGsgBiACEKgBIAUoAkwhDAwCCyAPQX9KDQMLQQAhASAARQ0ECyAIQf//e3EiDiAIIAhBgMAAcRshBkEAIQtBpAghDyAQIQgCQAJAAkACfwJAAkACQAJAAn8CQAJAAkACQAJAAkACQCAMQQFrLAAAIgFBX3EgASABQQ9xQQNGGyABIBIbIgFB2ABrDiEEEhISEhISEhIOEg8GDg4OEgYSEhISAgUDEhIJEgESEgQACwJAIAFBwQBrDgcOEgsSDg4OAAsgAUHTAEYNCQwRCyAFKQNAIRRBpAgMBQtBACEBAkACQAJAAkACQAJAAkAgEkH/AXEOCAABAgMEFwUGFwsgBSgCQCANNgIADBYLIAUoAkAgDTYCAAwVCyAFKAJAIA2sNwMADBQLIAUoAkAgDTsBAAwTCyAFKAJAIA06AAAMEgsgBSgCQCANNgIADBELIAUoAkAgDaw3AwAMEAsgCUEIIAlBCEsbIQkgBkEIciEGQfgAIQELIBAhByABQSBxIQ4gBSkDQCIUUEUEQANAIAdBAWsiByAUp0EPcUGAhwFqLQAAIA5yOgAAIBRCD1YhDCAUQgSIIRQgDA0ACwsgBSkDQFANAyAGQQhxRQ0DIAFBBHZBpAhqIQ9BAiELDAMLIBAhASAFKQNAIhRQRQRAA0AgAUEBayIBIBSnQQdxQTByOgAAIBRCB1YhByAUQgOIIRQgBw0ACwsgASEHIAZBCHFFDQIgCSAQIAdrIgFBAWogASAJSBshCQwCCyAFKQNAIhRCf1cEQCAFQgAgFH0iFDcDQEEBIQtBpAgMAQsgBkGAEHEEQEEBIQtBpQgMAQtBpghBpAggBkEBcSILGwshDyAUIBAQRCEHCyAGQf//e3EgBiAJQX9KGyEGAkAgBSkDQCIUQgBSDQAgCQ0AQQAhCSAQIQcMCgsgCSAUUCAQIAdraiIBIAEgCUgbIQkMCQsgBSgCQCIBQdgSIAEbIgdBACAJEKsBIgEgByAJaiABGyEIIA4hBiABIAdrIAkgARshCQwICyAJBEAgBSgCQAwCC0EAIQEgAEEgIApBACAGECYMAgsgBUEANgIMIAUgBSkDQD4CCCAFIAVBCGo2AkBBfyEJIAVBCGoLIQhBACEBAkADQCAIKAIAIgdFDQECQCAFQQRqIAcQqgEiB0EASCIODQAgByAJIAFrSw0AIAhBBGohCCAJIAEgB2oiAUsNAQwCCwtBfyELIA4NBQsgAEEgIAogASAGECYgAUUEQEEAIQEMAQtBACEIIAUoAkAhDANAIAwoAgAiB0UNASAFQQRqIAcQqgEiByAIaiIIIAFKDQEgACAFQQRqIAcQIiAMQQRqIQwgASAISw0ACwsgAEEgIAogASAGQYDAAHMQJiAKIAEgASAKSBshAQwFCyAAIAUrA0AgCiAJIAYgAUEXERkAIQEMBAsgBSAFKQNAPAA3QQEhCSATIQcgDiEGDAILQX8hCwsgBUHQAGokACALDwsgAEEgIAsgCCAHayIOIAkgCSAOSBsiDGoiCCAKIAggCkobIgEgCCAGECYgACAPIAsQIiAAQTAgASAIIAZBgIAEcxAmIABBMCAMIA5BABAmIAAgByAOECIgAEEgIAEgCCAGQYDAAHMQJgwACwALkAIBA38CQCABIAIoAhAiBAR/IAQFQQAhBAJ/IAIgAi0ASiIDQQFrIANyOgBKIAIoAgAiA0EIcQRAIAIgA0EgcjYCAEF/DAELIAJCADcCBCACIAIoAiwiAzYCHCACIAM2AhQgAiADIAIoAjBqNgIQQQALDQEgAigCEAsgAigCFCIFa0sEQCACIAAgASACKAIkEQEADwsCfyACLABLQX9KBEAgASEEA0AgASAEIgNFDQIaIAAgA0EBayIEai0AAEEKRw0ACyACIAAgAyACKAIkEQEAIgQgA0kNAiAAIANqIQAgAigCFCEFIAEgA2sMAQsgAQshBCAFIAAgBBAZGiACIAIoAhQgBGo2AhQgASEECyAEC0gCAX8BfiMAQRBrIgMkACADIAA2AgwgAyABNgIIIAMgAjYCBCADKAIMIAMoAgggAygCBCADKAIMQQhqEFghBCADQRBqJAAgBAt3AQF/IwBBEGsiASAANgIIIAFChSo3AwACQCABKAIIRQRAIAFBADYCDAwBCwNAIAEoAggtAAAEQCABIAEoAggtAACtIAEpAwBCIX58Qv////8PgzcDACABIAEoAghBAWo2AggMAQsLIAEgASkDAD4CDAsgASgCDAuHBQEBfyMAQTBrIgUkACAFIAA2AiggBSABNgIkIAUgAjcDGCAFIAM2AhQgBSAENgIQAkACQAJAIAUoAihFDQAgBSgCJEUNACAFKQMYQv///////////wBYDQELIAUoAhBBEkEAEBQgBUEAOgAvDAELIAUoAigoAgBFBEAgBSgCKEGAAiAFKAIQEFpBAXFFBEAgBUEAOgAvDAILCyAFIAUoAiQQczYCDCAFIAUoAgwgBSgCKCgCAHA2AgggBSAFKAIoKAIQIAUoAghBAnRqKAIANgIEA0ACQCAFKAIERQ0AAkAgBSgCBCgCHCAFKAIMRw0AIAUoAiQgBSgCBCgCABBbDQACQAJAIAUoAhRBCHEEQCAFKAIEKQMIQn9SDQELIAUoAgQpAxBCf1ENAQsgBSgCEEEKQQAQFCAFQQA6AC8MBAsMAQsgBSAFKAIEKAIYNgIEDAELCyAFKAIERQRAIAVBIBAYIgA2AgQgAEUEQCAFKAIQQQ5BABAUIAVBADoALwwCCyAFKAIEIAUoAiQ2AgAgBSgCBCAFKAIoKAIQIAUoAghBAnRqKAIANgIYIAUoAigoAhAgBSgCCEECdGogBSgCBDYCACAFKAIEIAUoAgw2AhwgBSgCBEJ/NwMIIAUoAigiACAAKQMIQgF8NwMIAkAgBSgCKCIAKQMIuiAAKAIAuEQAAAAAAADoP6JkRQ0AIAUoAigoAgBBgICAgHhPDQAgBSgCKCAFKAIoKAIAQQF0IAUoAhAQWkEBcUUEQCAFQQA6AC8MAwsLCyAFKAIUQQhxBEAgBSgCBCAFKQMYNwMICyAFKAIEIAUpAxg3AxAgBUEBOgAvCyAFLQAvQQFxIQAgBUEwaiQAIAAL1BEBAX8jAEGwAWsiBiQAIAYgADYCqAEgBiABNgKkASAGIAI2AqABIAYgAzYCnAEgBiAENgKYASAGIAU2ApQBIAZBADYCkAEDQCAGKAKQAUEPS0UEQCAGQSBqIAYoApABQQF0akEAOwEAIAYgBigCkAFBAWo2ApABDAELCyAGQQA2AowBA0AgBigCjAEgBigCoAFPRQRAIAZBIGogBigCpAEgBigCjAFBAXRqLwEAQQF0aiIAIAAvAQBBAWo7AQAgBiAGKAKMAUEBajYCjAEMAQsLIAYgBigCmAEoAgA2AoABIAZBDzYChAEDQAJAIAYoAoQBQQFJDQAgBkEgaiAGKAKEAUEBdGovAQANACAGIAYoAoQBQQFrNgKEAQwBCwsgBigCgAEgBigChAFLBEAgBiAGKAKEATYCgAELAkAgBigChAFFBEAgBkHAADoAWCAGQQE6AFkgBkEAOwFaIAYoApwBIgEoAgAhACABIABBBGo2AgAgACAGQdgAaigBADYBACAGKAKcASIBKAIAIQAgASAAQQRqNgIAIAAgBkHYAGooAQA2AQAgBigCmAFBATYCACAGQQA2AqwBDAELIAZBATYCiAEDQAJAIAYoAogBIAYoAoQBTw0AIAZBIGogBigCiAFBAXRqLwEADQAgBiAGKAKIAUEBajYCiAEMAQsLIAYoAoABIAYoAogBSQRAIAYgBigCiAE2AoABCyAGQQE2AnQgBkEBNgKQAQNAIAYoApABQQ9NBEAgBiAGKAJ0QQF0NgJ0IAYgBigCdCAGQSBqIAYoApABQQF0ai8BAGs2AnQgBigCdEEASARAIAZBfzYCrAEMAwUgBiAGKAKQAUEBajYCkAEMAgsACwsCQCAGKAJ0QQBMDQAgBigCqAEEQCAGKAKEAUEBRg0BCyAGQX82AqwBDAELIAZBADsBAiAGQQE2ApABA0AgBigCkAFBD09FBEAgBigCkAFBAWpBAXQgBmogBigCkAFBAXQgBmovAQAgBkEgaiAGKAKQAUEBdGovAQBqOwEAIAYgBigCkAFBAWo2ApABDAELCyAGQQA2AowBA0AgBigCjAEgBigCoAFJBEAgBigCpAEgBigCjAFBAXRqLwEABEAgBigClAEhASAGKAKkASAGKAKMASICQQF0ai8BAEEBdCAGaiIDLwEAIQAgAyAAQQFqOwEAIABB//8DcUEBdCABaiACOwEACyAGIAYoAowBQQFqNgKMAQwBCwsCQAJAAkACQCAGKAKoAQ4CAAECCyAGIAYoApQBIgA2AkwgBiAANgJQIAZBFDYCSAwCCyAGQYDwADYCUCAGQcDwADYCTCAGQYECNgJIDAELIAZBgPEANgJQIAZBwPEANgJMIAZBADYCSAsgBkEANgJsIAZBADYCjAEgBiAGKAKIATYCkAEgBiAGKAKcASgCADYCVCAGIAYoAoABNgJ8IAZBADYCeCAGQX82AmAgBkEBIAYoAoABdDYCcCAGIAYoAnBBAWs2AlwCQAJAIAYoAqgBQQFGBEAgBigCcEHUBksNAQsgBigCqAFBAkcNASAGKAJwQdAETQ0BCyAGQQE2AqwBDAELA0AgBiAGKAKQASAGKAJ4azoAWQJAIAYoAkggBigClAEgBigCjAFBAXRqLwEAQQFqSwRAIAZBADoAWCAGIAYoApQBIAYoAowBQQF0ai8BADsBWgwBCwJAIAYoApQBIAYoAowBQQF0ai8BACAGKAJITwRAIAYgBigCTCAGKAKUASAGKAKMAUEBdGovAQAgBigCSGtBAXRqLwEAOgBYIAYgBigCUCAGKAKUASAGKAKMAUEBdGovAQAgBigCSGtBAXRqLwEAOwFaDAELIAZB4AA6AFggBkEAOwFaCwsgBkEBIAYoApABIAYoAnhrdDYCaCAGQQEgBigCfHQ2AmQgBiAGKAJkNgKIAQNAIAYgBigCZCAGKAJoazYCZCAGKAJUIAYoAmQgBigCbCAGKAJ4dmpBAnRqIAZB2ABqKAEANgEAIAYoAmQNAAsgBkEBIAYoApABQQFrdDYCaANAIAYoAmwgBigCaHEEQCAGIAYoAmhBAXY2AmgMAQsLAkAgBigCaARAIAYgBigCbCAGKAJoQQFrcTYCbCAGIAYoAmggBigCbGo2AmwMAQsgBkEANgJsCyAGIAYoAowBQQFqNgKMASAGQSBqIAYoApABQQF0aiIBLwEAQQFrIQAgASAAOwEAAkAgAEH//wNxRQRAIAYoApABIAYoAoQBRg0BIAYgBigCpAEgBigClAEgBigCjAFBAXRqLwEAQQF0ai8BADYCkAELAkAgBigCkAEgBigCgAFNDQAgBigCYCAGKAJsIAYoAlxxRg0AIAYoAnhFBEAgBiAGKAKAATYCeAsgBiAGKAJUIAYoAogBQQJ0ajYCVCAGIAYoApABIAYoAnhrNgJ8IAZBASAGKAJ8dDYCdANAAkAgBigChAEgBigCfCAGKAJ4ak0NACAGIAYoAnQgBkEgaiAGKAJ8IAYoAnhqQQF0ai8BAGs2AnQgBigCdEEATA0AIAYgBigCfEEBajYCfCAGIAYoAnRBAXQ2AnQMAQsLIAYgBigCcEEBIAYoAnx0ajYCcAJAAkAgBigCqAFBAUYEQCAGKAJwQdQGSw0BCyAGKAKoAUECRw0BIAYoAnBB0ARNDQELIAZBATYCrAEMBAsgBiAGKAJsIAYoAlxxNgJgIAYoApwBKAIAIAYoAmBBAnRqIAYoAnw6AAAgBigCnAEoAgAgBigCYEECdGogBigCgAE6AAEgBigCnAEoAgAgBigCYEECdGogBigCVCAGKAKcASgCAGtBAnU7AQILDAELCyAGKAJsBEAgBkHAADoAWCAGIAYoApABIAYoAnhrOgBZIAZBADsBWiAGKAJUIAYoAmxBAnRqIAZB2ABqKAEANgEACyAGKAKcASIAIAAoAgAgBigCcEECdGo2AgAgBigCmAEgBigCgAE2AgAgBkEANgKsAQsgBigCrAEhACAGQbABaiQAIAALsQIBAX8jAEEgayIDJAAgAyAANgIYIAMgATYCFCADIAI2AhAgAyADKAIYKAIENgIMIAMoAgwgAygCEEsEQCADIAMoAhA2AgwLAkAgAygCDEUEQCADQQA2AhwMAQsgAygCGCIAIAAoAgQgAygCDGs2AgQgAygCFCADKAIYKAIAIAMoAgwQGRoCQCADKAIYKAIcKAIYQQFGBEAgAygCGCgCMCADKAIUIAMoAgwQPSEAIAMoAhggADYCMAwBCyADKAIYKAIcKAIYQQJGBEAgAygCGCgCMCADKAIUIAMoAgwQGiEAIAMoAhggADYCMAsLIAMoAhgiACADKAIMIAAoAgBqNgIAIAMoAhgiACADKAIMIAAoAghqNgIIIAMgAygCDDYCHAsgAygCHCEAIANBIGokACAACzYBAX8jAEEQayIBJAAgASAANgIMIAEoAgwQXiABKAIMKAIAEDcgASgCDCgCBBA3IAFBEGokAAvtAQEBfyMAQRBrIgEgADYCCAJAAkACQCABKAIIRQ0AIAEoAggoAiBFDQAgASgCCCgCJA0BCyABQQE2AgwMAQsgASABKAIIKAIcNgIEAkACQCABKAIERQ0AIAEoAgQoAgAgASgCCEcNACABKAIEKAIEQSpGDQEgASgCBCgCBEE5Rg0BIAEoAgQoAgRBxQBGDQEgASgCBCgCBEHJAEYNASABKAIEKAIEQdsARg0BIAEoAgQoAgRB5wBGDQEgASgCBCgCBEHxAEYNASABKAIEKAIEQZoFRg0BCyABQQE2AgwMAQsgAUEANgIMCyABKAIMC9IEAQF/IwBBIGsiAyAANgIcIAMgATYCGCADIAI2AhQgAyADKAIcQdwWaiADKAIUQQJ0aigCADYCECADIAMoAhRBAXQ2AgwDQAJAIAMoAgwgAygCHCgC0ChKDQACQCADKAIMIAMoAhwoAtAoTg0AIAMoAhggAygCHCADKAIMQQJ0akHgFmooAgBBAnRqLwEAIAMoAhggAygCHEHcFmogAygCDEECdGooAgBBAnRqLwEATgRAIAMoAhggAygCHCADKAIMQQJ0akHgFmooAgBBAnRqLwEAIAMoAhggAygCHEHcFmogAygCDEECdGooAgBBAnRqLwEARw0BIAMoAhwgAygCDEECdGpB4BZqKAIAIAMoAhxB2Chqai0AACADKAIcQdwWaiADKAIMQQJ0aigCACADKAIcQdgoamotAABKDQELIAMgAygCDEEBajYCDAsgAygCGCADKAIQQQJ0ai8BACADKAIYIAMoAhxB3BZqIAMoAgxBAnRqKAIAQQJ0ai8BAEgNAAJAIAMoAhggAygCEEECdGovAQAgAygCGCADKAIcQdwWaiADKAIMQQJ0aigCAEECdGovAQBHDQAgAygCECADKAIcQdgoamotAAAgAygCHEHcFmogAygCDEECdGooAgAgAygCHEHYKGpqLQAASg0ADAELIAMoAhxB3BZqIAMoAhRBAnRqIAMoAhxB3BZqIAMoAgxBAnRqKAIANgIAIAMgAygCDDYCFCADIAMoAgxBAXQ2AgwMAQsLIAMoAhxB3BZqIAMoAhRBAnRqIAMoAhA2AgAL1xMBA38jAEEwayICJAAgAiAANgIsIAIgATYCKCACIAIoAigoAgA2AiQgAiACKAIoKAIIKAIANgIgIAIgAigCKCgCCCgCDDYCHCACQX82AhAgAigCLEEANgLQKCACKAIsQb0ENgLUKCACQQA2AhgDQCACKAIYIAIoAhxIBEACQCACKAIkIAIoAhhBAnRqLwEABEAgAiACKAIYIgE2AhAgAigCLEHcFmohAyACKAIsIgQoAtAoQQFqIQAgBCAANgLQKCAAQQJ0IANqIAE2AgAgAigCGCACKAIsQdgoampBADoAAAwBCyACKAIkIAIoAhhBAnRqQQA7AQILIAIgAigCGEEBajYCGAwBCwsDQCACKAIsKALQKEECSARAAkAgAigCEEECSARAIAIgAigCEEEBaiIANgIQDAELQQAhAAsgAigCLEHcFmohAyACKAIsIgQoAtAoQQFqIQEgBCABNgLQKCABQQJ0IANqIAA2AgAgAiAANgIMIAIoAiQgAigCDEECdGpBATsBACACKAIMIAIoAixB2ChqakEAOgAAIAIoAiwiACAAKAKoLUEBazYCqC0gAigCIARAIAIoAiwiACAAKAKsLSACKAIgIAIoAgxBAnRqLwECazYCrC0LDAELCyACKAIoIAIoAhA2AgQgAiACKAIsKALQKEECbTYCGANAIAIoAhhBAU4EQCACKAIsIAIoAiQgAigCGBB5IAIgAigCGEEBazYCGAwBCwsgAiACKAIcNgIMA0AgAiACKAIsKALgFjYCGCACKAIsQdwWaiEBIAIoAiwiAygC0CghACADIABBAWs2AtAoIAIoAiwgAEECdCABaigCADYC4BYgAigCLCACKAIkQQEQeSACIAIoAiwoAuAWNgIUIAIoAhghASACKAIsQdwWaiEDIAIoAiwiBCgC1ChBAWshACAEIAA2AtQoIABBAnQgA2ogATYCACACKAIUIQEgAigCLEHcFmohAyACKAIsIgQoAtQoQQFrIQAgBCAANgLUKCAA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AQsgAigCCEEANgIAIAIoAghCADcDECACKAIIQgA3AwggAigCCEIANwMgIAIoAghCADcDGCACKAIIQQA2AiggAigCCEEAOgAsIAIoAgggAikDECACKAIMEI8BQQFxRQRAIAIoAggQJSACQQA2AhwMAQsgAiACKAIINgIcCyACKAIcIQEgAkEgaiQAIAEL1gIBAX8jAEEgayIDJAAgAyAANgIYIAMgATYCFCADIAI2AhAgAyADQQxqQgQQKTYCCAJAIAMoAghFBEAgA0F/NgIcDAELA0AgAygCFARAIAMoAhQoAgQgAygCEHFBgAZxBEAgAygCCEIAECwaIAMoAgggAygCFC8BCBAfIAMoAgggAygCFC8BChAfAn8jAEEQayIAIAMoAgg2AgwgACgCDC0AAEEBcUULBEAgAygCGEEIakEUQQAQFCADKAIIEBYgA0F/NgIcDAQLIAMoAhggA0EMakIEEDZBAEgEQCADKAIIEBYgA0F/NgIcDAQLIAMoAhQvAQoEQCADKAIYIAMoAhQoAgwgAygCFC8BCq0QNkEASARAIAMoAggQFiADQX82AhwMBQsLCyADIAMoAhQoAgA2AhQMAQsLIAMoAggQFiADQQA2AhwLIAMoAhwhACADQSBqJAAgAAtoAQF/IwBBEGsiAiAANgIMIAIgATYCCCACQQA7AQYDQCACKAIMBEAgAigCDCgCBCACKAIIcUGABnEEQCACIAIoAgwvAQogAi8BBkEEamo7AQYLIAIgAigCDCgCADYCDAwBCwsgAi8BBgvwAQEBfyMAQRBrIgEkACABIAA2AgwgASABKAIMNgIIIAFBADYCBANAIAEoAgwEQAJAAkAgASgCDC8BCEH1xgFGDQAgASgCDC8BCEH14AFGDQAgASgCDC8BCEGBsgJGDQAgASgCDC8BCEEBRw0BCyABIAEoAgwoAgA2AgAgASgCCCABKAIMRgRAIAEgASgCADYCCAsgASgCDEEANgIAIAEoAgwQIyABKAIEBEAgASgCBCABKAIANgIACyABIAEoAgA2AgwMAgsgASABKAIMNgIEIAEgASgCDCgCADYCDAwBCwsgASgCCCEAIAFBEGokACAAC7IEAQF/IwBBQGoiBSQAIAUgADYCOCAFIAE7ATYgBSACNgIwIAUgAzYCLCAFIAQ2AiggBSAFKAI4IAUvATatECkiADYC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IAEoAhBB//8DRgRAIAEgASgCDDYCEAsgASgCCEH//wNGBEAgASABKAIENgIICwJAIAEoApQBQQRxRQ0AIAEoAgggASgCBEYEQCABKAIQIAEoAgxGDQELIAEoApABQRVBABAUIAEtABdBAXEEQCABKAKkARAWCyABQQA2AqwBDAELAkAgASgCEEUEQCABKAIIRQ0BCyABKAKQAUEBQQAQFCABLQAXQQFxBEAgASgCpAEQFgsgAUEANgKsAQwBCyABIAEoAqQBEDE3AyggASABKAKkARAxNwMgIAEpAyggASkDIFIEQCABKAKQAUEBQQAQFCABLQAXQQFxBEAgASgCpAEQFgsgAUEANgKsAQwBCyABIAEoAqQBEDE3AzAgASABKAKkARAxNwOAAQJ/IwBBEGsiBSABKAKkATYCDCAFKAIMLQAAQQFxRQsEQCABKAKQAUEUQQAQFCABLQAXQQFxBEAgASgCpAEQFgsgAUEANgKsAQwBCyABLQAXQQFxBEAgASgCpAEQFgsCQCABKQOAAUL///////////8AWARAIAEpA4ABIAEpA4ABIAEpAzB8WA0BCyABKAKQAUEEQRYQFCABQQA2AqwBDAELIAEpA4ABIAEpAzB8IAEpA5gBIAEpAzh8VgRAIAEoApABQRVBABAUIAFBADYCrAEMAQsCQCABKAKUAUEEcUUNACABKQOAASABKQMwfCABKQOYASABKQM4fFENACABKAKQAUEVQQAQFCABQQA2AqwBDAELIAEpAyggASkDMEIugFYEQCABKAKQAUEVQQAQFCABQQA2AqwBDAELIAEgASkDKCABKAKQARCQASIFNgKMASAFRQRAIAFBADYCrAEMAQsgASgCjAFBAToALCABKAKMASABKQMwNwMYIAEoAowBIAEpA4ABNwMgIAEgASgCjAE2AqwBCyABKAKsASEFIAFBsAFqJAAgACAFNgJQDAELIAAoAmQgACkDMBAsGiAAKAJkIQUgACkDWCEJIAAoAmgoAhQhBiAAKAJUIQcjAEHQAGsiASQAIAEgBTYCSCABIAk3A0AgASAGNgI8IAEgBzYCOAJAIAEoAkgQMEIWVARAIAEoAjhBFUEAEBQgAUEANgJMDAELIwBBEGsiBSABKAJINgIMIAECfiAFKAIMLQAAQQFxBEAgBSgCDCkDEAwBC0IACzcDCCABKAJI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ECADQcgAEBgiADYCDAJAIABFBEAgAygCEEEBQbSbASgCABAUIANBADYCHAwBCyADKAIMIAMoAhA2AgAgAygCDCADLQAbQQFxOgAEIAMoAgwgAygCFDYCCAJAIAMoAgwoAghBAU4EQCADKAIMKAIIQQlMDQELIAMoAgxBCTYCCAsgAygCDEEAOgAMIAMoAgxBADYCMCADKAIMQQA2AjQgAygCDEEANgI4IAMgAygCDDYCHAsgAygCHCEAIANBIGokACAACzgBAX8jAEEQayIBIAA2AgwgASgCDEEANgIAIAEoAgxBADYCBCABKAIMQQA2AgggASgCDEEAOgAMC+MIAQF/IwBBQGoiAiAANgI4IAIgATYCNCACIAIoAjgoAnw2AjAgAiACKAI4KAI4IAIoAjgoAmxqNgIsIAIgAigCOCgCeDYCICACIAIoAjgoApABNgIcIAICfyACKAI4KAJsIAIoAjgoAixBhgJrSwRAIAIoAjgoAmwgAigCOCgCLEGGAmtrDAELQQALNgIYIAIgAigCOCgCQDYCFCACIAIoAjgoAjQ2AhAgAiACKAI4KAI4IAIoAjgoAmxqQYICajYCDCACIAIoAiwgAigCIEEBa2otAAA6AAsgAiACKAIsIAIoAiBqLQAAOgAKIAIoAjgoAnggAigCOCgCjAFPBEAgAiACKAIwQQJ2NgIwCyACKAIcIAIoAjgoAnRLBEAgAiACKAI4KAJ0NgIcCwNAAkAgAiACKAI4KAI4IAIoAjRqNgIoAkAgAigCKCACKAIgai0AACACLQAKRw0AIAIoAiggAigCIEEBa2otAAAgAi0AC0cNACACKAIoLQAAIAIoAiwtAABHDQAgAiACKAIoIgBBAWo2AiggAC0AASACKAIsLQABRwRADAELIAIgAigCLEECajYCLCACIAIoAihBAWo2AigDQCACIAIoAiwiAEEBajYCLCAALQABIQEgAiACKAIoIgBBAWo2AigCf0EAIAAtAAEgAUcNABogAiACKAIsIgBBAWo2AiwgAC0AASEBIAIgAigCKCIAQQFqNgIoQQAgAC0AASABRw0AGiACIAIoAiwiAEEBajYCLCAALQABIQEgAiACKAIoIgBBAWo2AihBACAALQABIAFHDQAaIAIgAigCLCIAQQFqNgIsIAAtAAEhASACIAIoAigiAEEBajYCKEEAIAAtAAEgAUcNABogAiACKAIsIgBBAWo2AiwgAC0AASEBIAIgAigCKCIAQQFqNgIoQQAgAC0AASABRw0AGiACIAIoAiwiAEEBajYCLCAALQABIQEgAiACKAIoIgBBAWo2AihBACAALQABIAFHDQAaIAIgAigCLCIAQQFqNgIsIAAtAAEhASACIAIoAigiAEEBajYCKEEAIAAtAAEgAUcNABogAiACKAIsIgBBAWo2AiwgAC0AASEBIAIgAigCKCIAQQFqNgIoQQAgAC0AASABRw0AGiACKAIsIAIoAgxJC0EBcQ0ACyACQYICIAIoAgwgAigCLGtrNgIkIAIgAigCDEGCAms2AiwgAigCJCACKAIgSgRAIAIoAjggAigCNDYCcCACIAIoAiQ2AiAgAigCJCACKAIcTg0CIAIgAigCLCACKAIgQQFrai0AADoACyACIAIoAiwgAigCIGotAAA6AAoLCyACIAIoAhQgAigCNCACKAIQcUEBdGovAQAiATYCNEEAIQAgASACKAIYSwR/IAIgAigCMEEBayIANgIwIABBAEcFQQALQQFxDQELCwJAIAIoAiAgAigCOCgCdE0EQCACIAIoAiA2AjwMAQsgAiACKAI4KAJ0NgI8CyACKAI8C5IQAQF/IwBBMGsiAiQAIAIgADYCKCACIAE2AiQgAgJ/IAIoAigoAiwgAigCKCgCDEEFa0kEQCACKAIoKAIsDAELIAIoAigoAgxBBWsLNgIgIAJBADYCECACIAIoAigoAgAoAgQ2AgwDQAJAIAJB//8DNgIcIAIgAigCKCgCvC1BKmpBA3U2AhQgAigCKCgCACgCECACKAIUSQ0AIAIgAigCKCgCACgCECACKAIUazYCFCACIAIoAigoAmwgAigCKCgCXGs2AhggAigCHCACKAIYIAIoAigoAgAoAgRqSwRAIAIgAigCGCACKAIoKAIAKAIEajYCHAsgAigCHCACKAIUSwRAIAIgAigCFDYCHAsCQCACKAIcIAIoAiBPDQACQCACKAIcRQRAIAIoAiRBBEcNAQsgAigCJEUNACACKAIcIAIoAhggAigCKCgCACgCBGpGDQELDAELQQAhACACIAIoAiRBBEYEfyACKAIcIAIoAhggAigCKCgCACgCBGpGBUEAC0EBcTYCECACKAIoQQBBACACKAIQEF0gAigCKCgCCCACKAIoKAIUQQRraiACKAIcOgAAIAIoAigoAgggAigCKCgCFEEDa2ogAigCHEEIdjoAACACKAIoKAIIIAIoAigoAhRBAmtqIAIoAhxBf3M6AAAgAigCKCgCCCACKAIoKAIUQQFraiACKAIcQX9zQQh2OgAAIAIoAigoAgAQHCACKAIYBEAgAigCGCACKAIcSwRAIAIgAigCHDYCGAsgAigCKCgCACgCDCACKAIoKAI4IAIoAigoAlxqIAIoAhgQGRogAigCKCgCACIAIAIoAhggACgCDGo2AgwgAigCKCgCACIAIAAoAhAgAigCGGs2AhAgAigCKCgCACIAIAIoAhggACgCFGo2AhQgAigCKCIAIAIoAhggACgCXGo2AlwgAiACKAIcIAIoAhhrNgIcCyACKAIcBEAgAigCKCgCACACKAIoKAIAKAIMIAIoAhwQdhogAigCKCgCACIAIAIoAhwgACgCDGo2AgwgAigCKCgCACIAIAAoAhAgAigCHGs2AhAgAigCKCgCACIAIAIoAhwgACgCFGo2AhQLIAIoAhBFDQELCyACIAIoAgwgAigCKCgCACgCBGs2AgwgAigCDARAAkAgAigCDCACKAIoKAIsTwRAIAIoAihBAjYCsC0gAigCKCgCOCACKAIoKAIAKAIAIAIoAigoAixrIAIoAigoAiwQGRogAigCKCACKAIoKAIsNgJsDAELIAIoAgwgAigCKCgCPCACKAIoKAJsa08EQCACKAIoIgAgACgCbCACKAIoKAIsazYCbCACKAIoKAI4IAIoAigoAjggAigCKCgCLGogAigCKCgCbBAZGiACKAIoKAKwLUECSQRAIAIoAigiACAAKAKwLUEBajYCsC0LCyACKAIoKAI4IAIoAigoAmxqIAIoAigoAgAoAgAgAigCDGsgAigCDBAZGiACKAIoIgAgAigCDCAAKAJsajYCbAsgAigCKCACKAIoKAJsNgJcIAIoAigiAQJ/IAIoAgwgAigCKCgCLCACKAIoKAK0LWtLBEAgAigCKCgCLCACKAIoKAK0LWsMAQsgAigCDAsgASgCtC1qNgK0LQsgAigCKCgCwC0gAigCKCgCbEkEQCACKAIoIAIoAigoAmw2AsAtCwJAIAIoAhAEQCACQQM2AiwMAQsCQCACKAIkRQ0AIAIoAiRBBEYNACACKAIoKAIAKAIEDQAgAigCKCgCbCACKAIoKAJcRw0AIAJBATYCLAwBCyACIAIoAigoAjwgAigCKCgCbGtBAWs2AhQCQCACKAIoKAIAKAIEIAIoAhRNDQAgAigCKCgCXCACKAIoKAIsSA0AIAIoAigiACAAKAJcIAIoAigoAixrNgJcIAIoAigiACAAKAJsIAIoAigoAixrNgJsIAIoAigoAjggAigCKCgCOCACKAIoKAIsaiACKAIoKAJsEBkaIAIoAigoArAtQQJJBEAgAigCKCIAIAAoArAtQQFqNgKwLQsgAiACKAIoKAIsIAIoAhRqNgIUCyACKAIUIAIoAigoAgAoAgRLBEAgAiACKAIoKAIAKAIENgIUCyACKAIUBEAgAigCKCgCACACKAIoKAI4IAIoAigoAmxqIAIoAhQQdhogAigCKCIAIAIoAhQgACgCbGo2AmwLIAIoAigoAsAtIAIoAigoAmxJBEAgAigCKCACKAIoKAJsNgLALQsgAiACKAIoKAK8LUEqakEDdTYCFCACIAIoAigoAgwgAigCFGtB//8DSwR/Qf//AwUgAigCKCgCDCACKAIUaws2AhQgAgJ/IAIoAhQgAigCKCgCLEsEQCACKAIoKAIsDAELIAIoAhQLNgIgIAIgAigCKCgCbCACKAIoKAJcazYCGAJAIAIoAhggAigCIEkEQCACKAIYRQRAIAIoAiRBBEcNAgsgAigCJEUNASACKAIoKAIAKAIEDQEgAigCGCACKAIUSw0BCyACAn8gAigCGCACKAIUSwRAIAIoAhQMAQsgAigCGAs2AhwgAgJ/QQAgAigCJEEERw0AGkEAIAIoAigoAgAoAgQNABogAigCHCACKAIYRgtBAXE2AhAgAigCKCACKAIoKAI4IAIoAigoAlxqIAIoAhwgAigCEBBdIAIoAigiACACKAIcIAAoAlxqNgJcIAIoAigoAgAQHAsgAkECQQAgAigCEBs2AiwLIAIoAiwhACACQTBqJAAgAAuyAgEBfyMAQRBrIgEkACABIAA2AggCQCABKAIIEHgEQCABQX42AgwMAQsgASABKAIIKAIcKAIENgIEIAEoAggoAhwoAggEQCABKAIIKAIoIAEoAggoAhwoAgggASgCCCgCJBEEAAsgASgCCCgCHCgCRARAIAEoAggoAiggASgCCCgCHCgCRCABKAIIKAIkEQQACyABKAIIKAIc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DQAgAiEAIANBAWsiAw0ACwsgBCgCFBogASACNgKgAQwCCyMAQRBrIgAgASgCqAEoAgQ2AgwgAUEAIAAoAgxrQQJ0QajZAGooAgA2AqABDAELIAFBADYCoAELCwJAIAEoAqABRQRAIAEgASgCpAE2AqwBDAELIAEgASgCoAEQLgJ/IAEoAqQBBEAgASgCpAEQLkECagwBC0EAC2pBAWoQGCIANgIcIABFBEAgAUG4EygCADYCrAEMAQsgASgCHCEAAn8gASgCpAEEQCABKAKkAQwBC0H6EgshA0HfEkH6EiABKAKkARshAiABIAEoAqABNgIIIAEgAjYCBCABIAM2AgAgAEG+CiABEG8gASgCqAEgASgCHDYCCCABIAEoAhw2AqwBCyABKAKsASEAIAFBsAFqJAAgAAsIAEEBQTgQfwszAQF/IAAoAhQiAyABIAIgACgCECADayIBIAEgAksbIgEQGRogACAAKAIUIAFqNgIUIAILjwUCBn4BfyABIAEoAgBBD2pBcHEiAUEQajYCACAAAnwgASkDACEDIAEpAwghBiMAQSBrIggkAAJAIAZC////////////AIMiBEKAgICAgIDAgDx9IARCgICAgICAwP/DAH1UBEAgBkIEhiADQjyIhCEEIANC//////////8PgyIDQoGAgICAgICACFoEQCAEQoGAgICAgICAwAB8IQIMAgsgBEKAgICAgICAgEB9IQIgA0KAgICAgICAgAiFQgBSDQEgAiAEQgGDfCECDAELIANQIARCgICAgICAwP//AFQgBEKAgICAgIDA//8AURtFBEAgBkIEhiADQjyIhEL/////////A4NCgICAgICAgPz/AIQhAgwBC0KAgICAgICA+P8AIQIgBEL///////+//8MAVg0AQgAhAiAEQjCIpyIAQZH3AEkNACADIQIgBkL///////8/g0KAgICAgIDAAIQiBSEHAkAgAEGB9wBrIgFBwABxBEAgAiABQUBqrYYhB0IAIQIMAQsgAUUNACAHIAGtIgSGIAJBwAAgAWutiIQhByACIASGIQILIAggAjcDECAIIAc3AxgCQEGB+AAgAGsiAEHAAHEEQCAFIABBQGqtiCEDQgAhBQwBCyAARQ0AIAVBwAAgAGuthiADIACtIgKIhCEDIAUgAoghBQsgCCADNwMAIAggBTcDCCAIKQMI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ADYCtC0gASgCFEEERgRAIAEoAhgCfyABKAIYKAJcQQBOBEAgASgCGCgCOCABKAIYKAJcagwBC0EACyABKAIYKAJsIAEoAhgoAlxrQQEQKCABKAIYIAEoAhgoAmw2AlwgASgCGCgCABAcIAEoAhgoAgAoAhBFBEAgAUECNgIcDAILIAFBAzYCHAwBCyABKAIYKAKgLQRAIAEoAhgCfyABKAIYKAJcQQBOBEAgASgCGCgCOCABKAIYKAJcagwBC0EACyABKAIYKAJsIAEoAhgoAlxrQQAQKCABKAIYIAEoAhgoAmw2AlwgASgCGCgCABAcIAEoAhgoAgAoAhBFBEAgAUEANgIcDAILCyABQQE2AhwLIAEoAhwhAiABQSBqJAAgAgwBCwJ/IAAoAiwoAogBQQNGBEAgACgCLCECIAAoAjQhAyMAQTBrIgEkACABIAI2AiggASADNgIkAkADQAJAIAEoAigoAnRBggJNBEAgASgCKBBcAkAgASgCKCgCdEGCAksNACABKAIkDQAgAUEANgIsDAQLIAEoAigoAnRFDQELIAEoAihBADYCYAJAIAEoAigoAnRBA0kNACABKAIoKAJsRQ0AIAEgASgCKCgCOCABKAIoKAJsakEBazYCGCABIAEoAhgtAAA2AhwgASgCHCECIAEgASgCGCIDQQFqNgIYAkAgAy0AASACRw0AIAEoAhwhAiABIAEoAhgiA0EBajYCGCADLQABIAJHDQAgASgCHCECIAEgASgCGCIDQQFqNgIYIAMtAAEgAkcNACABIAEoAigoAjggASgCKCgCbGpBggJqNgIUA0AgASgCHCECIAEgASgCGCIDQQFqNgIYAn9BACADLQABIAJHDQAaIAEoAhwhAiABIAEoAhgiA0EBajYCGEEAIAMtAAEgAkcNABogASgCHCECIAEgASgCGCIDQQFqNgIYQQAgAy0AASACRw0AGiABKAIcIQIgASABKAIYIgNBAWo2AhhBACADLQABIAJHDQAaIAEoAhwhAiABIAEoAhgiA0EBajYCGEEAIAMtAAEgAkcNABogASgCHCECIAEgASgCGCIDQQFqNgIYQQAgAy0AASACRw0AGiABKAIcIQIgASABKAIYIgNBAWo2AhhBACADLQABIAJHDQAaIAEoAhwhAiABIAEoAhgiA0EBajYCGEEAIAMtAAEgAkcNABogASgCGCABKAIUSQtBAXENAAsgASgCKEGCAiABKAIUIAEoAhhrazYCYCABKAIoKAJgIAEoAigoAnRLBEAgASgCKCABKAIoKAJ0NgJgCwsLAkAgASgCKCgCYEEDTwRAIAEgASgCKCgCYEEDazoAEyABQQE7ARAgASgCKCICKAKkLSACKAKgLUEBdGogAS8BEDsBACABLQATIQMgASgCKCICKAKYLSEEIAIgAigCoC0iAkEBajYCoC0gAiAEaiADOgAAIAEgAS8BEEEBazsBECABKAIoIAEtABNB0N0Aai0AAEECdGpBmAlqIgIgAi8BAEEBajsBACABKAIoQYgTagJ/IAEvARBBgAJJBEAgAS8BEC0A0FkMAQsgAS8BEEEHdkGAAmotANBZC0ECdGoiAiACLwEAQQFqOwEAIAEgASgCKCgCoC0gASgCKCgCnC1BAWtGNgIgIAEoAigiAiACKAJ0IAEoAigoAmBrNgJ0IAEoAigiAiABKAIoKAJgIAIoAmxqNgJsIAEoAihBADYCYAwBCyABIAEoAigiAigCOCACKAJsai0AADoADyABKAIoIgIoAqQtIAIoAqAtQQF0akEAOwEAIAEtAA8hAyABKAIoIgIoApgtIQQgAiACKAKgLSICQQFqNgKgLSACIARqIAM6AAAgASgCKCABLQAPQQJ0aiICIAIvAZQBQQFqOwGUASABIAEoAigoAqAtIAEoAigoApwtQQFrRjYCICABKAIoIgIgAigCdEEBazYCdCABKAIoIgIgAigCbEEBajYCbAsgASgCIARAIAEoAigCfyABKAIoKAJcQQBOBEAgASgCKCgCOCABKAIoKAJcagwBC0EACyABKAIoKAJsIAEoAigoAlxrQQAQKCABKAIoIAEoAigoAmw2AlwgASgCKCgCABAcIAEoAigoAgAoAhBFBEAgAUEANgIsDAQLCwwBCwsgASgCKEEANgK0LSABKAIkQQRGBEAgASgCKAJ/IAEoAigoAlxBAE4EQCABKAIoKAI4IAEoAigoAlxqDAELQQALIAEoAigoAmwgASgCKCgCXGtBARAoIAEoAiggASgCKCgCbDYCXCABKAIoKAIAEBwgASgCKCgCACgCEEUEQCABQQI2AiwMAgsgAUEDNgIsDAELIAEoAigoAqAtBEAgASgCKAJ/IAEoAigoAlxBAE4EQCABKAIoKAI4IAEoAigoAlxqDAELQQALIAEoAigoAmwgASgCKCgCXGtBABAoIAEoAiggASgCKCgCbDYCXCABKAIoKAIAEBwgASgCKCgCACgCEEUEQCABQQA2AiwMAgsLIAFBATYCLAsgASgCLCECIAFBMGokACACDAELIAAoAiwgACgCNCAAKAIsKAKEAUEMbEGA7wBqKAIIEQMACwsLNgIEAkAgACgCBEECRwRAIAAoAgRBA0cNAQsgACgCLEGaBTYCBAsCQCAAKAIEBEAgACgCBEECRw0BCyAAKAI4KAIQRQRAIAAoAixBfzYCKAsgAEEANgI8DAILIAAoAgRBAUYEQAJAIAAoAjRBAUYEQCAAKAIsIQIjAEEgayIBJAAgASACNgIcIAFBAzYCGAJAIAEoAhwoArwtQRAgASgCGGtKBEAgAUECNgIUIAEoAhwiAiACLwG4LSABKAIUQf//A3EgASgCHCgCvC10cjsBuC0gASgCHC8BuC1B/wFxIQMgASgCHCgCCCEEIAEoAhwiBigCFCECIAYgAkEBajYCFCACIARqIAM6AAAgASgCHC8BuC1BCHYhAyABKAIcKAIIIQQgASgCHCIGKAIUIQIgBiACQQFqNgIUIAIgBGogAzoAACABKAIcIAEoAhRB//8DcUEQIAEoAhwoArwta3U7AbgtIAEoAhwiAiACKAK8LSABKAIYQRBrajYCvC0MAQsgASgCHCICIAIvAbgtQQIgASgCHCgCvC10cjsBuC0gASgCHCICIAEoAhggAigCvC1qNgK8LQsgAUGS6AAvAQA2AhACQCABKAIcKAK8LUEQIAEoAhBrSgRAIAFBkOgALwEANgIMIAEoAhwiAiACLwG4LSABKAIMQf//A3EgASgCHCgCvC10cjsBuC0gASgCHC8BuC1B/wFxIQMgASgCHCgCCCEEIAEoAhwiBigCFCECIAYgAkEBajYCFCACIARqIAM6AAAgASgCHC8BuC1BCHYhAyABKAIcKAIIIQQgASgCHCIGKAIUIQIgBiACQQFqNgIUIAIgBGogAzoAACABKAIcIAEoAgxB//8DcUEQIAEoAhwoArwta3U7AbgtIAEoAhwiAiACKAK8LSABKAIQQRBrajYCvC0MAQsgASgCHCICIAIvAbgtQZDoAC8BACABKAIcKAK8LXRyOwG4LSABKAIcIgIgASgCECACKAK8LWo2ArwtCyABKAIcELwBIAFBIGokAAwBCyAAKAI0QQVHBEAgACgCLEEAQQBBABBdIAAoAjRBA0YEQCAAKAIsKAJEIAAoAiwoAkxBAWtBAXRqQQA7AQAgACgCLCgCREEAIAAoAiwoAkxBAWtBAXQQMyAAKAIsKAJ0RQRAIAAoAixBADYCbCAAKAIsQQA2AlwgACgCLEEANgK0LQsLCwsgACgCOBAcIAAoAjgoAhBFBEAgACgCLEF/NgIoIABBADYCPAwDCwsLIAAoAjRBBEcEQCAAQQA2AjwMAQsgACgCLCgCGEEATARAIABBATYCPAwBCwJAIAAoAiwoAhhBAkYEQCAAKAI4KAIwQf8BcSECIAAoAiwoAgghAyAAKAIsIgQoAhQhASAEIAFBAWo2AhQgASADaiACOgAAIAAoAjgoAjBBCHZB/wFxIQIgACgCLCgCCCEDIAAoAiwiBCgCFCEBIAQgAUEBajYCFCABIANqIAI6AAAgACgCOCgCMEEQdkH/AXEhAiAAKAIsKAIIIQMgACgCLCIEKAIUIQEgBCABQQFqNgIUIAEgA2ogAjoAACAAKAI4KAIwQRh2IQIgACgCLCgCCCEDIAAoAiwiBCgCFCEBIAQgAUEBajYCFCABIANqIAI6AAAgACgCOCgCCEH/AXEhAiAAKAIsKAIIIQMgACgCLCIEKAIUIQEgBCABQQFqNgIUIAEgA2ogAjoAACAAKAI4KAIIQQh2Qf8BcSECIAAoAiwoAgghAyAAKAIsIgQoAhQhASAEIAFBAWo2AhQgASADaiACOgAAIAAoAjgoAghBEHZB/wFxIQIgACgCLCgCCCEDIAAoAiwiBCgCFCEBIAQgAUEBajYCFCABIANqIAI6AAAgACgCOCgCCEEYdiECIAAoAiwoAgghAyAAKAIsIgQoAhQhASAEIAFBAWo2AhQgASADaiACOgAADAELIAAoAiwgACgCOCgCMEEQdhBLIAAoAiwgACgCOCgCMEH//wNxEEsLIAAoAjgQHCAAKAIsKAIYQQBKBEAgACgCLEEAIAAoAiwoAhhrNgIYCyAAIAAoAiwoAhRFNgI8CyAAKAI8IQEgAEFAayQAIAUgATYCCAwBCyAFKAIMQRBqIQEjAEHgAGsiACQAIAAgATYCWCAAQQI2AlQCQAJAAkAgACgCWBBKDQAgACgCWCgCDEUNACAAKAJYKAIADQEgACgCWCgCBEUNAQsgAEF+NgJcDAELIAAgACgCWCgCHDYCUCAAKAJQKAIEQb/+AEYEQCAAKAJQQcD+ADYCBAsgACAAKAJYKAIMNgJIIAAgACgCWCgCEDYCQCAAIAAoAlgoAgA2AkwgACAAKAJYKAIENgJEIAAgACgCUCgCPDYCPCAAIAAoAlAoAkA2AjggACAAKAJENgI0IAAgACgCQDYCMCAAQQA2AhADQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQCAAKAJQKAIEQbT+AGsOHwABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZGhscHR4fCyAAKAJQKAIMRQRAIAAoAlBBwP4ANgIEDCELA0AgACgCOEEQSQRAIAAoAkRFDSEgACAAKAJEQQFrNgJEIAAgACgCTCIBQQFqNgJMIAAgACgCPCABLQAAIAAoAjh0ajYCPCAAIAAoAjhBCGo2AjgMAQsLAkAgACgCUCgCDEECcUUNACAAKAI8QZ+WAkcNACAAKAJQKAIoRQRAIAAoAlBBDzYCKAtBAEEAQQAQGiEBIAAoAlAgATYCHCAAIAAoAjw6AAwgACAAKAI8QQh2OgANIAAoAlAoAhwgAEEMakECEBohASAAKAJQIAE2AhwgAEEANgI8IABBADYCOCAAKAJQQbX+ADYCBAwhCyAAKAJQQQA2AhQgACgCUCgCJARAIAAoAlAoAiRBfzYCMAsCQCAAKAJQKAIMQQFxBEAgACgCPEH/AXFBCHQgACgCPEEIdmpBH3BFDQELIAAoAlhBmgw2AhggACgCUEHR/gA2AgQMIQsgACgCPEEPcUEIRwRAIAAoAlhBmw82AhggACgCUEHR/gA2AgQMIQsgACAAKAI8QQR2NgI8IAAgACgCOEEEazYCOCAAIAAoAjxBD3FBCGo2AhQgACgCUCgCKEUEQCAAKAJQIAAoAhQ2AigLAkAgACgCFEEPTQRAIAAoAhQgACgCUCgCKE0NAQsgACgCWEGTDTYCGCAAKAJQQdH+ADYCBAwhCyAAKAJQQQEgACgCFHQ2AhhBAEEAQQAQPSEBIAAoAlAgATYCHCAAKAJYIAE2AjAgACgCUEG9/gBBv/4AIAAoAjxBgARxGzYCBCAAQQA2AjwgAEEANgI4DCALA0AgACgCOEEQSQRAIAAoAkRFDSAgACAAKAJEQQFrNgJEIAAgACgCTCIBQQFqNgJMIAAgACgCPCABLQAAIAAoAjh0ajYCPCAAIAAoAjhBCGo2AjgMAQsLIAAoAlAgACgCPDYCFCAAKAJQKAIUQf8BcUEIRwRAIAAoAlhBmw82AhggACgCUEHR/gA2AgQMIAsgACgCUCgCFEGAwANxBEAgACgCWEGgCTYCGCAAKAJQQdH+ADYCBAwgCyAAKAJQKAIkBEAgACgCUCgCJCAAKAI8QQh2QQFxNgIACwJAIAAoAlAoAhRBgARxRQ0AIAAoAlAoAgxBBHFFDQAgACAAKAI8OgAMIAAgACgCPEEIdjoADSAAKAJQKAIcIABBDGpBAhAaIQEgACgCUCABNgIcCyAAQQA2AjwgAEEANgI4IAAoAlBBtv4ANgIECwNAIAAoAjhBIEkEQCAAKAJERQ0fIAAgACgCREEBazYCRCAAIAAoAkwiAUEBajYCTCAAIAAoAjwgAS0AACAAKAI4dGo2AjwgACAAKAI4QQhqNgI4DAELCyAAKAJQKAIkBEAgACgCUCgCJCAAKAI8NgIECwJAIAAoAlAoAhRBgARxRQ0AIAAoAlAoAgxBBHFFDQAgACAAKAI8OgAMIAAgACgCPEEIdjoADSAAIAAoAjxBEHY6AA4gACAAKAI8QRh2OgAPIAAoAlAoAhwgAEEMakEEEBohASAAKAJQIAE2AhwLIABBADYCPCAAQQA2AjggACgCUEG3/gA2AgQLA0AgACgCOEEQSQRAIAAoAkRFDR4gACAAKAJEQQFrNgJEIAAgACgCTCIBQQFqNgJMIAAgACgCPCABLQAAIAAoAjh0ajYCPCAAIAAoAjhBCGo2AjgMAQsLIAAoAlAoAiQEQCAAKAJQKAIkIAAoAjxB/wFxNgIIIAAoAlAoAiQgACgCPEEIdjYCDAsCQCAAKAJQKAIUQYAEcUUNACAAKAJQKAIMQQRxRQ0AIAAgACgCPDoADCAAIAAoAjxBCHY6AA0gACgCUCgCHCAAQQxqQQIQGiEBIAAoAlAgATYCHAsgAEEANgI8IABBADYCOCAAKAJQQbj+ADYCBAsCQCAAKAJQKAIUQYAIcQRAA0AgACgCOEEQSQRAIAAoAkRFDR8gACAAKAJEQQFrNgJEIAAgACgCTCIBQQFqNgJMIAAgACgCPCABLQAAIAAoAjh0ajYCPCAAIAAoAjhBCGo2AjgMAQsLIAAoAlAgACgCPDYCRCAAKAJQKAIkBEAgACgCUCgCJCAAKAI8NgIUCwJAIAAoAlAoAhRBgARxRQ0AIAAoAlAoAgxBBHFFDQAgACAAKAI8OgAMIAAgACgCPEEIdjoADSAAKAJQKAIcIABBDGpBAhAaIQEgACgCUCABNgIcCyAAQQA2AjwgAEEANgI4DAELIAAoAlAoAiQEQCAAKAJQKAIkQQA2AhALCyAAKAJQQbn+ADYCBAsgACgCUCgCFEGACHEEQCAAIAAoAlAoAkQ2AiwgACgCLCAAKAJESwRAIAAgACgCRDYCLAsgACgCLARAAkAgACgCUCgCJEUNACAAKAJQKAIkKAIQRQ0AIAAgACgCUCgCJCgCFCAAKAJQKAJEazYCFCAAKAJQKAIkKAIQIAAoAhRqIAAoAkwCfyAAKAJQKAIkKAIYIAAoAhQgACgCLGpJBEAgACgCUCgCJCgCGCAAKAIUawwBCyAAKAIsCxAZGgsCQCAAKAJQKAIUQYAEcUUNACAAKAJQKAIMQQRxRQ0AIAAoAlAoAhwgACgCTCAAKAIsEBohASAAKAJQIAE2AhwLIAAgACgCRCAAKAIsazYCRCAAIAAoAiwgACgCTGo2AkwgACgCUCIBIAEoAkQgACgCLGs2AkQLIAAoAlAoAkQNGwsgACgCUEEANgJEIAAoAlBBuv4ANgIECwJAIAAoAlAoAhRBgBBxBEAgACgCREUNGyAAQQA2AiwDQCAAKAJMIQEgACAAKAIsIgJBAWo2AiwgACABIAJqLQAANgIUAkAgACgCUCgCJEUNACAAKAJQKAIkKAIcRQ0AIAAoAlAoAkQgACgCUCgCJCgCIE8NACAAKAIUIQIgACgCUCgCJCgCHCEDIAAoAlAiBCgCRCEBIAQgAUEBajYCRCABIANqIAI6AAALIAAoAhQEfyAAKAIsIAAoAkRJBUEAC0EBcQ0ACwJAIAAoAlAoAhRBgARxRQ0AIAAoAlAoAgxBBHFFDQAgACgCUCgCHCAAKAJMIAAoAiwQGiEBIAAoAlAgATYCHAsgACAAKAJEIAAoAixrNgJEIAAgACgCLCAAKAJMajYCTCAAKAIUDRsMAQsgACgCUCgCJARAIAAoAlAoAiRBADYCHAsLIAAoAlBBADYCRCAAKAJQQbv+ADYCBAsCQCAAKAJQKAIUQYAgcQRAIAAoAkRFDRogAEEANgIsA0AgACgCTCEBIAAgACgCLCICQQFqNgIsIAAgASACai0AADYCFAJAIAAoAlAoAiRFDQAgACgCUCgCJCgCJEUNACAAKAJQKAJEIAAoAlAoAiQoAihPDQAgACgCFCECIAAoAlAoAiQoAiQhAyAAKAJQIgQoAkQhASAEIAFBAWo2AkQgASADaiACOgAACyAAKAIUBH8gACgCLCAAKAJESQVBAAtBAXENAAsCQCAAKAJQKAIUQYAEcUUNACAAKAJQKAIMQQRxRQ0AIAAoAlAoAhwgACgCTCAAKAIsEBohASAAKAJQIAE2AhwLIAAgACgCRCAAKAIsazYCRCAAIAAoAiwgACgCTGo2AkwgACgCFA0aDAELIAAoAlAoAiQEQCAAKAJQKAIkQQA2AiQLCyAAKAJQQbz+ADYCBAsgACgCUCgCFEGABHEEQANAIAAoAjhBEEkEQCAAKAJERQ0aIAAgACgCREEBazYCRCAAIAAoAkwiAUEBajYCTCAAIAAoAjwgAS0AACAAKAI4dGo2AjwgACAAKAI4QQhqNgI4DAELCwJAIAAoAlAoAgxBBHFFDQAgACgCPCAAKAJQKAIcQf//A3FGDQAgACgCWEH7DDYCGCAAKAJQQdH+ADYCBAwaCyAAQQA2AjwgAEEANgI4CyAAKAJQKAIkBEAgACgCUCgCJCAAKAJQKAIUQQl1QQFxNgIsIAAoAlAoAiRBATYCMAtBAEEAQQAQGiEBIAAoAlAgATYCHCAAKAJYIAE2AjAgACgCUEG//gA2AgQMGAsDQCAAKAI4QSBJBEAgACgCREUNGCAAIAAoAkRBAWs2AkQgACAAKAJMIgFBAWo2AkwgACAAKAI8IAEtAAAgACgCOHRqNgI8IAAgACgCOEEIajYCOAwBCwsgACgCUCAAKAI8QQh2QYD+A3EgACgCPEEYdmogACgCPEGA/gNxQQh0aiAAKAI8Qf8BcUEYdGoiATYCHCAAKAJYIAE2AjAgAEEANgI8IABBADYCOCAAKAJQQb7+ADYCBAsgACgCUCgCEEUEQCAAKAJYIAAoAkg2AgwgACgCWCAAKAJANgIQIAAoAlggACgCTDYCACAAKAJYIAAoAkQ2AgQgACgCUCAAKAI8NgI8IAAoAlAgACgCODYCQCAAQQI2AlwMGAtBAEEAQQAQPSEBIAAoAlAgATYCHCAAKAJYIAE2AjAgACgCUEG//gA2AgQLIAAoAlRBBUYNFCAAKAJUQQZGDRQLIAAoAlAoAggEQCAAIAAoAjwgACgCOEEHcXY2AjwgACAAKAI4IAAoAjhBB3FrNgI4IAAoAlBBzv4ANgIEDBULA0AgACgCOEEDSQRAIAAoAkRFDRUgACAAKAJEQQFrNgJEIAAgACgCTCIBQQFqNgJMIAAgACgCPCABLQAAIAAoAjh0ajYCPCAAIAAoAjhBCGo2AjgMAQsLIAAoAlAgACgCPEEBcTYCCCAAIAAoAjxBAXY2AjwgACAAKAI4QQFrNgI4AkACQAJAAkACQCAAKAI8QQNxDgQAAQIDBAsgACgCUEHB/gA2AgQMAwsjAEEQayIBIAAoAlA2AgwgASgCDEGw8gA2AlAgASgCDEEJNgJYIAEoAgxBsIIBNgJUIAEoAgxBBTYCXCAAKAJQQcf+ADYCBCAAKAJUQQZGBEAgACAAKAI8QQJ2NgI8IAAgACgCOEECazYCOAwXCwwCCyAAKAJQQcT+ADYCBAwBCyAAKAJYQfANNgIYIAAoAlBB0f4ANgIECyAAIAAoAjxBAnY2AjwgACAAKAI4QQJrNgI4DBQLIAAgACgCPCAAKAI4QQdxdjYCPCAAIAAoAjggACgCOEEHcWs2AjgDQCAAKAI4QSBJBEAgACgCREUNFCAAIAAoAkRBAWs2AkQgACAAKAJMIgFBAWo2AkwgACAAKAI8IAEtAAAgACgCOHRqNgI8IAAgACgCOEEIajYCOAwBCwsgACgCPEH//wNxIAAoAjxBEHZB//8Dc0cEQCAAKAJYQaEKNgIYIAAoAlBB0f4ANgIEDBQLIAAoAlAgACgCPEH//wNxNgJEIABBADYCPCAAQQA2AjggACgCUEHC/gA2AgQgACgCVEEGRg0SCyAAKAJQQcP+ADYCBAsgACAAKAJQKAJENgIsIAAoAiwEQCAAKAIsIAAoAkRLBEAgACAAKAJENgIsCyAAKAIsIAAoAkBLBEAgACAAKAJANgIsCyAAKAIsRQ0RIAAoAkggACgCTCAAKAIsEBkaIAAgACgCRCAAKAIsazYCRCAAIAAoAiwgACgCTGo2AkwgACAAKAJAIAAoAixrNgJAIAAgACgCLCAAKAJIajYCSCAAKAJQIgEgASgCRCAAKAIsazYCRAwSCyAAKAJQQb/+ADYCBAwRCwNAIAAoAjhBDkkEQCAAKAJERQ0RIAAgACgCREEBazYCRCAAIAAoAkwiAUEBajYCTCAAIAAoAjwgAS0AACAAKAI4dGo2AjwgACAAKAI4QQhqNgI4DAELCyAAKAJQIAAoAjxBH3FBgQJqNgJkIAAgACgCPEEFdjYCPCAAIAAoAjhBBWs2AjggACgCUCAAKAI8QR9xQQFqNgJoIAAgACgCPEEFdjYCPCAAIAAoAjhBBWs2AjggACgCUCAAKAI8QQ9xQQRqNgJgIAAgACgCPEEEdjYCPCAAIAAoAjhBBGs2AjgCQCAAKAJQKAJkQZ4CTQRAIAAoAlAoAmhBHk0NAQsgACgCWEH9CTYCGCAAKAJQQdH+ADYCBAwRCyAAKAJQQQA2AmwgACgCUEHF/gA2AgQLA0AgACgCUCgCbCAAKAJQKAJgSQRAA0AgACgCOEEDSQRAIAAoAkRFDRIgACAAKAJEQQFrNgJEIAAgACgCTCIBQQFqNgJMIAAgACgCPCABLQAAIAAoAjh0ajYCPCAAIAAoAjhBCGo2AjgMAQsLIAAoAjxBB3EhAiAAKAJQQfQAaiEDIAAoAlAiBCgCbCEBIAQgAUEBajYCbCABQQF0QYDyAGovAQBBAXQgA2ogAjsBACAAIAAoAjxBA3Y2AjwgACAAKAI4QQNrNgI4DAELCwNAIAAoAlAoAmxBE0kEQCAAKAJQQfQAaiECIAAoAlAiAygCbCEBIAMgAUEBajYCbCABQQF0QYDyAGovAQBBAXQgAmpBADsBAAwBCwsgACgCUCAAKAJQQbQKajYCcCAAKAJQIAAoAlAoAnA2AlAgACgCUEEHNgJYIABBACAAKAJQQfQAakETIAAoAlBB8ABqIAAoAlBB2ABqIAAoAlBB9AVqEHU2AhAgACgCEARAIAAoAlhBhwk2AhggACgCUEHR/gA2AgQMEAsgACgCUEEANgJsIAAoAlBBxv4ANgIECwNAAkAgACgCUCgCbCAAKAJQKAJkIAAoAlAoAmhqTw0AA0ACQCAAIAAoAlAoAlAgACgCPEEBIAAoAlAoAlh0QQFrcUECdGooAQA2ASAgAC0AISAAKAI4TQ0AIAAoAkRFDREgACAAKAJEQQFrNgJEIAAgACgCTCIBQQFqNgJMIAAgACgCPCABLQAAIAAoAjh0ajYCPCAAIAAoAjhBCGo2AjgMAQsLAkAgAC8BIkEQSQRAIAAgACgCPCAALQAhdjYCPCAAIAAoAjggAC0AIWs2AjggAC8BIiECIAAoAlBB9ABqIQMgACgCUCIEKAJsIQEgBCABQQFqNgJsIAFBAXQgA2ogAjsBAAwBCwJAIAAvASJBEEYEQANAIAAoAjggAC0AIUECakkEQCAAKAJERQ0UIAAgACgCREEBazYCRCAAIAAoAkwiAUEBajYCTCAAIAAoAjwgAS0AACAAKAI4dGo2AjwgACAAKAI4QQhqNgI4DAELCyAAIAAoAjwgAC0AIXY2AjwgACAAKAI4IAAtACFrNgI4IAAoAlAoAmxFBEAgACgCWEHPCTYCGCAAKAJQQdH+ADYCBAwECyAAIAAoAlAgACgCUCgCbEEBdGovAXI2AhQgACAAKAI8QQNxQQNqNgIsIAAgACgCPEECdjYCPCAAIAAoAjhBAms2AjgMAQsCQCAALwEiQRFGBEADQCAAKAI4IAAtACFBA2pJBEAgACgCREUNFSAAIAAoAkRBAWs2AkQgACAAKAJMIgFBAWo2AkwgACAAKAI8IAEtAAAgACgCOHRqNgI8IAAgACgCOEEIajYCOAwBCwsgACAAKAI8IAAtACF2NgI8IAAgACgCOCAALQAhazYCOCAAQQA2AhQgACAAKAI8QQdxQQNqNgIsIAAgACgCPEEDdjYCPCAAIAAoAjhBA2s2AjgMAQsDQCAAKAI4IAAtACFBB2pJBEAgACgCREUNFCAAIAAoAkRBAWs2AkQgACAAKAJMIgFBAWo2AkwgACAAKAI8IAEtAAAgACgCOHRqNgI8IAAgACgCOEEIajYCOAwBCwsgACAAKAI8IAAtACF2NgI8IAAgACgCOCAALQAhazYCOCAAQQA2AhQgACAAKAI8Qf8AcUELajYCLCAAIAAoAjxBB3Y2AjwgACAAKAI4QQdrNgI4CwsgACgCUCgCbCAAKAIsaiAAKAJQKAJkIAAoAlAoAmhqSwRAIAAoAlhBzwk2AhggACgCUEHR/gA2AgQMAgsDQCAAIAAoAiwiAUEBazYCLCABBEAgACgCFCECIAAoAlBB9ABqIQMgACgCUCIEKAJsIQEgBCABQQFqNgJsIAFBAXQgA2ogAjsBAAwBCwsLDAELCyAAKAJQKAIEQdH+AEYNDiAAKAJQLwH0BEUEQCAAKAJYQfULNgIYIAAoAlBB0f4ANgIEDA8LIAAoAlAgACgCUEG0Cmo2AnAgACgCUCAAKAJQKAJwNgJQIAAoAlBBCTYCWCAAQQEgACgCUEH0AGogACgCUCgCZCAAKAJQQfAAaiAAKAJQQdgAaiAAKAJQQfQFahB1NgIQIAAoAhAEQCAAKAJYQesINgIYIAAoAlBB0f4ANgIEDA8LIAAoAlAgACgCUCgCcDYCVCAAKAJQQQY2AlwgAEECIAAoAlBB9ABqIAAoAlAoAmRBAXRqIAAoAlAoAmggACgCUEHwAGogACgCUEHcAGogACgCUEH0BWoQdTYCECAAKAIQBEAgACgCWEG5CTYCGCAAKAJQQdH+ADYCBAwPCyAAKAJQQcf+ADYCBCAAKAJUQQZGDQ0LIAAoAlBByP4ANgIECwJAIAAoAkRBBkkNACAAKAJAQYICSQ0AIAAoAlggACgCSDYCDCAAKAJYIAAoAkA2AhAgACgCWCAAKAJMNgIAIAAoAlggACgCRDYCBCAAKAJQIAAoAjw2AjwgACgCUCAAKAI4NgJAIAAoAjAhAiMAQeAAayIBIAAoAlg2AlwgASACNgJYIAEgASgCXCgCHDYCVCABIAEoAlwoAgA2AlAgASABKAJQIAEoAlwoAgRBBWtqNgJMIAEgASgCXCgCDDYCSCABIAEoAkggASgCWCABKAJcKAIQa2s2AkQgASABKAJIIAEoAlwoAhBBgQJrajYCQCABIAEoAlQoAiw2AjwgASABKAJUKAIwNgI4IAEgASgCVCgCNDYCNCABIAEoAlQoAjg2AjAgASABKAJUKAI8NgIsIAEgASgCVCgCQDYCKCABIAEoAlQoAlA2AiQgASABKAJUKAJUNgIgIAFBASABKAJUKAJYdEEBazYCHCABQQEgASgCVCgCXHRBAWs2AhgDQCABKAIoQQ9JBEAgASABKAJQIgJBAWo2AlAgASABKAIsIAItAAAgASgCKHRqNgIsIAEgASgCKEEIajYCKCABIAEoAlAiAkEBajYCUCABIAEoAiwgAi0AACABKAIodGo2AiwgASABKAIoQQhqNgIoCyABIAEoAiQgASgCLCABKAIccUECdGooAQA2ARACQAJAA0AgASABLQARNgIMIAEgASgCLCABKAIMdjYCLCABIAEoAiggASgCDGs2AiggASABLQAQNgIMIAEoAgxFBEAgAS8BEiECIAEgASgCSCIDQQFqNgJIIAMgAjoAAAwCCyABKAIMQRBxBEAgASABLwESNgIIIAEgASgCDEEPcTYCDCABKAIMBEAgASgCKCABKAIMSQRAIAEgASgCUCICQQFqNgJQIAEgASgCLCACLQAAIAEoAih0ajYCLCABIAEoAihBCGo2AigLIAEgASgCCCABKAIsQQEgASgCDHRBAWtxajYCCCABIAEoAiwgASgCDHY2AiwgASABKAIoIAEoAgxrNgIoCyABKAIoQQ9JBEAgASABKAJQIgJBAWo2AlAgASABKAIsIAItAAAgASgCKHRqNgIsIAEgASgCKEEIajYCKCABIAEoAlAiAkEBajYCUCABIAEoAiwgAi0AACABKAIodGo2AiwgASABKAIoQQhqNgIoCyABIAEoAiAgASgCLCABKAIYcUECdGooAQA2ARACQANAIAEgAS0AETYCDCABIAEoAiwgASgCDHY2AiwgASABKAIoIAEoAgxrNgIoIAEgAS0AEDYCDCABKAIMQRBxBEAgASABLwESNgIEIAEgASgCDEEPcTYCDCABKAIoIAEoAgxJBEAgASABKAJQIgJBAWo2AlAgASABKAIsIAItAAAgASgCKHRqNgIsIAEgASgCKEEIajYCKCABKAIoIAEoAgxJBEAgASABKAJQIgJBAWo2AlAgASABKAIsIAItAAAgASgCKHRqNgIsIAEgASgCKEEIajYCKAsLIAEgASgCBCABKAIsQQEgASgCDHRBAWtxajYCBCABIAEoAiwgASgCDHY2AiwgASABKAIoIAEoAgxrNgIoIAEgASgCSCABKAJEazYCDAJAIAEoAgQgASgCDEsEQCABIAEoAgQgASgCDGs2AgwgASgCDCABKAI4SwRAIAEoAlQoAsQ3BEAgASgCXEHdDDYCGCABKAJUQdH+ADYCBAwKCwsgASABKAIwNgIAAkAgASgCNEUEQCABIAEoAgAgASgCPCABKAIMa2o2AgAgASgCDCABKAIISQRAIAEgASgCCCABKAIMazYCCANAIAEgASgCACICQQFqNgIAIAItAAAhAiABIAEoAkgiA0EBajYCSCADIAI6AAAgASABKAIMQQFrIgI2AgwgAg0ACyABIAEoAkggASgCBGs2AgALDAELAkAgASgCNCABKAIMSQRAIAEgASgCACABKAI8IAEoAjRqIAEoAgxrajYCACABIAEoAgwgASgCNGs2AgwgASgCDCABKAIISQRAIAEgASgCCCABKAIMazYCCANAIAEgASgCACICQQFqNgIAIAItAAAhAiABIAEoAkgiA0EBajYCSCADIAI6AAAgASABKAIMQQFrIgI2AgwgAg0ACyABIAEoAjA2AgAgASgCNCABKAIISQRAIAEgASgCNDYCDCABIAEoAgggASgCDGs2AggDQCABIAEoAgAiAkEBajYCACACLQAAIQIgASABKAJIIgNBAWo2AkggAyACOgAAIAEgASgCDEEBayICNgIMIAINAAsgASABKAJIIAEoAgRrNgIACwsMAQsgASABKAIAIAEoAjQgASgCDGtqNgIAIAEoAgwgASgCCEkEQCABIAEoAgggASgCDGs2AggDQCABIAEoAgAiAkEBajYCACACLQAAIQIgASABKAJIIgNBAWo2AkggAyACOgAAIAEgASgCDEEBayICNgIMIAINAAsgASABKAJIIAEoAgRrNgIACwsLA0AgASgCCEECSwRAIAEgASgCACICQQFqNgIAIAItAAAhAiABIAEoAkgiA0EBajYCSCADIAI6AAAgASABKAIAIgJBAWo2AgAgAi0AACECIAEgASgCSCIDQQFqNgJIIAMgAjoAACABIAEoAgAiAkEBajYCACACLQAAIQIgASABKAJIIgNBAWo2AkggAyACOgAAIAEgASgCCEEDazYCCAwBCwsMAQsgASABKAJIIAEoAgRrNgIAA0AgASABKAIAIgJBAWo2AgAgAi0AACECIAEgASgCSCIDQQFqNgJIIAMgAjoAACABIAEoAgAiAkEBajYCACACLQAAIQIgASABKAJIIgNBAWo2AkggAyACOgAAIAEgASgCACICQQFqNgIAIAItAAAhAiABIAEoAkgiA0EBajYCSCADIAI6AAAgASABKAIIQQNrNgIIIAEoAghBAksNAAsLIAEoAggEQCABIAEoAgAiAkEBajYCACACLQAAIQIgASABKAJIIgNBAWo2AkggAyACOgAAIAEoAghBAUsEQCABIAEoAgAiAkEBajYCACACLQAAIQIgASABKAJIIgNBAWo2AkggAyACOgAACwsMAgsgASgCDEHAAHFFBEAgASABKAIgIAEvARIgASgCLEEBIAEoAgx0QQFrcWpBAnRqKAEANgEQDAELCyAB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AG5hbgAvZGV2L3VyYW5kb20AaW52YWxpZCBjb2RlIC0tIG1pc3NpbmcgZW5kLW9mLWJsb2NrAGluY29ycmVjdCBoZWFkZXIgY2hlY2sAaW5jb3JyZWN0IGxlbmd0aCBjaGVjawBpbmNvcnJlY3QgZGF0YSBjaGVjawBpbnZhbGlkIGRpc3RhbmNlIHRvbyBmYXIgYmFjawBoZWFkZXIgY3JjIG1pc21hdGNoAGluZgBpbnZhbGlkIHdpbmRvdyBzaXplAFJlYWQtb25seSBhcmNoaXZlAE5vdCBhIHppcCBhcmNoaXZlAFJlc291cmNlIHN0aWxsIGluIHVzZQBNYWxsb2MgZmFpbHVyZQBpbnZhbGlkIGJsb2NrIHR5cGUARmFpbHVyZSB0byBjcmVhdGUgdGVtcG9yYXJ5IGZpbGUAQ2FuJ3Qgb3BlbiBmaWxlAE5vIHN1Y2ggZmlsZQBQcmVtYXR1cmUgZW5kIG9mIGZpbGUAQ2FuJ3QgcmVtb3ZlIGZpbGUAaW52YWxpZCBsaXRlcmFsL2xlbmd0aCBjb2RlAGludmFsaWQgZGlzdGFuY2UgY29kZQB1bmtub3duIGNvbXByZXNzaW9uIG1ldGhvZABzdHJlYW0gZW5kAENvbXByZXNzZWQgZGF0YSBpbnZhbGlkAE11bHRpLWRpc2sgemlwIGFyY2hpdmVzIG5vdCBzdXBwb3J0ZWQAT3BlcmF0aW9uIG5vdCBzdXBwb3J0ZWQARW5jcnlwdGlvbiBtZXRob2Qgbm90IHN1cHBvcnRlZABDb21wcmVzc2lvbiBtZXRob2Qgbm90IHN1cHBvcnRlZABFbnRyeSBoYXMgYmVlbiBkZWxldGVkAENvbnRhaW5pbmcgemlwIGFyY2hpdmUgd2FzIGNsb3NlZABDbG9zaW5nIHppcCBhcmNoaXZlIGZhaWxlZABSZW5hbWluZyB0ZW1wb3JhcnkgZmlsZSBmYWlsZWQARW50cnkgaGFzIGJlZW4gY2hhbmdlZABObyBwYXNzd29yZCBwcm92aWRlZABXcm9uZyBwYXNzd29yZCBwcm92aWRlZABVbmtub3duIGVycm9yICVkAHJiAHIrYgByd2EAJXMuWFhYWFhYAE5BTgBJTkYAQUUAMS4yLjExAC9wcm9jL3NlbGYvZmQvAC4AKG51bGwpADogAFBLBgcA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0gAIADIACACyAAgAcgAIAPIACAAKAAgAigAIAEoACADKAAgAKgAIAKoACABqAAgA6gAIABoACACaAAgAWgAIANoACAA6AAgAugAIAHoACAD6AAgABgAIAIYACABGAAgAxgAIACYACACmAAgAZgAIAOYACAAWAAgAlgAIAFYACADWAAgANgAIALYACAB2AAgA9gAIAA4ACACOAAgATgAIAM4ACAAuAAgArgAIAG4ACADuAAgAHgAIAJ4ACABeAAgA3gAIAD4ACAC+AAgAfgAIAP4ACAABAAgAgQAIAEEACADBAAgAIQAIAKEACABhAAgA4QAIABEACACRAAgAUQAIANEACAAxAAgAsQAIAHEACADxAAgACQAIAIkACABJAAgAyQAIACkACACpAAgAaQAIAOkACAAZAAgAmQAIAFkACADZAAgAOQAIALkACAB5AAgA+QAIAAUACACFAAgARQAIAMUACAAlAAgApQAIAGUACADlAAgAFQAIAJUACABVAAgA1QAIADUACAC1AAgAdQAIAPUACAANAAgAjQAIAE0ACADNAAgALQAIAK0ACABtAAgA7QAIAB0ACACdAAgAXQAIAN0ACAA9AAgAvQAIAH0ACAD9AAgAEwAJABMBCQCTAAkAkwEJAFMACQBTAQkA0wAJANMBCQAzAAkAMwEJALMACQCzAQkAcwAJAHMBCQDzAAkA8wEJAAsACQALAQkAiwAJAIsBCQBLAAkASwEJAMsACQDLAQkAKwAJACsBCQCrAAkAqwEJAGsACQBrAQkA6wAJAOsBCQAbAAkAGwEJAJsACQCbAQkAWwAJAFsBCQDbAAkA2wEJADsACQA7AQkAuwAJALsBCQB7AAkAewEJAPsACQD7AQkABwAJAAcBCQCHAAkAhwEJAEcACQBHAQkAxwAJAMcBCQAnAAkAJwEJAKcACQCnAQkAZwAJAGcBCQDnAAkA5wEJABcACQAXAQkAlwAJAJcBCQBXAAkAVwEJANcACQDXAQkANwAJADcBCQC3AAkAtwEJAHcACQB3AQkA9wAJAPcBCQAPAAkADwEJAI8ACQCPAQkATwAJAE8BCQDPAAkAzwEJAC8ACQAvAQkArwAJAK8BCQBvAAkAbwEJAO8ACQDvAQkAHwAJAB8BCQCfAAkAnwEJAF8ACQBfAQkA3wAJAN8BCQA/AAkAPwEJAL8ACQC/AQkAfwAJAH8BCQD/AAkA/wEJAAAABwBAAAcAIAAHAGAABwAQAAcAUAAHADAABwBwAAcACAAHAEgABwAoAAcAaAAHABgABwBYAAcAOAAHAHgABwAEAAcARAAHACQABwBkAAcAFAAHAFQABwA0AAcAdAAHAAMACACDAAgAQwAIAMMACAAjAAgAowAIAGMACADjAAgAAAAFABAABQAIAAUAGAAFAAQABQAUAAUADAAFABwABQACAAUAEgAFAAoABQAaAAUABgAFABYABQAOAAUAHgAFAAEABQARAAUACQAFABkABQAFAAUAFQAFAA0ABQAdAAUAAwAFABMABQALAAUAGwAFAAcABQAXAAUAQbDqAAtNAQAAAAEAAAABAAAAAQAAAAIAAAACAAAAAgAAAAIAAAADAAAAAwAAAAMAAAADAAAABAAAAAQAAAAEAAAABAAAAAUAAAAFAAAABQAAAAUAQaDrAAtlAQAAAAEAAAACAAAAAgAAAAMAAAADAAAABAAAAAQAAAAFAAAABQAAAAYAAAAGAAAABwAAAAcAAAAIAAAACAAAAAkAAAAJAAAACgAAAAoAAAALAAAACwAAAAwAAAAMAAAADQAAAA0AQdDsAAsjAgAAAAMAAAAHAAAAAAAAABAREgAIBwkGCgULBAwDDQIOAQ8AQYTtAAtpAQAAAAIAAAADAAAABAAAAAUAAAAGAAAABwAAAAgAAAAKAAAADAAAAA4AAAAQAAAAFAAAABgAAAAcAAAAIAAAACgAAAAwAAAAOAAAAEAAAABQAAAAYAAAAHAAAACAAAAAoAAAAMAAAADgAEGE7gALegEAAAACAAAAAwAAAAQAAAAGAAAACAAAAAwAAAAQAAAAGAAAACAAAAAwAAAAQAAAAGAAAACAAAAAwAAAAAABAACAAQAAAAIAAAADAAAABAAAAAYAAAAIAAAADAAAABAAAAAYAAAAIAAAADAAAABAAAAAYAAAMS4yLjExAEGI7wALbQcAAAAEAAQACAAEAAgAAAAEAAUAEAAIAAgAAAAEAAYAIAAgAAgAAAAEAAQAEAAQAAkAAAAIABAAIAAgAAkAAAAIABAAgACAAAkAAAAIACAAgAAAAQkAAAAgAIAAAgEABAkAAAAgAAIBAgEAEAkAQYDwAAulAgMABAAFAAYABwAIAAkACgALAA0ADwARABMAFwAbAB8AIwArADMAOwBDAFMAYwBzAIMAowDDAOMAAgEAAAAAAAAQABAAEAAQABAAEAAQABAAEQARABEAEQASABIAEgASABMAEwATABMAFAAUABQAFAAVABUAFQAVABAATQDKAAAAAQACAAMABAAFAAcACQANABEAGQAhADEAQQBhAIEAwQABAYEBAQIBAwEEAQYBCAEMARABGAEgATABQAFgAAAAABAAEAAQABAAEQARABIAEgATABMAFAAUABUAFQAWABYAFwAXABgAGAAZABkAGgAaABsAGwAcABwAHQAdAEAAQAAQABEAEgAAAAgABwAJAAYACgAFAAsABAAMAAMADQACAA4AAQAPAEGw8gALwRFgBwAAAAhQAAAIEAAUCHMAEgcfAAAIcAAACDAAAAnAABAHCgAACGAAAAggAAAJoAAACAAAAAiAAAAIQAAACeAAEAcGAAAIWAAACBgAAAmQABMHOwAACHgAAAg4AAAJ0AARBxEAAAhoAAAIKAAACbAAAAgIAAAIiAAACEgAAAnwABAHBAAACFQAAAgUABUI4wATBysAAAh0AAAINAAACcgAEQcNAAAIZAAACCQAAAmoAAAIBAAACIQAAAhEAAAJ6AAQBwgAAAhcAAAIHAAACZgAFAdTAAAIfAAACDwAAAnYABIHFwAACGwAAAgsAAAJuAAACAwAAAiMAAAITAAACfgAEAcDAAAIUgAACBIAFQijABMHIwAACHIAAAgyAAAJxAARBwsAAAhiAAAIIgAACaQAAAgCAAAIggAACEIAAAnkABAHBwAACFoAAAgaAAAJlAAUB0MAAAh6AAAIOgAACdQAEgcTAAAIagAACCoAAAm0AAAICgAACIoAAAhKAAAJ9AAQBwUAAAhWAAAIFgBACAAAEwczAAAIdgAACDYAAAnMABEHDwAACGYAAAgmAAAJrAAACAYAAAiGAAAIRgAACewAEAcJAAAIXgAACB4AAAmcABQHYwAACH4AAAg+AAAJ3AASBxsAAAhuAAAILgAACbwAAAgOAAAIjgAACE4AAAn8AGAHAAAACFEAAAgRABUIgwASBx8AAAhxAAAIMQAACcIAEAcKAAAIYQAACCEAAAmiAAAIAQAACIEAAAhBAAAJ4gAQBwYAAAhZAAAIGQAACZIAEwc7AAAIeQAACDkAAAnSABEHEQAACGkAAAgpAAAJsgAACAkAAAiJAAAISQAACfIAEAcEAAAIVQAACBUAEAgCARMHKwAACHUAAAg1AAAJygARBw0AAAhlAAAIJQAACaoAAAgFAAAIhQAACEUAAAnqABAHCAAACF0AAAgdAAAJmgAUB1MAAAh9AAAIPQAACdoAEgcXAAAIbQAACC0AAAm6AAAIDQAACI0AAAhNAAAJ+gAQBwMAAAhTAAAIEwAVCMMAEwcjAAAIcwAACDMAAAnGABEHCwAACGMAAAgjAAAJpgAACAMAAAiDAAAIQwAACeYAEAcHAAAIWwAACBsAAAmWABQHQwAACHsAAAg7AAAJ1gASBxMAAAhrAAAIKwAACbYAAAgLAAAIiwAACEsAAAn2ABAHBQAACFcAAAgXAEAIAAATBzMAAAh3AAAINwAACc4AEQcPAAAIZwAACCcAAAmuAAAIBwAACIcAAAhHAAAJ7gAQBwkAAAhfAAAIHwAACZ4AFAdjAAAIfwAACD8AAAneABIHGwAACG8AAAgvAAAJvgAACA8AAAiPAAAITwAACf4AYAcAAAAIUAAACBAAFAhzABIHHwAACHAAAAgwAAAJwQAQBwoAAAhgAAAIIAAACaEAAAgAAAAIgAAACEAAAAnhABAHBgAACFgAAAgYAAAJkQATBzsAAAh4AAAIOAAACdEAEQcRAAAIaAAACCgAAAmxAAAICAAACIgAAAhIAAAJ8QAQBwQAAAhUAAAIFAAVCOMAEwcrAAAIdAAACDQAAAnJABEHDQAACGQAAAgkAAAJqQAACAQAAAiEAAAIRAAACekAEAcIAAAIXAAACBwAAAmZABQHUwAACHwAAAg8AAAJ2QASBxcAAAhsAAAILAAACbkAAAgMAAAIjAAACEwAAAn5ABAHAwAACFIAAAgSABUIowATByMAAAhyAAAIMgAACcUAEQcLAAAIYgAACCIAAAmlAAAIAgAACIIAAAhCAAAJ5QAQBwcAAAhaAAAIGgAACZUAFAdDAAAIegAACDoAAAnVABIHEwAACGoAAAgqAAAJtQAACAoAAAiKAAAISgAACfUAEAcFAAAIVgAACBYAQAgAABMHMwAACHYAAAg2AAAJzQARBw8AAAhmAAAIJgAACa0AAAgGAAAIhgAACEYAAAntABAHCQAACF4AAAgeAAAJnQAUB2MAAAh+AAAIPgAACd0AEgcbAAAIbgAACC4AAAm9AAAIDgAACI4AAAhOAAAJ/QBgBwAAAAhRAAAIEQAVCIMAEgcfAAAIcQAACDEAAAnDABAHCgAACGEAAAghAAAJowAACAEAAAiBAAAIQQAACeMAEAcGAAAIWQAACBkAAAmTABMHOwAACHkAAAg5AAAJ0wARBxEAAAhpAAAIKQAACbMAAAgJAAAIiQAACEkAAAnzABAHBAAACFUAAAgVABAIAgETBysAAAh1AAAINQAACcsAEQcNAAAIZQAACCUAAAmrAAAIBQAACIUAAAhFAAAJ6wAQBwgAAAhdAAAIHQAACZsAFAdTAAAIfQAACD0AAAnbABIHFwAACG0AAAgtAAAJuwAACA0AAAiNAAAITQAACfsAEAcDAAAIUwAACBMAFQjDABMHIwAACHMAAAgzAAAJxwARBwsAAAhjAAAIIwAACacAAAgDAAAIgwAACEMAAAnnABAHBwAACFsAAAgbAAAJlwAUB0MAAAh7AAAIOwAACdcAEgcTAAAIawAACCsAAAm3AAAICwAACIsAAAhLAAAJ9wAQBwUAAAhXAAAIFwBACAAAEwczAAAIdwAACDcAAAnPABEHDwAACGcAAAgnAAAJrwAACAcAAAiHAAAIRwAACe8AEAcJAAAIXwAACB8AAAmfABQHYwAACH8AAAg/AAAJ3wASBxsAAAhvAAAILwAACb8AAAgPAAAIjwAACE8AAAn/ABAFAQAXBQEBEwURABsFARARBQUAGQUBBBUFQQAdBQFAEAUDABgFAQIUBSEAHAUBIBIFCQAaBQEIFgWBAEAFAAAQBQIAFwWBARMFGQAbBQEYEQUHABkFAQYVBWEAHQUBYBAFBAAYBQEDFAUxABwFATASBQ0AGgUBDBYFwQBABQAAEQAKABEREQAAAAAFAAAAAAAACQAAAAALAAAAAAAAAAARAA8KERERAwoHAAEACQsLAAAJBgsAAAsABhEAAAAREREAQYGEAQshCwAAAAAAAAAAEQAKChEREQAKAAACAAkLAAAACQALAAALAEG7hAELAQwAQceEAQsVDAAAAAAMAAAAAAkMAAAAAAAMAAAMAEH1hAELAQ4AQYGFAQsVDQAAAAQNAAAAAAkOAAAAAAAOAAAOAEGvhQELARAAQbuFAQseDwAAAAAPAAAAAAkQAAAAAAAQAAAQAAASAAAAEhISAEHyhQELDhIAAAASEhIAAAAAAAAJAEGjhgELAQsAQa+GAQsVCgAAAAAKAAAAAAkLAAAAAAALAAALAEHdhgELAQwAQemGAQsnDAAAAAAMAAAAAAkMAAAAAAAMAAAMAAAwMTIzNDU2Nzg5QUJDREVGAEG0hwELARkAQduHAQsF//////8AQaCIAQtXGRJEOwI/LEcUPTMwChsGRktFNw9JDo4XA0AdPGkrNh9KLRwBICUpIQgMFRYiLhA4Pgs0MRhkdHV2L0EJfzkRI0MyQomKiwUEJignDSoeNYwHGkiTE5SVAEGAiQELig5JbGxlZ2FsIGJ5dGUgc2VxdWVuY2UARG9tYWluIGVycm9yAFJlc3VsdCBub3QgcmVwcmVzZW50YWJsZQBOb3QgYSB0dHkAUGVybWlzc2lvbiBkZW5pZWQAT3BlcmF0aW9uIG5vdCBwZXJtaXR0ZWQATm8gc3VjaCBmaWxlIG9yIGRpcmVjdG9yeQBObyBzdWNoIHByb2Nlc3MARmlsZSBleGlzdHMAVmFsdWUgdG9vIGxhcmdlIGZvciBkYXRhIHR5cGUATm8gc3BhY2UgbGVmdCBvbiBkZXZpY2UAT3V0IG9mIG1lbW9yeQBSZXNvdXJjZSBidXN5AEludGVycnVwdGVkIHN5c3RlbSBjYWxsAFJlc291cmNlIHRlbXBvcmFyaWx5IHVuYXZhaWxhYmxlAEludmFsaWQgc2VlawBDcm9zcy1kZXZpY2UgbGluawBSZWFkLW9ubHkgZmlsZSBzeXN0ZW0ARGlyZWN0b3J5IG5vdCBlbXB0eQBDb25uZWN0aW9uIHJlc2V0IGJ5IHBlZXIAT3BlcmF0aW9uIHRpbWVkIG91dABDb25uZWN0aW9uIHJlZnVzZWQASG9zdCBpcyBkb3duAEhvc3QgaXMgdW5yZWFjaGFibGUAQWRkcmVzcyBpbiB1c2UAQnJva2VuIHBpcGUASS9PIGVycm9yAE5vIHN1Y2ggZGV2aWNlIG9yIGFkZHJlc3MAQmxvY2sgZGV2aWNlIHJlcXVpcmVkAE5vIHN1Y2ggZGV2aWNlAE5vdCBhIGRpcmVjdG9yeQBJcyBhIGRpcmVjdG9yeQBUZXh0IGZpbGUgYnVzeQBFeGVjIGZvcm1hdCBlcnJvcgBJbnZhbGlkIGFyZ3VtZW50AEFyZ3VtZW50IGxpc3QgdG9vIGxvbmcAU3ltYm9saWMgbGluayBsb29wAEZpbGVuYW1lIHRvbyBsb25nAFRvbyBtYW55IG9wZW4gZmlsZXMgaW4gc3lzdGVtAE5vIGZpbGUgZGVzY3JpcHRvcnMgYXZhaWxhYmxlAEJhZCBmaWxlIGRlc2NyaXB0b3IATm8gY2hpbGQgcHJvY2VzcwBCYWQgYWRkcmVzcwBGaWxlIHRvbyBsYXJnZQBUb28gbWFueSBsaW5rcwBObyBsb2NrcyBhdmFpbGFibGUAUmVzb3VyY2UgZGVhZGxvY2sgd291bGQgb2NjdXIAU3RhdGUgbm90IHJlY292ZXJhYmxlAFByZXZpb3VzIG93bmVyIGRpZWQAT3BlcmF0aW9uIGNhbmNlbGVkAEZ1bmN0aW9uIG5vdCBpbXBsZW1lbnRlZABObyBtZXNzYWdlIG9mIGRlc2lyZWQgdHlwZQBJZGVudGlmaWVyIHJlbW92ZWQARGV2aWNlIG5vdCBhIHN0cmVhbQBObyBkYXRhIGF2YWlsYWJsZQBEZXZpY2UgdGltZW91dABPdXQgb2Ygc3RyZWFtcyByZXNvdXJjZXMATGluayBoYXMgYmVlbiBzZXZlcmVkAFByb3RvY29sIGVycm9yAEJhZCBtZXNzYWdlAEZpbGUgZGVzY3JpcHRvciBpbiBiYWQgc3RhdGUATm90IGEgc29ja2V0AERlc3RpbmF0aW9uIGFkZHJlc3MgcmVxdWlyZWQATWVzc2FnZSB0b28gbGFyZ2UAUHJvdG9jb2wgd3JvbmcgdHlwZSBmb3Igc29ja2V0AFByb3RvY29sIG5vdCBhdmFpbGFibGUAUHJvdG9jb2wgbm90IHN1cHBvcnRlZABTb2NrZXQgdHlwZSBub3Qgc3VwcG9ydGVkAE5vdCBzdXBwb3J0ZWQAUHJvdG9jb2wgZmFtaWx5IG5vdCBzdXBwb3J0ZWQAQWRkcmVzcyBmYW1pbHkgbm90IHN1cHBvcnRlZCBieSBwcm90b2NvbABBZGRyZXNzIG5vdCBhdmFpbGFibGUATmV0d29yayBpcyBkb3duAE5ldHdvcmsgdW5yZWFjaGFibGUAQ29ubmVjdGlvbiByZXNldCBieSBuZXR3b3JrAENvbm5lY3Rpb24gYWJvcnRlZABObyBidWZmZXIgc3BhY2UgYXZhaWxhYmxlAFNvY2tldCBpcyBjb25uZWN0ZWQAU29ja2V0IG5vdCBjb25uZWN0ZWQAQ2Fubm90IHNlbmQgYWZ0ZXIgc29ja2V0IHNodXRkb3duAE9wZXJhdGlvbiBhbHJlYWR5IGluIHByb2dyZXNzAE9wZXJhdGlvbiBpbiBwcm9ncmVzcwBTdGFsZSBmaWxlIGhhbmRsZQBSZW1vdGUgSS9PIGVycm9yAFF1b3RhIGV4Y2VlZGVkAE5vIG1lZGl1bSBmb3VuZABXcm9uZyBtZWRpdW0gdHlwZQBObyBlcnJvciBpbmZvcm1hdGlvbgBBkJcBC1JQUFAACgAAAAsAAAAMAAAADQAAAA4AAAAPAAAAEAAAABEAAAASAAAACwAAAAwAAAANAAAADgAAAA8AAAAQAAAAEQAAAAEAAAAIAAAAlEsAALRLAEGQmQELAgxQAEHImQELCR8AAADkTAAAAwBB5JkBC4wBLfRRWM+MscBG9rXLKTEDxwRbcDC0Xf0geH+LmthZKVBoSImrp1YDbP+3zYg/1He0K6WjcPG65Kj8QYP92W/hinovLXSWBx8NCV4Ddixw90ClLKdvV0GoqnTfoFhkA0rHxDxTrq9fGAQVseNtKIarDKS/Q/DpUIE5VxZSN/////////////////////8="; - if (!isDataURI(wasmBinaryFile)) { - wasmBinaryFile = locateFile(wasmBinaryFile); - } - function getBinary(file) { - try { - if (file == wasmBinaryFile && wasmBinary) { - return new Uint8Array(wasmBinary); - } - var binary = tryParseAsDataURI(file); - if (binary) { - return binary; - } - if (readBinary) { - return readBinary(file); - } else { - throw "sync fetching of the wasm failed: you can preload it to Module['wasmBinary'] manually, or emcc.py will do that for you when generating HTML (but not JS)"; - } - } catch (err2) { - abort(err2); - } - } - function instantiateSync(file, info) { - var instance; - var module2; - var binary; - try { - binary = getBinary(file); - module2 = new WebAssembly.Module(binary); - instance = new WebAssembly.Instance(module2, info); - } catch (e) { - var str = e.toString(); - err("failed to compile wasm module: " + str); - if (str.includes("imported Memory") || str.includes("memory import")) { - err( - "Memory size incompatibility issues may be due to changing INITIAL_MEMORY at runtime to something too large. Use ALLOW_MEMORY_GROWTH to allow any size memory (and also make sure not to set INITIAL_MEMORY at runtime to something smaller than it was at compile time)." - ); - } - throw e; - } - return [instance, module2]; - } - function createWasm() { - var info = { a: asmLibraryArg }; - function receiveInstance(instance, module2) { - var exports3 = instance.exports; - Module["asm"] = exports3; - wasmMemory = Module["asm"]["u"]; - updateGlobalBufferAndViews(wasmMemory.buffer); - wasmTable = Module["asm"]["pa"]; - addOnInit(Module["asm"]["v"]); - removeRunDependency(); - } - addRunDependency(); - if (Module["instantiateWasm"]) { - try { - var exports2 = Module["instantiateWasm"](info, receiveInstance); - return exports2; - } catch (e) { - err("Module.instantiateWasm callback failed with error: " + e); - return false; - } - } - var result = instantiateSync(wasmBinaryFile, info); - receiveInstance(result[0]); - return Module["asm"]; - } - var tempDouble; - var tempI64; - function callRuntimeCallbacks(callbacks) { - while (callbacks.length > 0) { - var callback = callbacks.shift(); - if (typeof callback == "function") { - callback(Module); - continue; - } - var func = callback.func; - if (typeof func === "number") { - if (callback.arg === void 0) { - wasmTable.get(func)(); - } else { - wasmTable.get(func)(callback.arg); - } - } else { - func(callback.arg === void 0 ? null : callback.arg); - } - } - } - function _gmtime_r(time, tmPtr) { - var date = new Date(HEAP32[time >> 2] * 1e3); - HEAP32[tmPtr >> 2] = date.getUTCSeconds(); - HEAP32[tmPtr + 4 >> 2] = date.getUTCMinutes(); - HEAP32[tmPtr + 8 >> 2] = date.getUTCHours(); - HEAP32[tmPtr + 12 >> 2] = date.getUTCDate(); - HEAP32[tmPtr + 16 >> 2] = date.getUTCMonth(); - HEAP32[tmPtr + 20 >> 2] = date.getUTCFullYear() - 1900; - HEAP32[tmPtr + 24 >> 2] = date.getUTCDay(); - HEAP32[tmPtr + 36 >> 2] = 0; - HEAP32[tmPtr + 32 >> 2] = 0; - var start = Date.UTC(date.getUTCFullYear(), 0, 1, 0, 0, 0, 0); - var yday = (date.getTime() - start) / (1e3 * 60 * 60 * 24) | 0; - HEAP32[tmPtr + 28 >> 2] = yday; - if (!_gmtime_r.GMTString) - _gmtime_r.GMTString = allocateUTF8("GMT"); - HEAP32[tmPtr + 40 >> 2] = _gmtime_r.GMTString; - return tmPtr; - } - function ___gmtime_r(a0, a1) { - return _gmtime_r(a0, a1); - } - var PATH = { - splitPath: function(filename) { - var splitPathRe = /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/; - return splitPathRe.exec(filename).slice(1); - }, - normalizeArray: function(parts, allowAboveRoot) { - var up = 0; - for (var i = parts.length - 1; i >= 0; i--) { - var last = parts[i]; - if (last === ".") { - parts.splice(i, 1); - } else if (last === "..") { - parts.splice(i, 1); - up++; - } else if (up) { - parts.splice(i, 1); - up--; - } - } - if (allowAboveRoot) { - for (; up; up--) { - parts.unshift(".."); - } - } - return parts; - }, - normalize: function(path) { - var isAbsolute = path.charAt(0) === "/", trailingSlash = path.substr(-1) === "/"; - path = PATH.normalizeArray( - path.split("/").filter(function(p) { - return !!p; - }), - !isAbsolute - ).join("/"); - if (!path && !isAbsolute) { - path = "."; - } - if (path && trailingSlash) { - path += "/"; - } - return (isAbsolute ? "/" : "") + path; - }, - dirname: function(path) { - var result = PATH.splitPath(path), root = result[0], dir = result[1]; - if (!root && !dir) { - return "."; - } - if (dir) { - dir = dir.substr(0, dir.length - 1); - } - return root + dir; - }, - basename: function(path) { - if (path === "/") - return "/"; - path = PATH.normalize(path); - path = path.replace(/\/$/, ""); - var lastSlash = path.lastIndexOf("/"); - if (lastSlash === -1) - return path; - return path.substr(lastSlash + 1); - }, - extname: function(path) { - return PATH.splitPath(path)[3]; - }, - join: function() { - var paths = Array.prototype.slice.call(arguments, 0); - return PATH.normalize(paths.join("/")); - }, - join2: function(l, r) { - return PATH.normalize(l + "/" + r); - } - }; - function getRandomDevice() { - { - try { - var crypto_module = require("crypto"); - return function() { - return crypto_module["randomBytes"](1)[0]; - }; - } catch (e) { - } - } - return function() { - abort("randomDevice"); - }; - } - var PATH_FS = { - resolve: function() { - var resolvedPath = "", resolvedAbsolute = false; - for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) { - var path = i >= 0 ? arguments[i] : FS.cwd(); - if (typeof path !== "string") { - throw new TypeError("Arguments to path.resolve must be strings"); - } else if (!path) { - return ""; - } - resolvedPath = path + "/" + resolvedPath; - resolvedAbsolute = path.charAt(0) === "/"; - } - resolvedPath = PATH.normalizeArray( - resolvedPath.split("/").filter(function(p) { - return !!p; - }), - !resolvedAbsolute - ).join("/"); - return (resolvedAbsolute ? "/" : "") + resolvedPath || "."; - }, - relative: function(from, to) { - from = PATH_FS.resolve(from).substr(1); - to = PATH_FS.resolve(to).substr(1); - function trim(arr) { - var start = 0; - for (; start < arr.length; start++) { - if (arr[start] !== "") - break; - } - var end = arr.length - 1; - for (; end >= 0; end--) { - if (arr[end] !== "") - break; - } - if (start > end) - return []; - return arr.slice(start, end - start + 1); - } - var fromParts = trim(from.split("/")); - var toParts = trim(to.split("/")); - var length = Math.min(fromParts.length, toParts.length); - var samePartsLength = length; - for (var i = 0; i < length; i++) { - if (fromParts[i] !== toParts[i]) { - samePartsLength = i; - break; - } - } - var outputParts = []; - for (var i = samePartsLength; i < fromParts.length; i++) { - outputParts.push(".."); - } - outputParts = outputParts.concat(toParts.slice(samePartsLength)); - return outputParts.join("/"); - } - }; - var TTY = { - ttys: [], - init: function() { - }, - shutdown: function() { - }, - register: function(dev, ops) { - TTY.ttys[dev] = { input: [], output: [], ops }; - FS.registerDevice(dev, TTY.stream_ops); - }, - stream_ops: { - open: function(stream) { - var tty = TTY.ttys[stream.node.rdev]; - if (!tty) { - throw new FS.ErrnoError(43); - } - stream.tty = tty; - stream.seekable = false; - }, - close: function(stream) { - stream.tty.ops.flush(stream.tty); - }, - flush: function(stream) { - stream.tty.ops.flush(stream.tty); - }, - read: function(stream, buffer2, offset, length, pos) { - if (!stream.tty || !stream.tty.ops.get_char) { - throw new FS.ErrnoError(60); - } - var bytesRead = 0; - for (var i = 0; i < length; i++) { - var result; - try { - result = stream.tty.ops.get_char(stream.tty); - } catch (e) { - throw new FS.ErrnoError(29); - } - if (result === void 0 && bytesRead === 0) { - throw new FS.ErrnoError(6); - } - if (result === null || result === void 0) - break; - bytesRead++; - buffer2[offset + i] = result; - } - if (bytesRead) { - stream.node.timestamp = Date.now(); - } - return bytesRead; - }, - write: function(stream, buffer2, offset, length, pos) { - if (!stream.tty || !stream.tty.ops.put_char) { - throw new FS.ErrnoError(60); - } - try { - for (var i = 0; i < length; i++) { - stream.tty.ops.put_char(stream.tty, buffer2[offset + i]); - } - } catch (e) { - throw new FS.ErrnoError(29); - } - if (length) { - stream.node.timestamp = Date.now(); - } - return i; - } - }, - default_tty_ops: { - get_char: function(tty) { - if (!tty.input.length) { - var result = null; - { - var BUFSIZE = 256; - var buf = Buffer.alloc ? Buffer.alloc(BUFSIZE) : new Buffer(BUFSIZE); - var bytesRead = 0; - try { - bytesRead = nodeFS.readSync( - process.stdin.fd, - buf, - 0, - BUFSIZE, - null - ); - } catch (e) { - if (e.toString().includes("EOF")) - bytesRead = 0; - else - throw e; - } - if (bytesRead > 0) { - result = buf.slice(0, bytesRead).toString("utf-8"); - } else { - result = null; - } - } - if (!result) { - return null; - } - tty.input = intArrayFromString(result, true); - } - return tty.input.shift(); - }, - put_char: function(tty, val) { - if (val === null || val === 10) { - out(UTF8ArrayToString(tty.output, 0)); - tty.output = []; - } else { - if (val != 0) - tty.output.push(val); - } - }, - flush: function(tty) { - if (tty.output && tty.output.length > 0) { - out(UTF8ArrayToString(tty.output, 0)); - tty.output = []; - } - } - }, - default_tty1_ops: { - put_char: function(tty, val) { - if (val === null || val === 10) { - err(UTF8ArrayToString(tty.output, 0)); - tty.output = []; - } else { - if (val != 0) - tty.output.push(val); - } - }, - flush: function(tty) { - if (tty.output && tty.output.length > 0) { - err(UTF8ArrayToString(tty.output, 0)); - tty.output = []; - } - } - } - }; - function mmapAlloc(size) { - var alignedSize = alignMemory(size, 65536); - var ptr = _malloc(alignedSize); - while (size < alignedSize) - HEAP8[ptr + size++] = 0; - return ptr; - } - var MEMFS = { - ops_table: null, - mount: function(mount) { - return MEMFS.createNode(null, "/", 16384 | 511, 0); - }, - createNode: function(parent, name, mode, dev) { - if (FS.isBlkdev(mode) || FS.isFIFO(mode)) { - throw new FS.ErrnoError(63); - } - if (!MEMFS.ops_table) { - MEMFS.ops_table = { - dir: { - node: { - getattr: MEMFS.node_ops.getattr, - setattr: MEMFS.node_ops.setattr, - lookup: MEMFS.node_ops.lookup, - mknod: MEMFS.node_ops.mknod, - rename: MEMFS.node_ops.rename, - unlink: MEMFS.node_ops.unlink, - rmdir: MEMFS.node_ops.rmdir, - readdir: MEMFS.node_ops.readdir, - symlink: MEMFS.node_ops.symlink - }, - stream: { llseek: MEMFS.stream_ops.llseek } - }, - file: { - node: { - getattr: MEMFS.node_ops.getattr, - setattr: MEMFS.node_ops.setattr - }, - stream: { - llseek: MEMFS.stream_ops.llseek, - read: MEMFS.stream_ops.read, - write: MEMFS.stream_ops.write, - allocate: MEMFS.stream_ops.allocate, - mmap: MEMFS.stream_ops.mmap, - msync: MEMFS.stream_ops.msync - } - }, - link: { - node: { - getattr: MEMFS.node_ops.getattr, - setattr: MEMFS.node_ops.setattr, - readlink: MEMFS.node_ops.readlink - }, - stream: {} - }, - chrdev: { - node: { - getattr: MEMFS.node_ops.getattr, - setattr: MEMFS.node_ops.setattr - }, - stream: FS.chrdev_stream_ops - } - }; - } - var node = FS.createNode(parent, name, mode, dev); - if (FS.isDir(node.mode)) { - node.node_ops = MEMFS.ops_table.dir.node; - node.stream_ops = MEMFS.ops_table.dir.stream; - node.contents = {}; - } else if (FS.isFile(node.mode)) { - node.node_ops = MEMFS.ops_table.file.node; - node.stream_ops = MEMFS.ops_table.file.stream; - node.usedBytes = 0; - node.contents = null; - } else if (FS.isLink(node.mode)) { - node.node_ops = MEMFS.ops_table.link.node; - node.stream_ops = MEMFS.ops_table.link.stream; - } else if (FS.isChrdev(node.mode)) { - node.node_ops = MEMFS.ops_table.chrdev.node; - node.stream_ops = MEMFS.ops_table.chrdev.stream; - } - node.timestamp = Date.now(); - if (parent) { - parent.contents[name] = node; - parent.timestamp = node.timestamp; - } - return node; - }, - getFileDataAsTypedArray: function(node) { - if (!node.contents) - return new Uint8Array(0); - if (node.contents.subarray) - return node.contents.subarray(0, node.usedBytes); - return new Uint8Array(node.contents); - }, - expandFileStorage: function(node, newCapacity) { - var prevCapacity = node.contents ? node.contents.length : 0; - if (prevCapacity >= newCapacity) - return; - var CAPACITY_DOUBLING_MAX = 1024 * 1024; - newCapacity = Math.max( - newCapacity, - prevCapacity * (prevCapacity < CAPACITY_DOUBLING_MAX ? 2 : 1.125) >>> 0 - ); - if (prevCapacity != 0) - newCapacity = Math.max(newCapacity, 256); - var oldContents = node.contents; - node.contents = new Uint8Array(newCapacity); - if (node.usedBytes > 0) - node.contents.set(oldContents.subarray(0, node.usedBytes), 0); - }, - resizeFileStorage: function(node, newSize) { - if (node.usedBytes == newSize) - return; - if (newSize == 0) { - node.contents = null; - node.usedBytes = 0; - } else { - var oldContents = node.contents; - node.contents = new Uint8Array(newSize); - if (oldContents) { - node.contents.set( - oldContents.subarray(0, Math.min(newSize, node.usedBytes)) - ); - } - node.usedBytes = newSize; - } - }, - node_ops: { - getattr: function(node) { - var attr = {}; - attr.dev = FS.isChrdev(node.mode) ? node.id : 1; - attr.ino = node.id; - attr.mode = node.mode; - attr.nlink = 1; - attr.uid = 0; - attr.gid = 0; - attr.rdev = node.rdev; - if (FS.isDir(node.mode)) { - attr.size = 4096; - } else if (FS.isFile(node.mode)) { - attr.size = node.usedBytes; - } else if (FS.isLink(node.mode)) { - attr.size = node.link.length; - } else { - attr.size = 0; - } - attr.atime = new Date(node.timestamp); - attr.mtime = new Date(node.timestamp); - attr.ctime = new Date(node.timestamp); - attr.blksize = 4096; - attr.blocks = Math.ceil(attr.size / attr.blksize); - return attr; - }, - setattr: function(node, attr) { - if (attr.mode !== void 0) { - node.mode = attr.mode; - } - if (attr.timestamp !== void 0) { - node.timestamp = attr.timestamp; - } - if (attr.size !== void 0) { - MEMFS.resizeFileStorage(node, attr.size); - } - }, - lookup: function(parent, name) { - throw FS.genericErrors[44]; - }, - mknod: function(parent, name, mode, dev) { - return MEMFS.createNode(parent, name, mode, dev); - }, - rename: function(old_node, new_dir, new_name) { - if (FS.isDir(old_node.mode)) { - var new_node; - try { - new_node = FS.lookupNode(new_dir, new_name); - } catch (e) { - } - if (new_node) { - for (var i in new_node.contents) { - throw new FS.ErrnoError(55); - } - } - } - delete old_node.parent.contents[old_node.name]; - old_node.parent.timestamp = Date.now(); - old_node.name = new_name; - new_dir.contents[new_name] = old_node; - new_dir.timestamp = old_node.parent.timestamp; - old_node.parent = new_dir; - }, - unlink: function(parent, name) { - delete parent.contents[name]; - parent.timestamp = Date.now(); - }, - rmdir: function(parent, name) { - var node = FS.lookupNode(parent, name); - for (var i in node.contents) { - throw new FS.ErrnoError(55); - } - delete parent.contents[name]; - parent.timestamp = Date.now(); - }, - readdir: function(node) { - var entries = [".", ".."]; - for (var key2 in node.contents) { - if (!node.contents.hasOwnProperty(key2)) { - continue; - } - entries.push(key2); - } - return entries; - }, - symlink: function(parent, newname, oldpath) { - var node = MEMFS.createNode(parent, newname, 511 | 40960, 0); - node.link = oldpath; - return node; - }, - readlink: function(node) { - if (!FS.isLink(node.mode)) { - throw new FS.ErrnoError(28); - } - return node.link; - } - }, - stream_ops: { - read: function(stream, buffer2, offset, length, position) { - var contents = stream.node.contents; - if (position >= stream.node.usedBytes) - return 0; - var size = Math.min(stream.node.usedBytes - position, length); - if (size > 8 && contents.subarray) { - buffer2.set(contents.subarray(position, position + size), offset); - } else { - for (var i = 0; i < size; i++) - buffer2[offset + i] = contents[position + i]; - } - return size; - }, - write: function(stream, buffer2, offset, length, position, canOwn) { - if (buffer2.buffer === HEAP8.buffer) { - canOwn = false; - } - if (!length) - return 0; - var node = stream.node; - node.timestamp = Date.now(); - if (buffer2.subarray && (!node.contents || node.contents.subarray)) { - if (canOwn) { - node.contents = buffer2.subarray(offset, offset + length); - node.usedBytes = length; - return length; - } else if (node.usedBytes === 0 && position === 0) { - node.contents = buffer2.slice(offset, offset + length); - node.usedBytes = length; - return length; - } else if (position + length <= node.usedBytes) { - node.contents.set( - buffer2.subarray(offset, offset + length), - position - ); - return length; - } - } - MEMFS.expandFileStorage(node, position + length); - if (node.contents.subarray && buffer2.subarray) { - node.contents.set( - buffer2.subarray(offset, offset + length), - position - ); - } else { - for (var i = 0; i < length; i++) { - node.contents[position + i] = buffer2[offset + i]; - } - } - node.usedBytes = Math.max(node.usedBytes, position + length); - return length; - }, - llseek: function(stream, offset, whence) { - var position = offset; - if (whence === 1) { - position += stream.position; - } else if (whence === 2) { - if (FS.isFile(stream.node.mode)) { - position += stream.node.usedBytes; - } - } - if (position < 0) { - throw new FS.ErrnoError(28); - } - return position; - }, - allocate: function(stream, offset, length) { - MEMFS.expandFileStorage(stream.node, offset + length); - stream.node.usedBytes = Math.max( - stream.node.usedBytes, - offset + length - ); - }, - mmap: function(stream, address, length, position, prot, flags) { - if (address !== 0) { - throw new FS.ErrnoError(28); - } - if (!FS.isFile(stream.node.mode)) { - throw new FS.ErrnoError(43); - } - var ptr; - var allocated; - var contents = stream.node.contents; - if (!(flags & 2) && contents.buffer === buffer) { - allocated = false; - ptr = contents.byteOffset; - } else { - if (position > 0 || position + length < contents.length) { - if (contents.subarray) { - contents = contents.subarray(position, position + length); - } else { - contents = Array.prototype.slice.call( - contents, - position, - position + length - ); - } - } - allocated = true; - ptr = mmapAlloc(length); - if (!ptr) { - throw new FS.ErrnoError(48); - } - HEAP8.set(contents, ptr); - } - return { ptr, allocated }; - }, - msync: function(stream, buffer2, offset, length, mmapFlags) { - if (!FS.isFile(stream.node.mode)) { - throw new FS.ErrnoError(43); - } - if (mmapFlags & 2) { - return 0; - } - MEMFS.stream_ops.write( - stream, - buffer2, - 0, - length, - offset, - false - ); - return 0; - } - } - }; - var ERRNO_CODES = { - EPERM: 63, - ENOENT: 44, - ESRCH: 71, - EINTR: 27, - EIO: 29, - ENXIO: 60, - E2BIG: 1, - ENOEXEC: 45, - EBADF: 8, - ECHILD: 12, - EAGAIN: 6, - EWOULDBLOCK: 6, - ENOMEM: 48, - EACCES: 2, - EFAULT: 21, - ENOTBLK: 105, - EBUSY: 10, - EEXIST: 20, - EXDEV: 75, - ENODEV: 43, - ENOTDIR: 54, - EISDIR: 31, - EINVAL: 28, - ENFILE: 41, - EMFILE: 33, - ENOTTY: 59, - ETXTBSY: 74, - EFBIG: 22, - ENOSPC: 51, - ESPIPE: 70, - EROFS: 69, - EMLINK: 34, - EPIPE: 64, - EDOM: 18, - ERANGE: 68, - ENOMSG: 49, - EIDRM: 24, - ECHRNG: 106, - EL2NSYNC: 156, - EL3HLT: 107, - EL3RST: 108, - ELNRNG: 109, - EUNATCH: 110, - ENOCSI: 111, - EL2HLT: 112, - EDEADLK: 16, - ENOLCK: 46, - EBADE: 113, - EBADR: 114, - EXFULL: 115, - ENOANO: 104, - EBADRQC: 103, - EBADSLT: 102, - EDEADLOCK: 16, - EBFONT: 101, - ENOSTR: 100, - ENODATA: 116, - ETIME: 117, - ENOSR: 118, - ENONET: 119, - ENOPKG: 120, - EREMOTE: 121, - ENOLINK: 47, - EADV: 122, - ESRMNT: 123, - ECOMM: 124, - EPROTO: 65, - EMULTIHOP: 36, - EDOTDOT: 125, - EBADMSG: 9, - ENOTUNIQ: 126, - EBADFD: 127, - EREMCHG: 128, - ELIBACC: 129, - ELIBBAD: 130, - ELIBSCN: 131, - ELIBMAX: 132, - ELIBEXEC: 133, - ENOSYS: 52, - ENOTEMPTY: 55, - ENAMETOOLONG: 37, - ELOOP: 32, - EOPNOTSUPP: 138, - EPFNOSUPPORT: 139, - ECONNRESET: 15, - ENOBUFS: 42, - EAFNOSUPPORT: 5, - EPROTOTYPE: 67, - ENOTSOCK: 57, - ENOPROTOOPT: 50, - ESHUTDOWN: 140, - ECONNREFUSED: 14, - EADDRINUSE: 3, - ECONNABORTED: 13, - ENETUNREACH: 40, - ENETDOWN: 38, - ETIMEDOUT: 73, - EHOSTDOWN: 142, - EHOSTUNREACH: 23, - EINPROGRESS: 26, - EALREADY: 7, - EDESTADDRREQ: 17, - EMSGSIZE: 35, - EPROTONOSUPPORT: 66, - ESOCKTNOSUPPORT: 137, - EADDRNOTAVAIL: 4, - ENETRESET: 39, - EISCONN: 30, - ENOTCONN: 53, - ETOOMANYREFS: 141, - EUSERS: 136, - EDQUOT: 19, - ESTALE: 72, - ENOTSUP: 138, - ENOMEDIUM: 148, - EILSEQ: 25, - EOVERFLOW: 61, - ECANCELED: 11, - ENOTRECOVERABLE: 56, - EOWNERDEAD: 62, - ESTRPIPE: 135 - }; - var NODEFS = { - isWindows: false, - staticInit: function() { - NODEFS.isWindows = !!process.platform.match(/^win/); - var flags = { fs: fs.constants }; - if (flags["fs"]) { - flags = flags["fs"]; - } - NODEFS.flagsForNodeMap = { - 1024: flags["O_APPEND"], - 64: flags["O_CREAT"], - 128: flags["O_EXCL"], - 256: flags["O_NOCTTY"], - 0: flags["O_RDONLY"], - 2: flags["O_RDWR"], - 4096: flags["O_SYNC"], - 512: flags["O_TRUNC"], - 1: flags["O_WRONLY"] - }; - }, - bufferFrom: function(arrayBuffer) { - return Buffer["alloc"] ? Buffer.from(arrayBuffer) : new Buffer(arrayBuffer); - }, - convertNodeCode: function(e) { - var code = e.code; - return ERRNO_CODES[code]; - }, - mount: function(mount) { - return NODEFS.createNode(null, "/", NODEFS.getMode(mount.opts.root), 0); - }, - createNode: function(parent, name, mode, dev) { - if (!FS.isDir(mode) && !FS.isFile(mode) && !FS.isLink(mode)) { - throw new FS.ErrnoError(28); - } - var node = FS.createNode(parent, name, mode); - node.node_ops = NODEFS.node_ops; - node.stream_ops = NODEFS.stream_ops; - return node; - }, - getMode: function(path) { - var stat; - try { - stat = fs.lstatSync(path); - if (NODEFS.isWindows) { - stat.mode = stat.mode | (stat.mode & 292) >> 2; - } - } catch (e) { - if (!e.code) - throw e; - throw new FS.ErrnoError(NODEFS.convertNodeCode(e)); - } - return stat.mode; - }, - realPath: function(node) { - var parts = []; - while (node.parent !== node) { - parts.push(node.name); - node = node.parent; - } - parts.push(node.mount.opts.root); - parts.reverse(); - return PATH.join.apply(null, parts); - }, - flagsForNode: function(flags) { - flags &= ~2097152; - flags &= ~2048; - flags &= ~32768; - flags &= ~524288; - var newFlags = 0; - for (var k in NODEFS.flagsForNodeMap) { - if (flags & k) { - newFlags |= NODEFS.flagsForNodeMap[k]; - flags ^= k; - } - } - if (!flags) { - return newFlags; - } else { - throw new FS.ErrnoError(28); - } - }, - node_ops: { - getattr: function(node) { - var path = NODEFS.realPath(node); - var stat; - try { - stat = fs.lstatSync(path); - } catch (e) { - if (!e.code) - throw e; - throw new FS.ErrnoError(NODEFS.convertNodeCode(e)); - } - if (NODEFS.isWindows && !stat.blksize) { - stat.blksize = 4096; - } - if (NODEFS.isWindows && !stat.blocks) { - stat.blocks = (stat.size + stat.blksize - 1) / stat.blksize | 0; - } - return { - dev: stat.dev, - ino: stat.ino, - mode: stat.mode, - nlink: stat.nlink, - uid: stat.uid, - gid: stat.gid, - rdev: stat.rdev, - size: stat.size, - atime: stat.atime, - mtime: stat.mtime, - ctime: stat.ctime, - blksize: stat.blksize, - blocks: stat.blocks - }; - }, - setattr: function(node, attr) { - var path = NODEFS.realPath(node); - try { - if (attr.mode !== void 0) { - fs.chmodSync(path, attr.mode); - node.mode = attr.mode; - } - if (attr.timestamp !== void 0) { - var date = new Date(attr.timestamp); - fs.utimesSync(path, date, date); - } - if (attr.size !== void 0) { - fs.truncateSync(path, attr.size); - } - } catch (e) { - if (!e.code) - throw e; - throw new FS.ErrnoError(NODEFS.convertNodeCode(e)); - } - }, - lookup: function(parent, name) { - var path = PATH.join2(NODEFS.realPath(parent), name); - var mode = NODEFS.getMode(path); - return NODEFS.createNode(parent, name, mode); - }, - mknod: function(parent, name, mode, dev) { - var node = NODEFS.createNode(parent, name, mode, dev); - var path = NODEFS.realPath(node); - try { - if (FS.isDir(node.mode)) { - fs.mkdirSync(path, node.mode); - } else { - fs.writeFileSync(path, "", { mode: node.mode }); - } - } catch (e) { - if (!e.code) - throw e; - throw new FS.ErrnoError(NODEFS.convertNodeCode(e)); - } - return node; - }, - rename: function(oldNode, newDir, newName) { - var oldPath = NODEFS.realPath(oldNode); - var newPath = PATH.join2(NODEFS.realPath(newDir), newName); - try { - fs.renameSync(oldPath, newPath); - } catch (e) { - if (!e.code) - throw e; - throw new FS.ErrnoError(NODEFS.convertNodeCode(e)); - } - oldNode.name = newName; - }, - unlink: function(parent, name) { - var path = PATH.join2(NODEFS.realPath(parent), name); - try { - fs.unlinkSync(path); - } catch (e) { - if (!e.code) - throw e; - throw new FS.ErrnoError(NODEFS.convertNodeCode(e)); - } - }, - rmdir: function(parent, name) { - var path = PATH.join2(NODEFS.realPath(parent), name); - try { - fs.rmdirSync(path); - } catch (e) { - if (!e.code) - throw e; - throw new FS.ErrnoError(NODEFS.convertNodeCode(e)); - } - }, - readdir: function(node) { - var path = NODEFS.realPath(node); - try { - return fs.readdirSync(path); - } catch (e) { - if (!e.code) - throw e; - throw new FS.ErrnoError(NODEFS.convertNodeCode(e)); - } - }, - symlink: function(parent, newName, oldPath) { - var newPath = PATH.join2(NODEFS.realPath(parent), newName); - try { - fs.symlinkSync(oldPath, newPath); - } catch (e) { - if (!e.code) - throw e; - throw new FS.ErrnoError(NODEFS.convertNodeCode(e)); - } - }, - readlink: function(node) { - var path = NODEFS.realPath(node); - try { - path = fs.readlinkSync(path); - path = NODEJS_PATH.relative( - NODEJS_PATH.resolve(node.mount.opts.root), - path - ); - return path; - } catch (e) { - if (!e.code) - throw e; - throw new FS.ErrnoError(NODEFS.convertNodeCode(e)); - } - } - }, - stream_ops: { - open: function(stream) { - var path = NODEFS.realPath(stream.node); - try { - if (FS.isFile(stream.node.mode)) { - stream.nfd = fs.openSync(path, NODEFS.flagsForNode(stream.flags)); - } - } catch (e) { - if (!e.code) - throw e; - throw new FS.ErrnoError(NODEFS.convertNodeCode(e)); - } - }, - close: function(stream) { - try { - if (FS.isFile(stream.node.mode) && stream.nfd) { - fs.closeSync(stream.nfd); - } - } catch (e) { - if (!e.code) - throw e; - throw new FS.ErrnoError(NODEFS.convertNodeCode(e)); - } - }, - read: function(stream, buffer2, offset, length, position) { - if (length === 0) - return 0; - try { - return fs.readSync( - stream.nfd, - NODEFS.bufferFrom(buffer2.buffer), - offset, - length, - position - ); - } catch (e) { - throw new FS.ErrnoError(NODEFS.convertNodeCode(e)); - } - }, - write: function(stream, buffer2, offset, length, position) { - try { - return fs.writeSync( - stream.nfd, - NODEFS.bufferFrom(buffer2.buffer), - offset, - length, - position - ); - } catch (e) { - throw new FS.ErrnoError(NODEFS.convertNodeCode(e)); - } - }, - llseek: function(stream, offset, whence) { - var position = offset; - if (whence === 1) { - position += stream.position; - } else if (whence === 2) { - if (FS.isFile(stream.node.mode)) { - try { - var stat = fs.fstatSync(stream.nfd); - position += stat.size; - } catch (e) { - throw new FS.ErrnoError(NODEFS.convertNodeCode(e)); - } - } - } - if (position < 0) { - throw new FS.ErrnoError(28); - } - return position; - }, - mmap: function(stream, address, length, position, prot, flags) { - if (address !== 0) { - throw new FS.ErrnoError(28); - } - if (!FS.isFile(stream.node.mode)) { - throw new FS.ErrnoError(43); - } - var ptr = mmapAlloc(length); - NODEFS.stream_ops.read(stream, HEAP8, ptr, length, position); - return { ptr, allocated: true }; - }, - msync: function(stream, buffer2, offset, length, mmapFlags) { - if (!FS.isFile(stream.node.mode)) { - throw new FS.ErrnoError(43); - } - if (mmapFlags & 2) { - return 0; - } - NODEFS.stream_ops.write( - stream, - buffer2, - 0, - length, - offset, - false - ); - return 0; - } - } - }; - var NODERAWFS = { - lookupPath: function(path) { - return { path, node: { mode: NODEFS.getMode(path) } }; - }, - createStandardStreams: function() { - FS.streams[0] = { - fd: 0, - nfd: 0, - position: 0, - path: "", - flags: 0, - tty: true, - seekable: false - }; - for (var i = 1; i < 3; i++) { - FS.streams[i] = { - fd: i, - nfd: i, - position: 0, - path: "", - flags: 577, - tty: true, - seekable: false - }; - } - }, - cwd: function() { - return process.cwd(); - }, - chdir: function() { - process.chdir.apply(void 0, arguments); - }, - mknod: function(path, mode) { - if (FS.isDir(path)) { - fs.mkdirSync(path, mode); - } else { - fs.writeFileSync(path, "", { mode }); - } - }, - mkdir: function() { - fs.mkdirSync.apply(void 0, arguments); - }, - symlink: function() { - fs.symlinkSync.apply(void 0, arguments); - }, - rename: function() { - fs.renameSync.apply(void 0, arguments); - }, - rmdir: function() { - fs.rmdirSync.apply(void 0, arguments); - }, - readdir: function() { - fs.readdirSync.apply(void 0, arguments); - }, - unlink: function() { - fs.unlinkSync.apply(void 0, arguments); - }, - readlink: function() { - return fs.readlinkSync.apply(void 0, arguments); - }, - stat: function() { - return fs.statSync.apply(void 0, arguments); - }, - lstat: function() { - return fs.lstatSync.apply(void 0, arguments); - }, - chmod: function() { - fs.chmodSync.apply(void 0, arguments); - }, - fchmod: function() { - fs.fchmodSync.apply(void 0, arguments); - }, - chown: function() { - fs.chownSync.apply(void 0, arguments); - }, - fchown: function() { - fs.fchownSync.apply(void 0, arguments); - }, - truncate: function() { - fs.truncateSync.apply(void 0, arguments); - }, - ftruncate: function(fd, len) { - if (len < 0) { - throw new FS.ErrnoError(28); - } - fs.ftruncateSync.apply(void 0, arguments); - }, - utime: function() { - fs.utimesSync.apply(void 0, arguments); - }, - open: function(path, flags, mode, suggestFD) { - if (typeof flags === "string") { - flags = VFS.modeStringToFlags(flags); - } - var nfd = fs.openSync(path, NODEFS.flagsForNode(flags), mode); - var fd = suggestFD != null ? suggestFD : FS.nextfd(nfd); - var stream = { - fd, - nfd, - position: 0, - path, - flags, - seekable: true - }; - FS.streams[fd] = stream; - return stream; - }, - close: function(stream) { - if (!stream.stream_ops) { - fs.closeSync(stream.nfd); - } - FS.closeStream(stream.fd); - }, - llseek: function(stream, offset, whence) { - if (stream.stream_ops) { - return VFS.llseek(stream, offset, whence); - } - var position = offset; - if (whence === 1) { - position += stream.position; - } else if (whence === 2) { - position += fs.fstatSync(stream.nfd).size; - } else if (whence !== 0) { - throw new FS.ErrnoError(ERRNO_CODES.EINVAL); - } - if (position < 0) { - throw new FS.ErrnoError(ERRNO_CODES.EINVAL); - } - stream.position = position; - return position; - }, - read: function(stream, buffer2, offset, length, position) { - if (stream.stream_ops) { - return VFS.read(stream, buffer2, offset, length, position); - } - var seeking = typeof position !== "undefined"; - if (!seeking && stream.seekable) - position = stream.position; - var bytesRead = fs.readSync( - stream.nfd, - NODEFS.bufferFrom(buffer2.buffer), - offset, - length, - position - ); - if (!seeking) - stream.position += bytesRead; - return bytesRead; - }, - write: function(stream, buffer2, offset, length, position) { - if (stream.stream_ops) { - return VFS.write(stream, buffer2, offset, length, position); - } - if (stream.flags & +"1024") { - FS.llseek(stream, 0, +"2"); - } - var seeking = typeof position !== "undefined"; - if (!seeking && stream.seekable) - position = stream.position; - var bytesWritten = fs.writeSync( - stream.nfd, - NODEFS.bufferFrom(buffer2.buffer), - offset, - length, - position - ); - if (!seeking) - stream.position += bytesWritten; - return bytesWritten; - }, - allocate: function() { - throw new FS.ErrnoError(ERRNO_CODES.EOPNOTSUPP); - }, - mmap: function(stream, address, length, position, prot, flags) { - if (stream.stream_ops) { - return VFS.mmap(stream, address, length, position, prot, flags); - } - if (address !== 0) { - throw new FS.ErrnoError(28); - } - var ptr = mmapAlloc(length); - FS.read(stream, HEAP8, ptr, length, position); - return { ptr, allocated: true }; - }, - msync: function(stream, buffer2, offset, length, mmapFlags) { - if (stream.stream_ops) { - return VFS.msync(stream, buffer2, offset, length, mmapFlags); - } - if (mmapFlags & 2) { - return 0; - } - FS.write(stream, buffer2, 0, length, offset); - return 0; - }, - munmap: function() { - return 0; - }, - ioctl: function() { - throw new FS.ErrnoError(ERRNO_CODES.ENOTTY); - } - }; - var FS = { - root: null, - mounts: [], - devices: {}, - streams: [], - nextInode: 1, - nameTable: null, - currentPath: "/", - initialized: false, - ignorePermissions: true, - trackingDelegate: {}, - tracking: { openFlags: { READ: 1, WRITE: 2 } }, - ErrnoError: null, - genericErrors: {}, - filesystems: null, - syncFSRequests: 0, - lookupPath: function(path, opts) { - path = PATH_FS.resolve(FS.cwd(), path); - opts = opts || {}; - if (!path) - return { path: "", node: null }; - var defaults = { follow_mount: true, recurse_count: 0 }; - for (var key2 in defaults) { - if (opts[key2] === void 0) { - opts[key2] = defaults[key2]; - } - } - if (opts.recurse_count > 8) { - throw new FS.ErrnoError(32); - } - var parts = PATH.normalizeArray( - path.split("/").filter(function(p) { - return !!p; - }), - false - ); - var current = FS.root; - var current_path = "/"; - for (var i = 0; i < parts.length; i++) { - var islast = i === parts.length - 1; - if (islast && opts.parent) { - break; - } - current = FS.lookupNode(current, parts[i]); - current_path = PATH.join2(current_path, parts[i]); - if (FS.isMountpoint(current)) { - if (!islast || islast && opts.follow_mount) { - current = current.mounted.root; - } - } - if (!islast || opts.follow) { - var count = 0; - while (FS.isLink(current.mode)) { - var link = FS.readlink(current_path); - current_path = PATH_FS.resolve(PATH.dirname(current_path), link); - var lookup = FS.lookupPath(current_path, { - recurse_count: opts.recurse_count - }); - current = lookup.node; - if (count++ > 40) { - throw new FS.ErrnoError(32); - } - } - } - } - return { path: current_path, node: current }; - }, - getPath: function(node) { - var path; - while (true) { - if (FS.isRoot(node)) { - var mount = node.mount.mountpoint; - if (!path) - return mount; - return mount[mount.length - 1] !== "/" ? mount + "/" + path : mount + path; - } - path = path ? node.name + "/" + path : node.name; - node = node.parent; - } - }, - hashName: function(parentid, name) { - var hash = 0; - for (var i = 0; i < name.length; i++) { - hash = (hash << 5) - hash + name.charCodeAt(i) | 0; - } - return (parentid + hash >>> 0) % FS.nameTable.length; - }, - hashAddNode: function(node) { - var hash = FS.hashName(node.parent.id, node.name); - node.name_next = FS.nameTable[hash]; - FS.nameTable[hash] = node; - }, - hashRemoveNode: function(node) { - var hash = FS.hashName(node.parent.id, node.name); - if (FS.nameTable[hash] === node) { - FS.nameTable[hash] = node.name_next; - } else { - var current = FS.nameTable[hash]; - while (current) { - if (current.name_next === node) { - current.name_next = node.name_next; - break; - } - current = current.name_next; - } - } - }, - lookupNode: function(parent, name) { - var errCode = FS.mayLookup(parent); - if (errCode) { - throw new FS.ErrnoError(errCode, parent); - } - var hash = FS.hashName(parent.id, name); - for (var node = FS.nameTable[hash]; node; node = node.name_next) { - var nodeName = node.name; - if (node.parent.id === parent.id && nodeName === name) { - return node; - } - } - return FS.lookup(parent, name); - }, - createNode: function(parent, name, mode, rdev) { - var node = new FS.FSNode(parent, name, mode, rdev); - FS.hashAddNode(node); - return node; - }, - destroyNode: function(node) { - FS.hashRemoveNode(node); - }, - isRoot: function(node) { - return node === node.parent; - }, - isMountpoint: function(node) { - return !!node.mounted; - }, - isFile: function(mode) { - return (mode & 61440) === 32768; - }, - isDir: function(mode) { - return (mode & 61440) === 16384; - }, - isLink: function(mode) { - return (mode & 61440) === 40960; - }, - isChrdev: function(mode) { - return (mode & 61440) === 8192; - }, - isBlkdev: function(mode) { - return (mode & 61440) === 24576; - }, - isFIFO: function(mode) { - return (mode & 61440) === 4096; - }, - isSocket: function(mode) { - return (mode & 49152) === 49152; - }, - flagModes: { r: 0, "r+": 2, w: 577, "w+": 578, a: 1089, "a+": 1090 }, - modeStringToFlags: function(str) { - var flags = FS.flagModes[str]; - if (typeof flags === "undefined") { - throw new Error("Unknown file open mode: " + str); - } - return flags; - }, - flagsToPermissionString: function(flag) { - var perms = ["r", "w", "rw"][flag & 3]; - if (flag & 512) { - perms += "w"; - } - return perms; - }, - nodePermissions: function(node, perms) { - if (FS.ignorePermissions) { - return 0; - } - if (perms.includes("r") && !(node.mode & 292)) { - return 2; - } else if (perms.includes("w") && !(node.mode & 146)) { - return 2; - } else if (perms.includes("x") && !(node.mode & 73)) { - return 2; - } - return 0; - }, - mayLookup: function(dir) { - var errCode = FS.nodePermissions(dir, "x"); - if (errCode) - return errCode; - if (!dir.node_ops.lookup) - return 2; - return 0; - }, - mayCreate: function(dir, name) { - try { - var node = FS.lookupNode(dir, name); - return 20; - } catch (e) { - } - return FS.nodePermissions(dir, "wx"); - }, - mayDelete: function(dir, name, isdir) { - var node; - try { - node = FS.lookupNode(dir, name); - } catch (e) { - return e.errno; - } - var errCode = FS.nodePermissions(dir, "wx"); - if (errCode) { - return errCode; - } - if (isdir) { - if (!FS.isDir(node.mode)) { - return 54; - } - if (FS.isRoot(node) || FS.getPath(node) === FS.cwd()) { - return 10; - } - } else { - if (FS.isDir(node.mode)) { - return 31; - } - } - return 0; - }, - mayOpen: function(node, flags) { - if (!node) { - return 44; - } - if (FS.isLink(node.mode)) { - return 32; - } else if (FS.isDir(node.mode)) { - if (FS.flagsToPermissionString(flags) !== "r" || flags & 512) { - return 31; - } - } - return FS.nodePermissions(node, FS.flagsToPermissionString(flags)); - }, - MAX_OPEN_FDS: 4096, - nextfd: function(fd_start, fd_end) { - fd_start = fd_start || 0; - fd_end = fd_end || FS.MAX_OPEN_FDS; - for (var fd = fd_start; fd <= fd_end; fd++) { - if (!FS.streams[fd]) { - return fd; - } - } - throw new FS.ErrnoError(33); - }, - getStream: function(fd) { - return FS.streams[fd]; - }, - createStream: function(stream, fd_start, fd_end) { - if (!FS.FSStream) { - FS.FSStream = function() { - }; - FS.FSStream.prototype = { - object: { - get: function() { - return this.node; - }, - set: function(val) { - this.node = val; - } - }, - isRead: { - get: function() { - return (this.flags & 2097155) !== 1; - } - }, - isWrite: { - get: function() { - return (this.flags & 2097155) !== 0; - } - }, - isAppend: { - get: function() { - return this.flags & 1024; - } - } - }; - } - var newStream = new FS.FSStream(); - for (var p in stream) { - newStream[p] = stream[p]; - } - stream = newStream; - var fd = FS.nextfd(fd_start, fd_end); - stream.fd = fd; - FS.streams[fd] = stream; - return stream; - }, - closeStream: function(fd) { - FS.streams[fd] = null; - }, - chrdev_stream_ops: { - open: function(stream) { - var device = FS.getDevice(stream.node.rdev); - stream.stream_ops = device.stream_ops; - if (stream.stream_ops.open) { - stream.stream_ops.open(stream); - } - }, - llseek: function() { - throw new FS.ErrnoError(70); - } - }, - major: function(dev) { - return dev >> 8; - }, - minor: function(dev) { - return dev & 255; - }, - makedev: function(ma, mi) { - return ma << 8 | mi; - }, - registerDevice: function(dev, ops) { - FS.devices[dev] = { stream_ops: ops }; - }, - getDevice: function(dev) { - return FS.devices[dev]; - }, - getMounts: function(mount) { - var mounts = []; - var check = [mount]; - while (check.length) { - var m = check.pop(); - mounts.push(m); - check.push.apply(check, m.mounts); - } - return mounts; - }, - syncfs: function(populate, callback) { - if (typeof populate === "function") { - callback = populate; - populate = false; - } - FS.syncFSRequests++; - if (FS.syncFSRequests > 1) { - err( - "warning: " + FS.syncFSRequests + " FS.syncfs operations in flight at once, probably just doing extra work" - ); - } - var mounts = FS.getMounts(FS.root.mount); - var completed = 0; - function doCallback(errCode) { - FS.syncFSRequests--; - return callback(errCode); - } - function done(errCode) { - if (errCode) { - if (!done.errored) { - done.errored = true; - return doCallback(errCode); - } - return; - } - if (++completed >= mounts.length) { - doCallback(null); - } - } - mounts.forEach(function(mount) { - if (!mount.type.syncfs) { - return done(null); - } - mount.type.syncfs(mount, populate, done); - }); - }, - mount: function(type, opts, mountpoint) { - var root = mountpoint === "/"; - var pseudo = !mountpoint; - var node; - if (root && FS.root) { - throw new FS.ErrnoError(10); - } else if (!root && !pseudo) { - var lookup = FS.lookupPath(mountpoint, { follow_mount: false }); - mountpoint = lookup.path; - node = lookup.node; - if (FS.isMountpoint(node)) { - throw new FS.ErrnoError(10); - } - if (!FS.isDir(node.mode)) { - throw new FS.ErrnoError(54); - } - } - var mount = { - type, - opts, - mountpoint, - mounts: [] - }; - var mountRoot = type.mount(mount); - mountRoot.mount = mount; - mount.root = mountRoot; - if (root) { - FS.root = mountRoot; - } else if (node) { - node.mounted = mount; - if (node.mount) { - node.mount.mounts.push(mount); - } - } - return mountRoot; - }, - unmount: function(mountpoint) { - var lookup = FS.lookupPath(mountpoint, { follow_mount: false }); - if (!FS.isMountpoint(lookup.node)) { - throw new FS.ErrnoError(28); - } - var node = lookup.node; - var mount = node.mounted; - var mounts = FS.getMounts(mount); - Object.keys(FS.nameTable).forEach(function(hash) { - var current = FS.nameTable[hash]; - while (current) { - var next = current.name_next; - if (mounts.includes(current.mount)) { - FS.destroyNode(current); - } - current = next; - } - }); - node.mounted = null; - var idx = node.mount.mounts.indexOf(mount); - node.mount.mounts.splice(idx, 1); - }, - lookup: function(parent, name) { - return parent.node_ops.lookup(parent, name); - }, - mknod: function(path, mode, dev) { - var lookup = FS.lookupPath(path, { parent: true }); - var parent = lookup.node; - var name = PATH.basename(path); - if (!name || name === "." || name === "..") { - throw new FS.ErrnoError(28); - } - var errCode = FS.mayCreate(parent, name); - if (errCode) { - throw new FS.ErrnoError(errCode); - } - if (!parent.node_ops.mknod) { - throw new FS.ErrnoError(63); - } - return parent.node_ops.mknod(parent, name, mode, dev); - }, - create: function(path, mode) { - mode = mode !== void 0 ? mode : 438; - mode &= 4095; - mode |= 32768; - return FS.mknod(path, mode, 0); - }, - mkdir: function(path, mode) { - mode = mode !== void 0 ? mode : 511; - mode &= 511 | 512; - mode |= 16384; - return FS.mknod(path, mode, 0); - }, - mkdirTree: function(path, mode) { - var dirs = path.split("/"); - var d = ""; - for (var i = 0; i < dirs.length; ++i) { - if (!dirs[i]) - continue; - d += "/" + dirs[i]; - try { - FS.mkdir(d, mode); - } catch (e) { - if (e.errno != 20) - throw e; - } - } - }, - mkdev: function(path, mode, dev) { - if (typeof dev === "undefined") { - dev = mode; - mode = 438; - } - mode |= 8192; - return FS.mknod(path, mode, dev); - }, - symlink: function(oldpath, newpath) { - if (!PATH_FS.resolve(oldpath)) { - throw new FS.ErrnoError(44); - } - var lookup = FS.lookupPath(newpath, { parent: true }); - var parent = lookup.node; - if (!parent) { - throw new FS.ErrnoError(44); - } - var newname = PATH.basename(newpath); - var errCode = FS.mayCreate(parent, newname); - if (errCode) { - throw new FS.ErrnoError(errCode); - } - if (!parent.node_ops.symlink) { - throw new FS.ErrnoError(63); - } - return parent.node_ops.symlink(parent, newname, oldpath); - }, - rename: function(old_path, new_path) { - var old_dirname = PATH.dirname(old_path); - var new_dirname = PATH.dirname(new_path); - var old_name = PATH.basename(old_path); - var new_name = PATH.basename(new_path); - var lookup, old_dir, new_dir; - lookup = FS.lookupPath(old_path, { parent: true }); - old_dir = lookup.node; - lookup = FS.lookupPath(new_path, { parent: true }); - new_dir = lookup.node; - if (!old_dir || !new_dir) - throw new FS.ErrnoError(44); - if (old_dir.mount !== new_dir.mount) { - throw new FS.ErrnoError(75); - } - var old_node = FS.lookupNode(old_dir, old_name); - var relative = PATH_FS.relative(old_path, new_dirname); - if (relative.charAt(0) !== ".") { - throw new FS.ErrnoError(28); - } - relative = PATH_FS.relative(new_path, old_dirname); - if (relative.charAt(0) !== ".") { - throw new FS.ErrnoError(55); - } - var new_node; - try { - new_node = FS.lookupNode(new_dir, new_name); - } catch (e) { - } - if (old_node === new_node) { - return; - } - var isdir = FS.isDir(old_node.mode); - var errCode = FS.mayDelete(old_dir, old_name, isdir); - if (errCode) { - throw new FS.ErrnoError(errCode); - } - errCode = new_node ? FS.mayDelete(new_dir, new_name, isdir) : FS.mayCreate(new_dir, new_name); - if (errCode) { - throw new FS.ErrnoError(errCode); - } - if (!old_dir.node_ops.rename) { - throw new FS.ErrnoError(63); - } - if (FS.isMountpoint(old_node) || new_node && FS.isMountpoint(new_node)) { - throw new FS.ErrnoError(10); - } - if (new_dir !== old_dir) { - errCode = FS.nodePermissions(old_dir, "w"); - if (errCode) { - throw new FS.ErrnoError(errCode); - } - } - try { - if (FS.trackingDelegate["willMovePath"]) { - FS.trackingDelegate["willMovePath"](old_path, new_path); - } - } catch (e) { - err( - "FS.trackingDelegate['willMovePath']('" + old_path + "', '" + new_path + "') threw an exception: " + e.message - ); - } - FS.hashRemoveNode(old_node); - try { - old_dir.node_ops.rename(old_node, new_dir, new_name); - } catch (e) { - throw e; - } finally { - FS.hashAddNode(old_node); - } - try { - if (FS.trackingDelegate["onMovePath"]) - FS.trackingDelegate["onMovePath"](old_path, new_path); - } catch (e) { - err( - "FS.trackingDelegate['onMovePath']('" + old_path + "', '" + new_path + "') threw an exception: " + e.message - ); - } - }, - rmdir: function(path) { - var lookup = FS.lookupPath(path, { parent: true }); - var parent = lookup.node; - var name = PATH.basename(path); - var node = FS.lookupNode(parent, name); - var errCode = FS.mayDelete(parent, name, true); - if (errCode) { - throw new FS.ErrnoError(errCode); - } - if (!parent.node_ops.rmdir) { - throw new FS.ErrnoError(63); - } - if (FS.isMountpoint(node)) { - throw new FS.ErrnoError(10); - } - try { - if (FS.trackingDelegate["willDeletePath"]) { - FS.trackingDelegate["willDeletePath"](path); - } - } catch (e) { - err( - "FS.trackingDelegate['willDeletePath']('" + path + "') threw an exception: " + e.message - ); - } - parent.node_ops.rmdir(parent, name); - FS.destroyNode(node); - try { - if (FS.trackingDelegate["onDeletePath"]) - FS.trackingDelegate["onDeletePath"](path); - } catch (e) { - err( - "FS.trackingDelegate['onDeletePath']('" + path + "') threw an exception: " + e.message - ); - } - }, - readdir: function(path) { - var lookup = FS.lookupPath(path, { follow: true }); - var node = lookup.node; - if (!node.node_ops.readdir) { - throw new FS.ErrnoError(54); - } - return node.node_ops.readdir(node); - }, - unlink: function(path) { - var lookup = FS.lookupPath(path, { parent: true }); - var parent = lookup.node; - var name = PATH.basename(path); - var node = FS.lookupNode(parent, name); - var errCode = FS.mayDelete(parent, name, false); - if (errCode) { - throw new FS.ErrnoError(errCode); - } - if (!parent.node_ops.unlink) { - throw new FS.ErrnoError(63); - } - if (FS.isMountpoint(node)) { - throw new FS.ErrnoError(10); - } - try { - if (FS.trackingDelegate["willDeletePath"]) { - FS.trackingDelegate["willDeletePath"](path); - } - } catch (e) { - err( - "FS.trackingDelegate['willDeletePath']('" + path + "') threw an exception: " + e.message - ); - } - parent.node_ops.unlink(parent, name); - FS.destroyNode(node); - try { - if (FS.trackingDelegate["onDeletePath"]) - FS.trackingDelegate["onDeletePath"](path); - } catch (e) { - err( - "FS.trackingDelegate['onDeletePath']('" + path + "') threw an exception: " + e.message - ); - } - }, - readlink: function(path) { - var lookup = FS.lookupPath(path); - var link = lookup.node; - if (!link) { - throw new FS.ErrnoError(44); - } - if (!link.node_ops.readlink) { - throw new FS.ErrnoError(28); - } - return PATH_FS.resolve( - FS.getPath(link.parent), - link.node_ops.readlink(link) - ); - }, - stat: function(path, dontFollow) { - var lookup = FS.lookupPath(path, { follow: !dontFollow }); - var node = lookup.node; - if (!node) { - throw new FS.ErrnoError(44); - } - if (!node.node_ops.getattr) { - throw new FS.ErrnoError(63); - } - return node.node_ops.getattr(node); - }, - lstat: function(path) { - return FS.stat(path, true); - }, - chmod: function(path, mode, dontFollow) { - var node; - if (typeof path === "string") { - var lookup = FS.lookupPath(path, { follow: !dontFollow }); - node = lookup.node; - } else { - node = path; - } - if (!node.node_ops.setattr) { - throw new FS.ErrnoError(63); - } - node.node_ops.setattr(node, { - mode: mode & 4095 | node.mode & ~4095, - timestamp: Date.now() - }); - }, - lchmod: function(path, mode) { - FS.chmod(path, mode, true); - }, - fchmod: function(fd, mode) { - var stream = FS.getStream(fd); - if (!stream) { - throw new FS.ErrnoError(8); - } - FS.chmod(stream.node, mode); - }, - chown: function(path, uid, gid, dontFollow) { - var node; - if (typeof path === "string") { - var lookup = FS.lookupPath(path, { follow: !dontFollow }); - node = lookup.node; - } else { - node = path; - } - if (!node.node_ops.setattr) { - throw new FS.ErrnoError(63); - } - node.node_ops.setattr(node, { timestamp: Date.now() }); - }, - lchown: function(path, uid, gid) { - FS.chown(path, uid, gid, true); - }, - fchown: function(fd, uid, gid) { - var stream = FS.getStream(fd); - if (!stream) { - throw new FS.ErrnoError(8); - } - FS.chown(stream.node, uid, gid); - }, - truncate: function(path, len) { - if (len < 0) { - throw new FS.ErrnoError(28); - } - var node; - if (typeof path === "string") { - var lookup = FS.lookupPath(path, { follow: true }); - node = lookup.node; - } else { - node = path; - } - if (!node.node_ops.setattr) { - throw new FS.ErrnoError(63); - } - if (FS.isDir(node.mode)) { - throw new FS.ErrnoError(31); - } - if (!FS.isFile(node.mode)) { - throw new FS.ErrnoError(28); - } - var errCode = FS.nodePermissions(node, "w"); - if (errCode) { - throw new FS.ErrnoError(errCode); - } - node.node_ops.setattr(node, { size: len, timestamp: Date.now() }); - }, - ftruncate: function(fd, len) { - var stream = FS.getStream(fd); - if (!stream) { - throw new FS.ErrnoError(8); - } - if ((stream.flags & 2097155) === 0) { - throw new FS.ErrnoError(28); - } - FS.truncate(stream.node, len); - }, - utime: function(path, atime, mtime) { - var lookup = FS.lookupPath(path, { follow: true }); - var node = lookup.node; - node.node_ops.setattr(node, { timestamp: Math.max(atime, mtime) }); - }, - open: function(path, flags, mode, fd_start, fd_end) { - if (path === "") { - throw new FS.ErrnoError(44); - } - flags = typeof flags === "string" ? FS.modeStringToFlags(flags) : flags; - mode = typeof mode === "undefined" ? 438 : mode; - if (flags & 64) { - mode = mode & 4095 | 32768; - } else { - mode = 0; - } - var node; - if (typeof path === "object") { - node = path; - } else { - path = PATH.normalize(path); - try { - var lookup = FS.lookupPath(path, { follow: !(flags & 131072) }); - node = lookup.node; - } catch (e) { - } - } - var created = false; - if (flags & 64) { - if (node) { - if (flags & 128) { - throw new FS.ErrnoError(20); - } - } else { - node = FS.mknod(path, mode, 0); - created = true; - } - } - if (!node) { - throw new FS.ErrnoError(44); - } - if (FS.isChrdev(node.mode)) { - flags &= ~512; - } - if (flags & 65536 && !FS.isDir(node.mode)) { - throw new FS.ErrnoError(54); - } - if (!created) { - var errCode = FS.mayOpen(node, flags); - if (errCode) { - throw new FS.ErrnoError(errCode); - } - } - if (flags & 512) { - FS.truncate(node, 0); - } - flags &= ~(128 | 512 | 131072); - var stream = FS.createStream( - { - node, - path: FS.getPath(node), - flags, - seekable: true, - position: 0, - stream_ops: node.stream_ops, - ungotten: [], - error: false - }, - fd_start, - fd_end - ); - if (stream.stream_ops.open) { - stream.stream_ops.open(stream); - } - if (Module["logReadFiles"] && !(flags & 1)) { - if (!FS.readFiles) - FS.readFiles = {}; - if (!(path in FS.readFiles)) { - FS.readFiles[path] = 1; - err("FS.trackingDelegate error on read file: " + path); - } - } - try { - if (FS.trackingDelegate["onOpenFile"]) { - var trackingFlags = 0; - if ((flags & 2097155) !== 1) { - trackingFlags |= FS.tracking.openFlags.READ; - } - if ((flags & 2097155) !== 0) { - trackingFlags |= FS.tracking.openFlags.WRITE; - } - FS.trackingDelegate["onOpenFile"](path, trackingFlags); - } - } catch (e) { - err( - "FS.trackingDelegate['onOpenFile']('" + path + "', flags) threw an exception: " + e.message - ); - } - return stream; - }, - close: function(stream) { - if (FS.isClosed(stream)) { - throw new FS.ErrnoError(8); - } - if (stream.getdents) - stream.getdents = null; - try { - if (stream.stream_ops.close) { - stream.stream_ops.close(stream); - } - } catch (e) { - throw e; - } finally { - FS.closeStream(stream.fd); - } - stream.fd = null; - }, - isClosed: function(stream) { - return stream.fd === null; - }, - llseek: function(stream, offset, whence) { - if (FS.isClosed(stream)) { - throw new FS.ErrnoError(8); - } - if (!stream.seekable || !stream.stream_ops.llseek) { - throw new FS.ErrnoError(70); - } - if (whence != 0 && whence != 1 && whence != 2) { - throw new FS.ErrnoError(28); - } - stream.position = stream.stream_ops.llseek(stream, offset, whence); - stream.ungotten = []; - return stream.position; - }, - read: function(stream, buffer2, offset, length, position) { - if (length < 0 || position < 0) { - throw new FS.ErrnoError(28); - } - if (FS.isClosed(stream)) { - throw new FS.ErrnoError(8); - } - if ((stream.flags & 2097155) === 1) { - throw new FS.ErrnoError(8); - } - if (FS.isDir(stream.node.mode)) { - throw new FS.ErrnoError(31); - } - if (!stream.stream_ops.read) { - throw new FS.ErrnoError(28); - } - var seeking = typeof position !== "undefined"; - if (!seeking) { - position = stream.position; - } else if (!stream.seekable) { - throw new FS.ErrnoError(70); - } - var bytesRead = stream.stream_ops.read( - stream, - buffer2, - offset, - length, - position - ); - if (!seeking) - stream.position += bytesRead; - return bytesRead; - }, - write: function(stream, buffer2, offset, length, position, canOwn) { - if (length < 0 || position < 0) { - throw new FS.ErrnoError(28); - } - if (FS.isClosed(stream)) { - throw new FS.ErrnoError(8); - } - if ((stream.flags & 2097155) === 0) { - throw new FS.ErrnoError(8); - } - if (FS.isDir(stream.node.mode)) { - throw new FS.ErrnoError(31); - } - if (!stream.stream_ops.write) { - throw new FS.ErrnoError(28); - } - if (stream.seekable && stream.flags & 1024) { - FS.llseek(stream, 0, 2); - } - var seeking = typeof position !== "undefined"; - if (!seeking) { - position = stream.position; - } else if (!stream.seekable) { - throw new FS.ErrnoError(70); - } - var bytesWritten = stream.stream_ops.write( - stream, - buffer2, - offset, - length, - position, - canOwn - ); - if (!seeking) - stream.position += bytesWritten; - try { - if (stream.path && FS.trackingDelegate["onWriteToFile"]) - FS.trackingDelegate["onWriteToFile"](stream.path); - } catch (e) { - err( - "FS.trackingDelegate['onWriteToFile']('" + stream.path + "') threw an exception: " + e.message - ); - } - return bytesWritten; - }, - allocate: function(stream, offset, length) { - if (FS.isClosed(stream)) { - throw new FS.ErrnoError(8); - } - if (offset < 0 || length <= 0) { - throw new FS.ErrnoError(28); - } - if ((stream.flags & 2097155) === 0) { - throw new FS.ErrnoError(8); - } - if (!FS.isFile(stream.node.mode) && !FS.isDir(stream.node.mode)) { - throw new FS.ErrnoError(43); - } - if (!stream.stream_ops.allocate) { - throw new FS.ErrnoError(138); - } - stream.stream_ops.allocate(stream, offset, length); - }, - mmap: function(stream, address, length, position, prot, flags) { - if ((prot & 2) !== 0 && (flags & 2) === 0 && (stream.flags & 2097155) !== 2) { - throw new FS.ErrnoError(2); - } - if ((stream.flags & 2097155) === 1) { - throw new FS.ErrnoError(2); - } - if (!stream.stream_ops.mmap) { - throw new FS.ErrnoError(43); - } - return stream.stream_ops.mmap( - stream, - address, - length, - position, - prot, - flags - ); - }, - msync: function(stream, buffer2, offset, length, mmapFlags) { - if (!stream || !stream.stream_ops.msync) { - return 0; - } - return stream.stream_ops.msync( - stream, - buffer2, - offset, - length, - mmapFlags - ); - }, - munmap: function(stream) { - return 0; - }, - ioctl: function(stream, cmd, arg) { - if (!stream.stream_ops.ioctl) { - throw new FS.ErrnoError(59); - } - return stream.stream_ops.ioctl(stream, cmd, arg); - }, - readFile: function(path, opts) { - opts = opts || {}; - opts.flags = opts.flags || 0; - opts.encoding = opts.encoding || "binary"; - if (opts.encoding !== "utf8" && opts.encoding !== "binary") { - throw new Error('Invalid encoding type "' + opts.encoding + '"'); - } - var ret; - var stream = FS.open(path, opts.flags); - var stat = FS.stat(path); - var length = stat.size; - var buf = new Uint8Array(length); - FS.read(stream, buf, 0, length, 0); - if (opts.encoding === "utf8") { - ret = UTF8ArrayToString(buf, 0); - } else if (opts.encoding === "binary") { - ret = buf; - } - FS.close(stream); - return ret; - }, - writeFile: function(path, data, opts) { - opts = opts || {}; - opts.flags = opts.flags || 577; - var stream = FS.open(path, opts.flags, opts.mode); - if (typeof data === "string") { - var buf = new Uint8Array(lengthBytesUTF8(data) + 1); - var actualNumBytes = stringToUTF8Array(data, buf, 0, buf.length); - FS.write(stream, buf, 0, actualNumBytes, void 0, opts.canOwn); - } else if (ArrayBuffer.isView(data)) { - FS.write(stream, data, 0, data.byteLength, void 0, opts.canOwn); - } else { - throw new Error("Unsupported data type"); - } - FS.close(stream); - }, - cwd: function() { - return FS.currentPath; - }, - chdir: function(path) { - var lookup = FS.lookupPath(path, { follow: true }); - if (lookup.node === null) { - throw new FS.ErrnoError(44); - } - if (!FS.isDir(lookup.node.mode)) { - throw new FS.ErrnoError(54); - } - var errCode = FS.nodePermissions(lookup.node, "x"); - if (errCode) { - throw new FS.ErrnoError(errCode); - } - FS.currentPath = lookup.path; - }, - createDefaultDirectories: function() { - FS.mkdir("/tmp"); - FS.mkdir("/home"); - FS.mkdir("/home/web_user"); - }, - createDefaultDevices: function() { - FS.mkdir("/dev"); - FS.registerDevice(FS.makedev(1, 3), { - read: function() { - return 0; - }, - write: function(stream, buffer2, offset, length, pos) { - return length; - } - }); - FS.mkdev("/dev/null", FS.makedev(1, 3)); - TTY.register(FS.makedev(5, 0), TTY.default_tty_ops); - TTY.register(FS.makedev(6, 0), TTY.default_tty1_ops); - FS.mkdev("/dev/tty", FS.makedev(5, 0)); - FS.mkdev("/dev/tty1", FS.makedev(6, 0)); - var random_device = getRandomDevice(); - FS.createDevice("/dev", "random", random_device); - FS.createDevice("/dev", "urandom", random_device); - FS.mkdir("/dev/shm"); - FS.mkdir("/dev/shm/tmp"); - }, - createSpecialDirectories: function() { - FS.mkdir("/proc"); - var proc_self = FS.mkdir("/proc/self"); - FS.mkdir("/proc/self/fd"); - FS.mount( - { - mount: function() { - var node = FS.createNode(proc_self, "fd", 16384 | 511, 73); - node.node_ops = { - lookup: function(parent, name) { - var fd = +name; - var stream = FS.getStream(fd); - if (!stream) - throw new FS.ErrnoError(8); - var ret = { - parent: null, - mount: { mountpoint: "fake" }, - node_ops: { - readlink: function() { - return stream.path; - } - } - }; - ret.parent = ret; - return ret; - } - }; - return node; - } - }, - {}, - "/proc/self/fd" - ); - }, - createStandardStreams: function() { - if (Module["stdin"]) { - FS.createDevice("/dev", "stdin", Module["stdin"]); - } else { - FS.symlink("/dev/tty", "/dev/stdin"); - } - if (Module["stdout"]) { - FS.createDevice("/dev", "stdout", null, Module["stdout"]); - } else { - FS.symlink("/dev/tty", "/dev/stdout"); - } - if (Module["stderr"]) { - FS.createDevice("/dev", "stderr", null, Module["stderr"]); - } else { - FS.symlink("/dev/tty1", "/dev/stderr"); - } - FS.open("/dev/stdin", 0); - FS.open("/dev/stdout", 1); - FS.open("/dev/stderr", 1); - }, - ensureErrnoError: function() { - if (FS.ErrnoError) - return; - FS.ErrnoError = function ErrnoError(errno, node) { - this.node = node; - this.setErrno = function(errno2) { - this.errno = errno2; - }; - this.setErrno(errno); - this.message = "FS error"; - }; - FS.ErrnoError.prototype = new Error(); - FS.ErrnoError.prototype.constructor = FS.ErrnoError; - [44].forEach(function(code) { - FS.genericErrors[code] = new FS.ErrnoError(code); - FS.genericErrors[code].stack = ""; - }); - }, - staticInit: function() { - FS.ensureErrnoError(); - FS.nameTable = new Array(4096); - FS.mount(MEMFS, {}, "/"); - FS.createDefaultDirectories(); - FS.createDefaultDevices(); - FS.createSpecialDirectories(); - FS.filesystems = { MEMFS, NODEFS }; - }, - init: function(input, output, error) { - FS.init.initialized = true; - FS.ensureErrnoError(); - Module["stdin"] = input || Module["stdin"]; - Module["stdout"] = output || Module["stdout"]; - Module["stderr"] = error || Module["stderr"]; - FS.createStandardStreams(); - }, - quit: function() { - FS.init.initialized = false; - var fflush = Module["_fflush"]; - if (fflush) - fflush(0); - for (var i = 0; i < FS.streams.length; i++) { - var stream = FS.streams[i]; - if (!stream) { - continue; - } - FS.close(stream); - } - }, - getMode: function(canRead, canWrite) { - var mode = 0; - if (canRead) - mode |= 292 | 73; - if (canWrite) - mode |= 146; - return mode; - }, - findObject: function(path, dontResolveLastLink) { - var ret = FS.analyzePath(path, dontResolveLastLink); - if (ret.exists) { - return ret.object; - } else { - return null; - } - }, - analyzePath: function(path, dontResolveLastLink) { - try { - var lookup = FS.lookupPath(path, { follow: !dontResolveLastLink }); - path = lookup.path; - } catch (e) { - } - var ret = { - isRoot: false, - exists: false, - error: 0, - name: null, - path: null, - object: null, - parentExists: false, - parentPath: null, - parentObject: null - }; - try { - var lookup = FS.lookupPath(path, { parent: true }); - ret.parentExists = true; - ret.parentPath = lookup.path; - ret.parentObject = lookup.node; - ret.name = PATH.basename(path); - lookup = FS.lookupPath(path, { follow: !dontResolveLastLink }); - ret.exists = true; - ret.path = lookup.path; - ret.object = lookup.node; - ret.name = lookup.node.name; - ret.isRoot = lookup.path === "/"; - } catch (e) { - ret.error = e.errno; - } - return ret; - }, - createPath: function(parent, path, canRead, canWrite) { - parent = typeof parent === "string" ? parent : FS.getPath(parent); - var parts = path.split("/").reverse(); - while (parts.length) { - var part = parts.pop(); - if (!part) - continue; - var current = PATH.join2(parent, part); - try { - FS.mkdir(current); - } catch (e) { - } - parent = current; - } - return current; - }, - createFile: function(parent, name, properties, canRead, canWrite) { - var path = PATH.join2( - typeof parent === "string" ? parent : FS.getPath(parent), - name - ); - var mode = FS.getMode(canRead, canWrite); - return FS.create(path, mode); - }, - createDataFile: function(parent, name, data, canRead, canWrite, canOwn) { - var path = name ? PATH.join2( - typeof parent === "string" ? parent : FS.getPath(parent), - name - ) : parent; - var mode = FS.getMode(canRead, canWrite); - var node = FS.create(path, mode); - if (data) { - if (typeof data === "string") { - var arr = new Array(data.length); - for (var i = 0, len = data.length; i < len; ++i) - arr[i] = data.charCodeAt(i); - data = arr; - } - FS.chmod(node, mode | 146); - var stream = FS.open(node, 577); - FS.write(stream, data, 0, data.length, 0, canOwn); - FS.close(stream); - FS.chmod(node, mode); - } - return node; - }, - createDevice: function(parent, name, input, output) { - var path = PATH.join2( - typeof parent === "string" ? parent : FS.getPath(parent), - name - ); - var mode = FS.getMode(!!input, !!output); - if (!FS.createDevice.major) - FS.createDevice.major = 64; - var dev = FS.makedev(FS.createDevice.major++, 0); - FS.registerDevice(dev, { - open: function(stream) { - stream.seekable = false; - }, - close: function(stream) { - if (output && output.buffer && output.buffer.length) { - output(10); - } - }, - read: function(stream, buffer2, offset, length, pos) { - var bytesRead = 0; - for (var i = 0; i < length; i++) { - var result; - try { - result = input(); - } catch (e) { - throw new FS.ErrnoError(29); - } - if (result === void 0 && bytesRead === 0) { - throw new FS.ErrnoError(6); - } - if (result === null || result === void 0) - break; - bytesRead++; - buffer2[offset + i] = result; - } - if (bytesRead) { - stream.node.timestamp = Date.now(); - } - return bytesRead; - }, - write: function(stream, buffer2, offset, length, pos) { - for (var i = 0; i < length; i++) { - try { - output(buffer2[offset + i]); - } catch (e) { - throw new FS.ErrnoError(29); - } - } - if (length) { - stream.node.timestamp = Date.now(); - } - return i; - } - }); - return FS.mkdev(path, mode, dev); - }, - forceLoadFile: function(obj) { - if (obj.isDevice || obj.isFolder || obj.link || obj.contents) - return true; - if (read_) { - try { - obj.contents = intArrayFromString(read_(obj.url), true); - obj.usedBytes = obj.contents.length; - } catch (e) { - throw new FS.ErrnoError(29); - } - } else { - throw new Error("Cannot load without read() or XMLHttpRequest."); - } - }, - createLazyFile: function(parent, name, url, canRead, canWrite) { - var properties; { - var properties = { isDevice: false, url }; - } - var node = FS.createFile(parent, name, properties, canRead, canWrite); - if (properties.contents) { - node.contents = properties.contents; - } else if (properties.url) { - node.contents = null; - node.url = properties.url; - } - Object.defineProperties(node, { - usedBytes: { - get: function() { - return this.contents.length; - } - } - }); - var stream_ops = {}; - var keys = Object.keys(node.stream_ops); - keys.forEach(function(key2) { - var fn = node.stream_ops[key2]; - stream_ops[key2] = function forceLoadLazyFile() { - FS.forceLoadFile(node); - return fn.apply(null, arguments); - }; - }); - stream_ops.read = function stream_ops_read(stream, buffer2, offset, length, position) { - FS.forceLoadFile(node); - var contents = stream.node.contents; - if (position >= contents.length) - return 0; - var size = Math.min(contents.length - position, length); - if (contents.slice) { - for (var i = 0; i < size; i++) { - buffer2[offset + i] = contents[position + i]; - } - } else { - for (var i = 0; i < size; i++) { - buffer2[offset + i] = contents.get(position + i); - } - } - return size; - }; - node.stream_ops = stream_ops; - return node; - }, - createPreloadedFile: function(parent, name, url, canRead, canWrite, onload, onerror, dontCreateFile, canOwn, preFinish) { - Browser.init(); - var fullname = name ? PATH_FS.resolve(PATH.join2(parent, name)) : parent; - function processData(byteArray) { - function finish(byteArray2) { - if (preFinish) - preFinish(); - if (!dontCreateFile) { - FS.createDataFile( - parent, - name, - byteArray2, - canRead, - canWrite, - canOwn - ); - } - if (onload) - onload(); - removeRunDependency(); - } - var handled = false; - Module["preloadPlugins"].forEach(function(plugin) { - if (handled) - return; - if (plugin["canHandle"](fullname)) { - plugin["handle"](byteArray, fullname, finish, function() { - if (onerror) - onerror(); - removeRunDependency(); - }); - handled = true; - } - }); - if (!handled) - finish(byteArray); - } - addRunDependency(); - if (typeof url == "string") { - Browser.asyncLoad( - url, - function(byteArray) { - processData(byteArray); - }, - onerror - ); - } else { - processData(url); - } - }, - indexedDB: function() { - return window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB; - }, - DB_NAME: function() { - return "EM_FS_" + window.location.pathname; - }, - DB_VERSION: 20, - DB_STORE_NAME: "FILE_DATA", - saveFilesToDB: function(paths, onload, onerror) { - onload = onload || function() { - }; - onerror = onerror || function() { - }; - var indexedDB = FS.indexedDB(); - try { - var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION); - } catch (e) { - return onerror(e); - } - openRequest.onupgradeneeded = function openRequest_onupgradeneeded() { - out("creating db"); - var db = openRequest.result; - db.createObjectStore(FS.DB_STORE_NAME); - }; - openRequest.onsuccess = function openRequest_onsuccess() { - var db = openRequest.result; - var transaction = db.transaction([FS.DB_STORE_NAME], "readwrite"); - var files = transaction.objectStore(FS.DB_STORE_NAME); - var ok = 0, fail = 0, total = paths.length; - function finish() { - if (fail == 0) - onload(); - else - onerror(); - } - paths.forEach(function(path) { - var putRequest = files.put( - FS.analyzePath(path).object.contents, - path - ); - putRequest.onsuccess = function putRequest_onsuccess() { - ok++; - if (ok + fail == total) - finish(); - }; - putRequest.onerror = function putRequest_onerror() { - fail++; - if (ok + fail == total) - finish(); - }; - }); - transaction.onerror = onerror; - }; - openRequest.onerror = onerror; - }, - loadFilesFromDB: function(paths, onload, onerror) { - onload = onload || function() { - }; - onerror = onerror || function() { - }; - var indexedDB = FS.indexedDB(); - try { - var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION); - } catch (e) { - return onerror(e); - } - openRequest.onupgradeneeded = onerror; - openRequest.onsuccess = function openRequest_onsuccess() { - var db = openRequest.result; - try { - var transaction = db.transaction([FS.DB_STORE_NAME], "readonly"); - } catch (e) { - onerror(e); - return; - } - var files = transaction.objectStore(FS.DB_STORE_NAME); - var ok = 0, fail = 0, total = paths.length; - function finish() { - if (fail == 0) - onload(); - else - onerror(); - } - paths.forEach(function(path) { - var getRequest = files.get(path); - getRequest.onsuccess = function getRequest_onsuccess() { - if (FS.analyzePath(path).exists) { - FS.unlink(path); - } - FS.createDataFile( - PATH.dirname(path), - PATH.basename(path), - getRequest.result, - true, - true, - true - ); - ok++; - if (ok + fail == total) - finish(); - }; - getRequest.onerror = function getRequest_onerror() { - fail++; - if (ok + fail == total) - finish(); - }; - }); - transaction.onerror = onerror; - }; - openRequest.onerror = onerror; - } - }; - var SYSCALLS = { - mappings: {}, - DEFAULT_POLLMASK: 5, - umask: 511, - calculateAt: function(dirfd, path, allowEmpty) { - if (path[0] === "/") { - return path; - } - var dir; - if (dirfd === -100) { - dir = FS.cwd(); - } else { - var dirstream = FS.getStream(dirfd); - if (!dirstream) - throw new FS.ErrnoError(8); - dir = dirstream.path; - } - if (path.length == 0) { - if (!allowEmpty) { - throw new FS.ErrnoError(44); - } - return dir; - } - return PATH.join2(dir, path); - }, - doStat: function(func, path, buf) { - try { - var stat = func(path); - } catch (e) { - if (e && e.node && PATH.normalize(path) !== PATH.normalize(FS.getPath(e.node))) { - return -54; - } - throw e; - } - HEAP32[buf >> 2] = stat.dev; - HEAP32[buf + 4 >> 2] = 0; - HEAP32[buf + 8 >> 2] = stat.ino; - HEAP32[buf + 12 >> 2] = stat.mode; - HEAP32[buf + 16 >> 2] = stat.nlink; - HEAP32[buf + 20 >> 2] = stat.uid; - HEAP32[buf + 24 >> 2] = stat.gid; - HEAP32[buf + 28 >> 2] = stat.rdev; - HEAP32[buf + 32 >> 2] = 0; - tempI64 = [ - stat.size >>> 0, - (tempDouble = stat.size, +Math.abs(tempDouble) >= 1 ? tempDouble > 0 ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) | 0) >>> 0 : ~~+Math.ceil( - (tempDouble - +(~~tempDouble >>> 0)) / 4294967296 - ) >>> 0 : 0) - ], HEAP32[buf + 40 >> 2] = tempI64[0], HEAP32[buf + 44 >> 2] = tempI64[1]; - HEAP32[buf + 48 >> 2] = 4096; - HEAP32[buf + 52 >> 2] = stat.blocks; - HEAP32[buf + 56 >> 2] = stat.atime.getTime() / 1e3 | 0; - HEAP32[buf + 60 >> 2] = 0; - HEAP32[buf + 64 >> 2] = stat.mtime.getTime() / 1e3 | 0; - HEAP32[buf + 68 >> 2] = 0; - HEAP32[buf + 72 >> 2] = stat.ctime.getTime() / 1e3 | 0; - HEAP32[buf + 76 >> 2] = 0; - tempI64 = [ - stat.ino >>> 0, - (tempDouble = stat.ino, +Math.abs(tempDouble) >= 1 ? tempDouble > 0 ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) | 0) >>> 0 : ~~+Math.ceil( - (tempDouble - +(~~tempDouble >>> 0)) / 4294967296 - ) >>> 0 : 0) - ], HEAP32[buf + 80 >> 2] = tempI64[0], HEAP32[buf + 84 >> 2] = tempI64[1]; - return 0; - }, - doMsync: function(addr, stream, len, flags, offset) { - var buffer2 = HEAPU8.slice(addr, addr + len); - FS.msync(stream, buffer2, offset, len, flags); - }, - doMkdir: function(path, mode) { - path = PATH.normalize(path); - if (path[path.length - 1] === "/") - path = path.substr(0, path.length - 1); - FS.mkdir(path, mode, 0); - return 0; - }, - doMknod: function(path, mode, dev) { - switch (mode & 61440) { - case 32768: - case 8192: - case 24576: - case 4096: - case 49152: - break; - default: - return -28; - } - FS.mknod(path, mode, dev); - return 0; - }, - doReadlink: function(path, buf, bufsize) { - if (bufsize <= 0) - return -28; - var ret = FS.readlink(path); - var len = Math.min(bufsize, lengthBytesUTF8(ret)); - var endChar = HEAP8[buf + len]; - stringToUTF8(ret, buf, bufsize + 1); - HEAP8[buf + len] = endChar; - return len; - }, - doAccess: function(path, amode) { - if (amode & ~7) { - return -28; - } - var node; - var lookup = FS.lookupPath(path, { follow: true }); - node = lookup.node; - if (!node) { - return -44; - } - var perms = ""; - if (amode & 4) - perms += "r"; - if (amode & 2) - perms += "w"; - if (amode & 1) - perms += "x"; - if (perms && FS.nodePermissions(node, perms)) { - return -2; - } - return 0; - }, - doDup: function(path, flags, suggestFD) { - var suggest = FS.getStream(suggestFD); - if (suggest) - FS.close(suggest); - return FS.open(path, flags, 0, suggestFD, suggestFD).fd; - }, - doReadv: function(stream, iov, iovcnt, offset) { - var ret = 0; - for (var i = 0; i < iovcnt; i++) { - var ptr = HEAP32[iov + i * 8 >> 2]; - var len = HEAP32[iov + (i * 8 + 4) >> 2]; - var curr = FS.read(stream, HEAP8, ptr, len, offset); - if (curr < 0) - return -1; - ret += curr; - if (curr < len) - break; - } - return ret; - }, - doWritev: function(stream, iov, iovcnt, offset) { - var ret = 0; - for (var i = 0; i < iovcnt; i++) { - var ptr = HEAP32[iov + i * 8 >> 2]; - var len = HEAP32[iov + (i * 8 + 4) >> 2]; - var curr = FS.write(stream, HEAP8, ptr, len, offset); - if (curr < 0) - return -1; - ret += curr; - } - return ret; - }, - varargs: void 0, - get: function() { - SYSCALLS.varargs += 4; - var ret = HEAP32[SYSCALLS.varargs - 4 >> 2]; - return ret; - }, - getStr: function(ptr) { - var ret = UTF8ToString(ptr); - return ret; - }, - getStreamFromFD: function(fd) { - var stream = FS.getStream(fd); - if (!stream) - throw new FS.ErrnoError(8); - return stream; - }, - get64: function(low, high) { - return low; - } - }; - function ___sys_chmod(path, mode) { - try { - path = SYSCALLS.getStr(path); - FS.chmod(path, mode); - return 0; - } catch (e) { - if (typeof FS === "undefined" || !(e instanceof FS.ErrnoError)) - abort(e); - return -e.errno; - } - } - function setErrNo(value) { - HEAP32[___errno_location() >> 2] = value; - return value; - } - function ___sys_fcntl64(fd, cmd, varargs) { - SYSCALLS.varargs = varargs; - try { - var stream = SYSCALLS.getStreamFromFD(fd); - switch (cmd) { - case 0: { - var arg = SYSCALLS.get(); - if (arg < 0) { - return -28; - } - var newStream; - newStream = FS.open(stream.path, stream.flags, 0, arg); - return newStream.fd; - } - case 1: - case 2: - return 0; - case 3: - return stream.flags; - case 4: { - var arg = SYSCALLS.get(); - stream.flags |= arg; - return 0; - } - case 12: { - var arg = SYSCALLS.get(); - var offset = 0; - HEAP16[arg + offset >> 1] = 2; - return 0; - } - case 13: - case 14: - return 0; - case 16: - case 8: - return -28; - case 9: - setErrNo(28); - return -1; - default: { - return -28; - } - } - } catch (e) { - if (typeof FS === "undefined" || !(e instanceof FS.ErrnoError)) - abort(e); - return -e.errno; - } - } - function ___sys_fstat64(fd, buf) { - try { - var stream = SYSCALLS.getStreamFromFD(fd); - return SYSCALLS.doStat(FS.stat, stream.path, buf); - } catch (e) { - if (typeof FS === "undefined" || !(e instanceof FS.ErrnoError)) - abort(e); - return -e.errno; - } - } - function ___sys_ioctl(fd, op, varargs) { - SYSCALLS.varargs = varargs; - try { - var stream = SYSCALLS.getStreamFromFD(fd); - switch (op) { - case 21509: - case 21505: { - if (!stream.tty) - return -59; - return 0; - } - case 21510: - case 21511: - case 21512: - case 21506: - case 21507: - case 21508: { - if (!stream.tty) - return -59; - return 0; - } - case 21519: { - if (!stream.tty) - return -59; - var argp = SYSCALLS.get(); - HEAP32[argp >> 2] = 0; - return 0; - } - case 21520: { - if (!stream.tty) - return -59; - return -28; - } - case 21531: { - var argp = SYSCALLS.get(); - return FS.ioctl(stream, op, argp); - } - case 21523: { - if (!stream.tty) - return -59; - return 0; - } - case 21524: { - if (!stream.tty) - return -59; - return 0; - } - default: - abort("bad ioctl syscall " + op); - } - } catch (e) { - if (typeof FS === "undefined" || !(e instanceof FS.ErrnoError)) - abort(e); - return -e.errno; - } - } - function ___sys_open(path, flags, varargs) { - SYSCALLS.varargs = varargs; - try { - var pathname = SYSCALLS.getStr(path); - var mode = varargs ? SYSCALLS.get() : 0; - var stream = FS.open(pathname, flags, mode); - return stream.fd; - } catch (e) { - if (typeof FS === "undefined" || !(e instanceof FS.ErrnoError)) - abort(e); - return -e.errno; - } - } - function ___sys_rename(old_path, new_path) { - try { - old_path = SYSCALLS.getStr(old_path); - new_path = SYSCALLS.getStr(new_path); - FS.rename(old_path, new_path); - return 0; - } catch (e) { - if (typeof FS === "undefined" || !(e instanceof FS.ErrnoError)) - abort(e); - return -e.errno; - } - } - function ___sys_rmdir(path) { - try { - path = SYSCALLS.getStr(path); - FS.rmdir(path); - return 0; - } catch (e) { - if (typeof FS === "undefined" || !(e instanceof FS.ErrnoError)) - abort(e); - return -e.errno; - } - } - function ___sys_stat64(path, buf) { - try { - path = SYSCALLS.getStr(path); - return SYSCALLS.doStat(FS.stat, path, buf); - } catch (e) { - if (typeof FS === "undefined" || !(e instanceof FS.ErrnoError)) - abort(e); - return -e.errno; - } - } - function ___sys_unlink(path) { - try { - path = SYSCALLS.getStr(path); - FS.unlink(path); - return 0; - } catch (e) { - if (typeof FS === "undefined" || !(e instanceof FS.ErrnoError)) - abort(e); - return -e.errno; - } - } - function _emscripten_memcpy_big(dest, src, num) { - HEAPU8.copyWithin(dest, src, src + num); - } - function emscripten_realloc_buffer(size) { - try { - wasmMemory.grow(size - buffer.byteLength + 65535 >>> 16); - updateGlobalBufferAndViews(wasmMemory.buffer); - return 1; - } catch (e) { - } - } - function _emscripten_resize_heap(requestedSize) { - var oldSize = HEAPU8.length; - requestedSize = requestedSize >>> 0; - var maxHeapSize = 2147483648; - if (requestedSize > maxHeapSize) { - return false; - } - for (var cutDown = 1; cutDown <= 4; cutDown *= 2) { - var overGrownHeapSize = oldSize * (1 + 0.2 / cutDown); - overGrownHeapSize = Math.min( - overGrownHeapSize, - requestedSize + 100663296 - ); - var newSize = Math.min( - maxHeapSize, - alignUp(Math.max(requestedSize, overGrownHeapSize), 65536) - ); - var replacement = emscripten_realloc_buffer(newSize); - if (replacement) { - return true; - } - } - return false; - } - function _fd_close(fd) { - try { - var stream = SYSCALLS.getStreamFromFD(fd); - FS.close(stream); - return 0; - } catch (e) { - if (typeof FS === "undefined" || !(e instanceof FS.ErrnoError)) - abort(e); - return e.errno; - } - } - function _fd_fdstat_get(fd, pbuf) { - try { - var stream = SYSCALLS.getStreamFromFD(fd); - var type = stream.tty ? 2 : FS.isDir(stream.mode) ? 3 : FS.isLink(stream.mode) ? 7 : 4; - HEAP8[pbuf >> 0] = type; - return 0; - } catch (e) { - if (typeof FS === "undefined" || !(e instanceof FS.ErrnoError)) - abort(e); - return e.errno; - } - } - function _fd_read(fd, iov, iovcnt, pnum) { - try { - var stream = SYSCALLS.getStreamFromFD(fd); - var num = SYSCALLS.doReadv(stream, iov, iovcnt); - HEAP32[pnum >> 2] = num; - return 0; - } catch (e) { - if (typeof FS === "undefined" || !(e instanceof FS.ErrnoError)) - abort(e); - return e.errno; - } - } - function _fd_seek(fd, offset_low, offset_high, whence, newOffset) { - try { - var stream = SYSCALLS.getStreamFromFD(fd); - var HIGH_OFFSET = 4294967296; - var offset = offset_high * HIGH_OFFSET + (offset_low >>> 0); - var DOUBLE_LIMIT = 9007199254740992; - if (offset <= -DOUBLE_LIMIT || offset >= DOUBLE_LIMIT) { - return -61; - } - FS.llseek(stream, offset, whence); - tempI64 = [ - stream.position >>> 0, - (tempDouble = stream.position, +Math.abs(tempDouble) >= 1 ? tempDouble > 0 ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) | 0) >>> 0 : ~~+Math.ceil( - (tempDouble - +(~~tempDouble >>> 0)) / 4294967296 - ) >>> 0 : 0) - ], HEAP32[newOffset >> 2] = tempI64[0], HEAP32[newOffset + 4 >> 2] = tempI64[1]; - if (stream.getdents && offset === 0 && whence === 0) - stream.getdents = null; - return 0; - } catch (e) { - if (typeof FS === "undefined" || !(e instanceof FS.ErrnoError)) - abort(e); - return e.errno; - } - } - function _fd_write(fd, iov, iovcnt, pnum) { - try { - var stream = SYSCALLS.getStreamFromFD(fd); - var num = SYSCALLS.doWritev(stream, iov, iovcnt); - HEAP32[pnum >> 2] = num; - return 0; - } catch (e) { - if (typeof FS === "undefined" || !(e instanceof FS.ErrnoError)) - abort(e); - return e.errno; - } - } - function _setTempRet0(val) { - } - function _time(ptr) { - var ret = Date.now() / 1e3 | 0; - if (ptr) { - HEAP32[ptr >> 2] = ret; - } - return ret; - } - function _tzset() { - if (_tzset.called) - return; - _tzset.called = true; - var currentYear = new Date().getFullYear(); - var winter = new Date(currentYear, 0, 1); - var summer = new Date(currentYear, 6, 1); - var winterOffset = winter.getTimezoneOffset(); - var summerOffset = summer.getTimezoneOffset(); - var stdTimezoneOffset = Math.max(winterOffset, summerOffset); - HEAP32[__get_timezone() >> 2] = stdTimezoneOffset * 60; - HEAP32[__get_daylight() >> 2] = Number(winterOffset != summerOffset); - function extractZone(date) { - var match = date.toTimeString().match(/\(([A-Za-z ]+)\)$/); - return match ? match[1] : "GMT"; - } - var winterName = extractZone(winter); - var summerName = extractZone(summer); - var winterNamePtr = allocateUTF8(winterName); - var summerNamePtr = allocateUTF8(summerName); - if (summerOffset < winterOffset) { - HEAP32[__get_tzname() >> 2] = winterNamePtr; - HEAP32[__get_tzname() + 4 >> 2] = summerNamePtr; - } else { - HEAP32[__get_tzname() >> 2] = summerNamePtr; - HEAP32[__get_tzname() + 4 >> 2] = winterNamePtr; - } - } - function _timegm(tmPtr) { - _tzset(); - var time = Date.UTC( - HEAP32[tmPtr + 20 >> 2] + 1900, - HEAP32[tmPtr + 16 >> 2], - HEAP32[tmPtr + 12 >> 2], - HEAP32[tmPtr + 8 >> 2], - HEAP32[tmPtr + 4 >> 2], - HEAP32[tmPtr >> 2], - 0 - ); - var date = new Date(time); - HEAP32[tmPtr + 24 >> 2] = date.getUTCDay(); - var start = Date.UTC(date.getUTCFullYear(), 0, 1, 0, 0, 0, 0); - var yday = (date.getTime() - start) / (1e3 * 60 * 60 * 24) | 0; - HEAP32[tmPtr + 28 >> 2] = yday; - return date.getTime() / 1e3 | 0; - } - var FSNode = function(parent, name, mode, rdev) { - if (!parent) { - parent = this; - } - this.parent = parent; - this.mount = parent.mount; - this.mounted = null; - this.id = FS.nextInode++; - this.name = name; - this.mode = mode; - this.node_ops = {}; - this.stream_ops = {}; - this.rdev = rdev; - }; - var readMode = 292 | 73; - var writeMode = 146; - Object.defineProperties(FSNode.prototype, { - read: { - get: function() { - return (this.mode & readMode) === readMode; - }, - set: function(val) { - val ? this.mode |= readMode : this.mode &= ~readMode; - } - }, - write: { - get: function() { - return (this.mode & writeMode) === writeMode; - }, - set: function(val) { - val ? this.mode |= writeMode : this.mode &= ~writeMode; - } - }, - isFolder: { - get: function() { - return FS.isDir(this.mode); - } - }, - isDevice: { - get: function() { - return FS.isChrdev(this.mode); - } - } - }); - FS.FSNode = FSNode; - FS.staticInit(); - { - var fs = frozenFs; - var NODEJS_PATH = path__default.default; - NODEFS.staticInit(); - } - { - var _wrapNodeError = function(func) { - return function() { - try { - return func.apply(this, arguments); - } catch (e) { - if (!e.code) - throw e; - throw new FS.ErrnoError(ERRNO_CODES[e.code]); - } - }; - }; - var VFS = Object.assign({}, FS); - for (var _key in NODERAWFS) - FS[_key] = _wrapNodeError(NODERAWFS[_key]); - } - function intArrayFromString(stringy, dontAddNull, length) { - var len = length > 0 ? length : lengthBytesUTF8(stringy) + 1; - var u8array = new Array(len); - var numBytesWritten = stringToUTF8Array( - stringy, - u8array, - 0, - u8array.length - ); - if (dontAddNull) - u8array.length = numBytesWritten; - return u8array; - } - function intArrayFromBase64(s) { - { - var buf; - try { - buf = Buffer.from(s, "base64"); - } catch (_) { - buf = new Buffer(s, "base64"); - } - return new Uint8Array( - buf["buffer"], - buf["byteOffset"], - buf["byteLength"] - ); - } - } - function tryParseAsDataURI(filename) { - if (!isDataURI(filename)) { - return; - } - return intArrayFromBase64(filename.slice(dataURIPrefix.length)); - } - var asmLibraryArg = { - s: ___gmtime_r, - p: ___sys_chmod, - e: ___sys_fcntl64, - k: ___sys_fstat64, - o: ___sys_ioctl, - q: ___sys_open, - i: ___sys_rename, - r: ___sys_rmdir, - c: ___sys_stat64, - h: ___sys_unlink, - l: _emscripten_memcpy_big, - m: _emscripten_resize_heap, - f: _fd_close, - j: _fd_fdstat_get, - g: _fd_read, - n: _fd_seek, - d: _fd_write, - a: _setTempRet0, - b: _time, - t: _timegm - }; - var asm = createWasm(); - Module["___wasm_call_ctors"] = asm["v"]; - Module["_zip_ext_count_symlinks"] = asm["w"]; - Module["_zip_file_get_external_attributes"] = asm["x"]; - Module["_zipstruct_stat"] = asm["y"]; - Module["_zipstruct_statS"] = asm["z"]; - Module["_zipstruct_stat_name"] = asm["A"]; - Module["_zipstruct_stat_index"] = asm["B"]; - Module["_zipstruct_stat_size"] = asm["C"]; - Module["_zipstruct_stat_mtime"] = asm["D"]; - Module["_zipstruct_stat_crc"] = asm["E"]; - Module["_zipstruct_error"] = asm["F"]; - Module["_zipstruct_errorS"] = asm["G"]; - Module["_zipstruct_error_code_zip"] = asm["H"]; - Module["_zipstruct_stat_comp_size"] = asm["I"]; - Module["_zipstruct_stat_comp_method"] = asm["J"]; - Module["_zip_close"] = asm["K"]; - Module["_zip_delete"] = asm["L"]; - Module["_zip_dir_add"] = asm["M"]; - Module["_zip_discard"] = asm["N"]; - Module["_zip_error_init_with_code"] = asm["O"]; - Module["_zip_get_error"] = asm["P"]; - Module["_zip_file_get_error"] = asm["Q"]; - Module["_zip_error_strerror"] = asm["R"]; - Module["_zip_fclose"] = asm["S"]; - Module["_zip_file_add"] = asm["T"]; - Module["_free"] = asm["U"]; - var _malloc = Module["_malloc"] = asm["V"]; - var ___errno_location = Module["___errno_location"] = asm["W"]; - Module["_zip_source_error"] = asm["X"]; - Module["_zip_source_seek"] = asm["Y"]; - Module["_zip_file_set_external_attributes"] = asm["Z"]; - Module["_zip_file_set_mtime"] = asm["_"]; - Module["_zip_fopen"] = asm["$"]; - Module["_zip_fopen_index"] = asm["aa"]; - Module["_zip_fread"] = asm["ba"]; - Module["_zip_get_name"] = asm["ca"]; - Module["_zip_get_num_entries"] = asm["da"]; - Module["_zip_source_read"] = asm["ea"]; - Module["_zip_name_locate"] = asm["fa"]; - Module["_zip_open"] = asm["ga"]; - Module["_zip_open_from_source"] = asm["ha"]; - Module["_zip_set_file_compression"] = asm["ia"]; - Module["_zip_source_buffer"] = asm["ja"]; - Module["_zip_source_buffer_create"] = asm["ka"]; - Module["_zip_source_close"] = asm["la"]; - Module["_zip_source_free"] = asm["ma"]; - Module["_zip_source_keep"] = asm["na"]; - Module["_zip_source_open"] = asm["oa"]; - Module["_zip_source_set_mtime"] = asm["qa"]; - Module["_zip_source_tell"] = asm["ra"]; - Module["_zip_stat"] = asm["sa"]; - Module["_zip_stat_index"] = asm["ta"]; - var __get_tzname = Module["__get_tzname"] = asm["ua"]; - var __get_daylight = Module["__get_daylight"] = asm["va"]; - var __get_timezone = Module["__get_timezone"] = asm["wa"]; - var stackSave = Module["stackSave"] = asm["xa"]; - var stackRestore = Module["stackRestore"] = asm["ya"]; - var stackAlloc = Module["stackAlloc"] = asm["za"]; - Module["cwrap"] = cwrap; - Module["getValue"] = getValue; - var calledRun; - dependenciesFulfilled = function runCaller() { - if (!calledRun) - run(); - if (!calledRun) - dependenciesFulfilled = runCaller; - }; - function run(args) { - if (runDependencies > 0) { - return; - } - preRun(); - if (runDependencies > 0) { - return; - } - function doRun() { - if (calledRun) - return; - calledRun = true; - Module["calledRun"] = true; - if (ABORT) - return; - initRuntime(); - readyPromiseResolve(Module); - if (Module["onRuntimeInitialized"]) - Module["onRuntimeInitialized"](); - postRun(); - } - if (Module["setStatus"]) { - Module["setStatus"]("Running..."); - setTimeout(function() { - setTimeout(function() { - Module["setStatus"](""); - }, 1); - doRun(); - }, 1); - } else { - doRun(); - } - } - Module["run"] = run; - if (Module["preInit"]) { - if (typeof Module["preInit"] == "function") - Module["preInit"] = [Module["preInit"]]; - while (Module["preInit"].length > 0) { - Module["preInit"].pop()(); - } - } - run(); - return createModule2; - }; -}(); -module.exports = createModule; -}(libzipSync)); - -const createModule = libzipSync.exports; - -const number64 = [ - `number`, - `number` -]; -var Errors = /* @__PURE__ */ ((Errors2) => { - Errors2[Errors2["ZIP_ER_OK"] = 0] = "ZIP_ER_OK"; - Errors2[Errors2["ZIP_ER_MULTIDISK"] = 1] = "ZIP_ER_MULTIDISK"; - Errors2[Errors2["ZIP_ER_RENAME"] = 2] = "ZIP_ER_RENAME"; - Errors2[Errors2["ZIP_ER_CLOSE"] = 3] = "ZIP_ER_CLOSE"; - Errors2[Errors2["ZIP_ER_SEEK"] = 4] = "ZIP_ER_SEEK"; - Errors2[Errors2["ZIP_ER_READ"] = 5] = "ZIP_ER_READ"; - Errors2[Errors2["ZIP_ER_WRITE"] = 6] = "ZIP_ER_WRITE"; - Errors2[Errors2["ZIP_ER_CRC"] = 7] = "ZIP_ER_CRC"; - Errors2[Errors2["ZIP_ER_ZIPCLOSED"] = 8] = "ZIP_ER_ZIPCLOSED"; - Errors2[Errors2["ZIP_ER_NOENT"] = 9] = "ZIP_ER_NOENT"; - Errors2[Errors2["ZIP_ER_EXISTS"] = 10] = "ZIP_ER_EXISTS"; - Errors2[Errors2["ZIP_ER_OPEN"] = 11] = "ZIP_ER_OPEN"; - Errors2[Errors2["ZIP_ER_TMPOPEN"] = 12] = "ZIP_ER_TMPOPEN"; - Errors2[Errors2["ZIP_ER_ZLIB"] = 13] = "ZIP_ER_ZLIB"; - Errors2[Errors2["ZIP_ER_MEMORY"] = 14] = "ZIP_ER_MEMORY"; - Errors2[Errors2["ZIP_ER_CHANGED"] = 15] = "ZIP_ER_CHANGED"; - Errors2[Errors2["ZIP_ER_COMPNOTSUPP"] = 16] = "ZIP_ER_COMPNOTSUPP"; - Errors2[Errors2["ZIP_ER_EOF"] = 17] = "ZIP_ER_EOF"; - Errors2[Errors2["ZIP_ER_INVAL"] = 18] = "ZIP_ER_INVAL"; - Errors2[Errors2["ZIP_ER_NOZIP"] = 19] = "ZIP_ER_NOZIP"; - Errors2[Errors2["ZIP_ER_INTERNAL"] = 20] = "ZIP_ER_INTERNAL"; - Errors2[Errors2["ZIP_ER_INCONS"] = 21] = "ZIP_ER_INCONS"; - Errors2[Errors2["ZIP_ER_REMOVE"] = 22] = "ZIP_ER_REMOVE"; - Errors2[Errors2["ZIP_ER_DELETED"] = 23] = "ZIP_ER_DELETED"; - Errors2[Errors2["ZIP_ER_ENCRNOTSUPP"] = 24] = "ZIP_ER_ENCRNOTSUPP"; - Errors2[Errors2["ZIP_ER_RDONLY"] = 25] = "ZIP_ER_RDONLY"; - Errors2[Errors2["ZIP_ER_NOPASSWD"] = 26] = "ZIP_ER_NOPASSWD"; - Errors2[Errors2["ZIP_ER_WRONGPASSWD"] = 27] = "ZIP_ER_WRONGPASSWD"; - Errors2[Errors2["ZIP_ER_OPNOTSUPP"] = 28] = "ZIP_ER_OPNOTSUPP"; - Errors2[Errors2["ZIP_ER_INUSE"] = 29] = "ZIP_ER_INUSE"; - Errors2[Errors2["ZIP_ER_TELL"] = 30] = "ZIP_ER_TELL"; - Errors2[Errors2["ZIP_ER_COMPRESSED_DATA"] = 31] = "ZIP_ER_COMPRESSED_DATA"; - return Errors2; -})(Errors || {}); -const makeInterface = (libzip) => ({ - get HEAP8() { - return libzip.HEAP8; - }, - get HEAPU8() { - return libzip.HEAPU8; - }, - errors: Errors, - SEEK_SET: 0, - SEEK_CUR: 1, - SEEK_END: 2, - ZIP_CHECKCONS: 4, - ZIP_CREATE: 1, - ZIP_EXCL: 2, - ZIP_TRUNCATE: 8, - ZIP_RDONLY: 16, - ZIP_FL_OVERWRITE: 8192, - ZIP_FL_COMPRESSED: 4, - ZIP_OPSYS_DOS: 0, - ZIP_OPSYS_AMIGA: 1, - ZIP_OPSYS_OPENVMS: 2, - ZIP_OPSYS_UNIX: 3, - ZIP_OPSYS_VM_CMS: 4, - ZIP_OPSYS_ATARI_ST: 5, - ZIP_OPSYS_OS_2: 6, - ZIP_OPSYS_MACINTOSH: 7, - ZIP_OPSYS_Z_SYSTEM: 8, - ZIP_OPSYS_CPM: 9, - ZIP_OPSYS_WINDOWS_NTFS: 10, - ZIP_OPSYS_MVS: 11, - ZIP_OPSYS_VSE: 12, - ZIP_OPSYS_ACORN_RISC: 13, - ZIP_OPSYS_VFAT: 14, - ZIP_OPSYS_ALTERNATE_MVS: 15, - ZIP_OPSYS_BEOS: 16, - ZIP_OPSYS_TANDEM: 17, - ZIP_OPSYS_OS_400: 18, - ZIP_OPSYS_OS_X: 19, - ZIP_CM_DEFAULT: -1, - ZIP_CM_STORE: 0, - ZIP_CM_DEFLATE: 8, - uint08S: libzip._malloc(1), - uint16S: libzip._malloc(2), - uint32S: libzip._malloc(4), - uint64S: libzip._malloc(8), - malloc: libzip._malloc, - free: libzip._free, - getValue: libzip.getValue, - open: libzip.cwrap(`zip_open`, `number`, [`string`, `number`, `number`]), - openFromSource: libzip.cwrap(`zip_open_from_source`, `number`, [`number`, `number`, `number`]), - close: libzip.cwrap(`zip_close`, `number`, [`number`]), - discard: libzip.cwrap(`zip_discard`, null, [`number`]), - getError: libzip.cwrap(`zip_get_error`, `number`, [`number`]), - getName: libzip.cwrap(`zip_get_name`, `string`, [`number`, `number`, `number`]), - getNumEntries: libzip.cwrap(`zip_get_num_entries`, `number`, [`number`, `number`]), - delete: libzip.cwrap(`zip_delete`, `number`, [`number`, `number`]), - stat: libzip.cwrap(`zip_stat`, `number`, [`number`, `string`, `number`, `number`]), - statIndex: libzip.cwrap(`zip_stat_index`, `number`, [`number`, ...number64, `number`, `number`]), - fopen: libzip.cwrap(`zip_fopen`, `number`, [`number`, `string`, `number`]), - fopenIndex: libzip.cwrap(`zip_fopen_index`, `number`, [`number`, ...number64, `number`]), - fread: libzip.cwrap(`zip_fread`, `number`, [`number`, `number`, `number`, `number`]), - fclose: libzip.cwrap(`zip_fclose`, `number`, [`number`]), - dir: { - add: libzip.cwrap(`zip_dir_add`, `number`, [`number`, `string`]) - }, - file: { - add: libzip.cwrap(`zip_file_add`, `number`, [`number`, `string`, `number`, `number`]), - getError: libzip.cwrap(`zip_file_get_error`, `number`, [`number`]), - getExternalAttributes: libzip.cwrap(`zip_file_get_external_attributes`, `number`, [`number`, ...number64, `number`, `number`, `number`]), - setExternalAttributes: libzip.cwrap(`zip_file_set_external_attributes`, `number`, [`number`, ...number64, `number`, `number`, `number`]), - setMtime: libzip.cwrap(`zip_file_set_mtime`, `number`, [`number`, ...number64, `number`, `number`]), - setCompression: libzip.cwrap(`zip_set_file_compression`, `number`, [`number`, ...number64, `number`, `number`]) - }, - ext: { - countSymlinks: libzip.cwrap(`zip_ext_count_symlinks`, `number`, [`number`]) - }, - error: { - initWithCode: libzip.cwrap(`zip_error_init_with_code`, null, [`number`, `number`]), - strerror: libzip.cwrap(`zip_error_strerror`, `string`, [`number`]) - }, - name: { - locate: libzip.cwrap(`zip_name_locate`, `number`, [`number`, `string`, `number`]) - }, - source: { - fromUnattachedBuffer: libzip.cwrap(`zip_source_buffer_create`, `number`, [`number`, `number`, `number`, `number`]), - fromBuffer: libzip.cwrap(`zip_source_buffer`, `number`, [`number`, `number`, ...number64, `number`]), - free: libzip.cwrap(`zip_source_free`, null, [`number`]), - keep: libzip.cwrap(`zip_source_keep`, null, [`number`]), - open: libzip.cwrap(`zip_source_open`, `number`, [`number`]), - close: libzip.cwrap(`zip_source_close`, `number`, [`number`]), - seek: libzip.cwrap(`zip_source_seek`, `number`, [`number`, ...number64, `number`]), - tell: libzip.cwrap(`zip_source_tell`, `number`, [`number`]), - read: libzip.cwrap(`zip_source_read`, `number`, [`number`, `number`, `number`]), - error: libzip.cwrap(`zip_source_error`, `number`, [`number`]), - setMtime: libzip.cwrap(`zip_source_set_mtime`, `number`, [`number`, `number`]) - }, - struct: { - stat: libzip.cwrap(`zipstruct_stat`, `number`, []), - statS: libzip.cwrap(`zipstruct_statS`, `number`, []), - statName: libzip.cwrap(`zipstruct_stat_name`, `string`, [`number`]), - statIndex: libzip.cwrap(`zipstruct_stat_index`, `number`, [`number`]), - statSize: libzip.cwrap(`zipstruct_stat_size`, `number`, [`number`]), - statCompSize: libzip.cwrap(`zipstruct_stat_comp_size`, `number`, [`number`]), - statCompMethod: libzip.cwrap(`zipstruct_stat_comp_method`, `number`, [`number`]), - statMtime: libzip.cwrap(`zipstruct_stat_mtime`, `number`, [`number`]), - statCrc: libzip.cwrap(`zipstruct_stat_crc`, `number`, [`number`]), - error: libzip.cwrap(`zipstruct_error`, `number`, []), - errorS: libzip.cwrap(`zipstruct_errorS`, `number`, []), - errorCodeZip: libzip.cwrap(`zipstruct_error_code_zip`, `number`, [`number`]) - } -}); - -let mod = null; -function getLibzipSync() { - if (mod === null) - mod = makeInterface(createModule()); - return mod; -} - -var ErrorCode = /* @__PURE__ */ ((ErrorCode2) => { - ErrorCode2["API_ERROR"] = `API_ERROR`; - ErrorCode2["BUILTIN_NODE_RESOLUTION_FAILED"] = `BUILTIN_NODE_RESOLUTION_FAILED`; - ErrorCode2["EXPORTS_RESOLUTION_FAILED"] = `EXPORTS_RESOLUTION_FAILED`; - ErrorCode2["MISSING_DEPENDENCY"] = `MISSING_DEPENDENCY`; - ErrorCode2["MISSING_PEER_DEPENDENCY"] = `MISSING_PEER_DEPENDENCY`; - ErrorCode2["QUALIFIED_PATH_RESOLUTION_FAILED"] = `QUALIFIED_PATH_RESOLUTION_FAILED`; - ErrorCode2["INTERNAL"] = `INTERNAL`; - ErrorCode2["UNDECLARED_DEPENDENCY"] = `UNDECLARED_DEPENDENCY`; - ErrorCode2["UNSUPPORTED"] = `UNSUPPORTED`; - return ErrorCode2; -})(ErrorCode || {}); -const MODULE_NOT_FOUND_ERRORS = /* @__PURE__ */ new Set([ - "BUILTIN_NODE_RESOLUTION_FAILED" /* BUILTIN_NODE_RESOLUTION_FAILED */, - "MISSING_DEPENDENCY" /* MISSING_DEPENDENCY */, - "MISSING_PEER_DEPENDENCY" /* MISSING_PEER_DEPENDENCY */, - "QUALIFIED_PATH_RESOLUTION_FAILED" /* QUALIFIED_PATH_RESOLUTION_FAILED */, - "UNDECLARED_DEPENDENCY" /* UNDECLARED_DEPENDENCY */ -]); -function makeError(pnpCode, message, data = {}, code) { - code != null ? code : code = MODULE_NOT_FOUND_ERRORS.has(pnpCode) ? `MODULE_NOT_FOUND` : pnpCode; - const propertySpec = { - configurable: true, - writable: true, - enumerable: false - }; - return Object.defineProperties(new Error(message), { - code: { - ...propertySpec, - value: code - }, - pnpCode: { - ...propertySpec, - value: pnpCode - }, - data: { - ...propertySpec, - value: data - } - }); -} -function getIssuerModule(parent) { - let issuer = parent; - while (issuer && (issuer.id === `[eval]` || issuer.id === `` || !issuer.filename)) - issuer = issuer.parent; - return issuer || null; -} -function getPathForDisplay(p) { - return npath.normalize(npath.fromPortablePath(p)); -} - -const [major, minor] = process.versions.node.split(`.`).map((value) => parseInt(value, 10)); -const WATCH_MODE_MESSAGE_USES_ARRAYS = major > 19 || major === 19 && minor >= 2; - -const builtinModules = new Set(require$$0.Module.builtinModules || Object.keys(process.binding(`natives`))); -const isBuiltinModule = (request) => request.startsWith(`node:`) || builtinModules.has(request); -function readPackageScope(checkPath) { - const rootSeparatorIndex = checkPath.indexOf(npath.sep); - let separatorIndex; - do { - separatorIndex = checkPath.lastIndexOf(npath.sep); - checkPath = checkPath.slice(0, separatorIndex); - if (checkPath.endsWith(`${npath.sep}node_modules`)) - return false; - const pjson = readPackage(checkPath + npath.sep); - if (pjson) { - return { - data: pjson, - path: checkPath - }; - } - } while (separatorIndex > rootSeparatorIndex); - return false; -} -function readPackage(requestPath) { - const jsonPath = npath.resolve(requestPath, `package.json`); - if (!fs__default.default.existsSync(jsonPath)) - return null; - return JSON.parse(fs__default.default.readFileSync(jsonPath, `utf8`)); -} -function ERR_REQUIRE_ESM(filename, parentPath = null) { - const basename = parentPath && path__default.default.basename(filename) === path__default.default.basename(parentPath) ? filename : path__default.default.basename(filename); - const msg = `require() of ES Module ${filename}${parentPath ? ` from ${parentPath}` : ``} not supported. -Instead change the require of ${basename} in ${parentPath} to a dynamic import() which is available in all CommonJS modules.`; - const err = new Error(msg); - err.code = `ERR_REQUIRE_ESM`; - return err; -} -function reportRequiredFilesToWatchMode(files) { - if (process.env.WATCH_REPORT_DEPENDENCIES && process.send) { - files = files.map((filename) => npath.fromPortablePath(VirtualFS.resolveVirtual(npath.toPortablePath(filename)))); - if (WATCH_MODE_MESSAGE_USES_ARRAYS) { - process.send({ "watch:require": files }); - } else { - for (const filename of files) { - process.send({ "watch:require": filename }); - } - } - } -} - -function applyPatch(pnpapi, opts) { - const defaultCache = {}; - let enableNativeHooks = true; - process.versions.pnp = String(pnpapi.VERSIONS.std); - const moduleExports = require$$0__default.default; - moduleExports.findPnpApi = (lookupSource) => { - const lookupPath = lookupSource instanceof url.URL ? url.fileURLToPath(lookupSource) : lookupSource; - const apiPath = opts.manager.findApiPathFor(lookupPath); - if (apiPath === null) - return null; - const apiEntry = opts.manager.getApiEntry(apiPath, true); - return apiEntry.instance.findPackageLocator(lookupPath) ? apiEntry.instance : null; - }; - function getRequireStack(parent) { - const requireStack = []; - for (let cursor = parent; cursor; cursor = cursor.parent) - requireStack.push(cursor.filename || cursor.id); - return requireStack; - } - const originalModuleLoad = require$$0.Module._load; - require$$0.Module._load = function(request, parent, isMain) { - if (!enableNativeHooks) - return originalModuleLoad.call(require$$0.Module, request, parent, isMain); - if (isBuiltinModule(request)) { - try { - enableNativeHooks = false; - return originalModuleLoad.call(require$$0.Module, request, parent, isMain); - } finally { - enableNativeHooks = true; - } - } - const parentApiPath = opts.manager.getApiPathFromParent(parent); - const parentApi = parentApiPath !== null ? opts.manager.getApiEntry(parentApiPath, true).instance : null; - if (parentApi === null) - return originalModuleLoad(request, parent, isMain); - if (request === `pnpapi`) - return parentApi; - const modulePath = require$$0.Module._resolveFilename(request, parent, isMain); - const isOwnedByRuntime = parentApi !== null ? parentApi.findPackageLocator(modulePath) !== null : false; - const moduleApiPath = isOwnedByRuntime ? parentApiPath : opts.manager.findApiPathFor(npath.dirname(modulePath)); - const entry = moduleApiPath !== null ? opts.manager.getApiEntry(moduleApiPath) : { instance: null, cache: defaultCache }; - const cacheEntry = entry.cache[modulePath]; - if (cacheEntry) { - if (cacheEntry.loaded === false && cacheEntry.isLoading !== true) { - try { - cacheEntry.isLoading = true; - if (isMain) { - process.mainModule = cacheEntry; - cacheEntry.id = `.`; - } - cacheEntry.load(modulePath); - } finally { - cacheEntry.isLoading = false; - } - } - return cacheEntry.exports; - } - const module = new require$$0.Module(modulePath, parent != null ? parent : void 0); - module.pnpApiPath = moduleApiPath; - reportRequiredFilesToWatchMode([modulePath]); - entry.cache[modulePath] = module; - if (isMain) { - process.mainModule = module; - module.id = `.`; - } - let hasThrown = true; - try { - module.isLoading = true; - module.load(modulePath); - hasThrown = false; - } finally { - module.isLoading = false; - if (hasThrown) { - delete require$$0.Module._cache[modulePath]; - } - } - return module.exports; - }; - function getIssuerSpecsFromPaths(paths) { - return paths.map((path) => ({ - apiPath: opts.manager.findApiPathFor(path), - path, - module: null - })); - } - function getIssuerSpecsFromModule(module) { - var _a; - if (module && module.id !== `` && module.id !== `internal/preload` && !module.parent && !module.filename && module.paths.length > 0) { - return [{ - apiPath: opts.manager.findApiPathFor(module.paths[0]), - path: module.paths[0], - module - }]; - } - const issuer = getIssuerModule(module); - if (issuer !== null) { - const path = npath.dirname(issuer.filename); - const apiPath = opts.manager.getApiPathFromParent(issuer); - return [{ apiPath, path, module }]; - } else { - const path = process.cwd(); - const apiPath = (_a = opts.manager.findApiPathFor(npath.join(path, `[file]`))) != null ? _a : opts.manager.getApiPathFromParent(null); - return [{ apiPath, path, module }]; - } - } - function makeFakeParent(path) { - const fakeParent = new require$$0.Module(``); - const fakeFilePath = npath.join(path, `[file]`); - fakeParent.paths = require$$0.Module._nodeModulePaths(fakeFilePath); - return fakeParent; - } - const pathRegExp = /^(?![a-zA-Z]:[\\/]|\\\\|\.{0,2}(?:\/|$))((?:@[^/]+\/)?[^/]+)\/*(.*|)$/; - const originalModuleResolveFilename = require$$0.Module._resolveFilename; - require$$0.Module._resolveFilename = function(request, parent, isMain, options) { - if (isBuiltinModule(request)) - return request; - if (!enableNativeHooks) - return originalModuleResolveFilename.call(require$$0.Module, request, parent, isMain, options); - if (options && options.plugnplay === false) { - const { plugnplay, ...rest } = options; - const forwardedOptions = Object.keys(rest).length > 0 ? rest : void 0; - try { - enableNativeHooks = false; - return originalModuleResolveFilename.call(require$$0.Module, request, parent, isMain, forwardedOptions); - } finally { - enableNativeHooks = true; - } - } - if (options) { - const optionNames = new Set(Object.keys(options)); - optionNames.delete(`paths`); - optionNames.delete(`plugnplay`); - if (optionNames.size > 0) { - throw makeError( - ErrorCode.UNSUPPORTED, - `Some options passed to require() aren't supported by PnP yet (${Array.from(optionNames).join(`, `)})` - ); - } - } - const issuerSpecs = options && options.paths ? getIssuerSpecsFromPaths(options.paths) : getIssuerSpecsFromModule(parent); - if (request.match(pathRegExp) === null) { - const parentDirectory = (parent == null ? void 0 : parent.filename) != null ? npath.dirname(parent.filename) : null; - const absoluteRequest = npath.isAbsolute(request) ? request : parentDirectory !== null ? npath.resolve(parentDirectory, request) : null; - if (absoluteRequest !== null) { - const apiPath = parentDirectory === npath.dirname(absoluteRequest) && (parent == null ? void 0 : parent.pnpApiPath) ? parent.pnpApiPath : opts.manager.findApiPathFor(absoluteRequest); - if (apiPath !== null) { - issuerSpecs.unshift({ - apiPath, - path: parentDirectory, - module: null - }); - } - } - } - let firstError; - for (const { apiPath, path, module } of issuerSpecs) { - let resolution; - const issuerApi = apiPath !== null ? opts.manager.getApiEntry(apiPath, true).instance : null; - try { - if (issuerApi !== null) { - resolution = issuerApi.resolveRequest(request, path !== null ? `${path}/` : null); - } else { - if (path === null) - throw new Error(`Assertion failed: Expected the path to be set`); - resolution = originalModuleResolveFilename.call(require$$0.Module, request, module || makeFakeParent(path), isMain); - } - } catch (error) { - firstError = firstError || error; - continue; - } - if (resolution !== null) { - return resolution; - } - } - const requireStack = getRequireStack(parent); - Object.defineProperty(firstError, `requireStack`, { - configurable: true, - writable: true, - enumerable: false, - value: requireStack - }); - if (requireStack.length > 0) - firstError.message += ` -Require stack: -- ${requireStack.join(` -- `)}`; - if (typeof firstError.pnpCode === `string`) - Error.captureStackTrace(firstError); - throw firstError; - }; - const originalFindPath = require$$0.Module._findPath; - require$$0.Module._findPath = function(request, paths, isMain) { - if (request === `pnpapi`) - return false; - if (!enableNativeHooks) - return originalFindPath.call(require$$0.Module, request, paths, isMain); - const isAbsolute = npath.isAbsolute(request); - if (isAbsolute) - paths = [``]; - else if (!paths || paths.length === 0) - return false; - for (const path of paths) { - let resolution; - try { - const pnpApiPath = opts.manager.findApiPathFor(isAbsolute ? request : path); - if (pnpApiPath !== null) { - const api = opts.manager.getApiEntry(pnpApiPath, true).instance; - resolution = api.resolveRequest(request, path) || false; - } else { - resolution = originalFindPath.call(require$$0.Module, request, [path], isMain); - } - } catch (error) { - continue; - } - if (resolution) { - return resolution; - } - } - return false; - }; - const originalExtensionJSFunction = require$$0.Module._extensions[`.js`]; - require$$0.Module._extensions[`.js`] = function(module, filename) { - var _a, _b; - if (filename.endsWith(`.js`)) { - const pkg = readPackageScope(filename); - if (pkg && ((_a = pkg.data) == null ? void 0 : _a.type) === `module`) { - const err = ERR_REQUIRE_ESM(filename, (_b = module.parent) == null ? void 0 : _b.filename); - Error.captureStackTrace(err); - throw err; - } - } - originalExtensionJSFunction.call(this, module, filename); - }; - const originalDlopen = process.dlopen; - process.dlopen = function(...args) { - const [module, filename, ...rest] = args; - return originalDlopen.call( - this, - module, - npath.fromPortablePath(VirtualFS.resolveVirtual(npath.toPortablePath(filename))), - ...rest - ); - }; - const originalEmit = process.emit; - process.emit = function(name, data, ...args) { - if (name === `warning` && typeof data === `object` && data.name === `ExperimentalWarning` && (data.message.includes(`--experimental-loader`) || data.message.includes(`Custom ESM Loaders is an experimental feature`))) - return false; - return originalEmit.apply(process, arguments); - }; - patchFs(fs__default.default, new PosixFS(opts.fakeFs)); -} - -function hydrateRuntimeState(data, { basePath }) { - const portablePath = npath.toPortablePath(basePath); - const absolutePortablePath = ppath.resolve(portablePath); - const ignorePattern = data.ignorePatternData !== null ? new RegExp(data.ignorePatternData) : null; - const packageLocatorsByLocations = /* @__PURE__ */ new Map(); - const packageRegistry = new Map(data.packageRegistryData.map(([packageName, packageStoreData]) => { - return [packageName, new Map(packageStoreData.map(([packageReference, packageInformationData]) => { - var _a; - if (packageName === null !== (packageReference === null)) - throw new Error(`Assertion failed: The name and reference should be null, or neither should`); - const discardFromLookup = (_a = packageInformationData.discardFromLookup) != null ? _a : false; - const packageLocator = { name: packageName, reference: packageReference }; - const entry = packageLocatorsByLocations.get(packageInformationData.packageLocation); - if (!entry) { - packageLocatorsByLocations.set(packageInformationData.packageLocation, { locator: packageLocator, discardFromLookup }); - } else { - entry.discardFromLookup = entry.discardFromLookup && discardFromLookup; - if (!discardFromLookup) { - entry.locator = packageLocator; - } - } - let resolvedPackageLocation = null; - return [packageReference, { - packageDependencies: new Map(packageInformationData.packageDependencies), - packagePeers: new Set(packageInformationData.packagePeers), - linkType: packageInformationData.linkType, - discardFromLookup, - get packageLocation() { - return resolvedPackageLocation || (resolvedPackageLocation = ppath.join(absolutePortablePath, packageInformationData.packageLocation)); - } - }]; - }))]; - })); - const fallbackExclusionList = new Map(data.fallbackExclusionList.map(([packageName, packageReferences]) => { - return [packageName, new Set(packageReferences)]; - })); - const fallbackPool = new Map(data.fallbackPool); - const dependencyTreeRoots = data.dependencyTreeRoots; - const enableTopLevelFallback = data.enableTopLevelFallback; - return { - basePath: portablePath, - dependencyTreeRoots, - enableTopLevelFallback, - fallbackExclusionList, - fallbackPool, - ignorePattern, - packageLocatorsByLocations, - packageRegistry - }; -} - -/** - * @param {object} exports - * @param {Set} keys - */ -function loop(exports, keys) { - if (typeof exports === 'string') { - return exports; - } - - if (exports) { - let idx, tmp; - if (Array.isArray(exports)) { - for (idx=0; idx < exports.length; idx++) { - if (tmp = loop(exports[idx], keys)) return tmp; - } - } else { - for (idx in exports) { - if (keys.has(idx)) { - return loop(exports[idx], keys); - } - } - } - } -} - -/** - * @param {string} name The package name - * @param {string} entry The target entry, eg "." - * @param {number} [condition] Unmatched condition? - */ -function bail(name, entry, condition) { - throw new Error( - condition - ? `No known conditions for "${entry}" entry in "${name}" package` - : `Missing "${entry}" export in "${name}" package` - ); -} - -/** - * @param {string} name the package name - * @param {string} entry the target path/import - */ -function toName(name, entry) { - return entry === name ? '.' - : entry[0] === '.' ? entry - : entry.replace(new RegExp('^' + name + '\/'), './'); -} - -/** - * @param {object} pkg package.json contents - * @param {string} [entry] entry name or import path - * @param {object} [options] - * @param {boolean} [options.browser] - * @param {boolean} [options.require] - * @param {string[]} [options.conditions] - * @param {boolean} [options.unsafe] - */ -function resolve(pkg, entry='.', options={}) { - let { name, exports } = pkg; - - if (exports) { - let { browser, require, unsafe, conditions=[] } = options; - - let target = toName(name, entry); - if (target[0] !== '.') target = './' + target; - - if (typeof exports === 'string') { - return target === '.' ? exports : bail(name, target); - } - - let allows = new Set(['default', ...conditions]); - unsafe || allows.add(require ? 'require' : 'import'); - unsafe || allows.add(browser ? 'browser' : 'node'); - - let key, tmp, isSingle=false; - - for (key in exports) { - isSingle = key[0] !== '.'; - break; - } - - if (isSingle) { - return target === '.' - ? loop(exports, allows) || bail(name, target, 1) - : bail(name, target); - } - - if (tmp = exports[target]) { - return loop(tmp, allows) || bail(name, target, 1); - } - - for (key in exports) { - tmp = key[key.length - 1]; - if (tmp === '/' && target.startsWith(key)) { - return (tmp = loop(exports[key], allows)) - ? (tmp + target.substring(key.length)) - : bail(name, target, 1); - } - if (tmp === '*' && target.startsWith(key.slice(0, -1))) { - // do not trigger if no *content* to inject - if (target.substring(key.length - 1).length > 0) { - return (tmp = loop(exports[key], allows)) - ? tmp.replace('*', target.substring(key.length - 1)) - : bail(name, target, 1); - } - } - } - - return bail(name, target); - } -} - -const ArrayIsArray = Array.isArray; -const JSONStringify = JSON.stringify; -const ObjectGetOwnPropertyNames = Object.getOwnPropertyNames; -const ObjectPrototypeHasOwnProperty = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop); -const RegExpPrototypeExec = (obj, string) => RegExp.prototype.exec.call(obj, string); -const RegExpPrototypeSymbolReplace = (obj, ...rest) => RegExp.prototype[Symbol.replace].apply(obj, rest); -const StringPrototypeEndsWith = (str, ...rest) => String.prototype.endsWith.apply(str, rest); -const StringPrototypeIncludes = (str, ...rest) => String.prototype.includes.apply(str, rest); -const StringPrototypeLastIndexOf = (str, ...rest) => String.prototype.lastIndexOf.apply(str, rest); -const StringPrototypeIndexOf = (str, ...rest) => String.prototype.indexOf.apply(str, rest); -const StringPrototypeReplace = (str, ...rest) => String.prototype.replace.apply(str, rest); -const StringPrototypeSlice = (str, ...rest) => String.prototype.slice.apply(str, rest); -const StringPrototypeStartsWith = (str, ...rest) => String.prototype.startsWith.apply(str, rest); -const SafeMap = Map; -const JSONParse = JSON.parse; - -function createErrorType(code, messageCreator, errorType) { - return class extends errorType { - constructor(...args) { - super(messageCreator(...args)); - this.code = code; - this.name = `${errorType.name} [${code}]`; - } - }; -} -const ERR_PACKAGE_IMPORT_NOT_DEFINED = createErrorType( - `ERR_PACKAGE_IMPORT_NOT_DEFINED`, - (specifier, packagePath, base) => { - return `Package import specifier "${specifier}" is not defined${packagePath ? ` in package ${packagePath}package.json` : ``} imported from ${base}`; - }, - TypeError -); -const ERR_INVALID_MODULE_SPECIFIER = createErrorType( - `ERR_INVALID_MODULE_SPECIFIER`, - (request, reason, base = void 0) => { - return `Invalid module "${request}" ${reason}${base ? ` imported from ${base}` : ``}`; - }, - TypeError -); -const ERR_INVALID_PACKAGE_TARGET = createErrorType( - `ERR_INVALID_PACKAGE_TARGET`, - (pkgPath, key, target, isImport = false, base = void 0) => { - const relError = typeof target === `string` && !isImport && target.length && !StringPrototypeStartsWith(target, `./`); - if (key === `.`) { - assert__default.default(isImport === false); - return `Invalid "exports" main target ${JSONStringify(target)} defined in the package config ${pkgPath}package.json${base ? ` imported from ${base}` : ``}${relError ? `; targets must start with "./"` : ``}`; - } - return `Invalid "${isImport ? `imports` : `exports`}" target ${JSONStringify( - target - )} defined for '${key}' in the package config ${pkgPath}package.json${base ? ` imported from ${base}` : ``}${relError ? `; targets must start with "./"` : ``}`; - }, - Error -); -const ERR_INVALID_PACKAGE_CONFIG = createErrorType( - `ERR_INVALID_PACKAGE_CONFIG`, - (path, base, message) => { - return `Invalid package config ${path}${base ? ` while importing ${base}` : ``}${message ? `. ${message}` : ``}`; - }, - Error -); - -function filterOwnProperties(source, keys) { - const filtered = /* @__PURE__ */ Object.create(null); - for (let i = 0; i < keys.length; i++) { - const key = keys[i]; - if (ObjectPrototypeHasOwnProperty(source, key)) { - filtered[key] = source[key]; - } - } - return filtered; -} - -const packageJSONCache = new SafeMap(); -function getPackageConfig(path, specifier, base, readFileSyncFn) { - const existing = packageJSONCache.get(path); - if (existing !== void 0) { - return existing; - } - const source = readFileSyncFn(path); - if (source === void 0) { - const packageConfig2 = { - pjsonPath: path, - exists: false, - main: void 0, - name: void 0, - type: "none", - exports: void 0, - imports: void 0 - }; - packageJSONCache.set(path, packageConfig2); - return packageConfig2; - } - let packageJSON; - try { - packageJSON = JSONParse(source); - } catch (error) { - throw new ERR_INVALID_PACKAGE_CONFIG( - path, - (base ? `"${specifier}" from ` : "") + url.fileURLToPath(base || specifier), - error.message - ); - } - let { imports, main, name, type } = filterOwnProperties(packageJSON, [ - "imports", - "main", - "name", - "type" - ]); - const exports = ObjectPrototypeHasOwnProperty(packageJSON, "exports") ? packageJSON.exports : void 0; - if (typeof imports !== "object" || imports === null) { - imports = void 0; - } - if (typeof main !== "string") { - main = void 0; - } - if (typeof name !== "string") { - name = void 0; - } - if (type !== "module" && type !== "commonjs") { - type = "none"; - } - const packageConfig = { - pjsonPath: path, - exists: true, - main, - name, - type, - exports, - imports - }; - packageJSONCache.set(path, packageConfig); - return packageConfig; -} -function getPackageScopeConfig(resolved, readFileSyncFn) { - let packageJSONUrl = new URL("./package.json", resolved); - while (true) { - const packageJSONPath2 = packageJSONUrl.pathname; - if (StringPrototypeEndsWith(packageJSONPath2, "node_modules/package.json")) { - break; - } - const packageConfig2 = getPackageConfig( - url.fileURLToPath(packageJSONUrl), - resolved, - void 0, - readFileSyncFn - ); - if (packageConfig2.exists) { - return packageConfig2; - } - const lastPackageJSONUrl = packageJSONUrl; - packageJSONUrl = new URL("../package.json", packageJSONUrl); - if (packageJSONUrl.pathname === lastPackageJSONUrl.pathname) { - break; - } - } - const packageJSONPath = url.fileURLToPath(packageJSONUrl); - const packageConfig = { - pjsonPath: packageJSONPath, - exists: false, - main: void 0, - name: void 0, - type: "none", - exports: void 0, - imports: void 0 - }; - packageJSONCache.set(packageJSONPath, packageConfig); - return packageConfig; -} - -/** - @license - Copyright Node.js contributors. All rights reserved. - - 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. -*/ -function throwImportNotDefined(specifier, packageJSONUrl, base) { - throw new ERR_PACKAGE_IMPORT_NOT_DEFINED( - specifier, - packageJSONUrl && url.fileURLToPath(new URL(".", packageJSONUrl)), - url.fileURLToPath(base) - ); -} -function throwInvalidSubpath(subpath, packageJSONUrl, internal, base) { - const reason = `request is not a valid subpath for the "${internal ? "imports" : "exports"}" resolution of ${url.fileURLToPath(packageJSONUrl)}`; - throw new ERR_INVALID_MODULE_SPECIFIER( - subpath, - reason, - base && url.fileURLToPath(base) - ); -} -function throwInvalidPackageTarget(subpath, target, packageJSONUrl, internal, base) { - if (typeof target === "object" && target !== null) { - target = JSONStringify(target, null, ""); - } else { - target = `${target}`; - } - throw new ERR_INVALID_PACKAGE_TARGET( - url.fileURLToPath(new URL(".", packageJSONUrl)), - subpath, - target, - internal, - base && url.fileURLToPath(base) - ); -} -const invalidSegmentRegEx = /(^|\\|\/)((\.|%2e)(\.|%2e)?|(n|%6e|%4e)(o|%6f|%4f)(d|%64|%44)(e|%65|%45)(_|%5f)(m|%6d|%4d)(o|%6f|%4f)(d|%64|%44)(u|%75|%55)(l|%6c|%4c)(e|%65|%45)(s|%73|%53))(\\|\/|$)/i; -const patternRegEx = /\*/g; -function resolvePackageTargetString(target, subpath, match, packageJSONUrl, base, pattern, internal, conditions) { - if (subpath !== "" && !pattern && target[target.length - 1] !== "/") - throwInvalidPackageTarget(match, target, packageJSONUrl, internal, base); - if (!StringPrototypeStartsWith(target, "./")) { - if (internal && !StringPrototypeStartsWith(target, "../") && !StringPrototypeStartsWith(target, "/")) { - let isURL = false; - try { - new URL(target); - isURL = true; - } catch { - } - if (!isURL) { - const exportTarget = pattern ? RegExpPrototypeSymbolReplace(patternRegEx, target, () => subpath) : target + subpath; - return exportTarget; - } - } - throwInvalidPackageTarget(match, target, packageJSONUrl, internal, base); - } - if (RegExpPrototypeExec( - invalidSegmentRegEx, - StringPrototypeSlice(target, 2) - ) !== null) - throwInvalidPackageTarget(match, target, packageJSONUrl, internal, base); - const resolved = new URL(target, packageJSONUrl); - const resolvedPath = resolved.pathname; - const packagePath = new URL(".", packageJSONUrl).pathname; - if (!StringPrototypeStartsWith(resolvedPath, packagePath)) - throwInvalidPackageTarget(match, target, packageJSONUrl, internal, base); - if (subpath === "") - return resolved; - if (RegExpPrototypeExec(invalidSegmentRegEx, subpath) !== null) { - const request = pattern ? StringPrototypeReplace(match, "*", () => subpath) : match + subpath; - throwInvalidSubpath(request, packageJSONUrl, internal, base); - } - if (pattern) { - return new URL( - RegExpPrototypeSymbolReplace(patternRegEx, resolved.href, () => subpath) - ); - } - return new URL(subpath, resolved); -} -function isArrayIndex(key) { - const keyNum = +key; - if (`${keyNum}` !== key) - return false; - return keyNum >= 0 && keyNum < 4294967295; -} -function resolvePackageTarget(packageJSONUrl, target, subpath, packageSubpath, base, pattern, internal, conditions) { - if (typeof target === "string") { - return resolvePackageTargetString( - target, - subpath, - packageSubpath, - packageJSONUrl, - base, - pattern, - internal); - } else if (ArrayIsArray(target)) { - if (target.length === 0) { - return null; - } - let lastException; - for (let i = 0; i < target.length; i++) { - const targetItem = target[i]; - let resolveResult; - try { - resolveResult = resolvePackageTarget( - packageJSONUrl, - targetItem, - subpath, - packageSubpath, - base, - pattern, - internal, - conditions - ); - } catch (e) { - lastException = e; - if (e.code === "ERR_INVALID_PACKAGE_TARGET") { - continue; - } - throw e; - } - if (resolveResult === void 0) { - continue; - } - if (resolveResult === null) { - lastException = null; - continue; - } - return resolveResult; - } - if (lastException === void 0 || lastException === null) - return lastException; - throw lastException; - } else if (typeof target === "object" && target !== null) { - const keys = ObjectGetOwnPropertyNames(target); - for (let i = 0; i < keys.length; i++) { - const key = keys[i]; - if (isArrayIndex(key)) { - throw new ERR_INVALID_PACKAGE_CONFIG( - url.fileURLToPath(packageJSONUrl), - base, - '"exports" cannot contain numeric property keys.' - ); - } - } - for (let i = 0; i < keys.length; i++) { - const key = keys[i]; - if (key === "default" || conditions.has(key)) { - const conditionalTarget = target[key]; - const resolveResult = resolvePackageTarget( - packageJSONUrl, - conditionalTarget, - subpath, - packageSubpath, - base, - pattern, - internal, - conditions - ); - if (resolveResult === void 0) - continue; - return resolveResult; - } - } - return void 0; - } else if (target === null) { - return null; - } - throwInvalidPackageTarget( - packageSubpath, - target, - packageJSONUrl, - internal, - base - ); -} -function patternKeyCompare(a, b) { - const aPatternIndex = StringPrototypeIndexOf(a, "*"); - const bPatternIndex = StringPrototypeIndexOf(b, "*"); - const baseLenA = aPatternIndex === -1 ? a.length : aPatternIndex + 1; - const baseLenB = bPatternIndex === -1 ? b.length : bPatternIndex + 1; - if (baseLenA > baseLenB) - return -1; - if (baseLenB > baseLenA) - return 1; - if (aPatternIndex === -1) - return 1; - if (bPatternIndex === -1) - return -1; - if (a.length > b.length) - return -1; - if (b.length > a.length) - return 1; - return 0; -} -function packageImportsResolve({ - name, - base, - conditions, - readFileSyncFn -}) { - if (name === "#" || StringPrototypeStartsWith(name, "#/") || StringPrototypeEndsWith(name, "/")) { - const reason = "is not a valid internal imports specifier name"; - throw new ERR_INVALID_MODULE_SPECIFIER(name, reason, url.fileURLToPath(base)); - } - let packageJSONUrl; - const packageConfig = getPackageScopeConfig(base, readFileSyncFn); - if (packageConfig.exists) { - packageJSONUrl = url.pathToFileURL(packageConfig.pjsonPath); - const imports = packageConfig.imports; - if (imports) { - if (ObjectPrototypeHasOwnProperty(imports, name) && !StringPrototypeIncludes(name, "*")) { - const resolveResult = resolvePackageTarget( - packageJSONUrl, - imports[name], - "", - name, - base, - false, - true, - conditions - ); - if (resolveResult != null) { - return resolveResult; - } - } else { - let bestMatch = ""; - let bestMatchSubpath; - const keys = ObjectGetOwnPropertyNames(imports); - for (let i = 0; i < keys.length; i++) { - const key = keys[i]; - const patternIndex = StringPrototypeIndexOf(key, "*"); - if (patternIndex !== -1 && StringPrototypeStartsWith( - name, - StringPrototypeSlice(key, 0, patternIndex) - )) { - const patternTrailer = StringPrototypeSlice(key, patternIndex + 1); - if (name.length >= key.length && StringPrototypeEndsWith(name, patternTrailer) && patternKeyCompare(bestMatch, key) === 1 && StringPrototypeLastIndexOf(key, "*") === patternIndex) { - bestMatch = key; - bestMatchSubpath = StringPrototypeSlice( - name, - patternIndex, - name.length - patternTrailer.length - ); - } - } - } - if (bestMatch) { - const target = imports[bestMatch]; - const resolveResult = resolvePackageTarget( - packageJSONUrl, - target, - bestMatchSubpath, - bestMatch, - base, - true, - true, - conditions - ); - if (resolveResult != null) { - return resolveResult; - } - } - } - } - } - throwImportNotDefined(name, packageJSONUrl, base); -} - -function makeApi(runtimeState, opts) { - const alwaysWarnOnFallback = Number(process.env.PNP_ALWAYS_WARN_ON_FALLBACK) > 0; - const debugLevel = Number(process.env.PNP_DEBUG_LEVEL); - const pathRegExp = /^(?![a-zA-Z]:[\\/]|\\\\|\.{0,2}(?:\/|$))((?:node:)?(?:@[^/]+\/)?[^/]+)\/*(.*|)$/; - const isStrictRegExp = /^(\/|\.{1,2}(\/|$))/; - const isDirRegExp = /\/$/; - const isRelativeRegexp = /^\.{0,2}\//; - const topLevelLocator = { name: null, reference: null }; - const fallbackLocators = []; - const emittedWarnings = /* @__PURE__ */ new Set(); - if (runtimeState.enableTopLevelFallback === true) - fallbackLocators.push(topLevelLocator); - if (opts.compatibilityMode !== false) { - for (const name of [`react-scripts`, `gatsby`]) { - const packageStore = runtimeState.packageRegistry.get(name); - if (packageStore) { - for (const reference of packageStore.keys()) { - if (reference === null) { - throw new Error(`Assertion failed: This reference shouldn't be null`); - } else { - fallbackLocators.push({ name, reference }); - } - } - } - } - } - const { - ignorePattern, - packageRegistry, - packageLocatorsByLocations - } = runtimeState; - function makeLogEntry(name, args) { - return { - fn: name, - args, - error: null, - result: null - }; - } - function trace(entry) { - var _a, _b, _c, _d, _e, _f; - const colors = (_c = (_b = (_a = process.stderr) == null ? void 0 : _a.hasColors) == null ? void 0 : _b.call(_a)) != null ? _c : process.stdout.isTTY; - const c = (n, str) => `\x1B[${n}m${str}\x1B[0m`; - const error = entry.error; - if (error) - console.error(c(`31;1`, `\u2716 ${(_d = entry.error) == null ? void 0 : _d.message.replace(/\n.*/s, ``)}`)); - else - console.error(c(`33;1`, `\u203C Resolution`)); - if (entry.args.length > 0) - console.error(); - for (const arg of entry.args) - console.error(` ${c(`37;1`, `In \u2190`)} ${nodeUtils.inspect(arg, { colors, compact: true })}`); - if (entry.result) { - console.error(); - console.error(` ${c(`37;1`, `Out \u2192`)} ${nodeUtils.inspect(entry.result, { colors, compact: true })}`); - } - const stack = (_f = (_e = new Error().stack.match(/(?<=^ +)at.*/gm)) == null ? void 0 : _e.slice(2)) != null ? _f : []; - if (stack.length > 0) { - console.error(); - for (const line of stack) { - console.error(` ${c(`38;5;244`, line)}`); - } - } - console.error(); - } - function maybeLog(name, fn) { - if (opts.allowDebug === false) - return fn; - if (Number.isFinite(debugLevel)) { - if (debugLevel >= 2) { - return (...args) => { - const logEntry = makeLogEntry(name, args); - try { - return logEntry.result = fn(...args); - } catch (error) { - throw logEntry.error = error; - } finally { - trace(logEntry); - } - }; - } else if (debugLevel >= 1) { - return (...args) => { - try { - return fn(...args); - } catch (error) { - const logEntry = makeLogEntry(name, args); - logEntry.error = error; - trace(logEntry); - throw error; - } - }; - } - } - return fn; - } - function getPackageInformationSafe(packageLocator) { - const packageInformation = getPackageInformation(packageLocator); - if (!packageInformation) { - throw makeError( - ErrorCode.INTERNAL, - `Couldn't find a matching entry in the dependency tree for the specified parent (this is probably an internal error)` - ); - } - return packageInformation; - } - function isDependencyTreeRoot(packageLocator) { - if (packageLocator.name === null) - return true; - for (const dependencyTreeRoot of runtimeState.dependencyTreeRoots) - if (dependencyTreeRoot.name === packageLocator.name && dependencyTreeRoot.reference === packageLocator.reference) - return true; - return false; - } - const defaultExportsConditions = /* @__PURE__ */ new Set([`default`, `node`, `require`]); - function applyNodeExportsResolution(unqualifiedPath, conditions = defaultExportsConditions) { - const locator = findPackageLocator(ppath.join(unqualifiedPath, `internal.js`), { - resolveIgnored: true, - includeDiscardFromLookup: true - }); - if (locator === null) { - throw makeError( - ErrorCode.INTERNAL, - `The locator that owns the "${unqualifiedPath}" path can't be found inside the dependency tree (this is probably an internal error)` - ); - } - const { packageLocation } = getPackageInformationSafe(locator); - const manifestPath = ppath.join(packageLocation, Filename.manifest); - if (!opts.fakeFs.existsSync(manifestPath)) - return null; - const pkgJson = JSON.parse(opts.fakeFs.readFileSync(manifestPath, `utf8`)); - let subpath = ppath.contains(packageLocation, unqualifiedPath); - if (subpath === null) { - throw makeError( - ErrorCode.INTERNAL, - `unqualifiedPath doesn't contain the packageLocation (this is probably an internal error)` - ); - } - if (!isRelativeRegexp.test(subpath)) - subpath = `./${subpath}`; - let resolvedExport; - try { - resolvedExport = resolve(pkgJson, ppath.normalize(subpath), { - conditions, - unsafe: true - }); - } catch (error) { - throw makeError( - ErrorCode.EXPORTS_RESOLUTION_FAILED, - error.message, - { unqualifiedPath: getPathForDisplay(unqualifiedPath), locator, pkgJson, subpath: getPathForDisplay(subpath), conditions }, - `ERR_PACKAGE_PATH_NOT_EXPORTED` - ); - } - if (typeof resolvedExport === `string`) - return ppath.join(packageLocation, resolvedExport); - return null; - } - function applyNodeExtensionResolution(unqualifiedPath, candidates, { extensions }) { - let stat; - try { - candidates.push(unqualifiedPath); - stat = opts.fakeFs.statSync(unqualifiedPath); - } catch (error) { - } - if (stat && !stat.isDirectory()) - return opts.fakeFs.realpathSync(unqualifiedPath); - if (stat && stat.isDirectory()) { - let pkgJson; - try { - pkgJson = JSON.parse(opts.fakeFs.readFileSync(ppath.join(unqualifiedPath, Filename.manifest), `utf8`)); - } catch (error) { - } - let nextUnqualifiedPath; - if (pkgJson && pkgJson.main) - nextUnqualifiedPath = ppath.resolve(unqualifiedPath, pkgJson.main); - if (nextUnqualifiedPath && nextUnqualifiedPath !== unqualifiedPath) { - const resolution = applyNodeExtensionResolution(nextUnqualifiedPath, candidates, { extensions }); - if (resolution !== null) { - return resolution; - } - } - } - for (let i = 0, length = extensions.length; i < length; i++) { - const candidateFile = `${unqualifiedPath}${extensions[i]}`; - candidates.push(candidateFile); - if (opts.fakeFs.existsSync(candidateFile)) { - return candidateFile; - } - } - if (stat && stat.isDirectory()) { - for (let i = 0, length = extensions.length; i < length; i++) { - const candidateFile = ppath.format({ dir: unqualifiedPath, name: `index`, ext: extensions[i] }); - candidates.push(candidateFile); - if (opts.fakeFs.existsSync(candidateFile)) { - return candidateFile; - } - } - } - return null; - } - function makeFakeModule(path) { - const fakeModule = new require$$0.Module(path, null); - fakeModule.filename = path; - fakeModule.paths = require$$0.Module._nodeModulePaths(path); - return fakeModule; - } - function callNativeResolution(request, issuer) { - if (issuer.endsWith(`/`)) - issuer = ppath.join(issuer, `internal.js`); - return require$$0.Module._resolveFilename(npath.fromPortablePath(request), makeFakeModule(npath.fromPortablePath(issuer)), false, { plugnplay: false }); - } - function isPathIgnored(path) { - if (ignorePattern === null) - return false; - const subPath = ppath.contains(runtimeState.basePath, path); - if (subPath === null) - return false; - if (ignorePattern.test(subPath.replace(/\/$/, ``))) { - return true; - } else { - return false; - } - } - const VERSIONS = { std: 3, resolveVirtual: 1, getAllLocators: 1 }; - const topLevel = topLevelLocator; - function getPackageInformation({ name, reference }) { - const packageInformationStore = packageRegistry.get(name); - if (!packageInformationStore) - return null; - const packageInformation = packageInformationStore.get(reference); - if (!packageInformation) - return null; - return packageInformation; - } - function findPackageDependents({ name, reference }) { - const dependents = []; - for (const [dependentName, packageInformationStore] of packageRegistry) { - if (dependentName === null) - continue; - for (const [dependentReference, packageInformation] of packageInformationStore) { - if (dependentReference === null) - continue; - const dependencyReference = packageInformation.packageDependencies.get(name); - if (dependencyReference !== reference) - continue; - if (dependentName === name && dependentReference === reference) - continue; - dependents.push({ - name: dependentName, - reference: dependentReference - }); - } - } - return dependents; - } - function findBrokenPeerDependencies(dependency, initialPackage) { - const brokenPackages = /* @__PURE__ */ new Map(); - const alreadyVisited = /* @__PURE__ */ new Set(); - const traversal = (currentPackage) => { - const identifier = JSON.stringify(currentPackage.name); - if (alreadyVisited.has(identifier)) - return; - alreadyVisited.add(identifier); - const dependents = findPackageDependents(currentPackage); - for (const dependent of dependents) { - const dependentInformation = getPackageInformationSafe(dependent); - if (dependentInformation.packagePeers.has(dependency)) { - traversal(dependent); - } else { - let brokenSet = brokenPackages.get(dependent.name); - if (typeof brokenSet === `undefined`) - brokenPackages.set(dependent.name, brokenSet = /* @__PURE__ */ new Set()); - brokenSet.add(dependent.reference); - } - } - }; - traversal(initialPackage); - const brokenList = []; - for (const name of [...brokenPackages.keys()].sort()) - for (const reference of [...brokenPackages.get(name)].sort()) - brokenList.push({ name, reference }); - return brokenList; - } - function findPackageLocator(location, { resolveIgnored = false, includeDiscardFromLookup = false } = {}) { - if (isPathIgnored(location) && !resolveIgnored) - return null; - let relativeLocation = ppath.relative(runtimeState.basePath, location); - if (!relativeLocation.match(isStrictRegExp)) - relativeLocation = `./${relativeLocation}`; - if (!relativeLocation.endsWith(`/`)) - relativeLocation = `${relativeLocation}/`; - do { - const entry = packageLocatorsByLocations.get(relativeLocation); - if (typeof entry === `undefined` || entry.discardFromLookup && !includeDiscardFromLookup) { - relativeLocation = relativeLocation.substring(0, relativeLocation.lastIndexOf(`/`, relativeLocation.length - 2) + 1); - continue; - } - return entry.locator; - } while (relativeLocation !== ``); - return null; - } - function tryReadFile(filePath) { - try { - return opts.fakeFs.readFileSync(npath.toPortablePath(filePath), `utf8`); - } catch (err) { - if (err.code === `ENOENT`) - return void 0; - throw err; - } - } - function resolveToUnqualified(request, issuer, { considerBuiltins = true } = {}) { - if (request.startsWith(`#`)) - throw new Error(`resolveToUnqualified can not handle private import mappings`); - if (request === `pnpapi`) - return npath.toPortablePath(opts.pnpapiResolution); - if (considerBuiltins && isBuiltinModule(request)) - return null; - const requestForDisplay = getPathForDisplay(request); - const issuerForDisplay = issuer && getPathForDisplay(issuer); - if (issuer && isPathIgnored(issuer)) { - if (!ppath.isAbsolute(request) || findPackageLocator(request) === null) { - const result = callNativeResolution(request, issuer); - if (result === false) { - throw makeError( - ErrorCode.BUILTIN_NODE_RESOLUTION_FAILED, - `The builtin node resolution algorithm was unable to resolve the requested module (it didn't go through the pnp resolver because the issuer was explicitely ignored by the regexp) - -Require request: "${requestForDisplay}" -Required by: ${issuerForDisplay} -`, - { request: requestForDisplay, issuer: issuerForDisplay } - ); - } - return npath.toPortablePath(result); - } - } - let unqualifiedPath; - const dependencyNameMatch = request.match(pathRegExp); - if (!dependencyNameMatch) { - if (ppath.isAbsolute(request)) { - unqualifiedPath = ppath.normalize(request); - } else { - if (!issuer) { - throw makeError( - ErrorCode.API_ERROR, - `The resolveToUnqualified function must be called with a valid issuer when the path isn't a builtin nor absolute`, - { request: requestForDisplay, issuer: issuerForDisplay } - ); - } - const absoluteIssuer = ppath.resolve(issuer); - if (issuer.match(isDirRegExp)) { - unqualifiedPath = ppath.normalize(ppath.join(absoluteIssuer, request)); - } else { - unqualifiedPath = ppath.normalize(ppath.join(ppath.dirname(absoluteIssuer), request)); - } - } - } else { - if (!issuer) { - throw makeError( - ErrorCode.API_ERROR, - `The resolveToUnqualified function must be called with a valid issuer when the path isn't a builtin nor absolute`, - { request: requestForDisplay, issuer: issuerForDisplay } - ); - } - const [, dependencyName, subPath] = dependencyNameMatch; - const issuerLocator = findPackageLocator(issuer); - if (!issuerLocator) { - const result = callNativeResolution(request, issuer); - if (result === false) { - throw makeError( - ErrorCode.BUILTIN_NODE_RESOLUTION_FAILED, - `The builtin node resolution algorithm was unable to resolve the requested module (it didn't go through the pnp resolver because the issuer doesn't seem to be part of the Yarn-managed dependency tree). - -Require path: "${requestForDisplay}" -Required by: ${issuerForDisplay} -`, - { request: requestForDisplay, issuer: issuerForDisplay } - ); - } - return npath.toPortablePath(result); - } - const issuerInformation = getPackageInformationSafe(issuerLocator); - let dependencyReference = issuerInformation.packageDependencies.get(dependencyName); - let fallbackReference = null; - if (dependencyReference == null) { - if (issuerLocator.name !== null) { - const exclusionEntry = runtimeState.fallbackExclusionList.get(issuerLocator.name); - const canUseFallbacks = !exclusionEntry || !exclusionEntry.has(issuerLocator.reference); - if (canUseFallbacks) { - for (let t = 0, T = fallbackLocators.length; t < T; ++t) { - const fallbackInformation = getPackageInformationSafe(fallbackLocators[t]); - const reference = fallbackInformation.packageDependencies.get(dependencyName); - if (reference == null) - continue; - if (alwaysWarnOnFallback) - fallbackReference = reference; - else - dependencyReference = reference; - break; - } - if (runtimeState.enableTopLevelFallback) { - if (dependencyReference == null && fallbackReference === null) { - const reference = runtimeState.fallbackPool.get(dependencyName); - if (reference != null) { - fallbackReference = reference; - } - } - } - } - } - } - let error = null; - if (dependencyReference === null) { - if (isDependencyTreeRoot(issuerLocator)) { - error = makeError( - ErrorCode.MISSING_PEER_DEPENDENCY, - `Your application tried to access ${dependencyName} (a peer dependency); this isn't allowed as there is no ancestor to satisfy the requirement. Use a devDependency if needed. - -Required package: ${dependencyName}${dependencyName !== requestForDisplay ? ` (via "${requestForDisplay}")` : ``} -Required by: ${issuerForDisplay} -`, - { request: requestForDisplay, issuer: issuerForDisplay, dependencyName } - ); - } else { - const brokenAncestors = findBrokenPeerDependencies(dependencyName, issuerLocator); - if (brokenAncestors.every((ancestor) => isDependencyTreeRoot(ancestor))) { - error = makeError( - ErrorCode.MISSING_PEER_DEPENDENCY, - `${issuerLocator.name} tried to access ${dependencyName} (a peer dependency) but it isn't provided by your application; this makes the require call ambiguous and unsound. - -Required package: ${dependencyName}${dependencyName !== requestForDisplay ? ` (via "${requestForDisplay}")` : ``} -Required by: ${issuerLocator.name}@${issuerLocator.reference} (via ${issuerForDisplay}) -${brokenAncestors.map((ancestorLocator) => `Ancestor breaking the chain: ${ancestorLocator.name}@${ancestorLocator.reference} -`).join(``)} -`, - { request: requestForDisplay, issuer: issuerForDisplay, issuerLocator: Object.assign({}, issuerLocator), dependencyName, brokenAncestors } - ); - } else { - error = makeError( - ErrorCode.MISSING_PEER_DEPENDENCY, - `${issuerLocator.name} tried to access ${dependencyName} (a peer dependency) but it isn't provided by its ancestors; this makes the require call ambiguous and unsound. - -Required package: ${dependencyName}${dependencyName !== requestForDisplay ? ` (via "${requestForDisplay}")` : ``} -Required by: ${issuerLocator.name}@${issuerLocator.reference} (via ${issuerForDisplay}) - -${brokenAncestors.map((ancestorLocator) => `Ancestor breaking the chain: ${ancestorLocator.name}@${ancestorLocator.reference} -`).join(``)} -`, - { request: requestForDisplay, issuer: issuerForDisplay, issuerLocator: Object.assign({}, issuerLocator), dependencyName, brokenAncestors } - ); - } - } - } else if (dependencyReference === void 0) { - if (!considerBuiltins && isBuiltinModule(request)) { - if (isDependencyTreeRoot(issuerLocator)) { - error = makeError( - ErrorCode.UNDECLARED_DEPENDENCY, - `Your application tried to access ${dependencyName}. While this module is usually interpreted as a Node builtin, your resolver is running inside a non-Node resolution context where such builtins are ignored. Since ${dependencyName} isn't otherwise declared in your dependencies, this makes the require call ambiguous and unsound. - -Required package: ${dependencyName}${dependencyName !== requestForDisplay ? ` (via "${requestForDisplay}")` : ``} -Required by: ${issuerForDisplay} -`, - { request: requestForDisplay, issuer: issuerForDisplay, dependencyName } - ); - } else { - error = makeError( - ErrorCode.UNDECLARED_DEPENDENCY, - `${issuerLocator.name} tried to access ${dependencyName}. While this module is usually interpreted as a Node builtin, your resolver is running inside a non-Node resolution context where such builtins are ignored. Since ${dependencyName} isn't otherwise declared in ${issuerLocator.name}'s dependencies, this makes the require call ambiguous and unsound. - -Required package: ${dependencyName}${dependencyName !== requestForDisplay ? ` (via "${requestForDisplay}")` : ``} -Required by: ${issuerForDisplay} -`, - { request: requestForDisplay, issuer: issuerForDisplay, issuerLocator: Object.assign({}, issuerLocator), dependencyName } - ); - } - } else { - if (isDependencyTreeRoot(issuerLocator)) { - error = makeError( - ErrorCode.UNDECLARED_DEPENDENCY, - `Your application tried to access ${dependencyName}, but it isn't declared in your dependencies; this makes the require call ambiguous and unsound. - -Required package: ${dependencyName}${dependencyName !== requestForDisplay ? ` (via "${requestForDisplay}")` : ``} -Required by: ${issuerForDisplay} -`, - { request: requestForDisplay, issuer: issuerForDisplay, dependencyName } - ); - } else { - error = makeError( - ErrorCode.UNDECLARED_DEPENDENCY, - `${issuerLocator.name} tried to access ${dependencyName}, but it isn't declared in its dependencies; this makes the require call ambiguous and unsound. - -Required package: ${dependencyName}${dependencyName !== requestForDisplay ? ` (via "${requestForDisplay}")` : ``} -Required by: ${issuerLocator.name}@${issuerLocator.reference} (via ${issuerForDisplay}) -`, - { request: requestForDisplay, issuer: issuerForDisplay, issuerLocator: Object.assign({}, issuerLocator), dependencyName } - ); - } - } - } - if (dependencyReference == null) { - if (fallbackReference === null || error === null) - throw error || new Error(`Assertion failed: Expected an error to have been set`); - dependencyReference = fallbackReference; - const message = error.message.replace(/\n.*/g, ``); - error.message = message; - if (!emittedWarnings.has(message) && debugLevel !== 0) { - emittedWarnings.add(message); - process.emitWarning(error); - } - } - const dependencyLocator = Array.isArray(dependencyReference) ? { name: dependencyReference[0], reference: dependencyReference[1] } : { name: dependencyName, reference: dependencyReference }; - const dependencyInformation = getPackageInformationSafe(dependencyLocator); - if (!dependencyInformation.packageLocation) { - throw makeError( - ErrorCode.MISSING_DEPENDENCY, - `A dependency seems valid but didn't get installed for some reason. This might be caused by a partial install, such as dev vs prod. - -Required package: ${dependencyLocator.name}@${dependencyLocator.reference}${dependencyLocator.name !== requestForDisplay ? ` (via "${requestForDisplay}")` : ``} -Required by: ${issuerLocator.name}@${issuerLocator.reference} (via ${issuerForDisplay}) -`, - { request: requestForDisplay, issuer: issuerForDisplay, dependencyLocator: Object.assign({}, dependencyLocator) } - ); - } - const dependencyLocation = dependencyInformation.packageLocation; - if (subPath) { - unqualifiedPath = ppath.join(dependencyLocation, subPath); - } else { - unqualifiedPath = dependencyLocation; - } - } - return ppath.normalize(unqualifiedPath); - } - function resolveUnqualifiedExport(request, unqualifiedPath, conditions = defaultExportsConditions) { - if (isStrictRegExp.test(request)) - return unqualifiedPath; - const unqualifiedExportPath = applyNodeExportsResolution(unqualifiedPath, conditions); - if (unqualifiedExportPath) { - return ppath.normalize(unqualifiedExportPath); - } else { - return unqualifiedPath; - } - } - function resolveUnqualified(unqualifiedPath, { extensions = Object.keys(require$$0.Module._extensions) } = {}) { - var _a, _b; - const candidates = []; - const qualifiedPath = applyNodeExtensionResolution(unqualifiedPath, candidates, { extensions }); - if (qualifiedPath) { - return ppath.normalize(qualifiedPath); - } else { - reportRequiredFilesToWatchMode(candidates.map((candidate) => npath.fromPortablePath(candidate))); - const unqualifiedPathForDisplay = getPathForDisplay(unqualifiedPath); - const containingPackage = findPackageLocator(unqualifiedPath); - if (containingPackage) { - const { packageLocation } = getPackageInformationSafe(containingPackage); - let exists = true; - try { - opts.fakeFs.accessSync(packageLocation); - } catch (err) { - if ((err == null ? void 0 : err.code) === `ENOENT`) { - exists = false; - } else { - const readableError = ((_b = (_a = err == null ? void 0 : err.message) != null ? _a : err) != null ? _b : `empty exception thrown`).replace(/^[A-Z]/, ($0) => $0.toLowerCase()); - throw makeError(ErrorCode.QUALIFIED_PATH_RESOLUTION_FAILED, `Required package exists but could not be accessed (${readableError}). - -Missing package: ${containingPackage.name}@${containingPackage.reference} -Expected package location: ${getPathForDisplay(packageLocation)} -`, { unqualifiedPath: unqualifiedPathForDisplay, extensions }); - } - } - if (!exists) { - const errorMessage = packageLocation.includes(`/unplugged/`) ? `Required unplugged package missing from disk. This may happen when switching branches without running installs (unplugged packages must be fully materialized on disk to work).` : `Required package missing from disk. If you keep your packages inside your repository then restarting the Node process may be enough. Otherwise, try to run an install first.`; - throw makeError( - ErrorCode.QUALIFIED_PATH_RESOLUTION_FAILED, - `${errorMessage} - -Missing package: ${containingPackage.name}@${containingPackage.reference} -Expected package location: ${getPathForDisplay(packageLocation)} -`, - { unqualifiedPath: unqualifiedPathForDisplay, extensions } - ); - } - } - throw makeError( - ErrorCode.QUALIFIED_PATH_RESOLUTION_FAILED, - `Qualified path resolution failed: we looked for the following paths, but none could be accessed. - -Source path: ${unqualifiedPathForDisplay} -${candidates.map((candidate) => `Not found: ${getPathForDisplay(candidate)} -`).join(``)}`, - { unqualifiedPath: unqualifiedPathForDisplay, extensions } - ); - } - } - function resolvePrivateRequest(request, issuer, opts2) { - var _a; - if (!issuer) - throw new Error(`Assertion failed: An issuer is required to resolve private import mappings`); - const resolved = packageImportsResolve({ - name: request, - base: url.pathToFileURL(npath.fromPortablePath(issuer)), - conditions: (_a = opts2.conditions) != null ? _a : defaultExportsConditions, - readFileSyncFn: tryReadFile - }); - if (resolved instanceof URL) { - return resolveUnqualified(npath.toPortablePath(url.fileURLToPath(resolved)), { extensions: opts2.extensions }); - } else { - if (resolved.startsWith(`#`)) - throw new Error(`Mapping from one private import to another isn't allowed`); - return resolveRequest(resolved, issuer, opts2); - } - } - function resolveRequest(request, issuer, opts2 = {}) { - try { - if (request.startsWith(`#`)) - return resolvePrivateRequest(request, issuer, opts2); - const { considerBuiltins, extensions, conditions } = opts2; - const unqualifiedPath = resolveToUnqualified(request, issuer, { considerBuiltins }); - if (request === `pnpapi`) - return unqualifiedPath; - if (unqualifiedPath === null) - return null; - const isIssuerIgnored = () => issuer !== null ? isPathIgnored(issuer) : false; - const remappedPath = (!considerBuiltins || !isBuiltinModule(request)) && !isIssuerIgnored() ? resolveUnqualifiedExport(request, unqualifiedPath, conditions) : unqualifiedPath; - return resolveUnqualified(remappedPath, { extensions }); - } catch (error) { - if (Object.prototype.hasOwnProperty.call(error, `pnpCode`)) - Object.assign(error.data, { request: getPathForDisplay(request), issuer: issuer && getPathForDisplay(issuer) }); - throw error; - } - } - function resolveVirtual(request) { - const normalized = ppath.normalize(request); - const resolved = VirtualFS.resolveVirtual(normalized); - return resolved !== normalized ? resolved : null; - } - return { - VERSIONS, - topLevel, - getLocator: (name, referencish) => { - if (Array.isArray(referencish)) { - return { name: referencish[0], reference: referencish[1] }; - } else { - return { name, reference: referencish }; - } - }, - getDependencyTreeRoots: () => { - return [...runtimeState.dependencyTreeRoots]; - }, - getAllLocators() { - const locators = []; - for (const [name, entry] of packageRegistry) - for (const reference of entry.keys()) - if (name !== null && reference !== null) - locators.push({ name, reference }); - return locators; - }, - getPackageInformation: (locator) => { - const info = getPackageInformation(locator); - if (info === null) - return null; - const packageLocation = npath.fromPortablePath(info.packageLocation); - const nativeInfo = { ...info, packageLocation }; - return nativeInfo; - }, - findPackageLocator: (path) => { - return findPackageLocator(npath.toPortablePath(path)); - }, - resolveToUnqualified: maybeLog(`resolveToUnqualified`, (request, issuer, opts2) => { - const portableIssuer = issuer !== null ? npath.toPortablePath(issuer) : null; - const resolution = resolveToUnqualified(npath.toPortablePath(request), portableIssuer, opts2); - if (resolution === null) - return null; - return npath.fromPortablePath(resolution); - }), - resolveUnqualified: maybeLog(`resolveUnqualified`, (unqualifiedPath, opts2) => { - return npath.fromPortablePath(resolveUnqualified(npath.toPortablePath(unqualifiedPath), opts2)); - }), - resolveRequest: maybeLog(`resolveRequest`, (request, issuer, opts2) => { - const portableIssuer = issuer !== null ? npath.toPortablePath(issuer) : null; - const resolution = resolveRequest(npath.toPortablePath(request), portableIssuer, opts2); - if (resolution === null) - return null; - return npath.fromPortablePath(resolution); - }), - resolveVirtual: maybeLog(`resolveVirtual`, (path) => { - const result = resolveVirtual(npath.toPortablePath(path)); - if (result !== null) { - return npath.fromPortablePath(result); - } else { - return null; - } - }) - }; -} - -function makeManager(pnpapi, opts) { - const initialApiPath = npath.toPortablePath(pnpapi.resolveToUnqualified(`pnpapi`, null)); - const initialApiStats = opts.fakeFs.statSync(npath.toPortablePath(initialApiPath)); - const apiMetadata = /* @__PURE__ */ new Map([ - [initialApiPath, { - cache: require$$0.Module._cache, - instance: pnpapi, - stats: initialApiStats, - lastRefreshCheck: Date.now() - }] - ]); - function loadApiInstance(pnpApiPath) { - const nativePath = npath.fromPortablePath(pnpApiPath); - const module = new require$$0.Module(nativePath, null); - module.load(nativePath); - return module.exports; - } - function refreshApiEntry(pnpApiPath, apiEntry) { - const timeNow = Date.now(); - if (timeNow - apiEntry.lastRefreshCheck < 500) - return; - apiEntry.lastRefreshCheck = timeNow; - const stats = opts.fakeFs.statSync(pnpApiPath); - if (stats.mtime > apiEntry.stats.mtime) { - process.emitWarning(`[Warning] The runtime detected new informations in a PnP file; reloading the API instance (${npath.fromPortablePath(pnpApiPath)})`); - apiEntry.stats = stats; - apiEntry.instance = loadApiInstance(pnpApiPath); - } - } - function getApiEntry(pnpApiPath, refresh = false) { - let apiEntry = apiMetadata.get(pnpApiPath); - if (typeof apiEntry !== `undefined`) { - if (refresh) { - refreshApiEntry(pnpApiPath, apiEntry); - } - } else { - apiMetadata.set(pnpApiPath, apiEntry = { - cache: {}, - instance: loadApiInstance(pnpApiPath), - stats: opts.fakeFs.statSync(pnpApiPath), - lastRefreshCheck: Date.now() - }); - } - return apiEntry; - } - const findApiPathCache = /* @__PURE__ */ new Map(); - function addToCacheAndReturn(start, end, target) { - if (target !== null) - target = VirtualFS.resolveVirtual(target); - let curr; - let next = start; - do { - curr = next; - findApiPathCache.set(curr, target); - next = ppath.dirname(curr); - } while (curr !== end); - return target; - } - function findApiPathFor(modulePath) { - let bestCandidate = null; - for (const [apiPath, apiEntry] of apiMetadata) { - const locator = apiEntry.instance.findPackageLocator(modulePath); - if (!locator) - continue; - if (apiMetadata.size === 1) - return apiPath; - const packageInformation = apiEntry.instance.getPackageInformation(locator); - if (!packageInformation) - throw new Error(`Assertion failed: Couldn't get package information for '${modulePath}'`); - if (!bestCandidate) - bestCandidate = { packageLocation: packageInformation.packageLocation, apiPaths: [] }; - if (packageInformation.packageLocation === bestCandidate.packageLocation) { - bestCandidate.apiPaths.push(apiPath); - } else if (packageInformation.packageLocation.length > bestCandidate.packageLocation.length) { - bestCandidate = { packageLocation: packageInformation.packageLocation, apiPaths: [apiPath] }; - } - } - if (bestCandidate) { - if (bestCandidate.apiPaths.length === 1) - return bestCandidate.apiPaths[0]; - const controlSegment = bestCandidate.apiPaths.map((apiPath) => ` ${npath.fromPortablePath(apiPath)}`).join(` -`); - throw new Error(`Unable to locate pnpapi, the module '${modulePath}' is controlled by multiple pnpapi instances. -This is usually caused by using the global cache (enableGlobalCache: true) - -Controlled by: -${controlSegment} -`); - } - const start = ppath.resolve(npath.toPortablePath(modulePath)); - let curr; - let next = start; - do { - curr = next; - const cached = findApiPathCache.get(curr); - if (cached !== void 0) - return addToCacheAndReturn(start, curr, cached); - const cjsCandidate = ppath.join(curr, Filename.pnpCjs); - if (opts.fakeFs.existsSync(cjsCandidate) && opts.fakeFs.statSync(cjsCandidate).isFile()) - return addToCacheAndReturn(start, curr, cjsCandidate); - const legacyCjsCandidate = ppath.join(curr, Filename.pnpJs); - if (opts.fakeFs.existsSync(legacyCjsCandidate) && opts.fakeFs.statSync(legacyCjsCandidate).isFile()) - return addToCacheAndReturn(start, curr, legacyCjsCandidate); - next = ppath.dirname(curr); - } while (curr !== PortablePath.root); - return addToCacheAndReturn(start, curr, null); - } - function getApiPathFromParent(parent) { - if (parent == null) - return initialApiPath; - if (typeof parent.pnpApiPath === `undefined`) { - if (parent.filename !== null) { - return parent.pnpApiPath = findApiPathFor(parent.filename); - } else { - return initialApiPath; - } - } - if (parent.pnpApiPath !== null) - return parent.pnpApiPath; - return null; - } - return { - getApiPathFromParent, - findApiPathFor, - getApiEntry - }; -} - -const localFs = { ...fs__default.default }; -const nodeFs = new NodeFS(localFs); -const defaultRuntimeState = $$SETUP_STATE(hydrateRuntimeState); -const defaultPnpapiResolution = __filename; -const defaultFsLayer = new VirtualFS({ - baseFs: new ZipOpenFS({ - baseFs: nodeFs, - libzip: () => getLibzipSync(), - maxOpenFiles: 80, - readOnlyArchives: true - }) -}); -class DynamicFS extends ProxiedFS { - constructor() { - super(ppath); - this.baseFs = defaultFsLayer; - } - mapToBase(p) { - return p; - } - mapFromBase(p) { - return p; - } -} -const dynamicFsLayer = new DynamicFS(); -let manager; -const defaultApi = Object.assign(makeApi(defaultRuntimeState, { - fakeFs: dynamicFsLayer, - pnpapiResolution: defaultPnpapiResolution -}), { - makeApi: ({ - basePath = void 0, - fakeFs = dynamicFsLayer, - pnpapiResolution = defaultPnpapiResolution, - ...rest - }) => { - const apiRuntimeState = typeof basePath !== `undefined` ? $$SETUP_STATE(hydrateRuntimeState, basePath) : defaultRuntimeState; - return makeApi(apiRuntimeState, { - fakeFs, - pnpapiResolution, - ...rest - }); - }, - setup: (api) => { - applyPatch(api || defaultApi, { - fakeFs: defaultFsLayer, - manager - }); - dynamicFsLayer.baseFs = new NodeFS(fs__default.default); - } -}); -manager = makeManager(defaultApi, { - fakeFs: dynamicFsLayer -}); -if (module.parent && module.parent.id === `internal/preload`) { - defaultApi.setup(); - if (module.filename) { - delete require$$0__default.default._cache[module.filename]; - } -} -if (process.mainModule === module) { - const reportError = (code, message, data) => { - process.stdout.write(`${JSON.stringify([{ code, message, data }, null])} -`); - }; - const reportSuccess = (resolution) => { - process.stdout.write(`${JSON.stringify([null, resolution])} -`); - }; - const processResolution = (request, issuer) => { - try { - reportSuccess(defaultApi.resolveRequest(request, issuer)); - } catch (error) { - reportError(error.code, error.message, error.data); - } - }; - const processRequest = (data) => { - try { - const [request, issuer] = JSON.parse(data); - processResolution(request, issuer); - } catch (error) { - reportError(`INVALID_JSON`, error.message, error.data); - } - }; - if (process.argv.length > 2) { - if (process.argv.length !== 4) { - process.stderr.write(`Usage: ${process.argv[0]} ${process.argv[1]} -`); - process.exitCode = 64; - } else { - processResolution(process.argv[2], process.argv[3]); - } - } else { - let buffer = ``; - const decoder = new StringDecoder__default.default.StringDecoder(); - process.stdin.on(`data`, (chunk) => { - buffer += decoder.write(chunk); - do { - const index = buffer.indexOf(` -`); - if (index === -1) - break; - const line = buffer.slice(0, index); - buffer = buffer.slice(index + 1); - processRequest(line); - } while (true); - }); - } -} - -module.exports = defaultApi; diff --git a/.pnp.loader.mjs b/.pnp.loader.mjs deleted file mode 100644 index 78226f53..00000000 --- a/.pnp.loader.mjs +++ /dev/null @@ -1,2042 +0,0 @@ -import { URL as URL$1, fileURLToPath, pathToFileURL } from 'url'; -import fs from 'fs'; -import path from 'path'; -import moduleExports, { Module } from 'module'; -import { EOL } from 'os'; -import assert from 'assert'; - -const SAFE_TIME = 456789e3; - -const PortablePath = { - root: `/`, - dot: `.`, - parent: `..` -}; -const npath = Object.create(path); -const ppath = Object.create(path.posix); -npath.cwd = () => process.cwd(); -ppath.cwd = () => toPortablePath(process.cwd()); -ppath.resolve = (...segments) => { - if (segments.length > 0 && ppath.isAbsolute(segments[0])) { - return path.posix.resolve(...segments); - } else { - return path.posix.resolve(ppath.cwd(), ...segments); - } -}; -const contains = function(pathUtils, from, to) { - from = pathUtils.normalize(from); - to = pathUtils.normalize(to); - if (from === to) - return `.`; - if (!from.endsWith(pathUtils.sep)) - from = from + pathUtils.sep; - if (to.startsWith(from)) { - return to.slice(from.length); - } else { - return null; - } -}; -npath.fromPortablePath = fromPortablePath; -npath.toPortablePath = toPortablePath; -npath.contains = (from, to) => contains(npath, from, to); -ppath.contains = (from, to) => contains(ppath, from, to); -const WINDOWS_PATH_REGEXP = /^([a-zA-Z]:.*)$/; -const UNC_WINDOWS_PATH_REGEXP = /^\/\/(\.\/)?(.*)$/; -const PORTABLE_PATH_REGEXP = /^\/([a-zA-Z]:.*)$/; -const UNC_PORTABLE_PATH_REGEXP = /^\/unc\/(\.dot\/)?(.*)$/; -function fromPortablePath(p) { - if (process.platform !== `win32`) - return p; - let portablePathMatch, uncPortablePathMatch; - if (portablePathMatch = p.match(PORTABLE_PATH_REGEXP)) - p = portablePathMatch[1]; - else if (uncPortablePathMatch = p.match(UNC_PORTABLE_PATH_REGEXP)) - p = `\\\\${uncPortablePathMatch[1] ? `.\\` : ``}${uncPortablePathMatch[2]}`; - else - return p; - return p.replace(/\//g, `\\`); -} -function toPortablePath(p) { - if (process.platform !== `win32`) - return p; - p = p.replace(/\\/g, `/`); - let windowsPathMatch, uncWindowsPathMatch; - if (windowsPathMatch = p.match(WINDOWS_PATH_REGEXP)) - p = `/${windowsPathMatch[1]}`; - else if (uncWindowsPathMatch = p.match(UNC_WINDOWS_PATH_REGEXP)) - p = `/unc/${uncWindowsPathMatch[1] ? `.dot/` : ``}${uncWindowsPathMatch[2]}`; - return p; -} -function convertPath(targetPathUtils, sourcePath) { - return targetPathUtils === npath ? fromPortablePath(sourcePath) : toPortablePath(sourcePath); -} - -const defaultTime = new Date(SAFE_TIME * 1e3); -async function copyPromise(destinationFs, destination, sourceFs, source, opts) { - const normalizedDestination = destinationFs.pathUtils.normalize(destination); - const normalizedSource = sourceFs.pathUtils.normalize(source); - const prelayout = []; - const postlayout = []; - const { atime, mtime } = opts.stableTime ? { atime: defaultTime, mtime: defaultTime } : await sourceFs.lstatPromise(normalizedSource); - await destinationFs.mkdirpPromise(destinationFs.pathUtils.dirname(destination), { utimes: [atime, mtime] }); - const updateTime = typeof destinationFs.lutimesPromise === `function` ? destinationFs.lutimesPromise.bind(destinationFs) : destinationFs.utimesPromise.bind(destinationFs); - await copyImpl(prelayout, postlayout, updateTime, destinationFs, normalizedDestination, sourceFs, normalizedSource, { ...opts, didParentExist: true }); - for (const operation of prelayout) - await operation(); - await Promise.all(postlayout.map((operation) => { - return operation(); - })); -} -async function copyImpl(prelayout, postlayout, updateTime, destinationFs, destination, sourceFs, source, opts) { - var _a, _b; - const destinationStat = opts.didParentExist ? await maybeLStat(destinationFs, destination) : null; - const sourceStat = await sourceFs.lstatPromise(source); - const { atime, mtime } = opts.stableTime ? { atime: defaultTime, mtime: defaultTime } : sourceStat; - let updated; - switch (true) { - case sourceStat.isDirectory(): - { - updated = await copyFolder(prelayout, postlayout, updateTime, destinationFs, destination, destinationStat, sourceFs, source, sourceStat, opts); - } - break; - case sourceStat.isFile(): - { - updated = await copyFile(prelayout, postlayout, updateTime, destinationFs, destination, destinationStat, sourceFs, source, sourceStat, opts); - } - break; - case sourceStat.isSymbolicLink(): - { - updated = await copySymlink(prelayout, postlayout, updateTime, destinationFs, destination, destinationStat, sourceFs, source, sourceStat, opts); - } - break; - default: - { - throw new Error(`Unsupported file type (${sourceStat.mode})`); - } - } - if (updated || ((_a = destinationStat == null ? void 0 : destinationStat.mtime) == null ? void 0 : _a.getTime()) !== mtime.getTime() || ((_b = destinationStat == null ? void 0 : destinationStat.atime) == null ? void 0 : _b.getTime()) !== atime.getTime()) { - postlayout.push(() => updateTime(destination, atime, mtime)); - updated = true; - } - if (destinationStat === null || (destinationStat.mode & 511) !== (sourceStat.mode & 511)) { - postlayout.push(() => destinationFs.chmodPromise(destination, sourceStat.mode & 511)); - updated = true; - } - return updated; -} -async function maybeLStat(baseFs, p) { - try { - return await baseFs.lstatPromise(p); - } catch (e) { - return null; - } -} -async function copyFolder(prelayout, postlayout, updateTime, destinationFs, destination, destinationStat, sourceFs, source, sourceStat, opts) { - if (destinationStat !== null && !destinationStat.isDirectory()) { - if (opts.overwrite) { - prelayout.push(async () => destinationFs.removePromise(destination)); - destinationStat = null; - } else { - return false; - } - } - let updated = false; - if (destinationStat === null) { - prelayout.push(async () => { - try { - await destinationFs.mkdirPromise(destination, { mode: sourceStat.mode }); - } catch (err) { - if (err.code !== `EEXIST`) { - throw err; - } - } - }); - updated = true; - } - const entries = await sourceFs.readdirPromise(source); - const nextOpts = opts.didParentExist && !destinationStat ? { ...opts, didParentExist: false } : opts; - if (opts.stableSort) { - for (const entry of entries.sort()) { - if (await copyImpl(prelayout, postlayout, updateTime, destinationFs, destinationFs.pathUtils.join(destination, entry), sourceFs, sourceFs.pathUtils.join(source, entry), nextOpts)) { - updated = true; - } - } - } else { - const entriesUpdateStatus = await Promise.all(entries.map(async (entry) => { - await copyImpl(prelayout, postlayout, updateTime, destinationFs, destinationFs.pathUtils.join(destination, entry), sourceFs, sourceFs.pathUtils.join(source, entry), nextOpts); - })); - if (entriesUpdateStatus.some((status) => status)) { - updated = true; - } - } - return updated; -} -const isCloneSupportedCache = /* @__PURE__ */ new WeakMap(); -function makeLinkOperation(opFs, destination, source, sourceStat, linkStrategy) { - return async () => { - await opFs.linkPromise(source, destination); - if (linkStrategy === "readOnly" /* ReadOnly */) { - sourceStat.mode &= ~146; - await opFs.chmodPromise(destination, sourceStat.mode); - } - }; -} -function makeCloneLinkOperation(opFs, destination, source, sourceStat, linkStrategy) { - const isCloneSupported = isCloneSupportedCache.get(opFs); - if (typeof isCloneSupported === `undefined`) { - return async () => { - try { - await opFs.copyFilePromise(source, destination, fs.constants.COPYFILE_FICLONE_FORCE); - isCloneSupportedCache.set(opFs, true); - } catch (err) { - if (err.code === `ENOSYS` || err.code === `ENOTSUP`) { - isCloneSupportedCache.set(opFs, false); - await makeLinkOperation(opFs, destination, source, sourceStat, linkStrategy)(); - } else { - throw err; - } - } - }; - } else { - if (isCloneSupported) { - return async () => opFs.copyFilePromise(source, destination, fs.constants.COPYFILE_FICLONE_FORCE); - } else { - return makeLinkOperation(opFs, destination, source, sourceStat, linkStrategy); - } - } -} -async function copyFile(prelayout, postlayout, updateTime, destinationFs, destination, destinationStat, sourceFs, source, sourceStat, opts) { - var _a; - if (destinationStat !== null) { - if (opts.overwrite) { - prelayout.push(async () => destinationFs.removePromise(destination)); - destinationStat = null; - } else { - return false; - } - } - const linkStrategy = (_a = opts.linkStrategy) != null ? _a : null; - const op = destinationFs === sourceFs ? linkStrategy !== null ? makeCloneLinkOperation(destinationFs, destination, source, sourceStat, linkStrategy) : async () => destinationFs.copyFilePromise(source, destination, fs.constants.COPYFILE_FICLONE) : linkStrategy !== null ? makeLinkOperation(destinationFs, destination, source, sourceStat, linkStrategy) : async () => destinationFs.writeFilePromise(destination, await sourceFs.readFilePromise(source)); - prelayout.push(async () => op()); - return true; -} -async function copySymlink(prelayout, postlayout, updateTime, destinationFs, destination, destinationStat, sourceFs, source, sourceStat, opts) { - if (destinationStat !== null) { - if (opts.overwrite) { - prelayout.push(async () => destinationFs.removePromise(destination)); - destinationStat = null; - } else { - return false; - } - } - prelayout.push(async () => { - await destinationFs.symlinkPromise(convertPath(destinationFs.pathUtils, await sourceFs.readlinkPromise(source)), destination); - }); - return true; -} - -function makeError(code, message) { - return Object.assign(new Error(`${code}: ${message}`), { code }); -} -function ENOSYS(message, reason) { - return makeError(`ENOSYS`, `${message}, ${reason}`); -} - -class FakeFS { - constructor(pathUtils) { - this.pathUtils = pathUtils; - } - async *genTraversePromise(init, { stableSort = false } = {}) { - const stack = [init]; - while (stack.length > 0) { - const p = stack.shift(); - const entry = await this.lstatPromise(p); - if (entry.isDirectory()) { - const entries = await this.readdirPromise(p); - if (stableSort) { - for (const entry2 of entries.sort()) { - stack.push(this.pathUtils.join(p, entry2)); - } - } else { - throw new Error(`Not supported`); - } - } else { - yield p; - } - } - } - async removePromise(p, { recursive = true, maxRetries = 5 } = {}) { - let stat; - try { - stat = await this.lstatPromise(p); - } catch (error) { - if (error.code === `ENOENT`) { - return; - } else { - throw error; - } - } - if (stat.isDirectory()) { - if (recursive) { - const entries = await this.readdirPromise(p); - await Promise.all(entries.map((entry) => { - return this.removePromise(this.pathUtils.resolve(p, entry)); - })); - } - for (let t = 0; t <= maxRetries; t++) { - try { - await this.rmdirPromise(p); - break; - } catch (error) { - if (error.code !== `EBUSY` && error.code !== `ENOTEMPTY`) { - throw error; - } else if (t < maxRetries) { - await new Promise((resolve) => setTimeout(resolve, t * 100)); - } - } - } - } else { - await this.unlinkPromise(p); - } - } - removeSync(p, { recursive = true } = {}) { - let stat; - try { - stat = this.lstatSync(p); - } catch (error) { - if (error.code === `ENOENT`) { - return; - } else { - throw error; - } - } - if (stat.isDirectory()) { - if (recursive) - for (const entry of this.readdirSync(p)) - this.removeSync(this.pathUtils.resolve(p, entry)); - this.rmdirSync(p); - } else { - this.unlinkSync(p); - } - } - async mkdirpPromise(p, { chmod, utimes } = {}) { - p = this.resolve(p); - if (p === this.pathUtils.dirname(p)) - return void 0; - const parts = p.split(this.pathUtils.sep); - let createdDirectory; - for (let u = 2; u <= parts.length; ++u) { - const subPath = parts.slice(0, u).join(this.pathUtils.sep); - if (!this.existsSync(subPath)) { - try { - await this.mkdirPromise(subPath); - } catch (error) { - if (error.code === `EEXIST`) { - continue; - } else { - throw error; - } - } - createdDirectory != null ? createdDirectory : createdDirectory = subPath; - if (chmod != null) - await this.chmodPromise(subPath, chmod); - if (utimes != null) { - await this.utimesPromise(subPath, utimes[0], utimes[1]); - } else { - const parentStat = await this.statPromise(this.pathUtils.dirname(subPath)); - await this.utimesPromise(subPath, parentStat.atime, parentStat.mtime); - } - } - } - return createdDirectory; - } - mkdirpSync(p, { chmod, utimes } = {}) { - p = this.resolve(p); - if (p === this.pathUtils.dirname(p)) - return void 0; - const parts = p.split(this.pathUtils.sep); - let createdDirectory; - for (let u = 2; u <= parts.length; ++u) { - const subPath = parts.slice(0, u).join(this.pathUtils.sep); - if (!this.existsSync(subPath)) { - try { - this.mkdirSync(subPath); - } catch (error) { - if (error.code === `EEXIST`) { - continue; - } else { - throw error; - } - } - createdDirectory != null ? createdDirectory : createdDirectory = subPath; - if (chmod != null) - this.chmodSync(subPath, chmod); - if (utimes != null) { - this.utimesSync(subPath, utimes[0], utimes[1]); - } else { - const parentStat = this.statSync(this.pathUtils.dirname(subPath)); - this.utimesSync(subPath, parentStat.atime, parentStat.mtime); - } - } - } - return createdDirectory; - } - async copyPromise(destination, source, { baseFs = this, overwrite = true, stableSort = false, stableTime = false, linkStrategy = null } = {}) { - return await copyPromise(this, destination, baseFs, source, { overwrite, stableSort, stableTime, linkStrategy }); - } - copySync(destination, source, { baseFs = this, overwrite = true } = {}) { - const stat = baseFs.lstatSync(source); - const exists = this.existsSync(destination); - if (stat.isDirectory()) { - this.mkdirpSync(destination); - const directoryListing = baseFs.readdirSync(source); - for (const entry of directoryListing) { - this.copySync(this.pathUtils.join(destination, entry), baseFs.pathUtils.join(source, entry), { baseFs, overwrite }); - } - } else if (stat.isFile()) { - if (!exists || overwrite) { - if (exists) - this.removeSync(destination); - const content = baseFs.readFileSync(source); - this.writeFileSync(destination, content); - } - } else if (stat.isSymbolicLink()) { - if (!exists || overwrite) { - if (exists) - this.removeSync(destination); - const target = baseFs.readlinkSync(source); - this.symlinkSync(convertPath(this.pathUtils, target), destination); - } - } else { - throw new Error(`Unsupported file type (file: ${source}, mode: 0o${stat.mode.toString(8).padStart(6, `0`)})`); - } - const mode = stat.mode & 511; - this.chmodSync(destination, mode); - } - async changeFilePromise(p, content, opts = {}) { - if (Buffer.isBuffer(content)) { - return this.changeFileBufferPromise(p, content, opts); - } else { - return this.changeFileTextPromise(p, content, opts); - } - } - async changeFileBufferPromise(p, content, { mode } = {}) { - let current = Buffer.alloc(0); - try { - current = await this.readFilePromise(p); - } catch (error) { - } - if (Buffer.compare(current, content) === 0) - return; - await this.writeFilePromise(p, content, { mode }); - } - async changeFileTextPromise(p, content, { automaticNewlines, mode } = {}) { - let current = ``; - try { - current = await this.readFilePromise(p, `utf8`); - } catch (error) { - } - const normalizedContent = automaticNewlines ? normalizeLineEndings(current, content) : content; - if (current === normalizedContent) - return; - await this.writeFilePromise(p, normalizedContent, { mode }); - } - changeFileSync(p, content, opts = {}) { - if (Buffer.isBuffer(content)) { - return this.changeFileBufferSync(p, content, opts); - } else { - return this.changeFileTextSync(p, content, opts); - } - } - changeFileBufferSync(p, content, { mode } = {}) { - let current = Buffer.alloc(0); - try { - current = this.readFileSync(p); - } catch (error) { - } - if (Buffer.compare(current, content) === 0) - return; - this.writeFileSync(p, content, { mode }); - } - changeFileTextSync(p, content, { automaticNewlines = false, mode } = {}) { - let current = ``; - try { - current = this.readFileSync(p, `utf8`); - } catch (error) { - } - const normalizedContent = automaticNewlines ? normalizeLineEndings(current, content) : content; - if (current === normalizedContent) - return; - this.writeFileSync(p, normalizedContent, { mode }); - } - async movePromise(fromP, toP) { - try { - await this.renamePromise(fromP, toP); - } catch (error) { - if (error.code === `EXDEV`) { - await this.copyPromise(toP, fromP); - await this.removePromise(fromP); - } else { - throw error; - } - } - } - moveSync(fromP, toP) { - try { - this.renameSync(fromP, toP); - } catch (error) { - if (error.code === `EXDEV`) { - this.copySync(toP, fromP); - this.removeSync(fromP); - } else { - throw error; - } - } - } - async lockPromise(affectedPath, callback) { - const lockPath = `${affectedPath}.flock`; - const interval = 1e3 / 60; - const startTime = Date.now(); - let fd = null; - const isAlive = async () => { - let pid; - try { - [pid] = await this.readJsonPromise(lockPath); - } catch (error) { - return Date.now() - startTime < 500; - } - try { - process.kill(pid, 0); - return true; - } catch (error) { - return false; - } - }; - while (fd === null) { - try { - fd = await this.openPromise(lockPath, `wx`); - } catch (error) { - if (error.code === `EEXIST`) { - if (!await isAlive()) { - try { - await this.unlinkPromise(lockPath); - continue; - } catch (error2) { - } - } - if (Date.now() - startTime < 60 * 1e3) { - await new Promise((resolve) => setTimeout(resolve, interval)); - } else { - throw new Error(`Couldn't acquire a lock in a reasonable time (via ${lockPath})`); - } - } else { - throw error; - } - } - } - await this.writePromise(fd, JSON.stringify([process.pid])); - try { - return await callback(); - } finally { - try { - await this.closePromise(fd); - await this.unlinkPromise(lockPath); - } catch (error) { - } - } - } - async readJsonPromise(p) { - const content = await this.readFilePromise(p, `utf8`); - try { - return JSON.parse(content); - } catch (error) { - error.message += ` (in ${p})`; - throw error; - } - } - readJsonSync(p) { - const content = this.readFileSync(p, `utf8`); - try { - return JSON.parse(content); - } catch (error) { - error.message += ` (in ${p})`; - throw error; - } - } - async writeJsonPromise(p, data) { - return await this.writeFilePromise(p, `${JSON.stringify(data, null, 2)} -`); - } - writeJsonSync(p, data) { - return this.writeFileSync(p, `${JSON.stringify(data, null, 2)} -`); - } - async preserveTimePromise(p, cb) { - const stat = await this.lstatPromise(p); - const result = await cb(); - if (typeof result !== `undefined`) - p = result; - if (this.lutimesPromise) { - await this.lutimesPromise(p, stat.atime, stat.mtime); - } else if (!stat.isSymbolicLink()) { - await this.utimesPromise(p, stat.atime, stat.mtime); - } - } - async preserveTimeSync(p, cb) { - const stat = this.lstatSync(p); - const result = cb(); - if (typeof result !== `undefined`) - p = result; - if (this.lutimesSync) { - this.lutimesSync(p, stat.atime, stat.mtime); - } else if (!stat.isSymbolicLink()) { - this.utimesSync(p, stat.atime, stat.mtime); - } - } -} -class BasePortableFakeFS extends FakeFS { - constructor() { - super(ppath); - } -} -function getEndOfLine(content) { - const matches = content.match(/\r?\n/g); - if (matches === null) - return EOL; - const crlf = matches.filter((nl) => nl === `\r -`).length; - const lf = matches.length - crlf; - return crlf > lf ? `\r -` : ` -`; -} -function normalizeLineEndings(originalContent, newContent) { - return newContent.replace(/\r?\n/g, getEndOfLine(originalContent)); -} - -class NodeFS extends BasePortableFakeFS { - constructor(realFs = fs) { - super(); - this.realFs = realFs; - if (typeof this.realFs.lutimes !== `undefined`) { - this.lutimesPromise = this.lutimesPromiseImpl; - this.lutimesSync = this.lutimesSyncImpl; - } - } - getExtractHint() { - return false; - } - getRealPath() { - return PortablePath.root; - } - resolve(p) { - return ppath.resolve(p); - } - async openPromise(p, flags, mode) { - return await new Promise((resolve, reject) => { - this.realFs.open(npath.fromPortablePath(p), flags, mode, this.makeCallback(resolve, reject)); - }); - } - openSync(p, flags, mode) { - return this.realFs.openSync(npath.fromPortablePath(p), flags, mode); - } - async opendirPromise(p, opts) { - return await new Promise((resolve, reject) => { - if (typeof opts !== `undefined`) { - this.realFs.opendir(npath.fromPortablePath(p), opts, this.makeCallback(resolve, reject)); - } else { - this.realFs.opendir(npath.fromPortablePath(p), this.makeCallback(resolve, reject)); - } - }).then((dir) => { - return Object.defineProperty(dir, `path`, { value: p, configurable: true, writable: true }); - }); - } - opendirSync(p, opts) { - const dir = typeof opts !== `undefined` ? this.realFs.opendirSync(npath.fromPortablePath(p), opts) : this.realFs.opendirSync(npath.fromPortablePath(p)); - return Object.defineProperty(dir, `path`, { value: p, configurable: true, writable: true }); - } - async readPromise(fd, buffer, offset = 0, length = 0, position = -1) { - return await new Promise((resolve, reject) => { - this.realFs.read(fd, buffer, offset, length, position, (error, bytesRead) => { - if (error) { - reject(error); - } else { - resolve(bytesRead); - } - }); - }); - } - readSync(fd, buffer, offset, length, position) { - return this.realFs.readSync(fd, buffer, offset, length, position); - } - async writePromise(fd, buffer, offset, length, position) { - return await new Promise((resolve, reject) => { - if (typeof buffer === `string`) { - return this.realFs.write(fd, buffer, offset, this.makeCallback(resolve, reject)); - } else { - return this.realFs.write(fd, buffer, offset, length, position, this.makeCallback(resolve, reject)); - } - }); - } - writeSync(fd, buffer, offset, length, position) { - if (typeof buffer === `string`) { - return this.realFs.writeSync(fd, buffer, offset); - } else { - return this.realFs.writeSync(fd, buffer, offset, length, position); - } - } - async closePromise(fd) { - await new Promise((resolve, reject) => { - this.realFs.close(fd, this.makeCallback(resolve, reject)); - }); - } - closeSync(fd) { - this.realFs.closeSync(fd); - } - createReadStream(p, opts) { - const realPath = p !== null ? npath.fromPortablePath(p) : p; - return this.realFs.createReadStream(realPath, opts); - } - createWriteStream(p, opts) { - const realPath = p !== null ? npath.fromPortablePath(p) : p; - return this.realFs.createWriteStream(realPath, opts); - } - async realpathPromise(p) { - return await new Promise((resolve, reject) => { - this.realFs.realpath(npath.fromPortablePath(p), {}, this.makeCallback(resolve, reject)); - }).then((path) => { - return npath.toPortablePath(path); - }); - } - realpathSync(p) { - return npath.toPortablePath(this.realFs.realpathSync(npath.fromPortablePath(p), {})); - } - async existsPromise(p) { - return await new Promise((resolve) => { - this.realFs.exists(npath.fromPortablePath(p), resolve); - }); - } - accessSync(p, mode) { - return this.realFs.accessSync(npath.fromPortablePath(p), mode); - } - async accessPromise(p, mode) { - return await new Promise((resolve, reject) => { - this.realFs.access(npath.fromPortablePath(p), mode, this.makeCallback(resolve, reject)); - }); - } - existsSync(p) { - return this.realFs.existsSync(npath.fromPortablePath(p)); - } - async statPromise(p, opts) { - return await new Promise((resolve, reject) => { - if (opts) { - this.realFs.stat(npath.fromPortablePath(p), opts, this.makeCallback(resolve, reject)); - } else { - this.realFs.stat(npath.fromPortablePath(p), this.makeCallback(resolve, reject)); - } - }); - } - statSync(p, opts) { - if (opts) { - return this.realFs.statSync(npath.fromPortablePath(p), opts); - } else { - return this.realFs.statSync(npath.fromPortablePath(p)); - } - } - async fstatPromise(fd, opts) { - return await new Promise((resolve, reject) => { - if (opts) { - this.realFs.fstat(fd, opts, this.makeCallback(resolve, reject)); - } else { - this.realFs.fstat(fd, this.makeCallback(resolve, reject)); - } - }); - } - fstatSync(fd, opts) { - if (opts) { - return this.realFs.fstatSync(fd, opts); - } else { - return this.realFs.fstatSync(fd); - } - } - async lstatPromise(p, opts) { - return await new Promise((resolve, reject) => { - if (opts) { - this.realFs.lstat(npath.fromPortablePath(p), opts, this.makeCallback(resolve, reject)); - } else { - this.realFs.lstat(npath.fromPortablePath(p), this.makeCallback(resolve, reject)); - } - }); - } - lstatSync(p, opts) { - if (opts) { - return this.realFs.lstatSync(npath.fromPortablePath(p), opts); - } else { - return this.realFs.lstatSync(npath.fromPortablePath(p)); - } - } - async fchmodPromise(fd, mask) { - return await new Promise((resolve, reject) => { - this.realFs.fchmod(fd, mask, this.makeCallback(resolve, reject)); - }); - } - fchmodSync(fd, mask) { - return this.realFs.fchmodSync(fd, mask); - } - async chmodPromise(p, mask) { - return await new Promise((resolve, reject) => { - this.realFs.chmod(npath.fromPortablePath(p), mask, this.makeCallback(resolve, reject)); - }); - } - chmodSync(p, mask) { - return this.realFs.chmodSync(npath.fromPortablePath(p), mask); - } - async fchownPromise(fd, uid, gid) { - return await new Promise((resolve, reject) => { - this.realFs.fchown(fd, uid, gid, this.makeCallback(resolve, reject)); - }); - } - fchownSync(fd, uid, gid) { - return this.realFs.fchownSync(fd, uid, gid); - } - async chownPromise(p, uid, gid) { - return await new Promise((resolve, reject) => { - this.realFs.chown(npath.fromPortablePath(p), uid, gid, this.makeCallback(resolve, reject)); - }); - } - chownSync(p, uid, gid) { - return this.realFs.chownSync(npath.fromPortablePath(p), uid, gid); - } - async renamePromise(oldP, newP) { - return await new Promise((resolve, reject) => { - this.realFs.rename(npath.fromPortablePath(oldP), npath.fromPortablePath(newP), this.makeCallback(resolve, reject)); - }); - } - renameSync(oldP, newP) { - return this.realFs.renameSync(npath.fromPortablePath(oldP), npath.fromPortablePath(newP)); - } - async copyFilePromise(sourceP, destP, flags = 0) { - return await new Promise((resolve, reject) => { - this.realFs.copyFile(npath.fromPortablePath(sourceP), npath.fromPortablePath(destP), flags, this.makeCallback(resolve, reject)); - }); - } - copyFileSync(sourceP, destP, flags = 0) { - return this.realFs.copyFileSync(npath.fromPortablePath(sourceP), npath.fromPortablePath(destP), flags); - } - async appendFilePromise(p, content, opts) { - return await new Promise((resolve, reject) => { - const fsNativePath = typeof p === `string` ? npath.fromPortablePath(p) : p; - if (opts) { - this.realFs.appendFile(fsNativePath, content, opts, this.makeCallback(resolve, reject)); - } else { - this.realFs.appendFile(fsNativePath, content, this.makeCallback(resolve, reject)); - } - }); - } - appendFileSync(p, content, opts) { - const fsNativePath = typeof p === `string` ? npath.fromPortablePath(p) : p; - if (opts) { - this.realFs.appendFileSync(fsNativePath, content, opts); - } else { - this.realFs.appendFileSync(fsNativePath, content); - } - } - async writeFilePromise(p, content, opts) { - return await new Promise((resolve, reject) => { - const fsNativePath = typeof p === `string` ? npath.fromPortablePath(p) : p; - if (opts) { - this.realFs.writeFile(fsNativePath, content, opts, this.makeCallback(resolve, reject)); - } else { - this.realFs.writeFile(fsNativePath, content, this.makeCallback(resolve, reject)); - } - }); - } - writeFileSync(p, content, opts) { - const fsNativePath = typeof p === `string` ? npath.fromPortablePath(p) : p; - if (opts) { - this.realFs.writeFileSync(fsNativePath, content, opts); - } else { - this.realFs.writeFileSync(fsNativePath, content); - } - } - async unlinkPromise(p) { - return await new Promise((resolve, reject) => { - this.realFs.unlink(npath.fromPortablePath(p), this.makeCallback(resolve, reject)); - }); - } - unlinkSync(p) { - return this.realFs.unlinkSync(npath.fromPortablePath(p)); - } - async utimesPromise(p, atime, mtime) { - return await new Promise((resolve, reject) => { - this.realFs.utimes(npath.fromPortablePath(p), atime, mtime, this.makeCallback(resolve, reject)); - }); - } - utimesSync(p, atime, mtime) { - this.realFs.utimesSync(npath.fromPortablePath(p), atime, mtime); - } - async lutimesPromiseImpl(p, atime, mtime) { - const lutimes = this.realFs.lutimes; - if (typeof lutimes === `undefined`) - throw ENOSYS(`unavailable Node binding`, `lutimes '${p}'`); - return await new Promise((resolve, reject) => { - lutimes.call(this.realFs, npath.fromPortablePath(p), atime, mtime, this.makeCallback(resolve, reject)); - }); - } - lutimesSyncImpl(p, atime, mtime) { - const lutimesSync = this.realFs.lutimesSync; - if (typeof lutimesSync === `undefined`) - throw ENOSYS(`unavailable Node binding`, `lutimes '${p}'`); - lutimesSync.call(this.realFs, npath.fromPortablePath(p), atime, mtime); - } - async mkdirPromise(p, opts) { - return await new Promise((resolve, reject) => { - this.realFs.mkdir(npath.fromPortablePath(p), opts, this.makeCallback(resolve, reject)); - }); - } - mkdirSync(p, opts) { - return this.realFs.mkdirSync(npath.fromPortablePath(p), opts); - } - async rmdirPromise(p, opts) { - return await new Promise((resolve, reject) => { - if (opts) { - this.realFs.rmdir(npath.fromPortablePath(p), opts, this.makeCallback(resolve, reject)); - } else { - this.realFs.rmdir(npath.fromPortablePath(p), this.makeCallback(resolve, reject)); - } - }); - } - rmdirSync(p, opts) { - return this.realFs.rmdirSync(npath.fromPortablePath(p), opts); - } - async linkPromise(existingP, newP) { - return await new Promise((resolve, reject) => { - this.realFs.link(npath.fromPortablePath(existingP), npath.fromPortablePath(newP), this.makeCallback(resolve, reject)); - }); - } - linkSync(existingP, newP) { - return this.realFs.linkSync(npath.fromPortablePath(existingP), npath.fromPortablePath(newP)); - } - async symlinkPromise(target, p, type) { - return await new Promise((resolve, reject) => { - this.realFs.symlink(npath.fromPortablePath(target.replace(/\/+$/, ``)), npath.fromPortablePath(p), type, this.makeCallback(resolve, reject)); - }); - } - symlinkSync(target, p, type) { - return this.realFs.symlinkSync(npath.fromPortablePath(target.replace(/\/+$/, ``)), npath.fromPortablePath(p), type); - } - async readFilePromise(p, encoding) { - return await new Promise((resolve, reject) => { - const fsNativePath = typeof p === `string` ? npath.fromPortablePath(p) : p; - this.realFs.readFile(fsNativePath, encoding, this.makeCallback(resolve, reject)); - }); - } - readFileSync(p, encoding) { - const fsNativePath = typeof p === `string` ? npath.fromPortablePath(p) : p; - return this.realFs.readFileSync(fsNativePath, encoding); - } - async readdirPromise(p, opts) { - return await new Promise((resolve, reject) => { - if (opts == null ? void 0 : opts.withFileTypes) { - this.realFs.readdir(npath.fromPortablePath(p), { withFileTypes: true }, this.makeCallback(resolve, reject)); - } else { - this.realFs.readdir(npath.fromPortablePath(p), this.makeCallback((value) => resolve(value), reject)); - } - }); - } - readdirSync(p, opts) { - if (opts == null ? void 0 : opts.withFileTypes) { - return this.realFs.readdirSync(npath.fromPortablePath(p), { withFileTypes: true }); - } else { - return this.realFs.readdirSync(npath.fromPortablePath(p)); - } - } - async readlinkPromise(p) { - return await new Promise((resolve, reject) => { - this.realFs.readlink(npath.fromPortablePath(p), this.makeCallback(resolve, reject)); - }).then((path) => { - return npath.toPortablePath(path); - }); - } - readlinkSync(p) { - return npath.toPortablePath(this.realFs.readlinkSync(npath.fromPortablePath(p))); - } - async truncatePromise(p, len) { - return await new Promise((resolve, reject) => { - this.realFs.truncate(npath.fromPortablePath(p), len, this.makeCallback(resolve, reject)); - }); - } - truncateSync(p, len) { - return this.realFs.truncateSync(npath.fromPortablePath(p), len); - } - async ftruncatePromise(fd, len) { - return await new Promise((resolve, reject) => { - this.realFs.ftruncate(fd, len, this.makeCallback(resolve, reject)); - }); - } - ftruncateSync(fd, len) { - return this.realFs.ftruncateSync(fd, len); - } - watch(p, a, b) { - return this.realFs.watch( - npath.fromPortablePath(p), - a, - b - ); - } - watchFile(p, a, b) { - return this.realFs.watchFile( - npath.fromPortablePath(p), - a, - b - ); - } - unwatchFile(p, cb) { - return this.realFs.unwatchFile(npath.fromPortablePath(p), cb); - } - makeCallback(resolve, reject) { - return (err, result) => { - if (err) { - reject(err); - } else { - resolve(result); - } - }; - } -} - -class ProxiedFS extends FakeFS { - getExtractHint(hints) { - return this.baseFs.getExtractHint(hints); - } - resolve(path) { - return this.mapFromBase(this.baseFs.resolve(this.mapToBase(path))); - } - getRealPath() { - return this.mapFromBase(this.baseFs.getRealPath()); - } - async openPromise(p, flags, mode) { - return this.baseFs.openPromise(this.mapToBase(p), flags, mode); - } - openSync(p, flags, mode) { - return this.baseFs.openSync(this.mapToBase(p), flags, mode); - } - async opendirPromise(p, opts) { - return Object.assign(await this.baseFs.opendirPromise(this.mapToBase(p), opts), { path: p }); - } - opendirSync(p, opts) { - return Object.assign(this.baseFs.opendirSync(this.mapToBase(p), opts), { path: p }); - } - async readPromise(fd, buffer, offset, length, position) { - return await this.baseFs.readPromise(fd, buffer, offset, length, position); - } - readSync(fd, buffer, offset, length, position) { - return this.baseFs.readSync(fd, buffer, offset, length, position); - } - async writePromise(fd, buffer, offset, length, position) { - if (typeof buffer === `string`) { - return await this.baseFs.writePromise(fd, buffer, offset); - } else { - return await this.baseFs.writePromise(fd, buffer, offset, length, position); - } - } - writeSync(fd, buffer, offset, length, position) { - if (typeof buffer === `string`) { - return this.baseFs.writeSync(fd, buffer, offset); - } else { - return this.baseFs.writeSync(fd, buffer, offset, length, position); - } - } - async closePromise(fd) { - return this.baseFs.closePromise(fd); - } - closeSync(fd) { - this.baseFs.closeSync(fd); - } - createReadStream(p, opts) { - return this.baseFs.createReadStream(p !== null ? this.mapToBase(p) : p, opts); - } - createWriteStream(p, opts) { - return this.baseFs.createWriteStream(p !== null ? this.mapToBase(p) : p, opts); - } - async realpathPromise(p) { - return this.mapFromBase(await this.baseFs.realpathPromise(this.mapToBase(p))); - } - realpathSync(p) { - return this.mapFromBase(this.baseFs.realpathSync(this.mapToBase(p))); - } - async existsPromise(p) { - return this.baseFs.existsPromise(this.mapToBase(p)); - } - existsSync(p) { - return this.baseFs.existsSync(this.mapToBase(p)); - } - accessSync(p, mode) { - return this.baseFs.accessSync(this.mapToBase(p), mode); - } - async accessPromise(p, mode) { - return this.baseFs.accessPromise(this.mapToBase(p), mode); - } - async statPromise(p, opts) { - return this.baseFs.statPromise(this.mapToBase(p), opts); - } - statSync(p, opts) { - return this.baseFs.statSync(this.mapToBase(p), opts); - } - async fstatPromise(fd, opts) { - return this.baseFs.fstatPromise(fd, opts); - } - fstatSync(fd, opts) { - return this.baseFs.fstatSync(fd, opts); - } - lstatPromise(p, opts) { - return this.baseFs.lstatPromise(this.mapToBase(p), opts); - } - lstatSync(p, opts) { - return this.baseFs.lstatSync(this.mapToBase(p), opts); - } - async fchmodPromise(fd, mask) { - return this.baseFs.fchmodPromise(fd, mask); - } - fchmodSync(fd, mask) { - return this.baseFs.fchmodSync(fd, mask); - } - async chmodPromise(p, mask) { - return this.baseFs.chmodPromise(this.mapToBase(p), mask); - } - chmodSync(p, mask) { - return this.baseFs.chmodSync(this.mapToBase(p), mask); - } - async fchownPromise(fd, uid, gid) { - return this.baseFs.fchownPromise(fd, uid, gid); - } - fchownSync(fd, uid, gid) { - return this.baseFs.fchownSync(fd, uid, gid); - } - async chownPromise(p, uid, gid) { - return this.baseFs.chownPromise(this.mapToBase(p), uid, gid); - } - chownSync(p, uid, gid) { - return this.baseFs.chownSync(this.mapToBase(p), uid, gid); - } - async renamePromise(oldP, newP) { - return this.baseFs.renamePromise(this.mapToBase(oldP), this.mapToBase(newP)); - } - renameSync(oldP, newP) { - return this.baseFs.renameSync(this.mapToBase(oldP), this.mapToBase(newP)); - } - async copyFilePromise(sourceP, destP, flags = 0) { - return this.baseFs.copyFilePromise(this.mapToBase(sourceP), this.mapToBase(destP), flags); - } - copyFileSync(sourceP, destP, flags = 0) { - return this.baseFs.copyFileSync(this.mapToBase(sourceP), this.mapToBase(destP), flags); - } - async appendFilePromise(p, content, opts) { - return this.baseFs.appendFilePromise(this.fsMapToBase(p), content, opts); - } - appendFileSync(p, content, opts) { - return this.baseFs.appendFileSync(this.fsMapToBase(p), content, opts); - } - async writeFilePromise(p, content, opts) { - return this.baseFs.writeFilePromise(this.fsMapToBase(p), content, opts); - } - writeFileSync(p, content, opts) { - return this.baseFs.writeFileSync(this.fsMapToBase(p), content, opts); - } - async unlinkPromise(p) { - return this.baseFs.unlinkPromise(this.mapToBase(p)); - } - unlinkSync(p) { - return this.baseFs.unlinkSync(this.mapToBase(p)); - } - async utimesPromise(p, atime, mtime) { - return this.baseFs.utimesPromise(this.mapToBase(p), atime, mtime); - } - utimesSync(p, atime, mtime) { - return this.baseFs.utimesSync(this.mapToBase(p), atime, mtime); - } - async mkdirPromise(p, opts) { - return this.baseFs.mkdirPromise(this.mapToBase(p), opts); - } - mkdirSync(p, opts) { - return this.baseFs.mkdirSync(this.mapToBase(p), opts); - } - async rmdirPromise(p, opts) { - return this.baseFs.rmdirPromise(this.mapToBase(p), opts); - } - rmdirSync(p, opts) { - return this.baseFs.rmdirSync(this.mapToBase(p), opts); - } - async linkPromise(existingP, newP) { - return this.baseFs.linkPromise(this.mapToBase(existingP), this.mapToBase(newP)); - } - linkSync(existingP, newP) { - return this.baseFs.linkSync(this.mapToBase(existingP), this.mapToBase(newP)); - } - async symlinkPromise(target, p, type) { - const mappedP = this.mapToBase(p); - if (this.pathUtils.isAbsolute(target)) - return this.baseFs.symlinkPromise(this.mapToBase(target), mappedP, type); - const mappedAbsoluteTarget = this.mapToBase(this.pathUtils.join(this.pathUtils.dirname(p), target)); - const mappedTarget = this.baseFs.pathUtils.relative(this.baseFs.pathUtils.dirname(mappedP), mappedAbsoluteTarget); - return this.baseFs.symlinkPromise(mappedTarget, mappedP, type); - } - symlinkSync(target, p, type) { - const mappedP = this.mapToBase(p); - if (this.pathUtils.isAbsolute(target)) - return this.baseFs.symlinkSync(this.mapToBase(target), mappedP, type); - const mappedAbsoluteTarget = this.mapToBase(this.pathUtils.join(this.pathUtils.dirname(p), target)); - const mappedTarget = this.baseFs.pathUtils.relative(this.baseFs.pathUtils.dirname(mappedP), mappedAbsoluteTarget); - return this.baseFs.symlinkSync(mappedTarget, mappedP, type); - } - async readFilePromise(p, encoding) { - if (encoding === `utf8`) { - return this.baseFs.readFilePromise(this.fsMapToBase(p), encoding); - } else { - return this.baseFs.readFilePromise(this.fsMapToBase(p), encoding); - } - } - readFileSync(p, encoding) { - if (encoding === `utf8`) { - return this.baseFs.readFileSync(this.fsMapToBase(p), encoding); - } else { - return this.baseFs.readFileSync(this.fsMapToBase(p), encoding); - } - } - async readdirPromise(p, opts) { - return this.baseFs.readdirPromise(this.mapToBase(p), opts); - } - readdirSync(p, opts) { - return this.baseFs.readdirSync(this.mapToBase(p), opts); - } - async readlinkPromise(p) { - return this.mapFromBase(await this.baseFs.readlinkPromise(this.mapToBase(p))); - } - readlinkSync(p) { - return this.mapFromBase(this.baseFs.readlinkSync(this.mapToBase(p))); - } - async truncatePromise(p, len) { - return this.baseFs.truncatePromise(this.mapToBase(p), len); - } - truncateSync(p, len) { - return this.baseFs.truncateSync(this.mapToBase(p), len); - } - async ftruncatePromise(fd, len) { - return this.baseFs.ftruncatePromise(fd, len); - } - ftruncateSync(fd, len) { - return this.baseFs.ftruncateSync(fd, len); - } - watch(p, a, b) { - return this.baseFs.watch( - this.mapToBase(p), - a, - b - ); - } - watchFile(p, a, b) { - return this.baseFs.watchFile( - this.mapToBase(p), - a, - b - ); - } - unwatchFile(p, cb) { - return this.baseFs.unwatchFile(this.mapToBase(p), cb); - } - fsMapToBase(p) { - if (typeof p === `number`) { - return p; - } else { - return this.mapToBase(p); - } - } -} - -const NUMBER_REGEXP = /^[0-9]+$/; -const VIRTUAL_REGEXP = /^(\/(?:[^/]+\/)*?(?:\$\$virtual|__virtual__))((?:\/((?:[^/]+-)?[a-f0-9]+)(?:\/([^/]+))?)?((?:\/.*)?))$/; -const VALID_COMPONENT = /^([^/]+-)?[a-f0-9]+$/; -class VirtualFS extends ProxiedFS { - constructor({ baseFs = new NodeFS() } = {}) { - super(ppath); - this.baseFs = baseFs; - } - static makeVirtualPath(base, component, to) { - if (ppath.basename(base) !== `__virtual__`) - throw new Error(`Assertion failed: Virtual folders must be named "__virtual__"`); - if (!ppath.basename(component).match(VALID_COMPONENT)) - throw new Error(`Assertion failed: Virtual components must be ended by an hexadecimal hash`); - const target = ppath.relative(ppath.dirname(base), to); - const segments = target.split(`/`); - let depth = 0; - while (depth < segments.length && segments[depth] === `..`) - depth += 1; - const finalSegments = segments.slice(depth); - const fullVirtualPath = ppath.join(base, component, String(depth), ...finalSegments); - return fullVirtualPath; - } - static resolveVirtual(p) { - const match = p.match(VIRTUAL_REGEXP); - if (!match || !match[3] && match[5]) - return p; - const target = ppath.dirname(match[1]); - if (!match[3] || !match[4]) - return target; - const isnum = NUMBER_REGEXP.test(match[4]); - if (!isnum) - return p; - const depth = Number(match[4]); - const backstep = `../`.repeat(depth); - const subpath = match[5] || `.`; - return VirtualFS.resolveVirtual(ppath.join(target, backstep, subpath)); - } - getExtractHint(hints) { - return this.baseFs.getExtractHint(hints); - } - getRealPath() { - return this.baseFs.getRealPath(); - } - realpathSync(p) { - const match = p.match(VIRTUAL_REGEXP); - if (!match) - return this.baseFs.realpathSync(p); - if (!match[5]) - return p; - const realpath = this.baseFs.realpathSync(this.mapToBase(p)); - return VirtualFS.makeVirtualPath(match[1], match[3], realpath); - } - async realpathPromise(p) { - const match = p.match(VIRTUAL_REGEXP); - if (!match) - return await this.baseFs.realpathPromise(p); - if (!match[5]) - return p; - const realpath = await this.baseFs.realpathPromise(this.mapToBase(p)); - return VirtualFS.makeVirtualPath(match[1], match[3], realpath); - } - mapToBase(p) { - if (p === ``) - return p; - if (this.pathUtils.isAbsolute(p)) - return VirtualFS.resolveVirtual(p); - const resolvedRoot = VirtualFS.resolveVirtual(this.baseFs.resolve(PortablePath.dot)); - const resolvedP = VirtualFS.resolveVirtual(this.baseFs.resolve(p)); - return ppath.relative(resolvedRoot, resolvedP) || PortablePath.dot; - } - mapFromBase(p) { - return p; - } -} - -const [major, minor] = process.versions.node.split(`.`).map((value) => parseInt(value, 10)); -const HAS_CONSOLIDATED_HOOKS = major > 16 || major === 16 && minor >= 12; -const HAS_UNFLAGGED_JSON_MODULES = major > 17 || major === 17 && minor >= 5 || major === 16 && minor >= 15; -const HAS_JSON_IMPORT_ASSERTION_REQUIREMENT = major > 17 || major === 17 && minor >= 1 || major === 16 && minor > 14; -const WATCH_MODE_MESSAGE_USES_ARRAYS = major > 19 || major === 19 && minor >= 2; - -const builtinModules = new Set(Module.builtinModules || Object.keys(process.binding(`natives`))); -const isBuiltinModule = (request) => request.startsWith(`node:`) || builtinModules.has(request); -function readPackageScope(checkPath) { - const rootSeparatorIndex = checkPath.indexOf(npath.sep); - let separatorIndex; - do { - separatorIndex = checkPath.lastIndexOf(npath.sep); - checkPath = checkPath.slice(0, separatorIndex); - if (checkPath.endsWith(`${npath.sep}node_modules`)) - return false; - const pjson = readPackage(checkPath + npath.sep); - if (pjson) { - return { - data: pjson, - path: checkPath - }; - } - } while (separatorIndex > rootSeparatorIndex); - return false; -} -function readPackage(requestPath) { - const jsonPath = npath.resolve(requestPath, `package.json`); - if (!fs.existsSync(jsonPath)) - return null; - return JSON.parse(fs.readFileSync(jsonPath, `utf8`)); -} - -async function tryReadFile$1(path2) { - try { - return await fs.promises.readFile(path2, `utf8`); - } catch (error) { - if (error.code === `ENOENT`) - return null; - throw error; - } -} -function tryParseURL(str, base) { - try { - return new URL$1(str, base); - } catch { - return null; - } -} -let entrypointPath = null; -function setEntrypointPath(file) { - entrypointPath = file; -} -function getFileFormat(filepath) { - var _a, _b; - const ext = path.extname(filepath); - switch (ext) { - case `.mjs`: { - return `module`; - } - case `.cjs`: { - return `commonjs`; - } - case `.wasm`: { - throw new Error( - `Unknown file extension ".wasm" for ${filepath}` - ); - } - case `.json`: { - if (HAS_UNFLAGGED_JSON_MODULES) - return `json`; - throw new Error( - `Unknown file extension ".json" for ${filepath}` - ); - } - case `.js`: { - const pkg = readPackageScope(filepath); - if (!pkg) - return `commonjs`; - return (_a = pkg.data.type) != null ? _a : `commonjs`; - } - default: { - if (entrypointPath !== filepath) - return null; - const pkg = readPackageScope(filepath); - if (!pkg) - return `commonjs`; - if (pkg.data.type === `module`) - return null; - return (_b = pkg.data.type) != null ? _b : `commonjs`; - } - } -} - -async function getFormat$1(resolved, context, defaultGetFormat) { - const url = tryParseURL(resolved); - if ((url == null ? void 0 : url.protocol) !== `file:`) - return defaultGetFormat(resolved, context, defaultGetFormat); - const format = getFileFormat(fileURLToPath(url)); - if (format) { - return { - format - }; - } - return defaultGetFormat(resolved, context, defaultGetFormat); -} - -async function getSource$1(urlString, context, defaultGetSource) { - const url = tryParseURL(urlString); - if ((url == null ? void 0 : url.protocol) !== `file:`) - return defaultGetSource(urlString, context, defaultGetSource); - return { - source: await fs.promises.readFile(fileURLToPath(url), `utf8`) - }; -} - -async function load$1(urlString, context, nextLoad) { - var _a; - const url = tryParseURL(urlString); - if ((url == null ? void 0 : url.protocol) !== `file:`) - return nextLoad(urlString, context, nextLoad); - const filePath = fileURLToPath(url); - const format = getFileFormat(filePath); - if (!format) - return nextLoad(urlString, context, nextLoad); - if (HAS_JSON_IMPORT_ASSERTION_REQUIREMENT && format === `json` && ((_a = context.importAssertions) == null ? void 0 : _a.type) !== `json`) { - const err = new TypeError(`[ERR_IMPORT_ASSERTION_TYPE_MISSING]: Module "${urlString}" needs an import assertion of type "json"`); - err.code = `ERR_IMPORT_ASSERTION_TYPE_MISSING`; - throw err; - } - if (process.env.WATCH_REPORT_DEPENDENCIES && process.send) { - const pathToSend = pathToFileURL( - npath.fromPortablePath( - VirtualFS.resolveVirtual(npath.toPortablePath(filePath)) - ) - ).href; - process.send({ - "watch:import": WATCH_MODE_MESSAGE_USES_ARRAYS ? [pathToSend] : pathToSend - }); - } - return { - format, - source: await fs.promises.readFile(filePath, `utf8`), - shortCircuit: true - }; -} - -const ArrayIsArray = Array.isArray; -const JSONStringify = JSON.stringify; -const ObjectGetOwnPropertyNames = Object.getOwnPropertyNames; -const ObjectPrototypeHasOwnProperty = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop); -const RegExpPrototypeExec = (obj, string) => RegExp.prototype.exec.call(obj, string); -const RegExpPrototypeSymbolReplace = (obj, ...rest) => RegExp.prototype[Symbol.replace].apply(obj, rest); -const StringPrototypeEndsWith = (str, ...rest) => String.prototype.endsWith.apply(str, rest); -const StringPrototypeIncludes = (str, ...rest) => String.prototype.includes.apply(str, rest); -const StringPrototypeLastIndexOf = (str, ...rest) => String.prototype.lastIndexOf.apply(str, rest); -const StringPrototypeIndexOf = (str, ...rest) => String.prototype.indexOf.apply(str, rest); -const StringPrototypeReplace = (str, ...rest) => String.prototype.replace.apply(str, rest); -const StringPrototypeSlice = (str, ...rest) => String.prototype.slice.apply(str, rest); -const StringPrototypeStartsWith = (str, ...rest) => String.prototype.startsWith.apply(str, rest); -const SafeMap = Map; -const JSONParse = JSON.parse; - -function createErrorType(code, messageCreator, errorType) { - return class extends errorType { - constructor(...args) { - super(messageCreator(...args)); - this.code = code; - this.name = `${errorType.name} [${code}]`; - } - }; -} -const ERR_PACKAGE_IMPORT_NOT_DEFINED = createErrorType( - `ERR_PACKAGE_IMPORT_NOT_DEFINED`, - (specifier, packagePath, base) => { - return `Package import specifier "${specifier}" is not defined${packagePath ? ` in package ${packagePath}package.json` : ``} imported from ${base}`; - }, - TypeError -); -const ERR_INVALID_MODULE_SPECIFIER = createErrorType( - `ERR_INVALID_MODULE_SPECIFIER`, - (request, reason, base = void 0) => { - return `Invalid module "${request}" ${reason}${base ? ` imported from ${base}` : ``}`; - }, - TypeError -); -const ERR_INVALID_PACKAGE_TARGET = createErrorType( - `ERR_INVALID_PACKAGE_TARGET`, - (pkgPath, key, target, isImport = false, base = void 0) => { - const relError = typeof target === `string` && !isImport && target.length && !StringPrototypeStartsWith(target, `./`); - if (key === `.`) { - assert(isImport === false); - return `Invalid "exports" main target ${JSONStringify(target)} defined in the package config ${pkgPath}package.json${base ? ` imported from ${base}` : ``}${relError ? `; targets must start with "./"` : ``}`; - } - return `Invalid "${isImport ? `imports` : `exports`}" target ${JSONStringify( - target - )} defined for '${key}' in the package config ${pkgPath}package.json${base ? ` imported from ${base}` : ``}${relError ? `; targets must start with "./"` : ``}`; - }, - Error -); -const ERR_INVALID_PACKAGE_CONFIG = createErrorType( - `ERR_INVALID_PACKAGE_CONFIG`, - (path, base, message) => { - return `Invalid package config ${path}${base ? ` while importing ${base}` : ``}${message ? `. ${message}` : ``}`; - }, - Error -); - -function filterOwnProperties(source, keys) { - const filtered = /* @__PURE__ */ Object.create(null); - for (let i = 0; i < keys.length; i++) { - const key = keys[i]; - if (ObjectPrototypeHasOwnProperty(source, key)) { - filtered[key] = source[key]; - } - } - return filtered; -} - -const packageJSONCache = new SafeMap(); -function getPackageConfig(path, specifier, base, readFileSyncFn) { - const existing = packageJSONCache.get(path); - if (existing !== void 0) { - return existing; - } - const source = readFileSyncFn(path); - if (source === void 0) { - const packageConfig2 = { - pjsonPath: path, - exists: false, - main: void 0, - name: void 0, - type: "none", - exports: void 0, - imports: void 0 - }; - packageJSONCache.set(path, packageConfig2); - return packageConfig2; - } - let packageJSON; - try { - packageJSON = JSONParse(source); - } catch (error) { - throw new ERR_INVALID_PACKAGE_CONFIG( - path, - (base ? `"${specifier}" from ` : "") + fileURLToPath(base || specifier), - error.message - ); - } - let { imports, main, name, type } = filterOwnProperties(packageJSON, [ - "imports", - "main", - "name", - "type" - ]); - const exports = ObjectPrototypeHasOwnProperty(packageJSON, "exports") ? packageJSON.exports : void 0; - if (typeof imports !== "object" || imports === null) { - imports = void 0; - } - if (typeof main !== "string") { - main = void 0; - } - if (typeof name !== "string") { - name = void 0; - } - if (type !== "module" && type !== "commonjs") { - type = "none"; - } - const packageConfig = { - pjsonPath: path, - exists: true, - main, - name, - type, - exports, - imports - }; - packageJSONCache.set(path, packageConfig); - return packageConfig; -} -function getPackageScopeConfig(resolved, readFileSyncFn) { - let packageJSONUrl = new URL("./package.json", resolved); - while (true) { - const packageJSONPath2 = packageJSONUrl.pathname; - if (StringPrototypeEndsWith(packageJSONPath2, "node_modules/package.json")) { - break; - } - const packageConfig2 = getPackageConfig( - fileURLToPath(packageJSONUrl), - resolved, - void 0, - readFileSyncFn - ); - if (packageConfig2.exists) { - return packageConfig2; - } - const lastPackageJSONUrl = packageJSONUrl; - packageJSONUrl = new URL("../package.json", packageJSONUrl); - if (packageJSONUrl.pathname === lastPackageJSONUrl.pathname) { - break; - } - } - const packageJSONPath = fileURLToPath(packageJSONUrl); - const packageConfig = { - pjsonPath: packageJSONPath, - exists: false, - main: void 0, - name: void 0, - type: "none", - exports: void 0, - imports: void 0 - }; - packageJSONCache.set(packageJSONPath, packageConfig); - return packageConfig; -} - -/** - @license - Copyright Node.js contributors. All rights reserved. - - 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. -*/ -function throwImportNotDefined(specifier, packageJSONUrl, base) { - throw new ERR_PACKAGE_IMPORT_NOT_DEFINED( - specifier, - packageJSONUrl && fileURLToPath(new URL(".", packageJSONUrl)), - fileURLToPath(base) - ); -} -function throwInvalidSubpath(subpath, packageJSONUrl, internal, base) { - const reason = `request is not a valid subpath for the "${internal ? "imports" : "exports"}" resolution of ${fileURLToPath(packageJSONUrl)}`; - throw new ERR_INVALID_MODULE_SPECIFIER( - subpath, - reason, - base && fileURLToPath(base) - ); -} -function throwInvalidPackageTarget(subpath, target, packageJSONUrl, internal, base) { - if (typeof target === "object" && target !== null) { - target = JSONStringify(target, null, ""); - } else { - target = `${target}`; - } - throw new ERR_INVALID_PACKAGE_TARGET( - fileURLToPath(new URL(".", packageJSONUrl)), - subpath, - target, - internal, - base && fileURLToPath(base) - ); -} -const invalidSegmentRegEx = /(^|\\|\/)((\.|%2e)(\.|%2e)?|(n|%6e|%4e)(o|%6f|%4f)(d|%64|%44)(e|%65|%45)(_|%5f)(m|%6d|%4d)(o|%6f|%4f)(d|%64|%44)(u|%75|%55)(l|%6c|%4c)(e|%65|%45)(s|%73|%53))(\\|\/|$)/i; -const patternRegEx = /\*/g; -function resolvePackageTargetString(target, subpath, match, packageJSONUrl, base, pattern, internal, conditions) { - if (subpath !== "" && !pattern && target[target.length - 1] !== "/") - throwInvalidPackageTarget(match, target, packageJSONUrl, internal, base); - if (!StringPrototypeStartsWith(target, "./")) { - if (internal && !StringPrototypeStartsWith(target, "../") && !StringPrototypeStartsWith(target, "/")) { - let isURL = false; - try { - new URL(target); - isURL = true; - } catch { - } - if (!isURL) { - const exportTarget = pattern ? RegExpPrototypeSymbolReplace(patternRegEx, target, () => subpath) : target + subpath; - return exportTarget; - } - } - throwInvalidPackageTarget(match, target, packageJSONUrl, internal, base); - } - if (RegExpPrototypeExec( - invalidSegmentRegEx, - StringPrototypeSlice(target, 2) - ) !== null) - throwInvalidPackageTarget(match, target, packageJSONUrl, internal, base); - const resolved = new URL(target, packageJSONUrl); - const resolvedPath = resolved.pathname; - const packagePath = new URL(".", packageJSONUrl).pathname; - if (!StringPrototypeStartsWith(resolvedPath, packagePath)) - throwInvalidPackageTarget(match, target, packageJSONUrl, internal, base); - if (subpath === "") - return resolved; - if (RegExpPrototypeExec(invalidSegmentRegEx, subpath) !== null) { - const request = pattern ? StringPrototypeReplace(match, "*", () => subpath) : match + subpath; - throwInvalidSubpath(request, packageJSONUrl, internal, base); - } - if (pattern) { - return new URL( - RegExpPrototypeSymbolReplace(patternRegEx, resolved.href, () => subpath) - ); - } - return new URL(subpath, resolved); -} -function isArrayIndex(key) { - const keyNum = +key; - if (`${keyNum}` !== key) - return false; - return keyNum >= 0 && keyNum < 4294967295; -} -function resolvePackageTarget(packageJSONUrl, target, subpath, packageSubpath, base, pattern, internal, conditions) { - if (typeof target === "string") { - return resolvePackageTargetString( - target, - subpath, - packageSubpath, - packageJSONUrl, - base, - pattern, - internal); - } else if (ArrayIsArray(target)) { - if (target.length === 0) { - return null; - } - let lastException; - for (let i = 0; i < target.length; i++) { - const targetItem = target[i]; - let resolveResult; - try { - resolveResult = resolvePackageTarget( - packageJSONUrl, - targetItem, - subpath, - packageSubpath, - base, - pattern, - internal, - conditions - ); - } catch (e) { - lastException = e; - if (e.code === "ERR_INVALID_PACKAGE_TARGET") { - continue; - } - throw e; - } - if (resolveResult === void 0) { - continue; - } - if (resolveResult === null) { - lastException = null; - continue; - } - return resolveResult; - } - if (lastException === void 0 || lastException === null) - return lastException; - throw lastException; - } else if (typeof target === "object" && target !== null) { - const keys = ObjectGetOwnPropertyNames(target); - for (let i = 0; i < keys.length; i++) { - const key = keys[i]; - if (isArrayIndex(key)) { - throw new ERR_INVALID_PACKAGE_CONFIG( - fileURLToPath(packageJSONUrl), - base, - '"exports" cannot contain numeric property keys.' - ); - } - } - for (let i = 0; i < keys.length; i++) { - const key = keys[i]; - if (key === "default" || conditions.has(key)) { - const conditionalTarget = target[key]; - const resolveResult = resolvePackageTarget( - packageJSONUrl, - conditionalTarget, - subpath, - packageSubpath, - base, - pattern, - internal, - conditions - ); - if (resolveResult === void 0) - continue; - return resolveResult; - } - } - return void 0; - } else if (target === null) { - return null; - } - throwInvalidPackageTarget( - packageSubpath, - target, - packageJSONUrl, - internal, - base - ); -} -function patternKeyCompare(a, b) { - const aPatternIndex = StringPrototypeIndexOf(a, "*"); - const bPatternIndex = StringPrototypeIndexOf(b, "*"); - const baseLenA = aPatternIndex === -1 ? a.length : aPatternIndex + 1; - const baseLenB = bPatternIndex === -1 ? b.length : bPatternIndex + 1; - if (baseLenA > baseLenB) - return -1; - if (baseLenB > baseLenA) - return 1; - if (aPatternIndex === -1) - return 1; - if (bPatternIndex === -1) - return -1; - if (a.length > b.length) - return -1; - if (b.length > a.length) - return 1; - return 0; -} -function packageImportsResolve({ - name, - base, - conditions, - readFileSyncFn -}) { - if (name === "#" || StringPrototypeStartsWith(name, "#/") || StringPrototypeEndsWith(name, "/")) { - const reason = "is not a valid internal imports specifier name"; - throw new ERR_INVALID_MODULE_SPECIFIER(name, reason, fileURLToPath(base)); - } - let packageJSONUrl; - const packageConfig = getPackageScopeConfig(base, readFileSyncFn); - if (packageConfig.exists) { - packageJSONUrl = pathToFileURL(packageConfig.pjsonPath); - const imports = packageConfig.imports; - if (imports) { - if (ObjectPrototypeHasOwnProperty(imports, name) && !StringPrototypeIncludes(name, "*")) { - const resolveResult = resolvePackageTarget( - packageJSONUrl, - imports[name], - "", - name, - base, - false, - true, - conditions - ); - if (resolveResult != null) { - return resolveResult; - } - } else { - let bestMatch = ""; - let bestMatchSubpath; - const keys = ObjectGetOwnPropertyNames(imports); - for (let i = 0; i < keys.length; i++) { - const key = keys[i]; - const patternIndex = StringPrototypeIndexOf(key, "*"); - if (patternIndex !== -1 && StringPrototypeStartsWith( - name, - StringPrototypeSlice(key, 0, patternIndex) - )) { - const patternTrailer = StringPrototypeSlice(key, patternIndex + 1); - if (name.length >= key.length && StringPrototypeEndsWith(name, patternTrailer) && patternKeyCompare(bestMatch, key) === 1 && StringPrototypeLastIndexOf(key, "*") === patternIndex) { - bestMatch = key; - bestMatchSubpath = StringPrototypeSlice( - name, - patternIndex, - name.length - patternTrailer.length - ); - } - } - } - if (bestMatch) { - const target = imports[bestMatch]; - const resolveResult = resolvePackageTarget( - packageJSONUrl, - target, - bestMatchSubpath, - bestMatch, - base, - true, - true, - conditions - ); - if (resolveResult != null) { - return resolveResult; - } - } - } - } - } - throwImportNotDefined(name, packageJSONUrl, base); -} - -const pathRegExp = /^(?![a-zA-Z]:[\\/]|\\\\|\.{0,2}(?:\/|$))((?:node:)?(?:@[^/]+\/)?[^/]+)\/*(.*|)$/; -const isRelativeRegexp = /^\.{0,2}\//; -function tryReadFile(filePath) { - try { - return fs.readFileSync(filePath, `utf8`); - } catch (err) { - if (err.code === `ENOENT`) - return void 0; - throw err; - } -} -async function resolvePrivateRequest(specifier, issuer, context, nextResolve) { - const resolved = packageImportsResolve({ - name: specifier, - base: pathToFileURL(issuer), - conditions: new Set(context.conditions), - readFileSyncFn: tryReadFile - }); - if (resolved instanceof URL) { - return { url: resolved.href, shortCircuit: true }; - } else { - if (resolved.startsWith(`#`)) - throw new Error(`Mapping from one private import to another isn't allowed`); - return resolve$1(resolved, context, nextResolve); - } -} -async function resolve$1(originalSpecifier, context, nextResolve) { - var _a; - const { findPnpApi } = moduleExports; - if (!findPnpApi || isBuiltinModule(originalSpecifier)) - return nextResolve(originalSpecifier, context, nextResolve); - let specifier = originalSpecifier; - const url = tryParseURL(specifier, isRelativeRegexp.test(specifier) ? context.parentURL : void 0); - if (url) { - if (url.protocol !== `file:`) - return nextResolve(originalSpecifier, context, nextResolve); - specifier = fileURLToPath(url); - } - const { parentURL, conditions = [] } = context; - const issuer = parentURL ? fileURLToPath(parentURL) : process.cwd(); - const pnpapi = (_a = findPnpApi(issuer)) != null ? _a : url ? findPnpApi(specifier) : null; - if (!pnpapi) - return nextResolve(originalSpecifier, context, nextResolve); - if (specifier.startsWith(`#`)) - return resolvePrivateRequest(specifier, issuer, context, nextResolve); - const dependencyNameMatch = specifier.match(pathRegExp); - let allowLegacyResolve = false; - if (dependencyNameMatch) { - const [, dependencyName, subPath] = dependencyNameMatch; - if (subPath === ``) { - const resolved = pnpapi.resolveToUnqualified(`${dependencyName}/package.json`, issuer); - if (resolved) { - const content = await tryReadFile$1(resolved); - if (content) { - const pkg = JSON.parse(content); - allowLegacyResolve = pkg.exports == null; - } - } - } - } - const result = pnpapi.resolveRequest(specifier, issuer, { - conditions: new Set(conditions), - extensions: allowLegacyResolve ? void 0 : [] - }); - if (!result) - throw new Error(`Resolving '${specifier}' from '${issuer}' failed`); - const resultURL = pathToFileURL(result); - if (url) { - resultURL.search = url.search; - resultURL.hash = url.hash; - } - if (!parentURL) - setEntrypointPath(fileURLToPath(resultURL)); - return { - url: resultURL.href, - shortCircuit: true - }; -} - -const binding = process.binding(`fs`); -const originalfstat = binding.fstat; -const ZIP_MASK = 4278190080; -const ZIP_MAGIC = 704643072; -binding.fstat = function(...args) { - const [fd, useBigint, req] = args; - if ((fd & ZIP_MASK) === ZIP_MAGIC && useBigint === false && req === void 0) { - try { - const stats = fs.fstatSync(fd); - return new Float64Array([ - stats.dev, - stats.mode, - stats.nlink, - stats.uid, - stats.gid, - stats.rdev, - stats.blksize, - stats.ino, - stats.size, - stats.blocks - ]); - } catch { - } - } - return originalfstat.apply(this, args); -}; - -const resolve = resolve$1; -const getFormat = HAS_CONSOLIDATED_HOOKS ? void 0 : getFormat$1; -const getSource = HAS_CONSOLIDATED_HOOKS ? void 0 : getSource$1; -const load = HAS_CONSOLIDATED_HOOKS ? load$1 : void 0; - -export { getFormat, getSource, load, resolve }; diff --git a/.yarn/cache/@eslint-community-eslint-utils-npm-4.4.0-d1791bd5a3-cdfe3ae42b.zip b/.yarn/cache/@eslint-community-eslint-utils-npm-4.4.0-d1791bd5a3-cdfe3ae42b.zip deleted file mode 100644 index 4e483570..00000000 Binary files a/.yarn/cache/@eslint-community-eslint-utils-npm-4.4.0-d1791bd5a3-cdfe3ae42b.zip and /dev/null differ diff --git a/.yarn/cache/@humanwhocodes-module-importer-npm-1.0.1-9d07ed2e4a-0fd22007db.zip b/.yarn/cache/@humanwhocodes-module-importer-npm-1.0.1-9d07ed2e4a-0fd22007db.zip deleted file mode 100644 index 7adb1e9f..00000000 Binary files a/.yarn/cache/@humanwhocodes-module-importer-npm-1.0.1-9d07ed2e4a-0fd22007db.zip and /dev/null differ diff --git a/.yarn/cache/@jridgewell-set-array-npm-1.1.2-45b82d7fb6-69a84d5980.zip b/.yarn/cache/@jridgewell-set-array-npm-1.1.2-45b82d7fb6-69a84d5980.zip deleted file mode 100644 index 3b901fc1..00000000 Binary files a/.yarn/cache/@jridgewell-set-array-npm-1.1.2-45b82d7fb6-69a84d5980.zip and /dev/null differ diff --git a/.yarn/cache/@nodelib-fs.scandir-npm-2.1.5-89c67370dd-a970d595bd.zip b/.yarn/cache/@nodelib-fs.scandir-npm-2.1.5-89c67370dd-a970d595bd.zip deleted file mode 100644 index 99f6bc1e..00000000 Binary files a/.yarn/cache/@nodelib-fs.scandir-npm-2.1.5-89c67370dd-a970d595bd.zip and /dev/null differ diff --git a/.yarn/cache/@nodelib-fs.stat-npm-2.0.5-01f4dd3030-012480b5ca.zip b/.yarn/cache/@nodelib-fs.stat-npm-2.0.5-01f4dd3030-012480b5ca.zip deleted file mode 100644 index e86d01e2..00000000 Binary files a/.yarn/cache/@nodelib-fs.stat-npm-2.0.5-01f4dd3030-012480b5ca.zip and /dev/null differ diff --git a/.yarn/cache/@nodelib-fs.walk-npm-1.2.8-b4a89da548-190c643f15.zip b/.yarn/cache/@nodelib-fs.walk-npm-1.2.8-b4a89da548-190c643f15.zip deleted file mode 100644 index 1750003a..00000000 Binary files a/.yarn/cache/@nodelib-fs.walk-npm-1.2.8-b4a89da548-190c643f15.zip and /dev/null differ diff --git a/.yarn/cache/@tootallnate-once-npm-2.0.0-e36cf4f140-ad87447820.zip b/.yarn/cache/@tootallnate-once-npm-2.0.0-e36cf4f140-ad87447820.zip deleted file mode 100644 index d240a82a..00000000 Binary files a/.yarn/cache/@tootallnate-once-npm-2.0.0-e36cf4f140-ad87447820.zip and /dev/null differ diff --git a/.yarn/cache/abbrev-npm-1.1.1-3659247eab-a4a97ec07d.zip b/.yarn/cache/abbrev-npm-1.1.1-3659247eab-a4a97ec07d.zip deleted file mode 100644 index a8b40a5f..00000000 Binary files a/.yarn/cache/abbrev-npm-1.1.1-3659247eab-a4a97ec07d.zip and /dev/null differ diff --git a/.yarn/cache/acorn-jsx-npm-5.3.2-d7594599ea-c3d3b2a89c.zip b/.yarn/cache/acorn-jsx-npm-5.3.2-d7594599ea-c3d3b2a89c.zip deleted file mode 100644 index 786b9ec4..00000000 Binary files a/.yarn/cache/acorn-jsx-npm-5.3.2-d7594599ea-c3d3b2a89c.zip and /dev/null differ diff --git a/.yarn/cache/agent-base-npm-6.0.2-428f325a93-f52b6872cc.zip b/.yarn/cache/agent-base-npm-6.0.2-428f325a93-f52b6872cc.zip deleted file mode 100644 index c7d271af..00000000 Binary files a/.yarn/cache/agent-base-npm-6.0.2-428f325a93-f52b6872cc.zip and /dev/null differ diff --git a/.yarn/cache/aggregate-error-npm-3.1.0-415a406f4e-1101a33f21.zip b/.yarn/cache/aggregate-error-npm-3.1.0-415a406f4e-1101a33f21.zip deleted file mode 100644 index 7db0127b..00000000 Binary files a/.yarn/cache/aggregate-error-npm-3.1.0-415a406f4e-1101a33f21.zip and /dev/null differ diff --git a/.yarn/cache/ajv-npm-6.12.6-4b5105e2b2-874972efe5.zip b/.yarn/cache/ajv-npm-6.12.6-4b5105e2b2-874972efe5.zip deleted file mode 100644 index 16973dd8..00000000 Binary files a/.yarn/cache/ajv-npm-6.12.6-4b5105e2b2-874972efe5.zip and /dev/null differ diff --git a/.yarn/cache/ansi-regex-npm-5.0.1-c963a48615-2aa4bb54ca.zip b/.yarn/cache/ansi-regex-npm-5.0.1-c963a48615-2aa4bb54ca.zip deleted file mode 100644 index fffc17ac..00000000 Binary files a/.yarn/cache/ansi-regex-npm-5.0.1-c963a48615-2aa4bb54ca.zip and /dev/null differ diff --git a/.yarn/cache/ansi-styles-npm-4.3.0-245c7d42c7-513b44c3b2.zip b/.yarn/cache/ansi-styles-npm-4.3.0-245c7d42c7-513b44c3b2.zip deleted file mode 100644 index a18e3e64..00000000 Binary files a/.yarn/cache/ansi-styles-npm-4.3.0-245c7d42c7-513b44c3b2.zip and /dev/null differ diff --git a/.yarn/cache/aproba-npm-2.0.0-8716bcfde6-5615cadcfb.zip b/.yarn/cache/aproba-npm-2.0.0-8716bcfde6-5615cadcfb.zip deleted file mode 100644 index 6b148888..00000000 Binary files a/.yarn/cache/aproba-npm-2.0.0-8716bcfde6-5615cadcfb.zip and /dev/null differ diff --git a/.yarn/cache/are-we-there-yet-npm-3.0.1-3395b1512f-52590c2486.zip b/.yarn/cache/are-we-there-yet-npm-3.0.1-3395b1512f-52590c2486.zip deleted file mode 100644 index 1f0af501..00000000 Binary files a/.yarn/cache/are-we-there-yet-npm-3.0.1-3395b1512f-52590c2486.zip and /dev/null differ diff --git a/.yarn/cache/argparse-npm-2.0.1-faff7999e6-83644b5649.zip b/.yarn/cache/argparse-npm-2.0.1-faff7999e6-83644b5649.zip deleted file mode 100644 index 26a9ce4a..00000000 Binary files a/.yarn/cache/argparse-npm-2.0.1-faff7999e6-83644b5649.zip and /dev/null differ diff --git a/.yarn/cache/brace-expansion-npm-1.1.11-fb95eb05ad-faf34a7bb0.zip b/.yarn/cache/brace-expansion-npm-1.1.11-fb95eb05ad-faf34a7bb0.zip deleted file mode 100644 index 9deab64a..00000000 Binary files a/.yarn/cache/brace-expansion-npm-1.1.11-fb95eb05ad-faf34a7bb0.zip and /dev/null differ diff --git a/.yarn/cache/brace-expansion-npm-2.0.1-17aa2616f9-a61e7cd2e8.zip b/.yarn/cache/brace-expansion-npm-2.0.1-17aa2616f9-a61e7cd2e8.zip deleted file mode 100644 index 11d5bd0d..00000000 Binary files a/.yarn/cache/brace-expansion-npm-2.0.1-17aa2616f9-a61e7cd2e8.zip and /dev/null differ diff --git a/.yarn/cache/callsites-npm-3.1.0-268f989910-072d17b6ab.zip b/.yarn/cache/callsites-npm-3.1.0-268f989910-072d17b6ab.zip deleted file mode 100644 index be6414c5..00000000 Binary files a/.yarn/cache/callsites-npm-3.1.0-268f989910-072d17b6ab.zip and /dev/null differ diff --git a/.yarn/cache/chalk-npm-4.1.2-ba8b67ab80-fe75c9d5c7.zip b/.yarn/cache/chalk-npm-4.1.2-ba8b67ab80-fe75c9d5c7.zip deleted file mode 100644 index 03d46b86..00000000 Binary files a/.yarn/cache/chalk-npm-4.1.2-ba8b67ab80-fe75c9d5c7.zip and /dev/null differ diff --git a/.yarn/cache/chownr-npm-2.0.0-638f1c9c61-c57cf9dd07.zip b/.yarn/cache/chownr-npm-2.0.0-638f1c9c61-c57cf9dd07.zip deleted file mode 100644 index e074b2f4..00000000 Binary files a/.yarn/cache/chownr-npm-2.0.0-638f1c9c61-c57cf9dd07.zip and /dev/null differ diff --git a/.yarn/cache/clean-stack-npm-2.2.0-a8ce435a5c-2ac8cd2b2f.zip b/.yarn/cache/clean-stack-npm-2.2.0-a8ce435a5c-2ac8cd2b2f.zip deleted file mode 100644 index c5109957..00000000 Binary files a/.yarn/cache/clean-stack-npm-2.2.0-a8ce435a5c-2ac8cd2b2f.zip and /dev/null differ diff --git a/.yarn/cache/color-convert-npm-2.0.1-79730e935b-79e6bdb9fd.zip b/.yarn/cache/color-convert-npm-2.0.1-79730e935b-79e6bdb9fd.zip deleted file mode 100644 index b3499adb..00000000 Binary files a/.yarn/cache/color-convert-npm-2.0.1-79730e935b-79e6bdb9fd.zip and /dev/null differ diff --git a/.yarn/cache/color-name-npm-1.1.4-025792b0ea-b044585952.zip b/.yarn/cache/color-name-npm-1.1.4-025792b0ea-b044585952.zip deleted file mode 100644 index ce1ffc4b..00000000 Binary files a/.yarn/cache/color-name-npm-1.1.4-025792b0ea-b044585952.zip and /dev/null differ diff --git a/.yarn/cache/color-support-npm-1.1.3-3be5c53455-9b73568176.zip b/.yarn/cache/color-support-npm-1.1.3-3be5c53455-9b73568176.zip deleted file mode 100644 index 625a79f1..00000000 Binary files a/.yarn/cache/color-support-npm-1.1.3-3be5c53455-9b73568176.zip and /dev/null differ diff --git a/.yarn/cache/commander-npm-2.20.3-d8dcbaa39b-ab8c07884e.zip b/.yarn/cache/commander-npm-2.20.3-d8dcbaa39b-ab8c07884e.zip deleted file mode 100644 index 6a14adf5..00000000 Binary files a/.yarn/cache/commander-npm-2.20.3-d8dcbaa39b-ab8c07884e.zip and /dev/null differ diff --git a/.yarn/cache/concat-map-npm-0.0.1-85a921b7ee-902a9f5d89.zip b/.yarn/cache/concat-map-npm-0.0.1-85a921b7ee-902a9f5d89.zip deleted file mode 100644 index 66b4c329..00000000 Binary files a/.yarn/cache/concat-map-npm-0.0.1-85a921b7ee-902a9f5d89.zip and /dev/null differ diff --git a/.yarn/cache/console-control-strings-npm-1.1.0-e3160e5275-8755d76787.zip b/.yarn/cache/console-control-strings-npm-1.1.0-e3160e5275-8755d76787.zip deleted file mode 100644 index a1f2fe66..00000000 Binary files a/.yarn/cache/console-control-strings-npm-1.1.0-e3160e5275-8755d76787.zip and /dev/null differ diff --git a/.yarn/cache/cross-spawn-npm-7.0.3-e4ff3e65b3-671cc7c728.zip b/.yarn/cache/cross-spawn-npm-7.0.3-e4ff3e65b3-671cc7c728.zip deleted file mode 100644 index 9613e383..00000000 Binary files a/.yarn/cache/cross-spawn-npm-7.0.3-e4ff3e65b3-671cc7c728.zip and /dev/null differ diff --git a/.yarn/cache/debug-npm-4.3.4-4513954577-3dbad3f94e.zip b/.yarn/cache/debug-npm-4.3.4-4513954577-3dbad3f94e.zip deleted file mode 100644 index d3a11d8e..00000000 Binary files a/.yarn/cache/debug-npm-4.3.4-4513954577-3dbad3f94e.zip and /dev/null differ diff --git a/.yarn/cache/deep-is-npm-0.1.4-88938b5a67-edb65dd0d7.zip b/.yarn/cache/deep-is-npm-0.1.4-88938b5a67-edb65dd0d7.zip deleted file mode 100644 index 2078a471..00000000 Binary files a/.yarn/cache/deep-is-npm-0.1.4-88938b5a67-edb65dd0d7.zip and /dev/null differ diff --git a/.yarn/cache/delegates-npm-1.0.0-9b1942d75f-a51744d9b5.zip b/.yarn/cache/delegates-npm-1.0.0-9b1942d75f-a51744d9b5.zip deleted file mode 100644 index 9921e5ec..00000000 Binary files a/.yarn/cache/delegates-npm-1.0.0-9b1942d75f-a51744d9b5.zip and /dev/null differ diff --git a/.yarn/cache/doctrine-npm-3.0.0-c6f1615f04-fd7673ca77.zip b/.yarn/cache/doctrine-npm-3.0.0-c6f1615f04-fd7673ca77.zip deleted file mode 100644 index 25e09031..00000000 Binary files a/.yarn/cache/doctrine-npm-3.0.0-c6f1615f04-fd7673ca77.zip and /dev/null differ diff --git a/.yarn/cache/emoji-regex-npm-8.0.0-213764015c-d4c5c39d5a.zip b/.yarn/cache/emoji-regex-npm-8.0.0-213764015c-d4c5c39d5a.zip deleted file mode 100644 index d02d8879..00000000 Binary files a/.yarn/cache/emoji-regex-npm-8.0.0-213764015c-d4c5c39d5a.zip and /dev/null differ diff --git a/.yarn/cache/encoding-npm-0.1.13-82a1837d30-bb98632f8f.zip b/.yarn/cache/encoding-npm-0.1.13-82a1837d30-bb98632f8f.zip deleted file mode 100644 index 202e9318..00000000 Binary files a/.yarn/cache/encoding-npm-0.1.13-82a1837d30-bb98632f8f.zip and /dev/null differ diff --git a/.yarn/cache/env-paths-npm-2.2.1-7c7577428c-65b5df55a8.zip b/.yarn/cache/env-paths-npm-2.2.1-7c7577428c-65b5df55a8.zip deleted file mode 100644 index 5fecf17a..00000000 Binary files a/.yarn/cache/env-paths-npm-2.2.1-7c7577428c-65b5df55a8.zip and /dev/null differ diff --git a/.yarn/cache/err-code-npm-2.0.3-082e0ff9a7-8b7b1be20d.zip b/.yarn/cache/err-code-npm-2.0.3-082e0ff9a7-8b7b1be20d.zip deleted file mode 100644 index 30585845..00000000 Binary files a/.yarn/cache/err-code-npm-2.0.3-082e0ff9a7-8b7b1be20d.zip and /dev/null differ diff --git a/.yarn/cache/escape-string-regexp-npm-4.0.0-4b531d8d59-98b48897d9.zip b/.yarn/cache/escape-string-regexp-npm-4.0.0-4b531d8d59-98b48897d9.zip deleted file mode 100644 index c23e416b..00000000 Binary files a/.yarn/cache/escape-string-regexp-npm-4.0.0-4b531d8d59-98b48897d9.zip and /dev/null differ diff --git a/.yarn/cache/esm-npm-3.2.25-762b3ebd40-978aabe2de.zip b/.yarn/cache/esm-npm-3.2.25-762b3ebd40-978aabe2de.zip deleted file mode 100644 index c1bfaf13..00000000 Binary files a/.yarn/cache/esm-npm-3.2.25-762b3ebd40-978aabe2de.zip and /dev/null differ diff --git a/.yarn/cache/esquery-npm-1.5.0-d8f8a06879-aefb0d2596.zip b/.yarn/cache/esquery-npm-1.5.0-d8f8a06879-aefb0d2596.zip deleted file mode 100644 index 6006b960..00000000 Binary files a/.yarn/cache/esquery-npm-1.5.0-d8f8a06879-aefb0d2596.zip and /dev/null differ diff --git a/.yarn/cache/esrecurse-npm-4.3.0-10b86a887a-ebc17b1a33.zip b/.yarn/cache/esrecurse-npm-4.3.0-10b86a887a-ebc17b1a33.zip deleted file mode 100644 index 97e67b46..00000000 Binary files a/.yarn/cache/esrecurse-npm-4.3.0-10b86a887a-ebc17b1a33.zip and /dev/null differ diff --git a/.yarn/cache/estraverse-npm-5.3.0-03284f8f63-072780882d.zip b/.yarn/cache/estraverse-npm-5.3.0-03284f8f63-072780882d.zip deleted file mode 100644 index eb7c3ccb..00000000 Binary files a/.yarn/cache/estraverse-npm-5.3.0-03284f8f63-072780882d.zip and /dev/null differ diff --git a/.yarn/cache/esutils-npm-2.0.3-f865beafd5-22b5b08f74.zip b/.yarn/cache/esutils-npm-2.0.3-f865beafd5-22b5b08f74.zip deleted file mode 100644 index c163c32a..00000000 Binary files a/.yarn/cache/esutils-npm-2.0.3-f865beafd5-22b5b08f74.zip and /dev/null differ diff --git a/.yarn/cache/fast-deep-equal-npm-3.1.3-790edcfcf5-e21a9d8d84.zip b/.yarn/cache/fast-deep-equal-npm-3.1.3-790edcfcf5-e21a9d8d84.zip deleted file mode 100644 index c0600899..00000000 Binary files a/.yarn/cache/fast-deep-equal-npm-3.1.3-790edcfcf5-e21a9d8d84.zip and /dev/null differ diff --git a/.yarn/cache/fast-json-stable-stringify-npm-2.1.0-02e8905fda-b191531e36.zip b/.yarn/cache/fast-json-stable-stringify-npm-2.1.0-02e8905fda-b191531e36.zip deleted file mode 100644 index 737d4761..00000000 Binary files a/.yarn/cache/fast-json-stable-stringify-npm-2.1.0-02e8905fda-b191531e36.zip and /dev/null differ diff --git a/.yarn/cache/fast-levenshtein-npm-2.0.6-fcd74b8df5-92cfec0a8d.zip b/.yarn/cache/fast-levenshtein-npm-2.0.6-fcd74b8df5-92cfec0a8d.zip deleted file mode 100644 index ffb76eb1..00000000 Binary files a/.yarn/cache/fast-levenshtein-npm-2.0.6-fcd74b8df5-92cfec0a8d.zip and /dev/null differ diff --git a/.yarn/cache/fastq-npm-1.15.0-1013f6514e-0170e6bfcd.zip b/.yarn/cache/fastq-npm-1.15.0-1013f6514e-0170e6bfcd.zip deleted file mode 100644 index fd84f16b..00000000 Binary files a/.yarn/cache/fastq-npm-1.15.0-1013f6514e-0170e6bfcd.zip and /dev/null differ diff --git a/.yarn/cache/file-entry-cache-npm-6.0.1-31965cf0af-f49701feaa.zip b/.yarn/cache/file-entry-cache-npm-6.0.1-31965cf0af-f49701feaa.zip deleted file mode 100644 index 3748d0b2..00000000 Binary files a/.yarn/cache/file-entry-cache-npm-6.0.1-31965cf0af-f49701feaa.zip and /dev/null differ diff --git a/.yarn/cache/find-up-npm-5.0.0-e03e9b796d-07955e3573.zip b/.yarn/cache/find-up-npm-5.0.0-e03e9b796d-07955e3573.zip deleted file mode 100644 index 034f3a07..00000000 Binary files a/.yarn/cache/find-up-npm-5.0.0-e03e9b796d-07955e3573.zip and /dev/null differ diff --git a/.yarn/cache/fs-minipass-npm-2.1.0-501ef87306-1b8d128dae.zip b/.yarn/cache/fs-minipass-npm-2.1.0-501ef87306-1b8d128dae.zip deleted file mode 100644 index 21a91aac..00000000 Binary files a/.yarn/cache/fs-minipass-npm-2.1.0-501ef87306-1b8d128dae.zip and /dev/null differ diff --git a/.yarn/cache/fs.realpath-npm-1.0.0-c8f05d8126-99ddea01a7.zip b/.yarn/cache/fs.realpath-npm-1.0.0-c8f05d8126-99ddea01a7.zip deleted file mode 100644 index 920c4cae..00000000 Binary files a/.yarn/cache/fs.realpath-npm-1.0.0-c8f05d8126-99ddea01a7.zip and /dev/null differ diff --git a/.yarn/cache/gauge-npm-4.0.4-8f878385e9-788b6bfe52.zip b/.yarn/cache/gauge-npm-4.0.4-8f878385e9-788b6bfe52.zip deleted file mode 100644 index ef82b873..00000000 Binary files a/.yarn/cache/gauge-npm-4.0.4-8f878385e9-788b6bfe52.zip and /dev/null differ diff --git a/.yarn/cache/glob-npm-7.2.3-2d866d17a5-29452e97b3.zip b/.yarn/cache/glob-npm-7.2.3-2d866d17a5-29452e97b3.zip deleted file mode 100644 index b2fa0ac3..00000000 Binary files a/.yarn/cache/glob-npm-7.2.3-2d866d17a5-29452e97b3.zip and /dev/null differ diff --git a/.yarn/cache/glob-parent-npm-6.0.2-2cbef12738-c13ee97978.zip b/.yarn/cache/glob-parent-npm-6.0.2-2cbef12738-c13ee97978.zip deleted file mode 100644 index 2a4d60d7..00000000 Binary files a/.yarn/cache/glob-parent-npm-6.0.2-2cbef12738-c13ee97978.zip and /dev/null differ diff --git a/.yarn/cache/has-flag-npm-4.0.0-32af9f0536-261a135703.zip b/.yarn/cache/has-flag-npm-4.0.0-32af9f0536-261a135703.zip deleted file mode 100644 index 6f5845da..00000000 Binary files a/.yarn/cache/has-flag-npm-4.0.0-32af9f0536-261a135703.zip and /dev/null differ diff --git a/.yarn/cache/has-unicode-npm-2.0.1-893adb4747-1eab07a743.zip b/.yarn/cache/has-unicode-npm-2.0.1-893adb4747-1eab07a743.zip deleted file mode 100644 index 5988a7e8..00000000 Binary files a/.yarn/cache/has-unicode-npm-2.0.1-893adb4747-1eab07a743.zip and /dev/null differ diff --git a/.yarn/cache/http-proxy-agent-npm-5.0.0-7f1f121b83-e2ee1ff165.zip b/.yarn/cache/http-proxy-agent-npm-5.0.0-7f1f121b83-e2ee1ff165.zip deleted file mode 100644 index a999ab7d..00000000 Binary files a/.yarn/cache/http-proxy-agent-npm-5.0.0-7f1f121b83-e2ee1ff165.zip and /dev/null differ diff --git a/.yarn/cache/https-proxy-agent-npm-5.0.1-42d65f358e-571fccdf38.zip b/.yarn/cache/https-proxy-agent-npm-5.0.1-42d65f358e-571fccdf38.zip deleted file mode 100644 index b8bc9949..00000000 Binary files a/.yarn/cache/https-proxy-agent-npm-5.0.1-42d65f358e-571fccdf38.zip and /dev/null differ diff --git a/.yarn/cache/humanize-ms-npm-1.2.1-e942bd7329-9c7a74a282.zip b/.yarn/cache/humanize-ms-npm-1.2.1-e942bd7329-9c7a74a282.zip deleted file mode 100644 index c09856b3..00000000 Binary files a/.yarn/cache/humanize-ms-npm-1.2.1-e942bd7329-9c7a74a282.zip and /dev/null differ diff --git a/.yarn/cache/iconv-lite-npm-0.6.3-24b8aae27e-3f60d47a5c.zip b/.yarn/cache/iconv-lite-npm-0.6.3-24b8aae27e-3f60d47a5c.zip deleted file mode 100644 index f3f767a2..00000000 Binary files a/.yarn/cache/iconv-lite-npm-0.6.3-24b8aae27e-3f60d47a5c.zip and /dev/null differ diff --git a/.yarn/cache/ignore-npm-5.2.4-fbe6e989e5-3d4c309c60.zip b/.yarn/cache/ignore-npm-5.2.4-fbe6e989e5-3d4c309c60.zip deleted file mode 100644 index 50627d8e..00000000 Binary files a/.yarn/cache/ignore-npm-5.2.4-fbe6e989e5-3d4c309c60.zip and /dev/null differ diff --git a/.yarn/cache/import-fresh-npm-3.3.0-3e34265ca9-2cacfad06e.zip b/.yarn/cache/import-fresh-npm-3.3.0-3e34265ca9-2cacfad06e.zip deleted file mode 100644 index 318d7b84..00000000 Binary files a/.yarn/cache/import-fresh-npm-3.3.0-3e34265ca9-2cacfad06e.zip and /dev/null differ diff --git a/.yarn/cache/imurmurhash-npm-0.1.4-610c5068a0-7cae75c8cd.zip b/.yarn/cache/imurmurhash-npm-0.1.4-610c5068a0-7cae75c8cd.zip deleted file mode 100644 index 9ddf4f88..00000000 Binary files a/.yarn/cache/imurmurhash-npm-0.1.4-610c5068a0-7cae75c8cd.zip and /dev/null differ diff --git a/.yarn/cache/indent-string-npm-4.0.0-7b717435b2-824cfb9929.zip b/.yarn/cache/indent-string-npm-4.0.0-7b717435b2-824cfb9929.zip deleted file mode 100644 index eedfdb0f..00000000 Binary files a/.yarn/cache/indent-string-npm-4.0.0-7b717435b2-824cfb9929.zip and /dev/null differ diff --git a/.yarn/cache/inflight-npm-1.0.6-ccedb4b908-f4f76aa072.zip b/.yarn/cache/inflight-npm-1.0.6-ccedb4b908-f4f76aa072.zip deleted file mode 100644 index c5a4bb07..00000000 Binary files a/.yarn/cache/inflight-npm-1.0.6-ccedb4b908-f4f76aa072.zip and /dev/null differ diff --git a/.yarn/cache/inherits-npm-2.0.4-c66b3957a0-4a48a73384.zip b/.yarn/cache/inherits-npm-2.0.4-c66b3957a0-4a48a73384.zip deleted file mode 100644 index 62c31cb7..00000000 Binary files a/.yarn/cache/inherits-npm-2.0.4-c66b3957a0-4a48a73384.zip and /dev/null differ diff --git a/.yarn/cache/ip-npm-2.0.0-204facb3cc-cfcfac6b87.zip b/.yarn/cache/ip-npm-2.0.0-204facb3cc-cfcfac6b87.zip deleted file mode 100644 index 0aad8938..00000000 Binary files a/.yarn/cache/ip-npm-2.0.0-204facb3cc-cfcfac6b87.zip and /dev/null differ diff --git a/.yarn/cache/is-extglob-npm-2.1.1-0870ea68b5-df033653d0.zip b/.yarn/cache/is-extglob-npm-2.1.1-0870ea68b5-df033653d0.zip deleted file mode 100644 index 0acbc56e..00000000 Binary files a/.yarn/cache/is-extglob-npm-2.1.1-0870ea68b5-df033653d0.zip and /dev/null differ diff --git a/.yarn/cache/is-fullwidth-code-point-npm-3.0.0-1ecf4ebee5-44a30c2945.zip b/.yarn/cache/is-fullwidth-code-point-npm-3.0.0-1ecf4ebee5-44a30c2945.zip deleted file mode 100644 index dccc80a9..00000000 Binary files a/.yarn/cache/is-fullwidth-code-point-npm-3.0.0-1ecf4ebee5-44a30c2945.zip and /dev/null differ diff --git a/.yarn/cache/is-glob-npm-4.0.3-cb87bf1bdb-d381c1319f.zip b/.yarn/cache/is-glob-npm-4.0.3-cb87bf1bdb-d381c1319f.zip deleted file mode 100644 index 52274ed2..00000000 Binary files a/.yarn/cache/is-glob-npm-4.0.3-cb87bf1bdb-d381c1319f.zip and /dev/null differ diff --git a/.yarn/cache/is-lambda-npm-1.0.1-7ab55bc8a8-93a32f0194.zip b/.yarn/cache/is-lambda-npm-1.0.1-7ab55bc8a8-93a32f0194.zip deleted file mode 100644 index f981b1be..00000000 Binary files a/.yarn/cache/is-lambda-npm-1.0.1-7ab55bc8a8-93a32f0194.zip and /dev/null differ diff --git a/.yarn/cache/is-path-inside-npm-3.0.3-2ea0ef44fd-abd50f0618.zip b/.yarn/cache/is-path-inside-npm-3.0.3-2ea0ef44fd-abd50f0618.zip deleted file mode 100644 index 27f29d70..00000000 Binary files a/.yarn/cache/is-path-inside-npm-3.0.3-2ea0ef44fd-abd50f0618.zip and /dev/null differ diff --git a/.yarn/cache/isexe-npm-2.0.0-b58870bd2e-26bf6c5480.zip b/.yarn/cache/isexe-npm-2.0.0-b58870bd2e-26bf6c5480.zip deleted file mode 100644 index 077597d6..00000000 Binary files a/.yarn/cache/isexe-npm-2.0.0-b58870bd2e-26bf6c5480.zip and /dev/null differ diff --git a/.yarn/cache/js-yaml-npm-4.1.0-3606f32312-c7830dfd45.zip b/.yarn/cache/js-yaml-npm-4.1.0-3606f32312-c7830dfd45.zip deleted file mode 100644 index 659c85d0..00000000 Binary files a/.yarn/cache/js-yaml-npm-4.1.0-3606f32312-c7830dfd45.zip and /dev/null differ diff --git a/.yarn/cache/json-schema-traverse-npm-0.4.1-4759091693-7486074d3b.zip b/.yarn/cache/json-schema-traverse-npm-0.4.1-4759091693-7486074d3b.zip deleted file mode 100644 index 54f0a7ac..00000000 Binary files a/.yarn/cache/json-schema-traverse-npm-0.4.1-4759091693-7486074d3b.zip and /dev/null differ diff --git a/.yarn/cache/json-stable-stringify-without-jsonify-npm-1.0.1-b65772b28b-cff44156dd.zip b/.yarn/cache/json-stable-stringify-without-jsonify-npm-1.0.1-b65772b28b-cff44156dd.zip deleted file mode 100644 index 47d58522..00000000 Binary files a/.yarn/cache/json-stable-stringify-without-jsonify-npm-1.0.1-b65772b28b-cff44156dd.zip and /dev/null differ diff --git a/.yarn/cache/levn-npm-0.4.1-d183b2d7bb-12c5021c85.zip b/.yarn/cache/levn-npm-0.4.1-d183b2d7bb-12c5021c85.zip deleted file mode 100644 index dda4d01a..00000000 Binary files a/.yarn/cache/levn-npm-0.4.1-d183b2d7bb-12c5021c85.zip and /dev/null differ diff --git a/.yarn/cache/locate-path-npm-6.0.0-06a1e4c528-72eb661788.zip b/.yarn/cache/locate-path-npm-6.0.0-06a1e4c528-72eb661788.zip deleted file mode 100644 index b67b7744..00000000 Binary files a/.yarn/cache/locate-path-npm-6.0.0-06a1e4c528-72eb661788.zip and /dev/null differ diff --git a/.yarn/cache/lodash.merge-npm-4.6.2-77cb4416bf-ad580b4bdb.zip b/.yarn/cache/lodash.merge-npm-4.6.2-77cb4416bf-ad580b4bdb.zip deleted file mode 100644 index f6bc72b4..00000000 Binary files a/.yarn/cache/lodash.merge-npm-4.6.2-77cb4416bf-ad580b4bdb.zip and /dev/null differ diff --git a/.yarn/cache/lru-cache-npm-6.0.0-b4c8668fe1-f97f499f89.zip b/.yarn/cache/lru-cache-npm-6.0.0-b4c8668fe1-f97f499f89.zip deleted file mode 100644 index 1635dac9..00000000 Binary files a/.yarn/cache/lru-cache-npm-6.0.0-b4c8668fe1-f97f499f89.zip and /dev/null differ diff --git a/.yarn/cache/minimatch-npm-3.1.2-9405269906-c154e56640.zip b/.yarn/cache/minimatch-npm-3.1.2-9405269906-c154e56640.zip deleted file mode 100644 index ba0c5104..00000000 Binary files a/.yarn/cache/minimatch-npm-3.1.2-9405269906-c154e56640.zip and /dev/null differ diff --git a/.yarn/cache/minipass-collect-npm-1.0.2-3b4676eab5-14df761028.zip b/.yarn/cache/minipass-collect-npm-1.0.2-3b4676eab5-14df761028.zip deleted file mode 100644 index 582f61ca..00000000 Binary files a/.yarn/cache/minipass-collect-npm-1.0.2-3b4676eab5-14df761028.zip and /dev/null differ diff --git a/.yarn/cache/minipass-flush-npm-1.0.5-efe79d9826-56269a0b22.zip b/.yarn/cache/minipass-flush-npm-1.0.5-efe79d9826-56269a0b22.zip deleted file mode 100644 index 913b687a..00000000 Binary files a/.yarn/cache/minipass-flush-npm-1.0.5-efe79d9826-56269a0b22.zip and /dev/null differ diff --git a/.yarn/cache/minipass-pipeline-npm-1.2.4-5924cb077f-b14240dac0.zip b/.yarn/cache/minipass-pipeline-npm-1.2.4-5924cb077f-b14240dac0.zip deleted file mode 100644 index 4deae416..00000000 Binary files a/.yarn/cache/minipass-pipeline-npm-1.2.4-5924cb077f-b14240dac0.zip and /dev/null differ diff --git a/.yarn/cache/minipass-sized-npm-1.0.3-306d86f432-79076749fc.zip b/.yarn/cache/minipass-sized-npm-1.0.3-306d86f432-79076749fc.zip deleted file mode 100644 index b6f4644f..00000000 Binary files a/.yarn/cache/minipass-sized-npm-1.0.3-306d86f432-79076749fc.zip and /dev/null differ diff --git a/.yarn/cache/minizlib-npm-2.1.2-ea89cd0cfb-f1fdeac0b0.zip b/.yarn/cache/minizlib-npm-2.1.2-ea89cd0cfb-f1fdeac0b0.zip deleted file mode 100644 index efb1b7f6..00000000 Binary files a/.yarn/cache/minizlib-npm-2.1.2-ea89cd0cfb-f1fdeac0b0.zip and /dev/null differ diff --git a/.yarn/cache/mkdirp-npm-1.0.4-37f6ef56b9-a96865108c.zip b/.yarn/cache/mkdirp-npm-1.0.4-37f6ef56b9-a96865108c.zip deleted file mode 100644 index 4625e914..00000000 Binary files a/.yarn/cache/mkdirp-npm-1.0.4-37f6ef56b9-a96865108c.zip and /dev/null differ diff --git a/.yarn/cache/ms-npm-2.1.2-ec0c1512ff-673cdb2c31.zip b/.yarn/cache/ms-npm-2.1.2-ec0c1512ff-673cdb2c31.zip deleted file mode 100644 index 725e9b8c..00000000 Binary files a/.yarn/cache/ms-npm-2.1.2-ec0c1512ff-673cdb2c31.zip and /dev/null differ diff --git a/.yarn/cache/ms-npm-2.1.3-81ff3cfac1-aa92de6080.zip b/.yarn/cache/ms-npm-2.1.3-81ff3cfac1-aa92de6080.zip deleted file mode 100644 index 2b635f28..00000000 Binary files a/.yarn/cache/ms-npm-2.1.3-81ff3cfac1-aa92de6080.zip and /dev/null differ diff --git a/.yarn/cache/natural-compare-npm-1.4.0-97b75b362d-23ad088b08.zip b/.yarn/cache/natural-compare-npm-1.4.0-97b75b362d-23ad088b08.zip deleted file mode 100644 index db454c31..00000000 Binary files a/.yarn/cache/natural-compare-npm-1.4.0-97b75b362d-23ad088b08.zip and /dev/null differ diff --git a/.yarn/cache/negotiator-npm-0.6.3-9d50e36171-b8ffeb1e26.zip b/.yarn/cache/negotiator-npm-0.6.3-9d50e36171-b8ffeb1e26.zip deleted file mode 100644 index e8c5cf48..00000000 Binary files a/.yarn/cache/negotiator-npm-0.6.3-9d50e36171-b8ffeb1e26.zip and /dev/null differ diff --git a/.yarn/cache/npmlog-npm-6.0.2-e0e69455c7-ae238cd264.zip b/.yarn/cache/npmlog-npm-6.0.2-e0e69455c7-ae238cd264.zip deleted file mode 100644 index a7bb4a7d..00000000 Binary files a/.yarn/cache/npmlog-npm-6.0.2-e0e69455c7-ae238cd264.zip and /dev/null differ diff --git a/.yarn/cache/once-npm-1.4.0-ccf03ef07a-cd0a885013.zip b/.yarn/cache/once-npm-1.4.0-ccf03ef07a-cd0a885013.zip deleted file mode 100644 index 1b943eec..00000000 Binary files a/.yarn/cache/once-npm-1.4.0-ccf03ef07a-cd0a885013.zip and /dev/null differ diff --git a/.yarn/cache/p-limit-npm-3.1.0-05d2ede37f-7c3690c4db.zip b/.yarn/cache/p-limit-npm-3.1.0-05d2ede37f-7c3690c4db.zip deleted file mode 100644 index b87d97cc..00000000 Binary files a/.yarn/cache/p-limit-npm-3.1.0-05d2ede37f-7c3690c4db.zip and /dev/null differ diff --git a/.yarn/cache/p-locate-npm-5.0.0-92cc7c7a3e-1623088f36.zip b/.yarn/cache/p-locate-npm-5.0.0-92cc7c7a3e-1623088f36.zip deleted file mode 100644 index 077f1c6e..00000000 Binary files a/.yarn/cache/p-locate-npm-5.0.0-92cc7c7a3e-1623088f36.zip and /dev/null differ diff --git a/.yarn/cache/p-map-npm-4.0.0-4677ae07c7-cb0ab21ec0.zip b/.yarn/cache/p-map-npm-4.0.0-4677ae07c7-cb0ab21ec0.zip deleted file mode 100644 index 092fe42f..00000000 Binary files a/.yarn/cache/p-map-npm-4.0.0-4677ae07c7-cb0ab21ec0.zip and /dev/null differ diff --git a/.yarn/cache/parent-module-npm-1.0.1-1fae11b095-6ba8b25514.zip b/.yarn/cache/parent-module-npm-1.0.1-1fae11b095-6ba8b25514.zip deleted file mode 100644 index 5b900e17..00000000 Binary files a/.yarn/cache/parent-module-npm-1.0.1-1fae11b095-6ba8b25514.zip and /dev/null differ diff --git a/.yarn/cache/path-exists-npm-4.0.0-e9e4f63eb0-505807199d.zip b/.yarn/cache/path-exists-npm-4.0.0-e9e4f63eb0-505807199d.zip deleted file mode 100644 index b5048416..00000000 Binary files a/.yarn/cache/path-exists-npm-4.0.0-e9e4f63eb0-505807199d.zip and /dev/null differ diff --git a/.yarn/cache/path-is-absolute-npm-1.0.1-31bc695ffd-060840f92c.zip b/.yarn/cache/path-is-absolute-npm-1.0.1-31bc695ffd-060840f92c.zip deleted file mode 100644 index ce195de7..00000000 Binary files a/.yarn/cache/path-is-absolute-npm-1.0.1-31bc695ffd-060840f92c.zip and /dev/null differ diff --git a/.yarn/cache/path-key-npm-3.1.1-0e66ea8321-55cd7a9dd4.zip b/.yarn/cache/path-key-npm-3.1.1-0e66ea8321-55cd7a9dd4.zip deleted file mode 100644 index dd7212e2..00000000 Binary files a/.yarn/cache/path-key-npm-3.1.1-0e66ea8321-55cd7a9dd4.zip and /dev/null differ diff --git a/.yarn/cache/prelude-ls-npm-1.2.1-3e4d272a55-cd192ec0d0.zip b/.yarn/cache/prelude-ls-npm-1.2.1-3e4d272a55-cd192ec0d0.zip deleted file mode 100644 index 38e79691..00000000 Binary files a/.yarn/cache/prelude-ls-npm-1.2.1-3e4d272a55-cd192ec0d0.zip and /dev/null differ diff --git a/.yarn/cache/promise-retry-npm-2.0.1-871f0b01b7-f96a3f6d90.zip b/.yarn/cache/promise-retry-npm-2.0.1-871f0b01b7-f96a3f6d90.zip deleted file mode 100644 index 9cefe077..00000000 Binary files a/.yarn/cache/promise-retry-npm-2.0.1-871f0b01b7-f96a3f6d90.zip and /dev/null differ diff --git a/.yarn/cache/punycode-npm-2.3.0-df4bdce06b-39f760e09a.zip b/.yarn/cache/punycode-npm-2.3.0-df4bdce06b-39f760e09a.zip deleted file mode 100644 index 0ad5b4fe..00000000 Binary files a/.yarn/cache/punycode-npm-2.3.0-df4bdce06b-39f760e09a.zip and /dev/null differ diff --git a/.yarn/cache/queue-microtask-npm-1.2.3-fcc98e4e2d-b676f8c040.zip b/.yarn/cache/queue-microtask-npm-1.2.3-fcc98e4e2d-b676f8c040.zip deleted file mode 100644 index 31453282..00000000 Binary files a/.yarn/cache/queue-microtask-npm-1.2.3-fcc98e4e2d-b676f8c040.zip and /dev/null differ diff --git a/.yarn/cache/resolve-from-npm-4.0.0-f758ec21bf-f4ba0b8494.zip b/.yarn/cache/resolve-from-npm-4.0.0-f758ec21bf-f4ba0b8494.zip deleted file mode 100644 index 86f591e3..00000000 Binary files a/.yarn/cache/resolve-from-npm-4.0.0-f758ec21bf-f4ba0b8494.zip and /dev/null differ diff --git a/.yarn/cache/retry-npm-0.12.0-72ac7fb4cc-623bd7d2e5.zip b/.yarn/cache/retry-npm-0.12.0-72ac7fb4cc-623bd7d2e5.zip deleted file mode 100644 index 12e25fcd..00000000 Binary files a/.yarn/cache/retry-npm-0.12.0-72ac7fb4cc-623bd7d2e5.zip and /dev/null differ diff --git a/.yarn/cache/reusify-npm-1.0.4-95ac4aec11-c3076ebcc2.zip b/.yarn/cache/reusify-npm-1.0.4-95ac4aec11-c3076ebcc2.zip deleted file mode 100644 index 595aa09a..00000000 Binary files a/.yarn/cache/reusify-npm-1.0.4-95ac4aec11-c3076ebcc2.zip and /dev/null differ diff --git a/.yarn/cache/rimraf-npm-3.0.2-2cb7dac69a-87f4164e39.zip b/.yarn/cache/rimraf-npm-3.0.2-2cb7dac69a-87f4164e39.zip deleted file mode 100644 index 6d2f5410..00000000 Binary files a/.yarn/cache/rimraf-npm-3.0.2-2cb7dac69a-87f4164e39.zip and /dev/null differ diff --git a/.yarn/cache/run-parallel-npm-1.2.0-3f47ff2034-cb4f97ad25.zip b/.yarn/cache/run-parallel-npm-1.2.0-3f47ff2034-cb4f97ad25.zip deleted file mode 100644 index fefbad56..00000000 Binary files a/.yarn/cache/run-parallel-npm-1.2.0-3f47ff2034-cb4f97ad25.zip and /dev/null differ diff --git a/.yarn/cache/safe-buffer-npm-5.2.1-3481c8aa9b-b99c4b41fd.zip b/.yarn/cache/safe-buffer-npm-5.2.1-3481c8aa9b-b99c4b41fd.zip deleted file mode 100644 index c80798ae..00000000 Binary files a/.yarn/cache/safe-buffer-npm-5.2.1-3481c8aa9b-b99c4b41fd.zip and /dev/null differ diff --git a/.yarn/cache/safer-buffer-npm-2.1.2-8d5c0b705e-cab8f25ae6.zip b/.yarn/cache/safer-buffer-npm-2.1.2-8d5c0b705e-cab8f25ae6.zip deleted file mode 100644 index 1a93be64..00000000 Binary files a/.yarn/cache/safer-buffer-npm-2.1.2-8d5c0b705e-cab8f25ae6.zip and /dev/null differ diff --git a/.yarn/cache/set-blocking-npm-2.0.0-49e2cffa24-6e65a05f7c.zip b/.yarn/cache/set-blocking-npm-2.0.0-49e2cffa24-6e65a05f7c.zip deleted file mode 100644 index fe99c6f4..00000000 Binary files a/.yarn/cache/set-blocking-npm-2.0.0-49e2cffa24-6e65a05f7c.zip and /dev/null differ diff --git a/.yarn/cache/shebang-command-npm-2.0.0-eb2b01921d-6b52fe8727.zip b/.yarn/cache/shebang-command-npm-2.0.0-eb2b01921d-6b52fe8727.zip deleted file mode 100644 index 727c5471..00000000 Binary files a/.yarn/cache/shebang-command-npm-2.0.0-eb2b01921d-6b52fe8727.zip and /dev/null differ diff --git a/.yarn/cache/shebang-regex-npm-3.0.0-899a0cd65e-1a2bcae50d.zip b/.yarn/cache/shebang-regex-npm-3.0.0-899a0cd65e-1a2bcae50d.zip deleted file mode 100644 index 3e891cda..00000000 Binary files a/.yarn/cache/shebang-regex-npm-3.0.0-899a0cd65e-1a2bcae50d.zip and /dev/null differ diff --git a/.yarn/cache/signal-exit-npm-3.0.7-bd270458a3-a2f098f247.zip b/.yarn/cache/signal-exit-npm-3.0.7-bd270458a3-a2f098f247.zip deleted file mode 100644 index 98720bd8..00000000 Binary files a/.yarn/cache/signal-exit-npm-3.0.7-bd270458a3-a2f098f247.zip and /dev/null differ diff --git a/.yarn/cache/smart-buffer-npm-4.2.0-5ac3f668bb-b5167a7142.zip b/.yarn/cache/smart-buffer-npm-4.2.0-5ac3f668bb-b5167a7142.zip deleted file mode 100644 index d587b3db..00000000 Binary files a/.yarn/cache/smart-buffer-npm-4.2.0-5ac3f668bb-b5167a7142.zip and /dev/null differ diff --git a/.yarn/cache/socks-proxy-agent-npm-7.0.0-7aacf32ea0-7205543701.zip b/.yarn/cache/socks-proxy-agent-npm-7.0.0-7aacf32ea0-7205543701.zip deleted file mode 100644 index 4be1d89c..00000000 Binary files a/.yarn/cache/socks-proxy-agent-npm-7.0.0-7aacf32ea0-7205543701.zip and /dev/null differ diff --git a/.yarn/cache/source-map-npm-0.6.1-1a3621db16-59ce8640cf.zip b/.yarn/cache/source-map-npm-0.6.1-1a3621db16-59ce8640cf.zip deleted file mode 100644 index 5f6c0e46..00000000 Binary files a/.yarn/cache/source-map-npm-0.6.1-1a3621db16-59ce8640cf.zip and /dev/null differ diff --git a/.yarn/cache/source-map-support-npm-0.5.21-09ca99e250-43e98d700d.zip b/.yarn/cache/source-map-support-npm-0.5.21-09ca99e250-43e98d700d.zip deleted file mode 100644 index 5fc27c84..00000000 Binary files a/.yarn/cache/source-map-support-npm-0.5.21-09ca99e250-43e98d700d.zip and /dev/null differ diff --git a/.yarn/cache/string-width-npm-4.2.3-2c27177bae-e52c10dc3f.zip b/.yarn/cache/string-width-npm-4.2.3-2c27177bae-e52c10dc3f.zip deleted file mode 100644 index 9b4c0881..00000000 Binary files a/.yarn/cache/string-width-npm-4.2.3-2c27177bae-e52c10dc3f.zip and /dev/null differ diff --git a/.yarn/cache/string_decoder-npm-1.3.0-2422117fd0-8417646695.zip b/.yarn/cache/string_decoder-npm-1.3.0-2422117fd0-8417646695.zip deleted file mode 100644 index e12cf759..00000000 Binary files a/.yarn/cache/string_decoder-npm-1.3.0-2422117fd0-8417646695.zip and /dev/null differ diff --git a/.yarn/cache/strip-ansi-npm-6.0.1-caddc7cb40-f3cd25890a.zip b/.yarn/cache/strip-ansi-npm-6.0.1-caddc7cb40-f3cd25890a.zip deleted file mode 100644 index 1a63f3ba..00000000 Binary files a/.yarn/cache/strip-ansi-npm-6.0.1-caddc7cb40-f3cd25890a.zip and /dev/null differ diff --git a/.yarn/cache/strip-json-comments-npm-3.1.1-dcb2324823-492f73e272.zip b/.yarn/cache/strip-json-comments-npm-3.1.1-dcb2324823-492f73e272.zip deleted file mode 100644 index e74ed10a..00000000 Binary files a/.yarn/cache/strip-json-comments-npm-3.1.1-dcb2324823-492f73e272.zip and /dev/null differ diff --git a/.yarn/cache/supports-color-npm-7.2.0-606bfcf7da-3dda818de0.zip b/.yarn/cache/supports-color-npm-7.2.0-606bfcf7da-3dda818de0.zip deleted file mode 100644 index 1fd9e12d..00000000 Binary files a/.yarn/cache/supports-color-npm-7.2.0-606bfcf7da-3dda818de0.zip and /dev/null differ diff --git a/.yarn/cache/text-table-npm-0.2.0-d92a778b59-b6937a38c8.zip b/.yarn/cache/text-table-npm-0.2.0-d92a778b59-b6937a38c8.zip deleted file mode 100644 index 08df4834..00000000 Binary files a/.yarn/cache/text-table-npm-0.2.0-d92a778b59-b6937a38c8.zip and /dev/null differ diff --git a/.yarn/cache/type-check-npm-0.4.0-60565800ce-ec688ebfc9.zip b/.yarn/cache/type-check-npm-0.4.0-60565800ce-ec688ebfc9.zip deleted file mode 100644 index 85a02959..00000000 Binary files a/.yarn/cache/type-check-npm-0.4.0-60565800ce-ec688ebfc9.zip and /dev/null differ diff --git a/.yarn/cache/type-fest-npm-0.20.2-b36432617f-4fb3272df2.zip b/.yarn/cache/type-fest-npm-0.20.2-b36432617f-4fb3272df2.zip deleted file mode 100644 index 8222fdcc..00000000 Binary files a/.yarn/cache/type-fest-npm-0.20.2-b36432617f-4fb3272df2.zip and /dev/null differ diff --git a/.yarn/cache/uri-js-npm-4.4.1-66d11cbcaf-7167432de6.zip b/.yarn/cache/uri-js-npm-4.4.1-66d11cbcaf-7167432de6.zip deleted file mode 100644 index bd21deb7..00000000 Binary files a/.yarn/cache/uri-js-npm-4.4.1-66d11cbcaf-7167432de6.zip and /dev/null differ diff --git a/.yarn/cache/util-deprecate-npm-1.0.2-e3fe1a219c-474acf1146.zip b/.yarn/cache/util-deprecate-npm-1.0.2-e3fe1a219c-474acf1146.zip deleted file mode 100644 index c2309cfe..00000000 Binary files a/.yarn/cache/util-deprecate-npm-1.0.2-e3fe1a219c-474acf1146.zip and /dev/null differ diff --git a/.yarn/cache/which-npm-2.0.2-320ddf72f7-1a5c563d3c.zip b/.yarn/cache/which-npm-2.0.2-320ddf72f7-1a5c563d3c.zip deleted file mode 100644 index 389ec5e2..00000000 Binary files a/.yarn/cache/which-npm-2.0.2-320ddf72f7-1a5c563d3c.zip and /dev/null differ diff --git a/.yarn/cache/wide-align-npm-1.1.5-889d77e592-d5fc37cd56.zip b/.yarn/cache/wide-align-npm-1.1.5-889d77e592-d5fc37cd56.zip deleted file mode 100644 index 4dc7fcc6..00000000 Binary files a/.yarn/cache/wide-align-npm-1.1.5-889d77e592-d5fc37cd56.zip and /dev/null differ diff --git a/.yarn/cache/wrappy-npm-1.0.2-916de4d4b3-159da4805f.zip b/.yarn/cache/wrappy-npm-1.0.2-916de4d4b3-159da4805f.zip deleted file mode 100644 index 6072a9f2..00000000 Binary files a/.yarn/cache/wrappy-npm-1.0.2-916de4d4b3-159da4805f.zip and /dev/null differ diff --git a/.yarn/cache/yallist-npm-4.0.0-b493d9e907-343617202a.zip b/.yarn/cache/yallist-npm-4.0.0-b493d9e907-343617202a.zip deleted file mode 100644 index f2d3306f..00000000 Binary files a/.yarn/cache/yallist-npm-4.0.0-b493d9e907-343617202a.zip and /dev/null differ diff --git a/.yarn/cache/yocto-queue-npm-0.1.0-c6c9a7db29-f77b3d8d00.zip b/.yarn/cache/yocto-queue-npm-0.1.0-c6c9a7db29-f77b3d8d00.zip deleted file mode 100644 index f56730df..00000000 Binary files a/.yarn/cache/yocto-queue-npm-0.1.0-c6c9a7db29-f77b3d8d00.zip and /dev/null differ diff --git a/.yarn/install-state.gz b/.yarn/install-state.gz deleted file mode 100644 index 7da77f34..00000000 Binary files a/.yarn/install-state.gz and /dev/null differ diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index b655c0cc..00000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,719 +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.10.25] = 2024-03-31 - -### Fixed - -- Build empty braced exponents. Fixes #61. - -## [0.10.24] = 2024-03-25 - -### Fixed - -- Prevent Firefox from omitting the dot on i or j -- Prevent infinite loop in an `\edef` macro -- Convert protocol in a URL to lower case, to enable a URL whitelist - -### Added - -- Support 60 binary operators from the `stix` package - -## [0.10.23] = 2024-03-11 - -### Fixed - -- Do not consolidate `` at a comma with a subsequent space - -### Added - -- Consolidate `\mathrm{…}` into a single `` element -- Optional CSS file for Fira Math font -- Support \dotminus -- Support \Earth - -## [0.10.22] = 2024-01-25 - -### Fixed - -- Parse `\middle` to end one group and start another group -- `\Set`, when containing an `\over` -- Render `\nabla` as a `` element -- Do not insert soft line break at `\int` or `\nabla` -- Edit home page for HTML validation -- Remove redundant CSS rule for `` font family -- Remove extraneous pair of braces from TypeScript `d.ts` file - -### Added - -- `\sslash` -- `\reflectbox` -- `\leftmodels` - -## [0.10.21] = 2024-1-4 - -### Fixed - -- `\color{…}` inside an environment array - -## [0.10.20] = 2023-12-31 - -### Fixed - -- Client-side rendering of `\cancel`, `\bcancel`, & `\xcancel` -- Write parens around `\tag` inside array environments -- Spacing of operators at ends of braced group -- `\mathop{…}` spacing -- `\boldsymbol` -- Spacing for unary operators - -## [0.10.19] = 2023-12-22 - -### Fixed - -- Render math mode \AA as italic -- Improve consolidation of elements in the base of of a - -## Added - -- \Angstrom - -## [0.10.18] = 2023-12-12 - -### Fixed - -- Fix: Suppress operator spacing at ends of mrow -- Fix: \hbox sets its contents to \textstyle -- Fix fix \bigm | - -## Added - -- \lAngle \rAngle, ⟪⟫ -- \llangle\rrangle, ⦉⦊ -- \llparenthesis \rrparenthesis, ⦇⦈ - -## [0.10.17] = 2023-10-25 - -### Fixed - -- Mitigate WebKit accent alignment -- Fix \sout in WebKit -- Fix visibility of AMS automatic equation numbers in WebKit -- Improve rendering option defaults - -## [0.10.16] = 2023-10-13 - -### Fixed - -- Prevent f′ from overlapping in Chromium -- Stretch \widetilde & \widehat in Chromium -- Prevent Firefox from substituting an emoji for \oplus -- Prevent Firefox from substituting a dotless i in \widetilde{U_i} -- Fix tag alignment in {align} environment - -## Added - -- \dprime \trprime \qprime \backprime \backdprime \backtrprime - -## [0.10.15] = 2023-10-4 - -### Changed - -- Move environment CSS from external file to inline - -### Added - -- Support TypeScript modules -- Support stix astronomy symbols - -## [0.10.14] = 2023-07-28 - -### Fixed - -- Center display math in Firefox & WebKit. -- Spurious line-breaking on delimiters. -- `\bigg(\Bigg(` sizes in Chromium. -- \boxed & \colorbox in WebKit -- \lower in WebKit -- \raise, \raisebox, & \lower all adjust height & depth in Chromium. (Alas, not in Firefox). - -### Changed - -- Use instead of (to comply with MathML-Core). - -### Added - -- Support \VDash - - -## [0.10.13] = 2023-06-08 - -### Changed - -- Simplify code for extensible arrows - -### Added - -- \QED - -## [0.10.12] = 2023-05-21 - -### Fixed - -- Display \nabla as upright, not italic - -## [0.10.11] = 2023-04-22 - -### Fixed - -- Center display mode math -- \bin{symbols} - -### Added - -- Support `throwOnError` rendering option -- Support `\eqeq` and `\eqeqeq` - -## [0.10.10] = 2023-02-14 - -### Fixed - -- Enable arbitrary Unicode characters inside strict-mode `\text{…}` - -## [0.10.9] = 2023-02-03 - -### Fixed - -- Unicode ℓ - -## [0.10.8] = 2023-01-31 - -### Fixed - -- Left-justify after a newline - -## [0.10.7] = 2023-01-30 - -### Fixed - -- `` containing a single `DocumentFragment`. Resolves issue #18. - -## [0.10.6] = 2023-01-29 - -### Fixed - -- Remove `mathcolor` property. Resolves issue #17. -- `` containing a document fragment -- `\definecolor` with lower case rgb - -## [0.10.5] = 2023-01-28 - -### Fixed - -- color/spacing/linebreaking interaction - -## [0.10.4] = 2023-01-25 - -### Fixed - -- Number parsing. Resolves issue #13. - -## [0.10.3] = 2023-01-17 - -### Fixed - -- Soft lines breaks via CSS flex-wrap - -## [0.10.2] = 2023-01-09 - -### Fixed - -- consumeSpaces() to consume non-breaking space - -### Added - -- Support \leftouterjoin, \rightouterjoin, \fullouterjoin - -## [0.10.1] = 2022-12-29 - -### Fixed - -- Consolidate contents of \operatorname when possible -- Insert space after a subsup whose base is an op -- Spelling errors - -## [0.10.0] = 2022-12-14 - -### Fixed - -- A space prevents an optional argument to \\ - -### Added - -- \cent -- Unicode input for chancery and roundhand (script) letters. - -### Removed - -- Support for \oldstylenums - -## [0.9.2] = 2022-12-06 - -### Fixed - -- \underline inside \text{} -- Align-left in {cases} in Firefox -- Hard line breaks -- Wrap \vdots in ``, not `` -- Use CSS style='font-weight:bold;' for \pmb - -## [0.9.1] = 2022-11-27 - -### Added - -- \underline inside \text{} -- Align-left in {cases} in Firefox -- Hard line breaks -- Wrap \vdots in , not -- \pmb via CSS font-weight: bold -- \texttt{} - -### Removed - -- CSS file for XTIS font - -## [0.9.0] = 2022-10-28 - -### Changed - -- Remove support for \arraystretch -- Control soft line breaks with a rendering option -- Array spacing via CSS, not attributes - -### Added - -- Support \gdef and \global\let -- Support array double borders called by double \hline and {array}{c||c} -- Support \mapsfrom - -### Fixed - -- Avoid unwanted stretch of harpoons -- \hline after \cr -- \prime vertical alignment in STIX TWO and Asana -- Ignore emoji suppression character ︎ - -### Securtity - -- Avoid recursive call to parser which evaded limit on \def - -## [0.8.0] = 2022-09-05 - -### Breaking Change - -- Soft line breaks are now controlled by the `wrap` rendering option. - Temml does this by creating a series of `` elements. - -## [0.7.3] = 2022-08-29 - -### Fixed - -- Get (lowered) prime from Temml.woff2 font -- Add a prime character to Temml.woff2 - -## [0.7.2] = 2022-08-08 - -### Fixed - -- Consolidation of text into a element - -## [0.7.1] = 2022-08-07 - -### Fixed - -- Vertical arrow heights in Chromium -- mclass, e.g. \mathrel, in Chromium - -## [0.7.0] = 2022-08-03 - -### Release Notes - -This release is all about Chromium. Ignalia has announced an [intent to ship](https://www.igalia.com/2022/06/22/Intent-to-Ship-MathML.html) MathML in Chromium. In anticipation of that event, this version of Temml is written to support both Firefox and Chromium. - -Those two implementations are not written to the same specification. So Temml’s MathML must conform simultaneously to both [MathML 3]( https://www.w3.org/TR/MathML3/) (Firefox) and [MathML Core](https://w3c.github.io/mathml-core/) (Chromium). Given that challenge, I’m pretty happy with how well it has turned out. Temml emulates several hundred LaTeX functions and nearly all of them work very well. - -It’s not all perfect. In this version, Temml drops support for `\cancelto`, `\toggle`, `\texttip`, `\phase`, and `\longdiv`. I think that `\toggle` and `\texttip` are probably gone forever. The others I hope to restore someday after Chromium fully supports the `menclose` element. - -Also, Chromium’s implementation of MathML is new and not yet mature. It fails with some stretchy accents and extensible arrows. Chromium cannot yet print a page that contains MathML. I’m testing this in Chrome Canary and those issues may be worked out before MathML is shipped. - -### Added - -- Support for [MathML Core](https://w3c.github.io/mathml-core/) for rendering in Chromium - -### Removed - -- Support for `\cancelto`, `\toggle`, `\texttip`, `\phase`, and `\longdiv` - -## [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 99bd5680..00000000 --- a/README.md +++ /dev/null @@ -1,43 +0,0 @@ -*Temml* is a LaTeX-to-MathML JavaScript conversion utility. It is built to be lightweight. - -| Library | Minified JavaScript + CSS | -|:--------------|:-------------------------:| -| Temml | 153 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 10kb. Sadly, Chromium has some rendering bugs when using system fonts. It -work better with the Latin Modern font, a 380 KB file. - -Temml’s coverage of LaTeX functions is as good as MathJax, slightly better than KaTeX 0.16.0 and substantially better than TeXZilla. See a [detailed coverage comparison](https://temml.org/docs/en/comparison.html). - -Temml's test suite includes many rendered examples, including the Temml [supported functions page](https://temml.org/docs/en/supported.html) and tests from [Mozilla](https://temml.org/tests/mozilla-tests.html), [Wikipedia](https://temml.org/tests/wiki-tests.html), [mhchem](https://temml.org/tests/mhchem-tests.html), and [LaTeXML](https://temml.org/tests/LaTeXML-tests.html). - -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{…}`, `\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/docs/administration.md b/docs/administration.md deleted file mode 100644 index f09e4071..00000000 --- a/docs/administration.md +++ /dev/null @@ -1,490 +0,0 @@ - - - - - - Temml Administration - - - - - -
- -# Temml Administration - -# Browser Support - -Temml works in browsers that support MathML. This includes Chrome, Edge, Firefox, and Safari. -Temml will never work in Internet Explorer. - -# Installation - -For use in the browser, you can download a zip file of Temml from the -[releases page][] of the Temml repository. For server-side use, you can obtain -Temml via CLI commands `npm install temml` or `yarn add temml`. - -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 use `temml.cjs` or `temml.mjs` instead -of `temml.min.js`. - -[releases page]: https://github.com/ronkok/Temml/releases - -#### Starter template - -```html - - - - - ... - - - - ... - -``` - -# API - -### Overview - -Say that you have an HTMLCollection of elements whose contents should be -converted from TeX strings to math. The code for such a conversion -might look like this: - -Option 1: Macros do not persist between calls to Temml: - -``` -// Render all the math. -for (let aSpan of [...mathSpans]) { - const tex = aSpan.textContent; - const displayMode = aSpan.classList.contains("display"); - temml.render(tex, aSpan, { displayMode }); -} -// Optional postProcess to render \ref{} -temml.postProcess(document.body); -``` - -
Option 2: Macros defined with \gdef do persist: - -``` -// Optional macros object to hold macros that persist between calls to Temml. -const macros = {} -// Render all the math. -for (let aSpan of [...mathSpans]) { - const tex = aSpan.textContent; - const displayMode = aSpan.classList.contains("display"); - // Notice the macros argument below. - // It carries macros that were defined with \gdef or \global\let - temml.render(tex, aSpan, { macros, displayMode }); -} -// Optional postProcess to render \ref{} -temml.postProcess(document.body); -``` - -::: indented -Notice that you can choose when to stop macro persistence by redefining `macros`. -::: - -
- -
- -
Option 3: Macros persist and there are some predefined macros: - -Now say that you wish to pre-define two macros and a color with document-wide scope. - -``` -// Optional preamble to pre-define macros. -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); -``` - -If the element you provide is a `` element, Temml will populate it. -Otherwise, it will create a new `` element and make it a child -of the element you provide. - -### 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. (default: `false`) - -- `wrap`: (`"tex"` | `"="` | `"none"`). A mode for soft line breaks in non-display - mode math. The `tex` option sets a soft line break after every top-level relation and - binary operator, per _The TeXbook_, page 173. The `=` option sets a soft line - break before the second and subsequent top-level `=` signs. `tex` is the default. - - Caveats: Soft line breaks work in Chromium and Firefox, but do not work in WebKit or Safari. - Display mode math gets no soft line breaks. Annotated math gets no soft line - breaks. If a writer sets a hard line break via `\\` or `\cr`, then Temml will - not set any soft line breaks in that expression. - -- `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`) - -- `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`) - -- 'throwOnError': `boolean`. If true, Temml will throw parse errors to the console. If false, Temml will write the parse error to the output of the `render()` function. (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. (`\edef` expansion counts all expanded tokens.) 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 can be helpful for other user agents, such as Microsoft Word. (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}`\ - where `protocol` is a lowercased string like `"http"` or `"https"` - that appears before a colon, or `"_relative"` for relative URLs. - - `{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`, everything in Temml will work except `\ref`. - -If you use the [auto-render extension][], it includes the post-processor nuances. - -[auto-render extension]: https://github.com/ronkok/Temml/tree/main/contrib/auto-render - -# 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. - -**Latin Modern** will provide the best quality rendering. It is a clone of -Computer Modern and so is very home-like for readers accustomed to LaTeX -documents. For best results, you must also serve a small -(10kb) `Temml.woff2` file. Then you’ll get support for `\mathscr{…}` and you’ll -get primes at the correct vertical alignment in Chrome and Edge. - -**Temml-Local.css** is the light-weight option. It calls two fonts: _Cambria -Math_, which comes pre-installed in Windows, or _STIX TWO_, which comes -pre-installed in iOS and MacOS (as of Safari 16). It also needs to be augmented -with `Temml.woff2`. - -Sadly, this option has rendering issues. Chrome botches extensible arrows and it -will fail to stretch the `∫` symbol on Windows. Android does not currently -provide a font with a MATH table, so it has many problems. - -**Asana** and **Libertinus** have some of the same rendering problems as Cambria Math, -although Asana does contain its own roundhand glyphs. - -**Fira Math** is a sans-serif math font. - -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 downloaded with the latest Temml [release][]. -- STIXTwoMath-Regular.woff2 is located at the STIX [repository][STIX]. -- LibertinusMath-Regular.woff2 is located at the Libertinus [repository][Libertinus]. -- The other fonts can be downloaded at [Mathematical OpenType Fonts][]. - -[release]: https://github.com/ronkok/Temml/releases -[STIX]: https://github.com/stipub/stixfonts/blob/master/fonts/static_otf_woff2/STIXTwoMath-Regular.woff2 -[Libertinus]: https://github.com/alerque/libertinus -[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. -* [copy-tex][]: When users select and copy elements, copies their LaTeX source to the clipboard -* [mhchem][]: Write beautiful chemical equations easily. -* [physics][]: Implement much of the LaTeX `physics` package. -* [texvc][]: Support functions used in wikimedia. - -[auto-render]: https://github.com/ronkok/Temml/tree/main/contrib/auto-render -[copy-tex]: https://github.com/ronkok/Temml/tree/main/contrib/copy-tex -[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` or `temml.mjs` instead of `temml.min.js`. -`temml.cjs` and `temml.mjs` both include `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.10.25, 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
\Angstrom₮\Angstrom₮Not supportedNot supportedNot supported\Angstrom
\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 }
\arraystretchNot supported\(\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₸
\astrosun₮\astrosun₮Not supportedNot supportedNot supported
\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₭Not supported
\backdprime₮\backdprime₮Not supportedNot supportedNot supported
\backtrprime₮\backtrprime₮Not supportedNot supportedNot supported
\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}
\barcap₮\barcap₮Not supportedNot supportedNot supported
\barcup₮\barcup₮Not supportedNot supportedNot supported
\barvee₮\barvee₮Not supportedNot supportedNot supported
\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)
\bigtimes₮\bigtimes₮Not supportedNot supported₸\bigtimes₸
\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
\blackhourglass₮\blackhourglass₮Not supportedNot supportedNot supported
\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₸
\boxast₮\boxast₮Not supportedNot supportedNot supported
\boxbox₮\boxbox₮Not supportedNot supportedNot supported
\boxcircle₮\boxcircle₮Not supportedNot supportedNot supported
\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₸
\capbarcup₮\capbarcup₮Not supportedNot supportedNot supported
\capdot₮\capdot₮Not supportedNot supportedNot supported
\capovercup₮\capovercup₮Not supportedNot supportedNot supported
{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
\cent₮\cent₮Not supportedNot supportedNot supported
\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₸
\circledequal₮\circledequal₮Not supportedNot supportedNot supported
\circledparallel₮\circledparallel₮Not supportedNot supportedNot supported
\circledR₮\circledR₮\(\circledR\)₭\circledR₭Not supported
\circledS₮\circledS₮\(\circledS\)₭\circledS₭Not supported
\circledvert₮\circledvert₮Not supportedNot supportedNot supported
\circlehbar₮\circlehbar₮Not supportedNot supportedNot supported
\class₮ab\class{mathHighlight}{cdef}gh₮Not supportedNot supportedNot supportedab\class{mathHighlight}{cdef}gh
\clineNot supportedNot supportedNot supportedNot supported
\closedvarcap₮\closedvarcap₮Not supportedNot supportedNot supported
\closedvarcup₮\closedvarcup₮Not 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
\concavediamond₮\concavediamond₮Not supportedNot supportedNot supported
\concavediamondtickleft₮\concavediamondtickleft₮Not supportedNot supportedNot supported
\concavediamondtickright₮\concavediamondtickright₮Not supportedNot supportedNot 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₸
\cupovercap₮\cupovercap₮Not supportedNot supportedNot supported
\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
\diameter₮\diameter₮Not supportedNot supportedNot 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₸
\doublebarvee₮\doublebarvee₮Not supportedNot supportedNot supported
\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₸
\dotminus₮\dotminus₮Not supportedNot supported₸\dotminus₸
\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₸
\dprime₮\dprime₮Not supportedNot supportedNot supported
{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
\Earth₮\Earth₮Not supportedNot supportedNot supported
\ell₮\ell₮\(\ell\)₭\ell₭₸\ell₸
\elseNot supportedNot supportedNot supportedNot supported
\empty₮\empty₮\(\empty\)₭\empty₭₸\empty₸
\emptyset₮\emptyset₮\(\emptyset\)₭\emptyset₭₸\emptyset₸
\encloseNot supported
See \angl
\(\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₸
\fullouterjoin₮\fullouterjoin₮Not supportedNot supportedNot supported
\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}
\hourglass₮\hourglass₮Not supportedNot supportedNot supported
\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₸
\interleave₮\interleave₮Not supportedNot supportedNot supported
\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
\invlazys₮\invlazys₮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₮Not supportedNot supportedNot supported\lAngle 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₸
\leftmodels₮\leftmodels₮Not supportedNot supportedNot supported
\leftmoon₮\leftmoon₮Not supportedNot supportedNot supported
\leftouterjoin₮\leftouterjoin₮Not supportedNot supportedNot supported
\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₸
\llangle₮\llangle A\rrangle₮Not supportedNot supported₸\llangle A\rrangle₸\llangle A\rrangle
\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
\llparenthesis₮\llparenthesis₮Not supportedNot supportedNot 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₸
\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₸
\lozengeminus₮\lozengeminus₮Not supportedNot supportedNot supported
\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
\mapsfrom₮\mapsfrom₮Not supportedNot supportedNot 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₸
\minusdot₮\minusdot₮Not supportedNot supportedNot supported
\minusoNot supported
See \standardstate
Not supported₭\minuso₭Not supported
\minusfdots₮\minusfdots₮Not supportedNot supportedNot supported
\minusrdots₮\minusrdots₮Not supportedNot supportedNot 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₸
\Nand₮\Nand₮Not supportedNot supportedNot supported
\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
\Nor₮\Nor₮Not supportedNot supportedNot supported
\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}
\obar₮\obar₮Not supportedNot supportedNot supported
\obslash₮\obslash₮Not supportedNot supportedNot supported
\oc₮\oc₮Not supportedNot supportedNot supported
\odiv₮\odiv₮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
\ogreaterthan₮\ogreaterthan₮Not supportedNot 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\(\oldstyle 0123456\)Not supportedNot supported\oldstyle 0123456
\oldstylenumsNot supportedNot supportedNot supportedNot supported
\olessthan₮\olessthan₮Not supportedNot supportedNot supported
\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
\operp₮\operp₮Not supportedNot supportedNot supported
\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₸
\Otimes₮\Otimes₮Not supportedNot supportedNot supported
\otimeshat₮\otimeshat₮Not supportedNot supportedNot supported
\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}
\phaseNot supportedNot 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}
\QED₮\QED₮Not supportedNot supportedNot supported
\qprime₮\qprime₮Not supportedNot supportedNot supported
\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₮Not supportedNot supportedNot supported\lAngle A\rAngle
\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}
\reflectbox₮\reflectbox{S}₮Not supportedNot supportedNot supported\reflectbox{S}
\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₸
\rightmoon₮\rightmoon₮Not supportedNot supportedNot supported
\rightouterjoin₮\rightouterjoin₮Not supportedNot supportedNot supported
\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₸
\rrangle₮\llangle A\rrangle₮Not supportedNot supported₸\llangle A\rrangle₸\llangle A\rrangle
\rrbracket₮\rrbracket₮Not supported₭\rrbracket₭Not supported
\rrparenthesis₮\rrparenthesis₮Not supportedNot supportedNot 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
\shuffle₮\shuffle₮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)
\smashtimes₮\smashtimes₮Not supportedNot supportedNot supported
\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₸
\Sqcap₮\Sqcap₮Not supportedNot supportedNot supported
\sqcup₮\sqcup₮\(\sqcup\)₭\sqcup₭₸\sqcup₸
\Sqcup₮\Sqcup₮Not supportedNot supportedNot supported
\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}
\sslash₮\sslash₮Not supportedNot supported₸\sslash₸
\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₸
\sun₮\sun₮Not supportedNot supportedNot supported
\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
\threedotcolon₮\threedotcolon₮Not supportedNot supportedNot supported
\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₸
\triangleminus₮\triangleminus₮Not supportedNot supportedNot supported
\triangleplus₮\triangleplus₮Not supportedNot supportedNot supported
\triangleright₮\triangleright₮\(\triangleright\)₭\triangleright₭₸\triangleright₸
\trianglerighteq₮\trianglerighteq₮\(\trianglerighteq\)₭\trianglerighteq₭₸\trianglerighteq₸
\triangletimes₮\triangletimes₮Not supportedNot supportedNot supported
\trprime₮\trprime₮Not supportedNot supportedNot supported
\tt₮{\tt AaBb123}₮\({\tt AaBb123}\)₭{\tt AaBb123}₭Not supported{\tt AaBb123}
\twocaps₮\twocaps₮Not supportedNot supportedNot supported
\twocups₮\twocups₮Not supportedNot supportedNot supported
\twoheadleftarrow₮\twoheadleftarrow₮\(\twoheadleftarrow\)₭\twoheadleftarrow₭₸\twoheadleftarrow₸
\twoheadrightarrow₮\twoheadrightarrow₮\(\twoheadrightarrow\)₭\twoheadrightarrow₭₸\twoheadrightarrow₸
\typecolon₮\typecolon₮Not supportedNot supportedNot supported
- -

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₮Not supportedNot supported₸\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₸
\Vee ₮\Vee₮Not supportedNot supported₸\Vee₸
\veebar₮\veebar₮\(\veebar\)₭\veebar₭₸\veebar₸
\veedot₮\veedot₮Not supportedNot supportedNot supported
\veedoublebar₮\veedoublebar₮Not supportedNot supportedNot supported
\veeeq₮\veeeq₮Not supportedNot supportedNot supported
\veeonvee₮\veeonvee₮Not supportedNot supportedNot supported
\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₸
\Wedge₮\Wedge₮Not supportedNot supported₸\wedge₸
\wedgebar₮\wedgebar₮Not supportedNot supportedNot supported
\wedgedot₮\wedgedot₮Not supportedNot supportedNot supported
\wedgedoublebar₮\wedgedoublebar₮Not supportedNot supportedNot supported
\wedgeq₮\wedgeq₮Not supportedNot supportedNot supported
\wedgeonwedge₮\wedgeonwedge₮Not supportedNot supportedNot supported
\weierp₮\weierp₮\(\weierp\)₭\weierp₭Not supported
\whitesquaretickleft₮\whitesquaretickleft₮Not supportedNot supportedNot supported
\whitesquaretickright₮\whitesquaretickright₮Not supportedNot supportedNot 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}
\Xor₮\Xor₮Not supportedNot supportedNot supported
\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-2024 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 b2faebeb..00000000 --- a/docs/support_table.md +++ /dev/null @@ -1,1882 +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). - -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$||| -|\Angstrom|$\Angstrom$|| stix | -|\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|(Not supported)||| -|\Arrowvert|(Not supported)|see `\Vert`|| -|\arrowvert|(Not supported)|see `\vert`|| -|\ast|$\ast$||| -|\astrosun|$\astrosun$|| stix | -|\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 | $\sigma^\backprime$ | `\sigma^\backprime` | ams | -+---------------------+--------------------------+--------------------------+-------------------+ -| \backdprime | $\sigma^\backdprime$ | `\sigma^\backdprime` | stix | -+---------------------+--------------------------+--------------------------+-------------------+ -| \backsim | $\backsim$ | | ams | -+---------------------+--------------------------+--------------------------+-------------------+ -| \backsimeq | $\backsimeq$ | | ams | -+---------------------+--------------------------+--------------------------+-------------------+ -| \backslash | $\backslash$ | | | -+---------------------+--------------------------+--------------------------+-------------------+ -| \backtrprime | $\sigma^\backtrprime$ | `\sigma^\backtrprime` | stix | -+---------------------+--------------------------+--------------------------+-------------------+ -| \bar | $\bar{y}$ | `\bar{y}` | | -+---------------------+--------------------------+--------------------------+-------------------+ -| \barcap | $\barcap$ | | stix | -+---------------------+--------------------------+--------------------------+-------------------+ -| \barcup | $\barcup$ | | stix | -+---------------------+--------------------------+--------------------------+-------------------+ -| \barvee | $\barvee$ | | stix | -+---------------------+--------------------------+--------------------------+-------------------+ -| \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} | `\begin{matrix}`\ | ams | -| | a & b \\ | `a & b \\`\ | | -| | c & d | `c & d`\ | | -| | \end{matrix}$ | `\end{matrix}` | | -+---------------------+--------------------------+--------------------------+-------------------+ -| \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)` | | -+---------------------+--------------------------+--------------------------+-------------------+ -| \bigtimes | $\bigtimes$ | | stix | -+---------------------+--------------------------+--------------------------+-------------------+ -| \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 | -+---------------------+--------------------------+--------------------------+-------------------+ -| \blackhourglass | $\blackhourglass$ | | stix | -+---------------------+--------------------------+--------------------------+-------------------+ -| \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} | `\begin{Bmatrix}`\ | ams | -| | a & b \\ | `a & b \\`\ | | -| | c & d | `c & d`\ | | -| | \end{Bmatrix}$ | `\end{Bmatrix}` | | -+---------------------+--------------------------+--------------------------+-------------------+ -| {Bmatrix\*} | $\begin{Bmatrix*}[r] | `\begin{Bmatrix*}[r]`\ | mathtools | -| | -1 & 3 \\ | `-1 & 3 \\`\ | | -| | 2 & -4 | `2 & -4`\ | | -| | \end{Bmatrix*}$ | `\end{Bmatrix*}` | | -+---------------------+--------------------------+--------------------------+-------------------+ -| {bmatrix} | $\begin{bmatrix} | `\begin{bmatrix}`\ | ams | -| | a & b \\ | `a & b \\`\ | | -| | c & d | `c & d`\ | | -| | \end{bmatrix}$ | `\end{bmatrix}` | | -+---------------------+--------------------------+--------------------------+-------------------+ -| {bmatrix\*} | $\begin{bmatrix*}[r] | `\begin{bmatrix*}[r]`\ | mathtools | -| | -1 & 3 \\ | `-1 & 3 \\`\ | | -| | 2 & -4 | `2 & -4`\ | | -| | \end{bmatrix*}$ | `\end{bmatrix*}` | | -+---------------------+--------------------------+--------------------------+-------------------+ -| \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 | -+---------------------+--------------------------+--------------------------+-------------------+ -| \boxast | $\boxast$ | | stix | -+---------------------+--------------------------+--------------------------+-------------------+ -| \boxbox | $\boxbox$ | | stix | -+---------------------+--------------------------+--------------------------+-------------------+ -| \boxcircle | $\boxcircle$ | | stix | -+---------------------+--------------------------+--------------------------+-------------------+ -| \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 | $\Bra{\psi}$ | `\Bra{\psi}` | braket | -+---------------------+--------------------------+--------------------------+-------------------+ -| \bra | $\bra{\psi}$ | `\bra{\psi}` | braket | -+---------------------+--------------------------+--------------------------+-------------------+ -| \braket | $\braket{\phi|\psi}$ | `\braket{\phi|\psi}` | braket | -+---------------------+--------------------------+--------------------------+-------------------+ -| \Braket | $\Braket{ϕ|\frac{∂^2}{∂ | `\Braket{ϕ|\frac{∂^2}{∂ | braket | -| | t^2}|ψ}$ | t^2}|ψ}` | | -+---------------------+--------------------------+--------------------------+-------------------+ -| \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 | -|\Cap|$\Cap$|| ams | -|\cap|$\cap$||| -|\capbarcup|$\capbarcup$|| stix | -|\capdot|$\capdot$|| stix | -|\capovercup|$\capovercup$|| stix | -|{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 | -|\cent|$\cent$|| wasysym | -|\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 | -|\circledequal|$\circledequal$|| stix | -|\circleddash|$\circleddash$|| ams | -|\circledparallel|$\circledparallel$|| stix | -|\circledR|$\circledR$|| ams | -|\circledS|$\circledS$|| ams | -|\circledvert|$\circledvert$|| stix | -|\circlehbar|$\circlehbar$|| stix | -|\class|(Not supported)||| -|\cline|(Not supported)||| -|\closedvarcap|$\closedvarcap$|| stix | -|\closedvarcup|$\closedvarcup$|| stix | -|\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 | -|\concavediamond|$\concavediamond$|| stix | -|\concavediamondtickleft|$\concavediamondtickleft$|| stix | -|\concavediamondtickright|$\concavediamondtickright$|| stix | -|\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$||| -|\cupovercap|$\cupovercap$|| stix | -|\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 | -|\diameter|$\diameter$|| stix | -|\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 | -|\dotminus|$\dotminus$|| stix | -|\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 | -|\doublebarvee|$\doublebarvee$|| stix | -|\doublebarwedge|$\doublebarwedge$|| stix | -|\doublecap|$\doublecap$|| ams | -|\doublecup|$\doublecup$|| ams | -|\Downarrow|$\Downarrow$||| -|\downarrow|$\downarrow$||| -|\downdownarrows|$\downdownarrows$|| ams | -|\downharpoonleft|$\downharpoonleft$|| ams | -|\downharpoonright|$\downharpoonright$|| ams | -|\dprime|$f^\dprime$|`f^\dprime`| stix | -|{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 | -|----------------|-------------|-------------------|-----------| -|\Earth|$\Earth$|| stix | -|\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`, `\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 | -|\eqeq|$\eqeq$|| unicodemath | -|\eqeqeq|$\eqeqeq$|| unicodemath | -|\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$ | | | -| \fullouterjoin | $\fullouterjoin$ | | stix | -| \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$ | | | -| \hourglass | $\hourglass$ | | stix | -| \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 | -| \interleave | $\interleave$ | | stix | -| \intlarhk | $\intlarhk$ | | | -| \intop | $\intop$ | | | -| \intx | $\intx$ | | | -| \invamp | $\invamp$ | | cmll | -| \invlazys | $\invlazys$ | | stix | -| \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 | $\Ket{\psi}$ | `\Ket{\psi}` | braket | -| \ket | $\ket{\psi}$ | `\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` | unicode-math | -| \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 | -| \leftmodels | $\leftmodels$ | | MnSymbol | -| \leftmoon | $\leftmoon$ | | stix | -| \leftouterjoin | $\leftouterjoin$ | | stix | -| \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$ | | | -| \llangle | $\llangle A\rrangle$ | `\llangle A\rrangle` | unicode-math | -| \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 | | | | -| \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 | -| \lozengeminus | $\lozengeminus$ | | stix | -| \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 | -|\mapsfrom|$\mapsfrom$ || stmaryrd | -|\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)`| ε-TeX | -|\min|$\min$ ||| -|\minuscolon|$\minuscolon$ || colonequals | -|\minuscoloncolon|$\minuscoloncolon$ || colonequals | -|\minusdot|$\minusdot$|| stix | -|\minusfdots|$\minusfdots$|| stix | -|\minusrdots|$\minusrdots$|| stix | -|\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$ ||| -|\Nand|$\Nand$|| stix | -|\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`|| -|\Nor|$\Nor$|| stix | -|\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}`|| -|\obar|$\obar$ || stix | -|\obslash|$\obslash$ || stix | -|\oc|$\oc$ || cmll | -|\odiv|$\odiv$ || stix | -|\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`|| -|\ogreaterthan|$\ogreaterthan$ || stix | -|\oiiint|$\oiiint$ ||| -|\oiint|$\oiint$ ||| -|\oint|$\oint$ ||| -|\oldstyle|(Not supported)||| -|\oldstylenums|(Not supported)||| -|\olessthan|$\olessthan$ || stix | -|\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`| | -|\operp|$\operp$ || stix | -|\oplus|$\oplus$ ||| -|\or|(Not supported)||| -|\order|$\order{x^2}$ |`\order{x^2}`| physics extension | -|\origof|$\origof$ || stix | -|\oslash|$\oslash$ ||| -|\otimes|$\otimes$ ||| -|\Otimes|$\Otimes$ || stix | -|\otimeshat|$\otimeshat$ || stix | -|\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|(Not supported)||| -|\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 | -| \QED | $\QED$ | | stix | -| \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 | -| \qprime | $f^\qprime$ | `f^\qprime` | stix | -| \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`| unicode-math | -| \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`.| | -| \reflectbox | $\reflectbox{S}$ | `\reflectbox{S}` | graphicx | -| \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 | -| \rightmoon | $\rightmoon$ | | stix | -| \rightouterjoin | $\rightouterjoin$ | | stix | -| \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$| | | -| \rrangle | $\llangle A\rrangle$ | `\llangle A\rrangle` | unicode-math | -| \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 | `\scriptscriptstyle \frac | | -| | cd$ | 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 | -+---------------------+--------------------------------------+----------------------------------+--------------------+ -| \\shuffle | $\shuffle$ | | stix | -+---------------------+--------------------------------------+----------------------------------+--------------------+ -| \\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 & | `\begin{smallmatrix}`\ | | -| | b \\ c & d |    `a & b \\`\ | | -| | \end{smallmatrix}$ |    `c & d`\ | | -| | | `\end{smallmatrix}` | | -+---------------------+--------------------------------------+----------------------------------+--------------------+ -| \\smallsetminus | $\smallsetminus$ | | ams | -+---------------------+--------------------------------------+----------------------------------+--------------------+ -| \\smallsmile | $\smallsmile$ | | ams | -+---------------------+--------------------------------------+----------------------------------+--------------------+ -| \\smash | $\left(x^{\smash{2}}\right)$ | `\left(x^{\smash{2}}\right)` | | -+---------------------+--------------------------------------+----------------------------------+--------------------+ -| \\smashtimes | $\smashtimes$ | | stix | -+---------------------+--------------------------------------+----------------------------------+--------------------+ -| \\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{equation}`\ | ams | -| | \begin{split} | `\begin{split}`\ | | -| | a &=b+c\\ |    `a &=b+c\\`\ | | -| | &=e+f |       `&=e+f`\ | | -| | \end{split} | `\end{split}`\ | | -| | \end{equation} $$ | `\end{equation}` | | -+---------------------+--------------------------------------+----------------------------------+--------------------+ -| \\sqcap | $\sqcap$ | | | -+---------------------+--------------------------------------+----------------------------------+--------------------+ -| \\Sqcap | $\Sqcap$ | | stix | -+---------------------+--------------------------------------+----------------------------------+--------------------+ -| \\sqcup | $\sqcup$ | | | -+---------------------+--------------------------------------+----------------------------------+--------------------+ -| \\Sqcup | $\Sqcup$ | | stix | -+---------------------+--------------------------------------+----------------------------------+--------------------+ -| \\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}` | | -+---------------------+--------------------------------------+----------------------------------+--------------------+ -| \\sslash | $\sslash$ | | stmaryrd | -+---------------------+--------------------------------------+----------------------------------+--------------------+ -| \\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} | `\sum_{\begin{subarray}{l}`\ | ams | -| | i\in\Lambda\\ |  `i\in\Lambda\\`\ | | -| | 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`|| -|\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 | -|\threedotcolon|$\threedotcolon$|| stix | -|\tilde|$\tilde M$|`\tilde M`|| -|\times|$\times$||| -|\Tiny|$\Tiny Tiny$|`\Tiny Tiny`|| -|\tiny|$\tiny tiny$|`\tiny tiny`|| -|\to|$\to$||| -|\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 | -|\triangleminus|$\triangleminus$|| stix | -|\triangleplus|$\triangleplus$|| stix | -|\triangleright|$\triangleright$||| -|\trianglerighteq|$\trianglerighteq$|| ams | -|\triangletimes|$\triangletimes$|| stix | -|\trprime|$f^\trprime$|`f^\trprime`| stix | -|\tt|${\tt AaBb123}$|`{\tt AaBb123}`|| -|\twocaps|$\twocaps$|| stix | -|\twocups|$\twocups$|| stix | -|\twoheadleftarrow|$\twoheadleftarrow$|| ams | -|\twoheadrightarrow|$\twoheadrightarrow$|| ams | -|\typecolon|$\typecolon$|| stix | - -## 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$ || MnSymbol | -|\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$ ||| -|\Vee|$\Vee$ || stix | -|\veebar|$\veebar$ || ams | -|\veedot|$\veedot$ || stix | -|\veedoublebar|$\veedoublebar$ || stix | -|\veeeq|$\veeeq$ || stix | -|\veeonvee|$\veeonvee$|| 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$ | | | -| \Wedge | $\Wedge$ | | stix | -| \wedgebar | $\wedgebar$ | | stix | -| \wedgedot | $\wedgedot$ | | stix | -| \wedgedoublebar | $\wedgedoublebar$ | | stix | -| \wedgeq | $\wedgeq$ | | stix | -| \wedgeonwedge | $\wedgeonwedge$ | | stix | -| \weierp | $\weierp$ | | texvc extension | -| \whitesquaretickleft | $\whitesquaretickleft$ | | stix | -| \whitesquaretickright | $\whitesquaretickright$ | | stix | -| \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 | -| \Xor | $\Xor$ | | stix | -| \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-2024 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 b920ad5b..00000000 --- a/docs/supported.md +++ /dev/null @@ -1,1663 +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. - -There is a similar [Support Table](./support_table.html), sorted alphabetically, -that lists both supported and some un-supported functions. - -## Accents - -+:=========================+:=========================+:===================================+ -| $f'$ `f'` | $\tilde{a}$ `\tilde{a}` | $\widetilde{ac}$ `\widetilde{ac}` | -+--------------------------+--------------------------+------------------------------------+ -| $f''$ `f''` | $\vec{F}$ `\vec{F}` | $\utilde{AB}$ `\utilde{AB}` | -+--------------------------+--------------------------+------------------------------------+ -| $f^{\prime}$ | $\overleftarrow{AB}$ | $\overrightarrow{ABC}$ | -| `f^{\prime}` | `\overleftarrow{AB}` | `\overrightarrow{ABC}` | -+--------------------------+--------------------------+------------------------------------+ -| $\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}` | -+--------------------------+--------------------------+------------------------------------+ -| $f^{\dprime}$ | $f^{\trprime}$ | $f^{\qprime}$ | -| `f^{\dprime}` | `f^{\trprime}` | `f^{\qprime}` | -+--------------------------+--------------------------+------------------------------------+ -| $\sigma^{\backprime}$ | $\sigma^{\backdprime}$ | $\sigma^{\backtrprime}$ | -| `\sigma^{\backprime}` | `\sigma^{\backdprime}` | `\sigma^{\backtrprime}` | -+--------------------------+--------------------------+------------------------------------+ - -**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}` | $\boxed{\pi=\frac c d}$ | -| | `\boxed{\pi=\frac c d}` | -+----------------------------------+----------------------------------------------------+ -| $\sout{abc}$ `\sout{abc}` | | -| | | -+----------------------------------+----------------------------------------------------+ -| $\ref{tag1}$ `\ref{tag1}` | | -| | | -+----------------------------------+----------------------------------------------------+ -| $$ | `\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}` | | -+------------------------------+---------------------------------------------+ -{colWidths="300 370"} - -`\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 of the standard HTML [predefined color names](https://www.w3schools.com/colors/colors_names.asp). -- Any color from the following `xcolor` table. - -
- -+==============================================================+==========================================================+========================================================+==============================================================+ -| ${\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` | | -+------------------+--------------------+--------------+---------------------------------+---------------------+ -| $\lt\gt$ `\lt`\ | $\lAngle~\rAngle$ | $┌ ┐$ `┌ ┐` | $\ulcorner \urcorner$ | $\Downarrow$ | -|         `\gt` | `\lAngle` \ | | `\ulcorner`\ | `\Downarrow` | -| | $~~~~$ `\rAngle` | | $~~~~$ `\urcorner` | | -+------------------+--------------------+--------------+---------------------------------+---------------------+ -| $\vert$ `|` | $\vert$ `\vert` | $└ ┘$ `└ ┘` | $\llcorner \lrcorner$ | $\Updownarrow$ | -| | | | `\llcorner`\ | `\Updownarrow` | -| | | | $~~~~$ `\lrcorner` | | -+------------------+--------------------+--------------+---------------------------------+---------------------+ -| $\Vert$ `\|` | $\Vert$ `\Vert` | `\left.` | `\right.` | $\backslash$ | -| | | | | `\backslash` | -| | | | | | -+------------------+--------------------+--------------+---------------------------------+---------------------+ -| $\lvert~\rvert$ | $\lVert~\rVert$ | $⟦~⟧$ `⟦ ⟧` | $\llbracket~\rrbracket$ | $\lBrace~\rBrace$ | -| `\lvert`\ | `\lVert`\ | | `\llbracket`\ | `\lBrace \rBrace` | -| $~~~~$ `\rvert` | $~~~~$ `\rVert` | | $~~~~$ `\rrbracket` | | -+------------------+--------------------+--------------+---------------------------------+---------------------+ -| | | | $\llparenthesis~\rrparenthesis$ | $\llangle~\rrangle$ | -| |       | | `\llparenthesis`\ | `\llangle \rrangle` | -| | | |        `\rrparenthesis` | | -+------------------+--------------------+--------------+---------------------------------+---------------------+ - - -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{bmatrix}` | -+-----------------------+----------------------------+----------------------------+------------------------------+ -| $\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}`\ | $\begin{array}{c|c:c} | `\begin{array}{c|c:c}`\ | -| a & b \\ |    `a & b \\`\ | a & b & c \\ \hline |   `a & b & c \\ \hline`\ | -| c & d |    `c & d`\ | d & e & f \\ \hdashline |    `d & e & f \\`\ | -| \end{Bmatrix}$ | `\end{Bmatrix}` | 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 | `\end{align}` | -| &=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` | $\Angstrom$ `\Angstrom` | $\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{\AE}$ `\text{\AE}` | $\text{\i}$ `\text{\i}` | -+----------------------+--------------------+--------------------+----------------------------+----------------------------+ -| $\ell$ `\ell` | $\hslash$ | $\wp$ `\wp` | $\text{\oe}$ `\text{\oe}` | $\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{𝗔-𝗭 𝗮-𝘇 𝟬-𝟵}$ | -| Monospace | $\text{𝙰-𝚉 𝚊-𝚣 𝟶-𝟿}$ | Sans serif italic | $\text{𝘈-𝘡 𝘢-𝘻}$ | -| Script | $\text{𝒜-𝒵 𝒶-𝓏}$ | Sans serif bold italic | $\text{𝘼-𝙕 𝙖-𝙯}$ | -| Fraktur | $\text{𝔄-ℨ}\text{𝔞-𝔷}$ | Bold Fraktur | $\text{𝕬-𝖅}\text{𝖆-𝖟}$ | - -There are two methods that will render any Unicode charater: - -1. Use the `\char` function and the Unicode code in hex. For example `\char"263a` will render as $\char"263a$ . -2. Write the character inside `\text{…}`. For example, `\text{☺}` will render as $\text{☺}$. - -
- -
More about Unicode script… - -The Unicode range U+1D49C - U+1D4B5, Mathematical Script, has been ambiguous. -Some fonts put chancery glyphs ($\mathcal{ABC}$) at those code points and some -fonts use roundhand glyphs ($\mathscr{ABC}$). Temml’s default for code points -in this range is chancery, which matches the fonts Cambria Math and STIX TWO. -It also matches the TeX function `\mathcal{…}`. - -Per Unicode 14+, Temml will return a roundhand glyph if you append a `\ufe01` -to a character in the range $\text{𝒜-𝒵}$. - -
-
- -## Layout - -### Line Breaks - -Hard line breaks are `\\` and `\newline`. - -Temml inserts soft line breaks per TeXbook p. 173 if not in display mode and -no hard line breaks are employed. They work in Chromium and Firefox, but not -in Safari. - -### Reflect - -+:==============================+:===========================+ -| $\reflectbox{ $ \frac a b $}$ | `\reflectbox{$\frac a b$}` | -+-------------------------------+----------------------------+ - -### 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` | $\QED$ `\QED` | $\lightning$ `\lightning` | -+------------------------+----------------------+-----------------------------+------------------------------+ -| $\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 | `\def\macroname{definition to be expanded}` | -| +---------------------------------+--------------------------------+ -| | $\def\foo#1#2{#1^2 #2^3} | `\def\foo#1#2{#1^2 #2^3} | -| | \foo a b + \foo c d$ | \foo a b + \foo c d` | -+-------------------+---------------------------------+--------------------------------+ -| \\xdef | `\xdef\macroname#1#2…{definition to be expanded}` | -+-------------------+------------------------------------------------------------------+ -| \\edef | `\edef\macroname#1#2…{definition}` | -+-------------------+------------------------------------------------------------------+ -| \\let | `\let\foo=\bar` | -+-------------------+------------------------------------------------------------------+ -| \\futurelet | `\futurelet\foo\bar x` | -+-------------------+------------------------------------------------------------------+ -| \\global\\def | `\global\def\macroname#1#2…{definition}` | -+-------------------+------------------------------------------------------------------+ -| `\newcommand` | `\newcommand\macroname[numargs]{definition}` | -| +---------------------------------+--------------------------------+ -| | $\newcommand\foo[2]{#1^2 #2^3} | `\newcommand\foo[2]{#1^2 #2^3} | -| | \foo a b + \foo c d$ | \foo a b + \foo c d ` | -+-------------------+---------------------------------+--------------------------------+ -| `\renewcommand` | `\renewcommand\macroname[numargs]{definition}` | -+-------------------+------------------------------------------------------------------+ -| `\providecommand` | `\providecommand\macroname[numargs]{definition}` | -+-------------------+---------------------------------+--------------------------------+ -{.grid colWidths="136 71 86"} - -To create macros with document-wide scope, use `\gdef`, `\global\let`, or define a -[preamble](./administration.html#preamble) in one of the Temml -[rendering options](./administration.html#options). (Global macros may be disabled for security reasons.) - -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 has no `\par`, so `\long` is ignored. - -## 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` | $\bigtimes$ `\bigtimes` | -+----------------------+--------------------------+----------------------------+-------------------------------+ - -$\sideset{_a^b}{_c^d}\sum$ `\sideset{_a^b}{_c^d}\sum` - -Direct Input: ∫ ∬ ∭ ⨌ ∮ ∯ ∰ ⨖ ∲ ∏ ∐ ∑ ⋀ ⋁ ⋂ ⋃ ⨀ ⨁ ⨂ ⨄ ⨆ ⨅ - -### Binary Operators - -+===========================+===========================+=============================+===========================+ -| $+$ `+` | $\closedvarcap$ | $\lhd$ `\lhd` | $\sslash$ `\sslash` | -| | `\closedvarcap` | | | -+---------------------------+---------------------------+-----------------------------+---------------------------+ -| $-$ `-` | $\closedvarcup$ | $\ltimes$ `\ltimes` | $\threedotcolon$ | -| | `\closedvarcup` | | `\threedotcolon` | -+---------------------------+---------------------------+-----------------------------+---------------------------+ -| $/$ `/` | $\Cup$ `\Cup` | $\minusdot$ `\minusdot` | $\times$ `\times` | -| | or `\doublecup` | | | -+---------------------------+---------------------------+-----------------------------+---------------------------+ -| $*$ `*` | $\cup$ `\cup` | $\minusfdots$ | $\twocaps$ `\twocaps` | -| | | `\minusfdots` | | -+---------------------------+---------------------------+-----------------------------+---------------------------+ -| $\amalg$ `\amalg` | $\cupovercap$ | $\minusrdots$ | $\twocups$ `\twocups` | -| | `\cupovercap` | `\minusrdots` | | -+---------------------------+---------------------------+-----------------------------+---------------------------+ -| $\And$ `\And` or `\with` | $\curlyvee$ `\curlyvee` | $x \mod a$ `x\mod a` | $\typecolon$ `\typecolon` | -+---------------------------+---------------------------+-----------------------------+---------------------------+ -| $\ast$ `\ast` | $\curlywedge$ | $\mp$ `\mp` | $\unlhd$ `\unlhd` | -| | `\curlywedge` | | | -+---------------------------+---------------------------+-----------------------------+---------------------------+ -| $\barcap$ `\barcap` | $\div$ `\div` | $\parr$ `\parr` | $\unrhd$ `\unrhd` | -| | | or `\upand` | | -+---------------------------+---------------------------+-----------------------------+---------------------------+ -| $\barcup$ `\barcup` | $\divideontimes$ | $\pm$ `\pm` | $\uplus$ `\uplus` | -| | `\divideontimes` | | | -+---------------------------+---------------------------+-----------------------------+---------------------------+ -| $\Nor$ `\barvee` or | $\dotminus$  `\dotminus`  | $x \pmod a$ `x \pmod a` | $\Vee$ `\Vee` | -| `\Nor` | | | | -+---------------------------+---------------------------+-----------------------------+---------------------------+ -| $\barwedge$ `\barwedge` | $\dotplus$ `\dotplus` | $x \pod a$ `x \pod a` | $\vee$ `\vee` or `\lor` | -| or `\Nand` | | | | -+---------------------------+---------------------------+-----------------------------+---------------------------+ -| $\bmod$ `\bmod` | $\doublebarvee$ | $\rhd$ `\rhd` | $\veebar$ `\veebar` or | -| | `\doublebarvee` | | `\Xor` | -+---------------------------+---------------------------+-----------------------------+---------------------------+ -| $\bowtie$ `\bowtie` or\ | $\doublebarwedge$ | $\rightouterjoin$ | $\veedot$ `\veedot` | -| `\Join` | `\doublebarwedge` | `\rightouterjoin` | | -+---------------------------+---------------------------+-----------------------------+---------------------------+ -| $\bullet$ `\bullet` | $\fullouterjoin$ | $\rightthreetimes$ | $\veedoublebar$ | -| | `\fullouterjoin` | `\rightthreetimes` | `\veedoublebar` | -+---------------------------+---------------------------+-----------------------------+---------------------------+ -| $\Cap$ `\Cap` | $\gtrdot$ `\gtrdot` | $\rtimes$ `\rtimes` | $\veeonvee$ `\veeonvee` | -| or `\doublecap` | | | | -+---------------------------+---------------------------+-----------------------------+---------------------------+ -| $\cap$ `\cap` | $\intercal$ `\intercal` | $\setminus$ `\setminus` | $\Wedge$ `\Wedge` | -+---------------------------+---------------------------+-----------------------------+---------------------------+ -| $\capbarcup$ `\capbarcup` | $\interleave$ | $\shuffle$ `\shuffle` | $\wedge$ `\wedge` or | -| | `\interleave` | | `\land` | -+---------------------------+---------------------------+-----------------------------+---------------------------+ -| $\capdot$ `\capdot` | $\invlazys$ `\invlazys` | $\smallsetminus$ | $\wedgebar$ `\wedgebar` | -| | | `\smallsetminus` | | -+---------------------------+---------------------------+-----------------------------+---------------------------+ -| $\capovercup$ | $\leftthreetimes$ | $\smashtimes$ `\smashtimes` | $\wedgedot$ `\wedgedot` | -| `\capovercup` | `\leftthreetimes` | | | -+---------------------------+---------------------------+-----------------------------+---------------------------+ -| $\cdot$ `\cdot` | $\leftouterjoin$ | $\sqcap$ `\sqcap` | $\wedgedoublebar$ | -| | `\leftouterjoin` | | `\wedgedoublebar` | -+---------------------------+---------------------------+-----------------------------+---------------------------+ -| $\cdotp$ `\cdotp` | $\leftmodels$ | $\Sqcap$ `\Sqcap` | $\wedgeonwedge$ | -| | `\leftmodels` | | `\wedgeonwedge` | -+---------------------------+---------------------------+-----------------------------+---------------------------+ -| $\centerdot$ `\centerdot` | $\ldotp$ `\ldotp` | $\sqcup$ `\sqcup` | $\wr$ `\wr` | -+---------------------------+---------------------------+-----------------------------+---------------------------+ -| $\circ$ `\circ` | $\lessdot$ `\lessdot` | $\Sqcup$ `\Sqcup` | ¶ | -+---------------------------+---------------------------+-----------------------------+---------------------------+ - -The _texvc_ extension provides $\plusmn$ `\plusmn`. - -Direct Input: + - / ∖ * ⋅ ∘ ± × ÷ ∓ ∔ ∧ ∨ ∩ ∪ ≀ ⊎ ⊓ ⊔ ⋈ ⟕ ⟖ ⟗ - -### Geometric Binary Operators - -+=====================================+=====================================+===================================+ -| $\bigcirc$ `\bigcirc` | $\circledvert$ `\circledvert` | $\ominus$ `\ominus` | -+-------------------------------------+-------------------------------------+-----------------------------------+ -| $\blackhourglass$ `\blackhourglass` | $\circlehbar$ `\circlehbar` | $\operp$ `\operp` | -+-------------------------------------+-------------------------------------+-----------------------------------+ -| $\boxast$ `\boxast` | $\concavediamond$ `\concavediamond` | $\oplus$ `\oplus` | -+-------------------------------------+-------------------------------------+-----------------------------------+ -| $\boxbox$ `\boxbox` | $\concavediamondtickleft$ | $\oslash$ `\oslash` | -| | `\concavediamondtickleft` | | -+-------------------------------------+-------------------------------------+-----------------------------------+ -| $\boxcircle$ `\boxcircle` | $\concavediamondtickright$ | $\otimes$ `\otimes` | -| | `\concavediamondtickright` | | -+-------------------------------------+-------------------------------------+-----------------------------------+ -| $\boxdot$ `\boxdot` | $\diamond$ `\diamond` | $\Otimes$ `\Otimes` | -+-------------------------------------+-------------------------------------+-----------------------------------+ -| $\boxminus$ `\boxminus` | $\hourglass$ `\hourglass` | $\otimeshat$ `\otimeshat` | -+-------------------------------------+-------------------------------------+-----------------------------------+ -| $\boxplus$ `\boxplus` | $\lozengeminus$ `\lozengeminus` | $\star$ `\star` | -+-------------------------------------+-------------------------------------+-----------------------------------+ -| $\boxtimes$ `\boxtimes` | $\obar$ `\obar` | $\triangle$ `\triangle` | -+-------------------------------------+-------------------------------------+-----------------------------------+ -| $\circledast$ `\circledast` | $\obslash$ `\obslash` | $\triangleminus$ `\triangleminus` | -+-------------------------------------+-------------------------------------+-----------------------------------+ -| $\circledcirc$ `\circledcirc` | $\odiv$ `\odiv` | $\triangleplus$ `\triangleplus` | -+-------------------------------------+-------------------------------------+-----------------------------------+ -| $\circleddash$ `\circleddash` | $\odot$ `\odot` | $\triangletimes$ `\triangletimes` | -+-------------------------------------+-------------------------------------+-----------------------------------+ -| $\circledequal$ `\circledequal` | $\ogreaterthan$ `\ogreaterthan` | $\whitesquaretickleft$ | -| | | `\whitesquaretickleft` | -+-------------------------------------+-------------------------------------+-----------------------------------+ -| $\circledparallel$ | $\olessthan$ `\olessthan` | $\whitesquaretickright$ | -| `\circledparallel` | | `\whitesquaretickright` | -+-------------------------------------+-------------------------------------+-----------------------------------+ - -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}` | $a_{\angl n}$   `a_{\angl n}` | -+--------------------------------+--------------------------------+ -| $\sqrt[3]{x}$ `\sqrt[3]{x}` | $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` | $\lessgtr$ | $\smile$ `\smile` | -| | | `\lessgtr` | | -+----------------------+----------------------+----------------------+----------------------+ -| $<$ `<` | $\eqcolon$ | $\lesssim$ | $\sqsubset$ | -| | `\eqcolon` or\ | `\lesssim` | `\sqsubset` | -| |   `\minuscolon` | | | -+----------------------+----------------------+----------------------+----------------------+ -| $>$ `>` | $\Eqcolon$ | $\ll$ `\ll` | $\sqsubseteq$ | -| | `\Eqcolon` or\ | | `\sqsubseteq` | -| | `\minuscoloncolon` | | | -+----------------------+----------------------+----------------------+----------------------+ -| $:$ `:` | $\eqqcolon$ | $\lll$ `\lll` | $\sqsupset$ | -| | `\eqqcolon` | | `\sqsupset` | -+----------------------+----------------------+----------------------+----------------------+ -| $:=$ `:=` | $\Eqqcolon$ | $\llless$ `\llless` | $\sqsupseteq$ | -| | `\Eqqcolon` | | `\sqsupseteq` | -+----------------------+----------------------+----------------------+----------------------+ -| $\approx$ `\approx` | $\eqdef$ `\eqdef` | $\lt$ `\lt` | $\stareq$ `\stareq` | -+----------------------+----------------------+----------------------+----------------------+ -| $\approxeq$ | $\eqsim$ `\eqsim` | $\measeq$ `\measeq` | $\Subset$ `\Subset` | -| `\approxeq` | | | | -+----------------------+----------------------+----------------------+----------------------+ -| $\arceq$ `\arceq` | $\eqslantgtr$ | $\mid$ `\mid` | $\subset$ `\subset` | -| | `\eqslantgtr` | | | -+----------------------+----------------------+----------------------+----------------------+ -| $\asymp$ `\asymp` | $\eqslantless$ | $\models$ `\models` | $\subseteq$ | -| | `\eqslantless` | | `\subseteq` | -+----------------------+----------------------+----------------------+----------------------+ -| $\backcong$ | $\equiv$ `\equiv` | $\multimap$ | $\subseteqq$ | -| `\backcong` | | `\multimap` | `\subseteqq` | -+----------------------+----------------------+----------------------+----------------------+ -| $\backepsilon$ | $\fallingdotseq$ | $\multimapboth$ | $\succ$ `\succ` | -| `\backepsilon` | `\fallingdotseq` | `\multimapboth` | | -+----------------------+----------------------+----------------------+----------------------+ -| $\backsim$ | $\frown$ `\frown` | $\multimapinv$ | $\succapprox$ | -| `\backsim` | | `\multimapinv` | `\succapprox` | -+----------------------+----------------------+----------------------+----------------------+ -| $\backsimeq$ | $\ge$ `\ge` | $\origof$ `\origof` | $\succcurlyeq$ | -| `\backsimeq` | | | `\succcurlyeq` | -+----------------------+----------------------+----------------------+----------------------+ -| $\between$ | $\geq$ `\geq` | $\owns$ `\owns` | $\succeq$ `\succeq` | -| `\between` | | | | -+----------------------+----------------------+----------------------+----------------------+ -| $\bumpeq$ `\bumpeq` | $\geqq$ `\geqq` | $\parallel$ | $\succsim$ | -| | | `\parallel` | `\succsim` | -+----------------------+----------------------+----------------------+----------------------+ -| $\Bumpeq$ `\Bumpeq` | $\geqslant$ | $\perp$ `\perp` | $\Supset$ `\Supset` | -| | `\geqslant` | | | -+----------------------+----------------------+----------------------+----------------------+ -| $\circeq$ `\circeq` | $\gg$ `\gg` | $\Perp$ `\Perp` | $\supset$ `\supset` | -+----------------------+----------------------+----------------------+----------------------+ -| $\coh$ `\coh` | $\ggg$ `\ggg` | $\pitchfork$ | $\supseteq$ | -| | | `\pitchfork` | `\supseteq` | -+----------------------+----------------------+----------------------+----------------------+ -| $\colonapprox$ | $\gggtr$ `\gggtr` | $\prec$ `\prec` | $\supseteqq$ | -| `\colonapprox` | | | `\supseteqq` | -+----------------------+----------------------+----------------------+----------------------+ -| $\Colonapprox$ | $\gt$ `\gt` | $\precapprox$ | $\thickapprox$ | -| `\Colonapprox` or\ | | `\precapprox` | `\thickapprox` | -| `\coloncolonapprox` | | | | -+----------------------+----------------------+----------------------+----------------------+ -| $\coloneq$ | $\gtrapprox$ | $\preccurlyeq$ | $\thicksim$ | -| `\coloneq` or\ | `\gtrapprox` | `\preccurlyeq` | `\thicksim` | -|  `\colonminus` | | | | -+----------------------+----------------------+----------------------+----------------------+ -| $\Coloneq$ | $\gtreqless$ | $\preceq$ `\preceq` | $\trianglelefteq$ | -| `\Coloneq` or\ | `\gtreqless` | | `\trianglelefteq` | -|  `\coloncolonminus` | | | | -+----------------------+----------------------+----------------------+----------------------+ -| $\coloneqq$ | $\gtreqqless$ | $\precsim$ | $\triangleq$ | -| `\coloneqq` or\ | `\gtreqqless` | `\precsim` | `\triangleq` | -|  `\colonequals` | | | | -+----------------------+----------------------+----------------------+----------------------+ -| $\Coloneqq$ | $\gtrless$ | $\propto$ `\propto` | $\trianglerighteq$ | -| `\Coloneqq` or \ | `\gtrless` | | `\trianglerighteq` | -|  `\coloncolonequals` | | | | -+----------------------+----------------------+----------------------+----------------------+ -| $\colonsim$ | $\gtrsim$ `\gtrsim` | $\questeq$ | $\varpropto$ | -| `\colonsim` | | `\questeq` | `\varpropto` | -+----------------------+----------------------+----------------------+----------------------+ -| $\Colonsim$ | $\imageof$ | \:`\ratio` or\ | $\vartriangle$ | -| `\Colonsim` or\ | `\imageof` |   `\vcentcolon` | `\vartriangle` | -|  `\coloncolonsim` | | | | -+----------------------+----------------------+----------------------+----------------------+ -| $\cong$ `\cong` | $\in$ `\in` or | $\risingdotseq$ | $\vartriangleleft$ | -| | `\isin` | `\risingdotseq` | `\vartriangleleft` | -+----------------------+----------------------+----------------------+----------------------+ -| $\curlyeqprec$ | $\incoh$ `\incoh` | $\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` | $\VDash$ `VDash` | -| | `\leqslant` | | | -+----------------------+----------------------+----------------------+----------------------+ -| $\Doteq$ `\Doteq` | $\lessapprox$ | $\sincoh$ `\sincoh` | $\Vvdash$ `\Vvdash` | -| | `\lessapprox` | | | -+----------------------+----------------------+----------------------+----------------------+ -| $\doteqdot$ | $\lesseqgtr$ | $\smallfrown$ | $\veeeq$ `\veeeq` | -| `\doteqdot` | `\lesseqgtr` | `\smallfrown` | | -+----------------------+----------------------+----------------------+----------------------+ -| $\eqeq$ `\eqeq` | $\lesseqqgtr$ | $\smallsmile$ | $\wedgeq$ `\wedgeq` | -| | `\lesseqqgtr` | `\smallsmile` | | -+----------------------+----------------------+----------------------+----------------------+ - -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$ | $\restriction$ | -| `\circlearrowleft` | `\Leftrightarrow` | `\restriction` | -+-------------------------+---------------------------+-------------------------+ -| $\circlearrowright$ | $\leftrightarrows$ | $\rightarrow$ | -| `\circlearrowright` | `\leftrightarrows` | `\rightarrow` | -+-------------------------+---------------------------+-------------------------+ -| $\curvearrowleft$ | $\leftrightharpoons$ | $\Rightarrow$ | -| `\curvearrowleft` | `\leftrightharpoons` | `\Rightarrow` | -+-------------------------+---------------------------+-------------------------+ -| $\curvearrowright$ | $\leftrightsquigarrow$ | $\rightarrowtail$ | -| `\curvearrowright` | `\leftrightsquigarrow` | `\rightarrowtail` | -+-------------------------+---------------------------+-------------------------+ -| $\dashleftarrow$ | $\Lleftarrow$ | $\rightharpoondown$ | -| `\dashleftarrow` | `\Lleftarrow` | `\rightharpoondown` | -+-------------------------+---------------------------+-------------------------+ -| $\dashrightarrow$ | $\longleftarrow$ | $\rightharpoonup$ | -| `\dashrightarrow` | `\longleftarrow` | `\rightharpoonup` | -+-------------------------+---------------------------+-------------------------+ -| $\downarrow$ | $\Longleftarrow$ | $\rightleftarrows$ | -| `\downarrow` | `\Longleftarrow` | `\rightleftarrows` | -+-------------------------+---------------------------+-------------------------+ -| $\Downarrow$ | $\longleftrightarrow$ | $\rightleftharpoons$ | -| `\Downarrow` | `\longleftrightarrow` | `\rightleftharpoons` | -+-------------------------+---------------------------+-------------------------+ -| $\downdownarrows$ | $\Longleftrightarrow$ | $\rightrightarrows$ | -| `\downdownarrows` | `\Longleftrightarrow` | `\rightrightarrows` | -+-------------------------+---------------------------+-------------------------+ -| $\downharpoonleft$ | $\longmapsto$ | $\rightsquigarrow$ | -| `\downharpoonleft` | `\longmapsto` | `\rightsquigarrow` | -+-------------------------+---------------------------+-------------------------+ -| $\downharpoonright$ | $\longrightarrow$ | $\Rrightarrow$ | -| `\downharpoonright` | `\longrightarrow` | `\Rrightarrow` | -+-------------------------+---------------------------+-------------------------+ -| $\gets$ `\gets` | $\Longrightarrow$ | $\Rsh$ `\Rsh` | -| | `\Longrightarrow` | | -+-------------------------+---------------------------+-------------------------+ -| $\hookleftarrow$ | $\looparrowleft$ | $\searrow$ `\searrow` | -| `\hookleftarrow` | `\looparrowleft` | | -+-------------------------+---------------------------+-------------------------+ -| $\hookrightarrow$ | $\looparrowright$ | $\swarrow$ `\swarrow` | -| `\hookrightarrow` | `\looparrowright` | | -+-------------------------+---------------------------+-------------------------+ -| $\iff$ `\iff` | $\Lsh$ `\Lsh` | $\to$ `\to` | -+-------------------------+---------------------------+-------------------------+ -| $\impliedby$ | $\mapsfrom$ `\mapsfrom` | $\twoheadleftarrow$ | -| `\impliedby` | | `\twoheadleftarrow` | -+-------------------------+---------------------------+-------------------------+ -| $\implies$ `\implies` | $\mapsto$ `\mapsto` | $\twoheadrightarrow$ | -| | | `\twoheadrightarrow` | -+-------------------------+---------------------------+-------------------------+ -| $\leadsto$ `\leadsto` | $\nearrow$ `\nearrow` | $\uparrow$ `\uparrow` | -+-------------------------+---------------------------+-------------------------+ -| $\leftarrow$ | $\nleftarrow$ | $\Uparrow$ `\Uparrow` | -| `\leftarrow` | `\nleftarrow` | | -+-------------------------+---------------------------+-------------------------+ -| $\Leftarrow$ | $\nLeftarrow$ | $\updownarrow$ | -| `\Leftarrow` | `\nLeftarrow` | `\updownarrow` | -+-------------------------+---------------------------+-------------------------+ -| $\leftarrowtail$ | $\nleftrightarrow$ | $\Updownarrow$ | -| `\leftarrowtail` | `\nleftrightarrow` | `\Updownarrow` | -+-------------------------+---------------------------+-------------------------+ -| $\leftharpoondown$ | $\nLeftrightarrow$ | $\upharpoonleft$ | -| `\leftharpoondown` | `\nLeftrightarrow` | `\upharpoonleft` | -+-------------------------+---------------------------+-------------------------+ -| $\leftharpoonup$ | $\nrightarrow$ | $\upharpoonright$ | -| `\leftharpoonup` | `\nrightarrow` | `\upharpoonright` | -+-------------------------+---------------------------+-------------------------+ -| $\leftleftarrows$ | $\nRightarrow$ | $\upuparrows$ | -| `\leftleftarrows` | `\nRightarrow` | `\upuparrows` | -+-------------------------+---------------------------+-------------------------+ -| $\leftrightarrow$ | $\nwarrow$ `\nwarrow` | | -| `\leftrightarrow` | | | -+-------------------------+---------------------------+-------------------------+ - -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}` | -+--------------------------------+----------------------------------+----------------------------------+ -| | | $\mathscr{AB}$ `\mathscr{AB}` | -| | | | -+--------------------------------+----------------------------------+----------------------------------+ - -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$ `\mathellipsis` | $\angle$ `\angle` | -+------------------------------------+------------------------------------+------------------------------------+ -| $\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$ `\blacksquare` | $\bot$ `\bot` | -+------------------------------------+------------------------------------+------------------------------------+ -| $\text{\textquotedblleft}$ | $\triangledown$ `\triangledown` | $\Bot$ `\Bot` | -| `\text{\textquotedblleft}` | | | -+------------------------------------+------------------------------------+------------------------------------+ -| $"$ `"` | $\triangleleft$ `\triangleleft` | $\text{\textdollar}$ `\$` or | -| | | `\text{\textdollar}` | -+------------------------------------+------------------------------------+------------------------------------+ -| $\text{\textquotedblright}$ | $\triangleright$ `\triangleright` | $\cent$ `\cent` | -| `\text{\textquotedblright}` | | | -+------------------------------------+------------------------------------+------------------------------------+ -| $\colon$ `\colon` | $\bigtriangledown$ | $\pounds$ `\pounds` | -| | `\bigtriangledown` | | -+------------------------------------+------------------------------------+------------------------------------+ -| $\backprime$ `\backprime` | $\bigtriangleup$ `\bigtriangleup` | $\mathsterling$ `\mathsterling` | -+------------------------------------+------------------------------------+------------------------------------+ -| $\prime$ `\prime` | $\blacktriangle$ `\blacktriangle` | $\text{\textsterling}$ | -| | | `\text{\textsterling}` | -+------------------------------------+------------------------------------+------------------------------------+ -| $\text{\textless}$ | $\blacktriangledown$ | $\yen$ `\yen` | -| `\text{\textless}` | `\blacktriangledown` | | -+------------------------------------+------------------------------------+------------------------------------+ -| $\text{\textgreater}$ | $\blacktriangleleft$ | $\euro$ `\euro` | -| `\text{\textgreater}` | `\blacktriangleleft` | | -+------------------------------------+------------------------------------+------------------------------------+ -| $\text{\textbar}$ | $\blacktriangleright$ | $\text{\texteuro}$ | -| `\text{\textbar}` | `\blacktriangleright` | `\text{\texteuro}` | -+------------------------------------+------------------------------------+------------------------------------+ -| $\text{\textbardbl}$ | $\Diamond$ `\Diamond` | $\degree$ `\degree` | -| `\text{\textbardbl}` | | | -+------------------------------------+------------------------------------+------------------------------------+ -| $\text{\textbraceleft}$ | $\lozenge$ `\lozenge` | $\text{\textdegree}$ | -| `\text{\textbraceleft}` | | `\text{\textdegree}` | -+------------------------------------+------------------------------------+------------------------------------+ -| $\text{\textbraceright}$ | $\blacklozenge$ `\blacklozenge` | $\mho$ `\mho` | -| `\text{\textbraceright}` | | | -+------------------------------------+------------------------------------+------------------------------------+ -| $\text{\textbackslash}$ | $\bigstar$ `\bigstar` | $\diagdown$ `\diagdown` | -| `\text{\textbackslash}` | | | -+------------------------------------+------------------------------------+------------------------------------+ -| $\text{\textvisiblespace}$ | $\maltese$ `\maltese` | $\diagup$ `\diagup` | -| `\text{\textvisiblespace}` | | | -+------------------------------------+------------------------------------+------------------------------------+ -| $\text{\P}$ `\text{\P}` or `\P` | $\clubsuit$ `\clubsuit` | $\varclubsuit$ `\varclubsuit` | -+------------------------------------+------------------------------------+------------------------------------+ -| $\text{\S}$ `\text{\S}` or `\S` | $\diamondsuit$ `\diamondsuit` | $\vardiamondsuit$ | -| | | `\vardiamondsuit` | -+------------------------------------+------------------------------------+------------------------------------+ -| $\copyright$ `\copyright` | $\heartsuit$ `\heartsuit` | $\varheartsuit$ `\varheartsuit` | -+------------------------------------+------------------------------------+------------------------------------+ -| $\circledR$ `\circledR` | $\spadesuit$ `\spadesuit` | $\varspadesuit$ `\varspadesuit` | -+------------------------------------+------------------------------------+------------------------------------+ -| $\circledS$ `\circledS` | $\female$ `\female` | $\male$ `\male` | -+------------------------------------+------------------------------------+------------------------------------+ -| $\text{\textregistered}$ | $\astrosun$ `\astrosun` | $\sun$ `\sun` | -| `\text{\textregistered}` | | | -+------------------------------------+------------------------------------+------------------------------------+ -| $\text{\textbullet}$ | $\leftmoon$ `\leftmoon` | $\rightmoon$ `\rightmoon` | -| `\text{\textbullet}` | | | -+------------------------------------+------------------------------------+------------------------------------+ -| $\smiley$ `\smiley` | $\Earth$ `\Earth` | $\flat$ `\flat` | -+------------------------------------+------------------------------------+------------------------------------+ -| $\standardstate$ `\standardstate` | $\natural$ `\natural` | $\sharp$ `\sharp` | -+------------------------------------+------------------------------------+------------------------------------+ -| $\permil$ `\permil` | $\QED$ `\QED` | $\lightning$ `\lightning` | -+------------------------------------+------------------------------------+------------------------------------+ -| $\diameter$ `\diameter` | | | -+------------------------------------+------------------------------------+------------------------------------+ - -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-2024 Ron Kok. -Released under the MIT License

- -
- -
- - - -
- - - - -- [Accents](#accents) -- [Delimiters](#delimiters) -- [Environments](#environments) -- [Letters](#letters) -- [Layout](#layout) -- [Operators](#operators) -- [Relations](#relations) -- [Style](#style-size-and-font) -- [Symbols](#symbols) - -
- - - \ No newline at end of file diff --git a/package.json b/package.json deleted file mode 100644 index d3b704ab..00000000 --- a/package.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "name": "temml", - "version": "0.10.24", - "description": "TeX to MathML conversion in JavaScript.", - "main": "dist/temml.js", - "engines": { - "node": ">=18.13.0" - }, - "exports": { - ".": { - "require": "./dist/temml.cjs", - "import": "./dist/temml.mjs", - "types": "./dist/temml.d.ts" - }, - "./*": "./*" - }, - "homepage": "https://temml.org", - "repository": { - "type": "git", - "url": "git://github.com/ronkok/Temml" - }, - "packageManager": "yarn@3.3.1", - "files": [ - "temml.js", - "src/", - "contrib/", - "dist/" - ], - "license": "MIT", - "devDependencies": { - "eslint": "^8.39.0", - "esm": "^3.2.25", - "rollup": "^2.66.1", - "terser": "^5.14.2" - }, - "scripts": { - "lint": "eslint temml.js src", - "unit-test": "node ./test/unit-test.cjs", - "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" - } -} 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/FiraMath-Regular.woff2 b/site/assets/FiraMath-Regular.woff2 deleted file mode 100644 index c13030cd..00000000 Binary files a/site/assets/FiraMath-Regular.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/LibertinusMath-Regular.woff2 b/site/assets/LibertinusMath-Regular.woff2 deleted file mode 100644 index 823b891b..00000000 Binary files a/site/assets/LibertinusMath-Regular.woff2 and /dev/null differ 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 4d542692..00000000 --- a/site/assets/Temml-Asana.css +++ /dev/null @@ -1,143 +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; - /* Prevent Firefox from omitting the dot on i or j. */ - font-feature-settings: "dtls" off; -} - -math * { - border-color: currentColor; -} - -math { - font-family: Asana Math, math; -} - -/* Next line is active in Firefox and Safari. - * Not in Chromium, which recognizes display: "block math" written inline. */ -math.tml-display { display: block; } - -*.mathcal, -mo.tml-prime { - font-feature-settings: 'salt'; -} - -mrow.tml-cancel { - background: linear-gradient(to top left, - rgba(0,0,0,0) 0%, - rgba(0,0,0,0) calc(50% - 0.06em), - rgba(0,0,0,1) 50%, - rgba(0,0,0,0) calc(50% + 0.06em), - rgba(0,0,0,0) 100%); -} - -mrow.tml-bcancel { - background: linear-gradient(to top right, - rgba(0,0,0,0) 0%, - rgba(0,0,0,0) calc(50% - 0.06em), - rgba(0,0,0,1) 50%, - rgba(0,0,0,0) calc(50% + 0.06em), - rgba(0,0,0,0) 100%); -} - -mrow.tml-xcancel { - background: linear-gradient(to top left, - rgba(0,0,0,0) 0%, - rgba(0,0,0,0) calc(50% - 0.06em), - rgba(0,0,0,1) 50%, - rgba(0,0,0,0) calc(50% + 0.06em), - rgba(0,0,0,0) 100%), - linear-gradient(to top right, - rgba(0,0,0,0) 0%, - rgba(0,0,0,0) calc(50% - 0.06em), - rgba(0,0,0,1) 50%, - rgba(0,0,0,0) calc(50% + 0.06em), - rgba(0,0,0,0) 100%) -} - -/* Prevent f' from overlapping in Chromium */ -mo.prime-pad { - padding-left: 0.08em; -} - -/* Array cell justification in Firefox & WebKit */ -.tml-right { - text-align: right; -} -.tml-left { - text-align: left; -} - -/* Stretch \widetilde & set array cell justification in Chromium */ -@supports (not (-webkit-backdrop-filter: blur(1px))) and (not (-moz-appearance: none)) { - .tml-crooked-2 { - transform: scale(2.0, 1.1) - } - .tml-crooked-3 { - transform: scale(3.0, 1.3) - } - .tml-crooked-4 { - transform: scale(4.0, 1.4) - } - .tml-right { - text-align: -webkit-right; - } - .tml-left { - text-align: -webkit-left; - } -} - -/* Adjust WebKit accents */ -@supports (-webkit-backdrop-filter: blur(1px)) { - .tml-xshift { transform: translate(0px, 0.45em) } - .tml-capshift { transform: translate(0px, 0.35em) } -} - -/* flex-wrap for line-breaking in Chromium */ -math { - display: inline-flex; - flex-wrap: wrap; - align-items: baseline; -} -math > mrow { - padding: 0.5ex 0ex; -} - -/* Avoid flex-wrap in Firefox */ -@-moz-document url-prefix() { - math { display: inline; } - math > mrow { padding: 0 } -} - -/* 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-Fira.css b/site/assets/Temml-Fira.css deleted file mode 100644 index 7596f1e3..00000000 --- a/site/assets/Temml-Fira.css +++ /dev/null @@ -1,154 +0,0 @@ -/* -Fira Math fonts are released under the SIL OPEN FONT LICENSE Version 1.1. - -The Fira Math WOFF2 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: Fira Math; - src: url('FiraMath-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; - /* Prevent Firefox from omitting the dot on i or j. */ - font-feature-settings: "dtls" off; -} - -math * { - border-color: currentColor; -} - -math { - font-family: "Fira Math", math; -} - -/* Next line is active in Firefox and Safari. - * Not in Chromium, which recognizes display: "block math" written inline. */ -math.tml-display { display: block; } - -*.mathscr { - font-family: "Temml"; -} - -/* Chromium prime alignment */ -mo.tml-prime { - font-family: Temml; -} - -mrow.tml-cancel { - background: linear-gradient(to top left, - rgba(0,0,0,0) 0%, - rgba(0,0,0,0) calc(50% - 0.06em), - rgba(0,0,0,1) 50%, - rgba(0,0,0,0) calc(50% + 0.06em), - rgba(0,0,0,0) 100%); -} - -mrow.tml-bcancel { - background: linear-gradient(to top right, - rgba(0,0,0,0) 0%, - rgba(0,0,0,0) calc(50% - 0.06em), - rgba(0,0,0,1) 50%, - rgba(0,0,0,0) calc(50% + 0.06em), - rgba(0,0,0,0) 100%); -} - -mrow.tml-xcancel { - background: linear-gradient(to top left, - rgba(0,0,0,0) 0%, - rgba(0,0,0,0) calc(50% - 0.06em), - rgba(0,0,0,1) 50%, - rgba(0,0,0,0) calc(50% + 0.06em), - rgba(0,0,0,0) 100%), - linear-gradient(to top right, - rgba(0,0,0,0) 0%, - rgba(0,0,0,0) calc(50% - 0.06em), - rgba(0,0,0,1) 50%, - rgba(0,0,0,0) calc(50% + 0.06em), - rgba(0,0,0,0) 100%) -} - -/* Prevent f' from overlapping in Chromium */ -mo.prime-pad { - padding-left: 0.08em; -} - -/* Array cell justification in Firefox & WebKit */ -.tml-right { - text-align: right; -} -.tml-left { - text-align: left; -} - -/* Stretch \widetilde & set array cell justification in Chromium */ -@supports (not (-webkit-backdrop-filter: blur(1px))) and (not (-moz-appearance: none)) { - .tml-crooked-2 { - transform: scale(2.0, 1.1) - } - .tml-crooked-3 { - transform: scale(3.0, 1.3) - } - .tml-crooked-4 { - transform: scale(4.0, 1.4) - } - .tml-right { - text-align: -webkit-right; - } - .tml-left { - text-align: -webkit-left; - } -} - -/* Adjust WebKit accents */ -@supports (-webkit-backdrop-filter: blur(1px)) { - .tml-xshift { transform: translate(0px, 0.45em) } - .tml-capshift { transform: translate(0px, 0.35em) } -} - -/* flex-wrap for line-breaking in Chromium */ -math { - display: inline-flex; - flex-wrap: wrap; - align-items: baseline; -} -math > mrow { - padding: 0.5ex 0ex; -} - -/* Avoid flex-wrap in Firefox */ -@-moz-document url-prefix() { - math { display: inline; } - math > mrow { padding: 0 } -} - -/* 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 bd2fd0a7..00000000 --- a/site/assets/Temml-Latin-Modern.css +++ /dev/null @@ -1,157 +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; - /* Prevent Firefox from omitting the dot on i or j. */ - font-feature-settings: "dtls" off; -} - -math * { - border-color: currentColor; -} - -math { - font-family: "Latin Modern Math", math; -} - -/* Next line is active in Firefox and Safari. - * Not in Chromium, which recognizes display: "block math" written inline. */ -math.tml-display { display: block; } - -*.mathscr { - font-family: "Temml"; -} - -/* Chromium prime alignment */ -mo.tml-prime { - font-family: Temml; -} - -mrow.tml-cancel { - background: linear-gradient(to top left, - rgba(0,0,0,0) 0%, - rgba(0,0,0,0) calc(50% - 0.06em), - rgba(0,0,0,1) 50%, - rgba(0,0,0,0) calc(50% + 0.06em), - rgba(0,0,0,0) 100%); -} - -mrow.tml-bcancel { - background: linear-gradient(to top right, - rgba(0,0,0,0) 0%, - rgba(0,0,0,0) calc(50% - 0.06em), - rgba(0,0,0,1) 50%, - rgba(0,0,0,0) calc(50% + 0.06em), - rgba(0,0,0,0) 100%); -} - -mrow.tml-xcancel { - background: linear-gradient(to top left, - rgba(0,0,0,0) 0%, - rgba(0,0,0,0) calc(50% - 0.06em), - rgba(0,0,0,1) 50%, - rgba(0,0,0,0) calc(50% + 0.06em), - rgba(0,0,0,0) 100%), - linear-gradient(to top right, - rgba(0,0,0,0) 0%, - rgba(0,0,0,0) calc(50% - 0.06em), - rgba(0,0,0,1) 50%, - rgba(0,0,0,0) calc(50% + 0.06em), - rgba(0,0,0,0) 100%) -} - -/* Prevent f' from overlapping in Chromium */ -mo.prime-pad { - padding-left: 0.08em; -} - -/* Array cell justification in Firefox & WebKit */ -.tml-right { - text-align: right; -} -.tml-left { - text-align: left; -} - -/* Stretch \widetilde & set array cell justification in Chromium */ -@supports (not (-webkit-backdrop-filter: blur(1px))) and (not (-moz-appearance: none)) { - .tml-crooked-2 { - transform: scale(2.0, 1.1) - } - .tml-crooked-3 { - transform: scale(3.0, 1.3) - } - .tml-crooked-4 { - transform: scale(4.0, 1.4) - } - .tml-right { - text-align: -webkit-right; - } - .tml-left { - text-align: -webkit-left; - } -} - -/* Adjust WebKit accents */ -@supports (-webkit-backdrop-filter: blur(1px)) { - .tml-xshift { transform: translate(0px, 0.45em) } - .tml-capshift { transform: translate(0px, 0.35em) } -} - -/* flex-wrap for line-breaking in Chromium */ -math { - display: inline-flex; - flex-wrap: wrap; - align-items: baseline; -} -math > mrow { - padding: 0.5ex 0ex; -} - -/* Avoid flex-wrap in Firefox */ -@-moz-document url-prefix() { - math { display: inline; } - math > mrow { padding: 0 } -} - -/* 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-Libertinus.css b/site/assets/Temml-Libertinus.css deleted file mode 100644 index 647b6465..00000000 --- a/site/assets/Temml-Libertinus.css +++ /dev/null @@ -1,154 +0,0 @@ -/* -The Latin Modern fonts are released under the Open Font License, version 1.1. -See https://github.com/alerque/libertinus/blob/master/OFL.txt. - -The Libertinus WOFF font has been obtained from -https://github.com/alerque/libertinus - -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: Libertinus Math; - src: url('./LibertinusMath-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; - /* Prevent Firefox from omitting the dot on i or j. */ - font-feature-settings: "dtls" off; -} - -math * { - border-color: currentColor; -} - -math { - font-family: Libertinus Math, math; -} - -/* Next line is active in Firefox and Safari. - * Not in Chromium, which recognizes display: "block math" written inline. */ -math.tml-display { display: block; } - -*.mathcal { - font-family: "Cambria Math", 'STIXTwoMath-Regular', "Times New Roman", math; -} - -mo.tml-prime { - font-feature-settings: 'ssty'; -} - -mrow.tml-cancel { - background: linear-gradient(to top left, - rgba(0,0,0,0) 0%, - rgba(0,0,0,0) calc(50% - 0.06em), - rgba(0,0,0,1) 50%, - rgba(0,0,0,0) calc(50% + 0.06em), - rgba(0,0,0,0) 100%); -} - -mrow.tml-bcancel { - background: linear-gradient(to top right, - rgba(0,0,0,0) 0%, - rgba(0,0,0,0) calc(50% - 0.06em), - rgba(0,0,0,1) 50%, - rgba(0,0,0,0) calc(50% + 0.06em), - rgba(0,0,0,0) 100%); -} - -mrow.tml-xcancel { - background: linear-gradient(to top left, - rgba(0,0,0,0) 0%, - rgba(0,0,0,0) calc(50% - 0.06em), - rgba(0,0,0,1) 50%, - rgba(0,0,0,0) calc(50% + 0.06em), - rgba(0,0,0,0) 100%), - linear-gradient(to top right, - rgba(0,0,0,0) 0%, - rgba(0,0,0,0) calc(50% - 0.06em), - rgba(0,0,0,1) 50%, - rgba(0,0,0,0) calc(50% + 0.06em), - rgba(0,0,0,0) 100%) -} - -/* Prevent f' from overlapping in Chromium */ -mo.prime-pad { - padding-left: 0.08em; -} - -/* Array cell justification in Firefox & WebKit */ -.tml-right { - text-align: right; -} -.tml-left { - text-align: left; -} - -/* Stretch \widetilde & set array cell justification in Chromium */ -@supports (not (-webkit-backdrop-filter: blur(1px))) and (not (-moz-appearance: none)) { - .tml-crooked-2 { - transform: scale(2.0, 1.1) - } - .tml-crooked-3 { - transform: scale(3.0, 1.3) - } - .tml-crooked-4 { - transform: scale(4.0, 1.4) - } - .tml-right { - text-align: -webkit-right; - } - .tml-left { - text-align: -webkit-left; - } -} - -/* Adjust WebKit accents */ -@supports (-webkit-backdrop-filter: blur(1px)) { - .tml-xshift { transform: translate(0px, 0.45em) } - .tml-capshift { transform: translate(0px, 0.35em) } -} - -/* flex-wrap for line-breaking in Chromium */ -math { - display: inline-flex; - flex-wrap: wrap; - align-items: baseline; -} -math > mrow { - padding: 0.5ex 0ex; -} - -/* Avoid flex-wrap in Firefox */ -@-moz-document url-prefix() { - math { display: inline; } - math > mrow { padding: 0 } -} - -/* 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 0b58a6d5..00000000 --- a/site/assets/Temml-Local.css +++ /dev/null @@ -1,140 +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", 'STIXTwoMath-Regular', 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; - /* Prevent Firefox from omitting the dot on i or j. */ - font-feature-settings: "dtls" off; -} - -math * { - border-color: currentColor; -} - -/* Next line is active in Firefox and Safari. - * Not in Chromium, which recognizes display: "block math" written inline. */ -math.tml-display { display: block; } - -math .mathscr { - font-family: "Temml"; -} - -mo.tml-prime { - font-family: Temml; -} - -mrow.tml-cancel { - background: linear-gradient(to top left, - rgba(0,0,0,0) 0%, - rgba(0,0,0,0) calc(50% - 0.06em), - rgba(0,0,0,1) 50%, - rgba(0,0,0,0) calc(50% + 0.06em), - rgba(0,0,0,0) 100%); -} - -mrow.tml-bcancel { - background: linear-gradient(to top right, - rgba(0,0,0,0) 0%, - rgba(0,0,0,0) calc(50% - 0.06em), - rgba(0,0,0,1) 50%, - rgba(0,0,0,0) calc(50% + 0.06em), - rgba(0,0,0,0) 100%); -} - -mrow.tml-xcancel { - background: linear-gradient(to top left, - rgba(0,0,0,0) 0%, - rgba(0,0,0,0) calc(50% - 0.06em), - rgba(0,0,0,1) 50%, - rgba(0,0,0,0) calc(50% + 0.06em), - rgba(0,0,0,0) 100%), - linear-gradient(to top right, - rgba(0,0,0,0) 0%, - rgba(0,0,0,0) calc(50% - 0.06em), - rgba(0,0,0,1) 50%, - rgba(0,0,0,0) calc(50% + 0.06em), - rgba(0,0,0,0) 100%) -} - -/* Prevent f' from overlapping in Chromium */ -mo.prime-pad { - padding-left: 0.08em; -} - -/* Array cell justification in Firefox & WebKit */ -.tml-right { - text-align: right; -} -.tml-left { - text-align: left; -} - -/* Stretch \widetilde & set array cell justification in Chromium */ -@supports (not (-webkit-backdrop-filter: blur(1px))) and (not (-moz-appearance: none)) { - .tml-crooked-2 { - transform: scale(2.0, 1.1) - } - .tml-crooked-3 { - transform: scale(3.0, 1.3) - } - .tml-crooked-4 { - transform: scale(4.0, 1.4) - } - .tml-right { - text-align: -webkit-right; - } - .tml-left { - text-align: -webkit-left; - } -} - -/* Adjust WebKit accents */ -@supports (-webkit-backdrop-filter: blur(1px)) { - .tml-xshift { transform: translate(0px, 0.45em) } - .tml-capshift { transform: translate(0px, 0.35em) } -} - -/* flex-wrap for line-breaking in Chromium */ -math { - display: inline-flex; - flex-wrap: wrap; - align-items: baseline; -} -math > mrow { - padding: 0.5ex 0ex; -} - -/* Avoid flex-wrap in Firefox */ -@-moz-document url-prefix() { - math { display: inline; } - math > mrow { padding: 0 } -} - -/* 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 6536ba58..00000000 --- a/site/assets/Temml-STIX2.css +++ /dev/null @@ -1,144 +0,0 @@ -/* -XITS is released under the SIL Open Font License. -See https://github.com/stipub/stixfonts/blob/master/OFL.txt details. - -The STIX2 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; - /* Prevent Firefox from omitting the dot on i or j. */ - font-feature-settings: "dtls" off; -} - -math * { - border-color: currentColor; -} - -/* Next line is active in Firefox and Safari. - * Not in Chromium, which recognizes display: "block math" written inline. */ -math.tml-display { display: block; } - -math { - font-family: STIX2, math; -} - -*.mathscr { - font-feature-settings: 'ss01'; -} - -mo.tml-prime { - font-feature-settings: 'ss04'; -} - -mrow.tml-cancel { - background: linear-gradient(to top left, - rgba(0,0,0,0) 0%, - rgba(0,0,0,0) calc(50% - 0.06em), - rgba(0,0,0,1) 50%, - rgba(0,0,0,0) calc(50% + 0.06em), - rgba(0,0,0,0) 100%); -} - -mrow.tml-bcancel { - background: linear-gradient(to top right, - rgba(0,0,0,0) 0%, - rgba(0,0,0,0) calc(50% - 0.06em), - rgba(0,0,0,1) 50%, - rgba(0,0,0,0) calc(50% + 0.06em), - rgba(0,0,0,0) 100%); -} - -mrow.tml-xcancel { - background: linear-gradient(to top left, - rgba(0,0,0,0) 0%, - rgba(0,0,0,0) calc(50% - 0.06em), - rgba(0,0,0,1) 50%, - rgba(0,0,0,0) calc(50% + 0.06em), - rgba(0,0,0,0) 100%), - linear-gradient(to top right, - rgba(0,0,0,0) 0%, - rgba(0,0,0,0) calc(50% - 0.06em), - rgba(0,0,0,1) 50%, - rgba(0,0,0,0) calc(50% + 0.06em), - rgba(0,0,0,0) 100%) -} - -/* Prevent f' from overlapping in Chromium */ -mo.prime-pad { - padding-left: 0.08em; -} - -/* Array cell justification in Firefox & WebKit */ -.tml-right { - text-align: right; -} -.tml-left { - text-align: left; -} - -/* Stretch \widetilde & set array cell justification in Chromium */ -@supports (not (-webkit-backdrop-filter: blur(1px))) and (not (-moz-appearance: none)) { - .tml-crooked-2 { - transform: scale(2.0, 1.1) - } - .tml-crooked-3 { - transform: scale(3.0, 1.3) - } - .tml-crooked-4 { - transform: scale(4.0, 1.4) - } - .tml-right { - text-align: -webkit-right; - } - .tml-left { - text-align: -webkit-left; - } -} - -/* Adjust WebKit accents */ -@supports (-webkit-backdrop-filter: blur(1px)) { - .tml-xshift { transform: translate(0px, 0.45em) } - .tml-capshift { transform: translate(0px, 0.35em) } -} - -/* flex-wrap for line-breaking in Chromium */ -math { - display: inline-flex; - flex-wrap: wrap; - align-items: baseline; -} -math > mrow { - padding: 0.5ex 0ex; -} - -/* Avoid flex-wrap in Firefox */ -@-moz-document url-prefix() { - math { display: inline; } - math > mrow { padding: 0 } -} - -/* 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 fccefda4..00000000 Binary files a/site/assets/Temml.woff2 and /dev/null differ diff --git a/site/assets/auto-render.min.js b/site/assets/auto-render.min.js deleted file mode 100644 index 55bcd20c..00000000 --- a/site/assets/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/site/assets/copy-tex.min.js b/site/assets/copy-tex.min.js deleted file mode 100644 index cbe6617d..00000000 --- a/site/assets/copy-tex.min.js +++ /dev/null @@ -1 +0,0 @@ -function closestMath(t){const e=t instanceof Element?t:t.parentElement;return e&&e.closest("math")}const defaultCopyDelimiters={inline:["$","$"],display:["$$","$$"]};function replaceMathwithTeX(t,e=defaultCopyDelimiters){const n=t.querySelectorAll("math");for(let t=0;tt instanceof Text?t.textContent:t.outerHTML)).join("");n.setData("text/html",l),n.setData("text/plain",replaceMathwithTeX(i).textContent),t.preventDefault()})); \ No newline at end of file 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 35214c3a..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={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=/^[\x00-\x20]*([^\\/#?]*?)(:|�*58|�*3a|&colon)/i.exec(e);return t?":"!==t[2]?null:/^[a-zA-Z][a-zA-Z0-9+\-.]*$/.test(t[1])?t[1].toLowerCase():null:"_relative"},round:function(e){return+e.toFixed(4)}};class a{constructor(e){e=e||{},this.displayMode=s.deflt(e.displayMode,!1),this.annotate=s.deflt(e.annotate,!1),this.leqno=s.deflt(e.leqno,!1),this.throwOnError=s.deflt(e.throwOnError,!1),this.errorColor=s.deflt(e.errorColor,"#b22222"),this.macros=e.macros||{},this.wrap=s.deflt(e.wrap,"tex"),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){if(e.url&&!e.protocol){const t=s.protocolFromUrl(e.url);if(null==t)return!1;e.protocol=t}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 x{constructor(e){this.text=e}toNode(){return document.createTextNode(this.text)}toMarkup(){return s.escape(this.text)}}class w{constructor(e,t,r){this.alt=t,this.src=e,this.classes=["mord"],this.style=r}hasClass(e){return this.classes.includes(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 v{constructor(e){this.text=e}toNode(){return document.createTextNode(this.text)}toMarkup(){return s.escape(this.toText())}toText(){return this.text}}const A=e=>{let t;return 1===e.length&&"mrow"===e[0].type?(t=e.pop(),t.type="mstyle"):t=new k("mstyle",e),t};var N={MathNode:k,TextNode:v,newDocumentFragment:function(e){return new p(e)}};const T=e=>{let t=0;if(e.body)for(const r of e.body)t+=T(r);else if("supsub"===e.type)t+=T(e.base),e.sub&&(t+=.7*T(e.sub)),e.sup&&(t+=.7*T(e.sup));else if("mathord"===e.type||"textord"===e.type)for(const r of e.text.split("")){const e=r.codePointAt(0);t+=96{const t=S(e.label);if(O.includes(e.label)){const r=T(e.base);1","\\gt",!0),I($,V,"∈","\\in",!0),I($,V,"∉","\\notin",!0),I($,V,"","\\@not"),I($,V,"⊂","\\subset",!0),I($,V,"⊃","\\supset",!0),I($,V,"⊆","\\subseteq",!0),I($,V,"⊇","\\supseteq",!0),I($,V,"⊈","\\nsubseteq",!0),I($,V,"⊈","\\nsubseteqq"),I($,V,"⊉","\\nsupseteq",!0),I($,V,"⊉","\\nsupseteqq"),I($,V,"⊨","\\models"),I($,V,"←","\\leftarrow",!0),I($,V,"≤","\\le"),I($,V,"≤","\\leq",!0),I($,V,"<","\\lt",!0),I($,V,"→","\\rightarrow",!0),I($,V,"→","\\to"),I($,V,"≱","\\ngeq",!0),I($,V,"≱","\\ngeqq"),I($,V,"≱","\\ngeqslant"),I($,V,"≰","\\nleq",!0),I($,V,"≰","\\nleqq"),I($,V,"≰","\\nleqslant"),I($,V,"⫫","\\Perp",!0),I($,_," ","\\ "),I($,_," ","\\space"),I($,_," ","\\nobreakspace"),I(L,_," ","\\ "),I(L,_," "," "),I(L,_," ","\\space"),I(L,_," ","\\nobreakspace"),I($,_,null,"\\nobreak"),I($,_,null,"\\allowbreak"),I($,H,",",","),I(L,H,":",":"),I($,H,";",";"),I($,G,"⊼","\\barwedge"),I($,G,"⊻","\\veebar"),I($,G,"⊙","\\odot",!0),I($,G,"⊕︎","\\oplus"),I($,G,"⊗","\\otimes",!0),I($,W,"∂","\\partial",!0),I($,G,"⊘","\\oslash",!0),I($,G,"⊚","\\circledcirc",!0),I($,G,"⊡","\\boxdot",!0),I($,G,"△","\\bigtriangleup"),I($,G,"▽","\\bigtriangledown"),I($,G,"†","\\dagger"),I($,G,"⋄","\\diamond"),I($,G,"◃","\\triangleleft"),I($,G,"▹","\\triangleright"),I($,U,"{","\\{"),I(L,W,"{","\\{"),I(L,W,"{","\\textbraceleft"),I($,D,"}","\\}"),I(L,W,"}","\\}"),I(L,W,"}","\\textbraceright"),I($,U,"{","\\lbrace"),I($,D,"}","\\rbrace"),I($,U,"[","\\lbrack",!0),I(L,W,"[","\\lbrack",!0),I($,D,"]","\\rbrack",!0),I(L,W,"]","\\rbrack",!0),I($,U,"(","\\lparen",!0),I($,D,")","\\rparen",!0),I($,U,"⦇","\\llparenthesis",!0),I($,D,"⦈","\\rrparenthesis",!0),I(L,W,"<","\\textless",!0),I(L,W,">","\\textgreater",!0),I($,U,"⌊","\\lfloor",!0),I($,D,"⌋","\\rfloor",!0),I($,U,"⌈","\\lceil",!0),I($,D,"⌉","\\rceil",!0),I($,W,"\\","\\backslash"),I($,W,"|","|"),I($,W,"|","\\vert"),I(L,W,"|","\\textbar",!0),I($,W,"‖","\\|"),I($,W,"‖","\\Vert"),I(L,W,"‖","\\textbardbl"),I(L,W,"~","\\textasciitilde"),I(L,W,"\\","\\textbackslash"),I(L,W,"^","\\textasciicircum"),I($,V,"↑","\\uparrow",!0),I($,V,"⇑","\\Uparrow",!0),I($,V,"↓","\\downarrow",!0),I($,V,"⇓","\\Downarrow",!0),I($,V,"↕","\\updownarrow",!0),I($,V,"⇕","\\Updownarrow",!0),I($,j,"∐","\\coprod"),I($,j,"⋁","\\bigvee"),I($,j,"⋀","\\bigwedge"),I($,j,"⨄","\\biguplus"),I($,j,"⋂","\\bigcap"),I($,j,"⋃","\\bigcup"),I($,j,"∫","\\int"),I($,j,"∫","\\intop"),I($,j,"∬","\\iint"),I($,j,"∭","\\iiint"),I($,j,"∏","\\prod"),I($,j,"∑","\\sum"),I($,j,"⨂","\\bigotimes"),I($,j,"⨁","\\bigoplus"),I($,j,"⨀","\\bigodot"),I($,j,"⨉","\\bigtimes"),I($,j,"∮","\\oint"),I($,j,"∯","\\oiint"),I($,j,"∰","\\oiiint"),I($,j,"∱","\\intclockwise"),I($,j,"∲","\\varointclockwise"),I($,j,"⨌","\\iiiint"),I($,j,"⨍","\\intbar"),I($,j,"⨎","\\intBar"),I($,j,"⨏","\\fint"),I($,j,"⨒","\\rppolint"),I($,j,"⨓","\\scpolint"),I($,j,"⨕","\\pointint"),I($,j,"⨖","\\sqint"),I($,j,"⨗","\\intlarhk"),I($,j,"⨘","\\intx"),I($,j,"⨙","\\intcap"),I($,j,"⨚","\\intcup"),I($,j,"⨅","\\bigsqcap"),I($,j,"⨆","\\bigsqcup"),I($,j,"∫","\\smallint"),I(L,P,"…","\\textellipsis"),I($,P,"…","\\mathellipsis"),I(L,P,"…","\\ldots",!0),I($,P,"…","\\ldots",!0),I($,P,"⋰","\\iddots",!0),I($,P,"⋯","\\@cdots",!0),I($,P,"⋱","\\ddots",!0),I($,W,"⋮","\\varvdots"),I($,F,"ˊ","\\acute"),I($,F,"`","\\grave"),I($,F,"¨","\\ddot"),I($,F,"…","\\dddot"),I($,F,"….","\\ddddot"),I($,F,"~","\\tilde"),I($,F,"‾","\\bar"),I($,F,"˘","\\breve"),I($,F,"ˇ","\\check"),I($,F,"^","\\hat"),I($,F,"→","\\vec"),I($,F,"˙","\\dot"),I($,F,"˚","\\mathring"),I($,R,"ı","\\imath",!0),I($,R,"ȷ","\\jmath",!0),I($,W,"ı","ı"),I($,W,"ȷ","ȷ"),I(L,W,"ı","\\i",!0),I(L,W,"ȷ","\\j",!0),I(L,W,"ß","\\ss",!0),I(L,W,"æ","\\ae",!0),I(L,W,"œ","\\oe",!0),I(L,W,"ø","\\o",!0),I($,R,"ø","\\o",!0),I(L,W,"Æ","\\AE",!0),I(L,W,"Œ","\\OE",!0),I(L,W,"Ø","\\O",!0),I($,R,"Ø","\\O",!0),I(L,F,"ˊ","\\'"),I(L,F,"ˋ","\\`"),I(L,F,"ˆ","\\^"),I(L,F,"˜","\\~"),I(L,F,"ˉ","\\="),I(L,F,"˘","\\u"),I(L,F,"˙","\\."),I(L,F,"¸","\\c"),I(L,F,"˚","\\r"),I(L,F,"ˇ","\\v"),I(L,F,"¨",'\\"'),I(L,F,"˝","\\H"),I($,F,"ˊ","\\'"),I($,F,"ˋ","\\`"),I($,F,"ˆ","\\^"),I($,F,"˜","\\~"),I($,F,"ˉ","\\="),I($,F,"˘","\\u"),I($,F,"˙","\\."),I($,F,"¸","\\c"),I($,F,"˚","\\r"),I($,F,"ˇ","\\v"),I($,F,"¨",'\\"'),I($,F,"˝","\\H");const X={"--":!0,"---":!0,"``":!0,"''":!0};I(L,W,"–","--",!0),I(L,W,"–","\\textendash"),I(L,W,"—","---",!0),I(L,W,"—","\\textemdash"),I(L,W,"‘","`",!0),I(L,W,"‘","\\textquoteleft"),I(L,W,"’","'",!0),I(L,W,"’","\\textquoteright"),I(L,W,"“","``",!0),I(L,W,"“","\\textquotedblleft"),I(L,W,"”","''",!0),I(L,W,"”","\\textquotedblright"),I($,W,"°","\\degree",!0),I(L,W,"°","\\degree"),I(L,W,"°","\\textdegree",!0),I($,W,"£","\\pounds"),I($,W,"£","\\mathsterling",!0),I(L,W,"£","\\pounds"),I(L,W,"£","\\textsterling",!0),I($,W,"✠","\\maltese"),I(L,W,"✠","\\maltese"),I($,W,"€","\\euro",!0),I(L,W,"€","\\euro",!0),I(L,W,"€","\\texteuro"),I($,W,"©","\\copyright",!0),I(L,W,"©","\\textcopyright"),I($,W,"⌀","\\diameter",!0),I(L,W,"⌀","\\diameter"),I($,W,"𝛤","\\varGamma"),I($,W,"𝛥","\\varDelta"),I($,W,"𝛩","\\varTheta"),I($,W,"𝛬","\\varLambda"),I($,W,"𝛯","\\varXi"),I($,W,"𝛱","\\varPi"),I($,W,"𝛴","\\varSigma"),I($,W,"𝛶","\\varUpsilon"),I($,W,"𝛷","\\varPhi"),I($,W,"𝛹","\\varPsi"),I($,W,"𝛺","\\varOmega"),I(L,W,"𝛤","\\varGamma"),I(L,W,"𝛥","\\varDelta"),I(L,W,"𝛩","\\varTheta"),I(L,W,"𝛬","\\varLambda"),I(L,W,"𝛯","\\varXi"),I(L,W,"𝛱","\\varPi"),I(L,W,"𝛴","\\varSigma"),I(L,W,"𝛶","\\varUpsilon"),I(L,W,"𝛷","\\varPhi"),I(L,W,"𝛹","\\varPsi"),I(L,W,"𝛺","\\varOmega");const Z='0123456789/@."';for(let e=0;e<14;e++){const t=Z.charAt(e);I($,W,t,t)}const Y='0123456789!@*()-=+";:?/.,';for(let e=0;e<25;e++){const t=Y.charAt(e);I(L,W,t,t)}const K="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";for(let e=0;e<52;e++){const t=K.charAt(e);I($,R,t,t),I(L,W,t,t)}const J="ÇÐÞçþℂℍℕℙℚℝℤℎℏℊℋℌℐℑℒℓ℘ℛℜℬℰℱℳℭℨ";for(let e=0;e<30;e++){const t=J.charAt(e);I($,R,t,t),I(L,W,t,t)}let Q="";for(let e=0;e<52;e++){Q=String.fromCharCode(55349,56320+e),I($,R,Q,Q),I(L,W,Q,Q),Q=String.fromCharCode(55349,56372+e),I($,R,Q,Q),I(L,W,Q,Q),Q=String.fromCharCode(55349,56424+e),I($,R,Q,Q),I(L,W,Q,Q),Q=String.fromCharCode(55349,56580+e),I($,R,Q,Q),I(L,W,Q,Q),Q=String.fromCharCode(55349,56736+e),I($,R,Q,Q),I(L,W,Q,Q),Q=String.fromCharCode(55349,56788+e),I($,R,Q,Q),I(L,W,Q,Q),Q=String.fromCharCode(55349,56840+e),I($,R,Q,Q),I(L,W,Q,Q),Q=String.fromCharCode(55349,56944+e),I($,R,Q,Q),I(L,W,Q,Q),Q=String.fromCharCode(55349,56632+e),I($,R,Q,Q),I(L,W,Q,Q);const t=K.charAt(e);Q=String.fromCharCode(55349,56476+e),I($,R,t,Q),I(L,W,t,Q)}for(let e=0;e<10;e++)Q=String.fromCharCode(55349,57294+e),I($,R,Q,Q),I(L,W,Q,Q),Q=String.fromCharCode(55349,57314+e),I($,R,Q,Q),I(L,W,Q,Q),Q=String.fromCharCode(55349,57324+e),I($,R,Q,Q),I(L,W,Q,Q),Q=String.fromCharCode(55349,57334+e),I($,R,Q,Q),I(L,W,Q,Q);const ee="([{⌊⌈⟨⟮⎰⟦⦃",te=")]}⌋⌉⟩⟯⎱⟦⦄";const re=function(e,t,r){return!E[t][e]||!E[t][e].replace||55349===e.charCodeAt(0)||Object.prototype.hasOwnProperty.call(X,e)&&r&&(r.fontFamily&&"tt"===r.fontFamily.slice(4,6)||r.font&&"tt"===r.font.slice(4,6))||(e=E[t][e].replace),new N.TextNode(e)},ne=e=>{if("mrow"!==e.type&&"mstyle"!==e.type)return e;if(0===e.children.length)return e;if(!e.children[0].attributes||"mtext"!==e.children[0].type)return e;const t=e.children[0].attributes.mathvariant||"",r=new N.MathNode("mtext",[new N.TextNode(e.children[0].children[0].text)]);for(let n=1;n0&&" "===r.children[0].text.charAt(n-1)&&(r.children[0].text=r.children[0].text.slice(0,-1)+" ");for(const[t,n]of Object.entries(e.attributes))r.attributes[t]=n;return r},oe=/^[0-9]$/,se=function(e,t=!1){if(!(1!==e.length||e[0]instanceof p))return e[0];if(!t){e[0]instanceof k&&"mo"===e[0].type&&!e[0].attributes.fence&&(e[0].attributes.lspace="0em",e[0].attributes.rspace="0em");const t=e.length-1;e[t]instanceof k&&"mo"===e[t].type&&!e[t].attributes.fence&&(e[t].attributes.lspace="0em",e[t].attributes.rspace="0em")}return new N.MathNode("mrow",e)},ae=e=>"atom"===e.type&&"rel"===e.family||"mclass"===e.type&&"mrel"===e.mclass,ie=function(e,t,r=!1){if(!r&&1===e.length){const r=ce(e[0],t);return r instanceof k&&"mo"===r.type&&(r.setAttribute("lspace","0em"),r.setAttribute("rspace","0em")),[r]}(e=>{if(e.length<2)return;const t=[];let r=!1;for(let n=0;n0;r--)t[r-1].end===t[r].start-2&&(n=e[t[r].start-1],o=e[t[r].start],("textord"===n.type&&"."===n.text||"atom"===n.type&&","===n.text)&&n.loc&&o.loc&&n.loc.end===o.loc.start)&&(t[r-1].end=t[r].end,t.splice(r,1));var n,o;for(let r=t.length-1;r>=0;r--){for(let n=t[r].start+1;n<=t[r].end;n++)e[t[r].start].text+=e[n].text;if(e.splice(t[r].start+1,t[r].end-t[r].start),e.length>t[r].start+1){const n=e[t[r].start+1];"supsub"===n.type&&n.base&&"textord"===n.base.type&&oe.test(n.base.text)&&(n.base.text=e[t[r].start].text+n.base.text,e.splice(t[r].start,1))}}})(e);const n=[];for(let r=0;r0&&ae(e[r])&&ae(e[r-1])&&o.setAttribute("lspace","0em"),n.push(o)}return n},le=function(e,t,r=!1){return se(ie(e,t,r),r)},ce=function(t,r){if(!t)return new N.MathNode("mrow");if(l[t.type]){return l[t.type](t,r)}throw new e("Got group of unknown type: '"+t.type+"'")},me=e=>new N.MathNode("mtd",[],[],{padding:"0",width:"50%"});function ue(e,t,r,n){let o=null;1===e.length&&"tag"===e[0].type&&(o=e[0].tag,e=e[0].body);const s=ie(e,r),a=n.displayMode||n.annotate?"none":n.wrap,i=0===s.length?null:s[0];let l=1===s.length&&null===o&&i instanceof k?s[0]:function(e,t,r){const n=[];let o=[],s=[],a=0,i=0,l=0;for(;i0&&o.push(new N.MathNode("mrow",s)),o.push(r),s=[];const e=new N.MathNode("mtd",o);e.style.textAlign="left",n.push(new N.MathNode("mtr",[e])),o=[],i+=1}else{if(s.push(r),r.type&&"mo"===r.type&&1===r.children.length&&!Object.hasOwn(r.attributes,"movablelimits")){const n=r.children[0].text;if(ee.indexOf(n)>-1)l+=1;else if(te.indexOf(n)>-1)l-=1;else if(0===l&&"="===t&&"="===n){if(a+=1,a>1){s.pop();const e=new N.MathNode("mrow",s);o.push(e),s=[r]}}else if(0===l&&"tex"===t&&"∇"!==n){const t=i0){const e=new N.MathNode("mrow",s);o.push(e)}if(n.length>0){const e=new N.MathNode("mtd",o);e.style.textAlign="left";const t=new N.MathNode("mtr",[e]);n.push(t);const s=new N.MathNode("mtable",n);return r||(s.setAttribute("columnalign","left"),s.setAttribute("rowspacing","0em")),s}return N.newDocumentFragment(o)}(s,a,n.displayMode);if(o&&(l=((e,t,r,n)=>{t=le(t[0].body,r),(t=ne(t)).classes.push("tml-tag"),e=new N.MathNode("mtd",[e]);const o=[me(),e,me()];o[n?0:2].classes.push(n?"tml-left":"tml-right"),o[n?0:2].children.push(t);const s=new N.MathNode("mtr",o,["tml-tageqn"]),a=new N.MathNode("mtable",[s]);return a.style.width="100%",a.setAttribute("displaystyle","true"),a})(l,o,r,n.leqno)),n.annotate){const e=new N.MathNode("annotation",[new N.TextNode(t)]);e.setAttribute("encoding","application/x-tex"),l=new N.MathNode("semantics",[l,e])}const c=new N.MathNode("math",[l]);return n.xml&&c.setAttribute("xmlns","http://www.w3.org/1998/Math/MathML"),n.displayMode&&(c.setAttribute("display","block"),c.style.display="block math",c.classes=["tml-display"]),c}const de="ABCDEFGHIJKLMNOPQRSTUVWXYZbdfhkltΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩβδλζφθψ𝐀𝐁𝐂𝐃𝐄𝐅𝐆𝐇𝐈𝐉𝐊𝐋𝐌𝐍𝐎𝐏𝐐𝐑𝐒𝐓𝐔𝐕𝐖𝐗𝐘𝐙𝐛𝐝𝐟𝐡𝐤𝐥𝐭",pe=new Set(["\\alpha","\\gamma","\\delta","\\epsilon","\\eta","\\iota","\\kappa","\\mu","\\nu","\\pi","\\rho","\\sigma","\\tau","\\upsilon","\\chi","\\psi","\\omega","\\imath","\\jmath"]),he=new Set(["\\Gamma","\\Delta","\\Sigma","\\Omega","\\beta","\\delta","\\lambda","\\theta","\\psi"]),ge=(e,t)=>{const r=e.isStretchy?M(e):new N.MathNode("mo",[re(e.label,e.mode)]);if("\\vec"===e.label)r.style.transform="scale(0.75) translate(10%, 30%)";else if(r.style.mathStyle="normal",r.style.mathDepth="0",be.has(e.label)&&s.isCharacterBox(e.base)){let t="";const n=e.base.text;("acegıȷmnopqrsuvwxyzαγεηικμνοπρςστυχωϕ𝐚𝐜𝐞𝐠𝐦𝐧𝐨𝐩𝐪𝐫𝐬𝐮𝐯𝐰𝐱𝐲𝐳".indexOf(n)>-1||pe.has(n))&&(t="tml-xshift"),(de.indexOf(n)>-1||he.has(n))&&(t="tml-capshift"),t&&r.classes.push(t)}e.isStretchy||r.setAttribute("stretchy","false");return new N.MathNode("\\c"===e.label?"munder":"mover",[ce(e.base,t),r])},fe=new Set(["\\acute","\\grave","\\ddot","\\dddot","\\ddddot","\\tilde","\\bar","\\breve","\\check","\\hat","\\vec","\\dot","\\mathring"]),be=new Set(["\\acute","\\bar","\\breve","\\check","\\dot","\\ddot","\\grave","\\hat","\\mathring","\\'","\\^","\\~","\\=","\\u","\\.",'\\"',"\\r","\\H","\\v"]);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=!fe.has(e.funcName);return{type:"accent",mode:e.parser.mode,label:e.funcName,isStretchy:n,base:r}},mathmlBuilder:ge}),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,base:r}},mathmlBuilder:ge}),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=M(e);r.style["math-depth"]=0;return new N.MathNode("munder",[ce(e.base,t),r])}});const ye={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},xe=["em","ex","mu","pt","mm","cm","in","px","bp","pc","dd","cc","nd","nc","sp"],we=function(e){return"string"!=typeof e&&(e=e.unit),xe.indexOf(e)>-1},ke=e=>[1,.7,.5][Math.max(e-1,0)],ve=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*ye[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/ke(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*ye[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+"'")}},Ae=e=>{const t=new N.MathNode("mspace");return t.setAttribute("width",e+"em"),t},Ne=(e,t=.3,r=0)=>{if(null==e&&0===r)return Ae(t);const n=e?[e]:[];return 0!==t&&n.unshift(Ae(t)),r>0&&n.push(Ae(r)),new N.MathNode("mrow",n)},Te=(e,t)=>Number(e)/ke(t),qe=(e,t,r,n)=>{const o=B(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("lspace","0"),o.setAttribute("rspace",s?"0.5em":"0");const i=n.withLevel(n.level<2?2:3),l=Te(a,i.level),c=Te(a,3),m=Ne(null,l.toFixed(4),0),u=Ne(null,c.toFixed(4),0),d=Te(s?0:.3,i.level).toFixed(4);let p,h;const g=t&&t.body&&(t.body.body||t.body.length>0);if(g){let e=ce(t,i);e=Ne(e,d,d),p=new N.MathNode("mover",[e,u])}const f=r&&r.body&&(r.body.body||r.body.length>0);if(f){let e=ce(r,i);e=Ne(e,d,d),h=new N.MathNode("munder",[e,u])}let b;return b=g||f?g&&f?new N.MathNode("munderover",[o,h,p]):g?new N.MathNode("mover",[o,p]):new N.MathNode("munder",[o,h]):new N.MathNode("mover",[o,m]),"3.0"===a&&(b.style.height="1em"),b.setAttribute("accent","false"),b};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=[qe(e.name,e.body,e.below,t)];return r.unshift(Ae(.2778)),r.push(Ae(.2778)),new N.MathNode("mrow",r)}});const Se={"\\xtofrom":["\\xrightarrow","\\xleftarrow"],"\\xleftrightharpoons":["\\xleftharpoonup","\\xrightharpoondown"],"\\xrightleftharpoons":["\\xrightharpoonup","\\xleftharpoondown"],"\\yieldsLeftRight":["\\yields","\\yieldsLeft"],"\\equilibrium":["\\longrightharpoonup","\\longleftharpoondown"],"\\equilibriumRight":["\\longrightharpoonup","\\eqleftharpoondown"],"\\equilibriumLeft":["\\eqrightharpoonup","\\longleftharpoondown"]};function Oe(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=Me(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 Me(e){return e&&("atom"===e.type||Object.prototype.hasOwnProperty.call(z,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=Se[e.name][0],n=Se[e.name][1],o=qe(r,e.body,e.upperArrowBelow,t),s=qe(n,e.lowerArrowBody,e.below,t);let a;const i=new N.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 N.MathNode("mpadded",[s]);e.setAttribute("width","0.5em"),a=new N.MathNode("mpadded",[Ae(.2778),e,i,Ae(.2778)])}else i.setAttribute("width","\\equilibriumRight"===e.name?"0.5em":"0"),a=new N.MathNode("mpadded",[Ae(.2778),i,s,Ae(.2778)]);return a.setAttribute("voffset","-0.18em"),a.setAttribute("height","-0.18em"),a.setAttribute("depth","+0.18em"),a}});const Ce={">":"\\\\cdrightarrow","<":"\\\\cdleftarrow","=":"\\\\cdlongequal",A:"\\uparrow",V:"\\downarrow","|":"\\Vert",".":"no arrow"},ze=e=>"textord"===e.type&&"@"===e.text;function Ee(e,t,r){const n=Ce[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]],[])],semisimple:!0};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 N.MathNode("mrow",[ce(e.label,t)]);return r=new N.MathNode("mpadded",[r]),r.setAttribute("width","0"),"left"===e.side&&r.setAttribute("lspace","-1width"),r.setAttribute("voffset","0.7em"),r=new N.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 N.MathNode("mrow",[ce(e.fragment,t)])}),c({type:"textord",names:["\\@char"],props:{numArgs:1,allowedInText:!0},handler({parser:t,token:r},n){const o=Oe(n[0],"ordgroup").body;let s="";for(let e=0;e{let t=e.toString(16);return 1===t.length&&(t="0"+t),t},Pe=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}'),Re=(t,r)=>{let n="";if("HTML"===t){if(!Ie.test(r))throw new e("Invalid HTML input.");n=r}else if("RGB"===t){if(!Le.test(r))throw new e("Invalid RGB input.");r.split(",").map((e=>{n+=De(Number(e.trim()))}))}else{if(!Fe.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+=De(Number((255*r).toFixed(0)))}))}return"#"!==n.charAt(0)&&(n="#"+n),n},je=(t,r,n)=>{const o=`\\\\color@${t}`;if(!$e.exec(t))throw new e("Invalid color: '"+t+"'",n);return Ge.test(t)?"#"+t:("#"===t.charAt(0)||(r.has(o)?t=r.get(o).tokens[0].text:Pe[t]&&(t=Pe[t])),t)},Ue=(e,t)=>{let r=ie(e.body,t.withColor(e.color));return r=r.map((t=>(t.style.color=e.color,t))),N.newDocumentFragment(r)};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]&&Oe(n[0],"raw").string;let s="";if(o){const e=Oe(r[0],"raw").string;s=Re(o,e)}else s=je(Oe(r[0],"raw").string,e.gullet.macros,t);const a=r[1];return{type:"color",mode:e.mode,color:s,body:d(a)}},mathmlBuilder:Ue}),c({type:"color",names:["\\color"],props:{numArgs:1,numOptionalArgs:1,allowedInText:!0,argTypes:["raw","raw"]},handler({parser:e,breakOnTokenText:t,token:r},n,o){const s=o[0]&&Oe(o[0],"raw").string;let a="";if(s){const e=Oe(n[0],"raw").string;a=Re(s,e)}else a=je(Oe(n[0],"raw").string,e.gullet.macros,r);const i=e.parseExpression(!0,t,!0);return{type:"color",mode:e.mode,color:a,body:i}},mathmlBuilder:Ue}),c({type:"color",names:["\\definecolor"],props:{numArgs:3,allowedInText:!0,argTypes:["raw","raw","raw"]},handler({parser:t,funcName:r,token:n},o){const s=Oe(o[0],"raw").string;if(!/^[A-Za-z]+$/.test(s))throw new e("Color name must be latin letters.",n);const a=Oe(o[1],"raw").string;if(!["HTML","RGB","rgb"].includes(a))throw new e("Color model must be HTML, RGB, or rgb.",n);const i=Oe(o[2],"raw").string,l=Re(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:0,allowedInText:!0},handler({parser:e},t,r){const n="["===e.gullet.future().text?e.parseSizeGroup(!0):null,o=!e.settings.displayMode;return{type:"cr",mode:e.mode,newLine:o,size:n&&Oe(n,"size").value}},mathmlBuilder(e,t){const r=new N.MathNode("mo");if(e.newLine&&(r.setAttribute("linebreak","newline"),e.size)){const n=ve(e.size,t);r.setAttribute("height",n.number+n.unit)}return r}});const He={"\\global":"\\global","\\long":"\\\\globallong","\\\\globallong":"\\\\globallong","\\def":"\\gdef","\\gdef":"\\gdef","\\edef":"\\xdef","\\xdef":"\\xdef","\\let":"\\\\globallet","\\futurelet":"\\\\globalfuture"},Ve=t=>{const r=t.text;if(/^(?:[\\{}$&#^_]|EOF)$/.test(r))throw new e("Expected a control sequence",t);return r},_e=(e,t,r,n)=>{let o=e.gullet.macros.get(r.text);null==o&&(r.noexpand=!0,o={tokens:[r],numArgs:0,unexpandable:!e.gullet.isExpandable(r.text)}),e.gullet.macros.set(t,o,n)};c({type:"internal",names:["\\global","\\long","\\\\globallong"],props:{numArgs:0,allowedInText:!0},handler({parser:t,funcName:r}){t.consumeSpaces();const n=t.fetch();if(He[n.text])return"\\global"!==r&&"\\\\globallong"!==r||(n.text=He[n.text]),Oe(t.parseFunction(),"internal");throw new e("Invalid token after macro prefix",n)}}),c({type:"internal",names:["\\def","\\gdef","\\edef","\\xdef"],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();if(s&&l.unshift(s),"\\edef"===r||"\\xdef"===r){if(l=t.gullet.expandTokens(l),l.length>t.gullet.settings.maxExpand)throw new e("Too many expansions in an "+r);l.reverse()}return t.gullet.macros.set(o,{tokens:l,numArgs:a,delimiters:i},r===He[r]),{type:"internal",mode:t.mode}}}),c({type:"internal",names:["\\let","\\\\globallet"],props:{numArgs:0,allowedInText:!0,primitive:!0},handler({parser:e,funcName:t}){const r=Ve(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 _e(e,r,n,"\\\\globallet"===t),{type:"internal",mode:e.mode}}}),c({type:"internal",names:["\\futurelet","\\\\globalfuture"],props:{numArgs:0,allowedInText:!0,primitive:!0},handler({parser:e,funcName:t}){const r=Ve(e.gullet.popToken()),n=e.gullet.popToken(),o=e.gullet.popToken();return _e(e,r,o,"\\\\globalfuture"===t),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=Ve(t.gullet.popToken()),t.gullet.popToken()):n=Ve(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},!t.settings.strict),{type:"internal",mode:t.mode}}});const We={"\\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}},Xe=["(","\\lparen",")","\\rparen","[","\\lbrack","]","\\rbrack","\\{","\\lbrace","\\}","\\rbrace","⦇","\\llparenthesis","⦈","\\rrparenthesis","\\lfloor","\\rfloor","⌊","⌋","\\lceil","\\rceil","⌈","⌉","<",">","\\langle","⟨","\\rangle","⟩","\\lAngle","⟪","\\rAngle","⟫","\\llangle","⦉","\\rrangle","⦊","\\lt","\\gt","\\lvert","\\rvert","\\lVert","\\rVert","\\lgroup","\\rgroup","⟮","⟯","\\lmoustache","\\rmoustache","⎰","⎱","\\llbracket","\\rrbracket","⟦","⟦","\\lBrace","\\rBrace","⦃","⦄","/","\\backslash","|","\\vert","\\|","\\Vert","\\uparrow","\\Uparrow","\\downarrow","\\Downarrow","\\updownarrow","\\Updownarrow","."],Ze=["}","\\left","\\middle","\\right"],Ye=e=>e.length>0&&(Xe.includes(e)||We[e]||Ze.includes(e)),Ke=[0,1.2,1.8,2.4,3];function Je(t,r){const n=Me(t);if(n&&Xe.includes(n.text))return["/","⁄"].includes(n.text)&&(n.text="∕"),["<","\\lt"].includes(n.text)&&(n.text="⟨"),[">","\\gt"].includes(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=Je(t[0],e);return{type:"delimsizing",mode:e.parser.mode,size:We[e.funcName].size,mclass:We[e.funcName].mclass,delim:r.text}},mathmlBuilder:e=>{const t=[];"."===e.delim&&(e.delim=""),t.push(re(e.delim,e.mode));const r=new N.MathNode("mo",t);return"mopen"===e.mclass||"mclose"===e.mclass?r.setAttribute("fence","true"):r.setAttribute("fence","false"),("∖"===e.delim||"\\vert"===e.delim||"|"===e.delim||e.delim.indexOf("arrow")>-1)&&r.setAttribute("stretchy","true"),r.setAttribute("symmetric","true"),r.setAttribute("minsize",Ke[e.size]+"em"),r.setAttribute("maxsize",Ke[e.size]+"em"),r}}),c({type:"leftright-right",names:["\\right"],props:{numArgs:1,argTypes:["primitive"]},handler:(e,t)=>({type:"leftright-right",mode:e.parser.mode,delim:Je(t[0],e).text})}),c({type:"leftright",names:["\\left"],props:{numArgs:1,argTypes:["primitive"]},handler:(t,r)=>{const n=Je(r[0],t),o=t.parser;++o.leftrightDepth;let s=o.parseExpression(!1,null,!0),a=o.fetch();for(;"\\middle"===a.text;){o.consume();const t=o.fetch().text;if(!E.math[t])throw new e(`Invalid delimiter '${t}' after '\\middle'`);Je({type:"atom",mode:"math",text:t},{funcName:"\\middle"}),s.push({type:"middle",mode:"math",delim:t}),o.consume(),s=s.concat(o.parseExpression(!1,null,!0)),a=o.fetch()}--o.leftrightDepth,o.expect("\\right",!1);const i=Oe(o.parseFunction(),"leftright-right");return{type:"leftright",mode:o.mode,body:s,left:n.text,right:i.delim}},mathmlBuilder:(e,t)=>{!function(e){if(!e.body)throw new Error("Bug: The leftright ParseNode wasn't fully parsed.")}(e);const r=ie(e.body,t);"."===e.left&&(e.left="");const n=new N.MathNode("mo",[re(e.left,e.mode)]);n.setAttribute("fence","true"),n.setAttribute("form","prefix"),("∖"===e.left||e.left.indexOf("arrow")>-1)&&n.setAttribute("stretchy","true"),r.unshift(n),"."===e.right&&(e.right="");const o=new N.MathNode("mo",[re(e.right,e.mode)]);return o.setAttribute("fence","true"),o.setAttribute("form","postfix"),("∖"===e.right||e.right.indexOf("arrow")>-1)&&o.setAttribute("stretchy","true"),r.push(o),se(r)}}),c({type:"middle",names:["\\middle"],props:{numArgs:1,argTypes:["primitive"]},handler:(t,r)=>{const n=Je(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=re(e.delim,e.mode),n=new N.MathNode("mo",[r]);return n.setAttribute("fence","true"),e.delim.indexOf("arrow")>-1&&n.setAttribute("stretchy","true"),n.setAttribute("form","prefix"),n.setAttribute("lspace","0.05em"),n.setAttribute("rspace","0.05em"),n}});const Qe=e=>{const t=new N.MathNode("mspace");return t.setAttribute("width","3pt"),t},et=(e,t)=>{let r;switch(r=e.label.indexOf("colorbox")>-1||"\\boxed"===e.label?new N.MathNode("mrow",[Qe(),ce(e.body,t),Qe()]):new N.MathNode("mrow",[ce(e.body,t)]),e.label){case"\\overline":r.style.padding="0.1em 0 0 0",r.style.borderTop="0.065em solid";break;case"\\underline":r.style.padding="0 0 0.1em 0",r.style.borderBottom="0.065em solid";break;case"\\cancel":r.classes.push("tml-cancel");break;case"\\bcancel":r.classes.push("tml-bcancel");break;case"\\angl":r.style.padding="0.03889em 0.03889em 0 0.03889em",r.style.borderTop="0.049em solid",r.style.borderRight="0.049em solid",r.style.marginRight="0.03889em";break;case"\\sout":r.style.backgroundImage="linear-gradient(black, black)",r.style.backgroundRepeat="no-repeat",r.style.backgroundSize="100% 1.5px",r.style.backgroundPosition="0 center";break;case"\\boxed":r.style={padding:"3pt 0 3pt 0",border:"1px solid"},r.setAttribute("scriptlevel","0"),r.setAttribute("displaystyle","true");break;case"\\fbox":r.style={padding:"3pt",border:"1px solid"};break;case"\\fcolorbox":case"\\colorbox":{const t={padding:"3pt 0 3pt 0"};"\\fcolorbox"===e.label&&(t.border="0.06em solid "+String(e.borderColor)),r.style=t;break}case"\\xcancel":r.classes.push("tml-xcancel")}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]&&Oe(n[0],"raw").string;let s="";if(o){const e=Oe(r[0],"raw").string;s=Re(o,e)}else s=je(Oe(r[0],"raw").string,e.gullet.macros);const a=r[1];return{type:"enclose",mode:e.mode,label:t,backgroundColor:s,body:a}},mathmlBuilder:et}),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]&&Oe(n[0],"raw").string;let s,a="";if(o){const e=Oe(r[0],"raw").string,t=Oe(r[0],"raw").string;a=Re(o,e),s=Re(o,t)}else a=je(Oe(r[0],"raw").string,e.gullet.macros),s=je(Oe(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:et}),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:["\\angl","\\cancel","\\bcancel","\\xcancel","\\sout","\\overline","\\boxed"],props:{numArgs:1},handler({parser:e,funcName:t},r){const n=r[0];return{type:"enclose",mode:e.mode,label:t,body:n}},mathmlBuilder:et}),c({type:"enclose",names:["\\underline"],props:{numArgs:1,allowedInText:!0},handler({parser:e,funcName:t},r){const n=r[0];return{type:"enclose",mode:e.mode,label:t,body:n}},mathmlBuilder:et});const tt={};function rt({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.`)},ct=(e,t,r)=>{let n;const o=e.tags.shift();if(o){if(!o.body)return n=new N.MathNode("mtext",[],[]),n;n=le(o.body,t,!0),n.classes=["tml-tag"]}else{if(e.envClasses.includes("multline")&&(e.leqno&&0!==r||!e.leqno&&r!==e.body.length-1))return n=new N.MathNode("mtext",[],[]),n;n=new N.MathNode("mtext",[new y(["tml-eqn"])])}return n};function mt(t,{cols:r,envClasses:n,addEqnNum:o,singleRow:s,emptySingleRow:a,maxNumCols:i,leqno:l},c){t.gullet.beginGroup(),s||t.gullet.macros.set("\\cr","\\\\\\relax"),o&&(t.gullet.macros.set("\\tag","\\@ifstar\\envtag@literal\\envtag@paren"),t.gullet.macros.set("\\envtag@paren","\\env@tag{{(\\text{#1})}}"),t.gullet.macros.set("\\envtag@literal","\\env@tag{\\text{#1}}"),t.gullet.macros.set("\\notag","\\env@notag"),t.gullet.macros.set("\\nonumber","\\env@notag")),t.gullet.beginGroup();let m=[];const u=[m],d=[],p=[];let h;const g=[];for(g.push(it(t));;){let r=t.parseExpression(!1,s?"\\end":"\\\\");if(o&&!h)for(let e=0;e1||!a)&&u.pop(),g.length{const t=new N.MathNode("mtd",[]);return t.style={padding:"0",width:"50%"},e.envClasses.includes("multline")&&(t.style.width="7.5%"),t},ht=function(e,t){const r=[],n=e.body.length,o=e.hLinesBeforeRow;for(let s=0;s0&&(2===o[0].length?c.children.forEach((e=>{e.style.borderTop="0.15em double"})):c.children.forEach((e=>{e.style.borderTop=o[0][0]?"0.06em dashed":"0.06em solid"}))),o[s+1].length>0&&(2===o[s+1].length?c.children.forEach((e=>{e.style.borderBottom="0.15em double"})):c.children.forEach((e=>{e.style.borderBottom=o[s+1][0]?"0.06em dashed":"0.06em solid"}))),r.push(c)}if(e.envClasses.length>0){const t=e.envClasses.includes("jot")?"0.7":e.envClasses.includes("small")?"0.35":"0.5",n=e.envClasses.includes("abut")||e.envClasses.includes("cases")?"0":e.envClasses.includes("small")?"0.1389":e.envClasses.includes("cd")?"0.25":"0.4",o=0===r.length?0:r[0].children.length,s=(t,r)=>0===t&&0===r||t===o-1&&1===r?"0":"align"!==e.envClasses[0]?n:1===r?"0":e.addEqnNum?t%2?"1":"0":t%2?"0":"1";for(let e=0;e1&&e.envClasses.includes("cases")&&(n.children[1].style.padding=n.children[1].style.padding.replace(/0em$/,"1em")),e.envClasses.includes("cases")||e.envClasses.includes("subarray"))for(const e of n.children)e.classes.push("tml-left")}}else for(let e=0;e0){const t=e.cols;let r=!1,n=0,o=t.length;for(;"separator"===t[n].type;)n+=1;for(;"separator"===t[o-1].type;)o-=1;if("separator"===t[0].type){const e="separator"===t[1].type?"0.15em double":"|"===t[0].separator?"0.06em solid ":"0.06em dashed ";for(const t of s.children)t.children[0].style.borderLeft=e}let i=e.addEqnNum?0:-1;for(let e=n;e0?a:"center ")+"right "),a&&s.setAttribute("columnalign",a.trim()),e.envClasses.includes("small")&&(s=new N.MathNode("mstyle",[s]),s.setAttribute("scriptlevel","1")),s},gt=function(t,r){-1===t.envName.indexOf("ed")&<(t);const n=[],o=mt(t.parser,{cols:n,addEqnNum:"align"===t.envName||"alignat"===t.envName,emptySingleRow:!0,envClasses:["abut","jot"],maxNumCols:"split"===t.envName?2:void 0,leqno:t.parser.settings.leqno},"display");let s,a=0;const i=t.envName.indexOf("at")>-1;if(r[0]&&i){let t="";for(let e=0;e1)throw new e("{subarray} can contain only one column");let o={cols:n,envClasses:["small"]};if(o=mt(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:ht}),rt({type:"array",names:["cases","dcases","rcases","drcases"],props:{numArgs:0},handler(e){const t=mt(e.parser,{cols:[],envClasses:["cases"]},ut(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:ht}),rt({type:"array",names:["align","align*","aligned","split"],props:{numArgs:0},handler:gt,mathmlBuilder:ht}),rt({type:"array",names:["alignat","alignat*","alignedat"],props:{numArgs:1},handler:gt,mathmlBuilder:ht}),rt({type:"array",names:["gathered","gather","gather*"],props:{numArgs:0},handler(e){"gathered"!==e.envName&<(e);const t={cols:[],envClasses:["abut","jot"],addEqnNum:"gather"===e.envName,emptySingleRow:!0,leqno:e.parser.settings.leqno};return mt(e.parser,t,"display")},mathmlBuilder:ht}),rt({type:"array",names:["equation","equation*"],props:{numArgs:0},handler(e){lt(e);const t={addEqnNum:"equation"===e.envName,emptySingleRow:!0,singleRow:!0,maxNumCols:1,envClasses:["align"],leqno:e.parser.settings.leqno};return mt(e.parser,t,"display")},mathmlBuilder:ht}),rt({type:"array",names:["multline","multline*"],props:{numArgs:0},handler(e){lt(e);const t={addEqnNum:"multline"===e.envName,maxNumCols:1,envClasses:["jot","multline"],leqno:e.parser.settings.leqno};return mt(e.parser,t,"display")},mathmlBuilder:ht}),rt({type:"array",names:["CD"],props:{numArgs:0},handler:t=>(lt(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 N.MathNode("mrow")}),c({type:"noTag",names:["\\env@notag"],props:{numArgs:0},handler:({parser:e})=>({type:"noTag",mode:e.mode}),mathmlBuilder:(e,t)=>new N.MathNode("mrow")});const bt=(e,t)=>{const r=e.font,n=t.withFont(r),o=ce(e.body,n);if(0===o.children.length)return o;if("boldsymbol"===r&&["mo","mpadded","mrow"].includes(o.type))return o.style.fontWeight="bold",o;if(((e,t)=>{if("mathrm"!==t||"ordgroup"!==e.body.type||1===e.body.body.length)return!1;if("mathord"!==e.body.body[0].type)return!1;for(let t=1;t{const n=u(r[0]);let o=t;return o in yt&&(o=yt[o]),{type:"font",mode:e.mode,font:o.slice(1),body:n}},mathmlBuilder:bt}),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,!0);return{type:"font",mode:o,font:`math${t.slice(1)}`,body:{type:"ordgroup",mode:e.mode,body:s}}},mathmlBuilder:bt});const xt=["display","text","script","scriptscript"],wt={auto:-1,display:0,text:0,script:1,scriptscript:2},kt=(e,t)=>{const r="auto"===e.scriptLevel?t.incrementLevel():"display"===e.scriptLevel?t.withLevel(ot):"text"===e.scriptLevel?t.withLevel(st):t.withLevel(at);let n=new N.MathNode("mfrac",[ce(e.numer,r),ce(e.denom,r)]);if(e.hasBarLine){if(e.barSize){const r=ve(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 N.MathNode("mo",[new N.TextNode(e.leftDelim.replace("\\",""))]);r.setAttribute("fence","true"),t.push(r)}if(t.push(n),null!=e.rightDelim){const r=new N.MathNode("mo",[new N.TextNode(e.rightDelim.replace("\\",""))]);r.setAttribute("fence","true"),t.push(r)}n=se(t)}return"auto"!==e.scriptLevel&&(n=new N.MathNode("mstyle",[n]),n.setAttribute("displaystyle",String("display"===e.scriptLevel)),n.setAttribute("scriptlevel",wt[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:kt}),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 vt=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?vt(o.text):null,a=u(t[1]),i="atom"===a.type&&"close"===a.family?vt(a.text):null,l=Oe(t[2],"size");let c,m=null;l.isBlank?c=!0:(m=l.value,c=m.number>0);let d="auto",p=t[3];if("ordgroup"===p.type){if(p.body.length>0){const e=Oe(p.body[0],"textord");d=xt[Number(e.text)]}}else p=Oe(p,"textord"),d=xt[Number(p.text)];return{type:"genfrac",mode:e.mode,numer:r,denom:n,continued:!1,hasBarLine:c,barSize:m,leftDelim:s,rightDelim:i,scriptLevel:d}},mathmlBuilder:kt}),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:Oe(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}(Oe(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:kt}),c({type:"hbox",names:["\\hbox"],props:{numArgs:1,argTypes:["hbox"],allowedInArgument:!0,allowedInText:!1},handler:({parser:e},t)=>({type:"hbox",mode:e.mode,body:d(t[0])}),mathmlBuilder(e,t){const r=t.withLevel(ot),n=le(e.body,r);return ne(n)}});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=B(e.label);return r.style["math-depth"]=0,new N.MathNode(e.isOver?"mover":"munder",[ce(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=Oe(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:d(o)}},mathmlBuilder:(e,t)=>{let r=le(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=Oe(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=Oe(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=le(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(!we(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=Oe(o[0],"raw").string.split(",");for(let r=0;r{const r=ve(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=ve(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 w(e.src,e.alt,s);return a.height=r,a.depth=n,new N.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=Oe(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=ve(e.dimension,t),n="em"===r.unit?Nt(r.number):"";if("text"===e.mode&&n.length>0){const e=new N.TextNode(n);return new N.MathNode("mtext",[e])}{const e=new N.MathNode("mspace");return e.setAttribute("width",r.number+r.unit),r.number<0&&(e.style.marginLeft=r.number+r.unit),e}}});const Nt=function(e){return e>=.05555&&e<=.05556?" ":e>=.1666&&e<=.1667?" ":e>=.2222&&e<=.2223?" ":e>=.2777&&e<=.2778?"  ":""},Tt=/[^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(Tt,"")}),mathmlBuilder(e,t){const r=new N.MathNode("mrow",[],["tml-label"]);return e.string.length>0&&r.setAttribute("id",e.string),r}});const qt=["\\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(qt.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)=>{let r;if("llap"===e.alignment){const n=ie(d(e.body),t),o=new N.MathNode("mphantom",n);r=new N.MathNode("mpadded",[o]),r.setAttribute("width","0px")}const n=ce(e.body,t);let o;if("llap"===e.alignment?(n.style.position="absolute",n.style.right="0",n.style.bottom="0",o=new N.MathNode("mpadded",[r,n])):o=new N.MathNode("mpadded",[n]),"rlap"===e.alignment)e.body.body.length>0&&"genfrac"===e.body.body[0].type&&o.setAttribute("lspace","0.16667em");else{const t="llap"===e.alignment?"-1":"-0.5";o.setAttribute("lspace",t+"width"),"llap"===e.alignment?o.style.position="relative":(o.style.display="flex",o.style.justifyContent="center")}return o.setAttribute("width","0px"),o}}),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:d(t[0]),text:d(t[1]),script:d(t[2]),scriptscript:d(t[3])}),mathmlBuilder:(e,t)=>{const r=((e,t)=>{switch(t.level){case nt:return e.display;case ot:return e.text;case st:return e.script;case at:return e.scriptscript;default:return e.text}})(e,t);return le(r,t)}});const St=["text","textord","mathord","atom"],Ot=e=>{const t=new N.MathNode("mspace");return t.setAttribute("width",e+"em"),t};function Bt(e,t){let r;const n=ie(e.body,t);if("minner"===e.mclass)r=new N.MathNode("mpadded",n);else if("mord"===e.mclass)e.isCharacterBox||"mathord"===n[0].type?(r=n[0],r.type="mi",1===r.children.length&&r.children[0].text&&"∇"===r.children[0].text&&r.setAttribute("mathvariant","normal")):r=new N.MathNode("mi",n);else{r=new N.MathNode("mrow",n),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 N.MathNode("mrow",n);const o=t.level<2;"mrow"===r.type?o&&("mbin"===e.mclass?(r.children.unshift(Ot(.2222)),r.children.push(Ot(.2222))):"mrel"===e.mclass?(r.children.unshift(Ot(.2778)),r.children.push(Ot(.2778))):"mpunct"===e.mclass?r.children.push(Ot(.1667)):"minner"===e.mclass&&(r.children.unshift(Ot(.0556)),r.children.push(Ot(.0556)))):"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 t of l){if(!St.includes(t.type)){a=!1;break}E[e.mode][t.text]?i.text+=E[e.mode][t.text].replace:t.text?i.text+=t.text:t.body&&t.body.map((e=>{i.text+=e.text}))}return{type:"mclass",mode:e.mode,mclass:"m"+t.slice(5),body:d(a?i:n),isCharacterBox:o,mustPromote:a}},mathmlBuilder:Bt});const Mt=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:Mt(t[0]),body:d(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:d(n)};return{type:"supsub",mode:o.mode,base:s,sup:"\\underset"===t?null:o,sub:"\\underset"===t?o:null}},mathmlBuilder:Bt});const Ct=(e,t,r)=>{if(!e)return r;const n=ce(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=ce(e.base,t),n=new N.MathNode("mprescripts"),o=new N.MathNode("none");let s=[];const a=Ct(e.prescripts.sub,t,o),i=Ct(e.prescripts.sup,t,o);if(e.isSideset&&(a.setAttribute("style","text-align: left;"),i.setAttribute("style","text-align: left;")),e.postscripts){s=[r,Ct(e.postscripts.sub,t,o),Ct(e.postscripts.sup,t,o),n,a,i]}else s=[r,n,a,i];return new N.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=d(t[0]),"\\"===n[0].text.charAt(0)&&(n[0].text=E.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 ie(e.body,t,!0)[0]}return le(e.body,t)}});const zt=["textord","mathord","atom"],Et=["\\smallint"],It=["textord","mathord","ordgroup","close","leftright"],$t=e=>{e.attributes.lspace="0.1667em",e.attributes.rspace="0.1667em"},Lt=(e,t)=>{let r;if(e.symbol)r=new k("mo",[re(e.name,e.mode)]),Et.includes(e.name)?r.setAttribute("largeop","false"):r.setAttribute("movablelimits","false"),e.fromMathOp&&$t(r);else if(e.body)r=new k("mo",ie(e.body,t)),e.fromMathOp&&$t(r);else if(r=new k("mi",[new v(e.name.slice(1))]),!e.parentIsSupSub){const t=[r,new k("mo",[re("⁡","text")])];if(e.needsLeadingSpace){const e=new k("mspace");e.setAttribute("width","0.1667em"),t.unshift(e)}if(!e.isFollowedByDelimiter){const e=new k("mspace");e.setAttribute("width","0.1667em"),t.push(e)}r=new k("mrow",t)}return r},Ft={"∏":"\\prod","∐":"\\coprod","∑":"\\sum","⋀":"\\bigwedge","⋁":"\\bigvee","⋂":"\\bigcap","⋃":"\\bigcup","⨀":"\\bigodot","⨁":"\\bigoplus","⨂":"\\bigotimes","⨄":"\\biguplus","⨅":"\\bigsqcap","⨆":"\\bigsqcup","⨉":"\\bigtimes"};c({type:"op",names:["\\coprod","\\bigvee","\\bigwedge","\\biguplus","\\bigcap","\\bigcup","\\intop","\\prod","\\sum","\\bigotimes","\\bigoplus","\\bigodot","\\bigsqcap","\\bigsqcup","\\bigtimes","\\smallint","∏","∐","∑","⋀","⋁","⋂","⋃","⨀","⨁","⨂","⨄","⨆"],props:{numArgs:0},handler:({parser:e,funcName:t},r)=>{let n=t;return 1===n.length&&(n=Ft[n]),{type:"op",mode:e.mode,limits:!0,parentIsSupSub:!1,symbol:!0,stack:!1,name:n}},mathmlBuilder:Lt}),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&&zt.includes(n[0].type);return{type:"op",mode:e.mode,limits:!0,parentIsSupSub:!1,symbol:o,fromMathOp:!0,stack:!1,name:o?n[0].text:null,body:o?null:d(r)}},mathmlBuilder:Lt});const Gt={"∫":"\\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:Ye(n),needsLeadingSpace:r.length>0&&It.includes(r),name:t}},mathmlBuilder:Lt}),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:Ye(n),needsLeadingSpace:r.length>0&&It.includes(r),name:t}},mathmlBuilder:Lt}),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=Gt[r]),{type:"op",mode:e.mode,limits:!1,parentIsSupSub:!1,symbol:!0,stack:!1,name:r}},mathmlBuilder:Lt});const Dt={};function Pt(e,t){Dt[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,s=e.gullet.future().text;return{type:"operatorname",mode:e.mode,body:d(n),alwaysHandleSupSub:"\\operatornamewithlimits"===t,limits:!1,parentIsSupSub:!1,isFollowedByDelimiter:Ye(s),needsLeadingSpace:o.length>0&&It.includes(o)}},mathmlBuilder:(e,t)=>{let r,n=ie(e.body,t.withFont("mathrm")),o=!0;for(let e=0;ee.toText())).join("");n=[new N.TextNode(e)]}else if(1===n.length&&["mover","munder"].includes(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 N.MathNode("mrow",n);{const e=new N.MathNode("mo",[re("⁡","text")]);return N.newDocumentFragment([n[0],e])}}if(o?(r=new N.MathNode("mi",n),1===n[0].text.length&&r.setAttribute("mathvariant","normal")):r=new N.MathNode("mrow",n),!e.parentIsSupSub){const t=[r,new N.MathNode("mo",[re("⁡","text")])];if(e.needsLeadingSpace){const e=new N.MathNode("mspace");e.setAttribute("width","0.1667em"),t.unshift(e)}if(!e.isFollowedByDelimiter){const e=new N.MathNode("mspace");e.setAttribute("width","0.1667em"),t.push(e)}return N.newDocumentFragment(t)}return r}}),Pt("\\operatorname","\\@ifstar\\operatornamewithlimits\\operatorname@"),m({type:"ordgroup",mathmlBuilder:(e,t)=>le(e.body,t,e.semisimple)}),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:d(r)}},mathmlBuilder:(e,t)=>{const r=ie(e.body,t);return new N.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=ie(d(e.body),t),n=new N.MathNode("mphantom",r),o=new N.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=ie(d(e.body),t),n=new N.MathNode("mphantom",r),o=new N.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:d(t[0])}),mathmlBuilder(e,t){const r=ie(e.body,t),n=A(r);return n.setAttribute("style","font-weight:bold"),n}});const Rt=(e,t)=>{const r=t.withLevel(ot),n=new N.MathNode("mpadded",[ce(e.body,r)]),o=ve(e.dy,t);return n.setAttribute("voffset",o.number+o.unit),o.number>0?n.style.padding=o.number+o.unit+" 0 0 0":n.style.padding="0 0 "+Math.abs(o.number)+o.unit+" 0",n};c({type:"raise",names:["\\raise","\\lower"],props:{numArgs:2,argTypes:["size","primitive"],primitive:!0},handler({parser:e,funcName:t},r){const n=Oe(r[0],"size").value;"\\lower"===t&&(n.number*=-1);const o=r[1];return{type:"raise",mode:e.mode,dy:n,body:o}},mathmlBuilder:Rt}),c({type:"raise",names:["\\raisebox"],props:{numArgs:2,argTypes:["size","hbox"],allowedInText:!0},handler({parser:e,funcName:t},r){const n=Oe(r[0],"size").value,o=r[1];return{type:"raise",mode:e.mode,dy:n,body:o}},mathmlBuilder:Rt}),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(Tt,"")}),mathmlBuilder(e,t){const r="\\ref"===e.funcName?["tml-ref"]:["tml-ref","tml-eqref"],n=new N.MathNode("mtext",[new N.TextNode("")],r);return n.setAttribute("href","#"+e.string),n}}),c({type:"reflect",names:["\\reflectbox"],props:{numArgs:1,argTypes:["hbox"],allowedInText:!0},handler:({parser:e},t)=>({type:"reflect",mode:e.mode,body:t[0]}),mathmlBuilder(e,t){const r=ce(e.body,t);return r.style.transform="scaleX(-1)",r}}),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=Oe(t[0],"size"),s=Oe(t[1],"size");return{type:"rule",mode:e.mode,shift:n&&Oe(n,"size").value,width:o.value,height:s.value}},mathmlBuilder(e,t){const r=ve(e.width,t),n=ve(e.height,t),o=e.shift?ve(e.shift,t):{number:0,unit:"em"},s=t.color&&t.getColor()||"black",a=new N.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 N.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 jt={"\\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,!0);return{type:"sizing",mode:r.mode,funcName:t,body:o}},mathmlBuilder:(e,t)=>{const r=t.withFontSize(jt[e.funcName]),n=ie(e.body,r),o=A(n),s=(jt[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]&&Oe(r[0],"ordgroup");if(s){let e="";for(let t=0;t{const r=new N.MathNode("mpadded",[ce(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 N.MathNode("mroot",[ce(r,t),ce(n,t.incrementLevel())]):new N.MathNode("msqrt",[ce(r,t)])}});const Ut={display:0,text:1,script:2,scriptscript:3},Ht={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,!0),s=t.slice(1,t.length-5);return{type:"styling",mode:r.mode,scriptLevel:s,body:o}},mathmlBuilder(e,t){const r=t.withLevel(Ut[e.scriptLevel]),n=ie(e.body,r),o=A(n),s=Ht[e.scriptLevel];return o.setAttribute("scriptlevel",s[0]),o.setAttribute("displaystyle",s[1]),o}});const Vt=/^m(over|under|underover)$/;m({type:"supsub",mathmlBuilder(e,t){let r,n,o=!1,s=!1,a=!1,i=!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=s&&!e.isFollowedByDelimiter,i=e.base.needsLeadingSpace);const l=e.base&&e.base.stack?[ce(e.base.body[0],t)]:[ce(e.base,t)],c=t.inSubOrSup();if(e.sub&&l.push(ce(e.sub,c)),e.sup){const t=ce(e.sup,c),r="mrow"===t.type?t.children[0]:t;r&&"mo"===r.type&&r.classes.includes("tml-prime")&&e.base&&e.base.text&&"f"===e.base.text&&r.classes.push("prime-pad"),l.push(t)}let m;if(o)m=r?"mover":"munder";else if(e.sub)if(e.sup){const r=e.base;m=r&&("op"===r.type&&r.limits||"multiscript"===r.type)&&(t.level===nt||r.alwaysHandleSupSub)||r&&"operatorname"===r.type&&r.alwaysHandleSupSub&&(t.level===nt||r.limits)?"munderover":"msubsup"}else{const r=e.base;m=r&&"op"===r.type&&r.limits&&(t.level===nt||r.alwaysHandleSupSub)||r&&"operatorname"===r.type&&r.alwaysHandleSupSub&&(r.limits||t.level===nt)?"munder":"msub"}else{const r=e.base;m=r&&"op"===r.type&&r.limits&&(t.level===nt||r.alwaysHandleSupSub)||r&&"operatorname"===r.type&&r.alwaysHandleSupSub&&(r.limits||t.level===nt)?"mover":"msup"}let u=new N.MathNode(m,l);if(s){const e=new N.MathNode("mo",[re("⁡","text")]);if(i){const t=new N.MathNode("mspace");t.setAttribute("width","0.1667em"),u=N.newDocumentFragment([t,u,e])}else u=N.newDocumentFragment([u,e]);if(a){const e=new N.MathNode("mspace");e.setAttribute("width","0.1667em"),u.children.push(e)}}else Vt.test(m)&&(u=new N.MathNode("mrow",[u]));return u}});const _t=["\\shortmid","\\nshortmid","\\shortparallel","\\nshortparallel","\\smallsetminus"],Wt=["\\Rsh","\\Lsh","\\restriction"];m({type:"atom",mathmlBuilder(e,t){const r=new N.MathNode("mo",[re(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")):"rel"===e.family&&(e=>{if(1===e.length){const t=e.codePointAt(0);return 8591-1||e.indexOf("harpoon")>-1||Wt.includes(e)})(e.text)?r.setAttribute("stretchy","false"):_t.includes(e.text)?r.setAttribute("mathsize","70%"):":"===e.text&&(r.attributes.lspace="0.2222em",r.attributes.rspace="0.2222em"),r}});const Xt={mathbf:"bold",mathrm:"normal",textit:"italic",mathit:"italic",mathnormal:"italic",mathbb:"double-struck",mathcal:"script",mathfrak:"fraktur",mathscr:"script",mathsf:"sans-serif",mathtt:"monospace"},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=>Yt[e]||119899,"script-bold":e=>119951,fraktur:e=>Kt[e]||120003,"fraktur-bold":e=>120107,"double-struck":e=>Jt[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=>Yt[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=>119575,italic:e=>119633,"bold-italic":e=>119575,script:e=>0,"script-bold":e=>0,fraktur:e=>0,"fraktur-bold":e=>0,"double-struck":e=>0,"sans-serif":e=>119749,"sans-serif-bold":e=>119749,"sans-serif-italic":e=>0,"sans-serif-bold-italic":e=>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=>Qt[e]||-51,italic:e=>0,"bold-italic":e=>er[e]||58,script:e=>0,"script-bold":e=>0,fraktur:e=>0,"fraktur-bold":e=>0,"double-struck":e=>0,"sans-serif":e=>tr[e]||116,"sans-serif-bold":e=>tr[e]||116,"sans-serif-italic":e=>0,"sans-serif-bold-italic":e=>rr[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}}),or=(e,t)=>{const r=e.codePointAt(0),n=64{const n=new N.MathNode(r,[e]),o=new N.MathNode("mstyle",[n]);return o.style["font-style"]="italic",o.style["font-family"]="Cambria, 'Times New Roman', serif","bold-italic"===t&&(o.style["font-weight"]="bold"),o})(o,s,t);"normal"!==s&&(o.text=o.text.split("").map((e=>or(e,s))).join("")),a=new N.MathNode(t,[o])}else if("text"===e.mode)"normal"!==s&&(o.text=or(o.text,s)),a=new N.MathNode("mtext",[o]);else if(lr.has(e.text))a=new N.MathNode("mo",[o]),a.classes.push("tml-prime");else{const e=o.text;"italic"!==s&&(o.text=or(o.text,s)),a=new N.MathNode("mi",[o]),o.text===e&&ir.test(e)&&a.setAttribute("mathvariant","italic")}return a}});const cr={"\\nobreak":"nobreak","\\allowbreak":"allowbreak"},mr={" ":{},"\\ ":{},"~":{className:"nobreak"},"\\space":{},"\\nobreakspace":{className:"nobreak"}};m({type:"spacing",mathmlBuilder(t,r){let n;if(Object.prototype.hasOwnProperty.call(mr,t.text))n=new N.MathNode("mtext",[new N.TextNode(" ")]);else{if(!Object.prototype.hasOwnProperty.call(cr,t.text))throw new e(`Unknown type of space "${t.text}"`);n=new N.MathNode("mo"),"\\nobreak"===t.text&&n.setAttribute("linebreak","nobreak")}return n}}),m({type:"tag"});const ur={"\\text":void 0,"\\textrm":"textrm","\\textsf":"textsf","\\texttt":"texttt","\\textnormal":"textrm","\\textsc":"textsc"},dr={"\\textbf":"textbf","\\textmd":"textmd"},pr={"\\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:d(n),font:t}},mathmlBuilder(e,t){const r=((e,t)=>{const r=e.font;return r?ur[r]?t.withTextFontFamily(ur[r]):dr[r]?t.withTextFontWeight(dr[r]):t.withTextFontShape(pr[r]):t})(e,t),n=le(e.body,r);return ne(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 N.TextNode(hr(e)),n=new N.MathNode("mtext",[r]);return n.setAttribute("mathvariant","monospace"),n}});const hr=e=>e.body.replace(/ /g,e.star?"␣":" "),gr=i;class fr{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 fr(e.loc.lexer,e.loc.start,t.loc.end):null:e&&e.loc}}class br{constructor(e,t){this.text=e,this.loc=t}range(e,t){return new br(t,fr.range(this,e))}}const yr="[ \r\n\t]",xr=`(\\\\[a-zA-Z@]+)${yr}*`,wr="[̀-ͯ]",kr=new RegExp(`${wr}+$`),vr=`(${yr}+)|\\\\(\n|[ \r\t]+\n?)[ \r\t]*|([!-\\[\\]-‧‪-퟿豈-￿]${wr}*|[\ud800-\udbff][\udc00-\udfff]${wr}*|\\\\verb\\*([^]).*?\\4|\\\\verb([^*a-zA-Z]).*?\\5|${xr}|\\\\[^\ud800-\udfff])`;class Ar{constructor(e,t){this.input=e,this.settings=t,this.tokenRegex=new RegExp(vr,"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 br("EOF",new fr(this,r,r));const n=this.tokenRegex.exec(t);if(null===n||n.index!==r)throw new e(`Unexpected character: '${t[r]}'`,new br(t[r],new fr(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 br(o,new fr(this,r,this.tokenRegex.lastIndex))}}class Nr{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,r=!1){if(r){for(let t=0;t0&&(this.undefStack[this.undefStack.length-1][e]=t)}else{const t=this.undefStack[this.undefStack.length-1];t&&!Object.prototype.hasOwnProperty.call(t,e)&&(t[e]=this.current[e])}this.current[e]=t}}const Tr=Dt;Pt("\\noexpand",(function(e){const t=e.popToken();return e.isExpandable(t.text)&&(t.noexpand=!0,t.treatAsRelax=!0),{tokens:[t],numArgs:0}})),Pt("\\expandafter",(function(e){const t=e.popToken();return e.expandOnce(!0),{tokens:[t],numArgs:0}})),Pt("\\@firstoftwo",(function(e){return{tokens:e.consumeArgs(2)[0],numArgs:0}})),Pt("\\@secondoftwo",(function(e){return{tokens:e.consumeArgs(2)[1],numArgs:0}})),Pt("\\@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}})),Pt("\\@ifstar","\\@ifnextchar *{\\@firstoftwo{#1}}"),Pt("\\TextOrMath",(function(e){const t=e.consumeArgs(2);return"text"===e.mode?{tokens:t[0],numArgs:0}:{tokens:t[1],numArgs:0}}));const qr={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},Sr=e=>{const t=e.future().text;return"EOF"===t?[null,""]:[qr[t.charAt(0)],t]},Or=(e,t,r)=>{for(let n=1;n=0;e--){const o=t[e].loc.start;o>n&&(r+=" ",n=o),r+=t[e].text,n+=t[e].text.length}return r}Pt("\\char",(function(t){let r,n=t.popToken(),o="";if("'"===n.text)r=8,n=t.popToken();else if('"'===n.text)r=16,n=t.popToken();else if("`"===n.text)if(n=t.popToken(),"\\"===n.text[0])o=n.text.charCodeAt(1);else{if("EOF"===n.text)throw new e("\\char` missing argument");o=n.text.charCodeAt(0)}else r=10;if(r){let s,a=n.text;if(o=qr[a.charAt(0)],null==o||o>=r)throw new e(`Invalid base-${r} digit ${n.text}`);for(o=Or(o,a,r),[s,a]=Sr(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","\\bigtimes":"\\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"};Pt("\\dots",(function(e){let t="\\dotso";const r=e.expandAfterFuture().text;return r in Mr?t=Mr[r]:("\\not"===r.slice(0,4)||r in E.math&&["bin","rel"].includes(E.math[r].group))&&(t="\\dotsb"),t}));const Cr={")":!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};Pt("\\dotso",(function(e){return e.future().text in Cr?"\\ldots\\,":"\\ldots"})),Pt("\\dotsc",(function(e){const t=e.future().text;return t in Cr&&","!==t?"\\ldots\\,":"\\ldots"})),Pt("\\cdots",(function(e){return e.future().text in Cr?"\\@cdots\\,":"\\@cdots"})),Pt("\\dotsb","\\cdots"),Pt("\\dotsm","\\cdots"),Pt("\\dotsi","\\!\\cdots"),Pt("\\idotsint","\\dotsi"),Pt("\\dotsx","\\ldots\\,"),Pt("\\DOTSI","\\relax"),Pt("\\DOTSB","\\relax"),Pt("\\DOTSX","\\relax"),Pt("\\tmspace","\\TextOrMath{\\kern#1#3}{\\mskip#1#2}\\relax"),Pt("\\,","{\\tmspace+{3mu}{.1667em}}"),Pt("\\thinspace","\\,"),Pt("\\>","\\mskip{4mu}"),Pt("\\:","{\\tmspace+{4mu}{.2222em}}"),Pt("\\medspace","\\:"),Pt("\\;","{\\tmspace+{5mu}{.2777em}}"),Pt("\\thickspace","\\;"),Pt("\\!","{\\tmspace-{3mu}{.1667em}}"),Pt("\\negthinspace","\\!"),Pt("\\negmedspace","{\\tmspace-{4mu}{.2222em}}"),Pt("\\negthickspace","{\\tmspace-{5mu}{.277em}}"),Pt("\\enspace","\\kern.5em "),Pt("\\enskip","\\hskip.5em\\relax"),Pt("\\quad","\\hskip1em\\relax"),Pt("\\qquad","\\hskip2em\\relax"),Pt("\\AA","\\TextOrMath{\\Angstrom}{\\mathring{A}}\\relax"),Pt("\\tag","\\@ifstar\\tag@literal\\tag@paren"),Pt("\\tag@paren","\\tag@literal{({#1})}"),Pt("\\tag@literal",(t=>{if(t.macros.get("\\df@tag"))throw new e("Multiple \\tag");return"\\def\\df@tag{\\text{#1}}"})),Pt("\\bmod","\\mathbin{\\text{mod}}"),Pt("\\pod","\\allowbreak\\mathchoice{\\mkern18mu}{\\mkern8mu}{\\mkern8mu}{\\mkern8mu}(#1)"),Pt("\\pmod","\\pod{{\\rm mod}\\mkern6mu#1}"),Pt("\\mod","\\allowbreak\\mathchoice{\\mkern18mu}{\\mkern12mu}{\\mkern12mu}{\\mkern12mu}{\\rm mod}\\,\\,#1"),Pt("\\newline","\\\\\\relax"),Pt("\\TeX","\\textrm{T}\\kern-.1667em\\raisebox{-.5ex}{E}\\kern-.125em\\textrm{X}"),Pt("\\LaTeX","\\textrm{L}\\kern-.35em\\raisebox{0.2em}{\\scriptstyle A}\\kern-.15em\\TeX"),Pt("\\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}}"),Pt("\\hspace","\\@ifstar\\@hspacer\\@hspace"),Pt("\\@hspace","\\hskip #1\\relax"),Pt("\\@hspacer","\\rule{0pt}{0pt}\\hskip #1\\relax"),Pt("\\colon",'\\mathpunct{\\char"3a}'),Pt("\\prescript","\\pres@cript{_{#1}^{#2}}{}{#3}"),Pt("\\ordinarycolon",'\\char"3a'),Pt("\\vcentcolon","\\mathrel{\\raisebox{0.035em}{\\ordinarycolon}}"),Pt("\\coloneq",'\\mathrel{\\raisebox{0.035em}{\\ordinarycolon}\\char"2212}'),Pt("\\Coloneq",'\\mathrel{\\char"2237\\char"2212}'),Pt("\\Eqqcolon",'\\mathrel{\\char"3d\\char"2237}'),Pt("\\Eqcolon",'\\mathrel{\\char"2212\\char"2237}'),Pt("\\colonapprox",'\\mathrel{\\raisebox{0.035em}{\\ordinarycolon}\\char"2248}'),Pt("\\Colonapprox",'\\mathrel{\\char"2237\\char"2248}'),Pt("\\colonsim",'\\mathrel{\\raisebox{0.035em}{\\ordinarycolon}\\char"223c}'),Pt("\\Colonsim",'\\mathrel{\\raisebox{0.035em}{\\ordinarycolon}\\char"223c}'),Pt("\\ratio","\\vcentcolon"),Pt("\\coloncolon","\\dblcolon"),Pt("\\colonequals","\\coloneqq"),Pt("\\coloncolonequals","\\Coloneqq"),Pt("\\equalscolon","\\eqqcolon"),Pt("\\equalscoloncolon","\\Eqqcolon"),Pt("\\colonminus","\\coloneq"),Pt("\\coloncolonminus","\\Coloneq"),Pt("\\minuscolon","\\eqcolon"),Pt("\\minuscoloncolon","\\Eqcolon"),Pt("\\coloncolonapprox","\\Colonapprox"),Pt("\\coloncolonsim","\\Colonsim"),Pt("\\notni","\\mathrel{\\char`∌}"),Pt("\\limsup","\\DOTSB\\operatorname*{lim\\,sup}"),Pt("\\liminf","\\DOTSB\\operatorname*{lim\\,inf}"),Pt("\\injlim","\\DOTSB\\operatorname*{inj\\,lim}"),Pt("\\projlim","\\DOTSB\\operatorname*{proj\\,lim}"),Pt("\\varlimsup","\\DOTSB\\operatorname*{\\overline{\\text{lim}}}"),Pt("\\varliminf","\\DOTSB\\operatorname*{\\underline{\\text{lim}}}"),Pt("\\varinjlim","\\DOTSB\\operatorname*{\\underrightarrow{\\text{lim}}}"),Pt("\\varprojlim","\\DOTSB\\operatorname*{\\underleftarrow{\\text{lim}}}"),Pt("\\centerdot","{\\medspace\\rule{0.167em}{0.189em}\\medspace}"),Pt("\\argmin","\\DOTSB\\operatorname*{arg\\,min}"),Pt("\\argmax","\\DOTSB\\operatorname*{arg\\,max}"),Pt("\\plim","\\DOTSB\\operatorname*{plim}"),Pt("\\leftmodels","\\mathop{\\reflectbox{$\\models$}}"),Pt("\\bra","\\mathinner{\\langle{#1}|}"),Pt("\\ket","\\mathinner{|{#1}\\rangle}"),Pt("\\braket","\\mathinner{\\langle{#1}\\rangle}"),Pt("\\Bra","\\left\\langle#1\\right|"),Pt("\\Ket","\\left|#1\\right\\rangle");const zr=(e,t)=>{const r=`}\\,\\middle${"|"===t[0]?"\\vert":"\\Vert"}\\,{`;return e.slice(0,t.index)+r+e.slice(t.index+t[0].length)};Pt("\\Braket",(function(e){let t=Br(e);const r=/\|\||\||\\\|/g;let n;for(;null!==(n=r.exec(t));)t=zr(t,n);return"\\left\\langle{"+t+"}\\right\\rangle"})),Pt("\\Set",(function(e){let t=Br(e);const r=/\|\||\||\\\|/.exec(t);return r&&(t=zr(t,r)),"\\left\\{\\:{"+t+"}\\:\\right\\}"})),Pt("\\set",(function(e){return"\\{{"+Br(e).replace(/\|/,"}\\mid{")+"}\\}"})),Pt("\\angln","{\\angl n}"),Pt("\\odv","\\@ifstar\\odv@next\\odv@numerator"),Pt("\\odv@numerator","\\frac{\\mathrm{d}#1}{\\mathrm{d}#2}"),Pt("\\odv@next","\\frac{\\mathrm{d}}{\\mathrm{d}#2}#1"),Pt("\\pdv","\\@ifstar\\pdv@next\\pdv@numerator");const Er=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(/\\,$/,"")]};Pt("\\pdv@numerator",(function(e){const[t,r,n]=Er(e.consumeArgs(2));return`\\frac{${r} ${t}}{${n}}`})),Pt("\\pdv@next",(function(e){const[t,r,n]=Er(e.consumeArgs(2));return`\\frac{${r}}{${n}} ${t}`})),Pt("\\upalpha","\\up@greek{\\alpha}"),Pt("\\upbeta","\\up@greek{\\beta}"),Pt("\\upgamma","\\up@greek{\\gamma}"),Pt("\\updelta","\\up@greek{\\delta}"),Pt("\\upepsilon","\\up@greek{\\epsilon}"),Pt("\\upzeta","\\up@greek{\\zeta}"),Pt("\\upeta","\\up@greek{\\eta}"),Pt("\\uptheta","\\up@greek{\\theta}"),Pt("\\upiota","\\up@greek{\\iota}"),Pt("\\upkappa","\\up@greek{\\kappa}"),Pt("\\uplambda","\\up@greek{\\lambda}"),Pt("\\upmu","\\up@greek{\\mu}"),Pt("\\upnu","\\up@greek{\\nu}"),Pt("\\upxi","\\up@greek{\\xi}"),Pt("\\upomicron","\\up@greek{\\omicron}"),Pt("\\uppi","\\up@greek{\\pi}"),Pt("\\upalpha","\\up@greek{\\alpha}"),Pt("\\uprho","\\up@greek{\\rho}"),Pt("\\upsigma","\\up@greek{\\sigma}"),Pt("\\uptau","\\up@greek{\\tau}"),Pt("\\upupsilon","\\up@greek{\\upsilon}"),Pt("\\upphi","\\up@greek{\\phi}"),Pt("\\upchi","\\up@greek{\\chi}"),Pt("\\uppsi","\\up@greek{\\psi}"),Pt("\\upomega","\\up@greek{\\omega}"),Pt("\\invamp",'\\mathbin{\\char"214b}'),Pt("\\parr",'\\mathbin{\\char"214b}'),Pt("\\with",'\\mathbin{\\char"26}'),Pt("\\multimapinv",'\\mathrel{\\char"27dc}'),Pt("\\multimapboth",'\\mathrel{\\char"29df}'),Pt("\\scoh",'{\\mkern5mu\\char"2322\\mkern5mu}'),Pt("\\sincoh",'{\\mkern5mu\\char"2323\\mkern5mu}'),Pt("\\coh",'{\\mkern5mu\\rule{}{0.7em}\\mathrlap{\\smash{\\raise2mu{\\char"2322}}}\n{\\smash{\\lower4mu{\\char"2323}}}\\mkern5mu}'),Pt("\\incoh",'{\\mkern5mu\\rule{}{0.7em}\\mathrlap{\\smash{\\raise2mu{\\char"2323}}}\n{\\smash{\\lower4mu{\\char"2322}}}\\mkern5mu}'),Pt("\\standardstate","\\text{\\tiny\\char`⦵}");const Ir={"^":!0,_:!0,"\\limits":!0,"\\nolimits":!0};class $r{constructor(e,t,r){this.settings=t,this.expansionCount=0,this.feed(e),this.macros=new Nr(Tr,t.macros),this.mode=r,this.stack=[]}feed(e){this.lexer=new Ar(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 br("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.length}expandAfterFuture(){return this.expandOnce(),this.future()}expandNextToken(){for(;;)if(!1===this.expandOnce()){const e=this.stack.pop();return e.treatAsRelax&&(e.text="\\relax"),e}throw new Error}expandMacro(e){return this.macros.has(e)?this.expandTokens([new br(e)]):void 0}expandTokens(e){const t=[],r=this.stack.length;for(this.pushTokens(e);this.stack.length>r;)if(!1===this.expandOnce(!0)){const e=this.stack.pop();e.treatAsRelax&&(e.noexpand=!1,e.treatAsRelax=!1),t.push(e)}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 Ar(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(gr,e)||Object.prototype.hasOwnProperty.call(E.math,e)||Object.prototype.hasOwnProperty.call(E.text,e)||Object.prototype.hasOwnProperty.call(Ir,e)}isExpandable(e){const t=this.macros.get(e);return null!=t?"string"==typeof t||"function"==typeof t||!t.unexpandable:Object.prototype.hasOwnProperty.call(gr,e)&&!gr[e].primitive}}const Lr=/^[₊₋₌₍₎₀₁₂₃₄₅₆₇₈₉ₐₑₕᵢⱼₖₗₘₙₒₚᵣₛₜᵤᵥₓᵦᵧᵨᵩᵪ]/,Fr=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","ᵝ":"β","ᵞ":"γ","ᵟ":"δ","ᵠ":"ϕ","ᵡ":"χ","ᶿ":"θ"}),Gr=Object.freeze({"𝒜":"A","ℬ":"B","𝒞":"C","𝒟":"D","ℰ":"E","ℱ":"F","𝒢":"G","ℋ":"H","ℐ":"I","𝒥":"J","𝒦":"K","ℒ":"L","ℳ":"M","𝒩":"N","𝒪":"O","𝒫":"P","𝒬":"Q","ℛ":"R","𝒮":"S","𝒯":"T","𝒰":"U","𝒱":"V","𝒲":"W","𝒳":"X","𝒴":"Y","𝒵":"Z"});var Dr={"́":{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"}},Pr={"á":"á","à":"à","ä":"ä","ǟ":"ǟ","ã":"ã","ā":"ā","ă":"ă","ắ":"ắ","ằ":"ằ","ẵ":"ẵ","ǎ":"ǎ","â":"â","ấ":"ấ","ầ":"ầ","ẫ":"ẫ","ȧ":"ȧ","ǡ":"ǡ","å":"å","ǻ":"ǻ","ḃ":"ḃ","ć":"ć","č":"č","ĉ":"ĉ","ċ":"ċ","ď":"ď","ḋ":"ḋ","é":"é","è":"è","ë":"ë","ẽ":"ẽ","ē":"ē","ḗ":"ḗ","ḕ":"ḕ","ĕ":"ĕ","ě":"ě","ê":"ê","ế":"ế","ề":"ề","ễ":"ễ","ė":"ė","ḟ":"ḟ","ǵ":"ǵ","ḡ":"ḡ","ğ":"ğ","ǧ":"ǧ","ĝ":"ĝ","ġ":"ġ","ḧ":"ḧ","ȟ":"ȟ","ĥ":"ĥ","ḣ":"ḣ","í":"í","ì":"ì","ï":"ï","ḯ":"ḯ","ĩ":"ĩ","ī":"ī","ĭ":"ĭ","ǐ":"ǐ","î":"î","ǰ":"ǰ","ĵ":"ĵ","ḱ":"ḱ","ǩ":"ǩ","ĺ":"ĺ","ľ":"ľ","ḿ":"ḿ","ṁ":"ṁ","ń":"ń","ǹ":"ǹ","ñ":"ñ","ň":"ň","ṅ":"ṅ","ó":"ó","ò":"ò","ö":"ö","ȫ":"ȫ","õ":"õ","ṍ":"ṍ","ṏ":"ṏ","ȭ":"ȭ","ō":"ō","ṓ":"ṓ","ṑ":"ṑ","ŏ":"ŏ","ǒ":"ǒ","ô":"ô","ố":"ố","ồ":"ồ","ỗ":"ỗ","ȯ":"ȯ","ȱ":"ȱ","ő":"ő","ṕ":"ṕ","ṗ":"ṗ","ŕ":"ŕ","ř":"ř","ṙ":"ṙ","ś":"ś","ṥ":"ṥ","š":"š","ṧ":"ṧ","ŝ":"ŝ","ṡ":"ṡ","ẗ":"ẗ","ť":"ť","ṫ":"ṫ","ú":"ú","ù":"ù","ü":"ü","ǘ":"ǘ","ǜ":"ǜ","ǖ":"ǖ","ǚ":"ǚ","ũ":"ũ","ṹ":"ṹ","ū":"ū","ṻ":"ṻ","ŭ":"ŭ","ǔ":"ǔ","û":"û","ů":"ů","ű":"ű","ṽ":"ṽ","ẃ":"ẃ","ẁ":"ẁ","ẅ":"ẅ","ŵ":"ŵ","ẇ":"ẇ","ẘ":"ẘ","ẍ":"ẍ","ẋ":"ẋ","ý":"ý","ỳ":"ỳ","ÿ":"ÿ","ỹ":"ỹ","ȳ":"ȳ","ŷ":"ŷ","ẏ":"ẏ","ẙ":"ẙ","ź":"ź","ž":"ž","ẑ":"ẑ","ż":"ż","Á":"Á","À":"À","Ä":"Ä","Ǟ":"Ǟ","Ã":"Ã","Ā":"Ā","Ă":"Ă","Ắ":"Ắ","Ằ":"Ằ","Ẵ":"Ẵ","Ǎ":"Ǎ","Â":"Â","Ấ":"Ấ","Ầ":"Ầ","Ẫ":"Ẫ","Ȧ":"Ȧ","Ǡ":"Ǡ","Å":"Å","Ǻ":"Ǻ","Ḃ":"Ḃ","Ć":"Ć","Č":"Č","Ĉ":"Ĉ","Ċ":"Ċ","Ď":"Ď","Ḋ":"Ḋ","É":"É","È":"È","Ë":"Ë","Ẽ":"Ẽ","Ē":"Ē","Ḗ":"Ḗ","Ḕ":"Ḕ","Ĕ":"Ĕ","Ě":"Ě","Ê":"Ê","Ế":"Ế","Ề":"Ề","Ễ":"Ễ","Ė":"Ė","Ḟ":"Ḟ","Ǵ":"Ǵ","Ḡ":"Ḡ","Ğ":"Ğ","Ǧ":"Ǧ","Ĝ":"Ĝ","Ġ":"Ġ","Ḧ":"Ḧ","Ȟ":"Ȟ","Ĥ":"Ĥ","Ḣ":"Ḣ","Í":"Í","Ì":"Ì","Ï":"Ï","Ḯ":"Ḯ","Ĩ":"Ĩ","Ī":"Ī","Ĭ":"Ĭ","Ǐ":"Ǐ","Î":"Î","İ":"İ","Ĵ":"Ĵ","Ḱ":"Ḱ","Ǩ":"Ǩ","Ĺ":"Ĺ","Ľ":"Ľ","Ḿ":"Ḿ","Ṁ":"Ṁ","Ń":"Ń","Ǹ":"Ǹ","Ñ":"Ñ","Ň":"Ň","Ṅ":"Ṅ","Ó":"Ó","Ò":"Ò","Ö":"Ö","Ȫ":"Ȫ","Õ":"Õ","Ṍ":"Ṍ","Ṏ":"Ṏ","Ȭ":"Ȭ","Ō":"Ō","Ṓ":"Ṓ","Ṑ":"Ṑ","Ŏ":"Ŏ","Ǒ":"Ǒ","Ô":"Ô","Ố":"Ố","Ồ":"Ồ","Ỗ":"Ỗ","Ȯ":"Ȯ","Ȱ":"Ȱ","Ő":"Ő","Ṕ":"Ṕ","Ṗ":"Ṗ","Ŕ":"Ŕ","Ř":"Ř","Ṙ":"Ṙ","Ś":"Ś","Ṥ":"Ṥ","Š":"Š","Ṧ":"Ṧ","Ŝ":"Ŝ","Ṡ":"Ṡ","Ť":"Ť","Ṫ":"Ṫ","Ú":"Ú","Ù":"Ù","Ü":"Ü","Ǘ":"Ǘ","Ǜ":"Ǜ","Ǖ":"Ǖ","Ǚ":"Ǚ","Ũ":"Ũ","Ṹ":"Ṹ","Ū":"Ū","Ṻ":"Ṻ","Ŭ":"Ŭ","Ǔ":"Ǔ","Û":"Û","Ů":"Ů","Ű":"Ű","Ṽ":"Ṽ","Ẃ":"Ẃ","Ẁ":"Ẁ","Ẅ":"Ẅ","Ŵ":"Ŵ","Ẇ":"Ẇ","Ẍ":"Ẍ","Ẋ":"Ẋ","Ý":"Ý","Ỳ":"Ỳ","Ÿ":"Ÿ","Ỹ":"Ỹ","Ȳ":"Ȳ","Ŷ":"Ŷ","Ẏ":"Ẏ","Ź":"Ź","Ž":"Ž","Ẑ":"Ẑ","Ż":"Ż","ά":"ά","ὰ":"ὰ","ᾱ":"ᾱ","ᾰ":"ᾰ","έ":"έ","ὲ":"ὲ","ή":"ή","ὴ":"ὴ","ί":"ί","ὶ":"ὶ","ϊ":"ϊ","ΐ":"ΐ","ῒ":"ῒ","ῑ":"ῑ","ῐ":"ῐ","ό":"ό","ὸ":"ὸ","ύ":"ύ","ὺ":"ὺ","ϋ":"ϋ","ΰ":"ΰ","ῢ":"ῢ","ῡ":"ῡ","ῠ":"ῠ","ώ":"ώ","ὼ":"ὼ","Ύ":"Ύ","Ὺ":"Ὺ","Ϋ":"Ϋ","Ῡ":"Ῡ","Ῠ":"Ῠ","Ώ":"Ώ","Ὼ":"Ὼ"};const Rr=["bin","op","open","punct","rel"];class jr{constructor(e,t,r=!1){this.mode="math",this.gullet=new $r(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","&"]}subparse(e){const t=this.nextToken;this.consume(),this.gullet.pushToken(new br("}")),this.gullet.pushTokens(e);const r=this.parseExpression(!1);return this.expect("}"),this.nextToken=t,r}parseExpression(e,t,r){const n=[];for(;;){"math"===this.mode&&this.consumeSpaces();const o=this.fetch();if(-1!==jr.endOfExpression.indexOf(o.text))break;if(t&&o.text===t)break;if(r&&"\\middle"===o.text)break;if(e&&gr[o.text]&&gr[o.text].infix)break;const s=this.parseAtom(t);if(!s)break;"internal"!==s.type&&(n.push(s),this.prevAtomType="atom"===s.type?s.family:s.type)}return"text"===this.mode&&this.formLigatures(n),this.handleInfixNodes(n)}handleInfixNodes(t){let r,n=-1;for(let o=0;o=128))return null;if(this.settings.strict&&"math"===this.mode)throw new e(`Unicode text character "${r[0]}" used in math mode`,t);o={type:"textord",mode:"text",loc:fr.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},Hr=[2,2,3,3];class Vr{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 Vr(t)}withLevel(e){return this.extend({level:e})}incrementLevel(){return this.extend({level:Math.min(this.level+1,3)})}inSubOrSup(){return this.extend({level:Hr[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 _r=function(e,t,r={}){t.textContent="";const n="math"===t.tagName.toLowerCase();n&&(r.wrap="none");const o=Wr(e,r);n||o.children.length>1?(t.textContent="",o.children.forEach((e=>{t.appendChild(e.toNode())}))):t.appendChild(o.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."),_r=function(){throw new e("Temml doesn't work in quirks mode.")});const Wr=function(t,r){const n=new a(r);try{const e=Ur(t,n);return ue(e,t,new Vr({level:n.displayMode?nt:ot,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 x(r+"\n"+t.toString())]);return o.style.color=n.errorColor,o.style.whiteSpace="pre-line",o}(r,t,n)}};return{version:"0.10.25",render:_r,renderToString:function(e,t){return Wr(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 jr(e,r,!0);delete n.gullet.macros.current["\\df@tag"];return n.parse()},__parse:function(e,t){const r=new a(t);return Ur(e,r)},__renderToMathMLTree:Wr,__defineSymbol:I,__defineMacro:Pt}}(); \ 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/copy-tex.html b/site/copy-tex.html deleted file mode 100644 index 65f3cfdf..00000000 --- a/site/copy-tex.html +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - Copy-tex test - - - - - - -

Copy-tex test

-

Try copy/pasting some of the text below.

- -

With any second order polynomial, \(\mathrm{a}x^{2} + \mathrm{b}x + \mathrm{c} = 0\), - you can solve for the zeros with the quadratic formula:

- -

$$ x = \frac{-\mathrm{b} ± \sqrt{\mathrm{b}^{2} - 4 \mathrm{a}\mathrm{c}}}{2 \mathrm{a}} $$

- -

The system: -\(\begin{matrix} - 3 x + 2 y + z = 39 \\ - 2 x + 3 y + z = 34 \\ - x + 2 y + 3 z = 26 -\end{matrix}\) when restated in matrix format is: -\(\begin{pmatrix} - 3 & 2 & 1 \\ - 2 & 3 & 1 \\ - 1 & 2 & 3 -\end{pmatrix} -\begin{bmatrix}x \\ y \\ z \end{bmatrix} = -\begin{bmatrix}39 \\ 34 \\ 26 \end{bmatrix}\)

- - - - \ No newline at end of file diff --git a/site/docs/docStyles.css b/site/docs/docStyles.css deleted file mode 100644 index b4099946..00000000 --- a/site/docs/docStyles.css +++ /dev/null @@ -1,377 +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; -} - -td > p:first-child { margin-top: 0em; } - -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: 0em; - 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:first-child { - 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 36be6490..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 Chrome, Edge, Firefox, and Safari. Temml will never work in Internet Explorer.

-

Installation

-

For use in the browser, you can download a zip file of Temml from the releases page of the Temml repository. For server-side use, you can obtain Temml via CLI commands npm install temml or yarn add temml.

-

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 use temml.cjs or temml.mjs 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. The code for such a conversion might look like this:

-

Option 1: Macros do not persist between calls to Temml:

-
// Render all the math.
-for (let aSpan of [...mathSpans]) {
-    const tex = aSpan.textContent;
-    const displayMode = aSpan.classList.contains("display");
-    temml.render(tex, aSpan, { displayMode });
-}
-// Optional postProcess to render \ref{}
-temml.postProcess(document.body);
Option 2: Macros defined with \gdef do persist: -
// Optional macros object to hold macros that persist between calls to Temml.
-const macros = {}
-// Render all the math.
-for (let aSpan of [...mathSpans]) {
-    const tex = aSpan.textContent;
-    const displayMode = aSpan.classList.contains("display");
-    // Notice the macros argument below.
-    // It carries macros that were defined with \gdef or \global\let
-    temml.render(tex, aSpan, { macros, displayMode });
-}
-// Optional postProcess to render \ref{}
-temml.postProcess(document.body);

Notice that you can choose when to stop macro persistence by redefining macros.

-
-
-
Option 3: Macros persist and there are some predefined macros: -

Now say that you wish to pre-define two macros and a color with document-wide scope.

-
// Optional preamble to pre-define macros.
-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);

If the element you provide is a <math> element, Temml will populate it. Otherwise, it will create a new <math> element and make it a child of the element you provide.

-

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. (default: false)

  • -
  • wrap: ("tex" | "=" | "none"). A mode for soft line breaks in non-display mode math. The tex option sets a soft line break after every top-level relation and binary operator, per The TeXbook, page 173. The = option sets a soft line break before the second and subsequent top-level = signs. tex is the default.

    -

    Caveats: Soft line breaks work in Chromium and Firefox, but do not work in WebKit or Safari. Display mode math gets no soft line breaks. Annotated math gets no soft line breaks. If a writer sets a hard line break via \\ or \cr, then Temml will not set any soft line breaks in that expression.

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

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

  • -
  • 'throwOnError': boolean. If true, Temml will throw parse errors to the console. If false, Temml will write the parse error to the output of the render() function. (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. (\edef expansion counts all expanded tokens.) 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 can be helpful for other user agents, such as Microsoft Word. (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}
      where protocol is a lowercased string like "http" or "https" that appears before a colon, or "_relative" for relative URLs.

    • -
    • {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, everything 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.

-

Latin Modern will provide the best quality rendering. It is a clone of Computer Modern and so is very home-like for readers accustomed to LaTeX documents. For best results, you must also serve a small (10kb) Temml.woff2 file. Then you’ll get support for \mathscr{…} and you’ll get primes at the correct vertical alignment in Chrome and Edge.

-

Temml-Local.css is the light-weight option. It calls two fonts: Cambria Math, which comes pre-installed in Windows, or STIX TWO, which comes pre-installed in iOS and MacOS (as of Safari 16). It also needs to be augmented with Temml.woff2.

-

Sadly, this option has rendering issues. Chrome botches extensible arrows and it will fail to stretch the symbol on Windows. Android does not currently provide a font with a MATH table, so it has many problems.

-

Asana and Libertinus have some of the same rendering problems as Cambria Math, although Asana does contain its own roundhand glyphs.

-

Fira Math is a sans-serif math font.

-

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.

  • -
  • copy-tex: When users select and copy <math> elements, copies their LaTeX source to the clipboard

  • -
  • mhchem: Write beautiful chemical equations easily.

  • -
  • physics: Implement much of the LaTeX physics package.

  • -
  • texvc: Support 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 or temml.mjs instead of temml.min.js. temml.cjs and temml.mjs both include 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)

-

Browser Issues

-

If you are deciding whether to render math in MathML, know that all the major browser engines now support MathML. If you want to revel in the sight of over a thousand LaTeX functions rendered well in MathML, head on over to the Temml function support page.

-

The rest of you, stay here. This section identifies functions that browsers render poorly.

- - - - - - - - - - - - - - - - - -
ItemChromiumGecko
(Firefox)
WebKit
(Safari)
Examples
Renders well on first paintbad¹E^ABCD
Accentsbad²𝖺^
Integral, ∫, in display modemeh³x2
\left( x \right)meh⁴meh⁴(x)
\bigg(, \Bigg(, etc.meh⁵

(2x2+2y2)

\cancel, \bcancel, \xcancelmeh⁶meh⁶meh⁶5
Tag placementpoor⁷

x(tag)

\mathllap, \mathrlapbad⁸=//
Extensible arrowspoor⁹bad9, 10AnoteB
Radical heightmeh¹¹meh¹¹fc
Size 4 radicalsmeh¹²
Line-breakingbad¹³
mhchem subscriptsbad¹⁴H2O
-

Notes:

-
  1. There are several items that WebKit places correctly only after a page refresh, or sometimes only after a back-button navigation.

  2. -
  3. WebKit renders some accents too high even after a page refresh. Temml does some work to mitigate this. It’s not enough.+ accent height

  4. -
  5. Chromium does not stretch a Cambria Math ∫ in display mode. Latin Modern is okay.+ accent italic correction

  6. -
  7. Chromium and WebKit mis+ extensible accents

  8. -
  9. Chromium sets + extensible arrows

  10. -
  11. Because Chromium does not support + height of ‖ in {Vmatrix} environment <enclose>, Temml uses background images for \cancel. It may not print properly.

  12. -
  13. WebKit mis-locates tags and AMS automatic equation numbers because it ignores width: 100% on an <mtable>.

  14. -
  15. WebKit laps are broken.

  16. -
  17. Chromium and WebKit system font extensible arrows have notes placed too high. Some do not stretch in Cambria Math. Again, Latin Modern is okay.

  18. -
  19. WebKit fails to stretch most extensible arrows.

  20. -
  21. Firefox and WebKit sometimes select radicals that are too tall. (Root cause: They don’t cramp subscripts and superscripts.)

  22. -
  23. In very tall radicals, Chromium does not accurately match the vinculum to the surd.

  24. -
  25. Automatic linebreaking (non-display mode) works in Chromium and Firefox. Not in WebKit.

  26. -
  27. WebKit hides mhchem subscripts and superscripts.

-

Another issue if you are targeting mobile: Android has not provided a math system font. They are planning to add a MATH table to the Noto Sans font. I don’t think it has shipped.

-

You can suggest revisions to this page at the Temml issues page.

-
-

Copyright © 2021-2024 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 c064268d..00000000 --- a/site/docs/en/comparison.html +++ /dev/null @@ -1,10466 +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.10.25, 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!
\!ab\(a\!b\)a ⁣ba\!baba\!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
\AngstromNot supportedNot supportedNot supported\Angstrom
\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
\argmaxarg maxxarg maxyxarg maxyxNot supportedarg maxxarg maxyxarg maxyx\begin{matrix}\argmax x \\ \argmax_y x \\\argmax\limits_y x\end{matrix}Not supported
\argminarg minNot 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 }
\arraystretchNot supported\(\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
\astrosunNot supportedNot supportedNot supported
\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
\backdprimeNot supportedNot supportedNot supported
\backtrprimeNot supportedNot supportedNot 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}
\barcapNot supportedNot supportedNot supported
\barcupNot supportedNot supportedNot supported
\barveeNot supportedNot supportedNot supported
\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)
\bigtimesNot supportedNot supported\bigtimes
\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
\blackhourglassNot supportedNot supportedNot supported
\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
\boxastNot supportedNot supportedNot supported
\boxboxNot supportedNot supportedNot supported
\boxcircleNot supportedNot supportedNot supported
\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}
\canceltoNot supportedNot supportedNot supportedNot supported
\Cap\(\Cap\)\Cap\Cap
\cap\(\cap\)\cap\cap
\capbarcupNot supportedNot supportedNot supported
\capdotNot supportedNot supportedNot supported
\capovercupNot supportedNot supportedNot supported
{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
\cent¢Not supportedNot supportedNot supported
\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
\circledequalNot supportedNot supportedNot supported
\circledparallelNot supportedNot supportedNot supported
\circledR®\(\circledR\)®\circledRNot supported
\circledS\(\circledS\)\circledSNot supported
\circledvertNot supportedNot supportedNot supported
\circlehbarNot supportedNot supportedNot supported
\classabcdefghNot supportedNot supportedNot supportedab\class{mathHighlight}{cdef}gh
\clineNot supportedNot supportedNot supportedNot supported
\closedvarcapNot supportedNot supportedNot supported
\closedvarcupNot 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
\concavediamondNot supportedNot supportedNot supported
\concavediamondtickleftNot supportedNot supportedNot supported
\concavediamondtickrightNot supportedNot supportedNot 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
\cupovercapNot supportedNot supportedNot supported
\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
\ddddotx….Not 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
\diameterNot supportedNot supportedNot 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
\doublebarveeNot supportedNot supportedNot supported
\dotx˙\(\dot x\)x˙\dot xx˙\dot x\dot x
\Doteq\(\Doteq\)\Doteq\Doteq
\doteq\(\doteq\)\doteq\doteq
\doteqdot\(\doteqdot\)\doteqdot\doteqdot
\dotminusNot supportedNot supported\dotminus
\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
\dprimeNot supportedNot supportedNot supported
{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
\EarthNot supportedNot supportedNot supported
\ell\(\ell\)\ell\ell
\elseNot supportedNot supportedNot supportedNot supported
\empty\(\empty\)\empty\empty
\emptyset\(\emptyset\)\emptyset\emptyset
\encloseNot supported
See \angl
\(\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
\fullouterjoinNot supportedNot supportedNot supported
\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}
\hourglassNot supportedNot supportedNot supported
\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
\injliminj limxinj limyxinj limyx\(\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
\interleaveNot supportedNot supportedNot supported
\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
\invlazysNot 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
\lAngleANot supportedNot supportedNot supported\lAngle 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
\leftmodelsNot supportedNot supportedNot supported
\leftmoonNot supportedNot supportedNot supported
\leftouterjoinNot supportedNot supportedNot supported
\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
\liminflim infxlim infyxlim infyx\(\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
\limsuplim supxlim supyxlim supyx\(\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
\llangleANot supportedNot supportedA\llangle A\rrangle\llangle A\rrangle
\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
\llparenthesisNot supportedNot supportedNot 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
\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
\lozengeminusNot supportedNot supportedNot supported
\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
\mapsfromNot supportedNot supportedNot 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}
\mathtipNot supportedNot 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
\minusdotNot supportedNot supportedNot supported
\minusoNot supported
See \standardstate
Not supported\minusoNot supported
\minusfdotsNot supportedNot supportedNot supported
\minusrdotsNot supportedNot supportedNot 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
\NandNot supportedNot supportedNot supported
\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
\NorNot supportedNot supportedNot supported
\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}
\obarNot supportedNot supportedNot supported
\obslashNot supportedNot supportedNot supported
\oc!Not supportedNot supportedNot supported
\odivNot 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
\ogreaterthanNot supportedNot 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\(\oldstyle 0123456\)Not supportedNot supported\oldstyle 0123456
\oldstylenumsNot supportedNot supportedNot supportedNot supported
\olessthanNot supportedNot supportedNot supported
\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
\operpNot supportedNot supportedNot supported
\oplus⊕︎\(\oplus\)\oplus\oplus
\orNot supportedNot supportedNot supportedNot supported
\origofNot supported\origofNot supported
\oslash\(\oslash\)\oslash\oslash
\otimes\(\otimes\)\otimes\otimes
\OtimesNot supportedNot supportedNot supported
\otimeshatNot supportedNot supportedNot supported
\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}
\phaseNot supportedNot 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
\projlimproj limnx\(\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}
\QEDNot supportedNot supportedNot supported
\qprimeNot supportedNot supportedNot supported
\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
\rAngleANot supportedNot supportedNot supported\lAngle A\rAngle
\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}
\reflectboxSNot supportedNot supportedNot supported\reflectbox{S}
\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
\rightmoonNot supportedNot supportedNot supported
\rightouterjoinNot supportedNot supportedNot supported
\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
\rrangleANot supportedNot supportedA\llangle A\rrangle\llangle A\rrangle
\rrbracketNot supported\rrbracketNot supported
\rrparenthesisNot supportedNot supportedNot 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
\shuffleNot 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)
\smashtimesNot supportedNot supportedNot supported
\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
\SqcapNot supportedNot supportedNot supported
\sqcup\(\sqcup\)\sqcup\sqcup
\SqcupNot supportedNot supportedNot supported
\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}
\sslashNot supportedNot supported\sslash
\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
\sunNot supportedNot supportedNot supported
\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 }
\textMMMMMM\(\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
\texttipNot supportedNot 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
\threedotcolonNot supportedNot supportedNot supported
\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
\toggleNot supportedNot 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
\triangleminusNot supportedNot supportedNot supported
\triangleplusNot supportedNot supportedNot supported
\triangleright\(\triangleright\)\triangleright\triangleright
\trianglerighteq\(\trianglerighteq\)\trianglerighteq\trianglerighteq
\triangletimesNot supportedNot supportedNot supported
\trprimeNot supportedNot supportedNot supported
\tt𝙰𝚊𝙱𝚋𝟷𝟸𝟹\({\tt AaBb123}\)AaBb123{\tt AaBb123}Not supported{\tt AaBb123}
\twocapsNot supportedNot supportedNot supported
\twocupsNot supportedNot supportedNot supported
\twoheadleftarrow\(\twoheadleftarrow\)\twoheadleftarrow\twoheadleftarrow
\twoheadrightarrow\(\twoheadrightarrow\)\twoheadrightarrow\twoheadrightarrow
\typecolonNot supportedNot supportedNot supported
- -

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
\varliminflimnx\(\varliminf\limits_n x\)limnx\varliminf\limits_n xNot supported\varliminf\limits_n x
\varlimsuplimnx\(\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
\VDashNot supportedNot supported\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
\Vee Not supportedNot supported\Vee
\veebar\(\veebar\)\veebar\veebar
\veedotNot supportedNot supportedNot supported
\veedoublebarNot supportedNot supportedNot supported
\veeeqNot supportedNot supportedNot supported
\veeonveeNot supportedNot supportedNot supported
\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
\WedgeNot supportedNot supported\wedge
\wedgebarNot supportedNot supportedNot supported
\wedgedotNot supportedNot supportedNot supported
\wedgedoublebarNot supportedNot supportedNot supported
\wedgeqNot supportedNot supportedNot supported
\wedgeonwedgeNot supportedNot supportedNot supported
\weierp\(\weierp\)\weierpNot supported
\whitesquaretickleftNot supportedNot supportedNot supported
\whitesquaretickrightNot supportedNot supportedNot 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}
\XorNot supportedNot supportedNot supported
\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-2024 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 81a13d8d..00000000 --- a/site/docs/en/support_table.html +++ /dev/null @@ -1,1630 +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.

-

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

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionRenderedSource or CommentPackage
!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

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionRenderedSource or Comment
\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
\Angstromstix
\anticommutator{A,B}\anticommutator{A}{B}physics extension
\approx
\approxeq
\arccosarccos
\arcctgarcctg
\arceqstix
\arcsinarcsin
\arctanarctan
\arctgarctg
\argarg
\argmaxarg maxstatmath
\argminarg minstatmath
{array}abcd\begin{array}{cc}
   a & b \\
   c & d
\end{array}
LaTeX2ε
\arrayNot supportedSee{array}
\arraystretchNot supported
\ArrowvertNot supportedsee\Vert
\arrowvertNot supportedsee\vert
\ast
\astrosunstix
\asymp
\atopab{a \atop b}
\atopwithdelimsNot supported
-

B

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionRenderedSource or CommentPackage
\backcong

MnSymbol
\backepsilon

ams
\backprimeσ\sigma^\backprimeams
\backdprimeσ\sigma^\backdprimestix
\backsim

ams
\backsimeq

ams
\backslash\

\backtrprimeσ\sigma^\backtrprimestix
\bary\bar{y}

\barcap

stix
\barcup

stix
\barvee

stix
\barwedge

ams
\ballotx

arev
\Bbb𝔸𝔹\Bbb{ABC}

\Bbbk𝕜

\bboxNot supported

\bcancel5\bcancel{5}cancel
\because

ams
\beginabcd\begin{matrix}
a & b \\
c & d
\end{matrix}
ams
\begingroupa\begingroup a\endgroup

\BetaΒ

\betaβ

\beth

ams
\between

ams
\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)

\bigtimes

stix
\bigsqcap

\bigsqcup

\bigstar

ams
\bigtriangledown

\bigtriangleup

\biguplus

\bigvee

\bigwedge

\binom(nk)\binom n kams
\blackhourglass

stix
\blacklozenge

ams
\blacksquare

ams
\blacktriangle

ams
\blacktriangledown

ams
\blacktriangleleft

ams
\blacktriangleright

ams
\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

\Bot

cmll
\bowtie

\Box

ams
\boxast

stix
\boxbox

stix
\boxcircle

stix
\boxdot

ams
\boxedab\boxed{ab}ams
\boxminus

ams
\boxplus

ams
\boxtimes

ams
\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

\bull

texvc extension
\bullet

\Bumpeq

ams
\bumpeq

ams
-

C

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionRenderedSource or Comment
\CNot supportedDeprecatedtexvc
\cc¸\text{\c{c}}
\cal𝒜𝒶𝒷{\cal AaBb}
\cancel5\cancel{5}cancel
\Capams
\cap
\capbarcupstix
\capdotstix
\capovercupstix
{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
\ceCX6HX5CHO\ce{C6H5-CHO}mhchem extension
\ceeNot supportedDeprecated
Use\ce instead.
mhchem
\cent¢wasysym
\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
\circledequalstix
\circleddashams
\circledparallelstix
\circledR®ams
\circledSams
\circledvertstix
\circlehbarstix
\classNot supported
\clineNot supported
\closedvarcapstix
\closedvarcupstix
\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
\concavediamondstix
\concavediamondtickleftstix
\concavediamondtickrightstix
\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
\cupovercapstix
\curl×physics extension
\curlyeqprecams
\curlyeqsuccams
\curlyveeams
\curlywedgeams
\curvearrowleftams
\curvearrowrightams
-

D

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionRenderedSource or CommentPackage
\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
\diameterstix
\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
\dotminusstix
\dotplusams
\dotproduct\dotproductphysics extension
\dotsx1++xnx_1 + \dots + x_n
\dotsbx1++xnx_1 +\dotsb + x_nams
\dotscx,,yx,\dotsc,yams
\dotsi

A1A2

\int_{A_1}\int_{A_2}\dotsiams
\dotsmx1x2xn$x_1 x_2 \dotsm x_nams
\dotsoams
\doublebarveestix
\doublebarwedgestix
\doublecapams
\doublecupams
\Downarrow
\downarrow
\downdownarrowsams
\downharpoonleftams
\downharpoonrightams
\dprimeff^\dprimestix
{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

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionRenderedSource or CommentPackage
\Earthstix
\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,\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
\eqequnicodemath
\eqeqequnicodemath
\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

- - - - - - - - - - - - - - - - - - - -
FunctionRenderedSource or CommentPackage
\fallingdotseqams
\fboxHi there!\fbox{Hi there!}
\fcolorboxA\fcolorbox{red}{aqua}{A}xcolor
\fdvδxδy\fdv{x}{y}physics extension
\femalestix
\fiNot supported
\Finvams
\flat
\footnotesizefootnotesize\footnotesize footnotesize
\forall
\fracab\frac a bams
\frak𝔄𝔞𝔅𝔟\frak{AaBb}
\frown
\fullouterjoinstix
\functionalderivativeδxδy\functionalderivative{x}{y}physics extension
\futurelet
-

G

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionRenderedSource or CommentPackage
\Gameams
\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
\gcdgcd
\gdefNot supported
\ge
\geneuroNot supportedSee\euro
\geneuronarrowNot supportedSee\euro
\geneurowideNot supportedSee\euro
\genfrac(aa+1]\genfrac ( ] {2pt}{0}a{a+1}ams
\geq
\geqqams
\geqslantams
\gets
\gg
\gggams
\gggtrams
\gimelams
\globalNot supported
\gnapproxams
\gneqams
\gneqqams
\gnsimams
\gradphysics extension
\gradientphysics extension
\graveeu`\grave{eu}
\gta>ba \gt bMathJax
\gtrapproxams
\gtrdotams
\gtreqlessams
\gtreqqlessams
\gtrlessams
\gtrsimams
\gvertneqq≩︀ams
-

H

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionRenderedSource or CommentPackage
\Ha˝\text{\H{a}}
\Harrtexvc extension
\hArrtexvc extension
\harrtexvc extension
\hatθ^\hat{\theta}
\hbar
\hbox x2\hbox{$x^2$}
\hbox toNot supported
\hdashlineabcd\begin{matrix}
   a & b \\
   \hdashline
   c & d
\end{matrix}
arydshln
\heartstexvc extension
\heartsuit
\hfilNot supported
\hfillNot supported
\hlineabcd\begin{matrix}
   a & b \\ \hline
   c & d
\end{matrix}
\homhom
\hookleftarrow
\hookrightarrow
\hourglassstix
\hphantomabcda\hphantom{bc}d
\hrefTEMML\href{https://temml.org/}{\Temml}
Requirestrustoption
href
\hskipwidw\hskip1em i\hskip2em d
\hslashams
\hspacesks\hspace{7ex} k
\classx\class{foo}{x}
Must enabletrust and disablestrictoption
\datax\data{foo=a, bar=b}{x}
Must enabletrust and disablestrictoption
\idx\id{bar}{x}
Must enabletrust and disablestrictoption
\stylex\style{color: red;}{x}
Must enabletrust and disablestrictoption
\hugehuge\huge huge
\HugeHuge\Huge Huge
-

I

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionRenderedSource or CommentPackage
\iı\text{\i}
\idotsint\int\idotsint\intams
\iddots
\ifNot supported
\iffABA\iff B
\ifmodeNot supported
\ifxNot supported
\iiiintams
\iiintams
\iintams
\Im
\imagetexvc extension
\imageofstix
\imathı
\impliedbyPQP\impliedby Qams
\impliesPQP\implies Qams
\in
\includegraphicssphere\includegraphics[height=1em,
totalheight=1.2em, width=1.2em,
alt=sphere]{../sphere.jpg}
graphicx
\incohcmll
\infinf
\infintexvc extension
\infty
\injliminj lim\injlimams
\innerproducta|b\innerproduct{a}{b}physics extension
\int
\intbar
\intBar
\intcap
\intclockwise
\intcup
\intercalams
\interleavestix
\intlarhk
\intop
\intx
\invampcmll
\invlazysstix
\IotaΙ
\iotaι
\isintexvc extension
\itAaBb{\it AaBb}
\itshapeNot supported
-

JK

- - - - - - - - - - - - - - - -
FunctionRenderedSource or CommentPackage
\jȷ\text{\j}
\jmathȷ
\Joinams
\KappaΚ
\kappaκ
\kerker
\kernIRI\kern-2.5pt R
\Ket|ψ\Ket{\psi}braket
\ket|ψ\ket{\psi}braket
\ketbra|ab|\ketbra{a}{b}physics extension
\KoppaϞ
\koppaϟ
-

L

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionRenderedSource or CommentPackage
\LNot supported
\lNot supported
\LambdaΛ
\lambdaλ
\label\label{idName}
Creates an HTML id.
Characters limited to:A-Za-z0-9_-
\land
\langA\lang A\rangletexvc extension
\lAngleA\lAngle A\rAngleunicode-math
\langleA\langle A\rangle
\laplacian2physics extension
\Larrtexvc extension
\lArrtexvc extension
\larrtexvc extension
\largelarge\large large
\LargeLarge\Large Large
\LARGELARGE\LARGE LARGE
\LaTeXLATEX
\lBracestix
\lbrace{
\lbrack[
\lceil
\ldotp.
\ldots
\le
\leadstoams
\left{ab\left\lbrace \dfrac ab \right.
\leftarrow
\Leftarrow
\LeftArrowNot supportedNon standard
\leftarrowtailams
\leftharpoondown
\leftharpoonup
\leftleftarrowsams
\leftmodelsMnSymbol
\leftmoonstix
\leftouterjoinstix
\Leftrightarrow
\leftrightarrow
\leftrightarrowsams
\leftrightharpoonsams
\leftrightsquigarrowams
\leftrootNot supported
\leftthreetimesams
\leq
\leqalignnoNot supported
\leqqams
\leqslantams
\lessapproxams
\lessdotams
\lesseqgtrams
\lesseqqgtrams
\lessgtrams
\lesssimams
\let
\lfloor
\lglg
\lgroup
\lhdams
\lightning
\limlim
\liminflim inf
\limitslimx\lim\limits_x
\limsuplim sup
\ll
\llangleA\llangle A\rrangleunicode-math
\llap=//{=}\llap{/\,}
\llbracketstmaryrd
\llcornerams
\Lleftarrowams
\lllams
\lllessams
\lmoustache
\lnln
\lnapproxams
\lneqams
\lneqqams
\lnot¬
\lnsimams
\loglog
\long
\Longleftarrow
\longleftarrow
\Longleftrightarrow
\longleftrightarrow
\longmapsto
\Longrightarrow
\longrightarrow
\looparrowleftams
\looparrowrightams
\lor
\lowerMM2MM\lower5pt{M^2}M  or
M\lower5pt\hbox{$M^2$}M
\lozengeams
\lozengeminusstix
\lparen(mathtools
\Lrarrtexvc extension
\lrArrtexvc extension
\lrarrtexvc extension
\lrcornerams
\lq
\Lshams
\lt<MathJax
\ltimesams
\lVertams
\lvert|ams
\lvertneqq≨︀ams
-

M

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionRenderedSource or CommentPackage
\malestix
\malteseams
\mapsfromstmaryrd
\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)ε-TeX
\minmin
\minuscoloncolonequals
\minuscoloncolon−∷colonequals
\minusdotstix
\minusfdotsstix
\minusrdotsstix
\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

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionRenderedSource or CommentPackage
\Ntexvc extension
\nabla
\Nandstix
\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
\Norstix
\normx\norm{x}physics extension
\normalfontNot supported
\normalsizenormalsize\normalsize normalsize
\not\not =
\notag

a=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

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionRenderedSource or CommentPackage
\OØ\text{\O}
\oø\text{\o}
\obarstix
\obslashstix
\oc!cmll
\odivstix
\odot
\odvdfdx\odv{f}{x}derivative
\odv*ddxf\odv*{f}{x}derivative
\OEŒ\text{\OE}
\oeœ\text{\oe}
\officialeuroNot supportedSee\euro
\ogreaterthanstix
\oiiint
\oiint
\oint
\oldstyleNot supported
\oldstylenumsNot supported
\olessthanstix
\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
\operpstix
\oplus⊕︎
\orNot supported
\order𝒪(x2)\order{x^2}physics extension
\origofstix
\oslash
\otimes
\Otimesstix
\otimeshatstix
\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

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionRenderedSource or CommentPackage
\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}
\phaseNot supported
\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
\projlimproj lim\projlimams
\propto
\providecommandHello\providecommand\greet{\text{Hello}}
\greet
\psiψ
\PsiΨ
\pu123 kJmol\pu{123 kJ//mol}mhchem extension
-

Q

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionRenderedSource or CommentPackage
\QNot supportedSee\Bbb{Q}
\qallallphysics extension
\qandandphysics extension
\qasasphysics extension
\qassumeassumephysics extension
\qc,physics extension
\qccc.c.physics extension
\qcomma,physics extension
\QEDstix
\qelseelsephysics extension
\qevenevenphysics extension
\qforforphysics extension
\qgivengivenphysics extension
\qififphysics extension
\qininphysics extension
\qintegerintegerphysics extension
\qletletphysics extension
\qoddoddphysics extension
\qororphysics extension
\qotherwiseotherwisephysics extension
\qprimeff^\qprimestix
\qq text \qq{text}physics extension
\qqtext text \qqtext{text}physics extension
\qquadaba\qquad\qquad{b}
\qsincesincephysics extension
\qthenthenphysics extension
\qty{5m}\qty{5 \text{m}}physics extension
\quadaba\quad\quad{b}
\quantity{5m}\quantity{5 \text{m}}physics extension
\qunlessunlessphysics extension
\qusingusingphysics extension
\questeqstix
-

R

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionRenderedSource or CommentPackage
\Rtexvc extension
\ra˚\text{\r{a}}
\raiseMM2MM\raise3pt{M^2}M  or
M\raise3pt\hbox{$M^2$}M
\raiseboxhigherh\raisebox{2pt}{ighe}r
\rangA\langle A\rangtexvc extension
\rAngleA\lAngle A\rAngleunicode-math
\rangleA\langle A\rangle
\rankrankM\rank Mphysics extension
\Rarrtexvc extension
\rArrtexvc extension
\rarrtexvc extension
\ratio:colonequals
\rBracestix
\rbrace}
\rbrack]
{rcases}aif bcif d}\begin{rcases}
   a &\text{if } b \\
   c &\text{if } d
\end{rcases}
mathtools
\rceil
\Re
\realtexvc extension
\Realstexvc extension
\realstexvc extension
\ref\ref{tag1}
Some sites do not support\ref.
\reflectboxS\reflectbox{S}graphicx
\relax
\renewcommandAhoy!\def\hail{Hi!}
\renewcommand\hail{\text{Ahoy!}}
\hail
newcommand
\renewenvironmentNot supportednewcommand
\requireNot supported
\ResRes[f(z)]\Res[f(z)]physics extension
\restrictionams
\rfloor
\rgroup
\rhdams
\RhoΡ
\rhoρ
\rightab)\left.\dfrac a b\right)
\Rightarrow
\rightarrow
\rightarrowtailams
\rightharpoondown
\rightharpoonup
\rightleftarrowsams
\rightleftharpoonsams
\rightmoonstix
\rightouterjoinstix
\rightrightarrowsams
\rightsquigarrowams
\rightthreetimesams
\risingdotseqams
\rlap/=\rlap{\,/}{=}
\rmAaBb12{\rm AaBb12}
\rmoustache
\rootNot supported
\rotateboxNot supported
\rparen)mathtools
\rppolint
\rq
\rrangleA\llangle A\rrangleunicode-math
\rrbracketstmaryrd
\Rrightarrowams
\Rshams
\rtimesams
\RuleNot supportedsee\rule
\rulexxx\rule[6pt]{2ex}{1ex}x
\rVertams
\rvert|ams
-

S

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionRenderedSource or CommentPackage
\S§\text{\S} or\S

\SampiϠ

\sampiϡ

\scNot supportedSee\textsc

\scoh

cmll
\scaleboxNot supported

\scpolint

\scrNot supportedSee\mathscr

\scriptscriptstylecd\scriptscriptstyle \frac -cd

\scriptsizescriptsize\scriptsize scriptsize

\scriptstyleABA{\scriptstyle B}

\sdot

texvc 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}

\sgnsgn

mismath
\sharp

\shift

cmll
\shneg

cmll
\shortmid

ams
\shortparallel

ams
\shoveleftNot supported

ams
\shoverightNot supported

ams
\shpos

cmll
\shuffle

stix
\sidesetcdab\sideset{_a^b}{_c^d}\sumams
\SigmaΣ

\sigmaσ

\sim

\simeq

\sinsin

\sincoh

cmll
\sinhsinh

\sixptsizesixptsize\sixptsize sixptsize

\shsh

\skewNot supported

\skipNot supported

\slNot supported

\smallsmall\small small

\smallfrown

ams
\smallint

{smallmatrix}abcd\begin{smallmatrix}
   a & b \\
   c & d
\end{smallmatrix}

\smallsetminus

ams
\smallsmile

ams
\smash(x2)\left(x^{\smash{2}}\right)

\smashtimes

stix
\smile

\smiley

wasysym
\soutabc\sout{abc}ulem
\SpaceNot supportedsee\space

\spacea ba\space b

\spades

texvc extension
\spadesuit

\sphericalangle

ams
{split}

a=b+c=e+f

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

\Sqcap

stix
\sqcup

\Sqcup

stix
\sqint

\square

\sqrtx3\sqrt[3]{x}

\sqsubset

ams
\sqsubseteq

\sqsupset

ams
\sqsupseteq

ams
\ssß\text{\ss}

\sslash

stmaryrd
\stackrel=!\stackrel{!}{=}

\standardstate

chemstyle
\star

\stareq

stix
\StigmaϚ

\stigmaϛ

\strictif

txfonts/pxfonts
\strictfi

txfonts/pxfonts
\strutNot supported

\styleNot supportedNon standard

\sub

texvc extension
{subarray}

iΛ0<j<nP(i,j)

\sum_{\begin{subarray}{l}
 i\in\Lambda\\
  0<j<n
\end{subarray}}P(i,j)
ams
\sube

texvc extension
\Subset

ams
\subset

\subseteq

\subseteqq

ams
\subsetneq

ams
\subsetneqq

ams
\substack

0<i<m0<j<n

\sum_{\substack{0<i<m\\0<j<n}}ams
\succ

\succapprox

ams
\succcurlyeq

ams
\succeq

\succnapprox

ams
\succneqq

ams
\succnsim

ams
\succsim

ams
\sum

\sun

stix
\supsup

\supe

texvc extension
\Supset

ams
\supset

ams
\supseteq

\supseteqq

ams
\supsetneq

ams
\supsetneqq

ams
\surd|

\swarrow

-

T

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionRenderedSource or CommentPackage
\tag

e=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
\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
\threedotcolonstix
\tildeM~\tilde M
\times×
\TinyTiny\Tiny Tiny
\tinytiny\tiny tiny
\to
\top
\TrTrρ\Tr\rhophysics extension
\trtrρ\tr\rhophysics extension
\triangle
\triangledownams
\triangleleft
\trianglelefteqams
\triangleqams
\triangleminusstix
\triangleplusstix
\triangleright
\trianglerighteqams
\triangletimesstix
\trprimeff^\trprimestix
\tt𝙰𝚊𝙱𝚋𝟷𝟸𝟹{\tt AaBb123}
\twocapsstix
\twocupsstix
\twoheadleftarrowams
\twoheadrightarrowams
\typecolonstix
-

U

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionRenderedSource or CommentPackage
\ua˘\text{\u{a}}
\Uarrtexvc extension
\uArrtexvc extension
\uarrtexvc extension
\ulcornerams
\underbarX\underbar{X}
\underbracex++xn times\underbrace{x+⋯+x}_{n\text{ times}}
\underbracketNot supported
\undergroupAB\undergroup{AB}MnSymbol
\underleftarrowAB\underleftarrow{AB}ams
\underleftrightarrowAB\underleftrightarrow{AB}ams
\underrightarrowAB\underrightarrow{AB}ams
\underlinea long argument\underline{\text{a long argument}}
\underlinesegmentNot supported
\underparenabc\underparen{abc}
\underrightarrowAB\underrightarrow{AB}
\underset=!\underset{!}{=}AMS
\unicodeNot supportedSee\char
\unlhdams
\unrhdams
\upNot supported
\upalphaαupgreek
\Uparrow
\uparrow
\upbetaβupgreek
\updeltaδupgreek
\upchiχupgreek
\Updownarrow
\updownarrow
\upetaηupgreek
\upepsilonϵupgreek
\upgammaγupgreek
\upharpoonleftams
\upharpoonrightams
\upiotaιupgreek
\upkappaκupgreek
\uplambdaλupgreek
\upmuμupgreek
\upnuνupgreek
\upomegaωupgreek
\upomicronοupgreek
\uplusupgreek
\upphiϕupgreek
\uppiπupgreek
\uppsiψupgreek
\uprhoρupgreek
\uprootNot supported
\upshapeNot supported
\upsigmaσupgreek
\UpsilonΥ
\upsilonυ
\uptauτupgreek
\upthetaθupgreek
\upuparrowsams
\upupsilonυupgreek
\upxiξupgreek
\upzetaζupgreek
\urcornerams
\url𝚑𝚝𝚝𝚙𝚜://𝚝𝚎𝚖𝚖𝚕.𝚘𝚛𝚐/\url{https://temml.org/}
Requirestrustoption
\utildeAB~\utilde{AB}undertilde
-

V

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionRenderedSource or CommentPackage
\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
\varnothingams
\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
\VDashMnSymbol
\vDashams
\vdash
\vdotphysics extension
\vdots
\vecF\vec{F}
\vectorarrow𝒂\vectorarrow{a}physics extension
\vectorbold𝒂\vectorbold{a}physics extension
\vectorunit𝒂^\vectorunit{a}physics extension
\vee
\Veestix
\veebarams
\veedotstix
\veedoublebarstix
\veeeqstix
\veeonveestix
\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

- - - - - - - - - - - - - - - - - - - - - -
FunctionRenderedSource or CommentPackage
\wedge
\Wedgestix
\wedgebarstix
\wedgedotstix
\wedgedoublebarstix
\wedgeqstix
\wedgeonwedgestix
\weierptexvc extension
\whitesquaretickleftstix
\whitesquaretickrightstix
\widecheckABˇ\widecheck{AB}mathabx
\widehatAB^\widehat{AB}
\wideparenabc\wideparen{abc}MnSymbol
\widetildeAB~\widetilde{AB}
\with&cmll
\wn?cmll
\wp
\wr
-

X

- - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionRenderedSource or CommentPackage
\xcancelABC\xcancel{ABC}cancel
\xdefNot supported
\XiΞ
\xiξ
\xhookleftarrowabc\xhookleftarrow{abc}mathtools
\xhookrightarrowabc\xhookrightarrow{abc}mathtools
\xLeftarrowabc\xLeftarrow{abc}mathtools
\xleftarrowabc\xleftarrow{abc}ams
\xleftharpoondownabc\xleftharpoondown{abc}mathtools
\xleftharpoonupabc\xleftharpoonup{abc}mathtools
\xLeftrightarrowabc\xLeftrightarrow{abc}mathtools
\xleftrightarrowabc\xleftrightarrow{abc}mathtools
\xleftrightharpoonsabcabc\xleftrightharpoons{abc}mathtools
\xlongequal=abc\xlongequal{abc}extpfeil
\xmapstoabc\xmapsto{abc}mathtools
\Xorstix
\xRightarrowabc\xRightarrow{abc}mathtools
\xrightarrowabc\xrightarrow{abc}ams
\xrightharpoondownabc\xrightharpoondown{abc}mathtools
\xrightharpoonupabc\xrightharpoonup{abc}mathtools
\xrightleftharpoonsabcabc\xrightleftharpoons{abc}mathtools
\xtofromabcabc\xtofrom{abc}extpfeil
\xtwoheadleftarrowabc\xtwoheadleftarrow{abc}extpfeil
\xtwoheadrightarrowabc\xtwoheadrightarrow{abc}extpfeil
-

YZ

- - - - - - - -
FunctionRenderedSource or CommentPackage
\yen¥ams
\Ztexvc extension
\ZetaΖ
\zetaζ
-
-

Copyright © 2021-2024 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 d30d9563..00000000 --- a/site/docs/en/supported.html +++ /dev/null @@ -1,768 +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.

-

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

-

Accents

- - - - - - - - - - - - - - -
f f'a~ \tilde{a}ac~ \widetilde{ac}
f f''F \vec{F}AB~ \utilde{AB}
f f^{\prime}AB \overleftarrow{AB}ABC \overrightarrow{ABC}
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}
f f^{\dprime}f f^{\trprime}f f^{\qprime}
σ \sigma^{\backprime}σ \sigma^{\backdprime}σ \sigma^{\backtrprime}
-

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}π=cd \boxed{\pi=\frac c d}
abc \sout{abc}

\ref{tag1}

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 of the standard HTML predefined color names.

  • -
  • Any color from the following xcolor table.

-
- - - - - - - - - - - - - - - - - - - - -
  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
<> \lt
        \gt
  \lAngle
     \rAngle
┌ ┐ \ulcorner
     \urcorner
\Downarrow
| || \vert └ ┘ \llcorner
     \lrcorner
\Updownarrow
\| \Vert\left.\right.\ \backslash
| | \lvert
     \rvert
  \lVert
     \rVert
  ⟦ ⟧  \llbracket
     \rrbracket
  \lBrace \rBrace

     

  \llparenthesis
       \rrparenthesis
  \llangle \rrangle
-

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}
abcd\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{bmatrix}
|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\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}}
-

AMS Environments

-

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
\end{align}

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 \AngstromØ \text{\O}
\daleth \Finv𝕜 \Bbbkæ \text{\ae}ß \text{\ss}
ð \eth \hbar \ReÆ \text{\AE}ı \text{\i}
\ell \hslash \wpœ \text{\oe}ȷ \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

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

There are two methods that will render any Unicode charater:

-
  1. Use the \char function and the Unicode code in hex. For example \char"263a will render as .

  2. -
  3. Write the character inside \text{…}. For example, \text{☺} will render as .

-
-
More about Unicode script… -

The Unicode range U+1D49C - U+1D4B5, Mathematical Script, has been ambiguous. Some fonts put chancery glyphs (𝒜𝒞) at those code points and some fonts use roundhand glyphs (𝒜𝒞). Temml’s default for code points in this range is chancery, which matches the fonts Cambria Math and STIX TWO. It also matches the TeX function \mathcal{…}.

-

Per Unicode 14+, Temml will return a roundhand glyph if you append a \ufe01 to a character in the range 𝒜-𝒵.

-
-
-

Layout

-

Line Breaks

-

Hard line breaks are \\ and \newline.

-

Temml inserts soft line breaks per TeXbook p. 173 if not in display mode and no hard line breaks are employed. They work in Chromium and Firefox, but not in Safari.

-

Reflect

-
 ab\reflectbox{$\frac a b$}
-

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

- - - - - - - - - - - - - - - - - -
FunctionProducesFunctionProduces
\,³∕₁₈ 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 \QED \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

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

To create macros with document-wide scope, use \gdef, \global\let, or define a preamble in one of the Temml rendering options. (Global macros may be disabled for security reasons.)

-

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 has no \par, so \long is ignored.

-

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 \bigtimes
-

cdab \sideset{_a^b}{_c^d}\sum

-

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

-

Binary Operators

- - - - - - - - - - - - - - - - - - - - - - -
+ + \closedvarcap \lhd \sslash
- \closedvarcup \ltimes \threedotcolon
/ / \Cup or \doublecup \minusdot× \times
* * \cup \minusfdots \twocaps
⨿ \amalg \cupovercap \minusrdots \twocups
& \And or \with \curlyveexmoda x\mod a \typecolon
\ast \curlywedge \mp \unlhd
\barcap÷ \div \parr or \upand \unrhd
\barcup \divideontimes± \pm \uplus
\barvee or \Nor  \dotminus x(moda) x \pmod a \Vee
\barwedge or \Nand \dotplusx(a) x \pod a \vee or \lor
mod \bmod \doublebarvee \rhd \veebar or \Xor
\bowtie or
\Join
\doublebarwedge \rightouterjoin \veedot
\bullet \fullouterjoin \rightthreetimes \veedoublebar
\Cap or \doublecap \gtrdot \rtimes \veeonvee
\cap \intercal \setminus \Wedge
\capbarcup \interleave \shuffle \wedge or \land
\capdot \invlazys \smallsetminus \wedgebar
\capovercup \leftthreetimes \smashtimes \wedgedot
\cdot \leftouterjoin \sqcap \wedgedoublebar
· \cdotp \leftmodels \Sqcap \wedgeonwedge
\centerdot. \ldotp \sqcup \wr
\circ \lessdot \Sqcup
-

The texvc extension provides ± \plusmn.

-

Direct Input: + - / ∖ * ⋅ ∘ ± × ÷ ∓ ∔ ∧ ∨ ∩ ∪ ≀ ⊎ ⊓ ⊔ ⋈ ⟕ ⟖ ⟗

-

Geometric Binary Operators

- - - - - - - - - - - - - -
\bigcirc \circledvert \ominus
\blackhourglass \circlehbar \operp
\boxast \concavediamond⊕︎ \oplus
\boxbox \concavediamondtickleft \oslash
\boxcircle \concavediamondtickright \otimes
\boxdot \diamond \Otimes
\boxminus \hourglass \otimeshat
\boxplus \lozengeminus \star
\boxtimes \obar \triangle
\circledast \obslash \triangleminus
\circledcirc \odiv \triangleplus
\circleddash \odot \triangletimes
\circledequal \ogreaterthan \whitesquaretickleft
\circledparallel \olessthan \whitesquaretickright
-

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}
a/b   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 \cosecdim \dim2xyf \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 \infmax \maxsup \sup
arg max \argmaxinj lim \injlimmin \minlim \varinjlim
arg min \argminlim \limplim \plimlim \varliminf
det \detlim inf \liminfPr \Prlim \varlimsup
gcd \gcdlim sup \limsupproj lim \projlimlim \varprojlim
-

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

-

Enclosing Operators

- -
x \sqrt{x}an   a_{\angl n}
x3 \sqrt[3]{x}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𝒫 \pvRes[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 \lessgtr \smile
< < \eqcolon or
  \minuscolon
\lesssim \sqsubset
> >−∷ \Eqcolon or
\minuscoloncolon
\ll \sqsubseteq
: : \eqqcolon \lll \sqsupset
:= :==∷ \Eqqcolon \llless \sqsupseteq
\approx \eqdef< \lt \stareq
\approxeq \eqsim \measeq \Subset
\arceq \eqslantgtr| \mid \subset
\asymp \eqslantless \models \subseteq
\backcong \equiv \multimap \subseteqq
\backepsilon \fallingdotseq \multimapboth \succ
\backsim \frown \multimapinv \succapprox
\backsimeq \ge \origof \succcurlyeq
\between \geq \owns \succeq
\bumpeq \geqq \parallel \succsim
\Bumpeq \geqslant \perp \Supset
\circeq \gg \Perp \supset
\coh \ggg \pitchfork \supseteq
: \colonapprox \gggtr \prec \supseteqq
∷≈ \Colonapprox or
\coloncolonapprox
> \gt \precapprox \thickapprox
: \coloneq or
 \colonminus
\gtrapprox \preccurlyeq \thicksim
∷− \Coloneq or
 \coloncolonminus
\gtreqless \preceq \trianglelefteq
\coloneqq or
 \colonequals
\gtreqqless \precsim \triangleq
\Coloneqq or
 \coloncolonequals
\gtrless \propto \trianglerighteq
: \colonsim \gtrsim \questeq \varpropto
: \Colonsim or
 \coloncolonsim
\imageof:\ratio or
  \vcentcolon
\vartriangle
\cong \in or \isin \risingdotseq \vartriangleleft
\curlyeqprec \incoh \scoh \vartriangleright
\curlyeqsucc \le \shortmid \vdash
\dashv \leq \shortparallel \vDash
\dblcolon or
   \coloncolon
\leqq \sim \Vdash
\doteq \leqslant \simeq VDash
\Doteq \lessapprox \sincoh \Vvdash
\doteqdot \lesseqgtr \smallfrown \veeeq
\eqeq \lesseqqgtr \smallsmile \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 \restriction
\circlearrowright \leftrightarrows \rightarrow
\curvearrowleft \leftrightharpoons \Rightarrow
\curvearrowright \leftrightsquigarrow \rightarrowtail
\dashleftarrow \Lleftarrow \rightharpoondown
\dashrightarrow \longleftarrow \rightharpoonup
\downarrow \Longleftarrow \rightleftarrows
\Downarrow \longleftrightarrow \rightleftharpoons
\downdownarrows \Longleftrightarrow \rightrightarrows
\downharpoonleft \longmapsto \rightsquigarrow
\downharpoonright \longrightarrow \Rrightarrow
\gets \Longrightarrow \Rsh
\hookleftarrow \looparrowleft \searrow
\hookrightarrow \looparrowright \swarrow
\iff \Lsh \to
\impliedby \mapsfrom \twoheadleftarrow
\implies \mapsto \twoheadrightarrow
\leadsto \nearrow \uparrow
\leftarrow \nleftarrow \Uparrow
\Leftarrow \nLeftarrow \updownarrow
\leftarrowtail \nleftrightarrow \Updownarrow
\leftharpoondown \nLeftrightarrow \upharpoonleft
\leftharpoonup \nrightarrow \upharpoonright
\leftleftarrows \nRightarrow \upuparrows
\leftrightarrow \nwarrow

-

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}

𝒜 \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} \triangledown \Bot
" " \triangleleft$ \$ or \text{\textdollar}
\text{\textquotedblright} \triangleright¢ \cent
: \colon \bigtriangledown£ \pounds
\backprime \bigtriangleup£ \mathsterling
\prime \blacktriangle£ \text{\textsterling}
< \text{\textless} \blacktriangledown¥ \yen
> \text{\textgreater} \blacktriangleleft \euro
| \text{\textbar} \blacktriangleright \text{\texteuro}
\text{\textbardbl} \Diamond° \degree
{ \text{\textbraceleft} \lozenge° \text{\textdegree}
} \text{\textbraceright} \blacklozenge \mho
\ \text{\textbackslash} \bigstar \diagdown
\text{\textvisiblespace} \maltese \diagup
\text{\P} or \P \clubsuit \varclubsuit
§ \text{\S} or \S \diamondsuit \vardiamondsuit
© \copyright \heartsuit \varheartsuit
® \circledR \spadesuit \varspadesuit
\circledS \female \male
® \text{\textregistered} \astrosun \sun
\text{\textbullet} \leftmoon \rightmoon
\smiley \Earth \flat
\standardstate \natural \sharp
\permil \QED \lightning
\diameter

-

Symbols in the texvc extension

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

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

-

Units

- - - - - - - - - - -
UnitValueUnitValue
emCSS embp1/72​ inch
exCSS expc12 pt
mu1/18 emdd1238/1157​ pt
pt1/72.27 inchcc14856/1157 pt
mm1 mmnd685/642 pt
cm1 cmnc1370/107​ pt
in1 inchsp1/65536 pt
-

The effect of script level and font size:

- - - - - - -
Unittextstyle
normal size
scriptscripthuge
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-2024 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 46dd4380..00000000 --- a/site/index.html +++ /dev/null @@ -1,231 +0,0 @@ - - - - - - -Temml - Convert TeX to MathML - - - - - - - - - - - - -
- - -

- - TEMML -

- -
-
-

A TeX-to-MathML conversion library in JavaScript.

- -

- -
-
-
Input:
- -
-
-
-
Output:
-
-
- CBdl=μ0(Ienc+ε0ddtSEn^da) -
-
- -
-
-
-
- -     - -   -
-
- -  
- -  
- -   -
-
-
-    -    - -
-
-
-
- -
- -
-
- -
- - - - -
- - diff --git a/site/indexStyles.css b/site/indexStyles.css deleted file mode 100644 index e7d6dbed..00000000 --- a/site/indexStyles.css +++ /dev/null @@ -1,206 +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); -} - -.active-button { - background: #888; -} - -@media (max-width: 799px){ - nav { - width: 90%; - } - article, #input, #output, #title, #copyright { - width: 100%; - } - .ioArea { - width: 93% - } - #why ul { padding-inline-start: 0; } - #wide + label, - #wide { visibility: hidden; } -} - -#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/tests/Arrow note height table.html b/site/tests/Arrow note height table.html deleted file mode 100644 index b66a0115..00000000 --- a/site/tests/Arrow note height table.html +++ /dev/null @@ -1,193 +0,0 @@ - - - - - - Rename OverShift and UnderShift - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
MethodLatin
Modern
Cambria
Math
STIX
TWO
LibertinusAsana
1Current Chromium <mover>AnoteBAnoteBAnoteBAnoteBAnoteB
2Ink height + StretchStackTopShiftUp - AB - - note - - - AB - - note - - - AB - - note - - - AB - - note - - - AB - - note - -
3Baseline + StretchStackTopShiftUp - AB - - note - - - AB - - note - - - AB - - note - - - AB - - note - - - AB - - note - -
4Ink height + StretchStackGapAboveMin - AB - - note - - - AB - - note - - - AB - - note - - - AB - - note - - - AB - - note - -
5Ink height + 0.111em (as per LaTeX) - AB - - note - - - AB - - note - - - AB - - note - - - AB - - note - - - AB - - note - -
\ 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 692a76d8..00000000 --- a/site/tests/LaTeXML-tests.html +++ /dev/null @@ -1,112 +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
61 + \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

- - -
SourceTemml
\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{}.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
LanguageTemml
Arabicتراك يقوم بحفظ كل الكلمات باستخدام صيغة2
BulgarianБългарският език работи ли?2
ČeskyCˇesˇtina v koˊdovaˊnıˊ UTF-8, zˇaˊdnyˊ probleˊm.2
Chinese (Traditional)繁體中文, 漢字測試2
Chinese (Simplified)简体中文,汉字测试2
Croatian(Ako podrzˇava srpski i slovenski mora podrzˇavati i Hrvatski - cˇcˊzˇsˇđ CˇCˊZˇSˇĐ)
EnglishYes indeed, Trac supports English. Fully.2
FrançaisIl 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
HungarianAˊrvıˊztu˝ro˝ tu¨ko¨rfuˊroˊgeˊp2
IcelandicÆvar sagði við o¨mmu sıˊna: Sjaˊðu hvað eˊg er stoˊr!2
Japanese漢字 ひらがな カタカナ ハンカクカナ 日本語試験2
Korean이번에는 한글로 써보겠습니다. 잘 보이나요? 한글2
LatvianLatviesˇu valoda arıˉ straˉdaˉ!2
Lithuanian(Sudalyvaukime 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ącˊ w tę łoˊdzˊ jez˙a lub osiem skrzynˊ fig;Nocna gz˙egz˙oˊłka zawsze dzienną przekuka.)
Portuguese(Eˊ possıˊvel guardar caracteres especias da lıˊngua portuguesa, incluindo o sıˊmbolo da moeda europeˊia , trema u¨, crase aˋ, agudos aˊeˊıˊoˊuˊ,circunflexos aˆeˆoˆ, til a˜o˜, cedilha ç, ordinais ªº, grau °¹²³.)
Russian(Проверка русского языка: кажется работает... И буква "ё" есть...2
Serbian(Podrzˇan, uprkos cˇinjenici da se za njegovopisanje koriste чак два алфабета.)
SlovenianTa suhi sˇkafec pusˇcˇa vodo zˇe od nekdaj!2
Spanish(Esto es un pequen˜o texto en Espan˜ol,donde el veloz murcieˊlago hinduˊ comıˊa cardlllo y kiwi)
SwedishRa¨ven raskar o¨ver isen med luva pa˚.2
ThaiTrac แสดงภาษาไทยได้อย่างถูกต้อง!2
UkrainianПеревірка української мови...2
Urduٹریک اردو بھی سپورٹ کرتا ہے۔2
VietnameseVieˆˊt tieˆˊng Vit cu˜ng đưc.2
-
- - diff --git a/site/tests/environment-tests.html b/site/tests/environment-tests.html deleted file mode 100644 index 95e24a97..00000000 --- a/site/tests/environment-tests.html +++ /dev/null @@ -1,155 +0,0 @@ - - - - - - Environment Tests - - - - - - -

Environments

- - - - - - - - - - -
abcd\begin{matrix}
   a & b \\
   c & d
\end{matrix}
abcd\begin{array}{cc}
   a & b \\
   c & d
\end{array}
ab1.23.5\begin{matrix*}
   a & b \\
   1.2 & 3.5
\end{matrix*}
abcd\begin{darray}{cc}
   a & b \\
   c & d
\end{darray}
(abcd)\begin{pmatrix}
   a & b \\
   c & d
\end{pmatrix}
[abcd]\begin{bmatrix}
   a & b \\
   c & d
\end{bmatrix}
(ab1.23.5)\begin{pmatrix*}[r]
   a & b \\
   1.2 & 3.5
\end{pmatrix*}
[ab1.23.5]\begin{bmatrix*}[r]
   a & b \\
   1.2 & 3.5
\end{bmatrix*}
|abcd|\begin{vmatrix}
   a & b \\
   c & d
\end{vmatrix}
abcd\begin{Vmatrix}
   a & b \\
   c & d
\end{Vmatrix}
|ab1.23.5|\begin{vmatrix}
   a & b \\
   1.2 & 3.5
\end{vmatrix*}
ab1.23.5\begin{Vmatrix}
   a & b \\
   1.2 & 3.5
\end{Vmatrix*}
{ab1.23.5}\begin{Bmatrix}
   a & b \\
   1.2 & 3.5
\end{Bmatrix*}
abcdefghi\begin{array}{c|c:c}
  a & b & c \\ \hline
   d & e & f \\
   \hdashline
   g & h & i
\end{array} 
{ab1.23.5}\begin{Bmatrix*}[r]
   a & b \\
   1.2 & 3.5
\end{Bmatrix*}
abcdefghi\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}⇒
x={aif bcif dx = \begin{dcases}
   a &\text{if } b \\
   c &\text{if } d
\end{dcases}
aif bcif d}\begin{drcases}
   a &\text{if } b \\
  c &\text{if } d
\end{drcases}⇒
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}}
-

- - - - - - -

a=b+c=e+f

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

10x+3y=23x+13y=4

\begin{align}
   10&x+ &3&y = 2 \\
   3&x+&13&y = 4
\end{align}

a=b+c=e+f

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

10x+3y=23x+13y=4

\begin{align*}
   10&x+ &3&y = 2 \\
   3&x+&13&y = 4
\end{align*}
a=be=b+c\begin{gathered}
a=b \\
e=b+c
\end{gathered}\
10x+3y=23x+13y=4\begin{aligned}
   10&x+ &3&y = 2 \\
   3&x+&13&y = 4
\end{aligned}

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}

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}
10x+3y=23x+13y=4\begin{alignedat}{2}
   \10&x+ &3&y = 2\\
   3&x+&13&y = 4 \\
\end{alignedat}\

AaBbcC=D

\begin{CD}
A @>a>> B \\
@VbVV @AAcA \\
C @= D
\end{CD}

unodostres

\begin{multline}
   \rm uno \\
   \rm dos \\
   \rm tres
\end{multline}
- - 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 67ff8a90..00000000 --- a/site/tests/katex-tests.html +++ /dev/null @@ -1,609 +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}
Axx2x22A2xA2Xaccents
-

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=34aligned
-

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=1200

alignedat
-

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+1121/212(xy)0|abcd|]Arrays
\begin{smallmatrix} a & b \\ c & d \end{smallmatrix}
\begin{subarray}{c}a \\ b\end{subarray}
abcd absubarray
-

ArrayMode

-

2fx122fx1x22fx1xn2fx2x12fx222fx2xn2fxnx12fxnx22fxn2

ArrayMode
-

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+bcd/eBaseline
-

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=EF

CD
-

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=01i

DisplayMode
-

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=i

equation
-

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+c

gather
-

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}
abffcdghijklmabffcdghijklmababa0+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/){xxxxx/y(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
-

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}
ABABABABtextAB~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}
sin22lim222222lim22222222lim supxx=?lim infxxlim supxx0<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}}}
xxxxxxxxxxxxxxxxxxxOverUnderline
-

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)a 123b12=c101112d(a+(dphantom
-

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\rvertb} \\
\scriptscriptstyle{^3+[-1][1-1]
1=1(=1)\lvert a\rvertb} \\
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

- - - - - - -
SourceTemml
𝐀𝐚𝟎𝐴𝑎𝑨𝒂𝔅𝔞𝔸𝒜𝐀𝐚𝟎𝐴𝑎𝑨𝒂𝔅𝔞𝔸𝒜
𝖠𝖺𝟢𝗔𝗮𝟬𝘈𝘢𝙰𝚊𝟶𝖠𝖺𝟢𝗔𝗮𝟬𝘈𝘢𝙰𝚊𝟶
\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}
𝖺𝖻𝖼𝟣𝟤𝟥 𝗮𝗯𝗰𝟭𝟮𝟯 𝘢𝘣𝘤123abc123 𝐚𝐛𝐜𝟏𝟐𝟑 𝑎𝑏𝑐123abc123 𝐚𝐛𝐜𝟏𝟐𝟑 𝑎𝑏𝑐123𝐚𝐛𝐜𝟏𝟐𝟑 𝗮𝗯𝗰𝟭𝟮𝟯 𝘢𝘣𝘤123𝑎𝑏𝑐123 𝒂𝒃𝒄123 𝘢𝘣𝘤123TextStacked
-

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 a<b and c<d.𝖿𝗈𝗋 𝖺<𝖻 𝖺𝗇𝖽 𝖼<𝖽.𝖿𝗈𝗋 𝖺<𝖻 𝗮𝗻𝗱 𝖼<𝖽𝖿𝗈𝗋 𝖺<𝖻 𝖺𝗇𝖽 𝖼<𝖽.TextWithMath
-

Unicode

- - - - - -
SourceTemml
\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 9ca695ba..00000000 --- a/site/tests/mhchem-tests.html +++ /dev/null @@ -1,204 +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)

- - - - -
SourceTemml
\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

- - - -
SourceTemml
\ce{H2O}H2O
\ce{Sb2O3}Sb2O3
-

Charges

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

Stoichiometric Numbers

- - - - - - - -
SourceTemml
\ce{2 H2O}2H2O
\ce{2H2O}2H2O
\ce{0.5 H2O}0.5H2O
\ce{1/2 H2O}12H2O
\ce{(1/2) H2O}(1/2)H2O
\ce{$n$ H2O}n H2O
-

Isotopes

- - - - - -
\ce{^{227}_{90}Th+}X90227X290902227227Th+
\ce{^227_90Th+}X90227X290902227227Th+
\ce{^{0}_{-1}n^{-}}X10X211200n
\ce{^0_-1n-}X10X211200n
\ce{H{}^3HO}HX3X2233HO
\ce{H^3HO}HX3X2233HO
-

Reaction Arrows

- - - - - - - - - - - -
SourceTemml
\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

- - - - -
SourceTemml
\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

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

Crystal Systems

- - - -
SourceTemml
\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

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

(Italic) Math

- - - - - -
SourceTemml
\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

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

Upright Text, Escape Parsing

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

Bonds

- - - - - - - - - -
SourceTemml
\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

- - - - -
SourceTemml
\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

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

Unpaired Electrons, Radical Dots

- - - -
SourceTemml
\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

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

Precipitate and Gas

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

Other Symbols and Shortcuts

- - - - - - - - -
SourceTemml
\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-][+ 2H+]
$\underset{\text{amphoteres Hydroxid}}
{\ce{Zn(OH)2 v}}$ <=>[+ 2OH-][+ 2H+]
$\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{Hg}]}
{[\ce{Hg2^2+}]}$}
K=[Hg2+][Hg][Hg22+]
\ce{$K =
\ce{\frac{[Hg^2+][Hg]}{[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

- - - - - - - - - - - - - -
SourceTemml
\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 kJ/mol
\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 1974f64e..00000000 --- a/site/tests/mozilla-tests.html +++ /dev/null @@ -1,108 +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^2

x2y2

ex1TeXbook p128
2_2F_3

2F3

ex2TeXbook p128
3x+y^2\over k+1

x+y2k+1

ex3TeXbook p139
4x+y^{2\over k+1}

x+y2k+1

ex4TeXbook p139
5a\over{b/2}

ab/2

ex5TeXbook p139
6a_0 + \cfrac{1}{a_1 +
\cfrac{1}{a_2 +
\cfrac{1}{a_3 +
\cfrac{1}{a_4}}}}

a0+1a1+1a2+1a3+1a4

ex6TeXbook p142
7a_0+{1\over a_1+{1\over
a_2+{1\over a_3+
{1\over a_4}}}}

a0+1a1+1a2+1a3+1a4

ex7TeXbook p142
8n\choose {k / 2}

(nk/2)

ex8TeXbook p143
9

{p \choose 2} x^2 y^{p-2}

-
  • {1\over{1-x}}
    {1\over{1-x^2}}

(p2)x2yp211x11x2

ex9TeXbook p143
10\sum_{\scriptstyle 0 \le
i \le m \atop \scriptstyle
0 < j < n} P(i, j)

0im0<j<nP(i,j)

ex10TeXbook p145
11x^{2y}

x2y

ex11TeXbook p128
12\sum_{i=1}^p
\sum_{j=1}^q
\sum_{k=1}^r
a_{ij}b_{jk}c_{ki}

i=1pj=1qk=1raijbjkcki

ex12TeXbook p145
13\sqrt{1+\sqrt{1+\sqrt{1+
\sqrt{1+\sqrt{1+\sqrt{1+
\sqrt{1+x}}}}}}}

1+1+1+1+1+1+1+x

ex13TeXbook 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)|2

ex14TeXbook p147
152^{2^{2^x}}

222x

ex15TeXbook p128
16\int_1^x {dt\over t}

1xdtt

ex16TeXbook p168
17\int\!\!\!\int_D dx,dy

Ddxdy

ex17TeXbook p169
18f(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)={1/3if 0x1;2/3if 3x4;0elsewhere.

ex18TeXbook p175
19\overbrace{x +\cdots + x}
^{k \text{ times}}

x++xk times

ex19TeXbook p176
20y_{x^2}

yx2

ex20TeXbook p128
21\sum_{p\text{ prime}}
f(p)=\int_{t>1} f(t)d\pi(t)

p primef(p)=t>1f(t)dπ(t)

ex21TeXbook 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}

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

ex23TeXbook 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|>0

ex24TeXbook p181
25y_{x_2}

yx2

ex25TeXbook p128
26x_{92}^{31415} + \pi

x9231415+π

ex26TeXbook p129
27x_{y^a_b}^{z^c_d}

xybazdc

ex27TeXbook p129
28y_3'''

y3

ex28TeXbook p130
29\lim_{n\rightarrow+\infty}
{\sqrt{2\pi n}\over n!}
\genfrac (){}{}n{e}^n = 1

limn+2πnn!(ne)n=1

ex29

30\det(A) = \sum_{\sigma
\in S_n} \epsilon(\sigma)
\prod_{i=1}^n
a_{i, \sigma_i}

det(A)=σSnϵ(σ)i=1nai,σi

ex30

- - diff --git a/site/tests/wiki-tests.html b/site/tests/wiki-tests.html deleted file mode 100644 index 7837d5dc..00000000 --- a/site/tests/wiki-tests.html +++ /dev/null @@ -1,590 +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,lim infv,lim supw
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,ψ
23dy/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
dy/dx,dy/dx,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
,ı,ȷ,𝕜,,,,,,§,,A˚
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
10710^{30} a^{2+2}
a_{i,j} b_{f'}
1030a2+2ai,jbf
108x_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}
ωαωαωγαωα
112x', 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
116A \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^2

k=1Nk2

120\textstyle \sum_{k=1}^N k^2

k=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_i

i=1Nxi

124\textstyle \prod_{i=1}^N x_i

i=1Nxi

125\coprod_{i=1}^N x_i

i=1Nxi

126\textstyle \coprod_{i=1}^N x_i

i=1Nxi

127\lim_{n \to \infty}x_n

limnxn

128\textstyle \lim_{n \to \infty}x_n

limnxn

129\int\limits_{1}^{3}\frac{e^3/x}{x^2}\, dx

13e3/xx2dx

130\int_{1}^{3}\frac{e^3/x}{x^2}\, dx

13e3/xx2dx

131\textstyle \int\limits_{-N}^{N} e^x dx

NNexdx

132\textstyle \int_{-N}^{N} e^x dx

NNexdx

133\iint\limits_D dx\,dy

Ddxdy

134\iiint\limits_E dx\,dy\,dz

Edxdydz

135\iiiint\limits_F dx\,dy\,dz\,dt

Fdxdydzdt

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_i

i=1nEi

139\bigcup_{i=1}^n E_i

i=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.5

24=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}}} = a

2c+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)
155f(n) = \begin{cases}
n/2, & \text{if }n\text{ is even} \\
3n+1, & \text{if }n\text{ is odd} \end{cases}
f(n)={n/2,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

164f(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 \rceil
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. I know of no servable math font that has glyphs
for regular-weight Greek sans-serif. Consequently, 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
224x_{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
229a \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)
244S_{\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} i

i=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κ11/3,1L0κ1l0
255f(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α
260V = \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
-

The next line tests the length of an extensible arrow. Since Firefox does not
support the minsize attribute, Temml has a workaround. The middle arrow
should be as long at the bar between C & D.

-
266A \rightarrow B \xrightarrow{i} C
\rule[0.3em]{1.75em}{0.05em} D
ABiCD
-

The next line tests the fix for Temml issue #21. Firefox would ordinarily omit
the dot on the i below. It's fixed by a Temml CSS rule, so it renders properly.

-
267\widetilde{U_i}Ui~
-
- - 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 379c5c99..00000000 --- a/src/Lexer.js +++ /dev/null @@ -1,115 +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 - "([!-\\[\\]-\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(tokenRegexString, '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 6b6cae00..00000000 --- a/src/MacroExpander.js +++ /dev/null @@ -1,436 +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 the number of such tokens will be - * returned. This number might be zero or positive. - * - * If not, the return value is `false`, and the next token remains at the - * top of the stack. - * - * In either case, the next token will be on the top of the stack, - * or the stack will be empty (in case of empty expansion - * and no other tokens). - * - * 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 false; - } - 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.length; - } - - /** - * 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 (;;) { - if (this.expandOnce() === false) { // fully expanded - const token = this.stack.pop(); - // The token after \noexpand is interpreted as if its meaning were ‘\relax’ - if (token.treatAsRelax) { - token.text = "\\relax" - } - return token - } - } - - // 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) { - // Expand only expandable tokens - if (this.expandOnce(true) === false) { // fully expanded - const token = this.stack.pop(); - if (token.treatAsRelax) { - // the expansion of \noexpand is the token itself - token.noexpand = false; - token.treatAsRelax = false; - } - output.push(token); - } - } - 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 1d4aeaa1..00000000 --- a/src/Namespace.js +++ /dev/null @@ -1,107 +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 local `set` take constant time, while global - * `set` takes time proportional to the depth of group nesting. - */ - -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 optionally set it globally too. - * Local set() sets the current value and (when appropriate) adds an undo - * operation to the undo stack. Global set() may change the undo - * operation at every level, so takes time linear in their number. - */ - set(name, value, global = false) { - if (global) { - // Global set is equivalent to setting in all groups. Simulate this - // by destroying any undos currently scheduled for this name, - // and adding an undo with the *new* value (in case it later gets - // locally reset within this environment). - for (let i = 0; i < this.undefStack.length; i++) { - delete this.undefStack[i][name]; - } - if (this.undefStack.length > 0) { - this.undefStack[this.undefStack.length - 1][name] = value; - } - } else { - // 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 a0f76736..00000000 --- a/src/Parser.js +++ /dev/null @@ -1,993 +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 ParseError from "./ParseError"; -import { combiningDiacriticalMarksEndRegex } from "./Lexer"; -import { uSubsAndSups, unicodeSubRegEx } from "./unicodeSupOrSub" -import { asciiFromScript } from "./asciiFromScript" -import SourceLocation from "./SourceLocation"; -import { Token } from "./Token"; -import { isDelimiter } from "./functions/delimsizing" - -// Pre-evaluate both modules as unicodeSymbols require String.normalize() -import unicodeAccents from /*preval*/ "./unicodeAccents"; -import unicodeSymbols from /*preval*/ "./unicodeSymbols"; - -const binLeftCancellers = ["bin", "op", "open", "punct", "rel"]; - -/** - * 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", "&"]; - } - - /** - * Fully parse a separate sequence of tokens as a separate job. - * Tokens should be specified in reverse order, as in a MacroDefinition. - */ - subparse(tokens) { - // Save the next token from the current job. - const oldToken = this.nextToken; - this.consume(); - - // Run the new job, terminating it with an excess '}' - this.gullet.pushToken(new Token("}")); - this.gullet.pushTokens(tokens); - const parse = this.parseExpression(false); - this.expect("}"); - - // Restore the next token from the current job. - this.nextToken = oldToken; - - return parse; - } - -/** - * 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 precedence 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. - * - * `breakOnMiddle`: \color, \over, and old styling functions work on an implicit group. - * These groups end just before the usual tokens, but they also - * end just before `\middle`. - */ - parseExpression(breakOnInfix, breakOnTokenText, breakOnMiddle) { - 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 (breakOnMiddle && lex.text === "\\middle") { - 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. - const isSub = unicodeSubRegEx.test(lex.text) - const subsupTokens = []; - subsupTokens.push(new Token(uSubsAndSups[lex.text])) - this.consume() - // Continue fetching tokens to fill out the group. - while (true) { - const token = this.fetch().text - if (!(uSubsAndSups[token])) { break } - if (unicodeSubRegEx.test(token) !== isSub) { break } - subsupTokens.unshift(new Token(uSubsAndSups[token])) - this.consume() - } - // Now create a (sub|super)script. - const body = this.subparse(subsupTokens) - 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 - const isFollowedByDelimiter = (!base || base.type !== "op" && base.type !== "operatorname") - ? undefined - : isDelimiter(this.nextToken.text); - return { - type: "supsub", - mode: this.mode, - base: base, - sup: superscript, - sub: subscript, - isFollowedByDelimiter - } - } - } 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 (true) { - const ch = this.fetch().text - // \ufe0e is the Unicode variation selector to supress emoji. Ignore it. - if (ch === " " || ch === "\u00a0" || ch === "\ufe0e") { - this.consume() - } else { - break - } - } - } - - /** - * 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/ - 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]) { - let group = symbols[this.mode][text].group; - if (group === "bin" && binLeftCancellers.includes(this.prevAtomType)) { - // Change from a binary operator to a unary (prefix) operator - group = "open" - } - 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 { - if (asciiFromScript[text]) { - // Unicode 14 disambiguates chancery from roundhand. - // See https://www.unicode.org/charts/PDF/U1D400.pdf - this.consume() - const nextCode = this.fetch().text.charCodeAt(0) - // mathcal is Temml default. Use mathscript if called for. - const font = nextCode === 0xfe01 ? "mathscr" : "mathcal"; - if (nextCode === 0xfe00 || nextCode === 0xfe01) { this.consume() } - return { - type: "font", - mode: "math", - font, - body: { type: "mathord", mode: "math", loc, text: asciiFromScript[text] } - } - } - // Default ord character. No disambiguation necessary. - s = { - type: group, - mode: this.mode, - loc, - text - }; - } - symbol = s; - } else if (text.charCodeAt(0) >= 0x80) { - // no symbol for e.g. ^ - if (this.settings.strict && 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, - base: symbol - }; - } - } - return symbol; - } -} diff --git a/src/Settings.js b/src/Settings.js deleted file mode 100644 index 6cb51fda..00000000 --- a/src/Settings.js +++ /dev/null @@ -1,54 +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.leqno = utils.deflt(options.leqno, false); // boolean - this.throwOnError = utils.deflt(options.throwOnError, false); // boolean - this.errorColor = utils.deflt(options.errorColor, "#b22222"); // string - this.macros = options.macros || {}; - this.wrap = utils.deflt(options.wrap, "tex") // "tex" | "=" - 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) { - const protocol = utils.protocolFromUrl(context.url); - if (protocol == null) { - return false - } - context.protocol = protocol - } - 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/asciiFromScript.js b/src/asciiFromScript.js deleted file mode 100644 index 8a5e2616..00000000 --- a/src/asciiFromScript.js +++ /dev/null @@ -1,29 +0,0 @@ -// Used for Unicode input of calligraphic and script letters -export const asciiFromScript = Object.freeze({ - "\ud835\udc9c": "A", - "\u212c": "B", - "\ud835\udc9e": "C", - "\ud835\udc9f": "D", - "\u2130": "E", - "\u2131": "F", - "\ud835\udca2": "G", - "\u210B": "H", - "\u2110": "I", - "\ud835\udca5": "J", - "\ud835\udca6": "K", - "\u2112": "L", - "\u2133": "M", - "\ud835\udca9": "N", - "\ud835\udcaa": "O", - "\ud835\udcab": "P", - "\ud835\udcac": "Q", - "\u211B": "R", - "\ud835\udcae": "S", - "\ud835\udcaf": "T", - "\ud835\udcb0": "U", - "\ud835\udcb1": "V", - "\ud835\udcb2": "W", - "\ud835\udcb3": "X", - "\ud835\udcb4": "Y", - "\ud835\udcb5": "Z" -}) diff --git a/src/buildMathML.js b/src/buildMathML.js deleted file mode 100644 index 6f1590e8..00000000 --- a/src/buildMathML.js +++ /dev/null @@ -1,290 +0,0 @@ -/** - * This file converts a parse tree into a corresponding 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 { DocumentFragment } from "./tree" -import setLineBreaks from "./linebreaking" - -/** - * 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); -}; - -export const consolidateText = mrow => { - // If possible, consolidate adjacent elements into a single element. - if (mrow.type !== "mrow" && mrow.type !== "mstyle") { return mrow } - if (mrow.children.length === 0) { return mrow } // empty group, e.g., \text{} - if (!mrow.children[0].attributes || mrow.children[0].type !== "mtext") { return mrow } - const variant = mrow.children[0].attributes.mathvariant || "" - const mtext = new mathMLTree.MathNode( - "mtext", - [new mathMLTree.TextNode(mrow.children[0].children[0].text)] - ) - 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 - } - } - // 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" - } - for (const [key, value] of Object.entries(mrow.attributes)) { - mtext.attributes[key] = value - } - return mtext -} - -const numberRegEx = /^[0-9]$/ -const isDotOrComma = (node, followingNode) => { - return ((node.type === "textord" && node.text === ".") || - (node.type === "atom" && node.text === ",")) && - // Don't consolidate if there is a space after the comma. - node.loc && followingNode.loc && node.loc.end === followingNode.loc.start -} -const consolidateNumbers = expression => { - // Consolidate adjacent numbers. We want to return 1,506.3, - // not 1,506.3 - if (expression.length < 2) { return } - const nums = []; - let inNum = false - // Find adjacent numerals - for (let i = 0; i < expression.length; i++) { - const node = expression[i]; - if (node.type === "textord" && numberRegEx.test(node.text)) { - if (!inNum) { nums.push({ start: i }) } - inNum = true - } else { - if (inNum) { nums[nums.length - 1].end = i - 1 } - inNum = false - } - } - if (inNum) { nums[nums.length - 1].end = expression.length - 1 } - - // Determine if numeral groups are separated by a comma or dot. - for (let i = nums.length - 1; i > 0; i--) { - if (nums[i - 1].end === nums[i].start - 2 && - isDotOrComma(expression[nums[i].start - 1], expression[nums[i].start])) { - // Merge the two groups. - nums[i - 1].end = nums[i].end - nums.splice(i, 1) - } - } - - // Consolidate the number nodes - for (let i = nums.length - 1; i >= 0; i--) { - for (let j = nums[i].start + 1; j <= nums[i].end; j++) { - expression[nums[i].start].text += expression[j].text - } - expression.splice(nums[i].start + 1, nums[i].end - nums[i].start) - // Check if the is followed by a numeric base in a supsub, e.g. the "3" in 123^4 - // If so, merge the first into the base. - if (expression.length > nums[i].start + 1) { - const nextTerm = expression[nums[i].start + 1]; - if (nextTerm.type === "supsub" && nextTerm.base && nextTerm.base.type === "textord" && - numberRegEx.test(nextTerm.base.text)) { - nextTerm.base.text = expression[nums[i].start].text + nextTerm.base.text - expression.splice(nums[i].start, 1) - } - } - } -} - -/** - * 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, semisimple = false) { - if (body.length === 1 && !(body[0] instanceof DocumentFragment)) { - return body[0]; - } else if (!semisimple) { - // Suppress spacing on nodes at both ends of the row. - if (body[0] instanceof MathNode && body[0].type === "mo" && !body[0].attributes.fence) { - body[0].attributes.lspace = "0em" - body[0].attributes.rspace = "0em" - } - const end = body.length - 1 - if (body[end] instanceof MathNode && body[end].type === "mo" && !body[end].attributes.fence) { - body[end].attributes.lspace = "0em" - body[end].attributes.rspace = "0em" - } - } - 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, semisimple = false) { - if (!semisimple && expression.length === 1) { - const group = buildGroup(expression[0], style); - if (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]; - } - - consolidateNumbers(expression) - - 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, semisimple = false) { - return makeRow(buildExpression(expression, style, semisimple), semisimple); -}; - -/** - * 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 = _ => { - return new mathMLTree.MathNode("mtd", [], [], { padding: "0", width: "50%" }) -} - -const taggedExpression = (expression, tag, style, leqno) => { - tag = buildExpressionRow(tag[0].body, style) - tag = consolidateText(tag) - tag.classes.push("tml-tag") - - expression = new mathMLTree.MathNode("mtd", [expression]) - const rowArray = [glue(), expression, glue()] - rowArray[leqno ? 0 : 2].classes.push(leqno ? "tml-left" : "tml-right") - rowArray[leqno ? 0 : 2].children.push(tag) - const mtr = new mathMLTree.MathNode("mtr", rowArray, ["tml-tageqn"]) - const table = new mathMLTree.MathNode("mtable", [mtr]) - table.style.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 wrap = (settings.displayMode || settings.annotate) ? "none" : settings.wrap - - const n1 = expression.length === 0 ? null : expression[0] - let wrapper = expression.length === 1 && tag === null && (n1 instanceof MathNode) - ? expression[0] - : setLineBreaks(expression, wrap, settings.displayMode) - - if (tag) { - wrapper = taggedExpression(wrapper, tag, style, settings.leqno) - } - - 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"); - wrapper = new mathMLTree.MathNode("semantics", [wrapper, annotation]); - } - - const math = 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"); - math.style.display = "block math" // necessary in Chromium. - // Firefox and Safari do not recognize display: "block math". - // Set a class so that the CSS file can set display: block. - math.classes = ["tml-display"] - } - 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 54523ec5..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 this.classes.includes(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, true) - tag.classes = ["tml-tag"] - } else { - // \notag. Return an empty span. - tag = new mathMLTree.MathNode("mtext", [], []) - return tag - } - } else if (group.envClasses.includes("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("mtext", [], []) - return tag - } else { - // AMS automatcally numbered equaton. - // Insert a class so the element can be populated by a CSS counter. - // WebKit will display the CSS counter only inside a span. - tag = new mathMLTree.MathNode("mtext", [new Span(["tml-eqn"])]) - } - 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, - { - cols, // [{ type: string , align: l|c|r|null }] - envClasses, // align(ed|at|edat) | array | cases | cd | small | 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", "\\@ifstar\\envtag@literal\\envtag@paren") - parser.gullet.macros.set("\\envtag@paren", "\\env@tag{{(\\text{#1})}}"); - parser.gullet.macros.set("\\envtag@literal", "\\env@tag{\\text{#1}}") - parser.gullet.macros.set("\\notag", "\\env@notag"); - parser.gullet.macros.set("\\nonumber", "\\env@notag") - } - - // 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, - semisimple: true - }; - row.push(cell); - const next = parser.fetch().text; - if (next === "&") { - if (maxNumCols && row.length === maxNumCols) { - if (envClasses.includes("array")) { - if (parser.settings.strict) { - throw new ParseError("Too few columns " + "specified in the {array} column argument.", - parser.nextToken) - } - } else if (maxNumCols === 2) { - throw new ParseError("The split environment accepts no more than two columns", - 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, - body, - cols, - rowGaps, - hLinesBeforeRow, - envClasses, - addEqnNum, - scriptLevel, - tags, - leqno - }; -} - -// 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 glue = group => { - const glueNode = new mathMLTree.MathNode("mtd", []) - glueNode.style = { padding: "0", width: "50%" } - if (group.envClasses.includes("multline")) { - glueNode.style.width = "7.5%" - } - return glueNode -} - -const mathmlBuilder = function(group, style) { - const tbl = []; - const numRows = group.body.length - const hlines = group.hLinesBeforeRow; - - for (let i = 0; i < numRows; i++) { - const rw = group.body[i]; - const row = []; - const cellLevel = 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(cellLevel))] - ) - - if (group.envClasses.includes("multline")) { - const align = i === 0 ? "left" : i === numRows - 1 ? "right" : "center" - mtd.setAttribute("columnalign", align) - if (align !== "center") { - mtd.classes.push("tml-" + align) - } - } - row.push(mtd) - } - if (group.addEqnNum) { - row.unshift(glue(group)); - row.push(glue(group)); - const tag = getTag(group, style.withLevel(cellLevel), i) - if (group.leqno) { - row[0].children.push(tag) - row[0].classes.push("tml-left") - } else { - row[row.length - 1].children.push(tag) - row[row.length - 1].classes.push("tml-right") - } - } - const mtr = new mathMLTree.MathNode("mtr", row, []) - // Write horizontal rules - if (i === 0 && hlines[0].length > 0) { - if (hlines[0].length === 2) { - mtr.children.forEach(cell => { cell.style.borderTop = "0.15em double" }) - } else { - mtr.children.forEach(cell => { - cell.style.borderTop = hlines[0][0] ? "0.06em dashed" : "0.06em solid" - }) - } - } - if (hlines[i + 1].length > 0) { - if (hlines[i + 1].length === 2) { - mtr.children.forEach(cell => { cell.style.borderBottom = "0.15em double" }) - } else { - mtr.children.forEach(cell => { - cell.style.borderBottom = hlines[i + 1][0] ? "0.06em dashed" : "0.06em solid" - }) - } - } - tbl.push(mtr); - } - - if (group.envClasses.length > 0) { - const pad = group.envClasses.includes("jot") - ? "0.7" // 0.5ex + 0.09em top & bot padding - : group.envClasses.includes("small") - ? "0.35" - : "0.5" // 0.5ex default top & bot padding - const sidePadding = group.envClasses.includes("abut") - ? "0" - : group.envClasses.includes("cases") - ? "0" - : group.envClasses.includes("small") - ? "0.1389" - : group.envClasses.includes("cd") - ? "0.25" - : "0.4" // default side padding - - const numCols = tbl.length === 0 ? 0 : tbl[0].children.length - - const sidePad = (j, hand) => { - if (j === 0 && hand === 0) { return "0" } - if (j === numCols - 1 && hand === 1) { return "0" } - if (group.envClasses[0] !== "align") { return sidePadding } - if (hand === 1) { return "0" } - if (group.addEqnNum) { - return (j % 2) ? "1" : "0" - } else { - return (j % 2) ? "0" : "1" - } - } - - // Padding - for (let i = 0; i < tbl.length; i++) { - for (let j = 0; j < tbl[i].children.length; j++) { - tbl[i].children[j].style.padding = `${pad}ex ${sidePad(j, 1)}em ${pad}ex ${sidePad(j, 0)}em` - } - } - - // Justification - const align = group.envClasses.includes("align") || group.envClasses.includes("alignat") - for (let i = 0; i < tbl.length; i++) { - const row = tbl[i]; - if (align) { - for (let j = 0; j < row.children.length; j++) { - // Chromium does not recognize text-align: left. Use -webkit- - // TODO: Remove -webkit- when Chromium no longer needs it. - row.children[j].classes = ["tml-" + (j % 2 ? "left" : "right")] - } - if (group.addEqnNum) { - const k = group.leqno ? 0 : row.children.length - 1 - row.children[k].classes = ["tml-" + (group.leqno ? "left" : "right")] - } - } - if (row.children.length > 1 && group.envClasses.includes("cases")) { - row.children[1].style.padding = row.children[1].style.padding.replace(/0em$/, "1em") - } - - if (group.envClasses.includes("cases") || group.envClasses.includes("subarray")) { - for (const cell of row.children) { - cell.classes.push("tml-left") - } - } - } - } else { - // Set zero padding on side of the matrix - for (let i = 0; i < tbl.length; i++) { - tbl[i].children[0].style.paddingLeft = "0em" - if (tbl[i].children.length === tbl[0].children.length) { - tbl[i].children[tbl[i].children.length - 1].style.paddingRight = "0em" - } - } - } - - let table = new mathMLTree.MathNode("mtable", tbl) - if (group.scriptLevel === "display") { table.setAttribute("displaystyle", "true") } - - if (group.addEqnNum || group.envClasses.includes("multline")) { - table.style.width = "100%" - } - - // Column separator lines and column alignment - let align = ""; - - if (group.cols && group.cols.length > 0) { - const cols = group.cols; - let prevTypeWasAlign = false; - let iStart = 0; - let iEnd = cols.length; - - while (cols[iStart].type === "separator") { - iStart += 1 - } - while (cols[iEnd - 1].type === "separator") { - iEnd -= 1 - } - - if (cols[0].type === "separator") { - const sep = cols[1].type === "separator" - ? "0.15em double" - : cols[0].separator === "|" - ? "0.06em solid " - : "0.06em dashed " - for (const row of table.children) { - row.children[0].style.borderLeft = sep - } - } - let iCol = group.addEqnNum ? 0 : -1 - for (let i = iStart; i < iEnd; i++) { - if (cols[i].type === "align") { - const colAlign = alignMap[cols[i].align]; - align += colAlign - iCol += 1 - for (const row of table.children) { - if (colAlign.trim() !== "center" && iCol < row.children.length) { - row.children[iCol].classes = ["tml-" + colAlign.trim()] - } - } - 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) { - const sep = cols[i + 1].type === "separator" - ? "0.15em double" - : cols[i].separator === "|" - ? "0.06em solid" - : "0.06em dashed" - for (const row of table.children) { - if (iCol < row.children.length) { - row.children[iCol].style.borderRight = sep - } - } - } - prevTypeWasAlign = false - } - } - if (cols[cols.length - 1].type === "separator") { - const sep = cols[cols.length - 2].type === "separator" - ? "0.15em double" - : cols[cols.length - 1].separator === "|" - ? "0.06em solid" - : "0.06em dashed" - for (const row of table.children) { - row.children[row.children.length - 1].style.borderRight = sep - row.children[row.children.length - 1].style.paddingRight = "0.4em" - } - } - } - if (group.addEqnNum) { - // allow for glue cells on each side - align = "left " + (align.length > 0 ? align : "center ") + "right " - } - if (align) { - // Firefox reads this attribute, not the -webkit-left|right written above. - // TODO: When Chrome no longer needs "-webkit-", use CSS and delete the next line. - table.setAttribute("columnalign", align.trim()) - } - - if (group.envClasses.includes("small")) { - // A small array. Wrap in scriptstyle. - table = new mathMLTree.MathNode("mstyle", [table]) - table.setAttribute("scriptlevel", "1") - } - - return table -}; - -// Convenience function for align, align*, aligned, alignat, alignat*, alignedat, split. -const alignedHandler = function(context, args) { - if (context.envName.indexOf("ed") === -1) { - validateAmsEnvironmentContext(context); - } - const cols = []; - const res = parseArray( - context.parser, - { - cols, - addEqnNum: context.envName === "align" || context.envName === "alignat", - emptySingleRow: true, - envClasses: ["abut", "jot"], // set row spacing & provisional column spacing - 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; - const isAlignedAt = context.envName.indexOf("at") > -1 - if (args[0] && isAlignedAt) { - // alignat environment takes an argument w/ number of columns - let arg0 = "" - for (let i = 0; i < args[0].body.length; i++) { - const textord = assertNodeType(args[0].body[i], "textord") - arg0 += textord.text - } - if (isNaN(arg0)) { - throw new ParseError("The alignat enviroment requires a numeric first argument.") - } - numMaths = Number(arg0) - numCols = numMaths * 2 - } - res.body.forEach(function(row) { - if (isAlignedAt) { - // 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 - }; - } - if (context.envName === "split") { - // Append no more classes - } else if (isAlignedAt) { - res.envClasses.push("alignat") // Sets justification - } else { - res.envClasses[0] = "align" // Sets column spacing & justification - } - 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, - envClasses: ["array"], - 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 = { - envClasses: [], - cols: [] - }; - 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 = []; - } - } - const res = parseArray(context.parser, payload, "text") - res.cols = new Array(res.body[0].length).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 = { type: "small" }; - const res = parseArray(context.parser, payload, "script"); - res.envClasses = ["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, - envClasses: ["small"] - }; - 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: [], - envClasses: ["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. -defineEnvironment({ - type: "array", - names: ["align", "align*", "aligned", "split"], - props: { - numArgs: 0 - }, - handler: alignedHandler, - mathmlBuilder -}); - -// alignat environment is like an align environment, but one must explicitly -// specify maximum number of columns in each row, and can adjust where spacing occurs. -defineEnvironment({ - type: "array", - names: ["alignat", "alignat*", "alignedat"], - props: { - numArgs: 1 - }, - 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 (context.envName !== "gathered") { - validateAmsEnvironmentContext(context); - } - const res = { - cols: [], - envClasses: ["abut", "jot"], - addEqnNum: context.envName === "gather", - emptySingleRow: true, - leqno: context.parser.settings.leqno - }; - return parseArray(context.parser, res, "display"); - }, - 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, - envClasses: ["align"], - 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, - envClasses: ["jot", "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 7bc50d9c..00000000 --- a/src/environments/cd.js +++ /dev/null @@ -1,253 +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], - semisimple: true - }; - 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); - } - body.pop() - - // End row group - parser.gullet.endGroup(); - // End array group defining \\ - parser.gullet.endGroup(); - - return { - type: "array", - mode: "math", - body, - envClasses: ["jot", "cd"], - cols: [], - 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 90c76d2f..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/hbox"; -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/phantom"; -import "./functions/pmb"; -import "./functions/raise"; -import "./functions/ref"; -import "./functions/reflect"; -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/verb"; diff --git a/src/functions/accent.js b/src/functions/accent.js deleted file mode 100644 index f883083a..00000000 --- a/src/functions/accent.js +++ /dev/null @@ -1,152 +0,0 @@ -import defineFunction, { normalizeArgument } from "../defineFunction" -import mathMLTree from "../mathMLTree" -import stretchy from "../stretchy" -import * as mml from "../buildMathML" -import utils from "../utils" - -const smalls = "acegıȷmnopqrsuvwxyzαγεηικμνοπρςστυχωϕ𝐚𝐜𝐞𝐠𝐦𝐧𝐨𝐩𝐪𝐫𝐬𝐮𝐯𝐰𝐱𝐲𝐳" -const talls = "ABCDEFGHIJKLMNOPQRSTUVWXYZbdfhkltΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩβδλζφθψ" - + "𝐀𝐁𝐂𝐃𝐄𝐅𝐆𝐇𝐈𝐉𝐊𝐋𝐌𝐍𝐎𝐏𝐐𝐑𝐒𝐓𝐔𝐕𝐖𝐗𝐘𝐙𝐛𝐝𝐟𝐡𝐤𝐥𝐭" -const longSmalls = new Set(["\\alpha", "\\gamma", "\\delta", "\\epsilon", "\\eta", "\\iota", - "\\kappa", "\\mu", "\\nu", "\\pi", "\\rho", "\\sigma", "\\tau", "\\upsilon", "\\chi", "\\psi", - "\\omega", "\\imath", "\\jmath"]) -const longTalls = new Set(["\\Gamma", "\\Delta", "\\Sigma", "\\Omega", "\\beta", "\\delta", - "\\lambda", "\\theta", "\\psi"]) - -const mathmlBuilder = (group, style) => { - const accentNode = group.isStretchy - ? stretchy.accentNode(group) - : new mathMLTree.MathNode("mo", [mml.makeText(group.label, group.mode)]); - - if (group.label === "\\vec") { - accentNode.style.transform = "scale(0.75) translate(10%, 30%)" - } else { - accentNode.style.mathStyle = "normal" - accentNode.style.mathDepth = "0" - if (needWebkitShift.has(group.label) && utils.isCharacterBox(group.base)) { - let shift = "" - const ch = group.base.text - if (smalls.indexOf(ch) > -1 || longSmalls.has(ch)) { shift = "tml-xshift" } - if (talls.indexOf(ch) > -1 || longTalls.has(ch)) { shift = "tml-capshift" } - if (shift) { accentNode.classes.push(shift) } - } - } - if (!group.isStretchy) { - accentNode.setAttribute("stretchy", "false") - } - - const node = new mathMLTree.MathNode((group.label === "\\c" ? "munder" : "mover"), - [mml.buildGroup(group.base, style), accentNode] - ); - - return node; -}; - -const nonStretchyAccents = new Set([ - "\\acute", - "\\grave", - "\\ddot", - "\\dddot", - "\\ddddot", - "\\tilde", - "\\bar", - "\\breve", - "\\check", - "\\hat", - "\\vec", - "\\dot", - "\\mathring" -]) - -const needWebkitShift = new Set([ - "\\acute", - "\\bar", - "\\breve", - "\\check", - "\\dot", - "\\ddot", - "\\grave", - "\\hat", - "\\mathring", - "\\'", "\\^", "\\~", "\\=", "\\u", "\\.", '\\"', "\\r", "\\H", "\\v" -]) - -// 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 = !nonStretchyAccents.has(context.funcName); - - return { - type: "accent", - mode: context.parser.mode, - label: context.funcName, - isStretchy: isStretchy, - 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, - base: base - }; - }, - mathmlBuilder -}); diff --git a/src/functions/accentunder.js b/src/functions/accentunder.js deleted file mode 100644 index 6519cd40..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.accentNode(group); - accentNode.style["math-depth"] = 0 - const node = new mathMLTree.MathNode("munder", [ - mml.buildGroup(group.base, style), - accentNode - ]); - return node; - } -}); diff --git a/src/functions/arrow.js b/src/functions/arrow.js deleted file mode 100644 index e7866f39..00000000 --- a/src/functions/arrow.js +++ /dev/null @@ -1,230 +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 padding = width => { - const node = new mathMLTree.MathNode("mspace") - node.setAttribute("width", width + "em") - return node -} - -const paddedNode = (group, lspace = 0.3, rspace = 0) => { - if (group == null && rspace === 0) { return padding(lspace) } - const row = group ? [group] : []; - if (lspace !== 0) { row.unshift(padding(lspace)) } - if (rspace > 0) { row.push(padding(rspace)) } - return new mathMLTree.MathNode("mrow", row) -} - -const labelSize = (size, scriptLevel) => Number(size) / emScale(scriptLevel); - -const munderoverNode = (fName, body, below, style) => { - const arrowNode = stretchy.mathMLnode(fName); - // Is this the short part of a mhchem equilibrium arrow? - const isEq = fName.slice(1, 3) === "eq" - const minWidth = fName.charAt(1) === "x" - ? "1.75" // mathtools extensible arrows are ≥ 1.75em long - : fName.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 - // TODO: When Firefox supports minsize, use the next line. - //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 label dimensions accordingly. - const labelStyle = style.withLevel(style.level < 2 ? 2 : 3) - const minArrowWidth = labelSize(minWidth, labelStyle.level) - // The dummyNode will be inside a inside a - // So it will be at scriptlevel 3 - const dummyWidth = labelSize(minWidth, 3) - const emptyLabel = paddedNode(null, minArrowWidth.toFixed(4), 0) - const dummyNode = paddedNode(null, dummyWidth.toFixed(4), 0) - // The arrow is a little longer than the label. Set a spacer length. - const space = labelSize((isEq ? 0 : 0.3), labelStyle.level).toFixed(4) - let upperNode - let lowerNode - - const gotUpper = (body && body.body && - // \hphantom visible content - (body.body.body || body.body.length > 0)) - if (gotUpper) { - let label = mml.buildGroup(body, labelStyle) - label = paddedNode(label, space, space) - // Since Firefox does not support minsize, stack a invisible node - // on top of the label. Its width will serve as a min-width. - // TODO: Refactor this after Firefox supports minsize. - upperNode = new mathMLTree.MathNode("mover", [label, dummyNode]) - } - const gotLower = (below && below.body && - (below.body.body || below.body.length > 0)) - if (gotLower) { - let label = mml.buildGroup(below, labelStyle) - label = paddedNode(label, space, space) - lowerNode = new mathMLTree.MathNode("munder", [label, dummyNode]) - } - - let node - if (!gotUpper && !gotLower) { - node = new mathMLTree.MathNode("mover", [arrowNode, emptyLabel]) - } else if (gotUpper && gotLower) { - node = new mathMLTree.MathNode("munderover", [arrowNode, lowerNode, upperNode]) - } else if (gotUpper) { - node = new mathMLTree.MathNode("mover", [arrowNode, upperNode]) - } else { - node = new mathMLTree.MathNode("munder", [arrowNode, lowerNode]) - } - if (minWidth === "3.0") { node.style.height = "1em" } // CD environment - node.setAttribute("accent", "false") // Necessary for MS Word - 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 5 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 row = [node] - row.unshift(padding(0.2778)) - row.push(padding(0.2778)) - return new mathMLTree.MathNode("mrow", row) - } -}); - -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", - [padding(0.2778), botNode, raiseNode, padding(0.2778)] - ) - } else { - raiseNode.setAttribute("width", (group.name === "\\equilibriumRight" ? "0.5em" : "0")) - wrapper = new mathMLTree.MathNode( - "mpadded", - [padding(0.2778), raiseNode, botArrow, padding(0.2778)] - ) - } - - wrapper.setAttribute("voffset", "-0.18em") - wrapper.setAttribute("height", "-0.18em") - wrapper.setAttribute("depth", "+0.18em") - 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 245226b5..00000000 --- a/src/functions/color.js +++ /dev/null @@ -1,250 +0,0 @@ -import defineFunction, { ordargument } from "../defineFunction" -import mathMLTree 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(Number((num * 255).toFixed(0))) - }) - } - 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) => { - // In LaTeX, color is not supposed to change the spacing of any node. - // So instead of wrapping the group in an , we apply - // the color individually to each node and return a document fragment. - let expr = mml.buildExpression(group.body, style.withColor(group.color)) - expr = expr.map(e => { - e.style.color = group.color - return e - }) - return mathMLTree.newDocumentFragment(expr) -} - -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, breakOnTokenText, 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) - } - - // Parse out the implicit body that should be colored. - const body = parser.parseExpression(true, breakOnTokenText, true) - - 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 6b7e3029..00000000 --- a/src/functions/cr.js +++ /dev/null @@ -1,45 +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: 0, - allowedInText: true - }, - - handler({ parser }, args, optArgs) { - const size = parser.gullet.future().text === "[" ? parser.parseSizeGroup(true) : null; - 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 38e552e7..00000000 --- a/src/functions/def.js +++ /dev/null @@ -1,262 +0,0 @@ -import defineFunction from "../defineFunction"; -import ParseError from "../ParseError"; -import { assertNodeType } from "../parseNode"; - -const globalMap = { - "\\global": "\\global", - "\\long": "\\\\globallong", - "\\\\globallong": "\\\\globallong", - "\\def": "\\gdef", - "\\gdef": "\\gdef", - "\\edef": "\\xdef", - "\\xdef": "\\xdef", - "\\let": "\\\\globallet", - "\\futurelet": "\\\\globalfuture" -} - -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, global) => { - 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, global); -}; - -// -> | -// -> |\global -// -> | -// -> \global|\long|\outer -defineFunction({ - type: "internal", - names: [ - "\\global", - "\\long", - "\\\\globallong" // can’t be entered directly - ], - props: { - numArgs: 0, - allowedInText: true - }, - handler({ parser, funcName }) { - parser.consumeSpaces(); - const token = parser.fetch(); - if (globalMap[token.text]) { - // Temml doesn't have \par, so ignore \long - if (funcName === "\\global" || funcName === "\\\\globallong") { - token.text = globalMap[token.text]; - } - return assertNodeType(parser.parseFunction(), "internal"); - } - throw new ParseError(`Invalid token after macro prefix`, token); - } -}); - -// Basic support for macro definitions: \def, \gdef, \edef, \xdef -// -> -// -> \def|\gdef|\edef|\xdef -// -> -defineFunction({ - type: "internal", - names: ["\\def", "\\gdef", "\\edef", "\\xdef"], - 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" || funcName === "\\xdef") { - tokens = parser.gullet.expandTokens(tokens); - if (tokens.length > parser.gullet.settings.maxExpand) { - throw new ParseError("Too many expansions in an " + funcName); - } - tokens.reverse(); // to fit in with stack order - } - // Final arg is the expansion of the macro - parser.gullet.macros.set( - name, - { tokens, numArgs, delimiters }, - funcName === globalMap[funcName] - ); - return { type: "internal", mode: parser.mode }; - } -}); - -// -> -// -> \futurelet -// | \let -// -> |= -defineFunction({ - type: "internal", - names: [ - "\\let", - "\\\\globallet" // can’t be entered directly - ], - 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, funcName === "\\\\globallet"); - return { type: "internal", mode: parser.mode }; - } -}); - -// ref: https://www.tug.org/TUGboat/tb09-3/tb22bechtolsheim.pdf -defineFunction({ - type: "internal", - names: [ - "\\futurelet", - "\\\\globalfuture" // can’t be entered directly - ], - 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, funcName === "\\\\globalfuture"); - 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 }, - !parser.settings.strict - ) - - return { type: "internal", mode: parser.mode }; - - } -}); diff --git a/src/functions/delimsizing.js b/src/functions/delimsizing.js deleted file mode 100644 index 773df8a4..00000000 --- a/src/functions/delimsizing.js +++ /dev/null @@ -1,325 +0,0 @@ -import defineFunction from "../defineFunction"; -import mathMLTree from "../mathMLTree"; -import ParseError from "../ParseError"; -import { assertNodeType, checkSymbolNodeType } from "../parseNode"; - -import * as mml from "../buildMathML"; -import symbols from "../symbols"; - -// 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", - "⦇", - "\\llparenthesis", - "⦈", - "\\rrparenthesis", - "\\lfloor", - "\\rfloor", - "\u230a", - "\u230b", - "\\lceil", - "\\rceil", - "\u2308", - "\u2309", - "<", - ">", - "\\langle", - "\u27e8", - "\\rangle", - "\u27e9", - "\\lAngle", - "\u27ea", - "\\rAngle", - "\u27eb", - "\\llangle", - "⦉", - "\\rrangle", - "⦊", - "\\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", - "." -]; - -// Export isDelimiter for benefit of parser. -const dels = ["}", "\\left", "\\middle", "\\right"] -export const isDelimiter = str => str.length > 0 && - (delimiters.includes(str) || delimiterSizes[str] || dels.includes(str)) - -// 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) { - const symDelim = checkSymbolNodeType(delim) - if (symDelim && delimiters.includes(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 (["/", "\u2044"].includes(symDelim.text)) { symDelim.text = "\u2215" } - if (["<", "\\lt"].includes(symDelim.text)) { symDelim.text = "⟨" } - if ([">", "\\gt"].includes(symDelim.text)) { symDelim.text = "⟩" } - 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" || group.delim === "\\vert" || - group.delim === "|" || group.delim.indexOf("arrow") > -1) { - // 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) => { - return { - type: "leftright-right", - mode: context.parser.mode, - delim: checkDelimiter(args[0], context).text - }; - } -}); - -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' or `\\middle` - let body = parser.parseExpression(false, null, true) - let nextToken = parser.fetch() - while (nextToken.text === "\\middle") { - // `\middle`, from the ε-TeX package, ends one group and starts another group. - // We had to parse this expression with `breakOnMiddle` enabled in order - // to get TeX-compliant parsing of \over. - // But we do not want, at this point, to end on \middle, so continue - // to parse until we fetch a `\right`. - parser.consume() - const middle = parser.fetch().text - if (!symbols.math[middle]) { - throw new ParseError(`Invalid delimiter '${middle}' after '\\middle'`); - } - checkDelimiter({ type: "atom", mode: "math", text: middle }, { funcName: "\\middle" }) - body.push({ type: "middle", mode: "math", delim: middle }) - parser.consume() - body = body.concat(parser.parseExpression(false, null, true)) - nextToken = parser.fetch() - } - --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 - }; - }, - 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" || group.left.indexOf("arrow") > -1) { - 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" || group.right.indexOf("arrow") > -1) { - rightNode.setAttribute("stretchy", "true") - } - 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"); - if (group.delim.indexOf("arrow") > -1) { - middleNode.setAttribute("stretchy", "true") - } - // The next line is not semantically correct, but - // Chromium fails to stretch if it is not there. - middleNode.setAttribute("form", "prefix") - // 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 7d30d7da..00000000 --- a/src/functions/enclose.js +++ /dev/null @@ -1,217 +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 padding = _ => { - const node = new mathMLTree.MathNode("mspace") - node.setAttribute("width", "3pt") - return node -} - -const mathmlBuilder = (group, style) => { - let node - if (group.label.indexOf("colorbox") > -1 || group.label === "\\boxed") { - // MathML core does not support +width attribute in . - // Firefox does not reliably add side padding. - // Insert - node = new mathMLTree.MathNode("mrow", [ - padding(), - mml.buildGroup(group.body, style), - padding() - ]) - } else { - node = new mathMLTree.MathNode("mrow", [mml.buildGroup(group.body, style)]) - } - switch (group.label) { - case "\\overline": - node.style.padding = "0.1em 0 0 0" - node.style.borderTop = "0.065em solid" - break - case "\\underline": - node.style.padding = "0 0 0.1em 0" - node.style.borderBottom = "0.065em solid" - break - case "\\cancel": - // We can't use an inline background-gradient. It does not work client-side. - // So set a class and put the rule in the external CSS file. - node.classes.push("tml-cancel") - break - case "\\bcancel": - node.classes.push("tml-bcancel") - break - /* - case "\\longdiv": - node.setAttribute("notation", "longdiv"); - break - case "\\phase": - node.setAttribute("notation", "phasorangle"); - break */ - case "\\angl": - node.style.padding = "0.03889em 0.03889em 0 0.03889em" - node.style.borderTop = "0.049em solid" - node.style.borderRight = "0.049em solid" - node.style.marginRight = "0.03889em" - break - case "\\sout": - node.style.backgroundImage = 'linear-gradient(black, black)' - node.style.backgroundRepeat = 'no-repeat' - node.style.backgroundSize = '100% 1.5px' - node.style.backgroundPosition = '0 center' - break - case "\\boxed": - // \newcommand{\boxed}[1]{\fbox{\m@th$\displaystyle#1$}} from amsmath.sty - node.style = { padding: "3pt 0 3pt 0", border: "1px solid" } - node.setAttribute("scriptlevel", "0") - node.setAttribute("displaystyle", "true") - break - case "\\fbox": - node.style = { padding: "3pt", border: "1px solid" } - 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("height", `+${2 * fboxsep}pt`) - //node.setAttribute("voffset", `${fboxsep}pt`) - const style = { padding: "3pt 0 3pt 0" } - - if (group.label === "\\fcolorbox") { - style.border = "0.06em solid " + String(group.borderColor) - } - node.style = style - break - } - case "\\xcancel": - node.classes.push("tml-xcancel") - 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: ["\\angl", "\\cancel", "\\bcancel", "\\xcancel", "\\sout", "\\overline", "\\boxed"], - // , "\\phase", "\\longdiv" - props: { - numArgs: 1 - }, - handler({ parser, funcName }, args) { - const body = args[0]; - return { - type: "enclose", - mode: parser.mode, - label: funcName, - body - }; - }, - mathmlBuilder -}); - -defineFunction({ - type: "enclose", - names: ["\\underline"], - props: { - numArgs: 1, - allowedInText: true - }, - 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 01c72a95..00000000 --- a/src/functions/font.js +++ /dev/null @@ -1,150 +0,0 @@ -import defineFunction, { normalizeArgument } from "../defineFunction" -import * as mml from "../buildMathML" -import mathMLTree from "../mathMLTree" - -const isLongVariableName = (group, font) => { - if (font !== "mathrm" || group.body.type !== "ordgroup" || group.body.body.length === 1) { - return false - } - if (group.body.body[0].type !== "mathord") { return false } - for (let i = 1; i < group.body.body.length; i++) { - const parseNodeType = group.body.body[i].type - if (!(parseNodeType === "mathord" || - (parseNodeType === "textord" && !isNaN(group.body.body[i].text)))) { - return false - } - } - return true -} - -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", "mrow"].includes(mathGroup.type)) { - mathGroup.style.fontWeight = "bold" - return mathGroup - } - // Check if it is possible to consolidate elements into a single element. - if (isLongVariableName(group, font)) { - // This is a \mathrm{…} group. It gets special treatment because symbolsOrd.js - // wraps elements with s to work around a Firefox bug. - const mi = mathGroup.children[0].children[0]; - delete mi.attributes.mathvariant - for (let i = 1; i < mathGroup.children.length; i++) { - mi.children[0].text += mathGroup.children[i].type === "mn" - ? mathGroup.children[i].children[0].text - : mathGroup.children[i].children[0].children[0].text - } - // Wrap in a to prevent the same Firefox bug. - const bogus = new mathMLTree.MathNode("mtext", new mathMLTree.TextNode("\u200b")) - return new mathMLTree.MathNode("mrow", [bogus, mi]) - } - 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 (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", - - // 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, true); - 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 e93133d4..00000000 --- a/src/functions/hbox.js +++ /dev/null @@ -1,30 +0,0 @@ -import defineFunction, { ordargument } from "../defineFunction"; -import { StyleLevel } from "../constants" -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 set scriptlevel to \textstyle -// and 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 newStyle = style.withLevel(StyleLevel.TEXT) - const mrow = mml.buildExpressionRow(group.body, newStyle) - return mml.consolidateText(mrow) - } -}); diff --git a/src/functions/horizBrace.js b/src/functions/horizBrace.js deleted file mode 100644 index 095364f8..00000000 --- a/src/functions/horizBrace.js +++ /dev/null @@ -1,32 +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); - accentNode.style["math-depth"] = 0 - 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 e3a369ef..00000000 --- a/src/functions/kern.js +++ /dev/null @@ -1,75 +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); - if (dimension.number < 0) { - node.style.marginLeft = 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 f0c5500d..00000000 --- a/src/functions/lap.js +++ /dev/null @@ -1,75 +0,0 @@ -// Horizontal overlap functions -import defineFunction, { ordargument } 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 - let strut - if (group.alignment === "llap") { - // We need an invisible strut with the same depth as the group. - // We can't just read the depth, so we use \vphantom methods. - const phantomInner = mml.buildExpression(ordargument(group.body), style); - const phantom = new mathMLTree.MathNode("mphantom", phantomInner); - strut = new mathMLTree.MathNode("mpadded", [phantom]); - strut.setAttribute("width", "0px"); - } - - const inner = mml.buildGroup(group.body, style) - let node - if (group.alignment === "llap") { - inner.style.position = "absolute" - inner.style.right = "0" - inner.style.bottom = `0` // If we could have read the ink depth, it would go here. - node = new mathMLTree.MathNode("mpadded", [strut, inner]) - } else { - node = new mathMLTree.MathNode("mpadded", [inner]) - } - - 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") - if (group.alignment === "llap") { - node.style.position = "relative" - } else { - node.style.display = "flex" - node.style.justifyContent = "center" - } - } - 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 1e7dd332..00000000 --- a/src/functions/mclass.js +++ /dev/null @@ -1,207 +0,0 @@ -import defineFunction, { ordargument } from "../defineFunction"; -import symbols from "../symbols"; -import mathMLTree from "../mathMLTree"; -import utils from "../utils"; - -import * as mml from "../buildMathML"; - -const textAtomTypes = ["text", "textord", "mathord", "atom"] - -const padding = width => { - const node = new mathMLTree.MathNode("mspace") - node.setAttribute("width", width + "em") - return node -} - -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"; - if (node.children.length === 1 && node.children[0].text && node.children[0].text === "∇") { - node.setAttribute("mathvariant", "normal") - } - } else { - node = new mathMLTree.MathNode("mi", inner); - } - } else { - node = new mathMLTree.MathNode("mrow", inner) - 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("mrow", 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 (node.type === "mrow") { - if (doSpacing ) { - if (group.mclass === "mbin") { - // medium space - node.children.unshift(padding(0.2222)) - node.children.push(padding(0.2222)) - } else if (group.mclass === "mrel") { - // thickspace - node.children.unshift(padding(0.2778)) - node.children.push(padding(0.2778)) - } else if (group.mclass === "mpunct") { - node.children.push(padding(0.1667)) - } else if (group.mclass === "minner") { - node.children.unshift(padding(0.0556)) // 1 mu is the most likely option - node.children.push(padding(0.0556)) - } - } - } else { - 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 (symbols[parser.mode][arg.text]) { - mord.text += symbols[parser.mode][arg.text].replace - } else 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 d70662da..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, true); - return inner[0] - } else { - return mml.buildExpressionRow(group.body, style) - } - } -}); diff --git a/src/functions/op.js b/src/functions/op.js deleted file mode 100644 index 772a0da4..00000000 --- a/src/functions/op.js +++ /dev/null @@ -1,346 +0,0 @@ -// Limits, symbols -import defineFunction, { ordargument } from "../defineFunction"; -import * as mathMLTree from "../mathMLTree"; -import * as mml from "../buildMathML"; -import { isDelimiter } 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"]; - -// 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 setSpacing = node => { - // The user wrote a \mathop{…} function. Change spacing from default to OP spacing. - // The most likely spacing for an OP is a thin space per TeXbook p170. - node.attributes.lspace = "0.1667em" - node.attributes.rspace = "0.1667em" -} - -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 (noSuccessor.includes(group.name)) { - node.setAttribute("largeop", "false") - } else { - node.setAttribute("movablelimits", "false") - } - if (group.fromMathOp) { setSpacing(node) } - } else if (group.body) { - // This is an operator with children. Add them. - node = new mathMLTree.MathNode("mo", mml.buildExpression(group.body, style)); - if (group.fromMathOp) { setSpacing(node) } - } 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")]); - const row = [node, operator] - // Set spacing - if (group.needsLeadingSpace) { - const lead = new mathMLTree.MathNode("mspace") - lead.setAttribute("width", "0.1667em") // thin space. - row.unshift(lead) - } - if (!group.isFollowedByDelimiter) { - const trail = new mathMLTree.MathNode("mspace") - trail.setAttribute("width", "0.1667em") // thin space. - row.push(trail) - } - node = new mathMLTree.MathNode("mrow", row) - } - } - - 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", - "\u2a09": "\\bigtimes" -}; - -defineFunction({ - type: "op", - names: [ - "\\coprod", - "\\bigvee", - "\\bigwedge", - "\\biguplus", - "\\bigcap", - "\\bigcup", - "\\intop", - "\\prod", - "\\sum", - "\\bigotimes", - "\\bigoplus", - "\\bigodot", - "\\bigsqcap", - "\\bigsqcup", - "\\bigtimes", - "\\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, - fromMathOp: true, - 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 && ordTypes.includes(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 && ordTypes.includes(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 fd67f24a..00000000 --- a/src/functions/operatorname.js +++ /dev/null @@ -1,141 +0,0 @@ -import defineFunction, { ordargument } from "../defineFunction" -import defineMacro from "../defineMacro"; -import mathMLTree from "../mathMLTree" -import { spaceCharacter } from "./kern" -import { ordTypes } from "./op" -import { isDelimiter } from "./delimsizing" - -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++) { - let node = expression[i] - if (node instanceof mathMLTree.MathNode) { - if (node.type === "mrow" && node.children.length === 1 && - node.children[0] instanceof mathMLTree.MathNode) { - node = node.children[0] - } - 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 - && ["mover", "munder"].includes(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) - if (expression[0].text.length === 1) { - 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")]) - const fragment = [wrapper, operator] - 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. - fragment.unshift(space) - } - if (!group.isFollowedByDelimiter) { - const trail = new mathMLTree.MathNode("mspace") - trail.setAttribute("width", "0.1667em") // thin space. - fragment.push(trail) - } - return mathMLTree.newDocumentFragment(fragment) - } - - 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 - const next = parser.gullet.future().text - return { - type: "operatorname", - mode: parser.mode, - body: ordargument(body), - alwaysHandleSupSub: (funcName === "\\operatornamewithlimits"), - limits: false, - parentIsSupSub: false, - isFollowedByDelimiter: isDelimiter(next), - needsLeadingSpace: prevAtomType.length > 0 && ordTypes.includes(prevAtomType) - }; - }, - mathmlBuilder -}); - -defineMacro("\\operatorname", - "\\@ifstar\\operatornamewithlimits\\operatorname@"); diff --git a/src/functions/ordgroup.js b/src/functions/ordgroup.js deleted file mode 100644 index 9cd85da4..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, group.semisimple); - } -}); 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 ab363165..00000000 --- a/src/functions/pmb.js +++ /dev/null @@ -1,30 +0,0 @@ -import defineFunction, { ordargument } from "../defineFunction" -import { wrapWithMstyle } from "../mathMLTree" -import * as mml from "../buildMathML" - -// In LaTeX, \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 font-weight:bold. - -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", "font-weight:bold") - return node - } -}) diff --git a/src/functions/raise.js b/src/functions/raise.js deleted file mode 100644 index 761d61bc..00000000 --- a/src/functions/raise.js +++ /dev/null @@ -1,68 +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" - -// \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) - // Add padding, which acts to increase height in Chromium. - // TODO: Figure out some way to change height in Firefox w/o breaking Chromium. - if (dy.number > 0) { - node.style.padding = dy.number + dy.unit + " 0 0 0" - } else { - node.style.padding = "0 0 " + Math.abs(dy.number) + dy.unit + " 0" - } - 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/reflect.js b/src/functions/reflect.js deleted file mode 100644 index 54f28eac..00000000 --- a/src/functions/reflect.js +++ /dev/null @@ -1,24 +0,0 @@ -import defineFunction from "../defineFunction" -import * as mml from "../buildMathML" - -defineFunction({ - type: "reflect", - names: ["\\reflectbox"], - props: { - numArgs: 1, - argTypes: ["hbox"], - allowedInText: true - }, - handler({ parser }, args) { - return { - type: "reflect", - mode: parser.mode, - body: args[0] - }; - }, - mathmlBuilder(group, style) { - const node = mml.buildGroup(group.body, style) - node.style.transform = "scaleX(-1)" - 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 cae4c582..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, true); - 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 62f623ae..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, true); - - 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 3e907a7b..00000000 --- a/src/functions/supsub.js +++ /dev/null @@ -1,149 +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 appendSpace = 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 - appendSpace = appendApplyFunction && !group.isFollowedByDelimiter - 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) { - const sup = mml.buildGroup(group.sup, childStyle) - const testNode = sup.type === "mrow" ? sup.children[0] : sup - if ((testNode && testNode.type === "mo" && testNode.classes.includes("tml-prime")) - && group.base && group.base.text && group.base.text === "f") { - // Chromium does not address italic correction on prime. Prevent f′ from overlapping. - testNode.classes.push("prime-pad") - } - children.push(sup) - } - - 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]) - } - if (appendSpace) { - const space = new mathMLTree.MathNode("mspace") - space.setAttribute("width", "0.1667em") // thin space. - node.children.push(space) - } - } 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 69ae4beb..00000000 --- a/src/functions/symbolsOp.js +++ /dev/null @@ -1,53 +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"] - -const arrows = ["\\Rsh", "\\Lsh", "\\restriction"] - -const isArrow = str => { - if (str.length === 1) { - const codePoint = str.codePointAt(0) - return (0x218f < codePoint && codePoint < 0x2200) - } - return str.indexOf("arrow") > -1 || str.indexOf("harpoon") > -1 || arrows.includes(str) -} - -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 (group.family === "rel" && isArrow(group.text)) { - 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 04b0eb90..00000000 --- a/src/functions/symbolsOrd.js +++ /dev/null @@ -1,97 +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)?$/ -const latinRegEx = /[A-Ba-z]/ -const primes = new Set(["\\prime", "\\dprime", "\\trprime", "\\qprime", - "\\backprime", "\\backdprime", "\\backtrprime"]); - -const italicNumber = (text, variant, tag) => { - const mn = new mathMLTree.MathNode(tag, [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("mrow", [node]) - } - } - 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 (numberRegEx.test(group.text)) { - const tag = group.mode === "text" ? "mtext" : "mn" - if (variant === "italic" || variant === "bold-italic") { - return italicNumber(text, variant, tag) - } else { - if (variant !== "normal") { - text.text = text.text.split("").map(c => variantChar(c, variant)).join("") - } - node = new mathMLTree.MathNode(tag, [text]) - } - } else if (group.mode === "text") { - if (variant !== "normal") { - text.text = variantChar(text.text, variant) - } - node = new mathMLTree.MathNode("mtext", [text]) - } else if (primes.has(group.text)) { - node = new mathMLTree.MathNode("mo", [text]) - // TODO: If/when Chromium uses ssty variant for prime, remove the next line. - node.classes.push("tml-prime") - } 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 3da72b78..00000000 --- a/src/functions/text.js +++ /dev/null @@ -1,75 +0,0 @@ -import defineFunction, { ordargument } from "../defineFunction"; -import * as mml from "../buildMathML"; - -// 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 mml.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/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 3f71417f..00000000 --- a/src/linebreaking.js +++ /dev/null @@ -1,138 +0,0 @@ -import mathMLTree from "./mathMLTree" -import { DocumentFragment } from "./tree" - -/* - * 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. - * - * The default is for 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. - * - * An option is for soft line breaks before an "=" sign. That changes the s. - * - * 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. - */ - -const openDelims = "([{⌊⌈⟨⟮⎰⟦⦃" -const closeDelims = ")]}⌋⌉⟩⟯⎱⟦⦄" - -export default function setLineBreaks(expression, wrapMode, isDisplayMode) { - const mtrs = []; - let mrows = []; - let block = []; - let numTopLevelEquals = 0 - let i = 0 - let level = 0 - while (i < expression.length) { - while (expression[i] instanceof DocumentFragment) { - expression.splice(i, 1, ...expression[i].children) // Expand the fragment. - } - const node = expression[i]; - if (node.attributes && node.attributes.linebreak && - node.attributes.linebreak === "newline") { - // A hard line break. Create a for the current block. - if (block.length > 0) { - mrows.push(new mathMLTree.MathNode("mrow", block)) - } - mrows.push(node) - block = []; - const mtd = new mathMLTree.MathNode("mtd", mrows) - mtd.style.textAlign = "left" - mtrs.push(new mathMLTree.MathNode("mtr", [mtd])) - mrows = []; - i += 1 - continue - } - block.push(node); - if (node.type && node.type === "mo" && node.children.length === 1 && - !Object.hasOwn(node.attributes, "movablelimits")) { - const ch = node.children[0].text - if (openDelims.indexOf(ch) > -1) { - level += 1 - } else if (closeDelims.indexOf(ch) > -1) { - level -= 1 - } else if (level === 0 && wrapMode === "=" && ch === "=") { - numTopLevelEquals += 1 - if (numTopLevelEquals > 1) { - block.pop() - // Start a new block. (Insert a soft linebreak.) - const element = new mathMLTree.MathNode("mrow", block) - mrows.push(element) - block = [node]; - } - } else if (level === 0 && wrapMode === "tex" && ch !== "∇") { - // 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("mrow", block) - mrows.push(element) - block = []; - } - } - } - i += 1 - } - if (block.length > 0) { - const element = new mathMLTree.MathNode("mrow", block) - mrows.push(element) - } - if (mtrs.length > 0) { - const mtd = new mathMLTree.MathNode("mtd", mrows) - mtd.style.textAlign = "left" - 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 5e4cc61e..00000000 --- a/src/macros.js +++ /dev/null @@ -1,705 +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 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}}`; -}); - -function recreateArgStr(context) { - // Recreate the macro's original argument string from the array of parse tokens. - const tokens = context.consumeArgs(1)[0]; - let str = "" - let expectedLoc = tokens[tokens.length - 1].loc.start - for (let i = tokens.length - 1; i >= 0; i--) { - const actualLoc = tokens[i].loc.start - if (actualLoc > expectedLoc) { - // context.consumeArgs has eaten a space. - str += " " - expectedLoc = actualLoc; - } - str += tokens[i].text - expectedLoc += tokens[i].text.length - } - return str -} - -// The Latin Modern font renders at the wrong vertical alignment. -// This macro provides a better rendering. -defineMacro("\\surd", '\\sqrt{\\vphantom{|}}') - -// See comment for \oplus in symbols.js. -defineMacro("\u2295", "\\oplus") - -// 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", "{\\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}"); - -// \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", - "\\bigtimes": "\\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 (["bin", "rel"].includes(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"); - -defineMacro("\\AA", "\\TextOrMath{\\Angstrom}{\\mathring{A}}\\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}"); - -////////////////////////////////////////////////////////////////////// -// MnSymbol.sty - -defineMacro("\\leftmodels", "\\mathop{\\reflectbox{$\\models$}}") - -////////////////////////////////////////////////////////////////////// -// 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"); -// A helper for \Braket and \Set -const replaceVert = (argStr, match) => { - const ch = match[0] === "|" ? "\\vert" : "\\Vert" - const replaceStr = `}\\,\\middle${ch}\\,{` - return argStr.slice(0, match.index) + replaceStr + argStr.slice(match.index + match[0].length) -} -defineMacro("\\Braket", function(context) { - let argStr = recreateArgStr(context) - const regEx = /\|\||\||\\\|/g - let match - while ((match = regEx.exec(argStr)) !== null) { - argStr = replaceVert(argStr, match) - } - return "\\left\\langle{" + argStr + "}\\right\\rangle" -}); -defineMacro("\\Set", function(context) { - let argStr = recreateArgStr(context) - const match = /\|\||\||\\\|/.exec(argStr) - if (match) { - argStr = replaceVert(argStr, match) - } - return "\\left\\{\\:{" + argStr + "}\\:\\right\\}" -}); -defineMacro("\\set", function(context) { - const argStr = recreateArgStr(context) - return "\\{{" + argStr.replace(/\|/, "}\\mid{") + "}\\}" -}); - -////////////////////////////////////////////////////////////////////// -// 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 d46460f2..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 itself). - */ - 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 e66d3d9e..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, - * 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.10.25"; - -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 21c1cbef..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 0x1D317 }, - "italic": ch => { return 0x1D351 }, - // \boldsymbol actually returns upright bold for upperCaseGreek - "bold-italic": ch => { return 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 0x1D3C5 }, - "sans-serif-bold": ch => { return 0x1D3C5 }, - "sans-serif-italic": ch => { return 0 }, - "sans-serif-bold-italic": ch => { return 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) - ? "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 87251bf9..00000000 --- a/src/stretchy.js +++ /dev/null @@ -1,113 +0,0 @@ -/** - * This file provides support for building horizontal stretchy elements. - */ - -import mathMLTree from "./mathMLTree" - -// TODO: Remove when Chromium stretches \widetilde & \widehat -const estimatedWidth = node => { - let width = 0 - if (node.body) { - for (const item of node.body) { - width += estimatedWidth(item) - } - } else if (node.type === "supsub") { - width += estimatedWidth(node.base) - if (node.sub) { width += 0.7 * estimatedWidth(node.sub) } - if (node.sup) { width += 0.7 * estimatedWidth(node.sup) } - } else if (node.type === "mathord" || node.type === "textord") { - for (const ch of node.text.split('')) { - const codePoint = ch.codePointAt(0) - if ((0x60 < codePoint && codePoint < 0x7B) || (0x03B0 < codePoint && codePoint < 0x3CA)) { - width += 0.56 // lower case latin or greek. Use advance width of letter n - } else if (0x2F < codePoint && codePoint < 0x3A) { - width += 0.50 // numerals. - } else { - width += 0.92 // advance width of letter M - } - } - } else { - width += 1.0 - } - return width -} - -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 -} - -const crookedWides = ["\\widetilde", "\\widehat", "\\widecheck", "\\utilde"] - -// TODO: Remove when Chromium stretches \widetilde & \widehat -const accentNode = (group) => { - const mo = mathMLnode(group.label) - if (crookedWides.includes(group.label)) { - const width = estimatedWidth(group.base) - if (1 < width && width < 1.6) { - mo.classes.push("tml-crooked-2") - } else if (1.6 <= width && width < 2.5) { - mo.classes.push("tml-crooked-3") - } else if (2.5 <= width) { - mo.classes.push("tml-crooked-4") - } - } - return mo -} - -export default { - mathMLnode, - accentNode -} diff --git a/src/symbols.js b/src/symbols.js deleted file mode 100644 index b15a6012..00000000 --- a/src/symbols.js +++ /dev/null @@ -1,1071 +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, "\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"); -// unicodemath -defineSymbol(math, rel, "\u2a75", "\\eqeq", true); -defineSymbol(math, rel, "\u2a76", "\\eqeqeq", true); -// 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); -// ∇ is actually a unary operator, not binary. But this works. -defineSymbol(math, bin, "\u2207", "\\nabla", true); -defineSymbol(math, textord, "\u266d", "\\flat", true); -defineSymbol(math, textord, "\u2113", "\\ell", true); -defineSymbol(math, textord, "\u266e", "\\natural", true); -defineSymbol(math, textord, "Å", "\\Angstrom", true); -defineSymbol(text, textord, "Å", "\\Angstrom", 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 -defineSymbol(math, bin, "\u2AFD", "\\sslash", true); // from stmaryrd - -// 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, "\u21a4", "\\mapsfrom", 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, "\u220E", "\\QED", true); -defineSymbol(math, mathord, "\u2030", "\\permil", true); -defineSymbol(text, textord, "\u2030", "\\permil"); -defineSymbol(math, mathord, "\u2609", "\\astrosun", true); -defineSymbol(math, mathord, "\u263c", "\\sun", true); -defineSymbol(math, mathord, "\u263e", "\\leftmoon", true); -defineSymbol(math, mathord, "\u263d", "\\rightmoon", true); -defineSymbol(math, mathord, "\u2295", "\\Earth"); - -// 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, "\u2036", "\\backdprime"); -defineSymbol(math, textord, "\u2037", "\\backtrprime"); -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, "\u22ab", "\\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, "\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); -defineSymbol(math, bin, "\u22c8", "\\bowtie", true); -defineSymbol(math, bin, "\u22c8", "\\Join"); -defineSymbol(math, bin, "\u27d5", "\\leftouterjoin", true); -defineSymbol(math, bin, "\u27d6", "\\rightouterjoin", true); -defineSymbol(math, bin, "\u27d7", "\\fullouterjoin", true); - -// stix Binary Operators -defineSymbol(math, bin, "\u2238", "\\dotminus", true); -defineSymbol(math, bin, "\u27D1", "\\wedgedot", true); -defineSymbol(math, bin, "\u27C7", "\\veedot", true); -defineSymbol(math, bin, "\u2A62", "\\doublebarvee", true); -defineSymbol(math, bin, "\u2A63", "\\veedoublebar", true) -defineSymbol(math, bin, "\u2A5F", "\\wedgebar", true) -defineSymbol(math, bin, "\u2A60", "\\wedgedoublebar", true) -defineSymbol(math, bin, "\u2A54", "\\Vee", true) -defineSymbol(math, bin, "\u2A53", "\\Wedge", true) -defineSymbol(math, bin, "\u2A43", "\\barcap", true) -defineSymbol(math, bin, "\u2A42", "\\barcup", true) -defineSymbol(math, bin, "\u2A48", "\\capbarcup", true) -defineSymbol(math, bin, "\u2A40", "\\capdot", true) -defineSymbol(math, bin, "\u2A47", "\\capovercup", true) -defineSymbol(math, bin, "\u2A46", "\\cupovercap", true) -defineSymbol(math, bin, "\u2A4D", "\\closedvarcap", true) -defineSymbol(math, bin, "\u2A4C", "\\closedvarcup", true) -defineSymbol(math, bin, "\u2A2A", "\\minusdot", true) -defineSymbol(math, bin, "\u2A2B", "\\minusfdots", true) -defineSymbol(math, bin, "\u2A2C", "\\minusrdots", true) -defineSymbol(math, bin, "\u22BB", "\\Xor", true) -defineSymbol(math, bin, "\u22BC", "\\Nand", true) -defineSymbol(math, bin, "\u22BD", "\\Nor", true) -defineSymbol(math, bin, "\u22BD", "\\barvee") -defineSymbol(math, bin, "\u2AF4", "\\interleave", true) -defineSymbol(math, bin, "\u29E2", "\\shuffle", true) -defineSymbol(math, bin, "\u2AF6", "\\threedotcolon", true) -defineSymbol(math, bin, "\u2982", "\\typecolon", true) -defineSymbol(math, bin, "\u223E", "\\invlazys", true) -defineSymbol(math, bin, "\u2A4B", "\\twocaps", true) -defineSymbol(math, bin, "\u2A4A", "\\twocups", true) -defineSymbol(math, bin, "\u2A4E", "\\Sqcap", true) -defineSymbol(math, bin, "\u2A4F", "\\Sqcup", true) -defineSymbol(math, bin, "\u2A56", "\\veeonvee", true) -defineSymbol(math, bin, "\u2A55", "\\wedgeonwedge", true) -defineSymbol(math, bin, "\u29D7", "\\blackhourglass", true) -defineSymbol(math, bin, "\u29C6", "\\boxast", true) -defineSymbol(math, bin, "\u29C8", "\\boxbox", true) -defineSymbol(math, bin, "\u29C7", "\\boxcircle", true) -defineSymbol(math, bin, "\u229C", "\\circledequal", true) -defineSymbol(math, bin, "\u29B7", "\\circledparallel", true) -defineSymbol(math, bin, "\u29B6", "\\circledvert", true) -defineSymbol(math, bin, "\u29B5", "\\circlehbar", true) -defineSymbol(math, bin, "\u27E1", "\\concavediamond", true) -defineSymbol(math, bin, "\u27E2", "\\concavediamondtickleft", true) -defineSymbol(math, bin, "\u27E3", "\\concavediamondtickright", true) -defineSymbol(math, bin, "\u22C4", "\\diamond", true) -defineSymbol(math, bin, "\u29D6", "\\hourglass", true) -defineSymbol(math, bin, "\u27E0", "\\lozengeminus", true) -defineSymbol(math, bin, "\u233D", "\\obar", true) -defineSymbol(math, bin, "\u29B8", "\\obslash", true) -defineSymbol(math, bin, "\u2A38", "\\odiv", true) -defineSymbol(math, bin, "\u29C1", "\\ogreaterthan", true) -defineSymbol(math, bin, "\u29C0", "\\olessthan", true) -defineSymbol(math, bin, "\u29B9", "\\operp", true) -defineSymbol(math, bin, "\u2A37", "\\Otimes", true) -defineSymbol(math, bin, "\u2A36", "\\otimeshat", true) -defineSymbol(math, bin, "\u22C6", "\\star", true) -defineSymbol(math, bin, "\u25B3", "\\triangle", true) -defineSymbol(math, bin, "\u2A3A", "\\triangleminus", true) -defineSymbol(math, bin, "\u2A39", "\\triangleplus", true) -defineSymbol(math, bin, "\u2A3B", "\\triangletimes", true) -defineSymbol(math, bin, "\u27E4", "\\whitesquaretickleft", true) -defineSymbol(math, bin, "\u27E5", "\\whitesquaretickright", true) -defineSymbol(math, bin, "\u2A33", "\\smashtimes", 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, "¢", "\\cent"); -defineSymbol(text, textord, "¢", "\\cent"); -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, "\u2033", "\\dprime"); -defineSymbol(math, textord, "\u2034", "\\trprime"); -defineSymbol(math, textord, "\u2057", "\\qprime"); -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, "\u2300", "\\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", "/", true); -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, "\u27ea", "\\lAngle", true); -defineSymbol(math, open, "\u2989", "\\llangle", 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, "\u27eb", "\\rAngle", true); -defineSymbol(math, close, "\u298a", "\\rrangle", 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"); -defineSymbol(math, bin, "\u22bb", "\\veebar"); -defineSymbol(math, bin, "\u2299", "\\odot", true); -// Firefox turns ⊕ into an emoji. So append \uFE0E. Define Unicode character in macros, not here. -defineSymbol(math, bin, "\u2295\uFE0E", "\\oplus"); -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, "\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(math, open, "⦇", "\\llparenthesis", true); -defineSymbol(math, close, "⦈", "\\rrparenthesis", 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, "\u2a09", "\\bigtimes"); -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, "\u2026", "\\dddot"); -defineSymbol(math, accent, "\u2026\u002e", "\\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, "\u2192", "\\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"); -defineSymbol(math, textord, "\u2300", "\\diameter", true); -defineSymbol(text, textord, "\u2300", "\\diameter"); - -// 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 ca1c82c6..00000000 --- a/src/tree.js +++ /dev/null @@ -1,50 +0,0 @@ -/** - * 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 this.classes.includes(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/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 e763c09f..00000000 --- a/src/utils.js +++ /dev/null @@ -1,127 +0,0 @@ -// -/** - * This file contains a list of utility functions which are useful in other - * files. - */ - -/** - * 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), or `null` if URL has invalid protocol - * (so should be outright rejected). - */ -export const protocolFromUrl = function(url) { - // Check for possible leading protocol. - // https://url.spec.whatwg.org/#url-parsing strips leading whitespace - // (\x00) or C0 control (\x00-\x1F) characters. - // eslint-disable-next-line no-control-regex - const protocol = /^[\x00-\x20]*([^\\/#?]*?)(:|�*58|�*3a|&colon)/i.exec(url); - if (!protocol) { - return "_relative"; - } - // Reject weird colons - if (protocol[2] !== ":") { - return null; - } - // Reject invalid characters in scheme according to - // https://datatracker.ietf.org/doc/html/rfc3986#section-3.1 - if (!/^[a-zA-Z][a-zA-Z0-9+\-.]*$/.test(protocol[1])) { - return null; - } - // Lowercase the protocol - return protocol[1].toLowerCase(); -}; - -/** - * 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); -}; - -export default { - deflt, - escape, - hyphenate, - getBaseElem, - isCharacterBox, - protocolFromUrl, - round -}; diff --git a/src/variant.js b/src/variant.js deleted file mode 100644 index 90225803..00000000 --- a/src/variant.js +++ /dev/null @@ -1,100 +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" -} - -/** - * 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" - 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.d.ts b/temml.d.ts deleted file mode 100644 index 9660db12..00000000 --- a/temml.d.ts +++ /dev/null @@ -1,60 +0,0 @@ -export interface Options { - displayMode?: boolean; - annotate?: boolean; - leqno?: boolean; - throwOnError?: boolean; - errorColor?: string; - macros?: Record; - wrap?: "tex" | "=" | "none"; - xml?: boolean; - colorIsTextColor?: boolean; - strict?: boolean; - trust?: boolean | ((context: any) => boolean); - maxSize?: [number, number]; - maxExpand?: number; -} - -export function render( - expression: string, - baseNode: HTMLElement, - options?: Options, -): void; - -export function renderToString(expression: string, options?: Options): string; - -export function generateParseTree(expression: string, options?: Options): any; - -export function definePreamble(expression: string, options?: Options): any; - -export function renderToMathMLTree(expression: string, options?: Options): any; - -declare function postProcess(block: any): void; -declare function defineMacro(name: string, body: any): void; -declare function defineSymbol( - mode: string, - group: string, - replace: string, - name: string, - acceptUnicodeChar: boolean, -): void; -declare class ParseError { - constructor( - message: string, // The error message - token: any, // An object providing position information - ); -} - -declare const Temml: { - version: string; - render: typeof render; - renderToString: typeof renderToString; - postProcess: typeof postProcess; - ParseError: typeof ParseError; - definePreamble: typeof definePreamble; - __parse: typeof generateParseTree; - __renderToMathMLTree: typeof renderToMathMLTree; - __defineSymbol: typeof defineSymbol; - __defineMacro: typeof defineMacro; -}; - -export default Temml; diff --git a/temml.js b/temml.js deleted file mode 100644 index 9e2c4b60..00000000 --- a/temml.js +++ /dev/null @@ -1,187 +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, TextNode } from "./src/domTree"; -import { defineSymbol } from "./src/symbols"; -import defineMacro from "./src/defineMacro"; -import { postProcess, version } from "./src/postProcess"; - -/** - * @type {import('./temml').render} - * Parse and build an expression, and place that expression in the DOM node - * given. - */ -let render = function(expression, baseNode, options = {}) { - baseNode.textContent = ""; - const alreadyInMathElement = baseNode.tagName.toLowerCase() === "math" - if (alreadyInMathElement) { options.wrap = "none" } - const math = renderToMathMLTree(expression, options) - if (alreadyInMathElement) { - // The element already exists. Populate it. - baseNode.textContent = "" - math.children.forEach(e => { baseNode.appendChild(e.toNode()) }) - } else if (math.children.length > 1) { - 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."); - }; - } -} - -/** - * @type {import('./temml').renderToString} - * Parse and build an expression, and return the markup for that. - */ -const renderToString = function(expression, options) { - const markup = renderToMathMLTree(expression, options).toMarkup(); - return markup; -}; - -/** - * @type {import('./temml').generateParseTree} - * Parse an expression and return the parse tree. - */ -const generateParseTree = function(expression, options) { - const settings = new Settings(options); - return parseTree(expression, settings); -}; - -/** - * @type {import('./temml').definePreamble} - * 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; -}; - -/** - * @type {import('./temml').renderToMathMLTree} - * 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); - } -}; - -/** @type {import('./temml').default} */ -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 06db29d6..00000000 --- a/test/Investigate.html +++ /dev/null @@ -1,187 +0,0 @@ - - - - - - Investigate - - - - - - -

- -

- -

- ( ( x + y ) )
( ( x ) ) -

- -

- - - - - - ⊕︎ - - - - - - - - - - - - - - -

- -

- - - θ - ^ - - -

-

- - - A - - B - - - - - - - - i - - - - - - - C - - - - D - - -

- - - - -

AaBbcC=D

- - -

unodostres

- -

-

-
- - - f - c - - - -
-
-

- -

-

- - - x - - - -
-

- - -

- - - - - 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 c6dea4f5..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/environment-tests.md b/test/environment-tests.md deleted file mode 100644 index 5f1af7b1..00000000 --- a/test/environment-tests.md +++ /dev/null @@ -1,143 +0,0 @@ - - - - - - Environment Tests - - - - - - - - -## 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{matrix*}[r] | `\begin{matrix*}`\ | $\begin{array}{cc} | `\begin{darray}{cc}`\ | -| a & b \\ |    `a & b \\`\ | a & b \\ |    `a & b \\`\ | -| 1.2 & 3.5 |    `1.2 & 3.5`\ | c & d |    `c & d`\ | -| \end{matrix*}$ | `\end{matrix*}` | \end{array}$ | `\end{darray}` | -+-----------------------+----------------------------+----------------------------+------------------------------+ -| $\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{bmatrix}` | -+-----------------------+----------------------------+----------------------------+------------------------------+ -| $\begin{pmatrix*}[r] | `\begin{pmatrix*}[r]`\ | $\begin{bmatrix*}[r] | `\begin{bmatrix*}[r]`\ | -| a & b \\ |    `a & b \\`\ | a & b \\ |    `a & b \\`\ | -| 1.2 & 3.5 |    `1.2 & 3.5`\ | 1.2 & 3.5 |    `1.2 & 3.5`\ | -| \end{pmatrix*}$ | `\end{pmatrix*}` | \end{bmatrix*}$ | `\end{bmatrix*}` | -+-----------------------+----------------------------+----------------------------+------------------------------+ -| $\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{vmatrix*}[r] | `\begin{vmatrix}`\ | $\begin{Vmatrix*}[r] | `\begin{Vmatrix}`\ | -| a & b \\ |    `a & b \\`\ | a & b \\ |    `a & b \\`\ | -| 1.2 & 3.5 |    `1.2 & 3.5`\ | 1.2 & 3.5 |    `1.2 & 3.5`\ | -| \end{vmatrix*}$ | `\end{vmatrix*}` | \end{Vmatrix*}$ | `\end{Vmatrix*}` | -+-----------------------+----------------------------+----------------------------+------------------------------+ -| $\begin{Bmatrix} | `\begin{Bmatrix}`\ | $\begin{array}{c|c:c} | `\begin{array}{c|c:c}`\ | -| a & b \\ |    `a & b \\`\ | a & b & c \\ \hline |   `a & b & c \\ \hline`\ | -| 1.2 & 3.5 |    `1.2 & 3.5`\ | d & e & f \\ \hdashline |    `d & e & f \\`\ | -| \end{Bmatrix}$ | `\end{Bmatrix*}` | g & h & i |    `\hdashline`\ | -| | | \end{array}$ |    `g & h & i`\ | -| | | | `\end{array}`  | -+-----------------------+----------------------------+----------------------------+------------------------------+ -| $\begin{Bmatrix*}[r] | `\begin{Bmatrix*}[r]`\ | $\begin{array}{c|c:c} | `\begin{array}{c|c:c}`\ | -| a & b \\ |    `a & b \\`\ | a & b & c \\ \hline |   `a & b & c \\ \hline`\ | -| 1.2 & 3.5 |    `1.2 & 3.5`\ | d & e & f \\ \hdashline |    `d & e & f \\`\ | -| \end{Bmatrix*}$ | `\end{Bmatrix*}` | 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}⇒` | -+-----------------------+----------------------------+----------------------------+------------------------------+ -| $x = \begin{dcases} | `x = \begin{dcases}`\ | $\begin{drcases} | `\begin{drcases}`\ | -| 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{dcases}$ | `\end{dcases}` | \end{drcases}⇒$ | `\end{drcases}⇒` | -+-----------------------+----------------------------+----------------------------+------------------------------+ -| $\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\\ |    `0a>> B \\`\ | 10&x+ &3&y = 2 \\ |    `\10&x+ &3&y = 2\\`\ | -| A @>a>> B \\ | `@VbVV @AAcA \\`\ | 3&x+&13&y = 4 |    `3&x+&13&y = 4 \\`\ | -| @VbVV @AAcA\\ | `C @= D`\ | \end{alignedat}$ | `\end{alignedat}`\ | -| C @= D | `\end{CD}` | | | -| \end{CD} | | | | -| $$ | | | | -+-------------------+------------------------+------------------------+---------------------------+ -| $$ | `\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} | | -| $$ | | $$ | | -+-------------------+------------------------+------------------------+---------------------------+ - - - - diff --git a/test/katex-tests.md b/test/katex-tests.md deleted file mode 100644 index 6e3ffd24..00000000 --- a/test/katex-tests.md +++ /dev/null @@ -1,1146 +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 - -#### 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 - -#### 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 aaffc0ba..00000000 --- a/test/main.css +++ /dev/null @@ -1,16 +0,0 @@ -body { - margin: 0; - padding: 0; - font-size: 24px; -} - -.math { - font-size: 24px; -} - -#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 c80a5700..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 f941cb1d..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!} | | | -| | \genfrac (){}{}n{e}^n = 1 | \genfrac (){}{}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 f3542668..00000000 --- a/test/repl.html +++ /dev/null @@ -1,60 +0,0 @@ - - - - - Temml REPL - - - - - - - - - - - - - - - -
- - diff --git a/test/temml.js b/test/temml.js deleted file mode 100644 index 56aeb153..00000000 --- a/test/temml.js +++ /dev/null @@ -1,11634 +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. - */ - - /** - * 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), or `null` if URL has invalid protocol - * (so should be outright rejected). - */ - const protocolFromUrl = function(url) { - // Check for possible leading protocol. - // https://url.spec.whatwg.org/#url-parsing strips leading whitespace - // (\x00) or C0 control (\x00-\x1F) characters. - // eslint-disable-next-line no-control-regex - const protocol = /^[\x00-\x20]*([^\\/#?]*?)(:|�*58|�*3a|&colon)/i.exec(url); - if (!protocol) { - return "_relative"; - } - // Reject weird colons - if (protocol[2] !== ":") { - return null; - } - // Reject invalid characters in scheme according to - // https://datatracker.ietf.org/doc/html/rfc3986#section-3.1 - if (!/^[a-zA-Z][a-zA-Z0-9+\-.]*$/.test(protocol[1])) { - return null; - } - // Lowercase the protocol - return protocol[1].toLowerCase(); - }; - - /** - * 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 = { - 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.leqno = utils.deflt(options.leqno, false); // boolean - this.throwOnError = utils.deflt(options.throwOnError, false); // boolean - this.errorColor = utils.deflt(options.errorColor, "#b22222"); // string - this.macros = options.macros || {}; - this.wrap = utils.deflt(options.wrap, "tex"); // "tex" | "=" - 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) { - const protocol = utils.protocolFromUrl(context.url); - if (protocol == null) { - return false - } - context.protocol = protocol; - } - 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 this.classes.includes(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 this.classes.includes(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 itself). - */ - 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. - */ - - // TODO: Remove when Chromium stretches \widetilde & \widehat - const estimatedWidth = node => { - let width = 0; - if (node.body) { - for (const item of node.body) { - width += estimatedWidth(item); - } - } else if (node.type === "supsub") { - width += estimatedWidth(node.base); - if (node.sub) { width += 0.7 * estimatedWidth(node.sub); } - if (node.sup) { width += 0.7 * estimatedWidth(node.sup); } - } else if (node.type === "mathord" || node.type === "textord") { - for (const ch of node.text.split('')) { - const codePoint = ch.codePointAt(0); - if ((0x60 < codePoint && codePoint < 0x7B) || (0x03B0 < codePoint && codePoint < 0x3CA)) { - width += 0.56; // lower case latin or greek. Use advance width of letter n - } else if (0x2F < codePoint && codePoint < 0x3A) { - width += 0.50; // numerals. - } else { - width += 0.92; // advance width of letter M - } - } - } else { - width += 1.0; - } - return width - }; - - 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 - }; - - const crookedWides = ["\\widetilde", "\\widehat", "\\widecheck", "\\utilde"]; - - // TODO: Remove when Chromium stretches \widetilde & \widehat - const accentNode = (group) => { - const mo = mathMLnode(group.label); - if (crookedWides.includes(group.label)) { - const width = estimatedWidth(group.base); - if (1 < width && width < 1.6) { - mo.classes.push("tml-crooked-2"); - } else if (1.6 <= width && width < 2.5) { - mo.classes.push("tml-crooked-3"); - } else if (2.5 <= width) { - mo.classes.push("tml-crooked-4"); - } - } - return mo - }; - - var stretchy = { - mathMLnode, - accentNode - }; - - /** - * 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, "\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"); - // unicodemath - defineSymbol(math, rel, "\u2a75", "\\eqeq", true); - defineSymbol(math, rel, "\u2a76", "\\eqeqeq", true); - // 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); - // ∇ is actually a unary operator, not binary. But this works. - defineSymbol(math, bin, "\u2207", "\\nabla", true); - defineSymbol(math, textord, "\u266d", "\\flat", true); - defineSymbol(math, textord, "\u2113", "\\ell", true); - defineSymbol(math, textord, "\u266e", "\\natural", true); - defineSymbol(math, textord, "Å", "\\Angstrom", true); - defineSymbol(text, textord, "Å", "\\Angstrom", 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 - defineSymbol(math, bin, "\u2AFD", "\\sslash", true); // from stmaryrd - - // 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, "\u21a4", "\\mapsfrom", 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, "\u220E", "\\QED", true); - defineSymbol(math, mathord, "\u2030", "\\permil", true); - defineSymbol(text, textord, "\u2030", "\\permil"); - defineSymbol(math, mathord, "\u2609", "\\astrosun", true); - defineSymbol(math, mathord, "\u263c", "\\sun", true); - defineSymbol(math, mathord, "\u263e", "\\leftmoon", true); - defineSymbol(math, mathord, "\u263d", "\\rightmoon", true); - defineSymbol(math, mathord, "\u2295", "\\Earth"); - - // 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, "\u2036", "\\backdprime"); - defineSymbol(math, textord, "\u2037", "\\backtrprime"); - 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, "\u22ab", "\\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, "\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); - defineSymbol(math, bin, "\u22c8", "\\bowtie", true); - defineSymbol(math, bin, "\u22c8", "\\Join"); - defineSymbol(math, bin, "\u27d5", "\\leftouterjoin", true); - defineSymbol(math, bin, "\u27d6", "\\rightouterjoin", true); - defineSymbol(math, bin, "\u27d7", "\\fullouterjoin", true); - - // stix Binary Operators - defineSymbol(math, bin, "\u2238", "\\dotminus", true); - defineSymbol(math, bin, "\u27D1", "\\wedgedot", true); - defineSymbol(math, bin, "\u27C7", "\\veedot", true); - defineSymbol(math, bin, "\u2A62", "\\doublebarvee", true); - defineSymbol(math, bin, "\u2A63", "\\veedoublebar", true); - defineSymbol(math, bin, "\u2A5F", "\\wedgebar", true); - defineSymbol(math, bin, "\u2A60", "\\wedgedoublebar", true); - defineSymbol(math, bin, "\u2A54", "\\Vee", true); - defineSymbol(math, bin, "\u2A53", "\\Wedge", true); - defineSymbol(math, bin, "\u2A43", "\\barcap", true); - defineSymbol(math, bin, "\u2A42", "\\barcup", true); - defineSymbol(math, bin, "\u2A48", "\\capbarcup", true); - defineSymbol(math, bin, "\u2A40", "\\capdot", true); - defineSymbol(math, bin, "\u2A47", "\\capovercup", true); - defineSymbol(math, bin, "\u2A46", "\\cupovercap", true); - defineSymbol(math, bin, "\u2A4D", "\\closedvarcap", true); - defineSymbol(math, bin, "\u2A4C", "\\closedvarcup", true); - defineSymbol(math, bin, "\u2A2A", "\\minusdot", true); - defineSymbol(math, bin, "\u2A2B", "\\minusfdots", true); - defineSymbol(math, bin, "\u2A2C", "\\minusrdots", true); - defineSymbol(math, bin, "\u22BB", "\\Xor", true); - defineSymbol(math, bin, "\u22BC", "\\Nand", true); - defineSymbol(math, bin, "\u22BD", "\\Nor", true); - defineSymbol(math, bin, "\u22BD", "\\barvee"); - defineSymbol(math, bin, "\u2AF4", "\\interleave", true); - defineSymbol(math, bin, "\u29E2", "\\shuffle", true); - defineSymbol(math, bin, "\u2AF6", "\\threedotcolon", true); - defineSymbol(math, bin, "\u2982", "\\typecolon", true); - defineSymbol(math, bin, "\u223E", "\\invlazys", true); - defineSymbol(math, bin, "\u2A4B", "\\twocaps", true); - defineSymbol(math, bin, "\u2A4A", "\\twocups", true); - defineSymbol(math, bin, "\u2A4E", "\\Sqcap", true); - defineSymbol(math, bin, "\u2A4F", "\\Sqcup", true); - defineSymbol(math, bin, "\u2A56", "\\veeonvee", true); - defineSymbol(math, bin, "\u2A55", "\\wedgeonwedge", true); - defineSymbol(math, bin, "\u29D7", "\\blackhourglass", true); - defineSymbol(math, bin, "\u29C6", "\\boxast", true); - defineSymbol(math, bin, "\u29C8", "\\boxbox", true); - defineSymbol(math, bin, "\u29C7", "\\boxcircle", true); - defineSymbol(math, bin, "\u229C", "\\circledequal", true); - defineSymbol(math, bin, "\u29B7", "\\circledparallel", true); - defineSymbol(math, bin, "\u29B6", "\\circledvert", true); - defineSymbol(math, bin, "\u29B5", "\\circlehbar", true); - defineSymbol(math, bin, "\u27E1", "\\concavediamond", true); - defineSymbol(math, bin, "\u27E2", "\\concavediamondtickleft", true); - defineSymbol(math, bin, "\u27E3", "\\concavediamondtickright", true); - defineSymbol(math, bin, "\u22C4", "\\diamond", true); - defineSymbol(math, bin, "\u29D6", "\\hourglass", true); - defineSymbol(math, bin, "\u27E0", "\\lozengeminus", true); - defineSymbol(math, bin, "\u233D", "\\obar", true); - defineSymbol(math, bin, "\u29B8", "\\obslash", true); - defineSymbol(math, bin, "\u2A38", "\\odiv", true); - defineSymbol(math, bin, "\u29C1", "\\ogreaterthan", true); - defineSymbol(math, bin, "\u29C0", "\\olessthan", true); - defineSymbol(math, bin, "\u29B9", "\\operp", true); - defineSymbol(math, bin, "\u2A37", "\\Otimes", true); - defineSymbol(math, bin, "\u2A36", "\\otimeshat", true); - defineSymbol(math, bin, "\u22C6", "\\star", true); - defineSymbol(math, bin, "\u25B3", "\\triangle", true); - defineSymbol(math, bin, "\u2A3A", "\\triangleminus", true); - defineSymbol(math, bin, "\u2A39", "\\triangleplus", true); - defineSymbol(math, bin, "\u2A3B", "\\triangletimes", true); - defineSymbol(math, bin, "\u27E4", "\\whitesquaretickleft", true); - defineSymbol(math, bin, "\u27E5", "\\whitesquaretickright", true); - defineSymbol(math, bin, "\u2A33", "\\smashtimes", 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, "¢", "\\cent"); - defineSymbol(text, textord, "¢", "\\cent"); - 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, "\u2033", "\\dprime"); - defineSymbol(math, textord, "\u2034", "\\trprime"); - defineSymbol(math, textord, "\u2057", "\\qprime"); - 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, "\u2300", "\\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", "/", true); - 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, "\u27ea", "\\lAngle", true); - defineSymbol(math, open, "\u2989", "\\llangle", 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, "\u27eb", "\\rAngle", true); - defineSymbol(math, close, "\u298a", "\\rrangle", 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"); - defineSymbol(math, bin, "\u22bb", "\\veebar"); - defineSymbol(math, bin, "\u2299", "\\odot", true); - // Firefox turns ⊕ into an emoji. So append \uFE0E. Define Unicode character in macros, not here. - defineSymbol(math, bin, "\u2295\uFE0E", "\\oplus"); - 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, "\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(math, open, "⦇", "\\llparenthesis", true); - defineSymbol(math, close, "⦈", "\\rrparenthesis", 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, "\u2a09", "\\bigtimes"); - 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, "\u2026", "\\dddot"); - defineSymbol(math, accent, "\u2026\u002e", "\\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, "\u2192", "\\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"); - defineSymbol(math, textord, "\u2300", "\\diameter", true); - defineSymbol(text, textord, "\u2300", "\\diameter"); - - // 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. - * - * The default is for 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. - * - * An option is for soft line breaks before an "=" sign. That changes the s. - * - * 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. - */ - - const openDelims = "([{⌊⌈⟨⟮⎰⟦⦃"; - const closeDelims = ")]}⌋⌉⟩⟯⎱⟦⦄"; - - function setLineBreaks(expression, wrapMode, isDisplayMode) { - const mtrs = []; - let mrows = []; - let block = []; - let numTopLevelEquals = 0; - let i = 0; - let level = 0; - while (i < expression.length) { - while (expression[i] instanceof DocumentFragment) { - expression.splice(i, 1, ...expression[i].children); // Expand the fragment. - } - const node = expression[i]; - if (node.attributes && node.attributes.linebreak && - node.attributes.linebreak === "newline") { - // A hard line break. Create a for the current block. - if (block.length > 0) { - mrows.push(new mathMLTree.MathNode("mrow", block)); - } - mrows.push(node); - block = []; - const mtd = new mathMLTree.MathNode("mtd", mrows); - mtd.style.textAlign = "left"; - mtrs.push(new mathMLTree.MathNode("mtr", [mtd])); - mrows = []; - i += 1; - continue - } - block.push(node); - if (node.type && node.type === "mo" && node.children.length === 1 && - !Object.hasOwn(node.attributes, "movablelimits")) { - const ch = node.children[0].text; - if (openDelims.indexOf(ch) > -1) { - level += 1; - } else if (closeDelims.indexOf(ch) > -1) { - level -= 1; - } else if (level === 0 && wrapMode === "=" && ch === "=") { - numTopLevelEquals += 1; - if (numTopLevelEquals > 1) { - block.pop(); - // Start a new block. (Insert a soft linebreak.) - const element = new mathMLTree.MathNode("mrow", block); - mrows.push(element); - block = [node]; - } - } else if (level === 0 && wrapMode === "tex" && ch !== "∇") { - // 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("mrow", block); - mrows.push(element); - block = []; - } - } - } - i += 1; - } - if (block.length > 0) { - const element = new mathMLTree.MathNode("mrow", block); - mrows.push(element); - } - if (mtrs.length > 0) { - const mtd = new mathMLTree.MathNode("mtd", mrows); - mtd.style.textAlign = "left"; - 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 corresponding 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); - }; - - const consolidateText = mrow => { - // If possible, consolidate adjacent elements into a single element. - if (mrow.type !== "mrow" && mrow.type !== "mstyle") { return mrow } - if (mrow.children.length === 0) { return mrow } // empty group, e.g., \text{} - if (!mrow.children[0].attributes || mrow.children[0].type !== "mtext") { return mrow } - const variant = mrow.children[0].attributes.mathvariant || ""; - const mtext = new mathMLTree.MathNode( - "mtext", - [new mathMLTree.TextNode(mrow.children[0].children[0].text)] - ); - 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; - } - } - // 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"; - } - for (const [key, value] of Object.entries(mrow.attributes)) { - mtext.attributes[key] = value; - } - return mtext - }; - - const numberRegEx$1 = /^[0-9]$/; - const isDotOrComma = (node, followingNode) => { - return ((node.type === "textord" && node.text === ".") || - (node.type === "atom" && node.text === ",")) && - // Don't consolidate if there is a space after the comma. - node.loc && followingNode.loc && node.loc.end === followingNode.loc.start - }; - const consolidateNumbers = expression => { - // Consolidate adjacent numbers. We want to return 1,506.3, - // not 1,506.3 - if (expression.length < 2) { return } - const nums = []; - let inNum = false; - // Find adjacent numerals - for (let i = 0; i < expression.length; i++) { - const node = expression[i]; - if (node.type === "textord" && numberRegEx$1.test(node.text)) { - if (!inNum) { nums.push({ start: i }); } - inNum = true; - } else { - if (inNum) { nums[nums.length - 1].end = i - 1; } - inNum = false; - } - } - if (inNum) { nums[nums.length - 1].end = expression.length - 1; } - - // Determine if numeral groups are separated by a comma or dot. - for (let i = nums.length - 1; i > 0; i--) { - if (nums[i - 1].end === nums[i].start - 2 && - isDotOrComma(expression[nums[i].start - 1], expression[nums[i].start])) { - // Merge the two groups. - nums[i - 1].end = nums[i].end; - nums.splice(i, 1); - } - } - - // Consolidate the number nodes - for (let i = nums.length - 1; i >= 0; i--) { - for (let j = nums[i].start + 1; j <= nums[i].end; j++) { - expression[nums[i].start].text += expression[j].text; - } - expression.splice(nums[i].start + 1, nums[i].end - nums[i].start); - // Check if the is followed by a numeric base in a supsub, e.g. the "3" in 123^4 - // If so, merge the first into the base. - if (expression.length > nums[i].start + 1) { - const nextTerm = expression[nums[i].start + 1]; - if (nextTerm.type === "supsub" && nextTerm.base && nextTerm.base.type === "textord" && - numberRegEx$1.test(nextTerm.base.text)) { - nextTerm.base.text = expression[nums[i].start].text + nextTerm.base.text; - expression.splice(nums[i].start, 1); - } - } - } - }; - - /** - * 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, semisimple = false) { - if (body.length === 1 && !(body[0] instanceof DocumentFragment)) { - return body[0]; - } else if (!semisimple) { - // Suppress spacing on nodes at both ends of the row. - if (body[0] instanceof MathNode && body[0].type === "mo" && !body[0].attributes.fence) { - body[0].attributes.lspace = "0em"; - body[0].attributes.rspace = "0em"; - } - const end = body.length - 1; - if (body[end] instanceof MathNode && body[end].type === "mo" && !body[end].attributes.fence) { - body[end].attributes.lspace = "0em"; - body[end].attributes.rspace = "0em"; - } - } - 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, semisimple = false) { - if (!semisimple && expression.length === 1) { - const group = buildGroup$1(expression[0], style); - if (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]; - } - - consolidateNumbers(expression); - - 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, semisimple = false) { - return makeRow(buildExpression(expression, style, semisimple), semisimple); - }; - - /** - * 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$1 = _ => { - return new mathMLTree.MathNode("mtd", [], [], { padding: "0", width: "50%" }) - }; - - const taggedExpression = (expression, tag, style, leqno) => { - tag = buildExpressionRow(tag[0].body, style); - tag = consolidateText(tag); - tag.classes.push("tml-tag"); - - expression = new mathMLTree.MathNode("mtd", [expression]); - const rowArray = [glue$1(), expression, glue$1()]; - rowArray[leqno ? 0 : 2].classes.push(leqno ? "tml-left" : "tml-right"); - rowArray[leqno ? 0 : 2].children.push(tag); - const mtr = new mathMLTree.MathNode("mtr", rowArray, ["tml-tageqn"]); - const table = new mathMLTree.MathNode("mtable", [mtr]); - table.style.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 wrap = (settings.displayMode || settings.annotate) ? "none" : settings.wrap; - - const n1 = expression.length === 0 ? null : expression[0]; - let wrapper = expression.length === 1 && tag === null && (n1 instanceof MathNode) - ? expression[0] - : setLineBreaks(expression, wrap, settings.displayMode); - - if (tag) { - wrapper = taggedExpression(wrapper, tag, style, settings.leqno); - } - - 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"); - wrapper = new mathMLTree.MathNode("semantics", [wrapper, annotation]); - } - - const math = 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"); - math.style.display = "block math"; // necessary in Chromium. - // Firefox and Safari do not recognize display: "block math". - // Set a class so that the CSS file can set display: block. - math.classes = ["tml-display"]; - } - return math; - } - - const smalls = "acegıȷmnopqrsuvwxyzαγεηικμνοπρςστυχωϕ𝐚𝐜𝐞𝐠𝐦𝐧𝐨𝐩𝐪𝐫𝐬𝐮𝐯𝐰𝐱𝐲𝐳"; - const talls = "ABCDEFGHIJKLMNOPQRSTUVWXYZbdfhkltΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩβδλζφθψ" - + "𝐀𝐁𝐂𝐃𝐄𝐅𝐆𝐇𝐈𝐉𝐊𝐋𝐌𝐍𝐎𝐏𝐐𝐑𝐒𝐓𝐔𝐕𝐖𝐗𝐘𝐙𝐛𝐝𝐟𝐡𝐤𝐥𝐭"; - const longSmalls = new Set(["\\alpha", "\\gamma", "\\delta", "\\epsilon", "\\eta", "\\iota", - "\\kappa", "\\mu", "\\nu", "\\pi", "\\rho", "\\sigma", "\\tau", "\\upsilon", "\\chi", "\\psi", - "\\omega", "\\imath", "\\jmath"]); - const longTalls = new Set(["\\Gamma", "\\Delta", "\\Sigma", "\\Omega", "\\beta", "\\delta", - "\\lambda", "\\theta", "\\psi"]); - - const mathmlBuilder$a = (group, style) => { - const accentNode = group.isStretchy - ? stretchy.accentNode(group) - : new mathMLTree.MathNode("mo", [makeText(group.label, group.mode)]); - - if (group.label === "\\vec") { - accentNode.style.transform = "scale(0.75) translate(10%, 30%)"; - } else { - accentNode.style.mathStyle = "normal"; - accentNode.style.mathDepth = "0"; - if (needWebkitShift.has(group.label) && utils.isCharacterBox(group.base)) { - let shift = ""; - const ch = group.base.text; - if (smalls.indexOf(ch) > -1 || longSmalls.has(ch)) { shift = "tml-xshift"; } - if (talls.indexOf(ch) > -1 || longTalls.has(ch)) { shift = "tml-capshift"; } - if (shift) { accentNode.classes.push(shift); } - } - } - if (!group.isStretchy) { - accentNode.setAttribute("stretchy", "false"); - } - - const node = new mathMLTree.MathNode((group.label === "\\c" ? "munder" : "mover"), - [buildGroup$1(group.base, style), accentNode] - ); - - return node; - }; - - const nonStretchyAccents = new Set([ - "\\acute", - "\\grave", - "\\ddot", - "\\dddot", - "\\ddddot", - "\\tilde", - "\\bar", - "\\breve", - "\\check", - "\\hat", - "\\vec", - "\\dot", - "\\mathring" - ]); - - const needWebkitShift = new Set([ - "\\acute", - "\\bar", - "\\breve", - "\\check", - "\\dot", - "\\ddot", - "\\grave", - "\\hat", - "\\mathring", - "\\'", "\\^", "\\~", "\\=", "\\u", "\\.", '\\"', "\\r", "\\H", "\\v" - ]); - - // 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 = !nonStretchyAccents.has(context.funcName); - - return { - type: "accent", - mode: context.parser.mode, - label: context.funcName, - isStretchy: isStretchy, - 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, - 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.accentNode(group); - accentNode.style["math-depth"] = 0; - const node = new mathMLTree.MathNode("munder", [ - buildGroup$1(group.base, style), - accentNode - ]); - 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 padding$2 = width => { - const node = new mathMLTree.MathNode("mspace"); - node.setAttribute("width", width + "em"); - return node - }; - - const paddedNode = (group, lspace = 0.3, rspace = 0) => { - if (group == null && rspace === 0) { return padding$2(lspace) } - const row = group ? [group] : []; - if (lspace !== 0) { row.unshift(padding$2(lspace)); } - if (rspace > 0) { row.push(padding$2(rspace)); } - return new mathMLTree.MathNode("mrow", row) - }; - - const labelSize = (size, scriptLevel) => Number(size) / emScale(scriptLevel); - - const munderoverNode = (fName, body, below, style) => { - const arrowNode = stretchy.mathMLnode(fName); - // Is this the short part of a mhchem equilibrium arrow? - const isEq = fName.slice(1, 3) === "eq"; - const minWidth = fName.charAt(1) === "x" - ? "1.75" // mathtools extensible arrows are ≥ 1.75em long - : fName.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 - // TODO: When Firefox supports minsize, use the next line. - //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 label dimensions accordingly. - const labelStyle = style.withLevel(style.level < 2 ? 2 : 3); - const minArrowWidth = labelSize(minWidth, labelStyle.level); - // The dummyNode will be inside a inside a - // So it will be at scriptlevel 3 - const dummyWidth = labelSize(minWidth, 3); - const emptyLabel = paddedNode(null, minArrowWidth.toFixed(4), 0); - const dummyNode = paddedNode(null, dummyWidth.toFixed(4), 0); - // The arrow is a little longer than the label. Set a spacer length. - const space = labelSize((isEq ? 0 : 0.3), labelStyle.level).toFixed(4); - let upperNode; - let lowerNode; - - const gotUpper = (body && body.body && - // \hphantom visible content - (body.body.body || body.body.length > 0)); - if (gotUpper) { - let label = buildGroup$1(body, labelStyle); - label = paddedNode(label, space, space); - // Since Firefox does not support minsize, stack a invisible node - // on top of the label. Its width will serve as a min-width. - // TODO: Refactor this after Firefox supports minsize. - upperNode = new mathMLTree.MathNode("mover", [label, dummyNode]); - } - const gotLower = (below && below.body && - (below.body.body || below.body.length > 0)); - if (gotLower) { - let label = buildGroup$1(below, labelStyle); - label = paddedNode(label, space, space); - lowerNode = new mathMLTree.MathNode("munder", [label, dummyNode]); - } - - let node; - if (!gotUpper && !gotLower) { - node = new mathMLTree.MathNode("mover", [arrowNode, emptyLabel]); - } else if (gotUpper && gotLower) { - node = new mathMLTree.MathNode("munderover", [arrowNode, lowerNode, upperNode]); - } else if (gotUpper) { - node = new mathMLTree.MathNode("mover", [arrowNode, upperNode]); - } else { - node = new mathMLTree.MathNode("munder", [arrowNode, lowerNode]); - } - if (minWidth === "3.0") { node.style.height = "1em"; } // CD environment - node.setAttribute("accent", "false"); // Necessary for MS Word - 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 5 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 row = [node]; - row.unshift(padding$2(0.2778)); - row.push(padding$2(0.2778)); - return new mathMLTree.MathNode("mrow", row) - } - }); - - 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", - [padding$2(0.2778), botNode, raiseNode, padding$2(0.2778)] - ); - } else { - raiseNode.setAttribute("width", (group.name === "\\equilibriumRight" ? "0.5em" : "0")); - wrapper = new mathMLTree.MathNode( - "mpadded", - [padding$2(0.2778), raiseNode, botArrow, padding$2(0.2778)] - ); - } - - wrapper.setAttribute("voffset", "-0.18em"); - wrapper.setAttribute("height", "-0.18em"); - wrapper.setAttribute("depth", "+0.18em"); - return wrapper - } - }); - - /** - * 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], - semisimple: true - }; - 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); - } - body.pop(); - - // End row group - parser.gullet.endGroup(); - // End array group defining \\ - parser.gullet.endGroup(); - - return { - type: "array", - mode: "math", - body, - envClasses: ["jot", "cd"], - cols: [], - 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(Number((num * 255).toFixed(0))); - }); - } - 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) => { - // In LaTeX, color is not supposed to change the spacing of any node. - // So instead of wrapping the group in an , we apply - // the color individually to each node and return a document fragment. - let expr = buildExpression(group.body, style.withColor(group.color)); - expr = expr.map(e => { - e.style.color = group.color; - return e - }); - return mathMLTree.newDocumentFragment(expr) - }; - - 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, breakOnTokenText, 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); - } - - // Parse out the implicit body that should be colored. - const body = parser.parseExpression(true, breakOnTokenText, true); - - 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: 0, - allowedInText: true - }, - - handler({ parser }, args, optArgs) { - const size = parser.gullet.future().text === "[" ? parser.parseSizeGroup(true) : null; - 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 globalMap = { - "\\global": "\\global", - "\\long": "\\\\globallong", - "\\\\globallong": "\\\\globallong", - "\\def": "\\gdef", - "\\gdef": "\\gdef", - "\\edef": "\\xdef", - "\\xdef": "\\xdef", - "\\let": "\\\\globallet", - "\\futurelet": "\\\\globalfuture" - }; - - 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, global) => { - 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, global); - }; - - // -> | - // -> |\global - // -> | - // -> \global|\long|\outer - defineFunction({ - type: "internal", - names: [ - "\\global", - "\\long", - "\\\\globallong" // can’t be entered directly - ], - props: { - numArgs: 0, - allowedInText: true - }, - handler({ parser, funcName }) { - parser.consumeSpaces(); - const token = parser.fetch(); - if (globalMap[token.text]) { - // Temml doesn't have \par, so ignore \long - if (funcName === "\\global" || funcName === "\\\\globallong") { - token.text = globalMap[token.text]; - } - return assertNodeType(parser.parseFunction(), "internal"); - } - throw new ParseError(`Invalid token after macro prefix`, token); - } - }); - - // Basic support for macro definitions: \def, \gdef, \edef, \xdef - // -> - // -> \def|\gdef|\edef|\xdef - // -> - defineFunction({ - type: "internal", - names: ["\\def", "\\gdef", "\\edef", "\\xdef"], - 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" || funcName === "\\xdef") { - tokens = parser.gullet.expandTokens(tokens); - if (tokens.length > parser.gullet.settings.maxExpand) { - throw new ParseError("Too many expansions in an " + funcName); - } - tokens.reverse(); // to fit in with stack order - } - // Final arg is the expansion of the macro - parser.gullet.macros.set( - name, - { tokens, numArgs, delimiters }, - funcName === globalMap[funcName] - ); - return { type: "internal", mode: parser.mode }; - } - }); - - // -> - // -> \futurelet - // | \let - // -> |= - defineFunction({ - type: "internal", - names: [ - "\\let", - "\\\\globallet" // can’t be entered directly - ], - 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, funcName === "\\\\globallet"); - return { type: "internal", mode: parser.mode }; - } - }); - - // ref: https://www.tug.org/TUGboat/tb09-3/tb22bechtolsheim.pdf - defineFunction({ - type: "internal", - names: [ - "\\futurelet", - "\\\\globalfuture" // can’t be entered directly - ], - 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, funcName === "\\\\globalfuture"); - 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 }, - !parser.settings.strict - ); - - 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", - "⦇", - "\\llparenthesis", - "⦈", - "\\rrparenthesis", - "\\lfloor", - "\\rfloor", - "\u230a", - "\u230b", - "\\lceil", - "\\rceil", - "\u2308", - "\u2309", - "<", - ">", - "\\langle", - "\u27e8", - "\\rangle", - "\u27e9", - "\\lAngle", - "\u27ea", - "\\rAngle", - "\u27eb", - "\\llangle", - "⦉", - "\\rrangle", - "⦊", - "\\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", - "." - ]; - - // Export isDelimiter for benefit of parser. - const dels = ["}", "\\left", "\\middle", "\\right"]; - const isDelimiter = str => str.length > 0 && - (delimiters.includes(str) || delimiterSizes[str] || dels.includes(str)); - - // 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) { - const symDelim = checkSymbolNodeType(delim); - if (symDelim && delimiters.includes(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 (["/", "\u2044"].includes(symDelim.text)) { symDelim.text = "\u2215"; } - if (["<", "\\lt"].includes(symDelim.text)) { symDelim.text = "⟨"; } - if ([">", "\\gt"].includes(symDelim.text)) { symDelim.text = "⟩"; } - 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" || group.delim === "\\vert" || - group.delim === "|" || group.delim.indexOf("arrow") > -1) { - // 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) => { - return { - type: "leftright-right", - mode: context.parser.mode, - delim: checkDelimiter(args[0], context).text - }; - } - }); - - 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' or `\\middle` - let body = parser.parseExpression(false, null, true); - let nextToken = parser.fetch(); - while (nextToken.text === "\\middle") { - // `\middle`, from the ε-TeX package, ends one group and starts another group. - // We had to parse this expression with `breakOnMiddle` enabled in order - // to get TeX-compliant parsing of \over. - // But we do not want, at this point, to end on \middle, so continue - // to parse until we fetch a `\right`. - parser.consume(); - const middle = parser.fetch().text; - if (!symbols.math[middle]) { - throw new ParseError(`Invalid delimiter '${middle}' after '\\middle'`); - } - checkDelimiter({ type: "atom", mode: "math", text: middle }, { funcName: "\\middle" }); - body.push({ type: "middle", mode: "math", delim: middle }); - parser.consume(); - body = body.concat(parser.parseExpression(false, null, true)); - nextToken = parser.fetch(); - } - --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 - }; - }, - 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" || group.left.indexOf("arrow") > -1) { - 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" || group.right.indexOf("arrow") > -1) { - rightNode.setAttribute("stretchy", "true"); - } - 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"); - if (group.delim.indexOf("arrow") > -1) { - middleNode.setAttribute("stretchy", "true"); - } - // The next line is not semantically correct, but - // Chromium fails to stretch if it is not there. - middleNode.setAttribute("form", "prefix"); - // 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 padding$1 = _ => { - const node = new mathMLTree.MathNode("mspace"); - node.setAttribute("width", "3pt"); - return node - }; - - const mathmlBuilder$8 = (group, style) => { - let node; - if (group.label.indexOf("colorbox") > -1 || group.label === "\\boxed") { - // MathML core does not support +width attribute in . - // Firefox does not reliably add side padding. - // Insert - node = new mathMLTree.MathNode("mrow", [ - padding$1(), - buildGroup$1(group.body, style), - padding$1() - ]); - } else { - node = new mathMLTree.MathNode("mrow", [buildGroup$1(group.body, style)]); - } - switch (group.label) { - case "\\overline": - node.style.padding = "0.1em 0 0 0"; - node.style.borderTop = "0.065em solid"; - break - case "\\underline": - node.style.padding = "0 0 0.1em 0"; - node.style.borderBottom = "0.065em solid"; - break - case "\\cancel": - // We can't use an inline background-gradient. It does not work client-side. - // So set a class and put the rule in the external CSS file. - node.classes.push("tml-cancel"); - break - case "\\bcancel": - node.classes.push("tml-bcancel"); - break - /* - case "\\longdiv": - node.setAttribute("notation", "longdiv"); - break - case "\\phase": - node.setAttribute("notation", "phasorangle"); - break */ - case "\\angl": - node.style.padding = "0.03889em 0.03889em 0 0.03889em"; - node.style.borderTop = "0.049em solid"; - node.style.borderRight = "0.049em solid"; - node.style.marginRight = "0.03889em"; - break - case "\\sout": - node.style.backgroundImage = 'linear-gradient(black, black)'; - node.style.backgroundRepeat = 'no-repeat'; - node.style.backgroundSize = '100% 1.5px'; - node.style.backgroundPosition = '0 center'; - break - case "\\boxed": - // \newcommand{\boxed}[1]{\fbox{\m@th$\displaystyle#1$}} from amsmath.sty - node.style = { padding: "3pt 0 3pt 0", border: "1px solid" }; - node.setAttribute("scriptlevel", "0"); - node.setAttribute("displaystyle", "true"); - break - case "\\fbox": - node.style = { padding: "3pt", border: "1px solid" }; - 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("height", `+${2 * fboxsep}pt`) - //node.setAttribute("voffset", `${fboxsep}pt`) - const style = { padding: "3pt 0 3pt 0" }; - - if (group.label === "\\fcolorbox") { - style.border = "0.06em solid " + String(group.borderColor); - } - node.style = style; - break - } - case "\\xcancel": - node.classes.push("tml-xcancel"); - 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: ["\\angl", "\\cancel", "\\bcancel", "\\xcancel", "\\sout", "\\overline", "\\boxed"], - // , "\\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 - }); - - defineFunction({ - type: "enclose", - names: ["\\underline"], - props: { - numArgs: 1, - allowedInText: true - }, - 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; - if (nxt === "\\relax") { - parser.consume(); - parser.consumeSpaces(); - 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, true); - tag.classes = ["tml-tag"]; - } else { - // \notag. Return an empty span. - tag = new mathMLTree.MathNode("mtext", [], []); - return tag - } - } else if (group.envClasses.includes("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("mtext", [], []); - return tag - } else { - // AMS automatcally numbered equaton. - // Insert a class so the element can be populated by a CSS counter. - // WebKit will display the CSS counter only inside a span. - tag = new mathMLTree.MathNode("mtext", [new Span(["tml-eqn"])]); - } - 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, - { - cols, // [{ type: string , align: l|c|r|null }] - envClasses, // align(ed|at|edat) | array | cases | cd | small | 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", "\\@ifstar\\envtag@literal\\envtag@paren"); - parser.gullet.macros.set("\\envtag@paren", "\\env@tag{{(\\text{#1})}}"); - parser.gullet.macros.set("\\envtag@literal", "\\env@tag{\\text{#1}}"); - parser.gullet.macros.set("\\notag", "\\env@notag"); - parser.gullet.macros.set("\\nonumber", "\\env@notag"); - } - - // 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, - semisimple: true - }; - row.push(cell); - const next = parser.fetch().text; - if (next === "&") { - if (maxNumCols && row.length === maxNumCols) { - if (envClasses.includes("array")) { - if (parser.settings.strict) { - throw new ParseError("Too few columns " + "specified in the {array} column argument.", - parser.nextToken) - } - } else if (maxNumCols === 2) { - throw new ParseError("The split environment accepts no more than two columns", - 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, - body, - cols, - rowGaps, - hLinesBeforeRow, - envClasses, - addEqnNum, - scriptLevel, - tags, - leqno - }; - } - - // 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 glue = group => { - const glueNode = new mathMLTree.MathNode("mtd", []); - glueNode.style = { padding: "0", width: "50%" }; - if (group.envClasses.includes("multline")) { - glueNode.style.width = "7.5%"; - } - return glueNode - }; - - const mathmlBuilder$7 = function(group, style) { - const tbl = []; - const numRows = group.body.length; - const hlines = group.hLinesBeforeRow; - - for (let i = 0; i < numRows; i++) { - const rw = group.body[i]; - const row = []; - const cellLevel = 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(cellLevel))] - ); - - if (group.envClasses.includes("multline")) { - const align = i === 0 ? "left" : i === numRows - 1 ? "right" : "center"; - mtd.setAttribute("columnalign", align); - if (align !== "center") { - mtd.classes.push("tml-" + align); - } - } - row.push(mtd); - } - if (group.addEqnNum) { - row.unshift(glue(group)); - row.push(glue(group)); - const tag = getTag(group, style.withLevel(cellLevel), i); - if (group.leqno) { - row[0].children.push(tag); - row[0].classes.push("tml-left"); - } else { - row[row.length - 1].children.push(tag); - row[row.length - 1].classes.push("tml-right"); - } - } - const mtr = new mathMLTree.MathNode("mtr", row, []); - // Write horizontal rules - if (i === 0 && hlines[0].length > 0) { - if (hlines[0].length === 2) { - mtr.children.forEach(cell => { cell.style.borderTop = "0.15em double"; }); - } else { - mtr.children.forEach(cell => { - cell.style.borderTop = hlines[0][0] ? "0.06em dashed" : "0.06em solid"; - }); - } - } - if (hlines[i + 1].length > 0) { - if (hlines[i + 1].length === 2) { - mtr.children.forEach(cell => { cell.style.borderBottom = "0.15em double"; }); - } else { - mtr.children.forEach(cell => { - cell.style.borderBottom = hlines[i + 1][0] ? "0.06em dashed" : "0.06em solid"; - }); - } - } - tbl.push(mtr); - } - - if (group.envClasses.length > 0) { - const pad = group.envClasses.includes("jot") - ? "0.7" // 0.5ex + 0.09em top & bot padding - : group.envClasses.includes("small") - ? "0.35" - : "0.5"; // 0.5ex default top & bot padding - const sidePadding = group.envClasses.includes("abut") - ? "0" - : group.envClasses.includes("cases") - ? "0" - : group.envClasses.includes("small") - ? "0.1389" - : group.envClasses.includes("cd") - ? "0.25" - : "0.4"; // default side padding - - const numCols = tbl.length === 0 ? 0 : tbl[0].children.length; - - const sidePad = (j, hand) => { - if (j === 0 && hand === 0) { return "0" } - if (j === numCols - 1 && hand === 1) { return "0" } - if (group.envClasses[0] !== "align") { return sidePadding } - if (hand === 1) { return "0" } - if (group.addEqnNum) { - return (j % 2) ? "1" : "0" - } else { - return (j % 2) ? "0" : "1" - } - }; - - // Padding - for (let i = 0; i < tbl.length; i++) { - for (let j = 0; j < tbl[i].children.length; j++) { - tbl[i].children[j].style.padding = `${pad}ex ${sidePad(j, 1)}em ${pad}ex ${sidePad(j, 0)}em`; - } - } - - // Justification - const align = group.envClasses.includes("align") || group.envClasses.includes("alignat"); - for (let i = 0; i < tbl.length; i++) { - const row = tbl[i]; - if (align) { - for (let j = 0; j < row.children.length; j++) { - // Chromium does not recognize text-align: left. Use -webkit- - // TODO: Remove -webkit- when Chromium no longer needs it. - row.children[j].classes = ["tml-" + (j % 2 ? "left" : "right")]; - } - if (group.addEqnNum) { - const k = group.leqno ? 0 : row.children.length - 1; - row.children[k].classes = ["tml-" + (group.leqno ? "left" : "right")]; - } - } - if (row.children.length > 1 && group.envClasses.includes("cases")) { - row.children[1].style.padding = row.children[1].style.padding.replace(/0em$/, "1em"); - } - - if (group.envClasses.includes("cases") || group.envClasses.includes("subarray")) { - for (const cell of row.children) { - cell.classes.push("tml-left"); - } - } - } - } else { - // Set zero padding on side of the matrix - for (let i = 0; i < tbl.length; i++) { - tbl[i].children[0].style.paddingLeft = "0em"; - if (tbl[i].children.length === tbl[0].children.length) { - tbl[i].children[tbl[i].children.length - 1].style.paddingRight = "0em"; - } - } - } - - let table = new mathMLTree.MathNode("mtable", tbl); - if (group.scriptLevel === "display") { table.setAttribute("displaystyle", "true"); } - - if (group.addEqnNum || group.envClasses.includes("multline")) { - table.style.width = "100%"; - } - - // Column separator lines and column alignment - let align = ""; - - if (group.cols && group.cols.length > 0) { - const cols = group.cols; - let prevTypeWasAlign = false; - let iStart = 0; - let iEnd = cols.length; - - while (cols[iStart].type === "separator") { - iStart += 1; - } - while (cols[iEnd - 1].type === "separator") { - iEnd -= 1; - } - - if (cols[0].type === "separator") { - const sep = cols[1].type === "separator" - ? "0.15em double" - : cols[0].separator === "|" - ? "0.06em solid " - : "0.06em dashed "; - for (const row of table.children) { - row.children[0].style.borderLeft = sep; - } - } - let iCol = group.addEqnNum ? 0 : -1; - for (let i = iStart; i < iEnd; i++) { - if (cols[i].type === "align") { - const colAlign = alignMap[cols[i].align]; - align += colAlign; - iCol += 1; - for (const row of table.children) { - if (colAlign.trim() !== "center" && iCol < row.children.length) { - row.children[iCol].classes = ["tml-" + colAlign.trim()]; - } - } - 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) { - const sep = cols[i + 1].type === "separator" - ? "0.15em double" - : cols[i].separator === "|" - ? "0.06em solid" - : "0.06em dashed"; - for (const row of table.children) { - if (iCol < row.children.length) { - row.children[iCol].style.borderRight = sep; - } - } - } - prevTypeWasAlign = false; - } - } - if (cols[cols.length - 1].type === "separator") { - const sep = cols[cols.length - 2].type === "separator" - ? "0.15em double" - : cols[cols.length - 1].separator === "|" - ? "0.06em solid" - : "0.06em dashed"; - for (const row of table.children) { - row.children[row.children.length - 1].style.borderRight = sep; - row.children[row.children.length - 1].style.paddingRight = "0.4em"; - } - } - } - if (group.addEqnNum) { - // allow for glue cells on each side - align = "left " + (align.length > 0 ? align : "center ") + "right "; - } - if (align) { - // Firefox reads this attribute, not the -webkit-left|right written above. - // TODO: When Chrome no longer needs "-webkit-", use CSS and delete the next line. - table.setAttribute("columnalign", align.trim()); - } - - if (group.envClasses.includes("small")) { - // A small array. Wrap in scriptstyle. - table = new mathMLTree.MathNode("mstyle", [table]); - table.setAttribute("scriptlevel", "1"); - } - - return table - }; - - // Convenience function for align, align*, aligned, alignat, alignat*, alignedat, split. - const alignedHandler = function(context, args) { - if (context.envName.indexOf("ed") === -1) { - validateAmsEnvironmentContext(context); - } - const cols = []; - const res = parseArray( - context.parser, - { - cols, - addEqnNum: context.envName === "align" || context.envName === "alignat", - emptySingleRow: true, - envClasses: ["abut", "jot"], // set row spacing & provisional column spacing - 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; - const isAlignedAt = context.envName.indexOf("at") > -1; - if (args[0] && isAlignedAt) { - // alignat environment takes an argument w/ number of columns - let arg0 = ""; - for (let i = 0; i < args[0].body.length; i++) { - const textord = assertNodeType(args[0].body[i], "textord"); - arg0 += textord.text; - } - if (isNaN(arg0)) { - throw new ParseError("The alignat enviroment requires a numeric first argument.") - } - numMaths = Number(arg0); - numCols = numMaths * 2; - } - res.body.forEach(function(row) { - if (isAlignedAt) { - // 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 - }; - } - if (context.envName === "split") ; else if (isAlignedAt) { - res.envClasses.push("alignat"); // Sets justification - } else { - res.envClasses[0] = "align"; // Sets column spacing & justification - } - 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, - envClasses: ["array"], - 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 = { - envClasses: [], - cols: [] - }; - 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 = []; - } - } - const res = parseArray(context.parser, payload, "text"); - res.cols = new Array(res.body[0].length).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 = { type: "small" }; - const res = parseArray(context.parser, payload, "script"); - res.envClasses = ["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, - envClasses: ["small"] - }; - 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: [], - envClasses: ["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. - defineEnvironment({ - type: "array", - names: ["align", "align*", "aligned", "split"], - props: { - numArgs: 0 - }, - handler: alignedHandler, - 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 where spacing occurs. - defineEnvironment({ - type: "array", - names: ["alignat", "alignat*", "alignedat"], - props: { - numArgs: 1 - }, - 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 (context.envName !== "gathered") { - validateAmsEnvironmentContext(context); - } - const res = { - cols: [], - envClasses: ["abut", "jot"], - addEqnNum: context.envName === "gather", - emptySingleRow: true, - leqno: context.parser.settings.leqno - }; - return parseArray(context.parser, res, "display"); - }, - 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, - envClasses: ["align"], - 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, - envClasses: ["jot", "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 isLongVariableName = (group, font) => { - if (font !== "mathrm" || group.body.type !== "ordgroup" || group.body.body.length === 1) { - return false - } - if (group.body.body[0].type !== "mathord") { return false } - for (let i = 1; i < group.body.body.length; i++) { - const parseNodeType = group.body.body[i].type; - if (!(parseNodeType === "mathord" || - (parseNodeType === "textord" && !isNaN(group.body.body[i].text)))) { - return false - } - } - return true - }; - - 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", "mrow"].includes(mathGroup.type)) { - mathGroup.style.fontWeight = "bold"; - return mathGroup - } - // Check if it is possible to consolidate elements into a single element. - if (isLongVariableName(group, font)) { - // This is a \mathrm{…} group. It gets special treatment because symbolsOrd.js - // wraps elements with s to work around a Firefox bug. - const mi = mathGroup.children[0].children[0]; - delete mi.attributes.mathvariant; - for (let i = 1; i < mathGroup.children.length; i++) { - mi.children[0].text += mathGroup.children[i].type === "mn" - ? mathGroup.children[i].children[0].text - : mathGroup.children[i].children[0].children[0].text; - } - // Wrap in a to prevent the same Firefox bug. - const bogus = new mathMLTree.MathNode("mtext", new mathMLTree.TextNode("\u200b")); - return new mathMLTree.MathNode("mrow", [bogus, mi]) - } - 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 (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", - - // 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, true); - 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 - }); - - // \hbox is provided for compatibility with LaTeX functions that act on a box. - // This function by itself doesn't do anything but set scriptlevel to \textstyle - // and 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 newStyle = style.withLevel(StyleLevel.TEXT); - const mrow = buildExpressionRow(group.body, newStyle); - return consolidateText(mrow) - } - }); - - const mathmlBuilder$4 = (group, style) => { - const accentNode = stretchy.mathMLnode(group.label); - accentNode.style["math-depth"] = 0; - 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); - if (dimension.number < 0) { - node.style.marginLeft = 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 - let strut; - if (group.alignment === "llap") { - // We need an invisible strut with the same depth as the group. - // We can't just read the depth, so we use \vphantom methods. - const phantomInner = buildExpression(ordargument(group.body), style); - const phantom = new mathMLTree.MathNode("mphantom", phantomInner); - strut = new mathMLTree.MathNode("mpadded", [phantom]); - strut.setAttribute("width", "0px"); - } - - const inner = buildGroup$1(group.body, style); - let node; - if (group.alignment === "llap") { - inner.style.position = "absolute"; - inner.style.right = "0"; - inner.style.bottom = `0`; // If we could have read the ink depth, it would go here. - node = new mathMLTree.MathNode("mpadded", [strut, inner]); - } else { - node = new mathMLTree.MathNode("mpadded", [inner]); - } - - 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"); - if (group.alignment === "llap") { - node.style.position = "relative"; - } else { - node.style.display = "flex"; - node.style.justifyContent = "center"; - } - } - 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"]; - - const padding = width => { - const node = new mathMLTree.MathNode("mspace"); - node.setAttribute("width", width + "em"); - return node - }; - - 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"; - if (node.children.length === 1 && node.children[0].text && node.children[0].text === "∇") { - node.setAttribute("mathvariant", "normal"); - } - } else { - node = new mathMLTree.MathNode("mi", inner); - } - } else { - node = new mathMLTree.MathNode("mrow", inner); - 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("mrow", 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 (node.type === "mrow") { - if (doSpacing ) { - if (group.mclass === "mbin") { - // medium space - node.children.unshift(padding(0.2222)); - node.children.push(padding(0.2222)); - } else if (group.mclass === "mrel") { - // thickspace - node.children.unshift(padding(0.2778)); - node.children.push(padding(0.2778)); - } else if (group.mclass === "mpunct") { - node.children.push(padding(0.1667)); - } else if (group.mclass === "minner") { - node.children.unshift(padding(0.0556)); // 1 mu is the most likely option - node.children.push(padding(0.0556)); - } - } - } else { - 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 (symbols[parser.mode][arg.text]) { - mord.text += symbols[parser.mode][arg.text].replace; - } else 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, true); - return inner[0] - } else { - return buildExpressionRow(group.body, style) - } - } - }); - - // 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"]; - - // 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 setSpacing = node => { - // The user wrote a \mathop{…} function. Change spacing from default to OP spacing. - // The most likely spacing for an OP is a thin space per TeXbook p170. - node.attributes.lspace = "0.1667em"; - node.attributes.rspace = "0.1667em"; - }; - - 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 (noSuccessor.includes(group.name)) { - node.setAttribute("largeop", "false"); - } else { - node.setAttribute("movablelimits", "false"); - } - if (group.fromMathOp) { setSpacing(node); } - } else if (group.body) { - // This is an operator with children. Add them. - node = new MathNode("mo", buildExpression(group.body, style)); - if (group.fromMathOp) { setSpacing(node); } - } 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")]); - const row = [node, operator]; - // Set spacing - if (group.needsLeadingSpace) { - const lead = new MathNode("mspace"); - lead.setAttribute("width", "0.1667em"); // thin space. - row.unshift(lead); - } - if (!group.isFollowedByDelimiter) { - const trail = new MathNode("mspace"); - trail.setAttribute("width", "0.1667em"); // thin space. - row.push(trail); - } - node = new MathNode("mrow", row); - } - } - - 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", - "\u2a09": "\\bigtimes" - }; - - defineFunction({ - type: "op", - names: [ - "\\coprod", - "\\bigvee", - "\\bigwedge", - "\\biguplus", - "\\bigcap", - "\\bigcup", - "\\intop", - "\\prod", - "\\sum", - "\\bigotimes", - "\\bigoplus", - "\\bigodot", - "\\bigsqcap", - "\\bigsqcup", - "\\bigtimes", - "\\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, - fromMathOp: true, - 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 && ordTypes.includes(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 && ordTypes.includes(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++) { - let node = expression[i]; - if (node instanceof mathMLTree.MathNode) { - if (node.type === "mrow" && node.children.length === 1 && - node.children[0] instanceof mathMLTree.MathNode) { - node = node.children[0]; - } - 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 - && ["mover", "munder"].includes(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); - if (expression[0].text.length === 1) { - 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")]); - const fragment = [wrapper, operator]; - 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. - fragment.unshift(space); - } - if (!group.isFollowedByDelimiter) { - const trail = new mathMLTree.MathNode("mspace"); - trail.setAttribute("width", "0.1667em"); // thin space. - fragment.push(trail); - } - return mathMLTree.newDocumentFragment(fragment) - } - - 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; - const next = parser.gullet.future().text; - return { - type: "operatorname", - mode: parser.mode, - body: ordargument(body), - alwaysHandleSupSub: (funcName === "\\operatornamewithlimits"), - limits: false, - parentIsSupSub: false, - isFollowedByDelimiter: isDelimiter(next), - needsLeadingSpace: prevAtomType.length > 0 && ordTypes.includes(prevAtomType) - }; - }, - mathmlBuilder: mathmlBuilder$1 - }); - - defineMacro("\\operatorname", - "\\@ifstar\\operatornamewithlimits\\operatorname@"); - - defineFunctionBuilders({ - type: "ordgroup", - mathmlBuilder(group, style) { - return buildExpressionRow(group.body, style, group.semisimple); - } - }); - - 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; - } - }); - - // In LaTeX, \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 font-weight:bold. - - 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", "font-weight:bold"); - return node - } - }); - - // \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); - // Add padding, which acts to increase height in Chromium. - // TODO: Figure out some way to change height in Firefox w/o breaking Chromium. - if (dy.number > 0) { - node.style.padding = dy.number + dy.unit + " 0 0 0"; - } else { - node.style.padding = "0 0 " + Math.abs(dy.number) + dy.unit + " 0"; - } - 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: "reflect", - names: ["\\reflectbox"], - props: { - numArgs: 1, - argTypes: ["hbox"], - allowedInText: true - }, - handler({ parser }, args) { - return { - type: "reflect", - mode: parser.mode, - body: args[0] - }; - }, - mathmlBuilder(group, style) { - const node = buildGroup$1(group.body, style); - node.style.transform = "scaleX(-1)"; - 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, true); - 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, true); - - 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 appendSpace = 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; - appendSpace = appendApplyFunction && !group.isFollowedByDelimiter; - 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) { - const sup = buildGroup$1(group.sup, childStyle); - const testNode = sup.type === "mrow" ? sup.children[0] : sup; - if ((testNode && testNode.type === "mo" && testNode.classes.includes("tml-prime")) - && group.base && group.base.text && group.base.text === "f") { - // Chromium does not address italic correction on prime. Prevent f′ from overlapping. - testNode.classes.push("prime-pad"); - } - children.push(sup); - } - - 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]); - } - if (appendSpace) { - const space = new mathMLTree.MathNode("mspace"); - space.setAttribute("width", "0.1667em"); // thin space. - node.children.push(space); - } - } 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"]; - - const arrows = ["\\Rsh", "\\Lsh", "\\restriction"]; - - const isArrow = str => { - if (str.length === 1) { - const codePoint = str.codePointAt(0); - return (0x218f < codePoint && codePoint < 0x2200) - } - return str.indexOf("arrow") > -1 || str.indexOf("harpoon") > -1 || arrows.includes(str) - }; - - 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 (group.family === "rel" && isArrow(group.text)) { - 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" - }; - - /** - * 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" - } - - 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 0x1D317 }, - "italic": ch => { return 0x1D351 }, - // \boldsymbol actually returns upright bold for upperCaseGreek - "bold-italic": ch => { return 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 0x1D3C5 }, - "sans-serif-bold": ch => { return 0x1D3C5 }, - "sans-serif-italic": ch => { return 0 }, - "sans-serif-bold-italic": ch => { return 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) - ? "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,.]*\d)?$/; - const latinRegEx = /[A-Ba-z]/; - const primes = new Set(["\\prime", "\\dprime", "\\trprime", "\\qprime", - "\\backprime", "\\backdprime", "\\backtrprime"]); - - const italicNumber = (text, variant, tag) => { - const mn = new mathMLTree.MathNode(tag, [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("mrow", [node]); - } - } - 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 (numberRegEx.test(group.text)) { - const tag = group.mode === "text" ? "mtext" : "mn"; - if (variant === "italic" || variant === "bold-italic") { - return italicNumber(text, variant, tag) - } else { - if (variant !== "normal") { - text.text = text.text.split("").map(c => variantChar(c, variant)).join(""); - } - node = new mathMLTree.MathNode(tag, [text]); - } - } else if (group.mode === "text") { - if (variant !== "normal") { - text.text = variantChar(text.text, variant); - } - node = new mathMLTree.MathNode("mtext", [text]); - } else if (primes.has(group.text)) { - node = new mathMLTree.MathNode("mo", [text]); - // TODO: If/when Chromium uses ssty variant for prime, remove the next line. - node.classes.push("tml-prime"); - } 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 consolidateText(mrow) - } - }); - - 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 - "([!-\\[\\]-\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(tokenRegexString, '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 local `set` take constant time, while global - * `set` takes time proportional to the depth of group nesting. - */ - - 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 optionally set it globally too. - * Local set() sets the current value and (when appropriate) adds an undo - * operation to the undo stack. Global set() may change the undo - * operation at every level, so takes time linear in their number. - */ - set(name, value, global = false) { - if (global) { - // Global set is equivalent to setting in all groups. Simulate this - // by destroying any undos currently scheduled for this name, - // and adding an undo with the *new* value (in case it later gets - // locally reset within this environment). - for (let i = 0; i < this.undefStack.length; i++) { - delete this.undefStack[i][name]; - } - if (this.undefStack.length > 0) { - this.undefStack[this.undefStack.length - 1][name] = value; - } - } else { - // 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}}`; - }); - - function recreateArgStr(context) { - // Recreate the macro's original argument string from the array of parse tokens. - const tokens = context.consumeArgs(1)[0]; - let str = ""; - let expectedLoc = tokens[tokens.length - 1].loc.start; - for (let i = tokens.length - 1; i >= 0; i--) { - const actualLoc = tokens[i].loc.start; - if (actualLoc > expectedLoc) { - // context.consumeArgs has eaten a space. - str += " "; - expectedLoc = actualLoc; - } - str += tokens[i].text; - expectedLoc += tokens[i].text.length; - } - return str - } - - // The Latin Modern font renders at the wrong vertical alignment. - // This macro provides a better rendering. - defineMacro("\\surd", '\\sqrt{\\vphantom{|}}'); - - // See comment for \oplus in symbols.js. - defineMacro("\u2295", "\\oplus"); - - // 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", "{\\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}"); - - // \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", - "\\bigtimes": "\\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 (["bin", "rel"].includes(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"); - - defineMacro("\\AA", "\\TextOrMath{\\Angstrom}{\\mathring{A}}\\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}"); - - ////////////////////////////////////////////////////////////////////// - // MnSymbol.sty - - defineMacro("\\leftmodels", "\\mathop{\\reflectbox{$\\models$}}"); - - ////////////////////////////////////////////////////////////////////// - // 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"); - // A helper for \Braket and \Set - const replaceVert = (argStr, match) => { - const ch = match[0] === "|" ? "\\vert" : "\\Vert"; - const replaceStr = `}\\,\\middle${ch}\\,{`; - return argStr.slice(0, match.index) + replaceStr + argStr.slice(match.index + match[0].length) - }; - defineMacro("\\Braket", function(context) { - let argStr = recreateArgStr(context); - const regEx = /\|\||\||\\\|/g; - let match; - while ((match = regEx.exec(argStr)) !== null) { - argStr = replaceVert(argStr, match); - } - return "\\left\\langle{" + argStr + "}\\right\\rangle" - }); - defineMacro("\\Set", function(context) { - let argStr = recreateArgStr(context); - const match = /\|\||\||\\\|/.exec(argStr); - if (match) { - argStr = replaceVert(argStr, match); - } - return "\\left\\{\\:{" + argStr + "}\\:\\right\\}" - }); - defineMacro("\\set", function(context) { - const argStr = recreateArgStr(context); - return "\\{{" + argStr.replace(/\|/, "}\\mid{") + "}\\}" - }); - - ////////////////////////////////////////////////////////////////////// - // 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 the number of such tokens will be - * returned. This number might be zero or positive. - * - * If not, the return value is `false`, and the next token remains at the - * top of the stack. - * - * In either case, the next token will be on the top of the stack, - * or the stack will be empty (in case of empty expansion - * and no other tokens). - * - * 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 false; - } - 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.length; - } - - /** - * 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 (;;) { - if (this.expandOnce() === false) { // fully expanded - const token = this.stack.pop(); - // The token after \noexpand is interpreted as if its meaning were ‘\relax’ - if (token.treatAsRelax) { - token.text = "\\relax"; - } - return token - } - } - - // 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) { - // Expand only expandable tokens - if (this.expandOnce(true) === false) { // fully expanded - const token = this.stack.pop(); - if (token.treatAsRelax) { - // the expansion of \noexpand is the token itself - token.noexpand = false; - token.treatAsRelax = false; - } - output.push(token); - } - } - 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; - } - } - - // 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': 'θ' - }); - - // Used for Unicode input of calligraphic and script letters - const asciiFromScript = Object.freeze({ - "\ud835\udc9c": "A", - "\u212c": "B", - "\ud835\udc9e": "C", - "\ud835\udc9f": "D", - "\u2130": "E", - "\u2131": "F", - "\ud835\udca2": "G", - "\u210B": "H", - "\u2110": "I", - "\ud835\udca5": "J", - "\ud835\udca6": "K", - "\u2112": "L", - "\u2133": "M", - "\ud835\udca9": "N", - "\ud835\udcaa": "O", - "\ud835\udcab": "P", - "\ud835\udcac": "Q", - "\u211B": "R", - "\ud835\udcae": "S", - "\ud835\udcaf": "T", - "\ud835\udcb0": "U", - "\ud835\udcb1": "V", - "\ud835\udcb2": "W", - "\ud835\udcb3": "X", - "\ud835\udcb4": "Y", - "\ud835\udcb5": "Z" - }); - - // 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 binLeftCancellers = ["bin", "op", "open", "punct", "rel"]; - - /** - * 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", "&"]; - } - - /** - * Fully parse a separate sequence of tokens as a separate job. - * Tokens should be specified in reverse order, as in a MacroDefinition. - */ - subparse(tokens) { - // Save the next token from the current job. - const oldToken = this.nextToken; - this.consume(); - - // Run the new job, terminating it with an excess '}' - this.gullet.pushToken(new Token("}")); - this.gullet.pushTokens(tokens); - const parse = this.parseExpression(false); - this.expect("}"); - - // Restore the next token from the current job. - this.nextToken = oldToken; - - return parse; - } - - /** - * 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 precedence 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. - * - * `breakOnMiddle`: \color, \over, and old styling functions work on an implicit group. - * These groups end just before the usual tokens, but they also - * end just before `\middle`. - */ - parseExpression(breakOnInfix, breakOnTokenText, breakOnMiddle) { - 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 (breakOnMiddle && lex.text === "\\middle") { - 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. - const isSub = unicodeSubRegEx.test(lex.text); - const subsupTokens = []; - subsupTokens.push(new Token(uSubsAndSups[lex.text])); - this.consume(); - // Continue fetching tokens to fill out the group. - while (true) { - const token = this.fetch().text; - if (!(uSubsAndSups[token])) { break } - if (unicodeSubRegEx.test(token) !== isSub) { break } - subsupTokens.unshift(new Token(uSubsAndSups[token])); - this.consume(); - } - // Now create a (sub|super)script. - const body = this.subparse(subsupTokens); - 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 - const isFollowedByDelimiter = (!base || base.type !== "op" && base.type !== "operatorname") - ? undefined - : isDelimiter(this.nextToken.text); - return { - type: "supsub", - mode: this.mode, - base: base, - sup: superscript, - sub: subscript, - isFollowedByDelimiter - } - } - } 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 (true) { - const ch = this.fetch().text; - // \ufe0e is the Unicode variation selector to supress emoji. Ignore it. - if (ch === " " || ch === "\u00a0" || ch === "\ufe0e") { - this.consume(); - } else { - break - } - } - } - - /** - * 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/ - 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]) { - let group = symbols[this.mode][text].group; - if (group === "bin" && binLeftCancellers.includes(this.prevAtomType)) { - // Change from a binary operator to a unary (prefix) operator - group = "open"; - } - 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 { - if (asciiFromScript[text]) { - // Unicode 14 disambiguates chancery from roundhand. - // See https://www.unicode.org/charts/PDF/U1D400.pdf - this.consume(); - const nextCode = this.fetch().text.charCodeAt(0); - // mathcal is Temml default. Use mathscript if called for. - const font = nextCode === 0xfe01 ? "mathscr" : "mathcal"; - if (nextCode === 0xfe00 || nextCode === 0xfe01) { this.consume(); } - return { - type: "font", - mode: "math", - font, - body: { type: "mathord", mode: "math", loc, text: asciiFromScript[text] } - } - } - // Default ord character. No disambiguation necessary. - s = { - type: group, - mode: this.mode, - loc, - text - }; - } - symbol = s; - } else if (text.charCodeAt(0) >= 0x80) { - // no symbol for e.g. ^ - if (this.settings.strict && 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, - 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, - * 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.10.25"; - - 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 */ - - /** - * @type {import('./temml').render} - * Parse and build an expression, and place that expression in the DOM node - * given. - */ - let render = function(expression, baseNode, options = {}) { - baseNode.textContent = ""; - const alreadyInMathElement = baseNode.tagName.toLowerCase() === "math"; - if (alreadyInMathElement) { options.wrap = "none"; } - const math = renderToMathMLTree(expression, options); - if (alreadyInMathElement) { - // The element already exists. Populate it. - baseNode.textContent = ""; - math.children.forEach(e => { baseNode.appendChild(e.toNode()); }); - } else if (math.children.length > 1) { - 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."); - }; - } - } - - /** - * @type {import('./temml').renderToString} - * Parse and build an expression, and return the markup for that. - */ - const renderToString = function(expression, options) { - const markup = renderToMathMLTree(expression, options).toMarkup(); - return markup; - }; - - /** - * @type {import('./temml').generateParseTree} - * Parse an expression and return the parse tree. - */ - const generateParseTree = function(expression, options) { - const settings = new Settings(options); - return parseTree(expression, settings); - }; - - /** - * @type {import('./temml').definePreamble} - * 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; - }; - - /** - * @type {import('./temml').renderToMathMLTree} - * 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); - } - }; - - /** @type {import('./temml').default} */ - 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 4236f81b..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, - * 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.10.25"; - - 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.cjs b/test/unit-test.cjs deleted file mode 100644 index ce8e5d87..00000000 --- a/test/unit-test.cjs +++ /dev/null @@ -1,2367 +0,0 @@ -const temml = require("../utils/temml.cjs") - -/* - * Unit tests for Temml. - * This file contains more than 1300 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 wrapSettings = str => new Settings({ wrap: str }); -const mathTagRegEx = /<\/?math>/g; - -// tagging literal -const r = x => x != null && Object.prototype.hasOwnProperty.call(x, 'raw') ? x.raw[0] : x; - -class ParseError { - constructor(message = "", token = {}) { - this.message = message - this.token = token - } -} - -const deflt = function(setting, defaultIfUndefined) { - return setting === undefined ? defaultIfUndefined : setting; -} - -class Settings { - constructor(options) { - // allow null options - options = options || {}; - this.displayMode = deflt(options.displayMode, false); // boolean - this.annotate = deflt(options.annotate, false) // boolean - this.leqno = deflt(options.leqno, false); // boolean - this.errorColor = deflt(options.errorColor, "#b22222"); // string - this.macros = options.macros || {}; - this.wrap = deflt(options.wrap, "tex") // "tex" | "=" - this.xml = deflt(options.xml, false); // boolean - this.colorIsTextColor = deflt(options.colorIsTextColor, false); // booelean - this.strict = deflt(options.strict, false); // boolean - this.trust = 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, deflt(options.maxExpand, 1000)); // number - } - - 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); - } -} - -function getProtocolViaTrust(url) { - let protocol; - parse(`\\url{${url}}`, new Settings({ - trust: context => protocol = context.protocol, - })); - return protocol; -} - -// 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 = temml.__parse(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.") } - } - - toBeFalsy() { - numTests += 1 - if (this.input) { say(this.input + " is 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") - new Expect("\u00a0\ufe0e" + `x ^ y `).toParseLike("x^y") - - assertion = "Temml should consolidate numbers into a single element" - let nodes = build(`12.34`) - new Expect(nodes.length).toBe(1) - new Expect(nodes[0].type).toBe("mn") - nodes = build(`12.34`) - new Expect(nodes.length).toBe(1) - new Expect(nodes[0].type).toBe("mn") - assertion = "Temml should split numbers if a space follows a comma" - let markup = temml.renderToString(`12, 340`) - new Expect(markup).toBe('12,340') - - 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 bins" - nodes = parse(r`1 + 2 - 3 * 4 \cdot 5 \pm 6 \div 7`) - for (let i = 1; i < nodes.length; i+=2) { - new Expect(nodes[i].type).toBe("atom"); - new Expect(nodes[i].family).toBe("bin"); - } - - assertion = "Parser should change bins to opens when they should be unary" - nodes = parse(r`a = -1 \ast (-4) \pm {+5} + \sin -2 x^{-2} \ast 3 \sum -c + \dots + d`) - for (const i of [4, 9, 11, 16, 21, 23]) { - new Expect(nodes[i].type).toBe("atom"); - new Expect(nodes[i].family).toBe("bin"); - } - for (const i of [2, 6, 13, 19]) { - new Expect(nodes[i].type).toBe("atom"); - new Expect(nodes[i].family).toBe("open"); - } - - 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 = "Empty super and subscripts should work" - new Expect("x^{}").toBuild(); - new Expect("x^{}_{}").toBuild(); - new Expect("x^{}_2").toBuild(); - new Expect("x^2_{}").toBuild(); - new Expect("x_{}").toBuild(); - - assertion = "A row builder should work when given a document fragment" - new Expect((build(`x^{\color{red}{hello}}`))[0].children.length).toBe(2) - new Expect((build(`x^{\color{red}{hello}}`))[0].children[1].type).toBe("mrow") - - 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} + ^{2}C + E_{2}^{3} + F_{2+3}") - new Expect(r`\text{B²⁺³}`).toParse() - new Expect(r`\text{B²⁺³}`).toBuild() - - assertion = "A supsub parser should merge a numeric base with a preceding number" - new Expect(temml.renderToString(r`123^4`)).toContain("123") - - 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(nodes[0].semisimple).toBeFalsy(); - 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).toBe(true); - - 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 = "An implicit group parser should work within environment arrays" - node = parse(r`\begin{array}{l}\color{red}a\\ b \\ c \end{array}`)[0]; - new Expect(node.type).toBe("array") - new Expect(node.body.length).toBe(3) - - assertion = "A semi-simple group builder should not affect spacing of operators" - markup = temml.renderToString(r`1\begingroup + 2 *\endgroup 3`) - new Expect(markup).toNotContain("lspace") - new Expect(markup).toNotContain("rspace") - assertion = "A braced group builder should change spacing of operators at ends of group" - markup = temml.renderToString(r`1{+ 2 *}3`) - new Expect(markup).toContain("lspace") - new Expect(markup).toContain("rspace") - - 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(); - 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(); - // Check for duplication of text. Prevent reoccurence of issue #9. - node = parse(r`\text{MMö}`)[0]; - new Expect(node.body[0].text).toBe("M") - - 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("enclose"); - - 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)`); - new Expect(temml.renderToString(r`\left\{a\over2\middle|b\right\}`)).toContain("a2") - - 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(); - new Expect(r`\begin{matrix}a&b\\ [c]&d\end{matrix}`).toParse() - new Expect(r`a\\ [b]`).toParse() - - 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(); - 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 \\boldsymbol builder should work" - new Expect(temml.renderToString(r`\boldsymbol{A}`)).toContain("𝑨") - new Expect(temml.renderToString(r`\boldsymbol{\mathrm{b}}`)).toContain('style="font-weight:bold;"') - - 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" - 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`\nabla`).replace(mathTagRegEx, ""); - new Expect(markup).toBe(''); - markup = temml.renderToString(r`\mathord\nabla`).replace(mathTagRegEx, ""); - new Expect(markup).toBe(''); - 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).toBe('Ax2kωΩı'); - 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 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("Max") - - assertion = "href and url commands should build their input" - new Expect(r`\href{http://example.com/}{\sin}`).toParse(trustSettings()) - new Expect("\\url{http://example.com/}").toParse(trustSettings()) - assertion = "href and url commands should allow empty URLs" - new Expect(r`\href{}{example here}`).toParse(trustSettings()) - new Expect("\\url{}").toParse(trustSettings()) - new Expect(r`\href{http://example.com/}{\sin}`).toBuild(trustSettings()) - new Expect("\\url{http://example.com/}").toBuild(trustSettings()) - assertion = "href and url commands should allow empty URLs" - new Expect(r`\href{}{example here}`).toBuild(trustSettings()) - new Expect("\\url{}").toBuild(trustSettings()) - assertion = "href and url commands should allow single-character URLs" - new Expect(r`\href%end`).toParseLike("\\href{%}end", trustSettings()) - new Expect("\\url%end").toParseLike("\\url{%}end", trustSettings()) - new Expect("\\url%%end\n").toParseLike("\\url{%}", trustSettings()) - new Expect("\\url end").toParseLike("\\url{e}nd", trustSettings()) - new Expect("\\url%end").toParseLike("\\url {%}end", trustSettings()) - assertion = "href and url commands should allow spaces ad single-character URLs" - new Expect(r`\href %end`).toParseLike("\\href{%}end", trustSettings()) - new Expect("\\url %end").toParseLike("\\url{%}end", trustSettings()) - assertion = "href and url commands should allow [#$%&~_^] without escaping" - let url = "http://example.org/~bar/#top?foo=$foo&bar=ba^r_boo%20baz"; - node = parse(`\\href{${url}}{\\alpha}`, trustSettings())[0]; - new Expect(node.href).toBe(url); - node = parse(`\\url{${url}}`, trustSettings())[0]; - new Expect(node.href).toBe(url); - assertion = "href and url commands should allow balanced braces in url" - node = parse(`\\href{${url}}{\\alpha}`, trustSettings())[0]; - new Expect(node.href).toBe(url); - url = "http://example.org/{{}t{oo}}"; - node = parse(`\\href{${url}}{\\alpha}`, trustSettings())[0]; - new Expect(node.href).toBe(url); - node = parse(`\\url{${url}}`, trustSettings())[0]; - new Expect(node.href).toBe(url); - assertion = "href and url commands should not allow balanced braces in url" - new Expect(r`\href{http://example.com/{a}{bar}`).toNotParse(trustSettings()) - new Expect(r`\href{http://example.com/}a}{bar}`).toNotParse(trustSettings()) - new Expect(`\\url{http://example.com/{a}`).toNotParse(trustSettings()) - new Expect(`\\url{http://example.com/}a}`).toNotParse(trustSettings()) - assertion = "href and url commands should allow for escapes in [#$%&~_^]" - url = "http://example.org/~bar/#top?foo=$}foo{&bar=bar^r_boo%20baz"; - url = url.replace(/([#$%&~_^{}])/g, '\\$1'); - new Expect(`\\href{${url}}{\\alpha}`).toParse(trustSettings()) - new Expect(`\\url{${url}}`).toParse(trustSettings()); - new Expect(`\\href{${url}}{\\alpha}`).toBuild(trustSettings()) - new Expect(`\\url{${url}}`).toBuild(trustSettings()); - assertion = "href and url commands should allow comments after URLs" - new Expect("\\url{http://example.com/}%comment\n").toParse(trustSettings()) - new Expect("\\url{http://example.com/}%comment\n").toBuild(trustSettings()) - - assertion = "href and url commands should allow relative URLs when trust option is false" - markup = temml.renderToString("\\href{relative}{foo}") - new Expect(markup).toContain("#b22222") // color of error message - - assertion = "href and url commands should not allow explicitly disallowed protocols" - new Expect("\\href{ftp://x}{foo}").toParse(new Settings({trust: (context) => 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"})) - new Expect("\\href{JavaScript:alert('x')}{foo}").toNotParse(new Settings({trust: context => context.protocol !== "javascript"})) - new Expect("\\url{!:}").toNotParse() - new Expect("\\url{foo:}").toNotParse() - new Expect("\\url{://foo}").toNotParse() - - assertion = "href and url commands should get protocols correctly" - new Expect (getProtocolViaTrust("foo")).toBe("_relative") - new Expect (getProtocolViaTrust("Foo:")).toBe("foo") - new Expect (getProtocolViaTrust("Foo:bar")).toBe("foo") - new Expect (getProtocolViaTrust("JavaScript:")).toBe("javascript") - new Expect (getProtocolViaTrust("JavaScript:code")).toBe("javascript") - new Expect (getProtocolViaTrust("?query=string&colon=")).toBe("_relative") - new Expect (getProtocolViaTrust("#query=string&colon=")).toBe("_relative") - new Expect (getProtocolViaTrust("dir/file&colon")).toBe("_relative") - new Expect (getProtocolViaTrust("//foo")).toBe("_relative") - new Expect (getProtocolViaTrust(" \t http://")).toBe("http") - new Expect (getProtocolViaTrust(" \t http://foo")).toBe("http") - - 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, \\gdef defines macros" - new Expect(r`\gdef\foo{x^2}\foo+\foo`).toParseLike(`x^2+x^2`) - new Expect(r`\gdef\foo{hi}\foo+\text\foo`).toParseLike(r`hi+\text{hi}`) - new Expect(r`\gdef\foo#1{hi #1}\text{\foo{Alice}, \foo{Bob}}`).toParseLike(r`\text{hi Alice, hi Bob}`) - new Expect(r`\gdef\foo#1#2{(#1,#2)}\foo 1 2+\foo 3 4`).toParseLike(r`(1, 2)+(3, 4)`) - new Expect(r`\gdef\foo#a{}`).toNotParse() - new Expect(r`\gdef\foo#1#2#3#4#5#6#7#8#9{}`).toParse() - new Expect(r`\gdef\foo#2{}`).toNotParse() - new Expect(r`\gdef\foo#1#2#3#4#5#6#7#8#9#10{}`).toNotParse() - new Expect(r`\gdef\foo1`).toNotParse() - new Expect(r`\gdef{\foo}{}`).toNotParse() - new Expect(r`\gdef\foo\bar`).toNotParse() - new Expect(r`\gdef{\foo\bar}{}`).toNotParse() - new Expect(r`\gdef{}{}`).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, \\gdef defines macros with delimited parameter" - new Expect(r`\gdef\foo|#1||{#1}\text{\foo| x y ||}`).toParseLike(r`\text{ x y }`) - new Expect(r`\gdef\foo#1|#2{#1+#2}\foo a 2 |34`).toParseLike(r`a2+34`) - new Expect(r`\gdef\foo#1#{#1}\foo1^{23}`).toParseLike(r`1^{23}`) - new Expect(r`\gdef\foo|{}\foo`).toNotParse() - new Expect(r`\gdef\foo#1|{#1}\foo1`).toNotParse() - new Expect(r`\gdef\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 = "\\def should be handled in Parser" - new Expect(r`\gdef\foo{1}`).toParse(new Settings({maxExpand: 0})) - new Expect(r`2^\def\foo{1}2`).toNotParse() - - assertion = "\\def works locally" - new Expect("\\def\\x{1}\\x{\\def\\x{2}\\x{\\def\\x{3}\\x}\\x}\\x").toParseLike(`1{2{3}2}1`) - - assertion = "\\gdef overrides at all levels" - new Expect("\\def\\x{1}\\x{\\def\\x{2}\\x{\\gdef\\x{3}\\x}\\x}\\x").toParseLike(`1{2{3}3}3`) - new Expect("\\def\\x{1}\\x{\\def\\x{2}\\x{\\global\\def\\x{3}\\x}\\x}\\x").toParseLike(`1{2{3}3}3`) - - assertion = "\\global needs to followed by macro prefixes, \\def or \\edef" - new Expect(r`\global\def\foo{}\foo`).toParseLike("") - new Expect(r`\global\edef\foo{}\foo`).toParseLike("") - new Expect(r`\def\DEF{\def}\global\DEF\foo{}\foo`).toParseLike("") - new Expect(r`\global\global\def\foo{}\foo`).toParseLike("") - new Expect(r`\global\long\def\foo{}\foo`).toParseLike("") - new Expect(r`\global\foo`).toNotParse() - new Expect(r`\global\bar x`).toNotParse() - - assertion = "\\gdef changes settings.macros" - let macros = {}; - new Expect(r`\gdef\foo{1}`).toParse(new Settings({macros})) - new Expect(macros["\\foo"]).toBeTruthy() - - assertion = "\\def doesn't change settings.macros" - macros = {} - new Expect(r`\def\foo{1}`).toParse(new Settings({macros})) - new Expect(macros["\\foo"]).toBeFalsy() - - 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`) - new Expect(temml.renderToString(r`\Set{\color{red}222|11111}`)).toContain('222|') - new Expect(temml.renderToString(r`\Set{a\over b}`)).toContain('ab') - new Expect(temml.renderToString(r`\Set{a\over b | c}`)).toContain('ab') - new Expect(temml.renderToString(r`\Set{a\over b || c}`)).toContain('‖') - - 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." - 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('class="tml-left"') - 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(`ÀÁÂÃÄÅÈÉÊËÌÍÎÏÑÒÓÔÕÖÙÚÛÜÝàáâãäåèéêëìíîïñòóôõöùúûüýÿ`).toBuildLike( - 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{ÀÁÂÃÄÅÈÉÊËÌÍÎÏÑÒÓÔÕÖÙÚÛÜÝàáâãäåèéêëìíîïñòóôõöùúûüýÿ}`).toBuildLike( - 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").toBuildLike(r`Á\acute C`); - new Expect("\\text{A\u0301C\u0301}").toBuildLike(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(`íȷ́`).toBuildLike(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() - new Expect(temml.renderToString("ℓ")).toContain("ℓ") - 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 = "Unicode script characters should parse correctly." - wideCharText = String.fromCharCode(0xD835, 0xdcaa); // Script O - markup = temml.renderToString(wideCharText) - new Expect(markup).toContain('class="mathcal"') - wideCharText = String.fromCharCode(0xD835, 0xdcaa, 0xfe01); // Trailing U_FE01 per Unicode 14 - markup = temml.renderToString(wideCharText) - new Expect(markup).toContain('class="mathscr"') - - 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})) - new Expect(r`\edef0{x}\edef0{00}\edef0{00}\edef0{00}\edef0{00}`).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 = "Newlines should cause left-justified lines." - markup = temml.renderToString(r`a + b \\ c + d`) - new Expect([...markup.matchAll(/text-align:left/g)].length).toBe(2) - - 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 = "\\AA should render upright in text mode and italic in math mode" - new Expect(temml.renderToString(r`\text{\AA}`)).toContain("Å") - new Expect(temml.renderToString(r`\AA`)).toContain("A") - - assertion = "Settings should allow unicode text when not strict" - new Expect(`é`).toParse() - new Expect(`試`).toParse() - - assertion = "Settings should forbid math-mode unicode text when strict" - new Expect(`é`).toNotParse(strictSettings()) - new Expect(`試`).toNotParse(strictSettings()); - - assertion = "Unicode characters inside \\text{} should parse" - new Expect(`\text{é}`).toParse() - new Expect(`\text{試}`).toParse() - - assertion = "Line-wrapping should work" - const wrapExpression = r`x = a \textcolor{blue}{+ a + a} = b + b + b`; - new Expect(wrapExpression).toParse() - new Expect(wrapExpression).toBuild(); - new Expect(wrapExpression).toBuild(wrapSettings("none")); - new Expect(wrapExpression).toBuild(wrapSettings("tex")); - new Expect(wrapExpression).toBuild(wrapSettings("=")); - // Line wrapping works by creating a series of elements. - // We check for regression by counting the number of elements. - new Expect(build(wrapExpression, wrapSettings("tex"))[0].children.length).toBe(7) - new Expect(build(wrapExpression, wrapSettings("="))[0].children.length).toBe(2) - new Expect(build(r`x^{\textcolor{red}{-yz}}`)[0].children.length).toBe(2) - - 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 7fbfad90..00000000 --- a/test/wiki-tests.md +++ /dev/null @@ -1,945 +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 \rceil | \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. I know of no servable math font that has glyphs\ -for regular-weight Greek sans-serif. Consequently, 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}}}}$ | -+-----+----------------------------------------------+-------------------------------------------------+ - -The next line tests the length of an extensible arrow. Since Firefox does not\ -support the `minsize` attribute, Temml has a workaround. The middle arrow\ -should be as long at the bar between C & D. - -+=====+====================================+====================================+ -| 266 | A \rightarrow B \xrightarrow{i} C\ | $A \rightarrow B \xrightarrow{i} C | -| | \rule[0.3em]{1.75em}{0.05em} D | \rule[0.3em]{1.75em}{0.05em} D$ | -+-----+------------------------------------+------------------------------------+ - -The next line tests the fix for Temml issue #21. Firefox would ordinarily omit\ -the dot on the i below. It's fixed by a Temml CSS rule, so it renders properly. - -+=====+=================+===================+ -| 267 | \widetilde{U_i} | $\widetilde{U_i}$ | -+-----+-----------------+-------------------+ - - -
- - 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 9419041d..00000000 --- a/utils/buildDocs.js +++ /dev/null @@ -1,97 +0,0 @@ -const fs = require("fs") // Node.js file system -const hurmet = require('./hurmet.cjs'); -const temml = require('./temml.cjs'); -const katex = require('./katex.min.js'); -const TeXZilla = require("./TeXZilla.js"); -// eslint-disable-next-line no-undef -globalThis.temml = temml; - -// The main Hurmet function has to be async because it contains an 'await' statement. -(async function main() { - // Build supported.html. - let supported = fs.readFileSync('./docs/supported.md').toString('utf8') - // convert Markdown to HTML - supported = await hurmet.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 = await hurmet.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 = await hurmet.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 1666ccb1..00000000 --- a/utils/buildTests.js +++ /dev/null @@ -1,33 +0,0 @@ -const fs = require("fs") // Node.js file system -const temml = require('./temml.cjs'); -const hurmet = require("./hurmet.cjs"); -// eslint-disable-next-line no-undef -globalThis.temml = temml; - -// The main Hurmet function has to be async because it contains an 'await' statement. -(async function main() { - let katexTests = fs.readFileSync('./test/katex-tests.md').toString('utf8') - // convert Markdown to HTML - katexTests = await hurmet.md2html(katexTests, "", true) - fs.writeFileSync('./site/tests/katex-tests.html', katexTests) - - let mhchemTests = fs.readFileSync('./test/mhchem-tests.md').toString('utf8') - mhchemTests = await hurmet.md2html(mhchemTests, "", true) - fs.writeFileSync('./site/tests/mhchem-tests.html', mhchemTests) - - let mozillaTests = fs.readFileSync('./test/mozilla-tests.md').toString('utf8') - mozillaTests = await hurmet.md2html(mozillaTests, "", true) - fs.writeFileSync('./site/tests/mozilla-tests.html', mozillaTests) - - let wikiTests = fs.readFileSync('./test/wiki-tests.md').toString('utf8') - wikiTests = await hurmet.md2html(wikiTests, "", true) - fs.writeFileSync('./site/tests/wiki-tests.html', wikiTests) - - let latexmlTests = fs.readFileSync('./test/LaTeXML-tests.md').toString('utf8') - latexmlTests = await hurmet.md2html(latexmlTests, "", true) - fs.writeFileSync('./site/tests/LaTeXML-tests.html', latexmlTests) - - let environmentTests = fs.readFileSync('./test/environment-tests.md').toString('utf8') - environmentTests = await hurmet.md2html(environmentTests, "", true) - fs.writeFileSync('./site/tests/environment-tests.html', environmentTests) -})(); diff --git a/utils/copyfiles.js b/utils/copyfiles.js deleted file mode 100644 index 29cd092d..00000000 --- a/utils/copyfiles.js +++ /dev/null @@ -1,65 +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-Libertinus.css', 'dist/Temml-Libertinus.css', (err) => { - if (err) { throw err } -}) - -fs.copyFile('site/assets/Temml-Fira.css', 'dist/Temml-Fira.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 } -}) - -fs.copyFile('temml.d.ts', 'dist/temml.d.ts', -(err) => { - if (err) { throw err } -}) diff --git a/utils/hurmet.cjs b/utils/hurmet.cjs deleted file mode 100644 index d3226305..00000000 --- a/utils/hurmet.cjs +++ /dev/null @@ -1,31088 +0,0 @@ -'use strict'; - -/* - * Hurmet, copyright (c) by Ron Kok - * Distributed under an MIT license: https://hurmet.org/LICENSE.txt - * - * Hurmet adds calculation cells to the ProseMirror rich text editor. - * See https://hurmet.org and https://hurmet.org/docs/en/manual.html - */ - -// utils.js - -const isValidIdentifier$1 = /^(?:[A-Za-zıȷ\u0391-\u03C9\u03D5\u210B\u210F\u2110\u2112\u2113\u211B\u212C\u2130\u2131\u2133]|(?:\uD835[\uDC00-\udc33\udc9c-\udcb5]))[A-Za-z0-9_\u0391-\u03C9\u03D5\u0300-\u0308\u030A\u030C\u0332\u20d0\u20d1\u20d6\u20d7\u20e1]*′*$/; -// Detect string interpolation ${varName} -const interpolateRegEx = /\$\{[^}\s]+\}/g; - -const clone = obj => { - // Clone a JavaScript object. - // That is, make a deep copy that does not contain any reference to the original object. - // This function works if the object contains only these types: - // boolean, number, bigint, string, null, undefined, date, array, object, Map - // Any other type, or non-tree structure (e.g., "this"), cannot be handled by this function. - // This is a modified version of https://stackoverflow.com/a/728694 - - // Handle boolean, number, bigint, string, null, or undefined - // eslint-disable-next-line eqeqeq - if (null == obj || "object" != typeof obj) { return obj } - - if (obj instanceof Date) { return new Date().setTime(obj.valueOf()) } - - if (Array.isArray(obj)) { - const copy = []; - for (let i = 0, len = obj.length; i < len; i++) { - copy[i] = clone(obj[i]); - } - return copy - } - - if (obj instanceof Map) { - const copy = new Map(); - for (const [key, value] of obj.entries()) { - copy.set(key, clone(value)); - } - return copy - } - - if (typeof obj === "object") { - const copy = Object.create(null); - Object.entries(obj).forEach(([key, value]) => { - copy[key] = clone(value); - }); - return copy - } - - throw new Error("Unable to clone obj! Its type isn't supported.") -}; - -// A function to return an array containing all matches to a RegEx pattern. -const arrayOfRegExMatches = (regex, text) => { - if (regex.constructor !== RegExp) { throw new Error('not RegExp') } - const result = []; - let match = null; - - /* eslint-disable no-cond-assign */ - if (regex.global) { - while (match = regex.exec(text)) { - result.push({ value: match[0], index: match.index, length: match[0].length }); - } - } else if (match = regex.exec(text)) { - result.push({ value: match[0], index: match.index, length: match[0].length }); - } - /* eslint-enable no-cond-assign */ - - return result -}; - -const textAccent = { - "\u0300": "`", - "\u0301": "'", - "\u0302": "^", - "\u0303": "~", - "\u0304": "=", - "\u0305": "=", - "\u0306": "u", - "\u0307": ".", - "\u0308": '"', - "\u030A": 'r', - "\u030c": "v" -}; - -const escapeRegEx = /[#$&%_~^]/g; -const accentRegEx$2 = /[\u0300-\u0308\u030A\u030c]/g; - -const addTextEscapes = str => { - // Insert escapes for # $ & % _ ~ ^ \ { } - // TODO: \textbackslash. - // TODO: How to escape { } without messing up Lex? - if (str.length > 1) { - let matches = arrayOfRegExMatches(escapeRegEx, str); - let L = matches.length; - if (L > 0) { - for (let i = L - 1; i >= 0; i--) { - const match = matches[i]; - const pos = match.index; - if (match.value === "~") { - str = str.slice(0, pos) + "\\textasciitilde " + str.slice(pos + 1); - } else if (match.value === "^") { - str = str.slice(0, pos) + "\\textasciicircum " + str.slice(pos + 1); - } else if (pos === 0) { - str = "\\" + str; - } else { - const pc = str.substr(pos - 1, 1); - if (pc !== "\\") { - str = str.slice(0, pos) + "\\" + str.slice(pos); - } - } - } - } - matches = arrayOfRegExMatches(accentRegEx$2, str); - L = matches.length; - if (L > 0) { - for (let i = L - 1; i >= 0; i--) { - const match = matches[i]; - const pos = match.index; - if (pos > 0) { - str = str.slice(0, pos - 1) + "\\" + textAccent[match.value] - + str.slice(pos - 1, pos) + str.slice(pos + 1); - } - } - } - } - return str -}; - -const numeralFromSuperScript = ch => { - // convert a superscript character, ⁰¹²³ etc, to the regular numeral equivalent. - switch (ch) { - case "²": - return "2" - case "³": - return "3" - case "⁻": - return "-" - case "¹": - return "1" - case "⁰": - return "0" - default: - return String.fromCharCode(ch.charCodeAt(0) - 0x2040) - } -}; - -// Trim spaces except for tabs. This is used to read tab-separated values (TSV). -const leadingSpaceRegEx$3 = /^[ \r\n\f]+/; -const trailingSpaceRegEx$1 = /[ \r\n\f]+$/; -const tablessTrim = str => { - return str.replace(leadingSpaceRegEx$3, "").replace(trailingSpaceRegEx$1, "") -}; - -const midDotRegEx = /^(\*|·|\.|-[A-Za-z])/; -const exponentRegEx = /[⁰¹²³\u2074-\u2079⁻]/; - -const unitTeXFromString = str => { - // I wrap a unit name with an extra pair of braces {}. - // Tt's a hint so that plugValsIntoEcho() can easily remove a unit name. - let unit = " {\\text{"; - let inExponent = false; - - for (let i = 0; i < str.length; i++) { - let ch = str.charAt(i); - if (exponentRegEx.test(ch)) { - ch = numeralFromSuperScript(ch); - } - if (midDotRegEx.test(str.slice(i))) { - unit += "}\\mkern1mu{\\cdot}\\mkern1mu\\text{"; - } else if (/[0-9-]/.test(ch)) { - ch = ch === "-" ? "\\text{-}" : ch; - if (inExponent) { - unit += ch; - } else { - unit += "}^{" + ch; - inExponent = true; - } - } else if (ch === "^") { - unit += "}^{"; - inExponent = true; - } else if (inExponent) { - unit += "}\\text{" + ch; - inExponent = false; - } else if (ch === "$") { - unit += "\\$"; - } else { - unit += ch; - } - } - - return unit + "}}" -}; - -// unit exponents of a number with no unit. -const allZeros = Object.freeze([0, 0, 0, 0, 0, 0, 0, 0]); - -// Data types -// Some operands will be two types at the same time, e.g. RATIONAL + MATRIX. -// So we'll enumerate data types in powers of two. -// That way, we can use a bit-wise "&" operator to test for an individual type. -const dt = Object.freeze({ - NULL: 0, - RATIONAL: 1, - COMPLEX: 2, - BOOLEAN: 4, - FROMCOMPARISON: 8, - BOOLEANFROMCOMPARISON: 12, // 4 + 8, useful for chained comparisons - STRING: 16, - QUANTITY: 32, // Contains both a magnitude and a unit-of-measure - DATE: 64, // Not currently used - RANGE: 128, // as in: 1:10 - TUPLE: 256, // Used for multiple assignment from a module. - MAP: 512, // A key:value store with all the same data type the same unit - ROWVECTOR: 1024, - COLUMNVECTOR: 2048, - MATRIX: 4096, // two dimensional - DATAFRAME: 8192, - MODULE: 16384, // contains user-defined functions - ERROR: 32768, - UNIT: 65536, // User-defined units. - DRAWING: 131072, - RICHTEXT: 262144, - DICTIONARY: 524288, - MACRO: 1048576 -}); - -const errorMessages = Object.freeze({ - EN: { - ERROR: "Error. Hurmet does not understand the expression.", - ERR_FUNC: "@", - BAD_FUN_NM:"Error. Unrecognized function name \"@\".", - DIV: "Error. Divide by zero.", - NAN: "Error. Value of $@$ is not a numeric.", - NANARG: "Error. Argument to function $@$ must be numeric.", - NULL: "Error. Missing value for $@$.", // $@$ will be italic in TeX - BAD_EQ: 'Error. Use "==" instead of "=" to check for equality.', - V_NAME: "Error. Variable $@$ not found.", - F_NAME: "Error. Function @ not found.", - NAN_OP: "Error. Arithmetic operation on a non-numeric value.", - UNIT_ADD: "Error. Adding incompatible units.", - UNIT_COMP: "Error. Comparing incompatible units.", - UNIT_APEND:"Error. Apppending incompatible units.", - UNIT_RES: "Error. Calculated units are not compatible with the desired result unit:", - UNIT_MISS: "Error. No units specified for the result.", - UNIT_IN: "Error. Incorrect unit for input to function @.", - UNIT_ARG: "Error. Unit mis-match between arguments to function @.", - UNIT_COL: "Error. Data frame column @ has no units. Do not make a unit-aware call to it.", - UNIT_AWARE: "Error. Calculation must be unit-aware in order to apply unit @", - DATE: "Error. Date required.", - LOGIC: "Error. Logic operation “@” on a non-boolean value.", - FACT: "Error. Factorial may be applied only to a unit-less non-negative integer.", - PER: "Error. Percentage may be applied only to a unit-less number.", - BINOM: "Error. Binomial may be applied only to unit-less numbers.", - LOGF: "Error. Argument to log!() must be a non-negative integer.", - Γ0: "Error. Γ(0) is infinite.", - ΓPOLE: "Error. Γ() of a negative integer is infinite.", - LOGΓ: "Error. Argument to Hurmet lgamma() must be a positive number.", - TAN90: "Error. tan($@$) is infinite.", - ATRIG: "Error. Input to @ must be between -1 and 1.", - COT: "Error. Input to @ must not be zero.", - ASEC: "Error. Absolute value of input to @ must be ≥ 1", - STRING: "Error. Text operand required.", - NUMARGS: "Error. Wrong number of arguments passed to function @.", - NONSQUARE: "Error. Only a square matrix can be inverted.", - SINGULAR: "Error. Matrix is singular and cannot be inverted.", - BAD_ROW_NAME: "Error. Data frame does not have a row named @.", - BAD_COLUMN_NAME: "Error. Data frame does not have a column named @.", - SINGLE_ARG:"Error. A call to a data frame must have two arguments in the brackets.", - BAD_TYPE: "Error. Unrecognized data type for $@$.", - CONCAT: "Error. Cannot add strings. Use \"&\" if concatenation is desired.", - MATRIX_DIV:"Error. Cannot divide one matrix by another.", - MATRIX_MOD:"Error. Cannot take the modulo of one matrix by another.", - BAD_INDEX: "Error. Index to a matrix must be numeric.", - FUNC_LINE: "Error in function @", - BAD_BREAK: "Error in function @. break called outside of a loop", - FETCH: "Error. A fetch() function must be the only item in its expression.", - STR_INDEX: "Error. The index to text may be only a real number or a range.", - UNIT_NAME: "Error. Unrecognized unit name: @", - INT_NUM: "Error. Number display type \"@\" must be an integer.", - TWO_MAPS: "Error. Both operands are maps. Hurmet accepts only one.", - BAD_FORMAT:"Error. Invalid format @.", - BAD_PREC: "Error. Significant digit specification must be between 1 and 15.", - ZERO_ROOT: "Error. Zeroth root.", - BAD_ROOT: "Error while taking root.", - UNREAL: "Error. Argument to function \"@\" must be a real number.", - BIGINDEX: "Error. Index too large.", - MIS_ELNUM: "Error. Mis-matched number of elements", - // eslint-disable-next-line max-len - CROSS: "Error. Cross product can be performed only on three-vectors. Use * if you want element-wise multiplication.", - QUANT_NUM: "Error. A Quantity must include a numeric magnitude.", - CURRENCY: "Error. Currency exchange rates must be defined before using a monetary unit.", - DF_UNIT: "Invalid unit \"&\" in data frame.", - FORM_FRAC: "Error. Hurmet can do binary or hexadecimal format only on integers.", - PRIVATE: "Error. Function @ is not private.", - INT_ARG: "Error. The @ function can take only integers as arguments.", - BAD_KEY: "Error. Data structure does not contain key \"@\".", - NUM_KEY: "Error. A key must be a string, not a number.", - IMMUT_UDF: `Error. Variable @ already contains a user-defined function. - Hurmet cannot assign a different value to @.`, - NO_PROP: `Error. Cannot call a property from variable "@" because it has no properties.`, - NOT_ARRAY: `Error. Cannot The second operand is not an array.`, - MULT_MIS: "Error. Mismatch in number of multiple assignment.", - COUNT: "Error. The count() function works only on strings.", - NOT_VECTOR:"Error. Arguments to @() must be vectors.", - BAD_DISPLAY:"Error. Result may not be suppressed. Use '?' display selector.", - NA_COMPL_OP:"Error. \"@\" cannot be performed on a complex number.", - NA_REAL: "Error. \"@\" can be performed only a complex number.", - ORIGIN: "Error. Function \"@\" is undefined at the origin.", - LOG_ZERO: "Error. Logarithm of zero is negative infinity.", - END_MISS: "Error. Too few END statments in function @.", - BAD_CONCAT: "Error. Unmatched dimensions.", - BAD_KEYSTR: "Error. The key in a key:value pair must be a string.", - BAD_APPEND: "Error. Can not append a @", - MAP_APPEND: "Error. Can not append. Wrong data type.", - BAD_TRANS: "Error. Only a matrix can be transposed.", - BAD_ARGS: "Error. Wrong number of arguments to function @", - BAD_SUM: "Error. Second argument to sum function must be 1 or 2.", - ZERO_STEP: "Error. Step value must be > zero." - } -}); - -const errorOprnd = (errorCode, messageInsert) => { - if (errorCode === "") { return { value: "Error", unit: null, dtype: dt.ERROR } } - let msg = errorMessages["EN"][errorCode]; - if (msg === undefined) { return { value: "Error", unit: null, dtype: dt.ERROR } } - if (messageInsert) { - messageInsert = addTextEscapes(messageInsert); - msg = msg.replace(/@/g, messageInsert); - } else { - msg = msg.replace(/@ ?/, ""); - } - return { value: msg, unit: null, dtype: dt.ERROR } -}; - -/* - * This file implements a rational number data type. - * Each rational number, r, is held as an array containing two BigInts. - * r[0] is the numerator and r[1] is the denominator. - * Negative rationals have a negative numerator, not a negative denominator. - * - * The code in this file is heavily influenced by Chapter 5 of - * __How JavaScript Works__ by Douglas Crockford - */ - -const iZero = BigInt(0); -const iOne = BigInt(1); -const iTwo = BigInt(2); -const zero = [iZero, iOne]; -const one = [iOne, iOne]; -const two = [iTwo, iOne]; -const pi$1 = [BigInt(31415926535897932384626433832795028841971693993751), - BigInt(10000000000000000000000000000000000000000000000000)]; -const e$1 = [BigInt(2718281828459045235360287471352662497757247093699959574966), - BigInt(1000000000000000000000000000000000000000000000000000000000)]; -// reduced Planck constant -const hbar = [BigInt(1054571817), - BigInt(10000000000000000000000000000000000000000000)]; - -const intAbs$1 = i => i >= iZero ? i : BigInt(-1) * i; // absolute value of a BigInt - -// eslint-disable-next-line max-len -const numberPattern = "^(-?)(?:(0x[0-9A-Fa-f]+)|([0-9]+)(?: ([0-9]+)\\/([0-9]+)|(?:\\.([0-9]+))?(?:e([+-]?[0-9]+)|(%))?))"; -const numberRegEx$6 = new RegExp(numberPattern); -// Capturing groups: -// [1] sign -// [2] hexadecimal integer -// [3] integer part -// [4] numerator of a mixed fraction -// [5] denominator of a mixed fraction -// [6] decimal fraction of significand, not including decimal point -// [7] exponent of a number in scientific notation -// [8] percentage sign - -const fromNumber = num => { - // Convert a JavaScript Number to a rational. - if (Number.isInteger(num)) { - return [BigInt(num), iOne] - } else { - const parts = num.toExponential().match(numberRegEx$6); - const decimalFrac = parts[6] || ""; - const exp = BigInt(parts[7]) - BigInt(decimalFrac.length); - if (exp < 0) { - return [BigInt(parts[1] + parts[3] + decimalFrac), BigInt(10) ** -exp] - } else if (parts[5]) { - const denominator = BigInt(parts[5]); - return normalize( - [BigInt(parts[1] + parts[3]) * denominator + BigInt(parts[4]) ]) - } else { - return normalize([BigInt(parts[1] + parts[3] + decimalFrac) * BigInt(10) ** exp, iOne]) - } - } -}; - -const fromString = str => { - // Convert an author's input string to a number. - const parts = str.match(numberRegEx$6); - let r; - if (parts[5]) { - // mixed fraction - const denominator = BigInt(parts[5]); - const numerator = BigInt(parts[1] + parts[3]) * denominator + BigInt(parts[4]); - r = normalize([numerator, denominator]); - - } else if (parts[2]) { - // hexadecimal - r = [BigInt(parts[2]), iOne]; - - } else { - // decimal - const decimalFrac = parts[6] || ""; - const numerator = BigInt(parts[3] + decimalFrac); - const exp = parts[7] - ? BigInt(parts[7]) - BigInt(decimalFrac.length) // scientific notation. - : parts[8] - ? BigInt(-2) - BigInt(decimalFrac.length) // percentage. - : BigInt(0) - BigInt(decimalFrac.length); - r = (exp < 0) - ? [numerator, BigInt(10) ** -exp] - : normalize([numerator * BigInt(10) ** exp, iOne]); - } - if (parts[1]) { r = negate$1(r); } - return r -}; - -const gcdi = (a, b) => { - // Greatest common divisor of two big integers - a = intAbs$1(a); - b = intAbs$1(b); - while (b !== iZero) { - const remainder = a % b; - a = b; - b = remainder; - } - return a -}; - -const gcd = (m, n) => { - // Greatest common divisor of two rationals - if (!Rnl.isInteger(m) || !Rnl.isInteger(n)) { return errorOprnd("INT_ARG", "gcd") } - return [gcdi(m[0] / m[1], n[0] / n[1]), iOne] -}; - -const normalize = r => { - const [numerator, denominator] = r; - if (denominator === iOne) { return r } - const gcD = gcdi(numerator, denominator); - return gcD === iOne ? r : [numerator / gcD, denominator / gcD] -}; - -const isRational = a => { - return Array.isArray(a) && a.length === 2 - && typeof a[0] === "bigint" && typeof a[1] === "bigint" -}; - -const isInteger = r => r[1] === iOne || (r[0] % r[1]) === iZero; - -const isZero = r => r[0] === iZero; - -const isNegative = r => r[0] < iZero; -const isPositive = r => r[0] > iZero; -const sign = r => isPositive(r) ? one : isZero(r) ? zero : negate$1(one); - -const negate$1 = r => [BigInt(-1) * r[0], r[1]]; - -const abs$1 = r => { - const numerator = r[0] < iZero ? BigInt(-1) * r[0] : r[0]; - return [numerator, r[1]] -}; - -const increment$1 = r => [r[0] + r[1], r[1]]; - -const decrement$1 = r => [r[0] - r[1], r[1]]; - -const floor = r => { - if (r[0] % r[1] === iZero) { return [r[0] / r[1], iOne] } - return (r[0] >= iZero) - ? [r[0] / r[1], iOne] - : [r[0] / r[1] - iOne, iOne] -}; - -const ceil = r => { - if (r[0] % r[1] === iZero) { return [r[0] / r[1], iOne] } - return (r[0] >= iZero) - ? [r[0] / r[1] + iOne, iOne] - : [r[0] / r[1], iOne] -}; - -const add$1 = (a, b) => { - return a[1] === b[1] - ? [a[0] + b[0], a[1]] - : normalize([a[0] * b[1] + b[0] * a[1], a[1] * b[1]]) -}; - -const subtract$1 = (a, b) => { - return (a[1] === b[1]) - ? [a[0] - b[0], a[1]] - : normalize([a[0] * b[1] - b[0] * a[1], a[1] * b[1]]) -}; - -const multiply$1 = (a, b) => [a[0] * b[0], a[1] * b[1]]; - -const divide$1 = (a, b) => { - let numerator = a[0] * b[1]; - let denominator = a[1] * b[0]; - if (denominator < 0) { - // Move the negative from the denominator to the numerator. - numerator *= BigInt(-1); - denominator *= BigInt(-1); - } - return [numerator, denominator] -}; - -const power$1 = (a, b) => { - if (b[0] === iZero) { - return [iOne, iOne] - } else { - b = normalize(b); - let result; - try { - result = isInteger(b) && isNegative(b) - ? [a[1] ** (BigInt(-1) * b[0]), a[0] ** (BigInt(-1) * b[0])] - : isInteger(b) - ? [a[0] ** b[0], a[1] ** b[0]] - : isPositive(a) || greaterThan(b, one) || lessThan(b, negate$1(one)) - ? fromNumber(toNumber(a) ** toNumber(b)) - : areEqual(mod(b, two), one) - ? fromNumber(-1 * (-1 * toNumber(a)) ** toNumber(b)) - : errorOprnd("BAD_ROOT"); - } catch (err) { - result = fromNumber(toNumber(a) ** toNumber(b)); - } - return result - } -}; - -const sqrt$1 = r => fromNumber(Math.sqrt(toNumber(r))); - -const exp$1 = r => fromNumber(Math.exp(toNumber(r))); - -const reciprocal = r => { - let numerator = r[1]; - let denominator = r[0]; - if (denominator < 0) { - numerator *= BigInt(-1); - denominator *= BigInt(-1); - } - return [numerator, denominator] -}; - -const hypot = (a, b) => { - // Ref: https://www.johndcook.com/blog/2010/06/02/whats-so-hard-about-finding-a-hypotenuse/ - const absA = abs$1(a); - const absB = abs$1(b); - const maximum = max(absA, absB); - const minimum = min(absA, absB); - const r = Rnl.divide(minimum, maximum); - return Rnl.multiply(maximum, sqrt$1(Rnl.increment(Rnl.multiply(r, r)))) -}; - -const mod = (a, b) => { - const quotient = divide$1(normalize(a), normalize(b)); - return [intAbs$1(quotient[0] % quotient[1]), iOne] -}; - -const rem = (a, b) => { - const quotient = divide$1(normalize(a), normalize(b)); - return [quotient[0] % quotient[1], iOne] -}; - -const areEqual = (a, b) => { - return (a[1] === b[1]) - ? a[0] === b[0] - : a[0] * b[1] === a[1] * b[0] -}; - -const lessThan = (a, b) => { - return (isNegative(a) !== isNegative(b)) - ? isNegative(a) - : isNegative(subtract$1(a, b)) -}; - -const greaterThan = (a, b) => { - return (isPositive(a) !== isPositive(b)) - ? isPositive(a) - : isPositive(subtract$1(a, b)) -}; - -const lessThanOrEqualTo = (a, b) => lessThan(a, b) || areEqual(a, b); - -const greaterThanOrEqualTo = (a, b) => greaterThan(a, b) || areEqual(a, b); - -const max = (a, b) => greaterThan(a, b) ? [a[0], a[1]] : [b[0], b[1]]; - -const min = (a, b) => lessThan(a, b) ? [a[0], a[1]] : [b[0], b[1]]; - -const cos$1 = x => { - return areEqual(x, divide$1(pi$1, two)) - ? zero - : fromNumber(Math.cos(toNumber(x))) -}; - -const sin$1 = x => fromNumber(Math.sin(toNumber(x))); - -const tan = x => { - if (areEqual(x, divide$1(pi$1, two))) { - return errorOprnd("TAN90", "π/2") - } - return fromNumber(Math.tan(toNumber(x))) -}; - -const cosh = x => { - // cosh(n) = (eⁿ + e⁻ⁿ) / 2 - const num = toNumber(x); - return fromNumber((Math.exp(num) + Math.exp(-num)) / 2) -}; - -const sinh = x => { - // sinh(n) = (eⁿ - e⁻ⁿ) / 2 - const num = toNumber(x); - return fromNumber((Math.exp(num) - Math.exp(-num)) / 2) -}; - -const tanh = x => { - // tanh(n) = (eⁿ - e⁻ⁿ) / (eⁿ + e⁻ⁿ) - const num = toNumber(x); - return fromNumber( - (Math.exp(num) - Math.exp(-num)) / (Math.exp(num) + Math.exp(-num)) - ) -}; - -const toNumber = r => { - // Return a JavaScript Number - const num = Number(r[0]) / Number(r[1]); // May be imprecise. - if (!isNaN(num) && num !== Infinity ) { return num } - const numStr = toStringSignificant(r, 20); - return Number(numStr) -}; - -const toStringSignificant = (r, numSignificantDigits) => { - // Return a string rounded to numSignificantDigits. - if (isZero(r)) { - return "0" - } else { - const quotient = intAbs$1(r[0] / r[1]); - if (quotient > 0) { - return toString(r, numSignificantDigits - String(quotient).length) - } else { - const inverseQuotientLength = String(intAbs$1(r[1] / r[0])).length; - return toString(r, inverseQuotientLength + numSignificantDigits - 1) - } - } -}; - -const toString = (r, numDigitsAfterDecimal) => { - // Return a string rounded to numDigitsAfterDecimal. - if (isZero(r)) { - return "0" - } else if (numDigitsAfterDecimal < 0) { - const N = -numDigitsAfterDecimal; - const significand = toString(divide$1(r, [BigInt(10) ** BigInt(N), iOne]), 0); - return significand + "0".repeat(N) - } else { - const [numerator, denominator] = normalize(r); - const quotient = numerator / denominator; - let remainder = numerator % denominator; - let result = String(quotient); - if (remainder === iZero && numDigitsAfterDecimal > 0) { - result += "." + "0".repeat(numDigitsAfterDecimal); - } else if (remainder !== iZero) { - remainder = intAbs$1(remainder); - const newNumerator = remainder * (BigInt(10) ** BigInt(numDigitsAfterDecimal)); - let fractus = newNumerator / denominator; - const residue = newNumerator % denominator; - if (numDigitsAfterDecimal === 0) { - return (intAbs$1(iTwo * residue) >= intAbs$1(denominator)) - ? String(quotient + iOne) - : result - } - if (intAbs$1(iTwo * residue) >= intAbs$1(denominator)) { - fractus = fractus + iOne; - } - result += "." + String(fractus).padStart(numDigitsAfterDecimal, "0"); - } - return result - } -}; - -// eslint-disable-next-line max-len -const preComputedFactorials = ["1", "1", "2", "6", "24", "120", "720", "5040", "40320", "362880", "3628800", "39916800", "479001600", "6227020800", "87178291200", "1307674368000", "20922789888000", "355687428096000", "6402373705728000", "121645100408832000", "2432902008176640000", "51090942171709440000", "1124000727777607680000", "25852016738884976640000", "620448401733239439360000", "15511210043330985984000000", "403291461126605635584000000", "10888869450418352160768000000", "304888344611713860501504000000", "8841761993739701954543616000000", "265252859812191058636308480000000", "8222838654177922817725562880000000", "263130836933693530167218012160000000", "8683317618811886495518194401280000000", "295232799039604140847618609643520000000", "10333147966386144929666651337523200000000", "371993326789901217467999448150835200000000", "13763753091226345046315979581580902400000000", "523022617466601111760007224100074291200000000", "20397882081197443358640281739902897356800000000", "815915283247897734345611269596115894272000000000", "33452526613163807108170062053440751665152000000000", "1405006117752879898543142606244511569936384000000000", "60415263063373835637355132068513997507264512000000000", "2658271574788448768043625811014615890319638528000000000", "119622220865480194561963161495657715064383733760000000000", "5502622159812088949850305428800254892961651752960000000000", "258623241511168180642964355153611979969197632389120000000000", "12413915592536072670862289047373375038521486354677760000000000", "608281864034267560872252163321295376887552831379210240000000000", "30414093201713378043612608166064768844377641568960512000000000000", "1551118753287382280224243016469303211063259720016986112000000000000", "80658175170943878571660636856403766975289505440883277824000000000000", "4274883284060025564298013753389399649690343788366813724672000000000000", "230843697339241380472092742683027581083278564571807941132288000000000000", "12696403353658275925965100847566516959580321051449436762275840000000000000", "710998587804863451854045647463724949736497978881168458687447040000000000000", "40526919504877216755680601905432322134980384796226602145184481280000000000000", "2350561331282878571829474910515074683828862318181142924420699914240000000000000", "138683118545689835737939019720389406345902876772687432540821294940160000000000000", "8320987112741390144276341183223364380754172606361245952449277696409600000000000000", "507580213877224798800856812176625227226004528988036003099405939480985600000000000000", "31469973260387937525653122354950764088012280797258232192163168247821107200000000000000", "1982608315404440064116146708361898137544773690227268628106279599612729753600000000000000", "126886932185884164103433389335161480802865516174545192198801894375214704230400000000000000", "8247650592082470666723170306785496252186258551345437492922123134388955774976000000000000000", "544344939077443064003729240247842752644293064388798874532860126869671081148416000000000000000", "36471110918188685288249859096605464427167635314049524593701628500267962436943872000000000000000", "2480035542436830599600990418569171581047399201355367672371710738018221445712183296000000000000000", "171122452428141311372468338881272839092270544893520369393648040923257279754140647424000000000000000", "11978571669969891796072783721689098736458938142546425857555362864628009582789845319680000000000000000", "850478588567862317521167644239926010288584608120796235886430763388588680378079017697280000000000000000", "61234458376886086861524070385274672740778091784697328983823014963978384987221689274204160000000000000000", "4470115461512684340891257138125051110076800700282905015819080092370422104067183317016903680000000000000000", "330788544151938641225953028221253782145683251820934971170611926835411235700971565459250872320000000000000000", "24809140811395398091946477116594033660926243886570122837795894512655842677572867409443815424000000000000000000", "1885494701666050254987932260861146558230394535379329335672487982961844043495537923117729972224000000000000000000", "145183092028285869634070784086308284983740379224208358846781574688061991349156420080065207861248000000000000000000", "11324281178206297831457521158732046228731749579488251990048962825668835325234200766245086213177344000000000000000000", "894618213078297528685144171539831652069808216779571907213868063227837990693501860533361810841010176000000000000000000", "71569457046263802294811533723186532165584657342365752577109445058227039255480148842668944867280814080000000000000000000", "5797126020747367985879734231578109105412357244731625958745865049716390179693892056256184534249745940480000000000000000000", "475364333701284174842138206989404946643813294067993328617160934076743994734899148613007131808479167119360000000000000000000", "39455239697206586511897471180120610571436503407643446275224357528369751562996629334879591940103770870906880000000000000000000", "3314240134565353266999387579130131288000666286242049487118846032383059131291716864129885722968716753156177920000000000000000000", "281710411438055027694947944226061159480056634330574206405101912752560026159795933451040286452340924018275123200000000000000000000", "24227095383672732381765523203441259715284870552429381750838764496720162249742450276789464634901319465571660595200000000000000000000", "2107757298379527717213600518699389595229783738061356212322972511214654115727593174080683423236414793504734471782400000000000000000000", "185482642257398439114796845645546284380220968949399346684421580986889562184028199319100141244804501828416633516851200000000000000000000", "16507955160908461081216919262453619309839666236496541854913520707833171034378509739399912570787600662729080382999756800000000000000000000", "1485715964481761497309522733620825737885569961284688766942216863704985393094065876545992131370884059645617234469978112000000000000000000000", "135200152767840296255166568759495142147586866476906677791741734597153670771559994765685283954750449427751168336768008192000000000000000000000", "12438414054641307255475324325873553077577991715875414356840239582938137710983519518443046123837041347353107486982656753664000000000000000000000", "1156772507081641574759205162306240436214753229576413535186142281213246807121467315215203289516844845303838996289387078090752000000000000000000000", "108736615665674308027365285256786601004186803580182872307497374434045199869417927630229109214583415458560865651202385340530688000000000000000000000", "10329978488239059262599702099394727095397746340117372869212250571234293987594703124871765375385424468563282236864226607350415360000000000000000000000", "991677934870949689209571401541893801158183648651267795444376054838492222809091499987689476037000748982075094738965754305639874560000000000000000000000", "96192759682482119853328425949563698712343813919172976158104477319333745612481875498805879175589072651261284189679678167647067832320000000000000000000000", "9426890448883247745626185743057242473809693764078951663494238777294707070023223798882976159207729119823605850588608460429412647567360000000000000000000000", "933262154439441526816992388562667004907159682643816214685929638952175999932299156089414639761565182862536979208272237582511852109168640000000000000000000000", "93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000"]; -// eslint-disable-next-line max-len -const preComputedDoubleFactorials = ["1", "1", "2", "3", "8", "15", "48", "105", "384", "945", "3840", "10395", "46080", "135135", "645120", "2027025", "10321920", "34459425", "185794560", "654729075", "3715891200", "13749310575", "81749606400", "316234143225", "1961990553600", "7905853580625", "51011754393600", "213458046676875", "1428329123020800"]; - -const factorial = (n) => { - if (lessThan(n, [BigInt(101), iOne])) { - return fromString(preComputedFactorials[toNumber(n)]) - } else { - return lanczos$1(increment$1(n)) - } -}; - -const doubleFactorial = n => { - if (lessThan(n, [BigInt(29), iOne])) { - return fromString(preComputedDoubleFactorials[toNumber(n)]) - } else { - let r = n; - for (let i = Rnl.toNumber(n) - 2; i > 0; i -= 2) { - r = multiply$1(r, fromNumber(i)); - } - return r - } -}; - -const lanczos$1 = xPlusOne => { - // Lanczos approximation of Gamma function. - // Coefficients are from 2004 PhD thesis by Glendon Pugh. - // *An Analysis of the Lanczos Gamma Approximation* - // The following equation is from p. 116 of the Pugh thesis: - // Γ(x+1) ≈ 2 * √(e / π) * ((x + 10.900511 + 0.5) / e) ^ (x + 0.5) * sum - const x = subtract$1(xPlusOne, one); - const term1 = multiply$1(two, sqrt$1(divide$1(e$1, pi$1))); - const term2 = power$1(divide$1(add$1(x, fromNumber(11.400511)), e$1), add$1(x, [iOne, iTwo])); - - // Coefficients from Pugh, Table 8.5 - const d = ["2.48574089138753565546e-5", "1.05142378581721974210", - "-3.45687097222016235469", "4.51227709466894823700", "-2.98285225323576655721", - "1.05639711577126713077", "-0.195428773191645869583", "0.0170970543404441224307", - "-0.000571926117404305781283", "0.00000463399473359905636708", - "-0.00000000271994908488607703910"]; - - // sum = d_0 + ∑_(k=1)^10 d_k/(x+k) - let sum = fromString(d[0]); - for (let k = 1; k <= 10; k++) { - sum = add$1(sum, divide$1(fromString(d[k]), add$1(x, fromNumber(k)))); - } - - return multiply$1(multiply$1(term1, term2), sum) -}; - -const Rnl = Object.freeze({ - fromNumber, - fromString, - normalize, - isRational, - isInteger, - isZero, - isNegative, - isPositive, - sign, - negate: negate$1, - abs: abs$1, - increment: increment$1, - decrement: decrement$1, - exp: exp$1, - floor, - ceil, - add: add$1, - subtract: subtract$1, - multiply: multiply$1, - divide: divide$1, - reciprocal, - gcd, - hbar, - mod, - rem, - hypot, - one, - pi: pi$1, - power: power$1, - sqrt: sqrt$1, - two, - cos: cos$1, - sin: sin$1, - tan, - cosh, - sinh, - tanh, - areEqual, - lessThan, - greaterThan, - lessThanOrEqualTo, - greaterThanOrEqualTo, - factorial, - doubleFactorial, - lanczos: lanczos$1, - max, - min, - numberPattern, - toNumber, - toString, - toStringSignificant, - zero -}); - -const siPrefixes = ["y", "z", "a", "f", "p", "n", "µ", "m", "", "k", - "M", "G", "T", "P", "E", "Z", "Y"]; - -const groupByThreeRegEx = /\B(?=(\d{3})+$)/g; -const groupByFourRegEx = /\B(?=(\d{4})+$)/g; // use sometimes in China -// Grouping as common in south Asia: 10,10,000 -const groupByLakhCroreRegEx = /(\d)(?=(\d\d)+\d$)/g; - -const formatRegEx = /^([beEfhkmprsStx%])?(-?[\d]+)?([∠°]{0,2})?$/; - -const superscript = str => { - // Convert a numeral string to Unicode superscript characters. - // Used for denominator in mixed fractions/ - let result = ""; - for (let i = 0; i < str.length; i++) { - const charCode = str.charCodeAt(i); - result += (charCode === 0x31) - ? "¹" - : charCode === 0x32 - ? "²" - : charCode === 0x33 - ? "³" - : String.fromCharCode(charCode + 0x2040); - } - return result -}; - -const subscript = str => { - // Convert a numeral string to Unicode subscript characters. - // Used for mixed fraction denominators. - let result = ""; - for (let i = 0; i < str.length; i++) { - result += String.fromCharCode(str.charCodeAt(i) + 0x2050); - } - return result -}; - -const texFromMixedFraction = (numParts) => { - return (numParts[1] ? "-" : "") + - numParts[3] + "\\,\\class{special-fraction}{\\text{" + - superscript(numParts[4]) + "\u2044" + subscript(numParts[5]) + "}}" -}; - -const intAbs = i => i >= BigInt(0) ? i : BigInt(-1) * i; // absolute value of a BigInt - -const roundedString = (r, spec) => { - // Return a string rounded to the correct number of digits - const N = spec.numDigits; - - switch (spec.ftype) { - case "h": { - // Round a fraction, but not an integer, to N significant digits. - const integerStr = String(Rnl.toString(r, 0)); - if (integerStr.replace("-", "").length >= N) { return integerStr } - if (N < 1 || N > 15) { return errorOprnd("BAD_PREC") } - return Rnl.toNumber(r).toPrecision(N) - } - - case "f": - case "%": - // Exactly N digits after the decimal. - return Rnl.toString(r, N) - - case "r": - case "p": { - // Round to N significant digits - if (N < 1 || N > 15) { return errorOprnd("BAD_PREC") } - const numStr = Rnl.toNumber(r).toPrecision(N); - return numStr.indexOf("e") > -1 ? Number(numStr).toPrecision() : numStr - } - - case "s": - case "S": - case "e": - case "E": - case "n": - case "N": - case "k": - // Some variety of scientific notation. - if (N < 1 || N > 15) { return errorOprnd("BAD_PREC") } - return Rnl.toNumber(r).toExponential(N - 1).replace("+", "") - - default: { - r = Rnl.normalize(r); - const sign = Rnl.isNegative(r) ? "-" : ""; - const numerator = intAbs(r[0]); - const denominator = r[1]; - - switch (spec.ftype) { - case "m": { - // Mixed fraction - const quotientStr = String(numerator / denominator); - const remainder = numerator % denominator; - return sign + quotientStr + "\u00a0" + superscript(remainder) + - "⁄" + subscript(denominator) - } - - case "t": - // Truncate to integer - return sign + String(numerator / denominator) - - case "b": - case "x": - case "X": - // binary or hexadecimal integer - if (denominator !== BigInt(1)) { return errorOprnd("INT_NUM", spec.ftype) } - if (numerator <= Number.MAX_SAFE_INTEGER) { - return (spec.ftype === "b") - ? sign + "0b" + Number(numerator).toString(2) - : spec.ftype === "x" - ? sign + "0x" + Number(numerator).toString(16) - : sign + "0x" + Number(numerator).toString(16).toUpperCase() - } else { - // TODO: display large hex or binary. - return "" - } - } - } - } -}; - -const formattedInteger = (intStr, decimalFormat) => { - const thousandsSeparator = decimalFormat.charAt(1); - if (thousandsSeparator === "0") { - return intStr - } else if (decimalFormat === "1,00,000.") { - return intStr.replace(groupByLakhCroreRegEx, "$1{,}") - } else if (decimalFormat === "1,0000,0000.") { - return intStr.replace(groupByFourRegEx, "$1{,}") - } else { - return intStr.replace(groupByThreeRegEx, - (thousandsSeparator === ",") - ? "{,}" - : (thousandsSeparator === " ") - ? "\\:" - : (thousandsSeparator === "’") - ? "’" - : "." - ) - } -}; - -const formattedDecimal = (numStr, decimalFormat, truncateTrailingZeros) => { - const pos = numStr.indexOf("."); - if (pos === -1) { - return formattedInteger(numStr, decimalFormat) - } else { - const intStr = numStr.slice(0, pos); - const decimalSeparator = decimalFormat.slice(-1); - let frac = (decimalSeparator === "." ? "." : "{,}") + numStr.slice(pos + 1); - if (truncateTrailingZeros) { frac = frac.replace(/(\.|{,})?0+$/, ""); } - return formattedInteger(intStr, decimalFormat) + frac - } -}; - -const parseFormatSpec = str => { - // Do the RegEx once, at compile time, not every time a number is formatted. - // - // str ≔ "Tn", where: - // T = type, [bEefhkmNnprSstx%], default: "h" - // n = number of digits, [0-9]+, default: 15 - // - // Possible future additions: complex number format [∠°] - - const match = formatRegEx.exec(str); - if (!match) { - const message = errorOprnd("BAD_FORMAT", str).value; - return [str, undefined, dt.ERROR, "\\text{" + message + "}"] - } - - let ftype = match[1] || "h"; - let N = Number(match[2] || "15"); - const ctype = match[3] || ""; - - // Check the specified number of digits - switch (ftype) { - case "b": - case "x": - case "X": - return [str, undefined, dt.STRING, "\\text{" + ftype + ctype + "}" ] - case "t": - N = 0; - break - case "f": - case "%": - break - default: - if (N < 1 || N > 15) { - const message = "\\text{" + errorOprnd("BAD_PREC").value + "}"; - return [str, undefined, dt.ERROR, message] - } - } - - if (ftype === "%") { ftype = "\\%"; } - return [str, undefined, dt.STRING, "\\text{" + ftype + String(N) + ctype + "}" ] -}; - -const angleRegEx = /[∠°]+$/; - -const format = (num, specStr = "h3", decimalFormat = "1,000,000.") => { - if (Rnl.isZero(num)) { return "0" } - - const spec = { ftype: specStr.charAt(0) }; - specStr = specStr.replace(angleRegEx, ""); - if (specStr.length > 1) { spec.numDigits = Number(specStr.slice(1)); } - - if (spec.ftype === "%" || spec.ftype === "p") { num[0] = num[0] * BigInt(100); } - - if ((spec .ftype === "b" || spec.ftype === "x") && !Rnl.isInteger(num)) { - return errorOprnd("FORM_FRAC") - } - - // Round the number - const numStr = roundedString(num, spec); - - // Add separators - switch (spec.ftype) { - case "f": - case "r": - case "h": - return formattedDecimal(numStr, decimalFormat, spec.ftype === "h") - case "t": - return formattedInteger(numStr, decimalFormat) - case "%": - case "p": - return formattedDecimal(numStr, decimalFormat) + "\\%" - case "m": - case "b": - case "x": - case "X": - return numStr - default: { - // Some sort of scientific notation. - const pos = numStr.indexOf("e"); - let significand = numStr.slice(0, pos); - if (decimalFormat.slice(-1) === ",") { significand = significand.replace(".", "{,}"); } - - switch (spec.ftype) { - case "e": - case "E": { - const result = significand + "\\text{" + spec.ftype; - if (numStr.charAt(pos + 1) === "-") { - return result + "-}" + numStr.slice(pos + 2) - } else { - return result + "}" + numStr.slice(pos + 1) - } - } - - case "s": - case "S": - case "n": - case "N": { - const op = spec.ftype === "S" ? "×" : "\\mkern2mu{\\cdot}\\mkern1mu"; - return significand + op + "10^{" + numStr.slice(pos + 1) + "}" - } - - case "k": { - const exponent = Number(numStr.slice(pos + 1)); - const quotient = exponent / 3; - const q = quotient >= 0 ? Math.floor(quotient) : Math.ceil(quotient); - const modulo = exponent % 3; - if (modulo !== 0) { - significand = String(Number(significand) * Math.pow(10, modulo)); - } - return significand + siPrefixes[8 + q] - } - } - } - } -}; - -/* - * Hurmet operands often have numeric values. Sometimes they are the numbers originally - * input by the writer, henceforward known as "plain". Sometimes we work instead with - * values that have been converted to SI base units. It turns out that operands inside - * evalRpn() can often get by with less information than in the original cell assignment attrs. - * Some details for various data types: - * - * RATIONAL operand: { value: plain, unit: allZeros, dtype: RATIONAL } - * RATIONAL cell attrs: ditto. - * Note: "allZeros" is the array of unit-checking exponents for a number: [0,0,0,0,0,0,0,0,0] - * - * RATIONAL + QUANTITY unit-unaware operand: same as RATIONAL. - * RATIONAL + QUANTITY unit-AWARE oprnd: { - * value: inBaseUnits, unit: expos, dtype: RATIONAL + QUANTITY - * } - * RATIONAL + QUANTITY cell attrs include both of the above and also a `resultdisplay` string. - * - * RATIONAL + ROWVECTOR is the same as RATIONAL except the value is an array of plains. - * RATIONAL + ROWVECTOR + QUANTITY is the same as RATIONAL + QUANTITY except values are arrays. - * COLUMNVECTOR is the same as ROWVECTOR exept that they are treated differently by operators. - * MATRIX indicates that values are each an array of row vectors. - * * - * A MAP's values are all the same data type and all have the same unit of measure. - * MAP oprnd: {name, value: see below, unit: {name, factor, gauge, expos}, dtype: dMAP + ...} - * where: value is: {name1: value, name2: value} or - * where value is: {plain: {name1: value, name2: value}, - * inBaseUnits: {name1: value, name2: value}, - * etc} - * A `resultdisplay` string is always in a MAP's cell attrs and sometimes in an operand. - * - * ERROR operand: { value: error message, unit: undefined, dtype: ERROR } - * - * When this module creates Hurmet operands, it does not make defensive copies of - * cell attributes. The deep data is referenced. So Hurmet evaluate.js must copy whenever - * operators or functions might change a cell attribute. - * - */ - -const fromAssignment = (cellAttrs, unitAware) => { - // Get the value that was assigned to a variable. Load it into an operand. - if (cellAttrs.value === null) { - // Return an error message. - const insert = (cellAttrs.name) ? cellAttrs.name : "?"; - return errorOprnd("NULL", insert) - } - - const oprnd = Object.create(null); - oprnd.dtype = cellAttrs.dtype; - oprnd.name = cellAttrs.name; - - // Get the unit data. - const dtype = cellAttrs.dtype; - if (dtype === dt.STRING || dtype === dt.BOOLEAN || dtype === dt.DRAWING || - dtype === dt.MODULE || dtype === dt.NULL) { - oprnd.unit = null; - } else if (cellAttrs.unit) { - oprnd.unit = clone(cellAttrs.unit); - } else { - oprnd.unit = null; - } - - // Get the value. - if (cellAttrs.dtype & dt.QUANTITY) { - // Here we discard some of the cellAttrs information. In a unit-aware calculation, - // number, matrix, and map operands contain only the value.inBaseUnits. - if (cellAttrs.dtype & dt.MAP) { - oprnd.value = clone(cellAttrs.value); - oprnd.value.data = unitAware - ? oprnd.value.data.inBaseUnits - : oprnd.value.data.plain; - } else { - oprnd.value = Object.freeze(unitAware - ? clone(cellAttrs.value.inBaseUnits) - : clone(cellAttrs.value.plain) - ); - } - oprnd.dtype = cellAttrs.dtype - dt.QUANTITY; - - } else if (cellAttrs.dtype === dt.STRING) { - const str = cellAttrs.value; - const ch = str.charAt(0); - const chEnd = str.charAt(str.length - 1); - oprnd.value = ch === '"' && chEnd === '"' ? str.slice(1, -1).trim() : str.trim(); - - } else if (cellAttrs.dtype === dt.DATAFRAME) { - // For data frames, Hurmet employs copy-on-write tactics. - // So at this point, we can pass a reference to the value - oprnd.value = cellAttrs.value; - - // Note the only operations on data frames are: (1) access, and (2) concatenate. - // That's where the copy-on-write takes place. - - } else { - // For all other data types, we employ copy-on-read. So we return a deep copy from here. - oprnd.value = clone(cellAttrs.value); - } - - return Object.freeze(oprnd) -}; - -// units.js - -/* - * Unit-aware calculation is a core feature of Hurmet. - * Dimensional analysis is used to verify that a calculation contains compatible units. - * Example: Check unit compatibility for: L = '145 N·m'/'15.2 lbf' = ?? feet - * Analysis step 1: first operand: N·m → mass¹·length²·time⁻² - * 2nd operand: lbf → mass¹·length¹·time⁻² - * Note the exponents of those two operands. When terms multiply, we add exponents. - * When terms divide, we subtract exponents. As in step 2, next line: - * mass^(1-1)∙length^(2-1)∙time^(-2-(-2)) = mass⁰·length¹·time⁰ = length¹ - * In the example, the exponents for mass and time both zero'd out. - * Only length has a non-zero exponent. In fact, the result dimension = length¹. - * This matches the desired result dimension (feet is a length), so this example checks out. - * - * Hurmet automates this process of checking unit compatibility. - * Each instance of a Hurmet quantity operand contains an array of unit-checking exponents. - * Each element of that array contains an exponent of one of the Hurmet base dimensions. - * Those exponent values come from the unitTable, below. - * - * The Hurmet base dimensions and standard units are, in order of array values: - * length (meter) - * mass (kg) - * time (second) - * electrical current (ampere) - * temperature (Kelvin) - * finite amount (1 unit) (Yes, I know that SI uses a mole. That's just silly.) - * luminous intensity (cd) - * money (Euro) (A user can redefine the default to some other currency) - */ - -const unitsAreCompatible = (a, b) => { - // Do a compatibility check on the unit-checking exponents a and b. - if (a == null && b == null) { return true } - if (a == null || b == null) { return false } - if (!Array.isArray(a) || !Array.isArray(b)) { return false } - // Compare the exponents in the arrays. - if (a.length !== b.length) { return false } - for (let i = 0; i < a.length; ++i) { - if (a[i] !== b[i]) { return false } - } - return true -}; - -// JSON.parse() is faster than a big object literal -// eslint-disable-next-line max-len -const prefixFactor = JSON.parse('{"Y":1e24,"yotta":1e24,"Z":1e21,"zetta":1e21,"E":1e18,"exa":1e18,"P":1e15,"peta":1e15,"T":1e12,"tera":1e12,"G":1e9,"giga":1e9,"M":1e6,"mega":1e6,"k":1000,"kilo":1000,"h":100,"hecto":100,"deka":10,"d":0.1,"deci":0.1,"c":0.01,"centi":0.01,"m":0.001,"milli":0.001,"µ":1e-6,"\u00B5":1e-6,"micro":1e-6,"n":1e-9,"nano":1e-9,"p":1e-12,"pico":1e-12,"f":1e-15,"femto":1e-15,"a":1e-18,"atto":1e-18,"z":1e-21,"zepto":1e-21,"y":1e-24,"yocto":1e-24,"Ki":1024,"kibi":1024,"Mi":1048576,"mebi":1048576,"Gi":1073741824,"gibi":1073741824,"Ti":1099511627776,"tebi":1099511627776}'); - - // factor, numerator, denominator, gauge, prefix|logarithm|currency, exponents - // exponent break-down: length, mass, time, elect, temp, amount, lum inten, money - // Each money factor is a revised weekly with data from the European Central Bank. -const unitTable = Object.freeze(JSON.parse(`{ -"#":["0.45359237", "1","0","0",[0,1,0,0,0,0,0,0]], -"$":["1","1","0","USD",[0,0,0,0,0,0,0,1]], -"£":["1","1","0","GBP",[0,0,0,0,0,0,0,1]], -"'":["0.3048","1","0","0",[1,0,0,0,0,0,0,0]], -"A":["1","1","0","siSymbol",[0,0,0,1,0,0,0,0]], -"AUD":["1.6601","1","0","AUD",[0,0,0,0,0,0,0,1]], -"Adobe point":["0.0254","72","0","0",[1,0,0,0,0,0,0,0]], -"At":["1","1","0","siSymbol",[0,0,0,0,1,0,1,0]], -"Australian dollar":["1","1","0","AUD",[0,0,0,0,0,0,0,1]], -"BRL":["5.4099","1","0","BRL",[0,0,0,0,0,0,0,1]], -"BTU":["1055.056","1","0","0",[2,1,-2,0,0,0,0,0]], -"BThU":["1055.056","1","0","0",[2,1,-2,0,0,0,0,0]], -"Bq":["1","1","0","siSymbol",[0,0,-1,0,0,0,0,0]], -"Brazilian Real":["1","1","0","BRL",[0,0,0,0,0,0,0,1]], -"British Pound":["1","1","0","GBP",[0,0,0,0,0,0,0,1]], -"Btu":["1055.056","1","0","0",[2,1,-2,0,0,0,0,0]], -"C":["1","1","0","siSymbol",[0,0,1,1,0,0,0,0]], -"C$":["1","1","0","CAD",[0,0,0,0,0,0,0,1]], -"CAD":["1.4688","1","0","CAD",[0,0,0,0,0,0,0,1]], -"CCF":["1","1","0","0",[3,0,0,0,0,0,0,0]], -"CHF":["0.9729","1","0","CHF",[0,0,0,0,0,0,0,1]], -"CNY":["7.8245","1","0","CNY",[0,0,0,0,0,0,0,1]], -"CY":["0.764554857984","1","0","0",[3,0,0,0,0,0,0,0]], -"Calorie":["4186.8","1","0","0",[2,1,-2,0,0,0,0,0]], -"Canadian dollar":["1","1","0","CAD",[0,0,0,0,0,0,0,1]], -"Celsius":["1","1","273.15","0",[0,0,0,0,1,0,0,0]], -"Chinese Yuan":["1","1","0","CNY",[0,0,0,0,0,0,0,1]], -"Ci":["37000000000","1","0","siSymbol",[0,0,-1,0,0,0,0,0]], -"Ckm":["100000","1","0","siSymbol",[1,0,0,0,0,0,0,0]], -"Da":["1.66053872e-24","1","0","siSymbol",[0,1,0,0,0,0,0,0]], -"Dalton":["1.66053872e-24","1","0","0",[0,1,0,0,0,0,0,0]], -"Didot point":["15.625","41559","0","0",[1,0,0,0,0,0,0,0]], -"EB":["9223372036854770000","1","0","0",[0,0,0,0,0,1,0,0]], -"EMU":["0.01","360000","0","0",[1,0,0,0,0,0,0,0]], -"EUR":["1","1","0","EUR",[0,0,0,0,0,0,0,1]], -"EiB":["9223372036854770000","1","0","0",[0,0,0,0,0,1,0,0]], -"Euro":["1","1","0","EUR",[0,0,0,0,0,0,0,1]], -"F":["1","1","0","siSymbol",[-2,-1,4,2,0,0,0,0]], -"Fahrenheit":["5","9","459","0",[0,0,0,0,1,0,0,0]], -"G":["0.0001","1","0","siSymbol",[-2,-2,-2,-1,0,0,0,0]], -"GB":["8589934592","1","0","0",[0,0,0,0,0,1,0,0]], -"GBP":["0.85795","1","0","GBP",[0,0,0,0,0,0,0,1]], -"Gal":["0.01","1","0","siSymbol",[1,0,-2,0,0,0,0,0]], -"Gi":["10","12.5663706143592","0","siWord",[0,0,0,0,1,0,1,0]], -"GiB":["8589934592","1","0","0",[0,0,0,0,0,1,0,0]], -"Gregorian year":["31556952","1","0","0",[0,0,1,0,0,0,0,0]], -"Gy":["1","1","0","siSymbol",[2,0,-2,0,0,0,0,0]], -"H":["1","1","0","siSymbol",[2,1,-2,-2,0,0,0,0]], -"HK$":["1","1","0","HKD",[0,0,0,0,0,0,0,1]], -"HKD":["8.4645","1","0","HKD",[0,0,0,0,0,0,0,1]], -"HP":["745.69987158227","1","0","0",[2,1,-3,0,0,0,0,0]], -"Hong Kong dollar":["1","1","0","HKD",[0,0,0,0,0,0,0,1]], -"Hz":["1","1","0","siSymbol",[0,0,-1,0,0,0,0,0]], -"ILS":["3.9265","1","0","ILS",[0,0,0,0,0,0,0,1]], -"INR":["90.4090","1","0","INR",[0,0,0,0,0,0,0,1]], -"Indian Rupee":["1","1","0","INR",[0,0,0,0,0,0,0,1]], -"Israeli New Shekel":["1","1","0","ILS",[0,0,0,0,0,0,0,1]], -"J":["1","1","0","siSymbol",[2,1,-2,0,0,0,0,0]], -"JPY":["163.74","1","0","JPY",[0,0,0,0,0,0,0,1]], -"Japanese Yen":["1","1","0","JPY",[0,0,0,0,0,0,0,1]], -"Joule":["1","1","0","0",[2,1,-2,0,0,0,0,0]], -"Julian year":["31557600","1","0","0",[0,0,1,0,0,0,0,0]], -"Jy":["1e-26","1","0","siSymbol",[0,1,-2,0,0,0,0,0]], -"K":["1","1","0","0",[0,0,0,0,1,0,0,0]], -"KiB":["8192","1","0","0",[0,0,0,0,0,1,0,0]], -"KRW":["1453.62","1","0","KRW",[0,0,0,0,0,0,0,1]], -"L":["0.001","1","0","siSymbol",[3,0,0,0,0,0,0,0]], -"Lego stud":["0.008","1","0","siSymbol",[1,0,0,0,0,0,0,0]], -"MB":["8388608","1","0","0",[0,0,0,0,0,1,0,0]], -"MCM":["5.06707479097497e-07","1","0","0",[2,0,0,0,0,0,0,0]], -"MMBtu":["1055056000","1","0","0",[2,1,-2,0,0,0,0,0]], -"MMbbl":["158987.294928","1","0","0",[3,0,0,0,0,0,0,0]], -"MMbblpd":["158987.294928","86400","0","0",[3,0,-1,0,0,0,0,0]], -"MMscf":["28316.846592","1","0","0",[3,0,0,0,0,0,0,0]], -"MMscfd":["0.32774128","1","0","0",[3,0,0,0,0,0,0,0]], -"MT":["1000","1","0","0",[0,1,0,0,0,0,0,0]], -"MXN":["18.1372","1","0","MXN",[0,0,0,0,0,0,0,1]], -"Mach":["331.6","1","0","0",[1,0,-1,0,0,0,0,0]], -"Mbbl":["158.987294928","1","0","0",[3,0,0,0,0,0,0,0]], -"Mexican Peso":["1","1","0","MXN",[0,0,0,0,0,0,0,1]], -"MiB":["8388608","1","0","0",[0,0,0,0,0,1,0,0]], -"Mscfd":["0.00032774128","1","0","0",[3,0,0,0,0,0,0,0]], -"Mscfh":["0.00786579072","1","0","0",[3,0,0,0,0,0,0,0]], -"N":["1","1","0","siSymbol",[1,1,-2,0,0,0,0,0]], -"NM":["1852","1","0","0",[1,0,0,0,0,0,0,0]], -"PB":["9007199254740990","1","0","0",[0,0,0,0,0,1,0,0]], -"PS":["735.49875","1","0","0",[2,1,-3,0,0,0,0,0]], -"Pa":["1","1","0","siSymbol",[-1,1,-2,0,0,0,0,0]], -"Pascal":["1","1","0","siWord",[-1,1,-2,0,0,0,0,0]], -"Pferdestärke":["735.49875","1","0","0",[2,1,-3,0,0,0,0,0]], -"PiB":["9007199254740990","1","0","0",[0,0,0,0,0,1,0,0]], -"R":["0.000258","1","0","siSymbol",[0,-1,1,1,0,0,0,0]], -"R$":["1","1","0","BRL",[0,0,0,0,0,0,0,1]], -"RT":["3516.8532","1","0","0",[2,1,-3,0,0,0,0,0]], -"RUB":["1","1","0","RUB",[0,0,0,0,0,0,0,1]], -"S":["1","1","0","siSymbol",[-2,-1,3,2,0,0,0,0]], -"SF":["0.09290304","1","0","0",[2,0,0,0,0,0,0,0]], -"SY":["0.83612736","1","0","0",[2,0,0,0,0,0,0,0]], -"Sv":["1","1","0","siSymbol",[2,0,-2,0,0,0,0,0]], -"Swiss Franc":["1","1","0","CHF",[0,0,0,0,0,0,0,1]], -"T":["1","1","0","siSymbol",[-2,-2,-2,-1,0,0,0,0]], -"TB":["8796093022208","1","0","0",[0,0,0,0,0,1,0,0]], -"TWD":["1","1","0","TWD",[0,0,0,0,0,0,0,1]], -"TeX point":["0.0003515","1","0","0",[1,0,0,0,0,0,0,0]], -"TiB":["8796093022208","1","0","0",[0,0,0,0,0,1,0,0]], -"US$":["1","1","0","USD",[0,0,0,0,0,0,0,1]], -"USD":["1.0823","1","0","USD",[0,0,0,0,0,0,0,1]], -"V":["1","1","0","siSymbol",[2,1,-3,-1,0,0,0,0]], -"VA":["1","1","0","siSymbol",[2,1,-3,0,0,0,0,0]], -"W":["1","1","0","siSymbol",[2,1,-3,0,0,0,0,0]], -"Wb":["1","1","0","siSymbol",[2,1,-2,-1,0,0,0,0]], -"Wh":["3600","1","0","siSymbol",[2,1,-2,0,0,0,0,0]], -"Won":["1","1","0","KRW",[0,0,0,0,0,0,0,1]], -"Yen":["1","1","0","JPY",[0,0,0,0,0,0,0,1]], -"a":["31556925.9747","1","0","siSymbol",[0,0,1,0,0,0,0,0]], -"ac":["4046.8564224","1","0","0",[2,0,0,0,0,0,0,0]], -"acre":["4046.8564224","1","0","0",[2,0,0,0,0,0,0,0]], -"admiralty mile":["1853.188","1","0","0",[1,0,0,0,0,0,0,0]], -"af":["1233.48183754752","1","0","0",[3,0,0,0,0,0,0,0]], -"amp":["1","1","0","0",[0,0,0,1,0,0,0,0]], -"ampere":["1","1","0","siWord",[0,0,0,1,0,0,0,0]], -"ampere turn":["1","1","0","siWord",[0,0,0,0,1,0,1,0]], -"amu":["1.66053872e-24","1","0","0",[0,1,0,0,0,0,0,0]], -"angstrom":["0.0000000001","1","0","0",[1,0,0,0,0,0,0,0]], -"angstrom star":["0.00000000010000015","1","0","0",[1,0,0,0,0,0,0,0]], -"apostilb":["1","3.14159265358979","0","0",[-2,0,0,0,0,0,1,0]], -"arcminute":["3.14159265358979","10800","0","0",[0,0,0,0,0,0,0,0]], -"arcsecond":["3.14159265358979","648000","0","0",[0,0,0,0,0,0,0,0]], -"are":["100","1","0","0",[2,0,0,0,0,0,0,0]], -"as":["4.3.14159265358979","648000","0","0",[0,0,0,0,0,0,0,0]], -"asb":["1","3.14159265358979","0","0",[-2,0,0,0,0,0,1,0]], -"assay ton":["0.0875","3","0","0",[0,1,0,0,0,0,0,0]], -"astronomical unit":["149597870691","1","0","0",[1,0,0,0,0,0,0,0]], -"atmosphere":["101325","1","0","siSymbol",[-1,1,-2,0,0,0,0,0]], -"au":["149597870691","1","0","0",[1,0,0,0,0,0,0,0]], -"bar":["100000","1","0","siWord",[-1,1,-2,0,0,0,0,0]], -"barg":["100000","1","0","0",[-1,1,-2,0,0,0,0,0]], -"barleycorn":["0.0254","3","0","0",[1,0,0,0,0,0,0,0]], -"barrel":["0.158987294928","1","0","0",[3,0,0,0,0,0,0,0]], -"barrel bulk":["0.14158423296","1","0","0",[3,0,0,0,0,0,0,0]], -"basis point":["0.0001","1","0","0",[0,0,0,0,0,0,0,0]], -"baud":["1","1","0","siSymbol",[0,0,-1,0,0,1,0,0]], -"bbl":["0.158987294928","1","0","0",[3,0,0,0,0,0,0,0]], -"becquerel":["1","1","0","siWord",[0,0,-1,0,0,0,0,0]], -"beer barrel":["0.119240471196","1","0","0",[3,0,0,0,0,0,0,0]], -"bit":["1","1","0","0",[0,0,0,0,0,1,0,0]], -"blink":["0.864","1","0","0",[0,0,1,0,0,0,0,0]], -"bo":["0.158987294928","1","0","0",[3,0,0,0,0,0,0,0]], -"boe":["6119000000","1","0","0",[2,1,-2,0,0,0,0,0]], -"boiler horsepower":["9812.5","1","0","0",[2,1,-3,0,0,0,0,0]], -"bpd":["0.158987294928","86400","0","0",[3,0,-1,0,0,0,0,0]], -"bph":["0.158987294928","3600","0","0",[3,0,-1,0,0,0,0,0]], -"breadth":["0.2286","1","0","0",[1,0,0,0,0,0,0,0]], -"bushel":["0.03523907016688","1","0","0",[3,0,0,0,0,0,0,0]], -"byte":["8","1","0","0",[0,0,0,0,0,1,0,0]], -"caballo de vapor":["735.49875","1","0","0",[2,1,-3,0,0,0,0,0]], -"cal":["4.1868","1","0","0",[2,1,-2,0,0,0,0,0]], -"calorie":["4.1868","1","0","siWord",[2,1,-2,0,0,0,0,0]], -"candela":["1","1","0","siWord",[0,0,0,0,0,0,1,0]], -"candlepower":["1","1","0","siWord",[0,0,0,0,0,0,1,0]], -"carat":["0.00002","1","0","0",[0,1,0,0,0,0,0,0]], -"cc":["0.000001","1","0","0",[3,0,0,0,0,0,0,0]], -"cd":["1","1","0","siSymbol",[0,0,0,0,0,0,1,0]], -"centipoise":["0.001","1","0","0",[-1,1,-1,0,0,0,0,0]], -"centistoke":["0.000001","1","0","0",[2,0,-1,0,0,0,0,0]], -"cfm":["0.0004719474432","1","0","0",[3,0,-1,0,0,0,0,0]], -"cfs":["0.028316846592","1","0","0",[3,0,-1,0,0,0,0,0]], -"ch":["735.49875","1","0","0",[2,1,-3,0,0,0,0,0]], -"chain":["20.116","1","0","0",[1,0,0,0,0,0,0,0]], -"cheval vapeur":["735.49875","1","0","0",[2,1,-3,0,0,0,0,0]], -"cmil":["5.06707479097497e-10","1","0","0",[2,0,0,0,0,0,0,0]], -"cmm":["0.00001","1","0","0",[1,0,0,0,0,0,0,0]], -"constant":["1","1","0","0",[0,0,0,0,0,0,0,0]], -"coulomb":["1","1","0","siWord",[0,0,1,1,0,0,0,0]], -"cp":["1","1","0","siWord",[0,0,0,0,0,0,1,0]], -"cps":["1","1","0","0",[0,0,-1,0,0,0,0,0]], -"cu ft":["0.028316846592","1","0","0",[3,0,0,0,0,0,0,0]], -"cu in":["0.000016387064","1","0","0",[3,0,0,0,0,0,0,0]], -"cu yd":["0.764554857984","1","0","0",[3,0,0,0,0,0,0,0]], -"cubic meter":["1","1","0","0",[3,0,0,0,0,0,0,0]], -"cubic metre":["1","1","0","0",[3,0,0,0,0,0,0,0]], -"cup":["0.0002365882365","1","0","0",[3,0,0,0,0,0,0,0]], -"curie":["37000000000","1","0","siWord",[0,0,-1,0,0,0,0,0]], -"cv":["735.49875","1","0","0",[2,1,-3,0,0,0,0,0]], -"cy":["0.764554857984","1","0","0",[3,0,0,0,0,0,0,0]], -"d":["86400","1","0","0",[0,0,1,0,0,0,0,0]], -"daN":["10","1","0","0",[1,1,-2,0,0,0,0,0]], -"darcy":["0.0000000000009869233","1","0","0",[2,0,0,0,0,0,0,0]], -"day":["86400","1","0","0",[0,0,1,0,0,0,0,0]], -"deg":["3.14159265358979","180","0","0",[0,0,0,0,0,0,0,0]], -"degree":["3.14159265358979","180","0","0",[0,0,0,0,0,0,0,0]], -"dekan":["31.4159265358979","180","0","0",[0,0,0,0,0,0,0,0]], -"diopter":["1","1","0","0",[-1,0,0,0,0,0,0,0]], -"dioptre":["1","1","0","0",[-1,0,0,0,0,0,0,0]], -"dollar":["1","1","0","USD",[0,0,0,0,0,0,0,1]], -"drum":["0.20819764812","1","0","0",[3,0,0,0,0,0,0,0]], -"dscf":["0.028316846592","1","0","0",[3,0,0,0,0,0,0,0]], -"dyn":["0.00001","1","0","0",[1,1,-2,0,0,0,0,0]], -"dyne":["0.00001","1","0","0",[1,1,-2,0,0,0,0,0]], -"eV":["1.602176462e-19","1","0","siSymbol",[2,1,-2,0,0,0,0,0]], -"electric horsepower":["746","1","0","0",[2,1,-3,0,0,0,0,0]], -"electrical horsepower":["746","1","0","0",[2,1,-3,0,0,0,0,0]], -"electron volt":["1.602176462e-19","1","0","0",[2,1,-2,0,0,0,0,0]], -"erg":["0.0000001","1","0","0",[2,1,-2,0,0,0,0,0]], -"euro":["1","1","0","EUR",[0,0,0,0,0,0,0,1]], -"exabyte":["9223372036854770000","1","0","0",[0,0,0,0,0,1,0,0]], -"exbibyte":["9223372036854770000","1","0","0",[0,0,0,0,0,1,0,0]], -"farad":["1","1","0","siWord",[-2,-1,4,2,0,0,0,0]], -"faraday":["96485.339924","1","0","0",[0,0,1,1,0,0,0,0]], -"fathom":["1.8288","1","0","0",[1,0,0,0,0,0,0,0]], -"fc":["10.7639104167097","1","0","0",[-2,0,0,0,0,0,1,0]], -"feet":["0.3048","1","0","0",[1,0,0,0,0,0,0,0]], -"fermi":["0.000000000000001","1","0","siWord",[1,0,0,0,0,0,0,0]], -"fl oz":["0.003785411784","128","0","0",[3,0,0,0,0,0,0,0]], -"flop":["1","1","0","0",[0,0,-1,0,0,0,0,0]], -"fluid ounce":["0.003785411784","128","0","0",[3,0,0,0,0,0,0,0]], -"food calorie":["4186.8","1","0","0",[2,1,-2,0,0,0,0,0]], -"foot":["0.3048","1","0","0",[1,0,0,0,0,0,0,0]], -"footcandle":["10.7639104167097","1","0","0",[-2,0,0,0,0,0,1,0]], -"footlambert":["1","3.14159265358979","0","0",[-2,0,0,0,0,0,1,0]], -"fortnight":["1209600","1","0","0",[0,0,1,0,0,0,0,0]], -"fps":["0.3048","1","0","0",[1,0,-1,0,0,0,0,0]], -"franklin":["0.00000000033356","1","0","siWord",[0,0,1,1,0,0,0,0]], -"ft":["0.3048","1","0","0",[1,0,0,0,0,0,0,0]], -"ft water":["2988.874","1","0","0",[-1,1,-2,0,0,0,0,0]], -"ftc":["10.7639104167097","1","0","0",[-2,0,0,0,0,0,1,0]], -"ftl":["3.426259","1","0","0",[-2,0,0,0,0,0,1,0]], -"furlong":["201.168","1","0","0",[1,0,0,0,0,0,0,0]], -"g":["0.001","1","0","siSymbol",[0,1,0,0,0,0,0,0]], -"gal":["0.003785411784","1","0","0",[3,0,0,0,0,0,0,0]], -"galileo":["0.01","1","0","siWord",[1,0,-2,0,0,0,0,0]], -"gallon":["0.003785411784","1","0","0",[3,0,0,0,0,0,0,0]], -"gauss":["0.0001","1","0","siSymbol",[-2,-2,-2,-1,0,0,0,0]], -"gigabyte":["8589934592","1","0","0",[0,0,0,0,0,1,0,0]], -"gilbert":["10","12.5663706143592","0","siWord",[0,0,0,0,1,0,1,0]], -"gill":["0.003785411784","32","0","0",[3,0,0,0,0,0,0,0]], -"gon":["3.14159265358979","200","0","0",[0,0,0,0,0,0,0,0]], -"gongjin":["1","1","0","siSymbol",[0,1,0,0,0,0,0,0]], -"gongli":["1000","1","0","siSymbol",[1,0,0,0,0,0,0,0]], -"gpd":["0.003785411784","86400","0","0",[3,0,-1,0,0,0,0,0]], -"gph":["0.003785411784","3600","0","0",[3,0,-1,0,0,0,0,0]], -"gpm":["0.003785411784","60","0","0",[3,0,-1,0,0,0,0,0]], -"gps":["0.003785411784","1","0","0",[3,0,-1,0,0,0,0,0]], -"gr":["0.00006479891","1","0","0",[0,1,0,0,0,0,0,0]], -"grad":["3.14159265358979","200","0","0",[0,0,0,0,0,0,0,0]], -"grain":["0.00006479891","1","0","0",[0,1,0,0,0,0,0,0]], -"gram":["0.001","1","0","0",[0,1,0,0,0,0,0,0]], -"gramme":["0.001","1","0","0",[0,1,0,0,0,0,0,0]], -"gray":["1","1","0","0",[2,0,-2,0,0,0,0,0]], -"great year":["814000000000","1","0","0",[0,0,1,0,0,0,0,0]], -"gsm":["0.001","1","0","0",[-2,1,0,0,0,0,0,0]], -"gutenberg":["0.0254","7200","0","0",[1,0,0,0,0,0,0,0]], -"gōngjin":["1","1","0","siSymbol",[0,1,0,0,0,0,0,0]], -"gōngli":["1000","1","0","siSymbol",[1,0,0,0,0,0,0,0]], -"h":["3600","1","0","0",[0,0,1,0,0,0,0,0]], -"ha":["10000","1","0","siSymbol",[2,0,0,0,0,0,0,0]], -"hand":["0.1016","1","0","0",[1,0,0,0,0,0,0,0]], -"hectare":["10000","1","0","siWord",[2,0,0,0,0,0,0,0]], -"helek":["10","3","0","0",[0,0,1,0,0,0,0,0]], -"hemisphere":["6.28318530717959","1","0","0",[0,0,0,0,0,0,0,0]], -"henrie":["1","1","0","siWord",[2,1,-2,-2,0,0,0,0]], -"henry":["1","1","0","siWord",[2,1,-2,-2,0,0,0,0]], -"hertz":["1","1","0","siWord",[0,0,-1,0,0,0,0,0]], -"hk":["735.49875","1","0","0",[2,1,-3,0,0,0,0,0]], -"horsepower":["745.69987158227","1","0","0",[2,1,-3,0,0,0,0,0]], -"hour":["3600","1","0","0",[0,0,1,0,0,0,0,0]], -"hp":["745.69987158227","1","0","0",[2,1,-3,0,0,0,0,0]], -"hpE":["746","1","0","0",[2,1,-3,0,0,0,0,0]], -"hpI":["745.69987158227","1","0","0",[2,1,-3,0,0,0,0,0]], -"hpM":["735.49875","1","0","0",[2,1,-3,0,0,0,0,0]], -"hpS":["9812.5","1","0","0",[2,1,-3,0,0,0,0,0]], -"hr":["3600","1","0","0",[0,0,1,0,0,0,0,0]], -"in":["0.0254","1","0","0",[1,0,0,0,0,0,0,0]], -"in Hg":["3863.8","1","0","0",[-1,1,-2,0,0,0,0,0]], -"inch":["0.0254","1","0","0",[1,0,0,0,0,0,0,0]], -"inche":["0.0254","1","0","0",[1,0,0,0,0,0,0,0]], -"jansky":["1e-26","1","0","0",[0,1,-2,0,0,0,0,0]], -"jar":["1","900000000","0","0",[-2,-1,4,2,0,0,0,0]], -"joule":["1","1","0","0",[2,1,-2,0,0,0,0,0]], -"k":["4448.2216152605","1","0","0",[1,1,-2,0,0,0,0,0]], -"kB":["8192","1","0","0",[0,0,0,0,0,1,0,0]], -"kB":["8192","1","0","0",[0,0,0,0,0,1,0,0]], -"kairi":["1852","1","0","0",[1,0,0,0,0,0,0,0]], -"kanal":["505.8570528","1","0","0",[2,0,0,0,0,0,0,0]], -"katal":["6.02214179e+23","1","0","siWord",[0,0,-1,0,0,1,0,0]], -"kcal":["4186.8","1","0","0",[2,1,-2,0,0,0,0,0]], -"kcmil":["5.06707479097497e-07","1","0","0",[2,0,0,0,0,0,0,0]], -"keg":["0.058673882652","1","0","0",[3,0,0,0,0,0,0,0]], -"kelvin":["1","1","0","0",[0,0,0,0,1,0,0,0]], -"kgf":["9.80665","1","0","0",[1,1,-2,0,0,0,0,0]], -"kilo":["1","1","0","0",[0,1,0,0,0,0,0,0]], -"kilobyte":["8192","1","0","0",[0,0,0,0,0,1,0,0]], -"kilogram":["1","1","0","0",[0,1,0,0,0,0,0,0]], -"kilogramme":["1","1","0","0",[0,1,0,0,0,0,0,0]], -"kilopond":["9.80665","1","0","0",[1,1,-2,0,0,0,0,0]], -"kip":["4448.2216152605","1","0","0",[1,1,-2,0,0,0,0,0]], -"klf":["4448.2216152605","0.3048","0","0",[0,1,-2,0,0,0,0,0]], -"kn":["1852","3600","0","0",[1,0,-1,0,0,0,0,0]], -"knot":["1852","3600","0","0",[1,0,-1,0,0,0,0,0]], -"kp":["9.80665","1","0","0",[1,1,-2,0,0,0,0,0]], -"kpf":["4448.2216152605","0.3048","0","0",[0,1,-2,0,0,0,0,0]], -"kph":["1000/3600","1","0","0",[1,0,-1,0,0,0,0,0]], -"kpph":["1000/3600","1","0","0",[-1,1,-3,0,0,0,0,0]], -"ks":["735.49875","1","0","0",[2,1,-3,0,0,0,0,0]], -"ksf":["47880.2589803358","1","0","0",[-1,1,-2,0,0,0,0,0]], -"ksi":["6894757.29316836","1","0","0",[-1,1,-2,0,0,0,0,0]], -"kwh":["3600000","1","0","0",[2,1,-2,0,0,0,0,0]], -"l":["0.001","1","0","siSymbol",[3,0,0,0,0,0,0,0]], -"lambert":["10000","3.14159265358979","0","0",[-2,0,0,0,0,0,1,0]], -"lb":["0.45359237","1","0","0",[0,1,0,0,0,0,0,0]], -"lbf":["4.4482216152605","1","0","0",[1,1,-2,0,0,0,0,0]], -"lbm":["0.45359237","1","0","0",[0,1,0,0,0,0,0,0]], -"league":["5556","1","0","0",[1,0,0,0,0,0,0,0]], -"lf":["0.3048","1","0","0",[1,0,0,0,0,0,0,0]], -"li":["500","1","0","0",[1,0,0,0,0,0,0,0]], -"light year":["9460730472580800","1","0","0",[1,0,0,0,0,0,0,0]], -"link":["0.201168","1","0","0",[1,0,0,0,0,0,0,0]], -"liter":["0.001","1","0","siWord",[3,0,0,0,0,0,0,0]], -"litre":["0.001","1","0","siWord",[3,0,0,0,0,0,0,0]], -"lm":["1","1","0","siSymbol",[0,0,0,0,0,0,1,0]], -"long ton":["1016.0469088","1","0","0",[0,1,0,0,0,0,0,0]], -"lt":["1016.0469088","1","0","0",[0,1,0,0,0,0,0,0]], -"ltpd":["0.0117598021851852","1","0","0",[0,1,-1,0,0,0,0,0]], -"lumen":["1","1","0","siWord",[0,0,0,0,0,0,1,0]], -"lunar day":["89416.32","1","0","0",[0,0,1,0,0,0,0,0]], -"lunar month":["2551442.976","1","0","0",[0,0,1,0,0,0,0,0]], -"lux":["1","1","0","siWord",[-2,0,0,0,0,0,1,0]], -"lx":["1","1","0","siSymbol",[-2,0,0,0,0,0,1,0]], -"m":["1","1","0","siSymbol",[1,0,0,0,0,0,0,0]], -"mD":["9.869233e-16","1","0","0",[2,0,0,0,0,0,0,0]], -"marathon":["42195","1","0","0",[1,0,0,0,0,0,0,0]], -"marla":["25.29285264","1","0","0",[2,0,0,0,0,0,0,0]], -"mas":["3.14159265358979","648000000","0","0",[0,0,0,0,0,0,0,0]], -"maxwell":["0.00000001","1","0","siSymbol",[2,1,-2,-1,0,0,0,0]], -"mb":["100","1","0","0",[-1,1,-2,0,0,0,0,0]], -"megabyte":["8388608","1","0","0",[0,0,0,0,0,1,0,0]], -"megaton TNT":["4184000000000000","1","0","0",[2,1,-2,0,0,0,0,0]], -"megatons TNT":["4184000000000000","1","0","0",[2,1,-2,0,0,0,0,0]], -"megohm":["1000000","1","0","0",[2,1,-3,-2,0,0,0,0]], -"meter":["1","1","0","siWord",[1,0,0,0,0,0,0,0]], -"metre":["1","1","0","siWord",[1,0,0,0,0,0,0,0]], -"metric horsepower":["735.49875","1","0","0",[2,1,-3,0,0,0,0,0]], -"metric ton":["1000","1","0","0",[0,1,0,0,0,0,0,0]], -"mgd":["3785.411784","86400","0","0",[3,0,-1,0,0,0,0,0]], -"mho":["1","1","0","0",[-2,-1,3,2,0,0,0,0]], -"mi":["1609.344","1","0","0",[1,0,0,0,0,0,0,0]], -"mil":["0.0000254","1","0","0",[1,0,0,0,0,0,0,0]], -"mile":["1609.344","1","0","0",[1,0,0,0,0,0,0,0]], -"min":["60","1","0","0",[0,0,1,0,0,0,0,0]], -"minute":["60","1","0","0",[0,0,1,0,0,0,0,0]], -"moa":["3.14159265358979","10800","0","0",[0,0,0,0,0,0,0,0]], -"mol":["6.02214179e+23","1","0","0",[0,0,0,0,0,1,0,0]], -"mole":["6.02214179e+23","1","0","0",[0,0,0,0,0,1,0,0]], -"mpg":["1609.344","0.003785411784","0","0",[-2,0,0,0,0,0,0,0]], -"mph":["0.44704","1","0","0",[1,0,-1,0,0,0,0,0]], -"mt":["1000","1","0","0",[0,1,0,0,0,0,0,0]], -"nautical mile":["1852","1","0","0",[1,0,0,0,0,0,0,0]], -"newton":["1","1","0","0",[1,1,-2,0,0,0,0,0]], -"nit":["1","1","0","0",[-2,0,0,0,0,0,1,0]], -"ohm":["1","1","0","siWord",[2,1,-3,-2,0,0,0,0]], -"ounce":["0.45359237","16","0","0",[0,1,0,0,0,0,0,0]], -"oz":["0.45359237","16","0","0",[0,1,0,0,0,0,0,0]], -"oz t":["0.0311034768","1","0","0",[0,1,0,0,0,0,0,0]], -"parsec":["30856780000000000","1","0","0",[1,0,0,0,0,0,0,0]], -"pc":["0.0254","6","0","0",[1,0,0,0,0,0,0,0]], -"pcf":["4.4482216152605","0.028316846592","0","0",[-2,1,-2,0,0,0,0,0]], -"pci":["4.4482216152605","0.000016387064","0","0",[-2,1,-2,0,0,0,0,0]], -"pebibyte":["9007199254740990","1","0","0",[0,0,0,0,0,1,0,0]], -"peck":["0.00880976754172","1","0","0",[3,0,0,0,0,0,0,0]], -"perfect ream":["516","1","0","0",[0,0,0,0,0,1,0,0]], -"person":["1","1","0","0",[0,0,0,0,0,1,0,0]], -"petabyte":["9007199254740990","1","0","0",[0,0,0,0,0,1,0,0]], -"pfd":["0.5","1","0","0",[0,1,0,0,0,0,0,0]], -"pferdestärke":["735.49875","1","0","0",[2,1,-3,0,0,0,0,0]], -"pfund":["0.5","1","0","0",[0,1,0,0,0,0,0,0]], -"phot":["10000","1","0","0",[-2,0,0,0,0,0,1,0]], -"pica":["0.0254","6","0","0",[1,0,0,0,0,0,0,0]], -"pied du roi":["9000","27706","0","0",[1,0,0,0,0,0,0,0]], -"pieze":["1000","1","0","0",[-1,1,-2,0,0,0,0,0]], -"pint":["0.000473176473","1","0","0",[3,0,0,0,0,0,0,0]], -"pk":["735.49875","1","0","0",[2,1,-3,0,0,0,0,0]], -"platonic year":["814000000000","1","0","0",[0,0,1,0,0,0,0,0]], -"plf":["4.4482216152605","0.3048","0","0",[0,1,-2,0,0,0,0,0]], -"point":["0.0254","72","0","0",[1,0,0,0,0,0,0,0]], -"poise":["0.1","1","0","siWord",[-1,1,-1,0,0,0,0,0]], -"pound":["0.45359237","1","0","0",[0,1,0,0,0,0,0,0]], -"poundal":["4.4482216152605","32.174","0","0",[1,1,-2,0,0,0,0,0]], -"ppm":["0.000001","1","0","0",[0,0,0,0,0,0,0,0]], -"ppmdv":["0.000001","1","0","0",[0,0,0,0,0,0,0,0]], -"ppmv":["0.000001","1","0","0",[0,0,0,0,0,0,0,0]], -"ppmw":["0.000001","1","0","0",[0,0,0,0,0,0,0,0]], -"printer's point":["0.0003515","1","0","0",[1,0,0,0,0,0,0,0]], -"printer's ream":["516","1","0","0",[0,0,0,0,0,1,0,0]], -"ps":["735.49875","1","0","0",[2,1,-3,0,0,0,0,0]], -"psf":["4.4482216152605","0.09290304","0","0",[-1,1,-2,0,0,0,0,0]], -"psi":["4.4482216152605","0.00064516","0","0",[-1,1,-2,0,0,0,0,0]], -"psia":["6894.75729316836","1","0","0",[-1,1,-2,0,0,0,0,0]], -"psig":["6894.75729316836","1","14.6959","0",[-1,1,-2,0,0,0,0,0]], -"px":["0.0254","96","0","0",[1,0,0,0,0,0,0,0]], -"pz":["1000","1","0","0",[-1,1,-2,0,0,0,0,0]], -"quart":["0.003785411784","4","0","0",[3,0,0,0,0,0,0,0]], -"quire":["25","1","0","0",[0,0,0,0,0,1,0,0]], -"rad":["1","1","0","0",[0,0,0,0,0,0,0,0]], -"radian":["1","1","0","0",[0,0,0,0,0,0,0,0]], -"rankin":["5","9","0","0",[0,0,0,0,1,0,0,0]], -"rd":["0.01","1","0","siSymbol",[2,0,-2,0,0,0,0,0]], -"real":["1","1","0","BRL",[0,0,0,0,0,0,0,1]], -"ream":["500","1","0","0",[0,0,0,0,0,1,0,0]], -"rem":["0.01","1","0","siSymbol",[2,0,-2,0,0,0,0,0]], -"rev":["6.28318530717959","1","0","0",[0,0,0,0,0,0,0,0]], -"rod":["5.0292","1","0","0",[1,0,0,0,0,0,0,0]], -"roentgen":["0.000258","1","0","siWord",[0,-1,1,1,0,0,0,0]], -"rpm":["6.28318530717959","3600","0","0",[0,0,-1,0,0,0,0,0]], -"ruble":["1","1","0","RUB",[0,0,0,0,0,0,0,1]], -"röntgen":["0.000258","1","0","siWord",[0,-1,1,1,0,0,0,0]], -"s":["1","1","0","siSymbol",[0,0,1,0,0,0,0,0]], -"saltspoon":["0.003785411784","3072","0","0",[3,0,0,0,0,0,0,0]], -"scf":["0.028316846592","1","0","0",[3,0,0,0,0,0,0,0]], -"scfd":["0.028316846592","86400","0","0",[3,0,-1,0,0,0,0,0]], -"scfh":["0.028316846592","3600","0","0",[3,0,-1,0,0,0,0,0]], -"scfm":["0.028316846592","60","0","0",[3,0,-1,0,0,0,0,0]], -"sea mile":["1852","1","0","0",[1,0,0,0,0,0,0,0]], -"sec":["1","1","0","0",[0,0,1,0,0,0,0,0]], -"second":["1","1","0","0",[0,0,1,0,0,0,0,0]], -"section":["2589988.110336","1","0","0",[2,0,0,0,0,0,0,0]], -"sennight":["604800","1","0","0",[0,0,1,0,0,0,0,0]], -"sheet":["1","1","0","0",[0,0,0,0,0,1,0,0]], -"short ream":["480","1","0","0",[0,0,0,0,0,1,0,0]], -"short ton":["907.18474","1","0","0",[0,1,0,0,0,0,0,0]], -"siemen":["1","1","0","siWord",[-2,-1,3,2,0,0,0,0]], -"sievert":["1","1","0","siWord",[2,0,-2,0,0,0,0,0]], -"slinch":["175.126835246477","1","0","0",[0,1,0,0,0,0,0,0]], -"slug":["14.5939029372064","1","0","0",[0,1,0,0,0,0,0,0]], -"smoot":["1.7018","1","0","0",[0,1,0,0,0,0,0,0]], -"span":["0.2286","1","0","0",[1,0,0,0,0,0,0,0]], -"sphere":["12.5663706143592","1","0","0",[0,0,0,0,0,0,0,0]], -"sq ft":["0.09290304","1","0","0",[2,0,0,0,0,0,0,0]], -"sq in":["0.00064516","1","0","0",[2,0,0,0,0,0,0,0]], -"sq km":["1000000","1","0","0",[2,0,0,0,0,0,0,0]], -"sq mi":["2589988.110336","1","0","0",[2,0,0,0,0,0,0,0]], -"sq yd":["0.83612736","1","0","0",[2,0,0,0,0,0,0,0]], -"square degree":["0.000304617419786709","1","0","0",[0,0,0,0,0,0,0,0]], -"square meter":["1","1","0","0",[2,0,0,0,0,0,0,0]], -"square metre":["1","1","0","0",[2,0,0,0,0,0,0,0]], -"square mi":["2589988.110336","1","0","0",[2,0,0,0,0,0,0,0]], -"sr":["1","1","0","siSymbol",[0,0,0,0,0,0,0,0]], -"ssp":["0.003785411784","3072","0","0",[3,0,0,0,0,0,0,0]], -"standard volume":["22.414","1","0","0",[3,0,0,0,0,0,0,0]], -"statampere":["0.00000000033356","1","0","0",[0,0,0,1,0,0,0,0]], -"statcoulomb":["0.00000000033356","1","0","0",[0,0,1,1,0,0,0,0]], -"statfarad":["0.0000000000011126","1","0","0",[-2,-1,4,2,0,0,0,0]], -"stathenrie":["898760000000","1","0","0",[2,1,-2,-2,0,0,0,0]], -"stathenry":["898760000000","1","0","0",[2,1,-2,-2,0,0,0,0]], -"statohm":["898760000000","1","0","0",[2,1,-3,-2,0,0,0,0]], -"statvolt":["299.79","1","0","0",[2,1,-3,-1,0,0,0,0]], -"statwatt":["0.0000001","1","0","0",[2,1,-3,0,0,0,0,0]], -"steam horsepower":["9812.5","1","0","0",[2,1,-3,0,0,0,0,0]], -"steradian":["1","1","0","0",[0,0,0,0,0,0,0,0]], -"stere":["1","1","0","0",[3,0,0,0,0,0,0,0]], -"stoke":["0.0001","1","0","0",[2,0,-1,0,0,0,0,0]], -"stone":["6.35029318","1","0","0",[0,1,0,0,0,0,0,0]], -"stpd":["0.0104998233796296","1","0","0",[0,1,-1,0,0,0,0,0]], -"stunde":["3600","1","0","0",[0,0,1,0,0,0,0,0]], -"survey feet":["1200","3937","0","0",[1,0,0,0,0,0,0,0]], -"survey foot":["1200","3937","0","0",[1,0,0,0,0,0,0,0]], -"Sv":["1","1","0","siSymbol",[2,0,-2,0,0,0,0,0]], -"sverdrup":["1000000","1","0","0",[3,0,-1,0,0,0,0,0]], -"sym":["1","1","0","siSymbol",[0,0,0,0,0,1,0,0]], -"tablespoon":["0.003785411784","256","0","0",[3,0,0,0,0,0,0,0]], -"tbsp":["0.003785411784","256","0","0",[3,0,0,0,0,0,0,0]], -"teaspoon":["0.003785411784","768","0","0",[3,0,0,0,0,0,0,0]], -"tebibyte":["8796093022208","1","0","0",[0,0,0,0,0,1,0,0]], -"terabyte":["8796093022208","1","0","0",[0,0,0,0,0,1,0,0]], -"tesla":["1","1","0","siSymbol",[-2,-2,-2,-1,0,0,0,0]], -"therm":["105480400","1","0","0",[2,1,-2,0,0,0,0,0]], -"tidal day":["89416.32","1","0","0",[0,0,1,0,0,0,0,0]], -"ton":["907.18474","1","0","0",[0,1,0,0,0,0,0,0]], -"tonf":["8896.443230521","1","0","0",[1,1,-2,0,0,0,0,0]], -"ton TNT":["4184000000","1","0","0",[2,1,-2,0,0,0,0,0]], -"ton refrigeration":["3516.8532","1","0","0",[2,1,-3,0,0,0,0,0]], -"tonne":["1000","1","0","0",[0,1,0,0,0,0,0,0]], -"tons TNT":["4184000000","1","0","0",[2,1,-2,0,0,0,0,0]], -"tons refrigeration":["3516.8532","1","0","0",[2,1,-3,0,0,0,0,0]], -"township":["93239571.972096","1","0","0",[2,0,0,0,0,0,0,0]], -"toz":["0.0311034768","1","0","0",[0,1,0,0,0,0,0,0]], -"tpy":["0.0000287475400032297","1","0","0",[0,1,-1,0,0,0,0,0]], -"tropical year":["31556925.9747","1","0","0",[0,0,1,0,0,0,0,0]], -"troy ounce":["0.0311034768","1","0","0",[0,1,0,0,0,0,0,0]], -"tsp":["0.003785411784","768","0","0",[3,0,0,0,0,0,0,0]], -"turn":["6.28318530717958","1","0","0",[0,0,0,0,0,0,0,0]], -"twip":["0.0254","1440","0","0",[1,0,0,0,0,0,0,0]], -"unit":["1","1","0","0",[0,0,0,0,0,1,0,0]], -"vapeur":["735.49875","1","0","0",[2,1,-3,0,0,0,0,0]], -"var":["1","1","0","siSymbol",[2,1,-3,0,0,0,0,0]], -"varistor":["1","1","0","siWord",[2,1,-3,0,0,0,0,0]], -"volt":["1","1","0","siWord",[2,1,-3,-1,0,0,0,0]], -"watt":["1","1","0","siWord",[2,1,-3,0,0,0,0,0]], -"weber":["1","1","0","siSymbol",[2,1,-2,-1,0,0,0,0]], -"week":["604800","1","0","0",[0,0,1,0,0,0,0,0]], -"won":["1","1","0","KRW",[0,0,0,0,0,0,0,1]], -"wppm":["0.000001","1","0","0",[0,0,0,0,0,0,0,0]], -"yard":["0.9144","1","0","0",[1,0,0,0,0,0,0,0]], -"yd":["0.9144","1","0","0",[1,0,0,0,0,0,0,0]], -"year":["31556952","1","0","0",[0,0,1,0,0,0,0,0]], -"yen":["1","1","0","JPY",[0,0,0,0,0,0,0,1]], -"£":["1","1","0","GBP",[0,0,0,0,0,0,0,1]], -"¥":["1","1","0","JPY",[0,0,0,0,0,0,0,1]], -"°":["3.14159265358979","180","0","0",[0,0,0,0,0,0,0,0]], -"°C":["1","1","273.15","0",[0,0,0,0,1,0,0,0]], -"°F":["5","9","459","0",[0,0,0,0,1,0,0,0]], -"°K":["1","1","0","0",[0,0,0,0,1,0,0,0]], -"°R":["5","9","0","0",[0,0,0,0,1,0,0,0]], -"°R":["5","9","0","0",[0,0,0,0,1,0,0,0]], -"Å":["0.0000000001","1","0","0",[1,0,0,0,0,0,0,0]], -"Ω":["1","1","0","siSymbol",[2,1,-3,-2,0,0,0,0]], -"”":["0.0254","1","0","0",[1,0,0,0,0,0,0,0]], -"₨":["1","1","0","INR",[0,0,0,0,0,0,0,1]], -"₪":["1","1","0","ILS",[0,0,0,0,0,0,0,1]], -"€":["1","1","0","EUR",[0,0,0,0,0,0,0,1]], -"℃":["1","1","273.15","0",[0,0,0,0,1,0,0,0]], -"℉":["5","9","459","0",[0,0,0,0,1,0,0,0]], -"Ω":["1","1","0","siSymbol",[2,1,-3,-2,0,0,0,0]], -"K":["1","1","0","0",[0,0,0,0,1,0,0,0]], -"Å":["0.0000000001","1","0","0",[1,0,0,0,0,0,0,0,0]] -}`)); - -const synonyms = Object.freeze({ - "$": "USD", - "US$": "USD", - "dollar": "USD", - "A$": "AUD", - "Australian dollar": "AUD", - "Brazilian Real": "BRL", - "real": "BRL", - "R$": "BRL", - "British Pound": "GBP", - "£": "GBP", - "C$": "CAD", - "Canadian dollar": "CAD", - "Chinese Yuan": "CNY", - "€": "EUR", - "Euro": "EUR", - "euro": "EUR", - "HK$": "HKD", - "Hong Kong dollar":"HKD", - "Indian Rupee": "IDR", - "₨": "IDR", - "Israeli New Shekel": "ILS", - "₪": "ILS", - "Mexican Peso": "MXN", - "Swiss Franc": "CHF", - "Won": "KRW", - "won": "KRW", - "yen": "JPY", - "Yen": "JPY", - "Japanese Yen": "JPY", - "¥": "JPY" -}); - -const unitFromWord = (inputStr) => { - const str = inputStr.trim(); - const L = str.length; - const u = { - name: str, - factor: Rnl.one, - gauge: Rnl.zero, - log: "", - expos: [0, 0, 0, 0, 0, 0, 0, 0] - }; - if (inputStr === "") { return u } - let word = ""; - let unitArray; - let doTheSearch = false; - let prefix = ""; - let gotSiPrefixUnit = false; - let gotMatch = false; - - for (let iPass = 1; iPass < 3; iPass++) { - if (iPass === 1) { - // The first pass will search with the assumption of no short-form SI prefix. - // We will, however, check for a long form SI prefix if the word is long enough. - - doTheSearch = true; - word = str; - - // Translate plural to signular - if (L > 2) { - if (word.charAt(word.length - 1) === "s") { - if (!(word === "cfs" || (L === 3 & word.charAt(1) === "p"))) { - word = word.slice(0, -1); - } - } - } - - let prefix = ""; - if (L > 3) { - const match = /^(yotta|zetta|exa|peta|tera|giga|mega|kilo|hecto|deka|deci|centi|milli|micro|nano|pico|femto|atto|zepto|yocto)/.exec(word); - if (match) { - prefix = match[0].value; - doTheSearch = true; - word = word.slice(prefix.length); - } - } - } else { - // We're in the second pass. Try an SI short-form prefix. - doTheSearch = false; - prefix = word.charAt(0); - if ("YZEPTGMkhdcmnpfazyµμ".indexOf(prefix) > -1) { - doTheSearch = true; - word = word.substring(1); - } - } - - if (doTheSearch) { - unitArray = unitTable[word]; - if (unitArray) { gotMatch = true; } - if (iPass === 1 && gotMatch && prefix === "") { - break - } else if (gotMatch) { - if (iPass === 1) { - gotMatch = (unitArray[3] === "siWord"); - gotSiPrefixUnit = true; - break - } else { - gotMatch = (unitArray[3] === "siSymbol"); - gotSiPrefixUnit = true; - } - } - } - } - - if (gotMatch) { - u.gauge = Rnl.fromString(unitArray[2]); - u.expos = Object.freeze(unitArray[4]); - if (u.expos[7] === 1) { - const currencyCode = (synonyms[word] ? synonyms[word] : word); - // Read the line whose key is the standard 3-letter currency code. - unitArray = unitTable[currencyCode]; - if (unitArray[0] === "0") { - return errorOprnd("CURRENCY") - } else { - u.factor = Rnl.reciprocal(Rnl.fromString(unitArray[0])); - } - } else { - // TODO: Change factor table to integers and use BigInt() instead of Rnl.fromString - u.factor = Rnl.divide(Rnl.fromString(unitArray[0]), Rnl.fromString(unitArray[1])); - } - - if (gotSiPrefixUnit) { - u.factor = Rnl.multiply(u.factor, Rnl.fromNumber(prefixFactor[prefix])); - } - - // TODO: Logarithmic units like dB or EMM -// const misc = unitArray[3] // SI prefix, or logarithm data, or 3-letter currency code -// if (misc === "10") { -// u.log = "°" -// } else if (misc === "10+") { -// u.log = "10+" + " " + u.gauge + " " + u.factor -// } - - } else { - return errorOprnd("UNIT_NAME", str) - } - - return Object.freeze(u) -}; - -const opOrNumRegEx = /[0-9·\-⁰¹²³\u2074-\u2079⁻/^()]/; -const numeralRegEx = /[0-9-]/; -const opRegEx = /^[·/\-^]$/; - -const unitFromUnitName = (inputStr) => { - - // TODO: Handle ° ʹ ″ - - if (!inputStr) { return { name: null, factor: null, gauge: null, log: "", expos: null } } - - let str = inputStr.trim(); - // Replace dashes & bullets with half-high dot - str = str.replace(/[*.•×\-−](?![0-9.])/g, "·"); - - // Create a unit object with default values. - const u = { name: str, factor: Rnl.one, gauge: Rnl.zero, log: "", expos: allZeros }; - - if (str === "") { - return u - } else if (str === "°" || str === "°ʹ" || str === "degMinSec") { - u.factor = Rnl.fromString("0.0174532925199433"); - return u - } else if (str === "feetInch") { - u.unitExpos = [1, 0, 0, 0, 0, 0, 0, 0]; - u.factor = Rnl.fromString("0.3048"); - return u - } else if (str === "″" || str === "ʹʹ") { - // TODO: Move to unitTable - u.unitExpos = [1, 0, 0, 0, 0, 0, 0, 0]; - u.factor = Rnl.fromString("0.0254"); - return u - } - - // Parse str for compound units - const tokenSep = ";"; - let inExponent = false; - let ch = ""; - let word = ""; - let rpnString = ""; - let expoRpnString = ""; - const expoQueue = []; - let iQueue = 0; - const opStack = [{ symbol: "", prec: -1 }]; - let simpleUnit = ""; - - // Operator Precedence for shunting yard algorithm - // 0 ( ) parentheses - // 1 · / multiplication or division - // 2 - unary minus operator - // 3 ^ exponentiation, right-to-left - - for (let i = 0; i < str.length; i++) { - ch = str.charAt(i); - - if (numeralRegEx.test(ch)) { - if (!inExponent) { - rpnString += tokenSep; - expoRpnString += tokenSep; - opStack.push({ symbol: "^", prec: 3 }); - inExponent = true; - } - rpnString += ch; // Append numbers directly to the RPN string. - expoRpnString += ch; - - } else if (exponentRegEx.test(ch)) { - if (!inExponent) { - rpnString += tokenSep; - expoRpnString += tokenSep; - opStack.push({ symbol: "^", prec: 3 }); - inExponent = true; - } - const asciiCh = numeralFromSuperScript(ch); - rpnString += asciiCh; // Append numbers directly to the RPN string. - expoRpnString += asciiCh; - - } else if (ch === "^") { - // The "^" character is not required, but it is permitted. - rpnString += tokenSep; - expoRpnString += tokenSep; - opStack.push({ symbol: "^", prec: 3 }); - inExponent = true; - - } else if (ch === "·" || ch === "/") { - inExponent = false; - rpnString += tokenSep; - expoRpnString += tokenSep; - while (opStack[opStack.length - 1].prec >= 1) { - const symbol = opStack.pop().symbol; - rpnString += symbol + tokenSep; - expoRpnString += symbol + tokenSep; - } - opStack.push({ symbol: ch, prec: 1 }); - - } else if (ch === "(") { - opStack.push({ symbol: "(", prec: 0 }); - - } else if (ch === ")") { - while (opStack[opStack.length - 1].prec > 0) { - const symbol = opStack.pop().symbol; - rpnString += symbol + tokenSep; - expoRpnString += symbol + tokenSep; - } - opStack.pop(); // Discard the opening parenthesis. - inExponent = false; - - } else if (ch === "-") { // Negative unary operator at the start of an exponent. - inExponent = true; - opStack.push({ symbol: "^", prec: 3 }); - opStack.push({ symbol: "-", prec: 2 }); - rpnString += tokenSep; - expoRpnString += tokenSep; - - } else { - inExponent = false; - let j; - for (j = i + 1; j < str.length; j++) { - if (opOrNumRegEx.test(str.charAt(j))) { break } - } - word = str.substring(i, j); // May actually be two words, as in "nautical miles" - simpleUnit = unitFromWord(word); - - if (simpleUnit.dtype && simpleUnit.dtype === dt.ERROR) { return simpleUnit } - - if (simpleUnit.factor === 0) { - u.name = ""; - return u - } - - rpnString += String(simpleUnit.factor[0]) + "," + String(simpleUnit.factor[1]); - expoRpnString += "¿" + iQueue; - expoQueue.push(simpleUnit.expos); - iQueue += 1; - - i = j - 1; - } - - } - - if (word === u.name) { - return Object.freeze(simpleUnit) - } - - // All the input characters have been addresssed. Clear the opStack. - while (opStack.length > 1) { - const symbol = opStack.pop().symbol; - rpnString += tokenSep + symbol; - expoRpnString += tokenSep + symbol; - } - - // Now, resolve the RPN string - const factors = []; - const expoStack = []; - const rpnArray = rpnString.split(tokenSep); - const expoRpnArray = expoRpnString.split(tokenSep); - let val2 = 1; - let e2; - iQueue = 0; - - for (let i = 0; i < rpnArray.length; i++) { - if (opRegEx.test(rpnArray[i])) { - val2 = factors.pop(); - e2 = expoStack.pop(); - } - - switch (rpnArray[i]) { - case "·": - factors[factors.length - 1] = Rnl.multiply(factors[factors.length - 1], val2); - expoStack[expoStack.length - 1] = expoStack[expoStack.length - 1].map((el, j) => { - return el + e2[j] - }); - break - - case "/": - // TODO: Rewrite next line. - if (Rnl.isZero(val2)) { return errorOprnd("DIV") } - factors[factors.length - 1] = Rnl.divide(factors[factors.length - 1], val2); - expoStack[expoStack.length - 1] = expoStack[expoStack.length - 1].map((el, j) => { - return el - e2[j] - }); - break - - case "^": - factors[factors.length - 1] = Rnl.power(factors[factors.length - 1], val2); - expoStack[expoStack.length - 1] = expoStack[expoStack.length - 1].map((el) => el * e2); - break - - case "-": // Negative unary operator - factors[factors.length - 1] = Rnl.negate(factors[factors.length - 1]); - break - - default: - if (rpnArray[i].indexOf(",") > -1) { - const ints = rpnArray[i].split(","); - factors.push([BigInt(ints[0]), BigInt(ints[1])]); - } else { - factors.push([BigInt(rpnArray[i]), BigInt(1)]); - } - if (expoRpnArray[i].charAt(0) === "¿") { - expoStack.push(expoQueue[iQueue]); - iQueue += 1; - } else { - expoStack.push(expoRpnArray[i]); - } - } - } - - u.factor = Object.freeze(factors.pop()); - u.expos = Object.freeze(expoStack.pop()); - return Object.freeze(u) -}; - -/* eslint-disable */ - -/* - * This file implements a complex number data type. - * Each complex number, z, is held as an array containing two rational number. - * z[0] is the real part and z[1] is the imaginary part. - * - * This module is a work in progress. - */ - -const j = [Rnl.zero, Rnl.one]; - -const isComplex = a => { - return Array.isArray(a) && a.length === 2 - && Rnl.isRational(a[0]) && Rnl.isRational(a[1]) -}; - -const real = z => z[0]; -const imag = z => z[1]; -const abs = z => Rnl.hypot(z[0], z[1]); -const negate = z => [Rnl.negate(z[0]), Rnl.negate(z[1])]; -const conjugate = z => [z[0], Rnl.negate(z[1])]; - -const angle = (z) => { - // For a complex number z, the angle (in radians) from - // the positive real axis to the vector representing z. + implies counter-clockwise. - // Electrical engineers call this the phase angle of the complex number. - if (Rnl.isZero(z[0]) && Rnl.isZero(z[1])) { - return errorOprnd("ORIGIN", "angle") - } else if (Rnl.isZero(z[1])) { - return Rnl.isPositive(z[0]) ? Rnl.zero : Rnl.pi - } else if (Rnl.isZero(z[0])) { - return Rnl.isPositive(z[1]) - ? Rnl.divide(Rnl.pi, Rnl.two) - : Rnl.negate(Rnl.divide(Rnl.pi, Rnl.two)) - } else { - return Rnl.fromNumber(Math.atan2(Rnl.toNumber(z[1]), Rnl.toNumber(z[0]))) - } -}; - -const add = (x, y) => [Rnl.add(x[0], y[0]), Rnl.add(x[1], y[1])]; -const subtract = (x, y) => [Rnl.subtract(x[0], y[0]), Rnl.subtract(x[1], y[1])]; - -const multiply = (x, y) => { - return [ - Rnl.subtract(Rnl.multiply(x[0], y[0]), Rnl.multiply(x[1], y[1])), - Rnl.add(Rnl.multiply(x[0], y[1]), Rnl.multiply(x[1], y[0])) - ] -}; - -const divide = (x, y) => { - if (!Rnl.isZero(x[1]) && !Rnl.isZero(y[1])) { - if (Rnl.lessThan(Rnl.abs(y[1]), Rnl.abs(y[0]))) { - const ratio = Rnl.divide(y[1], y[0]); - const denom = Rnl.add(y[0], Rnl.multiply(y[1], ratio)); - return [ - Rnl.divide(Rnl.add(x[0], Rnl.multiply(x[1], ratio)), denom), - Rnl.divide(Rnl.subtract(x[1], Rnl.multiply(x[0], ratio)), denom), - ] - } else { - const ratio = Rnl.divide(y[0], y[1]); - const denom = Rnl.add(y[1], Rnl.multiply(y[0], ratio)); - return [ - Rnl.divide(Rnl.add(x[1], Rnl.multiply(x[0], ratio)), denom), - Rnl.divide(Rnl.add(Rnl.negate(x[0]), Rnl.multiply(x[1], ratio)), denom), - ] - } - } else if (Rnl.isZero(x[1])) { - // real x divided by complex y - if (Rnl.lessThan(Rnl.abs(y[1]), Rnl.abs(y[0]))) { - const ratio = Rnl.divide(y[1], y[0]); - const denom = Rnl.add(y[0], Rnl.multiply(y[1], ratio)); - return [ - Rnl.divide(x[0], denom), - Rnl.negate(Rnl.multiply(x[0], Rnl.divide(ratio, denom))), - ] - } else { - const ratio = Rnl.divide(y[0], y[1]); - const denom = Rnl.add(y[1], Rnl.multiply(y[0], ratio)); - return [ - Rnl.divide(Rnl.multiply(x[0], ratio), denom), - Rnl.negate(Rnl.divide(x[0], denom)), - ] - } - } else if (Rnl.isZero(y[1])) { - // Complex x divided by real y - if (Rnl.isZero(y[0])) ; else { - return [Rnl.divide(x[0], y[0]), Rnl.divide(x[1], y[0])] - } - } else { - // both x and y are reals - if (Rnl.isZero(y[0])) { - return errorOprnd("DIV") - } else { - return [Rnl.divide(x[0], y[0]), Rnl.zero ] - } - } -}; - -const increment = z => [Rnl.increment(z[0]), z[1]]; -const decrement = z => [Rnl.decrement(z[0]), z[1]]; - -const inverse = z => { - // Complex inverse 1 / z - if (Rnl.isZero(z[1])) { - if (Rnl.isZero((z[0]))) { return errorOprnd("DIV") } - return [Rnl.inverse(z[0]), 0] - } else { - return divide([Rnl.one, Rnl.zero], z) - } -}; - -const cos = z => { - const real = Rnl.multiply(Rnl.cos(z[0]), Rnl.cosh(z[1])); - const imPart = Rnl.multiply(Rnl.negate(Rnl.sin(z[0])), Rnl.sinh(z[1])); - return [real, imPart] -}; - -const sin = z => { - const real = Rnl.multiply(Rnl.sin(z[0]), Rnl.cosh(z[1])); - const imPart = Rnl.multiply(Rnl.cos(z[0]), Rnl.sinh(z[1])); - return [real, imPart] -}; - -const log = x => { - let z = [Rnl.zero, Rnl.zero]; - // Natural (base e) logarithm of a complex number, x - if (Rnl.isZero(x[0]) && Rnl.isZero(x[1])) { - return errorOprnd("ORIGIN", "log") - } else { - z[0] = Rnl.fromNumber(Math.log(Rnl.toNumber(Rnl.hypot(x[0], x[1])))); - z[1] = angle(x); // phase angle, in radians - } - return z -}; - -const isSmall = x => Rnl.lessThan(Rnl.abs(x), [BigInt(1), BigInt(100000000000000)]); - -const exp = x => { - // Complex exponentiation - let z = [Rnl.zero, Rnl.zero]; - if (isSmall(x[1])) { - z[1] = Rnl.zero; - z[0] = Rnl.exp(x[0]); - } else { - if (Rnl.isZero(x[0])) { - z[0] = Rnl.cos(x[1]); - if (isSmall(z[0])) { z[0] = Rnl.zero; } - z[1] = Rnl.sin(x[1]); - if (isSmall(z[1])) { z[1] = Rnl.zero; } - } else { - const realExp = Rnl.exp(x[0]); - z[0] = Rnl.multiply(realExp, Rnl.cos(x[1])); - z[1] = Rnl.multiply(realExp, Rnl.sin(x[1])); - } - } - return z -}; - -const power = (x, y) =>{ - let z = [Rnl.zero, Rnl.zero]; - // powers: z = e^(log(x) × y) - if (!isComplex(y)) { - z = log(x); - z[0] = Rnl.multiply(z[0], y); - z[1] = Rnl.multiply(z[1], y); - } else if (Rnl.isZero(y[1])) { - z = log(x); - z[0] = Rnl.multiply(z[0], y[0]); - z[1] = Rnl.multiply(z[1], y[0]); - } else if (Rnl.isZero(x[1]) && !Rnl.isNegative(x[0])) { - x[0] = Rnl.fromNumber(Math.log(Rnl.toNumber(x[0]))); - z[0] = Rnl.multiply(x[0], y[0]); - z[1] = Rnl.multiply(x[0], y[1]); - } else { - x = log(x); - z[0] = Rnl.subtract(Rnl.multiply(x[0], y[0]), Rnl.multiply(x[1], y[1])); - z[1] = Rnl.add(Rnl.multiply(x[1], y[0]), Rnl.multiply(x[0], y[1])); - } - - z = exp(z); - if (isSmall(z[1])) { z[1] = Rnl.zero; } - if (isSmall(z[0])) { z[0] = Rnl.zero; } - return z -}; - -const acosh = z => { - // acosh(z) = log( z + √(z - 1) × √(z + 1) ) - return log(add(z, multiply(sqrt(decrement(z)), sqrt(increment(z))))) -}; - -const asinh = z => { - // Log(z + Sqrt(z * z + 1)) - const s = sqrt(add(multiply(z, z), [Rnl.one, Rnl.zero])); - return log(add(z, s)) -}; - -const atanh = z => { - // atanh(z) = [ log(1+z) - log(1-z) ] / 2 - return divide(subtract(log(increment(z)), log(subtract([Rnl.one, Rnl.zero], z))), [Rnl.two, Rnl.zero]) -}; - -const asin = z => { - // arcsinh (i * z) / i - return divide(asinh(multiply(j, z)), j) -}; - -const atan = z => { - // (Log(1 + iz) - Log(1 - iz)) / (2 * i) cf Kahan - const term1 = log(increment(multiply(j, z))); - const term2 = log(subtract([Rnl.one, Rnl.zero],(multiply(j, z)))); - return divide(subtract(term1, term2), [Rnl.zero, Rnl.two]) -}; - -const sqrt = x => { - const z = log(x); - z[0] = Rnl.divide(z[0], Rnl.two); - z[1] = Rnl.divide(z[1], Rnl.two); - return exp(z) -}; - -const lanczos = zPlusOne => { - // Lanczos approximation of Gamma function. - // Coefficients are from 2004 PhD thesis by Glendon Pugh. - // *An Analysis of the Lanczos Gamma Approximation* - // The following equation is from p. 116 of the Pugh thesis: - // Γ(z+1) ≈ 2 * √(e / π) * ((z + 10.900511 + 0.5) / e) ^ (z + 0.5) * sum - const z = subtract(zPlusOne, [Rnl.one, Rnl.zero]); - const sqr = Rnl.sqrt(Rnl.divide(e, pi)); - const term1 = multiply([Rnl.two, Rnl.zero], [sqr, Rnl.zero]); - const k = Rnl.fromNumber(11.400511); - const oneHalf = [[BigInt(1), BigInt(2)], Rnl.zero]; - const term2 = power(divide(add(z, [k, Rnl.zero]), [e, Rnl.zero]), add(z, oneHalf)); - - // Coefficients from Pugh, Table 8.5 - const d = ["2.48574089138753565546e-5", "1.05142378581721974210", - "-3.45687097222016235469", "4.51227709466894823700", "-2.98285225323576655721", - "1.05639711577126713077", "-0.195428773191645869583", "0.0170970543404441224307", - "-0.000571926117404305781283", "0.00000463399473359905636708", - "-0.00000000271994908488607703910"]; - - // sum = d_0 + ∑_(k=1)^10 d_k/(z+k) - let sum = [Rnl.fromString(d[0]), Rnl.zero]; - for (let k = 1; k <= 10; k++) { - const d = [Rnl.fromString(d[k]), Rnl.zero]; - const complexK = [Rnl.fromNumber(k), Rnl.zero]; - sum = add(sum, divide(d, add(z, complexK))); - } - - return multiply(multiply(term1, term2), sum) -}; - -const display$3 = (z, formatSpec, decimalFormat) => { - const complexSpec = /[∠°]/.test(formatSpec) ? formatSpec.slice(-1) : "j"; - let resultDisplay = ""; - let altResultDisplay = ""; - if (complexSpec === "j") { - const real = format(z[0], formatSpec, decimalFormat); - let imPart = format(z[1], formatSpec, decimalFormat); - if (imPart.charAt(0) === "-") { - resultDisplay = real + " - j\\," + -imPart; - altResultDisplay = real + " - j " + -imPart; - } else { - resultDisplay = real + " + j\\, " + imPart; - altResultDisplay = real + " + j " + imPart; - } - } else { - const mag = Rnl.hypot(z[0], z[1]); - let angle = Cpx.angle(z); - const inDegrees = complexSpec.indexOf("°") > -1; - if (inDegrees) { - angle = Rnl.divide(Rnl.multiply(angle, Rnl.fromNumber(180)), Rnl.pi); - } - resultDisplay = format(mag, formatSpec, decimalFormat) + "∠" + - format(angle, formatSpec, decimalFormat) + (inDegrees ? "°" : ""); - altResultDisplay = resultDisplay; - } - return [resultDisplay, altResultDisplay] -}; - -const Cpx = Object.freeze({ - j, - real, - imag, - abs, - conjugate, - angle, - inverse, - increment, - decrement, - isComplex, - add, - subtract, - divide, - multiply, - negate, - power, - exp, - log, - sqrt, - sin, - cos, - asin, - atan, - acosh, - asinh, - atanh, - lanczos, - display: display$3 -}); - -// Two helper functions -const isMatrix = oprnd => { - return ( - (oprnd.dtype & dt.ROWVECTOR) || - (oprnd.dtype & dt.COLUMNVECTOR) || - (oprnd.dtype & dt.MATRIX) - ) -}; -const isVector = oprnd => { - return (((oprnd.dtype & dt.ROWVECTOR) || (oprnd.dtype & dt.COLUMNVECTOR)) > 0) -}; - -const transpose = oprnd => { - const result = { unit: oprnd.unit }; - if (isVector(oprnd)) { - result.value = oprnd.value; - const delta = ((oprnd.dtype & dt.ROWVECTOR) ? 1 : -1 ) * (dt.COLUMNVECTOR - dt.ROWVECTOR); - result.dtype = oprnd.dtype + delta; - } else if (oprnd.dtype & dt.MATRIX) { - result.value = oprnd.value[0].map((x, i) => oprnd.value.map(y => y[i])); - result.dtype = oprnd.dtype; - } else { - return errorOprnd("BAD_TRANS") - } - return result -}; - -const convertFromBaseUnits$1 = (oprnd, gauge, factor) => { - let conversion = (isVector(oprnd)) - ? oprnd.value.map((e) => Rnl.divide(e, factor)) - : oprnd.value.map(row => row.map(e => Rnl.divide(e, factor))); - if (!Rnl.isZero(gauge)) { - conversion = (isVector(oprnd)) - ? oprnd.value.map((e) => Rnl.subtract(e, gauge)) - : oprnd.value.map(row => row.map(e => Rnl.subtract(e, gauge))); - } - return Object.freeze(conversion) -}; - -const convertToBaseUnits$1 = (oprnd, gauge, factor) => { - let conversion = clone(oprnd.value); - if (!Rnl.isZero(gauge)) { - conversion = (isVector(oprnd)) - ? oprnd.value.map((e) => Rnl.add(e, gauge)) - : oprnd.value.map(row => row.map(e => Rnl.add(e, gauge))); - } - conversion = (isVector(oprnd)) - ? conversion.map((e) => Rnl.multiply(e, factor)) - : conversion.map(row => row.map(e => Rnl.multiply(e, factor))); - return Object.freeze(conversion) -}; - -const elementDisplay = (value, dtype, formatSpec, decimalFormat, isAlt = false) => { - let display = value === undefined - ? "" - : (dtype & dt.RATIONAL) - ? format(value, formatSpec, decimalFormat) - : (dtype & dt.COMPLEX) - ? Cpx.display(value, formatSpec, decimalFormat)[0] - : (dtype & dt.BOOLEAN) || (dtype & dt.STRING) - ? (isAlt ? value : "\\text{" + value + "}") - : value; - if (isAlt && ((dtype & dt.RATIONAL) || (dtype & dt.COMPLEX))) { - display = display.replace(/{,}/g, ","); - } - return display -}; - -const display$2 = (m, formatSpec, decimalFormat) => { - let str = ""; - if (m.dtype & dt.MATRIX) { - str += "\\begin{pmatrix}"; - const numRows = m.value.length; - const numCols = m.value[0].length; - for (let i = 0; i < numRows; i++) { - for (let j = 0; j < numCols; j++) { - str += elementDisplay(m.value[i][j], m.dtype, formatSpec, decimalFormat) + " &"; - } - str = str.slice(0, -1) + " \\\\ "; - } - str = str.slice(0, -3).trim(); - str += "\\end{pmatrix}"; - } else { - const numArgs = m.value.plain ? m.value.plain.length : m.value.length; - if (numArgs === 0) { - str += "[\\,]"; - } else { - str += "\\begin{bmatrix}"; - const argSep = (m.dtype & dt.ROWVECTOR) ? " & " : " \\\\ "; - if (m.value.plain) { - for (let i = 0; i < numArgs; i++) { - str += elementDisplay(m.value.plain[i], m.dtype, formatSpec, decimalFormat) + - ((i < numArgs - 1) ? argSep : ""); - } - } else { - for (let i = 0; i < numArgs; i++) { - str += elementDisplay(m.value[i], m.dtype, formatSpec, decimalFormat) + - ((i < numArgs - 1) ? argSep : ""); - } - } - str += "\\end{bmatrix}"; - } - } - return str -}; - -const displayAlt$2 = (m, formatSpec, decimalFormat) => { - let str = ""; - if (m.dtype & dt.MATRIX) { - str += "("; - const numRows = m.value.length; - const numCols = m.value[0].length; - for (let i = 0; i < numRows; i++) { - for (let j = 0; j < numCols; j++) { - str += elementDisplay(m.value[i][j], m.dtype, formatSpec, decimalFormat, true) + ", "; - } - str = str.slice(0, -2) + "; "; - } - str = str.slice(0, -2).trim(); - str += ")"; - } else { - str += "["; - const argSep = (m.dtype & dt.ROWVECTOR) ? ", " : "; "; - if (m.value.plain) { - const numArgs = m.value.plain.length; - for (let i = 0; i < numArgs; i++) { - str += elementDisplay(m.value.plain[i], m.dtype, formatSpec, decimalFormat, true) + - ((i < numArgs - 1) ? argSep : ""); - } - } else { - const numArgs = m.value.length; - for (let i = 0; i < numArgs; i++) { - str += elementDisplay(m.value[i], m.dtype, formatSpec, decimalFormat, true) + - ((i < numArgs - 1) ? argSep : ""); - } - } - str += "]"; - } - return str -}; - -const findfirst$1 = (el, array) => { - if (!isVector(array)) { return errorOprnd("NOT_VECTOR", "findfirst") } - const isNumeric = Rnl.isRational(el); - for (let i = 0; i < array.value.length; i++) { - const val = array.value[i]; - if ((isNumeric & Rnl.areEqual(val, el)) || val === el ) { - return Rnl.fromNumber(i + 1) - } - } - return Rnl.zero -}; - -const identity = (num, mutable) => { - const n = Rnl.isRational(num) ? Rnl.toNumber(num) : num; - if (n === 1) { - return [Rnl.one] - } else { - const M = []; - for (let i = 0; i < n; i++) { - M.push(new Array(n).fill(Rnl.zero)); - M[i][i] = Rnl.one; - } - return mutable ? M : Object.freeze(M) - } -}; - -const invert = (matrix, returnDeterminant) => { - // Invert a square matrix via Gaussian elimination. - // A lightly editied copy of http://blog.acipo.com/matrix-inversion-in-javascript/ - - if (matrix.length !== matrix[0].length) { - return errorOprnd("NONSQUARE") - } - const dim = matrix.length; - let i = 0; - let ii = 0; - let j = 0; - let temp = Rnl.zero; - let determinant = Rnl.one; - - const C = clone(matrix); - const I = identity(dim, true); - - for (i = 0; i < dim; i += 1) { - // get the element temp on the diagonal - temp = C[i][i]; - - // if we have a 0 on the diagonal (we'll need to swap with a lower row) - if (Rnl.isZero(temp)) { - //look through every row below the i'th row - for (ii = i + 1; ii < dim; ii++) { - //if the ii'th row has a non-0 in the i'th col - if (!Rnl.isZero(C[ii][i])) { - //it would make the diagonal have a non-0 so swap it - for (j = 0; j < dim; j++) { - temp = C[i][j]; // temp store i'th row - C[i][j] = C[ii][j]; // replace i'th row by ii'th - C[ii][j] = temp; // repace ii'th by temp - temp = I[i][j]; // temp store i'th row - I[i][j] = I[ii][j]; // replace i'th row by ii'th - I[ii][j] = temp; // repace ii'th by temp - } - //don't bother checking other rows since we've swapped - break - } - } - //get the new diagonal - temp = C[i][i]; - //if it's still 0, not invertable (error) - if (Rnl.isZero(temp)) { return errorOprnd("SINGULAR") } - } - - if (returnDeterminant) { - determinant = Rnl.divide(determinant, temp); - if (i === dim - 1) { - return determinant - } - } - - // Scale this row down by temp (so we have a 1 on the diagonal) - for (j = 0; j < dim; j++) { - C[i][j] = Rnl.divide(C[i][j], temp); //apply to original matrix - I[i][j] = Rnl.divide(I[i][j], temp); //apply to identity - } - - // Subtract this row (scaled appropriately for each row) from ALL of - // the other rows so that there will be 0's in this column in the - // rows above and below this one - for (ii = 0; ii < dim; ii++) { - // Only apply to other rows (we want a 1 on the diagonal) - if (ii === i) { continue } - - // We want to change this element to 0 - temp = C[ii][i]; - - // Subtract (the row above(or below) scaled by temp) from (the - // current row) but start at the i'th column and assume all the - // stuff left of diagonal is 0 (which it should be if we made this - // algorithm correctly) - for (j = 0; j < dim; j++) { - C[ii][j] = Rnl.subtract(C[ii][j], Rnl.multiply(temp, C[i][j])); // original matrix - I[ii][j] = Rnl.subtract(I[ii][j], Rnl.multiply(temp, I[i][j])); // identity - } - } - } - - // We've finished. C should be the identity matrix. - // Matrix I should be the inverse. - return Object.freeze(I) -}; - - -const submatrix = (oprnd, index, colIndex) => { - if (!((index.dtype & dt.RATIONAL) || (index.dtype & dt.RANGE))) { - return errorOprnd("BAD_INDEX") - } - let value = []; - let dtype = oprnd.dtype; - - // Get the row index - let start = 0; - let step = 1; - let end = 0; - if (index.dtype & dt.RANGE) { - start = Rnl.toNumber(index.value[0]); - step = Rnl.toNumber(index.value[1]); - end = index.value[2] === "∞" - ? oprnd.value.length - : Rnl.toNumber(index.value[2]); - } else if (Rnl.areEqual(index.value, Rnl.zero)) { - // Return all the rows - start = 1; - end = oprnd.value.length; - } else { - start = Rnl.toNumber(index.value); - end = start; - } - - if (isVector(oprnd)) { - // Skip the column index. Proceed directly to load values into the result. - if (start === end) { - // return a scalar - value = oprnd.value[start - 1]; - dtype = oprnd.dtype - (oprnd.dtype & dt.ROWVECTOR) - - (oprnd.dtype & dt.COLUMNVECTOR); - } else if (step === 1) { - value = oprnd.value.slice(start - 1, end); - } else { - for (let i = start - 1; i < end; i += step) { - value.push(oprnd.value[i]); - } - } - Object.freeze(value); - return Object.freeze({ value, unit: oprnd.unit, dtype }) - } - - // Get the column index - let colStart = 0; - let colStep = 1; - let colEnd = 0; - if (colIndex) { - if (colIndex.dtype & dt.RANGE) { - colStart = Rnl.toNumber(colIndex.value[0]); - colStep = Rnl.toNumber(colIndex.value[1]); - colEnd = colIndex.value[2] === "∞" - ? oprnd.value[0].length - : Rnl.toNumber(colIndex.value[2]); - } else if (Rnl.areEqual(colIndex.value, Rnl.zero)) { - // Return an entire row. - colStart = 1; - colEnd = oprnd.value[0].length; - } else { - colStart = Rnl.toNumber(colIndex.value); - colEnd = colStart; - } - } - - // Now load values into the result - if (start === end && colStart === colEnd) { - // return a scalar - value = oprnd.value[start - 1][colStart - 1]; - dtype -= dt.MATRIX; - - } else if (start === end) { - // return a row vector - if (colStep === 1) { - value = oprnd.value[start - 1].slice(colStart - 1, colEnd); - } else { - for (let j = colStart - 1; j < colEnd; j += colStep) { - value.push(oprnd.value[start - 1][j]); - } - } - dtype = dtype - dt.MATRIX + dt.ROWVECTOR; - - } else if (colStart === colEnd) { - // return a column vector - for (let i = start - 1; i < end; i += step) { - value.push(oprnd.value[i][colStart - 1]); - } - dtype = dtype - dt.MATRIX + dt.COLUMNVECTOR; - - } else if (colStep === 1) { - for (let i = start - 1; i < end; i += step) { - value.push([]); - value[value.length - 1] = oprnd.value[i].slice(colStart - 1, colEnd); - } - - } else { - for (let i = start - 1; i < end; i += step) { - value.push([]); - for (let j = colStart - 1; j < colEnd; j += colStep) { - value[value.length - 1].push(oprnd[i][j]); - } - } - } - Object.freeze(value); - return Object.freeze({ value, unit: oprnd.unit, dtype }) -}; - -const multResultType = (o1, o2) => { - // o1 and o2 are to undergo matrix multiplication. - // The value is found elsewhere. - // Here we find the resulting data type. - if ((o1.dtype & dt.ROWVECTOR) && (o2.dtype & dt.COLUMNVECTOR)) { - return dt.RATIONAL - } else if ((o1.dtype & dt.MATRIX) && (o2.dtype & dt.COLUMNVECTOR)) { - return o2.dtype - } else if ((o1.dtype & dt.ROWVECTOR) && (o2.dtype & dt.MATRIX)) { - return o1.dtype - } else { - return dt.MATRIX + dt.RATIONAL - } -}; - -const operandFromRange = range => { - // Input was [start:step:end...] - // Populate a vector with values from a range - if (Rnl.isZero(range[1])) { return errorOprnd("ZERO_STEP") } - if (!Rnl.areEqual(Rnl.sign(Rnl.subtract(range[2], range[0])), Rnl.sign(range[1]))) { - range[1] = Rnl.negate(range[1]); - } - const array = []; - if (Rnl.greaterThan(range[2], range[0])) { - for (let j = range[0]; Rnl.lessThan(j, range[2]); j = Rnl.add(j, range[1])) { - array.push(j); - } - } else { - for (let j = range[0]; Rnl.greaterThanOrEqualTo(j, range[2]); j = Rnl.add(j, range[1])) { - array.push(j); - } - } - if (!Rnl.areEqual(array[array.length - 1], range[2])) { - array.push(range[2]); - } - Object.freeze(array); - return Object.freeze({ - value: array, - unit: { expos: allZeros }, - dtype: dt.RATIONAL + dt.COLUMNVECTOR - }) -}; - -const operandFromTokenStack = (tokenStack, numRows, numCols) => { - // TODO: Get dtype correct for matrices that contain strings or booleans. - if (numRows === 0 && numCols === 0) { - return Object.freeze({ value: new Array(0), unit: null, dtype: dt.COLUMNVECTOR }) - } else if (numRows === 1 && numCols === 1) { - // One element. Return a scalar. - return tokenStack.pop() - - } else if (numRows === 1 || numCols === 1) { - const numArgs = Math.max(numRows, numCols); - let array; - let dtype = tokenStack[tokenStack.length - 1].dtype; - if (numRows === 1 && (dtype & dt.COLUMNVECTOR)) { - // Matrix composed of column vectors appended side by side - dtype = dtype - dt.COLUMNVECTOR + dt.MATRIX; - array = new Array(tokenStack[0].value.length); - for (let i = 0; i < tokenStack[0].value.length; i++) { - array[i] = []; - for (let j = 0; j < numArgs; j++) { - array[i][j] = tokenStack[j].value[i]; - } - } - for (let i = 0; i < numArgs; i++) { tokenStack.pop(); } - } else { - // Vector - array = new Array(numArgs); - dtype += numRows === 1 ? dt.ROWVECTOR : dt.COLUMNVECTOR; - for (let j = numArgs - 1; j >= 0; j--) { - array[j] = tokenStack.pop().value; - } - } - Object.freeze((array)); - return Object.freeze({ - value: array, - unit: (dtype & dt.RATIONAL) ? { expos: allZeros } : null, - dtype - }) - - } else { - // 2D matrix - const array = new Array(numRows); - const dtype = tokenStack[tokenStack.length - 1].dtype + dt.MATRIX; - for (let j = 0; j < numRows; j++) { - array[j] = new Array(numCols); - } - for (let k = numRows - 1; k >= 0; k--) { - for (let j = numCols - 1; j >= 0; j--) { - array[k][j] = tokenStack.pop().value; - } - } - Object.freeze((array)); - return Object.freeze({ - value: array, - unit: (dtype & dt.RATIONAL) ? { expos: allZeros } : null, - dtype - }) - } -}; - -const ones = (m, n) => { - if (m === 1 || n === 1) { - return { - value: new Array(n).fill(Rnl.one), - unit: allZeros, - dtype: dt.RATIONAL + (m === 1 ? dt.ROWVECTOR : dt.COLUMNVECTOR) - } - } else { - const value = []; - for (let i = 0; i < m; i++) { - value.push(new Array(n).fill(Rnl.one)); - } - Object.freeze(value); - return Object.freeze({ - value: value, - unit: { expos: allZeros }, - dtype: dt.RATIONAL + dt.MATRIX - }) - } -}; - -const zeros = (m, n) => { - if (m === 1 || n === 1) { - return { - value: new Array(n).fill(Rnl.zero), - unit: allZeros, - dtype: dt.RATIONAL + (m === 1 ? dt.ROWVECTOR : dt.COLUMNVECTOR) - } - } else { - const value = []; - for (let i = 0; i < m; i++) { - value.push(new Array(n).fill(Rnl.zero)); - } - Object.freeze(value); - return Object.freeze({ - value: value, - unit: { expos: allZeros }, - dtype: dt.RATIONAL + dt.MATRIX - }) - } -}; - -const Matrix = Object.freeze({ - convertFromBaseUnits: convertFromBaseUnits$1, - convertToBaseUnits: convertToBaseUnits$1, - display: display$2, - displayAlt: displayAlt$2, - elementDisplay, - findfirst: findfirst$1, - identity, - invert, - multResultType, - ones, - operandFromRange, - operandFromTokenStack, - submatrix, - transpose, - zeros -}); - -const columnListFromRange = (start, end) => { - const columnList = []; - for (let i = start; i <= end; i++) { - columnList.push(i); - } - return columnList -}; - -const valueFromDatum = datum => { - return datum === "true" - ? true - : datum === "false" - ? false - : numberRegEx$5.test(datum) - ? Rnl.fromString(datum) - : datum === "" - ? undefined - : datum -}; - -const datumFromValue = (value, dtype, formatSpec) => { - return value === true - ? "true" - : value === false - ? "false" - : value = (dtype === dt.RATIONAL) - ? format(value, formatSpec, "1000000.") - : value -}; - -const identifyRange = (df, args) => { - // A helper function for range(). Also used by map.range() - - let iStart; - let iEnd; - let rowList = []; - let columnList = []; - - // Find what must be returned. I.e. populate rowList and columnList - if (df.value.data[0].length === 1) { - // The source is a single-row data frame. Each argument calls a column. - iStart = 0; - iEnd = 0; - if (df.dtype === dt.DATAFRAME) { df.value.usedRows.add(0); } - for (let i = 0; i < args.length; i++) { - if (args[i].dtype === dt.STRING) { - columnList.push(df.value.columnMap[args[i].value]); - } else if (args[i].dtype === dt.RATIONAL) { - columnList.push(Rnl.toNumber(args[i].value)); - } else if (args[i].dtype === dt.RANGE) { - const jStart = Rnl.toNumber(args[i].value[0]); - const jEnd = Rnl.toNumber(args[i].value[1]); - for (let j = jStart; j <= jEnd; j++) { - columnList.push(j); - } - } - } - } else if (args.length === 1 && args[0].dtype === dt.RATIONAL) { - // Return a column vector - iStart = 0; - iEnd = df.value.data[0].length - 1; - columnList.push(Rnl.toNumber(args[0].value) - 1); - } else if (args.length === 1 && args[0].dtype === dt.RANGE) { - iStart = Rnl.toNumber(args[0].value[0]) - 1; - iEnd = Rnl.toNumber(args[0].value[1]) - 1; - if (df.dtype === dt.DATAFRAME) { - for (let i = iStart; i <= iEnd; i++) { df.value.usedRows.add(i); } - } - columnList = columnListFromRange(0, df.value.data.length - 1); - } else if (args.length === 1 && args[0].dtype === dt.STRING) { - // Only one indicator has been given. - // Check both the rowMap and the columnMap. - if (df.value.rowMap && args[0].value in df.value.rowMap) { - // Return a row - iStart = df.value.rowMap[args[0].value]; - iEnd = iStart; - if (df.dtype === dt.DATAFRAME) { df.value.usedRows.add(iStart); } - columnList = columnListFromRange(0, df.value.data.length - 1); - } else if (df.value.columnMap && args[0].value in df.value.columnMap) { - // Return a column vector - iStart = 0; - iEnd = df.value.data[0].length - 1; - columnList.push(df.value.columnMap[args[0].value]); - } else { - return [errorOprnd("BAD_ROW_NAME", args[0].value), null, null, null] - } - } else if (args.length === 1 && args[0].dtype === dt.STRING + dt.COLUMNVECTOR) { - // A vector of row names - for (const rowName of args[0].value) { - rowList.push(rowName); - if (df.dtype === dt.DATAFRAME) { df.value.usedRows.add(df.value.rowMap[rowName]); } - } - columnList = columnListFromRange(0, df.value.data.length - 1); // All the columns. - } else if (args.length === 1 && args[0].dtype === dt.STRING + dt.ROWVECTOR) { - // A vector of column names - iStart = 0; - iEnd = df.value.data[0].length; - for (const colName of args[0].value) { - columnList.push(df.columnIndicator[colName]); - } - } else if (args.length === 2 && args[0].dtype === dt.STRING && df.value.rowMap - && args[0].value in df.value.rowMap && args[1].dtype === dt.STRING && - df.value.columnMap && args[0].value in df.value.columnMap) { - // Return a single cell value - iStart = df.value.rowMap[args[0].value]; - iEnd = iStart; - if (df.dtype === dt.DATAFRAME) { df.value.usedRows.add(iStart); } - columnList.push(df.value.columnMap[args[0].value]); - } else { - // Default for args is a list of (row|column) names - iStart = 0; - iEnd = args.length; - if (df.value.rowMap && df.value.rowMap[args[iEnd - 1].value]) { - // A row list - rowList = args.map(arg => arg.value); - columnList = columnListFromRange(0, df.value.data.length - 1); // All the columns. - } else { - // A column list - columnList = args.map(arg => df.value.columnMap[arg.value]); - } - } - return [rowList, columnList, iStart, iEnd] -}; - -const range$1 = (df, args, unitAware) => { - let unit = Object.create(null); - const [rowList, columnList, iStart, iEnd] = identifyRange(df, args); - if (rowList.dtype && rowList.dtype === dt.ERROR) { return rowList } - if (rowList.length === 0 && iStart === iEnd && columnList.length === 1) { - // Return one value. - let dtype = df.value.dtype[columnList[0]]; - if (dtype & dt.QUANTITY) { dtype -= dt.QUANTITY; } - const j = columnList[0]; - let value = valueFromDatum(df.value.data[j][iStart]); - unit.expos = (dtype & dt.RATIONAL) ? allZeros : null; - if (unitAware && df.value.units[j]) { - const unitName = df.value.units[j] ? df.value.units[j] : undefined; - const unitObj = unitFromUnitName(unitName); - value = Rnl.multiply(Rnl.add(value, unitObj.gauge), unitObj.factor); - unit.expos = unitObj.expos; - } - return { value, unit, dtype } - - } else if (columnList.length === 1) { - // Return data from one column, in a column vector or a quantity - const j = columnList[0]; - const unitName = df.value.units[j] ? df.value.units[j] : {}; - unit = (df.unit && df.unit[unitName]) ? df.unit[unitName] : { expos: null }; - const value = df.value.data[j].slice(iStart, iEnd + 1).map(e => valueFromDatum(e)); - const dtype = df.value.dtype[j] + dt.COLUMNVECTOR; - const newdf = { value, name: df.value.headings[j], unit, dtype }; - if (unitAware && unit.gauge) { - return { - value: Matrix.convertToBaseUnits(newdf, unit.gauge, unit.factor), - name: df.value.headings[j], - unit: { expos: clone(unit.expos) }, - dtype: dt.RATIONAL + dt.COLUMNVECTOR - } - } else { - return newdf - } - - } else { - // Return a data frame. - const headings = []; - const units = []; - const dtype = []; - const data = []; - const columnMap = Object.create(null); - const unitMap = Object.create(null); - const rowMap = rowList.length === 0 ? false : Object.create(null); - for (let j = 0; j < columnList.length; j++) { - headings.push(df.value.headings[columnList[j]]); - const unitName = df.value.units[columnList[j]]; - units.push(unitName); - if (unitName && !unitMap[unitName]) { unitMap[unitName] = df.unit[unitName]; } - dtype.push(df.value.dtype[columnList[j]]); - columnMap[df.value.headings[j]] = j; - if (rowList.length > 0) { - const elements = []; - for (let i = 0; i < rowList.length; i++) { - const rowName = rowList[i]; - elements.push(df.value.data[columnList[j]][df.value.rowMap[rowName]]); - rowMap[rowName] = i; - } - data.push(elements); - } else { - data.push(df.value.data[columnList[j]].slice(iStart, iEnd + 1)); - } - } - return { - value: { - data, - headings, - columnMap, - rowMap, - units, - usedRows: new Set(), - dtype - }, - unit: clone(unitMap), - dtype: dt.DATAFRAME - } - } -}; - -// const numberRegEx = new RegExp(Rnl.numberPattern + "$") -const numberRegEx$5 = new RegExp("^(?:=|" + Rnl.numberPattern.slice(1) + "$)"); -const mixedFractionRegEx = /^-?(?:[0-9]+(?: [0-9]+\/[0-9]+))$/; -const escRegEx = /^\\#/; - -const hasUnitRow = lines => { - // Determine if there is a row for unit names. - if (lines.length < 3) { return false } - const units = lines[1].split("\t").map(el => el.trim()); - for (const unitName of units) { - if (numberRegEx$5.test(unitName)) { return false } - } - const firstDataLine = lines[2].split("\t").map(el => el.trim()); - for (const datum of firstDataLine) { - if (numberRegEx$5.test(datum)) { return true } - } - return false -}; - -const dataFrameFromTSV = (str, vars) => { - // Load a TSV string into a data frame. - // Data frames are loaded column-wise. The subordinate data structures are: - let data = []; // where the main data lives, not including column names or units. - const headings = []; // An array containing the column names - const columnMap = Object.create(null); // map of column names to column index numbers - let rowMap = false; // ditto for rows. - const units = []; // array of unit names, one for each column - const dtype = []; // each column's Hurmet operand type - const unitMap = Object.create(null); // map from unit names to unit data - const usedRows = new Set(); - - if (str.charAt(0) === "`") { str = str.slice(1); } - - if (vars) { - // Substitute values in for string interpolation, ${…} - const matches = arrayOfRegExMatches(interpolateRegEx, str); - for (let i = matches.length - 1; i >= 0; i--) { - const mch = matches[i]; - const varName = mch.value.slice(2, -1); - let value = ""; - if (varName === "undefined") { - value = ""; - } else if (varName === "j" && !vars.j) { - value = "j"; - } else { - const cellAttrs = vars[varName]; - if (!cellAttrs) { return errorOprnd("V_NAME", varName) } - const oprnd = fromAssignment(cellAttrs, false); - if (oprnd.dtype === dt.ERROR) { return oprnd } - value = Rnl.isRational(oprnd.value) ? String(Rnl.toNumber(oprnd.value)) : oprnd.value; - } - str = str.slice(0, mch.index) + value + str.slice(mch.index + mch.length); - } - } - - // It's tab-separated values, so we can use splits to load in the data. - const lines = str.split(/\r?\n/g); - const gotUnits = hasUnitRow(lines); - - // Read in the column headings. - const cols = lines[0].split('\t'); - if (cols[0].length > 0 && cols[0].charAt(0) === "#") { - // Create a rowMap. The first datum in each row is a key to the row. - rowMap = Object.create(null); - cols[0] = cols[0].slice(1); - } else if (escRegEx.test(cols[0])) { - cols[0] = cols[0].slice(1); - } - cols.forEach((datum, col) => { - datum = datum.trim(); - headings.push(datum); - columnMap[datum] = col; - data.push([]); - }); - - // Units - if (gotUnits) { - const unitNames = lines[1].split('\t'); - unitNames.forEach(unitName => { - unitName = unitName.trim(); - units.push(unitName); - if (unitName.length > 0 && !unitMap[unitName]) { - const unit = unitFromUnitName(unitName); - if (unit) { - unitMap[unitName] = unit; - } else { - return errorOprnd("DF_UNIT", unitName) - } - } - }); - } - - // Data - let row = -1; - for (let i = (gotUnits ? 2 : 1); i < lines.length; i++) { - const line = lines[i]; - row += 1; - line.split('\t').forEach((datum, col) => { - datum = datum.trim(); - if (datum === "sumAbove()") { - let sum = Rnl.zero; - for (const num of data[col]) { - if (!isNaN(num)) { - sum = Rnl.add(sum, Rnl.fromString(num)); - } - } - datum = String(Rnl.toNumber(sum)); - } - data[col].push(datum); - if (rowMap && col === 0) { - rowMap[datum] = row; - } - }); - } - - // Data is loaded in. Finish by determining the operand type of each column - for (let j = 0; j < data.length; j++) { - for (let i = 0; i < data[0].length; i++) { - const datum = data[j][i]; - if (datum === "") { continue } // undefined datum. - dtype.push( - numberRegEx$5.test(datum) - ? dt.RATIONAL + ((units.length > 0 && units[j].length > 0) ? dt.QUANTITY : 0) - : (datum === "true" || datum === "false") - ? dt.BOOLEAN - : dt.STRING - ); - break - } - } - - // Check if this data qualifies as a Hurmet Map. - let isMap = false; - let iStart = 0; - if (Object.keys(unitMap).length === 0) { - isMap = true; - iStart = (rowMap) ? 1 : 0; - for (let i = iStart + 1; i < dtype.length; i++) { - if (dtype[i] !== dtype[iStart]) { isMap = false; break } - } - } - - if (isMap) { - if (dtype[iStart] === dt.RATIONAL) { - data = data.map((col, i) => dtype[i] === dt.RATIONAL - ? col.map(el => Rnl.fromString(el)) - : col - ); - } - return { - value: { data, headings, columnMap, rowMap, usedRows }, - unit: (dtype[0] === dt.RATIONAL ? { expos: allZeros } : null), - dtype: dt.MAP + dtype[iStart] - } - } else { - return { - value: { data, headings, columnMap, rowMap, units, usedRows, dtype }, - unit: unitMap, - dtype: dt.DATAFRAME - } - } -}; - -const dataFrameFromVectors = (vectors, formatSpec) => { - // Take an array of vectors and return a dataframe. - const data = []; - const headings = []; - const columnMap = Object.create(null); - const units = []; - const dtype = []; - const unitMap = Object.create(null); - const rowMap = (vectors[0].name && vectors[0].name === "name") ? Object.create(null) : false; - for (let j = 0; j < vectors.length; j++) { - const vector = vectors[j]; - const vectorType = (vector.dtype & dt.ROWVECTOR) - ? dt.ROWVECTOR - : (vector.dtype & dt.COLUMNVECTOR) - ? dt.COLUMNVECTOR - : dt.ERROR; - if (vectorType === dt.ERROR) { return errorOprnd("NOT_VECTOR", "dataframe") } - headings.push(vector.name); - columnMap[vector.name] = j; - const colDtype = vector.dtype - vectorType; - data.push(vector.value.map(e => datumFromValue(e, colDtype, formatSpec))); - dtype.push(colDtype); - if (vector.unit.name) { - units.push(vector.unit.name); - if (!unitMap[vector.unit.name]) { - const unit = unitFromUnitName(vector.unit.name); - unitMap[vector.unit.name] = unit; - } - } else { - units.push(null); - } - if (rowMap) { - const nameVector = vectors[0].value; - for (let i = 0; i < nameVector.length; i++) { - rowMap[nameVector[i]] = i; - } - } - } - return { - value: { - data: data, - headings: headings, - columnMap: columnMap, - rowMap: rowMap, - units: units, - usedRows: new Set(), - dtype: dtype - }, - unit: unitMap, - dtype: dt.DATAFRAME - } -}; - -const matrix2table = (matrix, headings, rowHeadings) => { - // Use the contents of a matrix to create a dataframe. - if (rowHeadings.length > 0) { headings = [""].concat(headings); } - const columnMap = Object.create(null); - for (let i = 0; i < headings.length; i++) { - columnMap[headings[i]] = i; - } - let rowMap = false; - if (rowHeadings.length > 0) { - rowMap = Object.create(null); - for (let i = 0; i < rowHeadings.length; i++) { - rowMap[rowHeadings[i]] = i; - } - } - const data = new Array(headings.length); - let delta = 0; - if (rowHeadings.length > 0) { - data[0] = rowHeadings; - delta = 1; - } - for (let j = 0; j < matrix.value[0].length; j++) { - const k = j + delta; - data[k] = []; - for (let i = 0; i < matrix.value.length; i++) { - data[k].push(matrix.value[i][j]); - } - } - return { - value: { data, headings, columnMap, rowMap }, - unit: matrix.unit, - dtype: matrix.dtype - dt.MATRIX + dt.MAP - } -}; - -const append$1 = (o1, o2, formatSpec, unitAware) => { - // Append a vector or single value to a dataframe. - // We use copy-on-write for dataframes, so copy it here. - const oprnd = o1.dtype === dt.DATAFRAME ? clone(o1) : clone(o2); - const addend = o1.dtype === dt.DATAFRAME ? o2 : o1; - if (o1.dtype === dt.DATAFRAME) { - oprnd.value.columnMap[addend.name] = oprnd.value.headings.length; - oprnd.value.headings.push(addend.name); - } else { - for (const [key, value] of Object.entries(oprnd.value.columnMap)) { - oprnd.value.columnMap[key] = value + 1; - } - oprnd.value.columnMap[addend.name] = 0; - oprnd.value.headings.unshift(addend.name); - } - let unit; - if (addend.unit && addend.unit.name && addend.unit.name.length > 0) { - if (o1.dtype === dt.DATAFRAME) { - oprnd.value.units.push(addend.unit.name); - } else { - oprnd.value.units.unshift(addend.unit.name); - } - unit = unitFromUnitName(addend.unit.name); - if (!oprnd.unit[addend.unit.name]) { - oprnd.unit[addend.unit.name] = unit; - } - } - const dtype = addend.dype === dt.RATIONAL && unit - ? dt.RATIONAL + dt.QUANTITY - : !isMatrix(addend) - ? addend.dtype - : (addend.dtype & dt.COLUMNVECTOR) - ? addend.dtype - dt.COLUMNVECTOR - : addend.dtype - dt.ROWVECTOR; - const numRows = oprnd.value.data[0].length; - if (numRows === 1 && !isMatrix(addend)) { - const v = unitAware && dtype === dt.RATIONAL && unit - ? Rnl.subtract(Rnl.divide(addend.value, unit.factor), unit.gauge) - : addend.value; - if (o1.dtype === dt.DATAFRAME) { - oprnd.value.data.push([datumFromValue(v, dtype, formatSpec)]); - } else { - oprnd.value.data.unshift([datumFromValue(v, dtype, formatSpec)]); - } - } else { - if (unitAware && dtype === dt.RATIONAL && unit) { - const v = Matrix.convertFromBaseUnits(addend, unit.gauge, unit.factor); - if (o1.dtype === dt.DATAFRAME) { - oprnd.value.data.push(v.map(e => datumFromValue(e, dtype, formatSpec))); - } else { - oprnd.value.data.unshift(v.map(e => datumFromValue(e, dtype, formatSpec))); - } - } else { - if (o1.dtype === dt.DATAFRAME) { - oprnd.value.data.push(addend.value.map( - e => datumFromValue(e, dtype, formatSpec) - )); - } else { - oprnd.value.data.unshift(addend.value.map( - e => datumFromValue(e, dtype, formatSpec) - )); - } - } - } - if (o1.dtype === dt.DATAFRAME) { - oprnd.value.dtype.push(dtype); - } else { - oprnd.value.dtype.unshift(dtype); - } - return oprnd -}; - -const quickDisplay = str => { - // This is called from the lexer for a display that changes with every keystroke. - if (str === "") { return "" } - str = str.trim(); - let arrayFormat = ""; - if (str.charAt(0) === "#") { - str = str.slice(1).trim(); - arrayFormat = "l|cccccccccccccccccccccccc"; - } else { - arrayFormat = "c"; - } - str = addTextEscapes(str); - const sepRegEx = / *\t */g; - const lines = str.split(/\r?\n/g); - let tex = ""; - if (lines.length < 3) { - tex = "\\begin{matrix}\\text{"; - for (let i = 0; i < lines.length; i++) { - tex += tablessTrim(lines[i]).replace(sepRegEx, "} & \\text{") + "} \\\\ \\text{"; - } - tex = tex.slice(0, -10) + "\\end{matrix}"; - } else { - tex = `\\begin{array}{${arrayFormat}}\\text{`; - const cells = new Array(lines.length); - for (let i = 0; i < lines.length; i++) { - cells[i] = tablessTrim(lines[i]).split(sepRegEx); - } - - let gotUnits = false; - let gotAnswer = false; - for (let j = 0; j < cells[1].length; j++) { - if (numberRegEx$5.test(cells[1][j])) { gotAnswer = true; break } - } - if (!gotAnswer) { - // line[1] had no numbers. If any numbers are in line[2] then line[1] is units. - for (let j = 0; j < cells[2].length; j++) { - if (numberRegEx$5.test(cells[2][j])) { gotUnits = true; break } - } - } - - for (let i = 0; i < lines.length; i++) { - tex += tablessTrim(lines[i]).replace(sepRegEx, "} & \\text{"); - tex += ((gotUnits && i === 1) || (!gotUnits && i === 0)) - ? "} \\\\ \\hline \\text{" - : "} \\\\ \\text{"; - } - - tex = tex.slice(0, -10) + "\\end{array}"; - } - tex = tex.replace(/·/g, "$·$"); - return tex -}; - -// The next 40 lines contain helper functions for display(). -const accentRegEx$1 = /^([^\u0300-\u0308\u030A\u030C\u0332\u20d0\u20d1\u20d6\u20d7\u20e1]+)([\u0300-\u0308\u030A\u030C\u0332\u20d0\u20d1\u20d6\u20d7\u20e1])(.+)?/; -const subscriptRegEx = /([^_]+)(_[^']+)?(.*)?/; -const accentFromChar$1 = Object.freeze({ - "\u0300": "\\grave", - "\u0301": "\\acute", - "\u0302": "\\hat", - "\u0303": "\\tilde", - "\u0304": "\\bar", - "\u0305": "\\bar", - "\u0307": "\\dot", - "\u0308": "\\ddot", - "\u030A": "\\mathring", - "\u030C": "\\check", - "\u0332": "\\underline", - "\u20d0": "\\overleftharpoon", - "\u20d1": "\\overrightharpoon", - "\u20d6": "\\overleftarrow", - "\u20d7": "\\vec", - "\u20e1": "\\overleftrightarrow" -}); -const formatColumnName = str => { - // We can't call parse(str) because that would be a circular dependency. - // So this module needs its own function to format dataframe column names. - if (!isValidIdentifier$1.test(str)) { - return "\\text{" + addTextEscapes(str) + "}" - } else { - // Format it like a Hurmet identifier. - str = str.replace(/′/g, "'"); // primes - let parts = str.match(accentRegEx$1); - if (parts) { - str = accentFromChar$1[parts[2]] + "{" + parts[1] + "}"; - return str + (parts[3] ? parts[3] : "") - } else { - parts = str.match(subscriptRegEx); - let result = parts[1].length > 1 ? `\\text{${parts[1]}}` : parts[1]; - if (parts[2]) { - result += "_" + `\\text{${parts[2].slice(1)}}`; - } - return result + (parts[3] ? parts[3] : "") - } - } -}; - -const isNotEmpty = row => { - if (!row) { return false } - for (let i = 0; i < row.length; i++) { - if (row[i] !== "" && row[i] !== null) { return true } - } - return false -}; - -const getNumInfo = df => { - // Gather info for in setting numbers on a decimal tab. - const data = df.data.plain ? df.data.plain : df.data; - const numCols = data.length; - const colInfo = new Array(numCols); - const cellInfo = new Array(numCols); - const DFisRational = !df.dtype && Rnl.isRational(data[0][0]); - for (let j = 0; j < numCols; j++) { - if (DFisRational || (df.dtype && df.dtype[j] & dt.RATIONAL)) { - colInfo[j] = { hasAlignChar: false, maxLenAfterAlignChar: 0 }; - cellInfo[j] = []; - for (let i = 0; i < data[0].length; i++) { - const datum = data[j][i]; - const pos = datum.indexOf("."); - const hasAlignChar = pos > -1; - const lenAfterAlignChar = hasAlignChar ? datum.length - pos - 1 : 0; - cellInfo[j].push({ hasAlignChar, lenAfterAlignChar }); - if (hasAlignChar) { - colInfo[j].hasAlignChar = true; - if (lenAfterAlignChar > colInfo[j].maxLenAfterAlignChar) { - colInfo[j].maxLenAfterAlignChar = lenAfterAlignChar; - } - } - } - } - } - return [colInfo, cellInfo] -}; - -const displayNum = (datum, colInfo, cellInfo, decimalFormat) => { - let str = formattedDecimal(datum, decimalFormat); - const n = colInfo.maxLenAfterAlignChar - cellInfo.lenAfterAlignChar; - if (colInfo.hasAlignChar && (n > 0 || !cellInfo.hasAlignChar)) { - str += "\\phantom{"; - if (colInfo.hasAlignChar && !cellInfo.hasAlignChar) { - str += decimalFormat.slice(-1) === "." ? "." : "{,}"; - } - if (n > 0) { str += "0".repeat(n); } - str += "}"; - } - return str -}; - -const totalRegEx = /^(?:total|sum)/i; - -const display$1 = (df, formatSpec = "h3", decimalFormat = "1,000,000.", omitHeading = false) => { - const data = df.data.plain ? df.data.plain : df.data; - if (data.length === 0) { return "" } - const numRows = data[0].length; - const numCols = data.length; - const writeRowNums = numRows > 5 && !df.rowMap; - const isMap = !df.dtype; - let str = "\\begin{array}{"; - str += df.rowMap - ? "l|" - : writeRowNums - ? "r|" - : ""; - for (let j = 1; j < numCols; j++) { - str += isMap - ? "c " - : numRows === 1 - ? "c " - : Rnl.isRational(data[j][0]) - ? "r " - : "l "; - } - str = str.slice(0, -1) + "}"; - - if (!omitHeading) { - // Write the column names - if (writeRowNums) { str += "&"; } - for (let j = 0; j < numCols; j++) { - str += "{" + formatColumnName(df.headings[j]) + "}&"; - } - str = str.slice(0, -1) + " \\\\ "; - } - - // Write the unit names - if (isNotEmpty(df.units)) { - if (writeRowNums) { str += "&"; } - for (let j = 0; j < numCols; j++) { - let rowTex = ""; - if (df.units[j] && df.units[j].length > 0) { - const unitTex = unitTeXFromString(df.units[j]); - rowTex = unitTex.replace("\\;\\, ", ""); - } else { - rowTex = ""; - } - str += rowTex + "&"; - } - str = str.slice(0, -1) + " \\\\ "; - } - str += "\\hline "; - - const [colInfo, cellInfo] = getNumInfo(df); - - // Write the data - for (let i = 0; i < numRows; i++) { - if (i === numRows - 1 && totalRegEx.test(data[0][i])) { str += "\\hline "; } - if (writeRowNums) { str += String(i + 1) + " & "; } - for (let j = 0; j < numCols; j++) { - const datum = data[j][i]; - if (isMap) { - str += datum === undefined - ? " & " - : Rnl.isRational(datum) - ? format(datum, formatSpec, decimalFormat) + "&" - : Cpx.isComplex(datum) - ? Cpx.display(datum, formatSpec, decimalFormat)[0] + "&" - : "\\text{" + addTextEscapes(datum) + "} &"; - } else { - str += mixedFractionRegEx.test(datum) - ? format(Rnl.fromString(datum), formatSpec, decimalFormat) + "&" - : numberRegEx$5.test(datum) - ? displayNum(datum, colInfo[j], cellInfo[j][i], decimalFormat) + "&" - : datum === "" - ? "&" - : "\\text{" + addTextEscapes(datum) + "}&"; - } - } - str = str.slice(0, -1) + " \\\\ "; - } - - str = str.slice(0, -3).trim(); - str += "\\end{array}"; - return str -}; - -const displayAlt$1 = (df, formatSpec = "h3", decimalFormat = "1,000,000.", - omitHeading = false) => { - const data = df.data.plain ? df.data.plain : df.data; - if (data.length === 0) { return "" } - const numRows = data[0].length; - const numCols = data.length; - const writeRowNums = numRows > 5 && !df.rowMap; - let str = "``"; - - if (!omitHeading) { - // Write the column names - if (writeRowNums) { str += "\t"; } - str += ( (df.headings[0] === "name" || df.headings[0] === "item") - ? "" - : df.headings[0]) + "\t"; - for (let j = 1; j < numCols; j++) { - str += df.headings[j] + "\t"; - } - str = str.slice(0, -1) + "\n"; - } - - // Write the unit names - if (isNotEmpty(df.units)) { - if (writeRowNums) { str += "\t"; } - for (let j = 0; j < numCols; j++) { - str += df.units[j] + "\t"; - } - str = str.slice(0, -1) + "\n"; - } - - // Write the data - const isMap = !df.dtype; - for (let i = 0; i < numRows; i++) { - if (writeRowNums) { str += String(i + 1) + "\t"; } - for (let j = 0; j < numCols; j++) { - const datum = data[j][i]; - if (isMap) { - str += datum === undefined - ? "\t" - : Rnl.isRational(datum) - ? format(datum, formatSpec, decimalFormat).replace(/{,}/g, ",") + "\t" - : Cpx.isComplex(datum) - ? Cpx.display(datum, formatSpec, decimalFormat)[1].replace(/{,}/g, ",") + "\t" - : datum + "\t"; - } else { - if (mixedFractionRegEx.test(datum)) { - str += format(Rnl.fromString(datum), formatSpec, "100000.") + "\t"; - } else { - str += datum + "\t"; - } - } - } - str = str.slice(0, -1) + "\n"; - } - - str = str.slice(0, -1).trim(); - str += "``"; - return str -}; - -const DataFrame = Object.freeze({ - append: append$1, - dataFrameFromTSV, - dataFrameFromVectors, - matrix2table, - display: display$1, - displayAlt: displayAlt$1, - quickDisplay, - range: range$1 -}); - -/* - * lexer.js - * This file supports parser.js. - */ - -// Define constants for token types. -const tt = Object.freeze({ - UNARY: 0, // unary TeX function, e.g. \sqrt - BINARY: 1, // binary TeX function, e.g. \xrightarrow, differs from tt.BIN - SUB: 2, - SUP: 3, - ACCENT: 4, - // A left paren or bracket, ( or [], will be made invisible if located - // directly after a token whose token type < 5. - UNARYMINUS: 5, - DIV: 6, // stacked division: / \atop - PRIME: 7, - CURRENCY: 8, // currency symbol: $,£,¥,€, etc. Precedes its number. - ORD: 9, - VAR: 10, // variable name, one letter long - NUM: 11, - SPACE: 12, - LONGVAR: 13, - LEFTBRACKET: 14, - RIGHTBRACKET: 15, - BIG_OPERATOR: 16, - LEFTRIGHT: 17, // | - STRING: 18, - UNIT: 19, // unit-of-measure, e.g., 'meters' or ° - BIN: 20, // binary infix operators that render but don't calculate, e.g., ± \cdots - ADD: 21, // binary infix addition or subtraction operator: + - - MULT: 22, // binary infix multiplication or division operator: × * · // ÷ - REL: 23, // relational operator: ≟ > < ≤ ≥ etc. - LOGIC: 24, // if and or xor else otherwise - SEP: 25, // argument separators, cell separators and row separators: , ; - FUNCTION: 26, - ACCESSOR: 28, // dot between a data frame name and a property, as in r.prop - ENVIRONMENT: 29, - FACTORIAL: 30, - SUPCHAR: 31, - ANGLE: 32, - RANGE: 33, // separator for ranges (1:n) - KEYWORD: 34, // keywords: for in while - PROPERTY: 36, // property name after a dot accessor - COMMENT: 37, - RETURN: 38, // A return statement inside a user-defined function. - TO: 39, - DATAFRAME: 40, - RICHTEXT: 41, - BOOLEAN: 42, - MACRO: 43 -}); - -const minusRegEx = /^-(?![-=<>:])/; -const numberRegEx$4 = new RegExp(Rnl.numberPattern); -const unitRegEx = /^(?:'[^']+'|[°ΩÅK])/; - -const texFromNumStr = (numParts, decimalFormat) => { - let num = ""; - if (numParts[2]) { - // Hexadecimal - num = "\\mathrm{" + numParts[2] + "}"; - } else if (numParts[5]) { - return texFromMixedFraction(numParts) - } else { - // Decimal - num = numParts[3]; - if (numParts[6]) { num += "." + numParts[6]; } - num = formattedDecimal(num, decimalFormat); - if (numParts[8]) { - num += "\\%"; - } else if (numParts[7]) { - if (numParts[7].charAt(0) === "-") { - num += "\\text{e-}" + numParts[7].slice(1); - } else { - num += "\\text{e}" + numParts[7]; - } - } - } - if (numParts[1]) { - num = "\\text{-}" + num; - } - return num -}; - -const isUnary = (prevToken) => { - switch (prevToken.ttype) { - case tt.NUM: - case tt.ORD: - case tt.VAR: - case tt.RIGHTBRACKET: - case tt.LONGVAR: - case tt.UNIT: - case tt.CURRENCY: - case tt.SUPCHAR: - case tt.PRIME: - case tt.FACTORIAL: - return false - default: - return true - } -}; - -const wordRegEx = /^(?:(?:[A-Za-zıȷ\u0391-\u03C9\u03D5\u212C\u2130\u2131\u210B\u2110\u2112\u2133\u211B\u212F\u210A\u2113\u2134]|(?:\uD835[\uDC00-\udc33\udc9c-\udccf\udd38-\udd50]))[A-Za-z0-9_\u0391-\u03C9\u03D5\u0300-\u0308\u030A\u030C\u0332\u20d0\u20d1\u20d6\u20d7\u20e1]*|!in|-->|->|left\.|right\.|log10|log2)/; - -const words = Object.freeze({ - // input, tex output, type, closeDelim - "true": ["true", "\\mathord{\\text{true}}", tt.BOOLEAN, ""], - "false": ["false", "\\mathord{\\text{false}}", tt.BOOLEAN, ""], - cos: ["cos", "\\cos", tt.FUNCTION, ""], - cosd: ["cosd", "\\operatorname{\\cos_d}", tt.FUNCTION, ""], - if: ["if", "\\mathrel{\\mathrm{if}}", tt.LOGIC, ""], - else: ["else", "\\mathrel{\\mathrm{else}}", tt.LOGIC, ""], - elseif: ["elseif", "\\mathrel{\\mathrm{elseif}}", tt.LOGIC, ""], - and: ["and", "\\mathrel{\\mathrm{and}}", tt.LOGIC, ""], - or: ["or", "\\mathrel{\\mathrm{or}}", tt.LOGIC, ""], - for: ["for", "\\mathrel{\\mathrm{for}}", tt.KEYWORD, ""], - while: ["while", "\\mathrel{\\mathrm{while}}", tt.KEYWORD, ""], - in: ["in", "\\mathrel{\\mathrm{in}}", tt.REL, ""], - "!in": ["!in", "\\mathrel{\\mathrm{!in}}", tt.REL, ""], - break: ["break", "\\mathrel{\\mathrm{break}}", tt.KEYWORD, ""], - to: ["to", "\\mathbin{\\mathrm{to}}", tt.TO, "" ], - throw: ["throw", "\\mathrel{\\mathrm{throw}}", tt.UNARY, ""], - print: ["print", "\\mathrel{\\mathrm{print}}", tt.UNARY, ""], - return: ["return", "\\mathrel{\\mathrm{return}}", tt.RETURN, ""], - sqrt: ["sqrt", "\\sqrt", tt.UNARY, ""], - otherwise: ["otherwise", "\\mathrel{\\mathrm{otherwise}}", tt.LOGIC, ""], - root: ["root", "\\sqrt", tt.BINARY, ""], - sin: ["sin", "\\sin", tt.FUNCTION, ""], - sind: ["sind", "\\operatorname{\\sin_d}", tt.FUNCTION, ""], - tan: ["tan", "\\tan", tt.FUNCTION, ""], - tand: ["tand", "\\operatorname{\\tan_d}", tt.FUNCTION, ""], - cotd: ["cotd", "\\operatorname{\\cot_d}", tt.FUNCTION, ""], - secd: ["secd", "\\operatorname{\\sec_d}", tt.FUNCTION, ""], - cscd: ["cscd", "\\operatorname{\\csc_d}", tt.FUNCTION, ""], - log: ["log", "\\log", tt.FUNCTION, ""], - ln: ["ln", "\\ln", tt.FUNCTION, ""], - log10: ["log10", "\\log_{10}", tt.FUNCTION, ""], - log2: ["log2", "\\log_{2}", tt.FUNCTION, ""], - "log!": ["log!", "\\operatorname{log!}", tt.FUNCTION, ""], - pi: ["pi", "\\mathrm{pi}", tt.ORD, ""], - π: ["π", "π", tt.ORD, ""], - "ℓ": ["ℓ", "ℓ", tt.VAR, ""], - // A few arrows are placed here to give them priority over other arrows - "->": ["->", "\u2192", tt.REL, ""], // right arrow - "-->": ["-->", "\\xrightarrow", tt.UNARY, ""], - "<-->": ["<-->", "\\xrightleftarrows", tt.UNARY, ""] -}); - -const miscRegEx = /^([/÷\u2215_:,;\t^+\\\-–−*∗×∘⊗⦼⊙√∛∜·.%|╏‖¦><=≈≟≠≡≤≥≅∈∉∋∌⊂⊄⊆⊈⊃⊇⊉!¡‼¬∧∨⊻~#?⇒⟶⟵→←&@′″∀∃∫∬∮∑([{⟨⌊⎿⌈⎾〖〗⏋⌉⏌⌋⟩}\])˽∣ℂℕℚℝℤℓℏ∠¨ˆˉ˙˜▪✓\u00A0\u20D7$£¥€₨₩₪]+)/; - -const miscSymbols = Object.freeze({ - // input, output, type, closeDelim - "#": ["#", "#", tt.COMMENT, ""], - "/": ["/", "\\dfrac{", tt.DIV, ""], // displaystyle fraction - "//": ["//", "\\tfrac{", tt.DIV, ""], // textstyle fraction - "///": ["///", "/", tt.MULT, ""], // inline (shilling) fraction - "\u2215": ["\u2215", "\u2215", tt.MULT, ""], // inline (shilling) fraction - "÷": ["÷", "÷", tt.MULT, ""], - "./": ["./", "\\mathbin{.'}", tt.MULT, ""], - "_": ["_", "_", tt.SUB, ""], - "^": ["^", "^", tt.SUP, ""], - ".^": [".^", "\\mathbin{.^}", tt.SUP, ""], - "+": ["+", "+", tt.ADD, ""], - "-": ["-", "-", tt.ADD, ""], - "–": ["-", "-", tt.ADD, ""], // \u2013 en dash - "−": ["-", "-", tt.ADD, ""], // \u2212 math minus - ".+": [".+", "\\mathbin{.+}", tt.ADD, ""], - ".-": [".-", "\\mathbin{.-}", tt.ADD, ""], - "*": ["*", "*", tt.MULT, ""], - "∗": ["∗", "∗", tt.MULT, ""], - "×": ["×", "×", tt.MULT, ""], - "∘": ["∘", "∘", tt.MULT, ""], // U+2218 - "⊗": ["⊗", "⊗", tt.MULT, ""], - ".*": [".*", "\\mathbin{.*}", tt.MULT, ""], - "√": ["√", "\\sqrt", tt.UNARY, ""], - "\u221B": ["\u221B", "\\sqrt[3]", tt.UNARY, ""], - "\u221C": ["\u221C", "\\sqrt[4]", tt.UNARY, ""], - "+-": ["+-", "\u00B1", tt.BIN, ""], - "**": ["**", "\\star", tt.BIN, ""], - "·": ["·", "\u22C5", tt.MULT, ""], // dot operator - "...": ["...", "\\dots", tt.RANGE, ""], - "%": ["%", "\\%", tt.FACTORIAL, ""], - "-:": ["-:", "÷", tt.MULT, ""], - "=": ["=", "=", tt.REL, ""], - "≈": ["≈", "≈", tt.REL, ""], - "==": ["==", "⩵", tt.REL, ""], - "≡": ["≡", "≡", tt.REL, ""], - ">": [">", "\\gt", tt.REL, ""], - "\u226f": ["\u226f", "\\ngtr", tt.REL, ""], - "<": ["<", "\\lt", tt.REL, ""], - "\u226e": ["\u226e", "\\nless", tt.REL, ""], - "?=": ["?=", "\u225F", tt.REL, ""], - "≟": ["≟", "\u225F", tt.REL, ""], - "≠": ["≠", "≠", tt.REL, ""], - "!=": ["!=", "≠", tt.REL, ""], - "<>": ["<>", "≠", tt.REL, ""], - ":=": [":=", "\u2254", tt.REL, ""], - "<=": ["<=", "≤", tt.REL, ""], - "≤": ["≤", "≤", tt.REL, ""], - ">=": [">=", "\u2265", tt.REL, ""], - "≥": ["≥", "≥", tt.REL, ""], - "-=": ["-=", "\u2261", tt.REL, ""], - "~=": ["~=", "\u2245", tt.REL, ""], - "≅": ["≅", "≅", tt.REL, ""], - "~~": ["~~", "\u2248", tt.REL, ""], - "~": ["~", "\\sim", tt.REL, ""], - "=>": ["=>", "\u21D2", tt.REL, ""], - "⟶": ["⟶", "\\xrightarrow", tt.UNARY, ""], - "⟵": ["⟵", "\\xleftarrow", tt.UNARY, ""], - "⇒": ["⇒", "\u21D2", tt.REL, ""], - "<=>": ["<=>", "\u21D4", tt.REL, ""], - "-<": ["-<", "\u227A", tt.REL, ""], - ">-": [">-", "\u227B", tt.REL, ""], - "-<=": ["-<=", "\u2AAF", tt.REL, ""], - ">-=": [">-=", "\u2AB0", tt.REL, ""], - "_|_": ["_|_", "\\bot", tt.REL, ""], - "|--": ["|--", "\u22A2", tt.REL, ""], - "|==": ["|==", "\\models", tt.REL, ""], - "∈": ["∈", "∈", tt.REL, ""], - "∉": ["∉", "∉", tt.REL, ""], - "∋": ["∋", "∋", tt.REL, ""], - "∌": ["∌", "∌", tt.REL, ""], - "⊂": ["⊂", "⊂", tt.REL, ""], - "⊃": ["⊃", "⊃", tt.REL, ""], - "⊄": ["⊄", "⊄", tt.REL, ""], - "⊅": ["⊅", "⊅", tt.REL, ""], - "⊆": ["⊆", "⊆", tt.REL, ""], - "⊈": ["⊈", "⊈", tt.REL, ""], - "⊇": ["⊇", "⊇", tt.REL, ""], - "⊉": ["⊉", "⊉", tt.REL, ""], - "▪": ["▪", "\\mathrel{▪}", tt.REL, ""], - - "!": ["!", "!", tt.FACTORIAL, ""], - "‼": ["‼", "!!", tt.FACTORIAL, ""], - "!!": ["!!", "!!", tt.FACTORIAL, ""], - "¡": ["¡", "¡", tt.FACTORIAL, ""], - "&": ["&", "\\mathbin{\\&}", tt.ADD, ""], // string concatenator - "&_": ["&_", "\\mathbin{\\underline{\\&}}", tt.ADD, ""], // concatenate to bottom - "′": ["′", "'", tt.PRIME, ""], - "″": ["″", "''", tt.PRIME, ""], - "′′": ["′′", "''", tt.PRIME, ""], - "′′′": ["′′′", "'''", tt.PRIME, ""], - - "∀": ["∀", "∀", tt.LOGIC, ""], - "∃": ["∃", "∃", tt.LOGIC, ""], - "∧": ["∧", "∧", tt.LOGIC, ""], - "∨": ["∨", "∨", tt.LOGIC, ""], - "⊻": ["⊻", "⊻", tt.LOGIC, ""], // xor - "¬": ["¬", "¬", tt.UNARY, ""], // logical not - "&&": ["&&", "{\\;\\&\\&\\;}", tt.LOGIC, ""], - - "\u222B": ["\u222B", "\\displaystyle\u222B", tt.BIG_OPERATOR, ""], // \int - "\u222C": ["\u222C", "\\displaystyle\u222C", tt.BIG_OPERATOR, ""], // \iint - "\u222E": ["\u222E", "\\displaystyle\u222E", tt.BIG_OPERATOR, ""], // \oint - "\u2211": ["\u2211", "\\displaystyle\u2211", tt.BIG_OPERATOR, ""], // \sum - - "(": ["(", "(", tt.LEFTBRACKET, ")"], - "[": ["[", "[", tt.LEFTBRACKET, "]"], - "{": ["{", "\\{", tt.LEFTBRACKET, "\\}"], - "{:": ["{:", "{", tt.LEFTBRACKET, "}"], - "⟨": ["⟨", "⟨", tt.LEFTBRACKET, "⟩"], - ")": [")", ")", tt.RIGHTBRACKET, ""], - "]": ["]", "]", tt.RIGHTBRACKET, ""], - "}": ["}", "\\}", tt.RIGHTBRACKET, ""], - "⟩": ["⟩", "⟩", tt.RIGHTBRACKET, ""], - ":}": [":}", "}", tt.RIGHTBRACKET, ""], - "|": ["|", "|", tt.LEFTRIGHT, ""], - "||": ["||", "\\mathbin{||}", tt.BIN, ""], - "\\|": ["\\|", "‖", tt.LEFTRIGHT, ""], - "‖": ["‖", "‖", tt.LEFTRIGHT, ""], - "<<": ["<<", "\u27E8", tt.LEFTBRACKET, "\u27E9"], - ">>": [">>", "\u27E9", tt.RIGHTBRACKET, ""], - "\u23BF": ["\u23BF", "\\lfloor ", tt.LEFTBRACKET, "\\rfloor "], - "\u230B": ["\u230B", "\\rfloor ", tt.RIGHTBRACKET, ""], - "\u23CC": ["\u23CC", "\\rfloor ", tt.RIGHTBRACKET, ""], - "\u2308": ["\u2308", "\\lceil ", tt.LEFTBRACKET, "\\rceil "], - "\u23BE": ["\u23BE", "\\lceil ", tt.LEFTBRACKET, "\\rceil "], - "\u2309": ["\u2309", "\\rceil ", tt.RIGHTBRACKET, ""], - "\u23CB": ["\u23CB", "\\rceil ", tt.RIGHTBRACKET, ""], - "\u3016": ["\u3016", "{", tt.LEFTBRACKET, "}"], - "\u3017": ["\u3017", "}", tt.RIGHTBRACKET, ""], - "¦": ["¦", "\\mid ", tt.REL, ""], - - // double-struck, i.e. blackboard bold - "ℂ": ["ℂ", "\u2102", tt.ORD, ""], - "ℕ": ["ℕ", "\u2115", tt.ORD, ""], - "ℚ": ["ℚ", "\u211A", tt.ORD, ""], - "ℝ": ["ℝ", "\u211D", tt.ORD, ""], - "ℤ": ["ℤ", "\u2124", tt.ORD, ""], - - "ℏ": ["ℏ", "ℏ", tt.ORD, ""], - - //arrows - "\u2192": ["\u2192", "\u2192", tt.REL, ""], - "\u2190": ["\u2190", "\u2190", tt.REL, ""], // left arrow - ">->": [">->", "\u21a3", tt.REL, ""], // \rightarrowtail - "->>": ["->>", "\u21a0", tt.REL, ""], // \twoheadrightarrow - "|->": ["|->", "\u21a6", tt.REL, ""], // \mapsto - - // extensible arrows - "<--": ["<--", "\\xleftarrow", tt.UNARY, ""], - "==>": ["==>", "\\xRightarrow", tt.UNARY, ""], - "<==": ["<==", "\\xLeftarrow", tt.UNARY, ""], - "<-->": ["<-->", "\\xleftrightarrow", tt.UNARY, ""], - "<==>": ["<==>", "\\xLeftrightarrow", tt.UNARY, ""], - - "\u2220": ["\u2220", "\u2220", tt.ANGLE, ""], - "✓": ["✓", "✓", tt.ORD, ""], - "˽": ["˽", "~", tt.SPACE, ""], // "~" is a no-break space in LaTeX. - "\\;": ["\\;", ";\\:", tt.SEP, ""], - "…": ["…", "…", tt.ORD, ""], - - ":": [":", "{:}", tt.RANGE, ""], // range separator - ",": [",", ",\\:", tt.SEP, ""], // function argument or vector row separator - "\t": ["\t", " & ", tt.SEP, ""], // matrix element separator - ";": [";", " \\\\ ", tt.SEP, ""], // row separator - - "$": ["$", "\\$", tt.CURRENCY, ""], - "£": ["£", "£", tt.CURRENCY, ""], - "¥": ["¥", "¥", tt.CURRENCY, ""], - "€": ["€", "€", tt.CURRENCY, ""], - "₨": ["₨", "₨", tt.CURRENCY, ""], - "₩": ["₩", "₩", tt.CURRENCY, ""], - "₪": ["₪", "₪", tt.CURRENCY, ""] -}); - -const texFunctionRegEx = /^(\\[A-Za-z]+\.?|\\([:.!\u0020]|'+))/; - -const texFunctions = Object.freeze({ - // input, output, type, closeDelim - "\\aleph": ["\\aleph", "\u2135", tt.VAR, ""], - "\\beth": ["\\beth", "\u2136", tt.VAR, ""], - "\\gimel": ["gimel", "\u2137", tt.VAR, ""], - "\\daleth": ["daleth", "\u2138", tt.VAR, ""], - "\\atop": ["\\atop", "\\atop{", tt.DIV, ""], - "\\cdots": ["\\cdots", "\u22ef", tt.BIN, ""], - "\\vdots": ["\\vdots", "\u22ee", tt.BIN, ""], - "\\ddots": ["\\ddots", "\u22f1", tt.BIN, ""], - "\\iff": ["\\iff", "\\iff", tt.LOGIC, ""], - "\\land": ["\\land", "\\land", tt.BIN, ""], - "\\lor": ["\\lor", "\\lor", tt.BIN, ""], - "\\ngtr": ["\\ngtr", "\\ngtr", tt.REL, ""], - "\\nless": ["\\nless", "\\nless", tt.REL, ""], - "\\nleq": ["\\nleq", "\\nleq", tt.REL, ""], - "\\ngeq": ["\\ngeq", "\\ngeq", tt.REL, ""], - "\\in": ["\\in", "∈", tt.REL, ""], - "\\notin": ["\\notin", "∉", tt.REL, ""], - "\\subset": ["\\subset", "⊂", tt.REL, ""], - "\\subseteq": ["\\subseteq", "⊆", tt.REL, ""], - "\\nsubset": ["\\nsubset", "⊄", tt.REL, ""], - "\\nsubseteq": ["\\nsubseteq", "⊈", tt.REL, ""], - "\\supset": ["\\subset", "⊃", tt.REL, ""], - "\\left.": ["\\left.", "\\left.", tt.LEFTBRACKET, "\\right."], - "\\right.": ["\\right.", "\\right.", tt.RIGHTBRACKET, ""], - "\\mod": ["\\mod", "\\mod", tt.BIN, ""], - "\\diamond": ["\\diamond", "\\diamond", tt.ORD, ""], - "\\square": ["\\square", "\\square", tt.ORD, ""], - "\\int": ["\\int", "\\displaystyle\\int", tt.BIG_OPERATOR, ""], - "\\iint": ["\\iint", "\\displaystyle\\iint", tt.BIG_OPERATOR, ""], - "\\iiint": ["\\iiint", "\\displaystyle\\iiint", tt.BIG_OPERATOR, ""], - "\\oint": ["\\oint", "\\displaystyle\\oint", tt.BIG_OPERATOR, ""], - "\\oiint": ["\\oiint", "\\displaystyle\\oiint", tt.BIG_OPERATOR, ""], - "\\oiiint": ["\\oiiint", "\\displaystyle\\oiiint", tt.BIG_OPERATOR, ""], - "\\over": ["\\over", "\\dfrac{", tt.DIV], - "\\sum": ["\\sum", "\\displaystyle\\sum", tt.BIG_OPERATOR, ""], - "\\prod": ["\\prod", "\\displaystyle\\prod", tt.BIG_OPERATOR, ""], - "\\quad": ["\\quad", "\\quad", tt.SPACE, ""], - "\\qquad": ["\\qquad", "\\qquad", tt.SPACE, ""] -}); - -const accents = new Set([ - "Bbb", - "Overrightarrow", - "acute", - "bar", - "bm", - "bold", - "boldsymbol", - "breve", - "check", - "ddot", - "dot", - "frak", - "grave", - "hat", - "mathbb", - "mathbf", - "mathcal", - "mathfrak", - "mathit", - "mathnormal", - "mathring", - "mathrm", - "mathscr", - "mathsf", - "mathtt", - "overbrace", - "overgroup", - "overleftarrow", - "overleftharpoon", - "overleftrightarrow", - "overline", - "overrightarrow", - "overrightharpoon", - "tilde", - "underbrace", - "undergroup", - "underleftarrow", - "underleftrightarrow", - "underline", - "underrightarrow", - "utilde", - "vec", - "widecheck", - "widehat", - "widetilde" -]); - -// Avoid "operatorname" for functions that are already math operators. -const mathOperators = new Set([ - "arccos", - "arcsin", - "arctan", - "arctg", - "arcctg", - "cos", - "cosec", - "cosh", - "cot", - "cotg", - "coth", - "csc", - "ctg", - "cth", - "det", - "dim", - "exp", - "gcd", - "lg", - "lim", - "ln", - "log", - "max", - "min", - "sec", - "sin", - "sinh", - "sh", - "sqrt", - "sup", - "tan", - "tanh", - "tg", - "th" -]); - -const colors = new Set([ - "blue", - "firebrick", - "gray", - "green", - "orange", - "pink", - "purple", - "red" -]); - -const unaries = new Set([ - "bcancel", - "boxed", - "cancel", - // Hurmet does not support \ce. - "clap", - "color", - "llap", - "mathclap", - "not", - "operatorname", - "phantom", - "pu", - "rlap", - "sout", - "sqrt", - "tag", - "textbf", - "textit", - "textmd", - "textnormal", - "textrm", - "textsc", - "textsf", - "texttt", - "textup", - "xLeftarrow", - "xLeftrightarrow", - "xRightarrow", - "xcancel", - "xleftarrow", - "xleftrightarrow", - "xleftharpoondown", - "xleftharpoons", - "xleftharpoonup", - "xlongequal", - "xmapsto", - "xrightarrow", - "xrightharpoondown", - "xrightharpoonup", - "xrightleftarrows", - "xrightleftharpoons", - "xtofrom", - "xtwoheadleftarrow", - "xtwoheadrightarrow" -]); - -const binaries = new Set([ - "dfrac", - "frac", - "lower", - "overset", - "raisebox", - "stackrel", - "tag", - "tfrac", - "underset" -]); - -const texREL = new Set([ - "Bumpeq", "Colonapprox", "Coloneq", "Coloneqq", "Colonsim", "Darr", "Doteq", "Downarrow", - "Eqcolon", "Eqqcolon", "Harr", "Larr", "Leftarrow", "Leftrightarrow", "Lleftarrow", - "Longleftarrow", "Longleftrightarrow", "Longrightarrow", "Lrarr", "Lsh", "Rarr", - "Rightarrow", "Rrightarrow", "Rsh", "Supset", "Subset", "Uarr", "Uparrow", "Updownarrow", - "Vdash", "Vvdash", "approx", "approxeq", "asymp", "backepsilon", "backsim", "backsimeq", - "between", "bowtie", "bumpeq", "circeq", "circlearrowleft", "circlearrowright", - "colonapprox", "coloneq", "coloneqq", "colonsim", "cong", "curlyeqprec", "curlyeqsucc", - "curvearrowleft", "curvearrowright", "dArr", "darr", "dashleftarrow", "dashrightarrow", - "dashv", "dblcolon", "doteq", "doteqdot", "downarrow", "downdownarrows", "downharpoonleft", - "downharpoonright", "eqcirc", "eqcolon", "eqqcolon", "eqsim", "eqslantgtr", "eqslantless", - "equiv", "fallingdotseq", "frown", "ge", "geq", "geqq", "geqslant", "gets", "gg", "ggg", - "gggtr", "gnapprox", "gneq", "gneqq", "gnsim", "gt", "gtrapprox", "gtreqless", "gtreqqless", - "gtrless", "gtrsim", "gvertneqq", "hArr", "harr", "hookleftarrow", "hookrightarrow", "iff", - "impliedby", "implies", "in", "isin", "Join", "gets", "impliedby", "implies", "in", - "lArr", "larr", "le", "leadsto", "leftarrow", "leftarrowtail", "leftharpoondown", - "leftharpoonup", "leftleftarrows", "leftrightarrow", "leftrightarrows", "leftrightharpoons", - "leftrightsquigarrow", "leq", "leqq", "leqslant", "lessapprox", "lesseqgtr", "lesseqqgtr", - "lessgtr", "lesssim", "ll", "lll", "llless", "lnapprox", "lneq", "lneqq", "lnsim", - "longleftarrow", "longleftrightarrow", "longmapsto", "longrightarrow", "looparrowleft", - "looparrowright", "lrArr", "lrarr", "lt", "lvertneqq", "mapsto", "mid", "models", - "multimap", "nLeftarrow", "nLeftrightarrow", "nRightarrow", "nVDash", "nVdash", "ncong", - "ne", "nearrow", "neq", "nexists", "ngeq", "ngeqq", "ngeqslant", "ngtr", "ni", "nleftarrow", - "nleftrightarrow", "nleq", "nleqq", "nleqslant", "nless", "nmid", "notin", "notni", - "nparallel", "nprec", "npreceq", "nrightarrow", "nshortmid", "nshortparallel", "nsim", - "nsubseteq", "nsubseteqq", "nsucc", "nsucceq", "nsupseteq", "nsupseteqq", "ntriangleleft", - "ntrianglelefteq", "ntriangleright", "ntrianglerighteq", "nvDash", "nvdash", "nwarrow", - "owns", "parallel", "perp", "pitchfork", "prec", "precapprox", "preccurlyeq", "preceq", - "precnapprox", "precneqq", "precnsim", "precsim", "propto", "rArr", "rarr", "restriction", - "rightarrow", "rightarrowtail", "rightharpoondown", "rightharpoonup", "rightleftarrows", - "rightleftharpoons", "rightrightarrows", "rightsquigarrow", "risingdotseq", "searrow", - "shortmid", "shortparallel", "sim", "simeq", "smallfrown", "smallsmile", "smile", - "sqsubset", "sqsubseteq", "sqsupset", "sqsupseteq", "sub", "sube", - "subseteqq", "subsetneq", "subsetneqq", "succ", "succapprox", "succcurlyeq", "succeq", - "succnapprox", "succneqq", "succnsim", "succsim", "supe", "supset", "supseteq", "supseteqq", - "supsetneq", "supsetneqq", "swarrow", "thickapprox", "thicksim", "to", "trianglelefteq", - "triangleq", "trianglerighteq", "twoheadleftarrow", "twoheadrightarrow", "uArr", "uarr", - "uparrow", "updownarrow", "upharpoonleft", "upharpoonright", "upuparrows", "varpropto", - "varsubsetneq", "varsubsetneqq", "varsupsetneq", "varsupsetneqq", "vartriangle", - "vartriangleleft", "vartriangleright", "vcentcolon", "vdash", "vDash" -]); - -const superRegEx = /^⁻?[²³¹⁰⁴⁵⁶⁷⁸⁹]+/; - -const cloneToken$1 = tkn => [tkn[0], tkn[1], tkn[2], tkn[3]]; - -const accentFromChar = Object.freeze({ - "\u0300": "\\grave", - "\u0301": "\\acute", - "\u0302": "\\hat", - "\u0303": "\\tilde", - "\u0304": "\\bar", - "\u0305": "\\bar", - "\u0307": "\\dot", - "\u0308": "\\ddot", - "\u030A": "\\mathring", - "\u030C": "\\check", - "\u0332": "\\underline", - "\u20d0": "\\overleftharpoon", - "\u20d1": "\\overrightharpoon", - "\u20d6": "\\overleftarrow", - "\u20d7": "\\vec", - "\u20e1": "\\overleftrightarrow" -}); - -const wideAccentFromChar = Object.freeze({ - "\u0300": "\\grave", - "\u0301": "\\acute", - "\u0302": "\\widehat", - "\u0303": "\\widetilde", - "\u0304": "\\overline", - "\u0305": "\\overline", - "\u0307": "\\dot", - "\u0308": "\\ddot", - "\u030A": "\\mathring", - "\u030C": "\\check", - "\u0332": "\\underline", - "\u20d0": "\\overleftharpoon", - "\u20d1": "\\overrightharpoon", - "\u20d6": "\\overleftarrow", - "\u20d7": "\\overrightarrow", - "\u20e1": "\\overleftrightarrow" -}); - -const groupSubscript = word => { - const pos = word.indexOf("_"); - return pos === -1 - ? word - : word.slice(0, pos + 1) + "{" + word.slice(pos + 1) + "}" -}; - -const checkForTrailingAccent = word => { - const ch = word.slice(-1); - if (/[\u0300-\u0308\u030A\u030C\u0332\u20d0\u20d1\u20d6\u20d7\u20e1]/.test(ch)) { - word = word.slice(0, -1); - return word === "i" - ? accentFromChar[ch] + "{ı}" // dotless i - : word === "j" - ? accentFromChar[ch] + "{ȷ}" // dotless j - : word.length === 1 - ? accentFromChar[ch] + "{" + word + "}" - : wideAccentFromChar[ch] + "{" + word + "}" - } else { - return word - } -}; - -const lexOneWord = (str, prevToken) => { - const matchObj = wordRegEx.exec(str); - if (matchObj) { - let match = matchObj[0].replace(/_*$/, ""); // drop trailing underscores - - // Get the immediately following character - const fc = str.charAt(match.length); - - const word = words[match]; - if (word && fc !== "′") { - return word - } else if (/^\(/.test(fc)) { - // word is followed by an open paren. Treat it as a function name - return (prevToken.ttype === tt.ACCENT) - ? [match, match + "}{", tt.FUNCTION, ""] - : match === "sqrt" - ? [match, "\\sqrt", tt.UNARY, ""] - : match === "f" - ? [match, match, tt.FUNCTION, ""] - : mathOperators.has(match) - ? [match, "\\" + match, tt.FUNCTION, ""] - : [match, "\\operatorname{" + groupSubscript(match) + "}", tt.FUNCTION, ""] - } else if (prevToken.ttype === tt.ACCESSOR) { - return [match, match, tt.PROPERTY, ""] - } else if (/[_\u0300-\u0308\u030A\u030C\u0332\u20d0\u20d1\u20d6\u20d7\u20e1]/.test(match)) { - let identifier = ""; - if (match.indexOf("_") === -1) { - identifier = checkForTrailingAccent(match); - return [match, identifier, (match.length > 2) ? tt.LONGVAR : tt.VAR, ""] - } else { - const segments = match.split("_"); - for (let i = segments.length - 1; i >= 0; i--) { - segments[i] = checkForTrailingAccent(segments[i]); - if (i > 0) { - segments[i] = "_\\text{" + segments[i] + "}"; - } - } - identifier = segments.join(""); - const primes = /^′*/.exec(str.slice(match.length)); - if (primes) { - match += primes[0]; - identifier += "'".repeat(primes[0].length); - } - const pos = identifier.indexOf("_"); - if (pos > -1) { - // Cramp subscript placement by wrapping it with braces. - // This helps Cambria Math to supply the correct size radical. - identifier = identifier.slice(0, pos) + "{" + identifier.slice(pos) + "}"; - } - return [match, identifier, (segments[0].length > 1) ? tt.LONGVAR : tt.VAR, ""] - } - } else if (match.length === 2 & match.charAt(0) === "\uD835") { - return [match, match, tt.VAR, ""] - } else if (match.length > 1) { - return [match, match, tt.LONGVAR, ""] - } else { - // Return a single character variable name - if (match.charAt(0) === "\uD835") { - return [match.substring(0, 2), match.substring(0, 2), tt.VAR, ""] - } else { - return [match.charAt(0), match.charAt(0), tt.VAR, ""] - } - } - } -}; - -const lex = (str, decimalFormat, prevToken, inRealTime = false) => { - // Get the next token in str. Return an array with the token's information: - // [input, TeX output, type, associated close delimiter] - let pos = 0; - let st = ""; - let matchObj; - - if (str.length > 3 && str.slice(0, 3) === "===") { - // A macro between triple-double quotation marks. - pos = str.indexOf('"""', 3); - if (pos > 0) { - st = str.slice(3, pos); - return ['"""' + st + '"""', st, tt.MACRO, ""] - } else { - return [str, str.slice(3), tt.MACRO, ""] - } - } - - if (str.charAt(0) === '"') { - // String between double quotation marks. Parser will convert it to \text{…} - pos = str.indexOf('"', 1); - if (pos > 0) { - // Disallow \r or \n by truncating the string. - st = str.substring(1, pos).replace(/\r?\n.*/, ""); - return ['"' + st + '"', st, tt.STRING, ""] - } else { - return [str, str.replace(/\r?\n.*/, ""), tt.STRING, ""] - } - } - - if (/^#/.test(str)) { - // comment - st = str.slice(2); - pos = st.indexOf("\n"); - if (pos > -1) { - const posReturn = st.indexOf("\n"); - if (posReturn > -1 && posReturn < pos) { pos = posReturn; } - } - if (pos > -1) { - st = st.slice(0, pos); - } - return [`#${st}`, `\\text{\\texttt{ \\#${st}}}`, tt.COMMENT, ""] - } - - if (/^``/.test(str)) { - // inline TSV string between double back ticks, a data frame literal. - pos = str.indexOf("`", (str.charAt(2) === "`" ? 3 : 2)); - const inputStr = (pos > 0 ? str.slice(2, pos) : str.slice(2)); - const st = tablessTrim(inputStr); - let tex = ""; - if (inRealTime) { - tex = DataFrame.quickDisplay(st); - } else { - const dataStructure = DataFrame.dataFrameFromTSV(st); - tex = DataFrame.display(dataStructure.value, "h3", decimalFormat); - } - return ["``" + inputStr + "``", tex, tt.DATAFRAME, ""] - } - - if (str.charAt(0) === '`') { - // Rich text string. Usually a return from a calculation. - // String between double quotation marks. Parser will convert it to \text{…} - pos = str.indexOf('`', 1); - if (pos > 0) { - // Disallow \r or \n by truncating the string. - st = str.substring(1, pos).replace(/\r?\n.*/, ""); - return ['`' + st + '`', st, tt.RICHTEXT, ""] - } else { - return [str, str.replace(/\r?\n.*/, ""), tt.RICHTEXT, ""] - } - } - - if (unitRegEx.test(str)) { - // String between single quotation marks. That signals a tt.UNIT. - pos = str.indexOf("'", 1); - if (pos > 0) { - st = str.substring(1, pos); - return ["'" + st + "'", unitTeXFromString(st), tt.UNIT, ""] - } else { - // One of the unambiguous unit symbols, like ° or Å - return [str.charAt(0), str.charAt(0), tt.UNIT, ""] - } - } - - // Strings beginning with "\" are passed through as a TeX control word. - matchObj = texFunctionRegEx.exec(str); - if (matchObj) { - // TeX control word, starting with backslash. e.g. \, or \circ - const match = matchObj[0]; - st = match.substring(1); - if (accents.has(st)) { - return [match, match, tt.ACCENT, ""] - } - if (unaries.has(st)) { - return [match, match, tt.UNARY, ""] - } - if (colors.has(st)) { - return [match, "\\textcolor{" + st + "}", tt.UNARY, ""] - } - if (binaries.has(st)) { - return [match, match, tt.BINARY, ""] - } - if (texREL.has(st)) { - return [match, match, tt.REL, ""] - } - const texFunc = texFunctions[match]; - if (texFunc) { - return cloneToken$1(texFunc) - } - // default case is a mathord. So I have not enumerated any ORDs - return [match, match, tt.ORD, ""] - } - - if (minusRegEx.test(str)) { - if (isUnary(prevToken)) { - // Check if the unary minus is part of a number - const numParts = str.match(numberRegEx$4); - if (numParts) { - // numbers - st = texFromNumStr(numParts, decimalFormat); - return [numParts[0], st, tt.NUM, ""] - } - } - return ["-", "-", tt.ADD, ""] - } - - const numParts = str.match(numberRegEx$4); - if (numParts) { - // numbers - st = texFromNumStr(numParts, decimalFormat); - return [numParts[0], st, tt.NUM, ""] - } - - // Before lexing for a word, find underscores before a group - if (/^_[([{]/.test(str)) { - return ["_", "_", tt.SUB, ""] - } - - const word = lexOneWord(str, prevToken); - if (word) { return cloneToken$1(word) } - - const nums = superRegEx.exec(str); - if (nums) { - return [nums[0], nums[0], tt.SUPCHAR, ""] - } - - //return maximal initial substring of str that appears in misc names - matchObj = miscRegEx.exec(str); - if (matchObj) { - const match = matchObj[0]; - for (let i = match.length; i >= 1; i--) { - st = match.substr(0, i); - if (miscSymbols[st]) { return cloneToken$1(miscSymbols[st]) } - } - } - - // No keywords were matched. Return 1 character. - const c1 = str.charAt(0); - if (c1 === "." && (prevToken.ttype === tt.VAR || prevToken.ttype === tt.LONGVAR || - prevToken.ttype === tt.STRING || prevToken.input === "]" || prevToken.input === ")" || - prevToken.ttype === tt.PROPERTY)) { - // Suppress the spacing of the accessor dot. - return [".", "{.}", tt.ACCESSOR, ""] - } - return [c1, addTextEscapes(c1), tt.VAR, ""] -}; - -/* - * parser.js - * - * This file takes a text string and compiles it to TeX. - * If the isCalc flag is set, then parse() also compiles the text to an RPN string - * used elsewhere for further Hurmet computation. - * -*/ - -const builtInFunctions = new Set([ - "Char", "Int", "abs", "acos", "acosd", "acosh", "acot", "acotd", "acoth", "acsc", "acscd", - "acsch", "angle", "asec", "asecd", "asech", "asin", "asind", "asinh", "atan", "atan2", - "atand", "atanh", "binomial", "ceil", "conj", "cos", "cosd", "cosh", - "cosh", "cot", "cotd", "coth", "coth", "count", "csc", "cscd", "csch", "csch", "exp", - "factorial", "fetch", "findmax", "floor", "format", "gamma", "gcd", "hcat", - "hypot", "imag", "isnan", "length", "lerp", "ln", "log", "log10", "log2", "lfact", "lgamma", - "logn", "mod", "number", "ones", "real", "rem", "rms", "round", "roundSig", "roundn", "sec", - "secd", "sech", "sech", "sign", "sin", "sind", "sinh", "startSvg", "string", "tan", "tand", - "tanh", "tanh", "trace", "transpose", "vcat", "zeros", "Γ" -]); - -const builtInReducerFunctions = new Set(["accumulate", "beamDiagram", "dataframe", - "findfirst", "matrix2table", "max", "mean", "median", "min", "product", "rand", "range", - "stddev", "sum", "variance" -]); - -const trigFunctions = new Set(["cos", "cosd", "cot", "cotd", "csc", "cscd", "sec", "secd", - "sin", "sind", "tand", "tan"]); - -const rationalRPN = numStr => { - // Return a representation of a rational number that is recognized by evalRPN(). - const num = Rnl.fromString(numStr); - return "®" + String(num[0]) + "/" + String(num[1]) -}; - -const checkForUnaryMinus = (token, prevToken) => { - switch (prevToken.ttype) { - case tt.NUM: - case tt.ORD: - case tt.VAR: - case tt.RIGHTBRACKET: - case tt.LONGVAR: - case tt.PROPERTY: - case tt.UNIT: - case tt.SUPCHAR: - case tt.PRIME: - case tt.FACTORIAL: - return token - // do nothing - } - if (token.output === "-") { - return { input: "~", output: "\\text{-}", ttype: tt.UNARYMINUS } - } else { - return { input: "+", output: "~+", ttype: tt.UNARYMINUS } - } -}; - -const numFromSuperChar = { - "⁻": "-", - "²": "2", - "³": "3", - "¹": "1", - "⁰": "0", - "⁴": "4", - "⁵": "5", - "⁶": "6", - "⁷": "7", - "⁸": "8", - "⁹": "9" -}; - -const numFromSupChars = str => { - let num = ""; - for (const ch of str) { - num += numFromSuperChar[ch]; - } - return num -}; - -const colorSpecRegEx = /^(#([a-f0-9]{6}|[a-f0-9]{3})|[a-z]+|\([^)]+\))/i; -const accentRegEx = /^(?:.|\uD835.)[\u0300-\u0308\u030A\u030C\u0332\u20d0\u20d1\u20d6\u20d7\u20e1]_/; - -const factors = /^[A-Za-zıȷ\u0391-\u03C9\u03D5\u210B\u210F\u2110\u2112\u2113\u211B\u212C\u2130\u2131\u2133\uD835[({√∛∜]/; - -const setUpIf = (rpn, tokenInput, exprStack, delim) => { - // The Hurmet CASES expression acts lazily. To accommodate that, push the - // sub-expression onto a stack of expressions. At the closing brace, - // we'll pop all the expressions off the stack and place them after the conditions. - // Later, evaluate.js will evaluate the conditions and then pick the correct expression. - const expression = rpn.replace(/^.*\xa0/, "").replace(/§$/, "\xa0"); - exprStack.push(expression); - rpn = rpn.length === expression.length ? "" : rpn.slice(0, rpn.length - expression.length); - delim.numArgs += 1; - if (tokenInput === "otherwise") { rpn += "true"; } - return rpn -}; - -const functionExpoRegEx = /^[\^⁻⁰¹²³\u2074-\u2079]/; - -const openParenRegEx$1 = /^ *\(/; - -const exponentOfFunction = (str, decimalFormat, isCalc) => { - // As in: sin²() - let expoInput = ""; - if (str.charAt(0) !== "^") { - expoInput = /^⁻?[⁰¹²³\u2074-\u2079⁻]+/.exec(str)[0]; - expoInput = expoInput.split("").map(ch => numeralFromSuperScript(ch)).join(""); - } else if (!openParenRegEx$1.test(str.slice(1))) { - expoInput = lex(str.slice(1), decimalFormat, { input: "", output: "", ttype: 50 })[0]; - } else { - // The exponent is in parens. Find its extent. - expoInput = "("; - let level = 1; - for (let i = 2; i < str.length; i++) { - const ch = str.charAt(i); - expoInput += ch; - if ("\"'`".indexOf(ch) > -1) { - const pos = str.indexOf(ch, i + 1); - expoInput += str.slice(i + 1, pos + 1); - i = pos; - } else if ("([{⟨\u2308\u23BF\u23BE\u3016".indexOf(ch) > -1) { - level += 1; - } else if (")]}⟩\u2309\u230B\u23CC\u3017".indexOf(ch) > -1) { - level -= 1; - } - if (level === 0) { break } - } - } - - const parseInput = (expoInput.charAt(0) === "(") - ? expoInput.slice(1, -1).trim() - : expoInput; - - if (isCalc) { - const expoOutput = parse$1(parseInput, decimalFormat, true); - return [expoInput, "{" + expoOutput[0] + "}", expoOutput[1]] - } else { - const expoTex = parse$1(parseInput, decimalFormat, false); - return [expoInput, "{" + expoTex + "}", ""] - } -}; - -const testForImplicitMult = (prevToken, texStack, str) => { - // Some math expressions imply a multiplication without writing an explicit operator token. - // Examples: e = m c², y = 3(2+5), n = (a+5)x, z = 5 + 2i - // Hurmet writes the echo expression with a more explicit written form of multiplication. - // The echo shows each multiplication in one of three ways: a x b, a · b, or (a)(b) - // This sub is going to determine if such an adjustment is required for the current position. - - if (texStack.length > 0) { - // Test for a tex unary function or a function w/ tt.SUP or tt.SUB - const topType = texStack[texStack.length - 1].ttype; - if (topType === tt.UNARY || topType === tt.BINARY) { return false } - if (topType === tt.SUB || topType === tt.SUP) { - if (texStack[texStack.length - 1].isOnFunction) { return false } - } - } - - let isPreceededByFactor = false; - if (prevToken.output) { - const pc = prevToken.output.charAt(prevToken.length - 1); - if (")]}".indexOf(pc) > -1) { - if ((pc === ")" || pc === "]") && /^[([]/.test(str)) { - // This was already handled by the tt.RIGHTBRACKET case - return false - } else { - isPreceededByFactor = true; - } - } else { - switch (prevToken.ttype) { - case tt.ORD: - case tt.NUM: - case tt.VAR: - case tt.LONGVAR: - case tt.PRIME: - case tt.SUP: - case tt.SUPCHAR: - case tt.SUB: - case tt.PROPERTY: - case tt.UNIT: - case tt.RIGHTBRACKET: - case tt.FACTORIAL: - isPreceededByFactor = true; - break - default: - isPreceededByFactor = false; - } - } - } - if (isPreceededByFactor && nextCharIsFactor(str, prevToken.ttype)) { return true } - return false -}; - -const multiplicands = new Set([tt.ORD, tt.VAR, tt.NUM, tt.LONGVAR, tt.RIGHTBRACKET, - tt.CURRENCY, tt.SUPCHAR, tt.BIG_OPERATOR]); - -const nextCharIsFactor = (str, tokenType) => { - const st = str.replace(leadingLaTeXSpaceRegEx, ""); - const fc = st.charAt(0); - - let fcMeetsTest = false; - if (st.length > 0) { - if (fc === "|" || fc === "‖") ; else if (/^[({[√∛∜∑0-9]/.test(st) && multiplicands.has(tokenType)) { - return true - } else { - if (factors.test(fc)) { - fcMeetsTest = !/^(if|and|atop|or|else|elseif|otherwise|not|for|in|while|end)\b/.test(st); - } - } - } - return fcMeetsTest -}; - -const cloneToken = token => { - return { - input: token.input, - output: token.output, - ttype: token.ttype, - closeDelim: token.closeDelim - } -}; - -const endOfOrd = new Set([tt.ORD, tt.VAR, tt.NUM, tt.LONGVAR, tt.RIGHTBRACKET, tt.SUPCHAR]); - -// The RegEx below is equal to /^\s+/ except it omits \n, \t, and the no-break space \xa0. -// I use \xa0 to precede the combining arrow accent character \u20D7. -const leadingSpaceRegEx$2 = /^[ \f\r\v\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]+/; -const leadingLaTeXSpaceRegEx = /^(˽|\\quad|\\qquad)+/; -const sumRegEx = /\\∑_¿([^\xa0]+)([^=]+)\xa0=(\xa0[^^]+)\xa0\^\xa0([^∑]+)\xa0∑/; - -/* eslint-disable indent-legacy */ -const rpnPrecFromType = [ - 13, 13, 16, 14, 17, 10, - 8, 10, 13, -1, -1, - -1, 1, -1, 0, 0, - 7, 0, -1, 15, 0, - 6, 8, 5, 4, 1, - 13, 17, 16, -1, 15, - 14, 10, 3, 2, 11, - -1, -1, 4, 3, -1, - -1, -1, -1 -]; - -const texPrecFromType = [ - 12, 12, 15, 13, 16, 10, - 2, 10, 12, 2, 2, - 2, 1, 2, 2, 0, - 2, 1, 2, 14, 1, - 2, 2, 1, 1, 1, - 2, -1, 15, 2, 14, - 13, 9, -1, 1, -1, - 15, -1, 1, -1, 2, - 2, 2, 2 -]; -/* eslint-enable indent-legacy */ - -/* Operator Precedence -TeX RPN - 0 0 ( [ { delimiters - 1 1 , ; : separators for arguments, elements, rows, and ranges - 1 2 for in while loop keywords - 1 3 : range separator - 1 4 if ∧ ∨ logical operators, return - 1 5 < > ≤ ≥ comparisons - 2 6 + - addition and subtraction - 2 7 ∑ big operators - 2 8 * (x)(y) / multiplication, division - 9 10 ∠ \angle. Used as a separator for complex numbers in polar notation - 10 11 - unary minus - 12 13 sqrt sin unary functions, math functions, and binary functions (e.g. root 3 x) - 13 14 ^ superscript, i.e. exponent - 14 15 ! % ‰ ° factorial, percent, permil, degree - 15 16 _ ' . subscript, prime, dot notation property accessor - 16 17 hat bb accent and font -*/ - -// Delimiter types -const dNOTHING = 0; -const dPAREN = 1; // () or [] or {}, but not one of the use cases below -const dFUNCTION = 2; // sin(x) -const dACCESSOR = 3; // identifier[index] or identifier[start:step:end] -const dMATRIX = 4; // [1; 2] or (1 \t 2; 3 \t 4) -const dVECTORFROMRANGE = 5; // [start:end] or [start:step:end] -const dDICTIONARY = 6; // {key => value, key => value} -const dCASES = 7; // { a if b; c otherwise } -const dBINOMIAL = 8; -const dSUBSCRIPT = 9; // Parens around a subscript do not get converted into matrices. -const dDISTRIB = 10; // A probability distribution defined by a confidence interval. - -const parse$1 = ( - str, - decimalFormat = "1,000,000.", - isCalc = false, // true when parsing the blue echo of an expression - inRealTime = false // true when updating a rendering with every keystroke in the editor. -) => { - // Variable definitions - let tex = ""; - let rpn = ""; - let token = {}; - let prevToken = { input: "", output: "", ttype: 50 }; - const dependencies = []; - let mustLex = true; - let mustAlign = false; - let posOfPrevRun = 0; - let isPrecededBySpace = false; - let isFollowedBySpace = false; - let isFollowedBySpaceOrNewline = false; - let isImplicitMult = false; - let followedByFactor = false; - let op; - const texStack = []; // operator stack for TeX rendering - const rpnStack = []; // operator stack for RPN - const delims = [{ delimType: dNOTHING, isTall: false }]; // delimiter stack - let okToAppend = true; - let fc = ""; - let pendingFunctionName = ""; - let tokenSep = "\xa0"; // no break space - let rpnPrec = -1; - const exprStack = []; // Use for lazy evalulation of ternary (If) expressions - let numFreeCommas = 0; // # of items in a tuple - let posArrow = 0; - - // This function, parse(), is the main function for this module. - // Before we get to the start line, we write two enclosed functions, - // popRpnTokens() and popTexTokens(). - // They are placed here in order to share variable scope with parse(). - - const popRpnTokens = rpnPrec => { - if (isCalc && rpnPrec >= 0) { - // Pop operators off the rpnStack and append them to the rpn string - while (rpnStack.length > 0) { - const topPrec = rpnStack[rpnStack.length - 1].prec; - // exponents, from right to left. - if (topPrec < rpnPrec || (topPrec === 13 && rpnPrec === 13)) { break } - const symbol = rpnStack.pop().symbol; - if (symbol === "→") { - rpn = rpn.slice(0, posArrow + 1) + '"' - + rpn.slice(posArrow + 1, -1).replace(/\u00a0/g, "§") + '"' + tokenSep; - posArrow = 0; - } - rpn += symbol + tokenSep; - } - } - }; - - const popTexTokens = (texPrec, okToAppend) => { - - if (!okToAppend) { return } - - // Pop tokens off the texStack. Append closing delimiters to the tex string. - // When necessary, insert an opening brace before a fraction numerator. - if (texStack.length === 0) { - if (prevToken.ttype !== tt.RIGHTBRACKET && prevToken.ttype !== tt.LEFTRIGHT) { - // The purpose of op.pos in general is to let some possible - // upcoming division know where to insert a "\frac{" before the numerator. - // If we've gotten here, then no operators are on the texStack, so set op.pos - // at the beginning of the previous token. - op = { pos: posOfPrevRun, ttype: prevToken.ttype, closeDelim: "" }; - } - return - } - - const topOp = texStack[texStack.length - 1]; - if ( - (texPrec === 2 || texPrec === 12 || texPrec === 14 || texPrec === 15) && - (prevToken.ttype !== tt.RIGHTBRACKET && prevToken.ttype !== tt.LEFTRIGHT) && - topOp.prec < texPrec - ) { - op = { pos: posOfPrevRun, ttype: prevToken.ttype, closeDelim: "" }; - return - } - - // Pop operators whose precedence ≥ texPrec. Append a close delimiter for each. - let delim = {}; - while (texStack[texStack.length - 1].prec >= texPrec && - // Also handle exponents, from right to left, as in 3^4^5 - !(texStack[texStack.length - 1].prec === 13 && texPrec === 13)) { - op = texStack.pop(); - - // Before we append braces, check if we must hide a pair of parens. - if (op.prec === 0) { - // We just popped a delimiter operator. - delim = delims[delims.length - 1]; - if ((op.ttype === tt.LEFTBRACKET || op.ttype === tt.LEFTRIGHT) && - op.closeDelim.length > 0) { - if (texStack.length > 0) { - if ( - op.ttype === tt.LEFTRIGHT && - token.output === ")" && - texStack[texStack.length - 1].closeDelim === ")" - ) { - // op is a middle |, as in P(A|B). Check if it's tall. - if (delim.isTall) { - tex = tex.substring(0, op.pos) + "\\middle" + tex.substring(op.pos); - delims[delims.length - 1].isTall = true; - } - // Pop another delim. - op = texStack.pop(); - delims.pop(); - delim = delims[delims.length - 1]; - } - } - - if (delim.delimType === dDICTIONARY && delim.open.length > 3) { - tex = tex.slice(0, op.pos) + delim.open + tex.slice(op.pos + 2); - op.closeDelim = delim.close; - } else if (delim.delimType === dMATRIX || delim.delimType === dACCESSOR) { - const inc = tex.slice(op.pos, op.pos + 1) === "\\" ? 2 : 1; - tex = tex.slice(0, op.pos) + delim.open + tex.slice(op.pos + inc); - op.closeDelim = delim.close; - } else if (delim.delimType === dCASES) { - tex = tex.slice(0, op.pos) + delim.open + tex.slice(op.pos + 2); - op.closeDelim = delim.close; - } else if (delim.delimType === dPAREN && - delim.name === "(" && /^(\/|\\atop\s)/.test(str)) { - // The parens surround a numerator. Delete them. - tex = tex.substring(0, op.pos) + tex.substring(op.pos + 1); - op.closeDelim = ""; - } else if (delim.isPrecededByDiv && delim.delimType === dPAREN && - delim.name === "(" && (/^[^^_!%°⁻²³¹⁰⁴⁵⁶⁷⁸⁹]/.test(str) || str.length === 0)) { - // The parens surround a denominator. Delete them. - tex = tex.substring(0, op.pos) + tex.substring(op.pos + 1); - op.closeDelim = ""; - } else if (delim.isTall) { - // Make the delims tall. - if (/^\\left/.test(tex.substring(op.pos)) === false) { - tex = tex.substring(0, op.pos) + "\\left" + tex.substring(op.pos); - } - if (/\\right/.test(op.closeDelim) === false) { - op.closeDelim = "\\right" + token.output; - } - } - } - } - - tex = tex.replace(/\\, *$/, ""); // Remove an implicit multiplication space. - tex += op.closeDelim; - - if (op.closeDelim.slice(-1) === "{") { - // We just closed the first part of a binary function, e.g. root()(), - // or a function exponent (sin^2 θ) or function subscript (log_10) - if (op.ttype === tt.BINARY) { - texStack.push({ prec: 12, pos: op.pos, ttype: tt.UNARY, closeDelim: "}" }); - if (isCalc) { - rpn += tokenSep; - if (rpnStack[rpnStack.length - 1].symbol === "\\sqrt") { - rpnStack[rpnStack.length - 1].symbol = "root"; - } - } - } - op.ttype = tt.UNARY; - prevToken = { input: "", output: "", ttype: tt.UNARY }; - return - } - - if (texStack.length === 0 || op.prec === 0) { - return - } - } - }; - - // With the closed functions out of the way, execute the main parse loop. - str = str.replace(leadingSpaceRegEx$2, ""); // trim leading white space from string - str = str.replace(/\s+$/, ""); // trim trailing white space - - while (str.length > 0) { - // Get the next token. - if (str.charAt(0) === "\n") { - str = str.slice(1); - const prevChar = prevToken ? prevToken.input.slice(-1) : "0"; - if ( - prevToken.ttype === tt.COMMENT || - ("{[(,;+-".indexOf(prevChar) === -1 && !/^ *[)}\]]/.test(str)) - ) { - popTexTokens(0, true); - tex += "\\\\ "; - const matchObj = /^ +/.exec(str); - str = str.replace(/^ */, ""); - if (str.length > 0 && str.charAt(0) === "=" & tex.indexOf("=") > -1) { - mustAlign = true; // We'll use the TeX {aligned} environment to align = signs. - tex += "&"; - } else if (matchObj) { - tex += "\\quad ".repeat(matchObj[0].length - 1); - } - } - str = str.trim(); - } - - mustLex = true; // default - - isImplicitMult = isPrecededBySpace && okToAppend && - testForImplicitMult(prevToken, texStack, str); - if (isCalc) { - if (prevToken.input === "⌧" && rpnStack.length > 1 - && rpnStack[rpnStack.length - 2].symbol === "∑" - && rpn.charAt(rpn.length - 2) === "^" - ) { - // This is the space after a ∑_(i=0)^n symbol. Do not treat as implicit multiplication. - rpnStack.pop(); - } - } - - if (isImplicitMult) { - const prevType = prevToken.ttype; - token = { - input: "⌧", - output: [tt.LONGVAR, tt.NUM, tt.UNIT].includes(prevType) ? "\\," : "", - ttype: tt.MULT - }; - isFollowedBySpace = false; - isFollowedBySpaceOrNewline = false; - mustLex = false; - } - - if (mustLex) { - const tkn = lex(str, decimalFormat, prevToken, inRealTime); - token = { input: tkn[0], output: tkn[1], ttype: tkn[2], closeDelim: tkn[3] }; - str = str.substring(token.input.length); - isFollowedBySpace = leadingSpaceRegEx$2.test(str) || /^(˽|\\quad|\\qquad)+/.test(str); - isFollowedBySpaceOrNewline = /^[ \n]/.test(str); - str = str.replace(leadingSpaceRegEx$2, ""); - followedByFactor = nextCharIsFactor(str, token.ttype); - } - - if (token.input === "!" && (isPrecededBySpace || !endOfOrd.has(prevToken.ttype))) { - // Redefine ! as logical not in certain contexts, to match Julia syntax. - token.ttype = tt.UNARY; - token.input = "¬"; - } - - switch (token.ttype) { - case tt.SPACE: // spaces and newlines - case tt.BIN: // infix math operators that render but don't calc, e.g. \bowtie - case tt.ADD: // infix add/subtract operators, + - - case tt.MULT: // infix mult/divide operators, × * · // ÷ - case tt.REL: // relational operators, e.g < == → - case tt.BIG_OPERATOR: { // int, sum, lim, etc - if (token.output.length > 0 && "- +".indexOf(token.output) > -1) { - token = checkForUnaryMinus(token, prevToken); - } - - if (isCalc && token.output === "→") { - // This arrow is used for anonymous functions, e.g., x → cos x. - rpn = rpn.replace(/¿([^\u00a0]+)$/, '"$1"'); - posArrow = rpn.length; - const posBracket = tex.lastIndexOf("〖"); - tex = tex.slice(0, posBracket) + tex.slice(posBracket + 1); - } - - if (isCalc && token.ttype !== tt.SPACE) { - if (token.output !== "\\text{-}" && token.ttype !== tt.BIG_OPERATOR) { - rpn += tokenSep; - } - popRpnTokens(rpnPrecFromType[token.ttype === tt.BIG_OPERATOR ? tt.VAR : token.ttype]); - } - - const texPrec = texPrecFromType[token.ttype]; - popTexTokens(texPrec, okToAppend); - tex += token.output + " "; - posOfPrevRun = tex.length; - - if (token.ttype === tt.BIG_OPERATOR && delims.length > 1) { - delims[delims.length - 1].isTall = true; - } - if (isCalc) { - if (token.input === "∑" || token.input === "\\sum") { - rpn += "\\∑"; - token.input === "∑"; - } - rpnStack.push({ prec: rpnPrecFromType[token.ttype], symbol: token.input }); - } - - okToAppend = true; - break - } - - case tt.ACCESSOR: // dot between a map name and a property, as in r.PROPERTY - case tt.ANGLE: // \angle. Used as a separator for complex numbers in polar notation - token = checkForUnaryMinus(token, prevToken); - if (isCalc) { - rpn += tokenSep; - rpnPrec = rpnPrecFromType[token.ttype]; - popRpnTokens(rpnPrec); - rpnStack.push({ prec: rpnPrec, symbol: token.input }); - } - popTexTokens(texPrecFromType[token.ttype], okToAppend); - tex += isCalc ? token.input : token.output + " "; - okToAppend = true; - break - - case tt.BOOLEAN: - popTexTokens(2, okToAppend); - if (isCalc) { - popRpnTokens(-1); - rpn += token.input; - } - if (isPrecededBySpace) { posOfPrevRun = tex.length; } - tex += token.output; - okToAppend = true; - break - - case tt.NUM: - case tt.ORD: - popTexTokens(2, okToAppend); - if (isCalc) { - // Numbers and ORDs get appended directly onto rpn. Pass -1 to suppress an rpn pop. - popRpnTokens(-1); - rpn += token.ttype === tt.NUM ? rationalRPN(token.input) : token.input; - } - if (isPrecededBySpace) { posOfPrevRun = tex.length; } - if (isCalc && - (prevToken.ttype === tt.MULT || (followedByFactor && prevToken.ttype !== tt.DIV))) { - token.output = "(" + token.output + ")"; - } - tex += token.output + " "; - okToAppend = true; - - if (!isFollowedBySpace && followedByFactor) { - // We've encountered something like the expression "2a". - popTexTokens(2, okToAppend); - if (isCalc) { - rpnPrec = rpnPrecFromType[tt.MULT]; - rpn += tokenSep; - popRpnTokens(rpnPrec); - rpnStack.push({ prec: rpnPrec, symbol: "⌧" }); - } - } - break - - case tt.STRING: { - popTexTokens(2, okToAppend); - const ch = token.input.charAt(0); - if (isCalc) { rpn += ch + token.output + ch; } // Keep before addTextEscapes() - if (isPrecededBySpace) { posOfPrevRun = tex.length; } - token.output = addTextEscapes(token.output); - token.output = token.output.replace(/ +$/, "\\,"); // Prevent loss of trailing space - tex += "\\text{" + token.output + "}"; - okToAppend = true; - break - } - - case tt.RICHTEXT: { - popTexTokens(2, okToAppend); - const ch = token.input.charAt(0); - if (isCalc) { rpn += ch + token.output + ch; } - if (isPrecededBySpace) { posOfPrevRun = tex.length; } - token.output = token.output === "`" ? "`" : parse$1(token.output, decimalFormat, false); - tex += "{" + token.output + "}"; - okToAppend = true; - break - } - - case tt.MACRO: { - popTexTokens(2, okToAppend); - if (isCalc) { rpn += '"""' + token.output + '"""'; } // Keep before addTextEscapes() - if (isPrecededBySpace) { posOfPrevRun = tex.length; } - token.output = addTextEscapes(token.output); - tex += "\\text{" + token.output + "}"; - okToAppend = true; - break - } - - case tt.DATAFRAME: - popTexTokens(2, okToAppend); - posOfPrevRun = tex.length; - tex += token.output; - if (isCalc) { - rpn += token.input; - // Identify string interpolation - const matches = arrayOfRegExMatches(interpolateRegEx, token.input); - for (const match of matches) { - dependencies.push(match.value.slice(2, -1)); - } - } - okToAppend = true; - break - - case tt.VAR: // variable name, one letter long - case tt.LONGVAR: { // multi-letter variable name - if (token.ttype === tt.LONGVAR && prevToken.input === "⌧") { - tex += "\\,"; // Place a space before a long variable name. - } - // variables get appended directly onto rpn. - popTexTokens(7, okToAppend); - if (isPrecededBySpace) { posOfPrevRun = tex.length; } - - if (!isCalc) { - if (token.ttype === tt.LONGVAR) { - if (!accentRegEx.test(token.input)) { - token.output = "\\mathrm{" + token.output + "}"; - } - } - } else if (prevToken.input === "for") { - rpn += '"' + token.input + '"'; // a loop index variable name. - } else { - // We're in the echo of a Hurmet calculation. - if (/^(\.[^.]|\[)/.test(str) || token.input === "im") { - // When the blue echo has an index in a bracket, e.g., varName[index], it renders - // the name of the variable, not the value. The value of the value of the index. - token.output = token.ttype === tt.LONGVAR - ? "\\mathrm{" + token.output + "}" - : token.output; - } else { - token.output = token.input; - token.output = (posArrow > 0 ? "" : "〖") + token.output; - } - rpn += token.input === "im" ? "im" : "¿" + token.input; - if (token.input !== "im") { dependencies.push(token.input); } - } - - tex += token.output + (str.charAt(0) === "." ? "" : " "); - if (isCalc) { - // The variable's value may be tall. We don't know. - delims[delims.length - 1].isTall = true; - } - okToAppend = true; - break - } - - case tt.UNIT: { // e.g. 'meters' - if (delims.length > 1 && delims[delims.length - 1].delimType === dMATRIX) { - token.output = "\\text{Error. Write a unit name outside a matrix, not inside. " - + "Apply one unit to the entire matrix.}"; - } - popTexTokens(14, true); - texStack.push({ prec: 14, pos: op.pos, ttype: tt.UNIT, closeDelim: "" }); - if (isCalc) { - popRpnTokens(rpnPrecFromType[tt.UNIT]); - rpn += tokenSep + "applyUnit" + tokenSep + token.input.replace(/'/g, ""); - } - if (!/^'?°'?$/.test(token.input)) { tex += "\\;"; } - tex += token.output; - okToAppend = true; - break - } - - case tt.PROPERTY: { - // A word after a dot ACCESSOR operator. I.e., A property in dot notation - // Treat somewhat similarly to tt.STRING - popTexTokens(15, okToAppend); - const pos = token.input.indexOf("_"); - if (isCalc) { - rpn += '"' + token.output + '"'; - tex += `\\mathrm{${token.output}}`; - if (str.charAt(0) !== ".") { tex += " "; } - } else if (pos > -1) { - tex += token.input.substring(0, pos) + "_\\mathrm{" + - token.input.substring(pos + 1) + "}"; - } else { - token.output = addTextEscapes(token.output); - token.output = token.output.replace(/ +$/, "\\,"); // Prevent loss of trailing space - tex += "\\text{" + token.output + "}"; - } - okToAppend = true; - break - } - - case tt.TO: { - // A probability distribution defined by its low and high values. - // As in: (2 to 3) or [2 to 3] or {2 to 3} - delims[delims.length - 1].delimType = dDISTRIB; - popTexTokens(1, okToAppend); - posOfPrevRun = tex.length; - tex += token.output; - if (isCalc) { - rpn += tokenSep; - popRpnTokens(3); - const symbol = delims[delims.length - 1].symbol; - const distribution = symbol === "(" - ? "normal" - : symbol === "[" - ? "uniform" - : "lognormal"; - rpnStack.push({ prec: 3, symbol: distribution }); - } - break - } - - case tt.RANGE: { - // range separator, as in 1:n - popTexTokens(1, okToAppend); - posOfPrevRun = tex.length; - if (isCalc && token.input !== "...") { - rpn += tokenSep; - popRpnTokens(3); - rpnStack.push({ prec: 3, symbol: ":" }); - if (["[", ","].includes(prevToken.input) && /^[,\]]/.test(str)) { - // A bare colon in a accessor, e.g., M[:, 2] - rpn += `®1/1${tokenSep}"∞"`; - } else if (/^end[,\]]/.test(str)) { - rpn += '"∞"'; // slice of the form: identifier[n:end] - str = str.slice(3); - } - } - const topDelim = delims[delims.length - 1]; - tex += topDelim.delimType === dPAREN && topDelim.symbol === "{" - ? "\\colon" - : token.output; - break - } - - case tt.DIV: { // / or \atop - if (isCalc) { rpn += tokenSep; } - popTexTokens(2, true); - rpnPrec = rpnPrecFromType[tt.DIV]; - popRpnTokens(rpnPrec); - if (token.input === "//") { - // case fraction - texStack.push({ prec: 2, pos: op.pos, ttype: tt.DIV, closeDelim: "}" }); - tex = tex.substring(0, op.pos) + "\\tfrac{" + tex.substring(op.pos) + "}{"; - } else if (token.input === "/" || token.input === "\\over") { - // displaystyle fraction - texStack.push({ prec: 2, pos: op.pos, ttype: tt.DIV, closeDelim: "}" }); - tex = tex.substring(0, op.pos) + "\\dfrac{" + tex.substring(op.pos) + "}{"; - } else { - // atop, for binomials - texStack.push({ prec: 2, pos: op.pos, ttype: tt.DIV, closeDelim: "}}" }); - tex = tex.substring(0, op.pos) + "{{" + tex.substring(op.pos) + "}\\atop{"; - if (delims[delims.length - 1].name === "(") { - delims[delims.length - 1].delimType = dBINOMIAL; - } - } - if (isCalc) { - if (token.input === "\\atop") { - if (delims[delims.length - 1].delimType === dBINOMIAL) { - rpnStack.push({ prec: rpnPrec, symbol: "()" }); - } - } else { - rpnStack.push({ prec: rpnPrec, symbol: token.input }); - } - } - delims[delims.length - 1].isTall = true; - posOfPrevRun = tex.length; - okToAppend = false; - break - } - - case tt.SUB: { // _ - popTexTokens(15, true); - const subCD = prevToken.ttype === tt.FUNCTION ? "}{" : "}"; - texStack.push({ prec: 15, pos: op.pos, ttype: tt.SUB, closeDelim: subCD }); - tex += "_{"; - if (isCalc) { rpn += "_"; } - okToAppend = false; - break - } - - case tt.SUP: // ^ - if (isCalc) { - if (/¿e$/.test(rpn)) { - // e^3. Replace e with 2.7182818284590452353602874713527 - // eslint-disable-next-line max-len - rpn = rpn.slice(0, -2) + "®27182818284590452353602874713527/10000000000000000000000000000000"; - } - rpn += tokenSep; - popRpnTokens(rpnPrecFromType[tt.SUP]); - } - popTexTokens(13, true); - if (prevToken.ttype === tt.RIGHTBRACKET) { - texStack.push({ prec: 13, pos: op.pos, ttype: tt.SUP, closeDelim: "}" }); - } else { - texStack.push({ prec: 13, pos: posOfPrevRun, ttype: tt.SUP, closeDelim: "}" }); - } - if (isCalc) { rpnStack.push({ prec: rpnPrecFromType[tt.SUP], symbol: "^" }); } - if (delims.length > 0 && str.charAt(0) === "(") { - delims[delims.length - 1].isTall = true; - } - tex += "^{"; - okToAppend = false; - break - - case tt.SUPCHAR: { // ²³¹⁰⁴⁵⁶⁷⁸⁹⁻ - if (isCalc) { - if (/¿e$/.test(rpn)) { - // e^3. Replace e with 2.7182818284590452353602874713527 - // eslint-disable-next-line max-len - rpn = rpn.slice(0, -2) + "®27182818284590452353602874713527/10000000000000000000000000000000"; - } - rpn += tokenSep; - popRpnTokens(rpnPrecFromType[tt.SUPCHAR]); - } - popTexTokens(13, true); - const supNum = numFromSupChars(token.output); - if (prevToken.ttype === tt.RIGHTBRACKET) { - texStack.push({ prec: 13, pos: op.pos, ttype: tt.SUP, closeDelim: "}" }); - } else { - texStack.push({ prec: 13, pos: posOfPrevRun, ttype: tt.SUP, closeDelim: "}" }); - } - tex += "^{" + supNum; - if (isCalc) { - rpnStack.push({ prec: rpnPrecFromType[tt.SUPCHAR], symbol: "^" }); - rpn += rationalRPN(supNum); - } - okToAppend = true; - break - } - - case tt.FUNCTION: { // e.g. sin or tan, shows parens - popTexTokens(2, okToAppend); - posOfPrevRun = tex.length; - // Is there an exponent on the function name? - if (functionExpoRegEx.test(str)) { - const [expoInput, expoTex, expoRPN] = exponentOfFunction(str, decimalFormat, isCalc); - if (isCalc && expoRPN === `®-1/1` && trigFunctions.has(token.input)) { - // Inverse trig function. - token.input = "a" + token.input; - token.output = "\\a" + token.output.slice(1); - } else { - if (isCalc) { token.input += tokenSep + expoRPN + tokenSep + "^"; } - token.output += "^" + expoTex; - } - const L = expoInput.length + (str.charAt(0) === "^" ? 1 : 0); - str = str.slice(L).trim(); - } - if (isCalc) { - rpnStack.push({ prec: rpnPrecFromType[tt.FUNCTION], symbol: token.input }); - if (prevToken.input === "⌧") { tex += "×"; } - } - fc = str.charAt(0); - texStack.push({ - prec: 12, - pos: tex.length, - ttype: tt.FUNCTION, - closeDelim: fc === "(" ? "" : "}" - }); - tex += token.output; - tex += fc === "(" ? "" : "{"; - pendingFunctionName = token.input; - okToAppend = false; - break - } - - case tt.ACCENT: - if (isCalc) { - rpn += tokenSep; - popRpnTokens(rpnPrecFromType[tt.ACCENT]); - } - popTexTokens(1, okToAppend); - - if (isCalc) { - texStack.push({ prec: 16, pos: tex.length, ttype: tt.ACCENT, closeDelim: "〗" }); - tex += (posArrow > 0 ? "" : "〖") + token.input; - rpn += "¿" + token.input; - dependencies.push(token.input); - } else { - texStack.push({ prec: 16, pos: tex.length, ttype: tt.ACCENT, closeDelim: "}" }); - tex += token.output + "{"; - } - - delims[delims.length - 1].isTall = true; - okToAppend = false; - break - - case tt.PRIME: - popTexTokens(15, true); - if (isCalc) { - rpn += token.input; - dependencies.push(prevToken.input + token.input); - } - tex = tex.trim() + token.output + " "; - okToAppend = true; - break - - case tt.BINARY: { // e.g. root(3)(x) - popTexTokens(1, okToAppend); - posOfPrevRun = tex.length; - const binCD = token.input === "root" ? "]{" : "}{"; - texStack.push({ prec: 12, pos: tex.length, ttype: tt.BINARY, closeDelim: binCD }); - if (isCalc) { - rpnStack.push({ prec: rpnPrecFromType[tt.BINARY], symbol: token.output }); - } - tex += token.output + (token.input === "root" ? "[" : "{"); - delims[delims.length - 1].isTall = true; - okToAppend = false; - break - } - - case tt.CURRENCY: { // e.g. $, £, etc - popTexTokens(1, okToAppend); - posOfPrevRun = tex.length; - texStack.push({ prec: 12, pos: tex.length, ttype: tt.CURRENCY, closeDelim: "" }); - if (isCalc) { - rpnStack.push({ - prec: rpnPrecFromType[tt.CURRENCY], - symbol: "applyUnit" + tokenSep + token.input - }); - if (prevToken.input === "⌧") { tex += "×"; } - } - tex += token.output; - okToAppend = false; - break - } - - case tt.UNARY: // e.g. bb, hat, or sqrt, or xrightarrow, hides parens - popTexTokens(1, okToAppend); - posOfPrevRun = tex.length; - texStack.push({ prec: 12, pos: tex.length, ttype: tt.UNARY, closeDelim: "}" }); - if (isCalc) { - rpnStack.push({ prec: rpnPrecFromType[tt.UNARY], symbol: token.input }); - if (prevToken.input === "⌧") { tex += "×"; } - } - tex += token.output; - - if (/det|inf/.test(token.input) && str.charAt(0) === "_") { - texStack.push({ prec: 15, pos: tex.length, ttype: tt.SUB, closeDelim: "}" }); - token = { input: "_", output: "_", ttype: tt.SUB }; - tex += "_{"; - str = str.substring(1); - str = str.replace(/^\s+/, ""); - } else if (token.input === "\\color") { - const colorMatch = colorSpecRegEx.exec(str); - if (colorMatch) { - tex += "{" + colorMatch[0].replace(/[()]/g, "") + "}"; - texStack.pop(); - str = str.slice(colorMatch[0].length).trim(); - } else { - // User is in the middle of writing a color spec. Avoid an error message. - tex += "{"; - } - } else { - tex += "{"; - } - delims[delims.length - 1].isTall = true; - okToAppend = false; - break - - case tt.FACTORIAL: - popTexTokens(14, true); - texStack.push({ prec: 14, pos: op.pos, ttype: tt.FACTORIAL, closeDelim: "" }); - if (isCalc) { - popRpnTokens(rpnPrecFromType[tt.FACTORIAL]); - rpn += tokenSep + token.output; - } - tex += token.output; - okToAppend = true; - break - - case tt.RETURN: - // Special treatment in order to enable user-defined functions. - popTexTokens(1, okToAppend); - posOfPrevRun = tex.length; - if (isCalc) { - popRpnTokens(4); - rpnStack.push({ prec: 4, symbol: "return" }); - } - tex += token.output + " "; - break - - case tt.KEYWORD: - // Either "for", "while", or "break" - popTexTokens(1, true); - posOfPrevRun = tex.length; - if (isCalc) { popRpnTokens(2); } - tex += token.output + " "; - break - - case tt.LOGIC: { - // logic words: if and or otherwise - popTexTokens(1, okToAppend); - if (isCalc) { rpn += tokenSep; } - popRpnTokens(4); - const topDelim = delims[delims.length - 1]; - if (token.input === "if" || token.input === "otherwise") { - if (topDelim.delimType === dPAREN && topDelim.name === "{") { - // Change the enclosing delim pair to a CASES expression. - topDelim.delimType = dCASES; - topDelim.close = "\\end{cases}"; - topDelim.open = "\\begin{cases}"; - // In order to get lazy evaluation of a CASES, we will have to move the - // expressions after the conditions. Temporarily change the token separator. - if (isCalc && tokenSep === "\xa0" && token.input === "if") { - // Change the token separators in the preceding RPN. - rpn = rpn.slice(0, topDelim.rpnPos) + - rpn.slice(topDelim.rpnPos).replace(/\xa0/g, "§"); - } - } - } - if (topDelim.delimType === dCASES && ["if", "otherwise"].includes(token.input)) { - tex += "&"; - } - tex += token.output; - if (isCalc) { - if (topDelim.delimType === dCASES && - (token.input === "if" || token.input === "otherwise")) { - // We're in an If Expression and we just reached the end of an expression. - rpn = setUpIf(rpn, token.input, exprStack, topDelim); - tokenSep = "\xa0"; - } else { - rpnStack.push({ prec: 4, symbol: token.input }); - } - } - posOfPrevRun = tex.length; - okToAppend = true; - break - } - - case tt.LEFTBRACKET: { - popTexTokens(2, okToAppend); - const isPrecededByDiv = prevToken.ttype === tt.DIV; - let isFuncParen = false; - - const texStackItem = { - prec: 0, - pos: tex.length, - ttype: tt.LEFTBRACKET, - closeDelim: token.closeDelim - }; - - if ((token.input === "(" || token.input === "[") && prevToken.ttype < 5) { - // The delimiters are here to delimit a TeX function extent. - // Make the delimiters invisible. - texStackItem.closeDelim = ""; - } else if (token.input === "(" && op.ttype === tt.BINARY) { - texStackItem.closeDelim = ""; - } else { - texStackItem.closeDelim = token.closeDelim; - isFuncParen = (token.input === "(" || token.input === "[") && - prevToken.ttype === tt.FUNCTION; - tex += token.output; - } - texStack.push(texStackItem); - - if (isCalc) { - while (rpnStack.length > 0 && rpnStack[rpnStack.length - 1].symbol === ".") { - rpn += tokenSep + rpnStack.pop().symbol; - } - rpnStack.push({ prec: 0, symbol: token.output.trim() }); - } - - const numArgs = /^\s*[)}\]]/.test(str) ? 0 : 1; - - const delim = { - name: token.input, - isTall: false, - open: token.output, - close: texStackItem.closeDelim, - numArgs, - numRows: numArgs, - rpnPos: rpn.length, - isPrecededByDiv, - isFuncParen, - isControlWordParen: prevToken.ttype < 5 - }; - - if (isFuncParen) { - delim.delimType = dFUNCTION; - delim.name = pendingFunctionName; - } else if (prevToken.ttype === tt.SUB) { - delim.delimType = dSUBSCRIPT; - delim.name = "("; - } else if (token.input === "{") { - // This may change to a CASES. - delim.delimType = dPAREN; - delim.rpnLength = rpn.length; - } else if (token.input === "[" && - ([tt.VAR, tt.LONGVAR, tt.STRING, tt.PROPERTY].includes(prevToken.ttype) || - prevToken.input === "]" || (prevToken.input === ")" && !isPrecededBySpace))) { - rpn += tokenSep; - delim.delimType = dACCESSOR; - } else { - // This may change to a MATRIX, but for now we'll say it's a paren. - delim.delimType = dPAREN; - delim.name = token.input; - } - delims.push(delim); - - pendingFunctionName = ""; - posOfPrevRun = tex.length; - okToAppend = false; - break - } - - case tt.SEP: { - // Either a comma or a tab or a semi-colon. Colons are handled elsewhere. - popTexTokens(1, okToAppend); - posOfPrevRun = tex.length; - const delim = delims[delims.length - 1]; - if ((delim.delimType === dPAREN || delim.delimType === dACCESSOR) - && ([";", "\t"].includes(token.input) - || token.input === "," && isFollowedBySpaceOrNewline)) { - delim.delimType = delim.delimType === dPAREN ? dMATRIX : dACCESSOR; - const ch = delim.name === "[" - ? "b" - : delim.name === "(" - ? "p" - : delim.name === "{:" - ? "" - : "B"; - delim.open = `\\begin{${ch}matrix}`; - delim.close = `\\end{${ch}matrix}`; - delim.isTall = true; - } - if (isCalc) { - if (prevToken.ttype === tt.LEFTBRACKET && delim.delimType === dACCESSOR) { - rpn += "®0/1"; - } - rpn += tokenSep; - popRpnTokens(1); - } - if (delim.delimType === dMATRIX && token.input === ",") { - token.output = " & "; - } - - tex += token.output + " "; - - if (isCalc) { - if (delims.length === 1) { - if (token.input === ",") { - numFreeCommas += 1; // item in a tuple - } - } else { - if (token.input === ";") { - delim.numRows += 1; - if (delims.length > 0 && delim.delimType === dCASES) { - // We're about to begin an expression inside an If Expression. - // Temporarily change the token separator. - tokenSep = "§"; - } - } - - if (delim.numRows === 1) { - if ([",", "\t"].includes(token.input) && (str.charAt(0) === "]")) { - rpn += "®0/1"; - } - if (token.input === "," && delim.delimType === dFUNCTION) { - if (delim.numArgs === 2 && delim.name === "plot" ) { - // The literal function for a plot() statement inside a draw() - // Wrap the rpn in quotation marks. - rpn = rpn.slice(0, delim.rpnPos + 5) + '"' - + rpn.slice(delim.rpnPos + 5, -1).replace(/\u00a0/g, "§") + '"' + tokenSep; - } - } - } - delim.numArgs += 1; - } - } - - okToAppend = true; - break - } - - case tt.RIGHTBRACKET: { - popTexTokens(0, true, token.output); - const topDelim = delims.pop(); - - if (topDelim.delimType === dPAREN && (!topDelim.isControlWordParen) - && topDelim.close !== token.output) { - // Enable unmatched delims, such as (1.2] or |ϕ⟩ - tex = tex.slice(0, -1 * topDelim.close.length) + token.output; - } - - if (topDelim.isTall && delims.length > 1) { - // If the inner parens are tall, then the outer parens must also be tall. - delims[delims.length - 1].isTall = true; - } - - if (isCalc) { - while (rpnStack.length > 0 && rpnStack[rpnStack.length - 1].prec > 0) { - rpn += tokenSep + rpnStack.pop().symbol; - } - if (topDelim.delimType === dCASES && prevToken.input !== "otherwise") { - // "otherwise" is optional. We've just found a case where it is omitted. - // So run function setUpIf as if "otherwise" were present. - rpn = setUpIf(rpn, "otherwise", exprStack, topDelim); - tokenSep = "\xa0"; - } - const rpnOp = rpnStack.pop(); - const numArgs = topDelim.numArgs; - const numRows = topDelim.numRows; - const numCols = topDelim.numArgs / topDelim.numRows; - - const firstSep = numArgs === 0 ? "" : tokenSep; - - switch (topDelim.delimType) { - case dFUNCTION: { - let symbol = rpnStack.pop().symbol; - const regEx = new RegExp(tokenSep + '!$'); - if (numArgs === 2) { - if (symbol === "log") { symbol = "logn"; } - if (symbol === "round") { symbol = "roundn"; } - if (symbol === "atan") { symbol = "atan2"; } - if (symbol === "plot") { - rpn = rpn.slice(0, 6) + '"' + rpn.slice(6).replace(/\u00a0/g, "§") + '"'; - } - } else if (symbol === "log" && regEx.test(rpn)) { - rpn = rpn.slice(0, rpn.length - 1) + "lfact"; - break - } - rpn += (symbol.slice(-1) === "^") - ? firstSep + symbol - : builtInFunctions.has(symbol) - ? firstSep + symbol - : builtInReducerFunctions.has(symbol) - ? firstSep + symbol + tokenSep + numArgs - : firstSep + "function" + tokenSep + symbol + tokenSep + numArgs; - break - } - - case dACCESSOR: - // This is the end of a […] following a variable name. - rpn += firstSep + "[]" + tokenSep + numArgs; - break - - case dMATRIX: - rpn += firstSep + "matrix" + tokenSep + numRows + tokenSep + numCols; - break - - case dCASES: - tokenSep = "\xa0"; - rpn += tokenSep + "cases" + tokenSep + numRows + tokenSep; - while (exprStack.length > 0) { - // Append the expressions that correspond to each condition. - rpn += exprStack.shift(); - } - rpn = rpn.slice(0, -1); - break - - case dVECTORFROMRANGE: - // [start:step:end] - rpn += tokenSep + "matrix" + tokenSep + "1" + tokenSep + "1"; - break - - case dDISTRIB: - // (bottom to top) - // Do nothing. This is handled by tt.TO above. - break - - default: - if (numArgs === 0 && topDelim.open === "[") { - // Treat as an empty matrix - rpn += "matrix" + tokenSep + 0 + tokenSep + 0; - } else if (numArgs === 1 && topDelim.open === "[") { - rpn += tokenSep + "matrix" + tokenSep + 1 + tokenSep + 1; - } - if (rpnOp.symbol === "\\lfloor") { rpn += tokenSep + "⎿⏌"; } - if (rpnOp.symbol === "\\lceil") { rpn += tokenSep + "⎾⏋"; } - } - if ((token.input === ")" && - // eslint-disable-next-line max-len - !(topDelim.delimType === dFUNCTION && str.charAt(0) === "[" && !isFollowedBySpace) && - nextCharIsFactor(str, tt.RIGHTBRACKET)) || - (token.input === "]" && /^\(/.test(str) || - topDelim.delimType === dMATRIX && /^\[/.test(str))) { - // Implicit multiplication between parens, as in (2)(3) - rpn += tokenSep; - popRpnTokens(rpnPrecFromType[tt.MULT]); - rpnStack.push({ prec: rpnPrecFromType[tt.MULT], symbol: "⌧" }); - isFollowedBySpace = false; - token = { input: "⌧", output: "⌧", ttype: tt.MULT }; - } - } - - posOfPrevRun = tex.length; - okToAppend = op.ttype !== tt.BINARY; - break - } - - case tt.LEFTRIGHT: { - // A "|" or "‖" character, which are used as |x|, ‖M‖, P(A|B), {x|x ∈ℝ}, |ϕ⟩ - popTexTokens(1, okToAppend); - const topDelim = delims[delims.length - 1]; - - let isRightDelim = false; - if (texStack.length > 0) { - isRightDelim = - texStack[texStack.length - 1].ttype === tt.LEFTRIGHT || - texStack[texStack.length - 1].closeDelim === "\u27E9" || // Dirac ket - texStack[texStack.length - 1].closeDelim === "\\right." || - texStack[texStack.length - 1].closeDelim === "\\end{vmatrix}"; - } - if (isRightDelim) { - // Treat as a right delimiter - topDelim.close = token.input === "|" ? "|" : "‖"; - texStack[texStack.length - 1].closeDelim = topDelim.close; - popTexTokens(0, okToAppend); - delims.pop(); - if (isCalc) { - while (rpnStack.length > 0 && rpnStack[rpnStack.length - 1].prec > 0) { - rpn += tokenSep + rpnStack.pop().symbol; - } - rpn += tokenSep + rpnStack.pop().symbol; - } - okToAppend = op.ttype !== tt.BINARY; - } else if (topDelim.delimType === dPAREN && topDelim.name === "{") { - tex += "\\mid "; - posOfPrevRun = tex.length; - okToAppend = true; - } else { - // Treat as a left delimiter - texStack.push({ - prec: 0, - pos: tex.length, - ttype: tt.LEFTRIGHT, - closeDelim: token.input === "|" ? "|" : "‖" - }); - - delims.push({ - delimType: dPAREN, - name: token.input, - isTall: false, - open: token.input === "|" ? "|" : "‖", - close: token.input === "|" ? "|" : "‖", - numArgs: 1, - numRows: 1, - rpnPos: rpn.length, - isPrecededByDiv: prevToken.ttype === tt.DIV - }); - - if (isCalc) { - rpnStack.push({ prec: 0, symbol: token.output }); - } - - tex += token.input === "|" ? "|" : "‖"; - posOfPrevRun = tex.length; - okToAppend = false; - } - break - } - - case tt.COMMENT: - popTexTokens(0, true); - tex += token.output + " "; - break - - default: - if (isCalc) { - rpn += tokenSep; - popRpnTokens(rpnPrecFromType[tt.ORD]); - } - popTexTokens(1, okToAppend); - texStack.push({ prec: 1, pos: tex.length, ttype: tt.ORD, closeDelim: "" }); - if (isCalc) { rpnStack.push({ prec: rpnPrecFromType[tt.ORD], symbol: token.output }); } - tex += token.output + " "; - posOfPrevRun = tex.length; - okToAppend = true; - } - - prevToken = cloneToken(token); - isPrecededBySpace = isFollowedBySpace || token.input === "⌧"; - } - - popTexTokens(0, true); // Pop all the remaining close delimiters off the stack. - - let indexVariable = ""; - if (isCalc) { - while (rpnStack.length > 0) { - rpn += tokenSep + rpnStack.pop().symbol; - } - let sum = sumRegEx.exec(rpn); - while (sum) { - // We've matched a ∑_(i=0)^n … term. Edit the index variable and the local RPN. - indexVariable = sum[1]; - rpn = rpn.slice(0, sum.index) + '"' + sum[1] + '"' + sum[2] + sum[3] + tokenSep - + '"' + sum[4].replace(/\u00a0/g, "§") + '"\xa0∑' + rpn.slice(sum.index + sum[0].length); - sum = sumRegEx.exec(rpn); - } - if (numFreeCommas > 0) { - rpn += tokenSep + "tuple" + tokenSep + String(numFreeCommas + 1); - } - const varRegEx = /〖[^ ().\\,;]+/g; - let arr; - while ((arr = varRegEx.exec(tex)) !== null) { - if ("¨ˆˉ˙˜".indexOf(arr[0][1]) === -1) { - const pos = arr.index + arr[0].length; - if (tex.length > pos && tex.charAt(pos) === "(") { - // We found a method, not a data index. Delete the 〖 - tex = tex.slice(0, arr.index) + tex.slice(arr.index + 1); - } else { - tex = tex.substring(0, pos) + "〗" + tex.substring(pos); - } - } - } - } - - tex = tex.replace(/ {2,}/g, " "); // Replace multiple spaces with single space. - tex = tex.replace(/\s+(?=[_^'!)}\]〗])/g, ""); // Delete spaces before right delims - tex = tex.replace(/\s+$/, ""); // Delete trailing space - if (indexVariable.length > 0) { - tex = tex.replace(new RegExp(`〖${indexVariable}〗`, "g"), indexVariable); - } - - if (mustAlign) { - const pos = tex.indexOf("="); - tex = "\\begin{aligned}" + tex.slice(0, pos) + "&" + tex.slice(pos) + "\\end{aligned}"; - } - - return isCalc ? [tex, rpn, dependencies] : tex -}; - -function insertOneHurmetVar(hurmetVars, attrs, changedVars, decimalFormat) { - // hurmetVars is a key:value store of variable names and attributes. - // This function is called to insert an assignment into hurmetVars. - const formatSpec = hurmetVars.format ? hurmetVars.format.value : "h15"; - - if (!Array.isArray(attrs.name)) { - // This is the typical case. - hurmetVars[attrs.name] = attrs; - if (changedVars) { - changedVars.add(attrs.name); - } - - } else if (attrs.value === null) { - for (let i = 0; i < attrs.name.length; i++) { - hurmetVars[attrs.name[i]] = { value: null }; - } - - } else if (isMatrix(attrs)) { - // Assign to a matrix of names - const isQuantity = Boolean(attrs.dtype & dt.QUANTITY); - let resultDisplay = attrs.resultdisplay; - resultDisplay = resultDisplay.replace(/\\(begin|end){[bp]matrix}/g, "").trim(); - const displays = resultDisplay.split(/&|\\\\/); - if (attrs.dtype & dt.MATRIX) { - // A 2 dimensional matrix. - const dtype = attrs.dtype - dt.MATRIX; - const numRows = isQuantity ? attrs.value.plain.length : attrs.value.length; - const numCols = attrs.name.length / numRows; - let iName = 0; - for (let i = 0; i < numRows; i++) { - for (let j = 0; j < numCols; j++) { - const value = isQuantity - ? { plain: attrs.value.plain[i][j], inBaseUnits: attrs.value.inBaseUnits[i][j] } - : attrs.value[i][j]; - hurmetVars[attrs.name[i]] = { - name: attrs.name[iName], - value, - resultdisplay: isQuantity - ? parse$1(displays[iName].trim() + " '" + attrs.unit + "'") - : displays[iName].trim(), - expos: attrs.expos, - unit: isQuantity ? attrs.unit : undefined, - dtype - }; - if (changedVars) { changedVars.add(attrs.name[i]); } - iName += 1; - } - } - } else { - // Assign to a vector of names. - const isColumn = Boolean(attrs.dtype & dt.COLUMNVECTOR); - const dtype = attrs.dtype - (isColumn ? dt.COLUMNVECTOR : dt.ROWVECTOR); - for (let i = 0; i < attrs.name.length; i++) { - const value = isQuantity - ? { plain: attrs.value.plain[i], inBaseUnits: attrs.value.inBaseUnits[i] } - : attrs.value[i]; - hurmetVars[attrs.name[i]] = { - name: attrs.name[i], - value, - resultdisplay: isQuantity - ? parse$1(displays[i].trim() + " '" + attrs.unit + "'") - : displays[i].trim(), - expos: attrs.expos, - unit: isQuantity ? attrs.unit : undefined, - dtype - }; - if (changedVars) { changedVars.add(attrs.name[i]); } - } - } - - // From this point forward, we're dealing with multiple assignment - } else if (attrs.dtype & dt.MAP) { - const unit = attrs.unit; - const unitName = unit && unit.name ? unit.name : undefined; - const dtype = attrs.dtype - dt.MAP; - let i = 0; - if (attrs.dtype & dt.QUANTITY) { - for (const value of attrs.value.data.plain) { - const result = { - value: { plain: value }, - expos: attrs.expos, - factor: attrs.factor, - dtype - }; - result.resultdisplay = format(value, formatSpec, decimalFormat); - if (unitName) { result.resultdisplay += " " + unitTeXFromString(unitName); } - hurmetVars[attrs.name[i]] = result; - if (changedVars) { changedVars.add(attrs.name[i]); } - i += 1; - } - i = 0; - for (const value of attrs.value.data.inBaseUnits) { - hurmetVars[attrs.name[i]].value.inBaseUnits = value; - i += 1; - } - } else { - for (const value of attrs.value.data) { - const result = { value, expos: attrs.expos, factor: attrs.factor, dtype }; - result.resultdisplay = Rnl.isRational(value) - ? format(value, formatSpec, decimalFormat) - : String(value); - if (unitName) { result.resultdisplay += " " + unitTeXFromString(unitName); } - hurmetVars[attrs.name[i]] = result; - if (changedVars) { changedVars.add(attrs.name[i]); } - i += 1; - } - } - } else if (attrs.dtype === dt.DATAFRAME) { - const isSingleRow = attrs.value.data[0].length === 1; - for (let i = 0; i < attrs.name.length; i++) { - let dtype = attrs.value.dtype[i]; - let value = isSingleRow ? undefined : []; - for (let j = 0; j < attrs.value.data[0].length; j++) { - const datum = attrs.value.data[i][j]; - const val = (dtype & dt.RATIONAL) ? Rnl.fromString(datum) : datum; - if (isSingleRow) { - value = val; - } else { - value.push(val); - } - } - if (!isSingleRow) { dtype += dt.COLUMNVECTOR; } - const result = { - value, - unit: attrs.unit[attrs.value.units[i]], - dtype - }; - if ((dtype & dt.RATIONAL) && isSingleRow) { - result.resultdisplay = parse$1(format(value)); - if (result.unit && result.unit.name) { - result.resultdisplay += " " + parse$1(`'${result.unit.name}'`); - } - } else if (dtype & dt.RATIONAL) { - result.resultdisplay = Matrix.display({ value, dtype }, formatSpec, decimalFormat) - + parse$1(`'${attrs.value.units[i]}'`); - } else { - result.resultdisplay = parse$1(value); - } - if (attrs.value.units[i]) { - result.value = { plain: result.value }; - const unit = attrs.unit[attrs.value.units[i]]; - result.value.inBaseUnits = isSingleRow - ? Rnl.multiply(Rnl.add(result.value.plain, unit.gauge), unit.factor) - : result.value.plain.map(e => Rnl.multiply(Rnl.add(e, unit.gauge), unit.factor)); - result.expos = unit.expos; - } - - hurmetVars[attrs.name[i]] = result; - if (changedVars) { changedVars.add(attrs.name[i]); } - } - } else if (attrs.dtype === dt.TUPLE) { - let i = 0; - for (const value of attrs.value.values()) { - hurmetVars[attrs.name[i]] = value; - if (changedVars) { changedVars.add(attrs.name[i]); } - i += 1; - } - } else if (attrs.dtype === dt.MODULE) { - if (attrs.name.length !== attrs.value.length) { - return errorOprnd("MULT_MIS") - } else { - let i = 0; - for (const value of attrs.value.values()) { - const result = clone(value); - hurmetVars[attrs.name[i]] = result; - if (changedVars) { changedVars.add(attrs.name[i]); } - i += 1; - } - } - } else ; -} - -/* - * This file deals with Hurmet maps, which are similar to hash maps. - * In a map, every value is of the same data type and has the same unit-of-measure. - */ - -const checkUnitEquality = (u1, u2) => { - let x; - let y; - if (u1.expos && u2.expos) { - x = u1.expos; - y = u2.expos; - } else { - x = u1; - y = u2; - } - if (Array.isArray(x)) { - if (Array.isArray(y)) { - if (x.length !== y.length) { return false } - x.forEach((e, i) => { if (e !== y[i]) { return false } }); - return true - } else { - return false - } - } else { - return x === y - } -}; - -const append = (o1, o2, shape1, shape2) => { - let map; - let scalar; - if (o1.dtype & dt.MAP) { - if (shape2 !== "scalar") { return errorOprnd("BAD_APPEND", shape2) } - map = o1; - scalar = o2; - } else { - if (shape1 !== "scalar") { return errorOprnd("BAD_APPEND", shape1) } - map = o2; - scalar = o1; - } - if (!(map.dtype & scalar.dtype)) { errorOprnd("MAP_APPEND"); } - if (!checkUnitEquality(map.unit, scalar.unit)) { errorOprnd("UNIT_APEND"); } - map.value.set(scalar.name, scalar.value); - return map -}; - -const convertFromBaseUnits = (data, gauge, factor) => { - data = data.map(column => Rnl.isRational(column[0]) - ? column.map(e => Rnl.divide(e, factor)) - : column - ); - if (!Rnl.isZero(gauge)) { - data = data.map(column => Rnl.isRational(column[0]) - ? column.map(e => Rnl.subtract(e, gauge)) - : column - ); - } - return data -}; - -const convertToBaseUnits = (data, gauge, factor) => { - if (!Rnl.isZero(gauge)) { - data = data.map(column => Rnl.isRational(column[0]) - ? column.map(e => Rnl.add(e, gauge)) - : column - ); - } - data = data.map(column => Rnl.isRational(column[0]) - ? column.map(e => Rnl.multiply(e, factor)) - : column - ); - return data -}; - -const range = (map, keys) => { - let unit = clone(map.unit); - const [rowList, columnList, iStart, iEnd] = identifyRange(map, keys); - if (rowList.length === 0 && iStart === iEnd && columnList.length === 1) { - // Return one value. - const value = map.value.data[columnList[0]][iStart]; - return { value, unit, dtype: map.dtype - dt.MAP } - - } else if (columnList.length === 1) { - // Return data from one column, in a column vector or a quantity - const value = map.value.data[columnList[0]].slice(iStart, iEnd + 1); - const dtype = columnList[0] === 0 - ? dt.COLUMNVECTOR + (typeof value[0] === "string" ? dt.STRING : map.dtype - dt.MAP) - : map.dtype - dt.MAP + dt.COLUMNVECTOR; - if (columnList[0] === -1) { unit = null; } - return { value, unit, dtype } - - } else { - // Return a map. - const headings = []; - const data = []; - const columnMap = Object.create(null); - const rowMap = rowList.length === 0 ? false : Object.create(null); - for (let j = 0; j < columnList.length; j++) { - headings.push(map.value.headings[columnList[j]]); - columnMap[map.value.headings[j]] = j; - if (rowList.length > 0) { - const elements = []; - for (let i = 0; i < rowList.length; i++) { - const rowName = rowList[i]; - elements.push(map.value.data[columnList[j]][map.value.rowMap[rowName]]); - rowMap[rowName] = i; - } - data.push(elements); - } else { - data.push(map.value.data[columnList[j]].slice(iStart, iEnd + 1)); - } - } - return { - value: { data, headings, columnMap, rowMap }, - unit, - dtype: map.dtype - } - } -}; - -const map = Object.freeze({ - append, - convertFromBaseUnits, - convertToBaseUnits, - range -}); - -function propertyFromDotAccessor(parent, index, unitAware) { - const property = Object.create(null); - if (parent.dtype & dt.MAP) { - return map.range(parent, [index], unitAware) - - } else if (parent.dtype & dt.DATAFRAME) { - return DataFrame.range(parent, [index], unitAware) - - } else if ((parent.dtype === dt.STRING || (parent.dtype & dt.ARRAY)) && - index.dtype === dt.RATIONAL) { - const indexVal = Rnl.toNumber(index.value); - property.value = parent.value.slice(indexVal - 1, indexVal); - property.unit = parent.unit; - property.dtype = parent.dtype; - return property - - } else if ((parent.dtype === dt.STRING || (parent.dtype & dt.ARRAY)) && - index.dtype === dt.RANGE) { - const start = index.value[0] - 1; - const step = index.value[1]; - const end = (index.value[2] === "∞") ? parent.value.length : index.value[2]; - property.unit = parent.unit; - property.dtype = parent.dtype; - if (step === 1) { - property.value = parent.value.slice(start, end); - } else { - property.value = []; - for (let j = start; j < end; j += step) { - property.value.push(parent.value[j]); - } - } - return property - - } else if (parent.dtype === dt.MODULE) { - // parent is a module and index has a value assigned to it. - return fromAssignment(parent.value[index.value], unitAware) - - } else { - return errorOprnd("NO_PROP", parent.name) - } -} - -const display = (tuple, formatSpec = "h3", decimalFormat = "1,000,000.") => { - if (tuple.size === 0) { return "" } - let str = "\\begin{array}{c}"; - - let haveUnits = false; - for (const attrs of tuple.values()) { - if (attrs.unit && attrs.unit.name) { haveUnits = true; break } - } - - // Write the unit names - if (haveUnits) { - let rowTex = ""; - for (const attrs of tuple.values()) { - if (attrs.unit && attrs.unit.name) { - rowTex += unitTeXFromString(attrs.unit.name).replace("\\;\\, ", ""); - } - rowTex += "&"; - } - str += rowTex.slice(0, -1) + " \\\\ "; - str += "\\hline "; - } - - // Write the data - let botRow = ""; - for (const attrs of tuple.values()) { - botRow += format(attrs.value, formatSpec, decimalFormat) + " & "; - } - str += botRow.slice(0, -1); - str += "\\end{array}"; - return str -}; - -const displayAlt = (tuple, formatSpec = "h3") => { - if (tuple.size === 0) { return "" } - let str = "``"; - - let haveUnits = false; - for (const attrs of tuple.values()) { - if (attrs.unit && attrs.unit.name) { haveUnits = true; break } - } - - // Write the unit names - if (haveUnits) { - let rowTex = ""; - for (const attrs of tuple.values()) { - if (attrs.unit && attrs.unit.name) { - rowTex += attrs.unit.name; - } - rowTex += "\t"; - } - str += rowTex.slice(0, -1) + "\n"; - } - - // Write the data - let botRow = ""; - for (const attrs of tuple.values()) { - botRow += format(attrs.value, formatSpec, "100000.") + "\t"; - } - str += botRow.slice(0, -1); - return str + "``" -}; - -const Tuple = Object.freeze({ - display, - displayAlt -}); - -// A result has been sent here from evaluate.js or updateCalculations.js. -// Format the result for display. - -const numMisMatchError = _ => { - const str = "Error. Mismatch in number of multiple assignment."; - return [`\\textcolor{firebrick}{\\text{${str}}}`, str] -}; -const testRegEx$1 = /^@{1,2}test /; -const compRegEx = /\u00a0([⩵≠><>≤≥∋∈∉∌⊂⊃⊄⊅]|==|in|!in|!=|=>|<=)$/; -const negatedComp = { - "⩵": ["≠", "≠"], - "==": ["≠", "≠"], - "≠": ["==", "=="], - ">": ["\\ngtr", "!>"], - "<": ["\\nless", "!<"], - "≤": ["\\nleq", "!≤"], - "≥": ["\\ngeq", "!≥"], - "∋": ["∌", "∌"], - "∈": ["∉", "∉"], - "⊂": ["⊄", "⊄"], - "⊃": ["⊅", "⊅"], - "∉": ["∈", "∈"], - "∌": ["∋", "∋"], - "⊄": ["⊂", "⊂"], - "⊅": ["⊃", "⊃"], - "in": ["∉", "∉"], - "!in": ["in", "in"], - "!=": ["==", "=="], - "=>": ["\\ngeq", "!≥"], - "<=": ["\\ngeq", "!≥"] -}; - -const formatResult = (stmt, result, formatSpec, decimalFormat, assert, isUnitAware) => { - if (!result) { return stmt } - - if (result.dtype === dt.DRAWING) { - stmt.resultdisplay = result.value; - delete stmt.resultdisplay.temp; - return stmt - } - - const numNames = !stmt.name - ? 0 - : !Array.isArray(stmt.name) - ? 1 - : stmt.name.length; - - if (stmt.resulttemplate.indexOf("?") > -1 || - stmt.resulttemplate.indexOf("!") > -1 || - stmt.resulttemplate.indexOf("@") > -1 || - stmt.resulttemplate.indexOf("%") > -1) { - stmt.value = result.value; - let resultDisplay = ""; - let altResultDisplay = ""; - if (stmt.resulttemplate.indexOf("!") > -1) { - // Suppress display of the result - resultDisplay = ""; - altResultDisplay = ""; - return stmt - - } else if (result.dtype & dt.BOOLEAN && testRegEx$1.test(stmt.entry) && - compRegEx.test(stmt.rpn)) { - if (testValue(result) === true) { - resultDisplay = parse$1(stmt.entry.replace(testRegEx$1, "")) + - ",\\text{ ok }✓"; - altResultDisplay = stmt.entry.replace(testRegEx$1, "") + ", ok ✓"; - } else { - const op = compRegEx.exec(stmt.rpn).slice(1); - const negOp = negatedComp[op]; - if (assert) { - const assertStr = assert.value.replace(/\.$/, ""); - resultDisplay = "\\colorbox{Salmon}{" + assertStr + ", but $" + - parse$1(stmt.entry.replace(testRegEx$1, "").replace(op, negOp[0])) + "$}"; - altResultDisplay = assertStr + ", but " + - stmt.entry.replace(testRegEx$1, "").replace(op, negOp[1]); - } else { - resultDisplay = parse$1(stmt.entry.replace(testRegEx$1, "").replace(op, negOp[0])) + - ",\\colorbox{Salmon}{ n.g.}"; - altResultDisplay = stmt.entry.replace(testRegEx$1, "").replace(op, negOp[1]) + - ", n.g."; - } - // eslint-disable-next-line no-console - console.log(altResultDisplay); - } - - } else if (isMatrix(result)) { - resultDisplay = Matrix.display((isUnitAware || result.value.plain) - ? { value: result.value.plain, dtype: result.dtype } - : result, - formatSpec, - decimalFormat - ); - altResultDisplay = Matrix.displayAlt((isUnitAware || result.value.plain) - ? { value: result.value.plain, dtype: result.dtype } - : result, - formatSpec, - decimalFormat - ); - - } else if (result.dtype === dt.DATAFRAME) { - if (numNames > 1 && numNames !== result.value.data.length) { - [resultDisplay, altResultDisplay] = numMisMatchError(); - } else { - const omitHeading = stmt.name && Array.isArray(stmt.name) && stmt.name.length > 1; - resultDisplay = DataFrame.display(result.value, formatSpec, - decimalFormat, omitHeading); - altResultDisplay = DataFrame.displayAlt(result.value, formatSpec, omitHeading); - } - - } else if (result.dtype & dt.MAP) { - let localValue; - if (isUnitAware || result.value.data.plain) { - localValue = clone(result.value); - localValue.data = result.value.data.plain; - } else { - localValue = result.value; - } - const omitHeading = stmt.name && Array.isArray(stmt.name) && stmt.name.length > 1; - resultDisplay = DataFrame.display(localValue, formatSpec, decimalFormat, omitHeading); - altResultDisplay = DataFrame.displayAlt(localValue, formatSpec, - decimalFormat, omitHeading); - - } else if (result.dtype === dt.TUPLE) { - if (numNames > 1 && numNames !== result.value.size) { - [resultDisplay, altResultDisplay] = numMisMatchError(); - } else { - resultDisplay = Tuple.display(result.value, formatSpec, decimalFormat); - altResultDisplay = Tuple.displayAlt(result.value, formatSpec); - } - - } else if (result.dtype & dt.STRING) { - resultDisplay = "\\text{" + addTextEscapes(result.value) + "}"; - if (result.unit) { - // This is a hack to return a color - resultDisplay = `\\textcolor{${result.unit}}{${resultDisplay}}`; - } - altResultDisplay = result.value; - - } else if (result.dtype & dt.RICHTEXT) { - resultDisplay = parse$1(result.value, decimalFormat, false); - altResultDisplay = result.value; - - } else if (result.dtype & dt.BOOLEAN) { - resultDisplay = "\\text{" + result.value + "}"; - altResultDisplay = String(result.value); - - } else if (result.dtype === dt.COMPLEX) { - const z = result.value; - [resultDisplay, altResultDisplay] = Cpx.display(z, formatSpec, decimalFormat); - - } else if (result.value.plain) { - resultDisplay = format(result.value.plain, formatSpec, decimalFormat); - if (resultDisplay.dtype && resultDisplay.dtype === dt.ERROR) { - resultDisplay = "\textcolor{firebrick}{\\text{" + resultDisplay.value + "}}"; - altResultDisplay = resultDisplay.value; - } else { - altResultDisplay = resultDisplay.replace(/{,}/g, ",").replace("\\", ""); - } - - } else if (Rnl.isRational(result.value)) { - resultDisplay = format(result.value, formatSpec, decimalFormat); - if (resultDisplay.dtype && resultDisplay.dtype === dt.ERROR) { - resultDisplay = "\\textcolor{firebrick}{\\text{" + resultDisplay.value + "}}"; - altResultDisplay = resultDisplay.value; - } else { - altResultDisplay = resultDisplay.replace(/{,}/g, ",").replace("\\", ""); - } - - } else if (result.dtype === dt.IMAGE) { - return stmt - - } else { - resultDisplay = result.value; - altResultDisplay = resultDisplay; - - } - - // Write the string to be plugged into echos of dependent nodes - stmt.resultdisplay = stmt.resulttemplate.replace(/(\? *\??|@ *@?|%%?)/, resultDisplay); - - // Write the TeX for this node - if (stmt.resulttemplate.indexOf("@") > -1) { - stmt.tex = stmt.resultdisplay; - stmt.displaySelector = stmt.altresulttemplate.indexOf("@@") > -1 ? "@@" : "@"; - if (!testRegEx$1.test(stmt.entry)) { - const pos = stmt.entry.lastIndexOf(stmt.displaySelector); - stmt.md = stmt.entry.slice(0, pos) + `〔${altResultDisplay}〕` - + stmt.entry.slice(pos + stmt.displaySelector.length); - } - stmt.alt = stmt.altresulttemplate.replace(/@@?/, altResultDisplay); - } else if (stmt.resulttemplate.indexOf("?") > -1) { - let pos = stmt.tex.lastIndexOf("?"); - stmt.tex = stmt.tex.slice(0, pos).replace(/\? *$/, "") + resultDisplay + stmt.tex.slice(pos + 1); - stmt.displaySelector = stmt.altresulttemplate.indexOf("??") > -1 ? "??" : "?"; - pos = stmt.alt.lastIndexOf(stmt.displaySelector); - stmt.md = stmt.alt.slice(0, pos) + `〔${altResultDisplay}〕` - + stmt.alt.slice(pos + stmt.displaySelector.length); - stmt.alt = stmt.alt.slice(0, pos) + altResultDisplay - + stmt.alt.slice(pos + stmt.displaySelector.length); - } else if (stmt.resulttemplate.indexOf("%") > -1) { - let pos = stmt.tex.lastIndexOf("%"); - stmt.tex = stmt.tex.slice(0, pos).replace(/% *$/, "") + resultDisplay + stmt.tex.slice(pos + 1); - stmt.displaySelector = stmt.altresulttemplate.indexOf("%%") > -1 ? "%%" : "%"; - pos = stmt.alt.lastIndexOf(stmt.displaySelector); - stmt.md = stmt.alt.slice(0, pos) + `〔${altResultDisplay}〕` - + stmt.alt.slice(pos + stmt.displaySelector.length); - stmt.alt = stmt.alt.slice(0, pos) + altResultDisplay - + stmt.alt.slice(pos + stmt.displaySelector.length); - } - } - return stmt -}; - -const testValue = oprnd => { - if (isVector(oprnd)) { - for (let i = 0; i < oprnd.value.length; i++) { - if (!oprnd.value[i]) { return false } - } - } else if (isMatrix(oprnd)) { - for (let i = 0; i < oprnd.value.length; i++) { - for (let j = 0; j < oprnd.value[0].length; j++) { - if (!oprnd.value[i][j]) { return false } - } - } - } else if (oprnd.dtype & dt.MAP) { - for (let j = 0; j < oprnd.value.data.length; j++) { - for (let i = 0; i < oprnd.value.data[0].length; i++) { - if (!oprnd.value.data[j][i]) { return false } - } - } - } else { - return oprnd.value - } - return true -}; - -/* - * This module receives a TeX template string and a object containing Hurmet variables. - * At each location where the template contains a variable, this module plugs in a TeX string - * of the variable's value, for display in the Hurmet blue echo.. - */ - -const varRegEx = /〖[^〗]*〗/; -const openParenRegEx = /(?:[([{|‖]|[^\\][,;:](?:\\:)?)$/; - -const plugValsIntoEcho = (str, vars, unitAware, formatSpec, decimalFormat) => { - // For each variable name in the echo string, substitute a value. - // The parser surrounded those names with 〖〗 delimiters. - let match; - while ((match = varRegEx.exec(str)) !== null) { - const varName = match[0].replace(/[〖〗()]/g, "").trim().replace(/'/g, "′"); - const matchLength = match[0].length; - const pos = match.index; - let hvar; - let display = ""; - - if (varName.indexOf(".") > -1) { - // Object with a dot accessor. - const names = varName.split("."); - const parentName = names[0]; - if (!vars[parentName]) { return errorOprnd("V_NAME", parentName) } - hvar = vars[parentName]; - if (hvar.dtype === dt.DATAFRAME && names.length === 2) { - // This is a dataframe.dict. I don't want to write an entire dictionary into - // a blue echo, so display just the names. - display = "\\mathrm{" + vars[names[0]].name + "{.}\\mathrm{" + names[1] + "}"; - return str.substring(0, pos) + display + str.substring(pos + matchLength) - } else { - // we want to display the property value. - for (let i = 1; i < names.length; i++) { - const propName = names[i].replace("}", "").replace("\\mathrm{", "").trim(); - const indexOprnd = { value: propName, unit: null, dtype: dt.STRING }; - hvar = propertyFromDotAccessor(hvar, indexOprnd, vars); - if (!hvar) { return errorOprnd("V_NAME", propName) } - const stmt = { resulttemplate: "@", altresulttemplate: "@" }; - hvar.resultdisplay = formatResult(stmt, hvar, formatSpec, null, - decimalFormat).resultdisplay; - } - } - } else if (!vars[varName] && varName === "T") { - // Transposed matrix - hvar = { dtype: dt.RATIONAL, resultdisplay: "\\text{T}" }; - } else if (varName === "e" && /^\^/.test(str.slice(pos + 3).trim())) { - // e^x - str = str.substring(0, pos) + "e" + str.substring(pos + matchLength); - continue - } else if (varName === "j") { - // √(-1) - str = str.substring(0, pos) + "j" + str.substring(pos + matchLength); - continue - } else if (!vars[varName]) { - return errorOprnd("V_NAME", varName) - } else { - // Get a clone in order to avoid mutating the inner properties of vars. - hvar = { - dtype: vars[varName].dtype, - resultdisplay: vars[varName].resultdisplay - }; - } - - if (!hvar || !hvar.resultdisplay) { - const insert = (varName) ? varName : "?"; - return errorOprnd("NULL", insert) - } else if (hvar.error) { - return errorOprnd("NULL", varName) - } - - let needsParens = true; // default - if (isMatrix(hvar) || (hvar.dtype & dt.DATAFRAME)) { needsParens = false; } - if (unitAware && (hvar.dtype & dt.QUANTITY)) { needsParens = true; } - - let isParened = false; // Is the match already nested inside parens? - if (pos > 0) { - const pStr = str.slice(0, pos).trim(); - if (openParenRegEx.test(pStr)) { - const fStr = str.slice(pos + varName.length + 2).trim(); - isParened = fStr.length > 0 && /^([)|‖\]},;:]|\\right)/.test(fStr); - } else if (/^\\begin{[bp]matrix}/.test(hvar.resultdisplay)) { - isParened = /\\end{[bp]matrix}$/.test(hvar.resultdisplay); - } - } - needsParens = needsParens && !isParened; - - if (hvar.dtype === dt.DATAFRAME || (hvar.dtype & dt.MAP)) { - display = "\\mathrm{" + parse$1(vars[varName].name) + "}"; - } else { - display = hvar.resultdisplay; - if (!unitAware) { - const posUnit = display.lastIndexOf("{\\text{"); - if (posUnit > -1) { - display = display.slice(0, posUnit).trim() - .replace(/\\; *$/, "").trim(); - } - } - if (needsParens) { - display = hvar.dtype > 256 ? "\\left(" + display + "\\right)" : "(" + display + ")"; - } - } - str = str.substring(0, pos) + display + str.substring(pos + matchLength); - } - return str -}; - -const negativeOne = Object.freeze(Rnl.negate(Rnl.one)); -const oneHalf = [BigInt(1), BigInt(2)]; -const thirty = [BigInt(30), BigInt(1)]; -const fortyFive = [BigInt(45), BigInt(1)]; -const sixty = [BigInt(60), BigInt(1)]; -const ninety = [BigInt(90), BigInt(1)]; -const halfPi = Object.freeze(Rnl.divide(Rnl.pi, Rnl.two)); - -const functionExpos = (functionName, args) => { - const numArgs = args.length; - - const expos = numArgs === 1 ? args[0].unit.expos : null; - - switch (functionName) { - case "abs": - case "round": - case "roundn": - case "sign": - case "trace": - case "fetch": - return expos - - case "cos": - case "sin": - case "tan": - case "sec": - case "csc": - case "cot": - case "acos": - case "arccos": - case "asin": - case "arcsin": - case "atan": - case "arctan": - case "asec": - case "arcsec": - case "acsc": - case "arccsc": - case "acot": - case "arccot": - case "cosd": - case "sind": - case "tand": - case "secd": - case "cscd": - case "cotd": - case "acosd": - case "asind": - case "atand": - case "asecd": - case "acscd": - case "acotd": - case "gud": - if (!unitsAreCompatible(expos, allZeros)) { - return errorOprnd("UNIT_IN", functionName) - } - return allZeros - - case "exp": - case "log": - case "ln": - case "log10": - case "log2": - case "logn": - case "cosh": - case "sinh": - case "tanh": - case "sech": - case "csch": - case "coth": - case "acosh": - case "asinh": - case "atanh": - case "asech": - case "acsch": - case "acoth": - case "binomial": - case "gamma": - case "Γ": - case "lgamma": - case "lfact": - case "factorial": - if (!unitsAreCompatible(expos, allZeros)) { - return errorOprnd("UNIT_IN", functionName) - } - return allZeros - - case "sqrt": - return expos.map(e => e / 2) - - case "gcd": - case "mht": - if (!unitsAreCompatible(expos, allZeros)) { - return errorOprnd("UNIT_IN", functionName) - } - return functionName === "hmt" ? [1, 0, 0, 0, 0, 0, 0, 0] : allZeros - - case "atan2": - case "hypot": - case "rms": - case "ceil": - case "floor": - case "sum": - case "mean": - case "median": - case "min": - case "max": - case "range": - case "stddev": - case "variance": { - const x = args[0].unit.expos; - for (let i = 1; i < args.length; i++) { - const y = args[i].unit.expos; - if (x.length !== y.length) { return errorOprnd("UNIT_ARG", functionName) } - for (let j = 0; j < x.length; j++) { - if (x[j] !== y[j]) { return errorOprnd("UNIT_ARG", functionName) } - } - } - return functionName === "atan2" ? allZeros : x - } - - case "real": - case "imag": - case "angle": - case "conj": - return allZeros - - case "product": { - const expos = clone(args[0].unit.expos); - for (let i = 1; i < args.length; i++) { - const p = args[i].unit.expos; - expos.map((e, j) => e + p[j]); - } - return expos - } - - default: - return errorOprnd("F_NAME", functionName) - } -}; - -const gamma = x => { - if (Rnl.isZero(x)) { - return errorOprnd("Γ0") - } else if (Rnl.isPositive(x) && Rnl.isInteger(x) && Rnl.lessThan(x, Rnl.fromNumber(101))) { - return Rnl.factorial(Rnl.subtract(x, Rnl.one)) - } else if (Rnl.isNegative(x) && Rnl.isInteger(x)) { - return errorOprnd("ΓPOLE") - } else if (Rnl.lessThan(x, oneHalf)) { - // reflection formula - return Rnl.fromNumber(Math.PI / (Math.sin(Math.PI * Rnl.toNumber(x))) - * Rnl.toNumber(gamma(Rnl.subtract(Rnl.one, x)))) - } else { - return Rnl.lanczos(x) - } -}; - -const lgamma = r => { - // Returns natural logarithm of the Gamma function. - // Ref: https://www.johndcook.com/blog/2010/08/16/how-to-compute-log-factorial/ - if (Rnl.isZero(r)) { return errorOprnd("Γ0") } - if (Rnl.isNegative(r)) { return errorOprnd("LOGΓ") } - if (Rnl.areEqual(r, Rnl.one) || Rnl.areEqual(r, Rnl.two)) { return Rnl.zero } - if (Rnl.lessThanOrEqualTo(r, Rnl.fromNumber(14))) { - return Rnl.fromNumber(Math.log(Rnl.toNumber(gamma(r)))) - } else { - const x = Rnl.toNumber(r); - // eslint-disable-next-line max-len - const y = (x - 0.5) * Math.log(x) - x + 0.5 * Math.log(2 * Math.PI) + 1 / (12 * x) - 1 / (360 * x ** 3) + 1 / (1260 * x ** 5) - 1 / (1680 * x ** 7) + 5 / (540 * x ** 9); - // Error bounded by: -691/(360360 * x^11), 16 significant digits - return Rnl.fromNumber(y) - } -}; - -const binomial = (n, k) => { - // (n \atop k) = n! / (k! (n - k)!) - // = exp(log!(n) - [log!(k) + log!(n - k)]) - if (Rnl.areEqual(n, k)) { return Rnl.one } - if (Rnl.isZero(n)) { return Rnl.zero } - if (Rnl.isNegative(k)) { return Rnl.zero } - if (Rnl.lessThan(n, k)) { return Rnl.zero } - - if (Rnl.isInteger(n) && Rnl.isInteger(k) && Rnl.isPositive(n) && Rnl.isPositive(k)) { - // positive integers -// if (Rnl.lessThan(n, twenty)) { - return Rnl.divide(Rnl.factorial(n), - Rnl.multiply(Rnl.factorial(k), Rnl.factorial(Rnl.subtract(n, k)))) -// } else { -// return Rnl.fromNumber(Math.round(Math.exp(Rnl.toNumber( -// Rnl.subtract(lfact(n), -// Rnl.add(lfact(k), lfact(Rnl.subtract(n, k)))))))) -// } - - } else if (Rnl.isInteger(n) && Rnl.isInteger(k) && Rnl.isPositive(k)) { - // negative integer n - // (-n \atop k) = (-1)^k * multiset(n, k) - return Rnl.multiply(Rnl.power(negativeOne, k), multiset(Rnl.negate(n), k)) - - } else { - // generalized for real or complex arguments - // (x \atop y) = Γ(x+1) / ( Γ(y+1) Γ(x-y+1) ) - return Rnl.divide( - gamma(Rnl.increment(n)), - Rnl.multiply(gamma(Rnl.increment(k)), gamma(Rnl.increment(Rnl.subtract(n, k)))) - ) - - } -}; - -const multiset = (n, k) => { - // ((n \atop k)) = ((n+k-1) \atop k) - // multiset(n, k) = binomial(n+k-1, k) - return binomial(Rnl.add(n, Rnl.decrement(k)), k) -}; - -const piOver180 = Rnl.divide(Rnl.pi, [BigInt(180), BigInt(1)]); - -const unary$1 = { - scalar: { - // Functions that take one real argument. - abs(x) { return Rnl.abs(x) }, - angle(x) { return errorOprnd("NA_REAL", "angle") }, - real(x) { return errorOprnd("NA_REAL", "real") }, - imag(x) { return errorOprnd("NA_REAL", "imag") }, - conj(x) { return errorOprnd("NA_REAL", "conj") }, - cos(x) { return Rnl.cos(x) }, - sin(x) { return Rnl.sin(x) }, - tan(x) { return Rnl.tan(x) }, - cosh(x) { return Rnl.cosh(x) }, - sinh(x) { return Rnl.sinh(x) }, - tanh(x) { return Rnl.tanh(x) }, - acos(x) { - if (Rnl.greaterThan(Rnl.abs(x), Rnl.one)) { return errorOprnd("ATRIG", "acos") } - return Rnl.fromNumber(Math.acos(Rnl.toNumber(x))) - }, - asin(x) { - if (Rnl.greaterThan(Rnl.abs(x), Rnl.one)) { return errorOprnd("ATRIG", "asin") } - return Rnl.fromNumber(Math.asin(Rnl.toNumber(x))) - }, - atan(x) { - return Rnl.fromNumber(Math.atan(Rnl.toNumber(x))) - }, - sec(x) { - return Rnl.fromNumber(1 / Math.cos(Rnl.toNumber(x))) - }, - csc(x) { - return Rnl.fromNumber(1 / Math.sin(Rnl.toNumber(x))) - }, - cot(x) { - if (Rnl.isZero(x)) { return errorOprnd("COT", "cotangent") } - return Rnl.fromNumber(1 / Math.tan(Rnl.toNumber(x))) - }, - asec(x) { - if (Rnl.greaterThanOrEqualTo(Rnl.abs(x), Rnl.one)) { - return errorOprnd("ASEC", "arcecant") - } - const temp = Math.atn(Math.sqrt(Rnl.toNumber(Rnl.decrement(Rnl.multiply(x, x))))); - return (Rnl.isPositive(x)) - ? Rnl.fromNumber(temp) - : Rnl.fromNumber(temp - Math.PI) - }, - acot(x) { - if (Rnl.greaterThanOrEqualTo(Rnl.abs(x), Rnl.one)) { - return errorOprnd("ASEC", "acot") - } - const temp = Math.atn(1 / (Math.sqrt(Rnl.toNumber(Rnl.decrement(Rnl.multiply(x, x)))))); - return (Rnl.isPositive(x)) - ? Rnl.fromNumber(temp) - : Rnl.fromNumber(temp - Math.PI) - }, - acsc(x) { - return Rnl.fromNumber(Math.atn(-Rnl.toNumber(x)) + Math.PI) - }, - exp(x) { - return Rnl.exp(x) - }, - log(x) { - return Rnl.isZero(x) ? errorOprnd("LOG_ZERO") : Rnl.fromNumber(Math.log(Rnl.toNumber(x))) - }, - ln(x) { - return Rnl.isZero(x) ? errorOprnd("LOG_ZERO") : Rnl.fromNumber(Math.log(Rnl.toNumber(x))) - }, - log10(x) { - return Rnl.isZero(x) - ? errorOprnd("LOG_ZERO") - : Rnl.fromNumber(Math.log10(Rnl.toNumber(x))) - }, - log2(x) { - return Rnl.isZero(x) - ? errorOprnd("LOG_ZERO") - : Rnl.fromNumber(Math.log2(Rnl.toNumber(x))) - }, - sech(x) { - // sech(n) = 2 / (eⁿ + e⁻ⁿ) - const num = Rnl.toNumber(x); - return Rnl.fromNumber(2 / (Math.exp(num) + Math.exp(-num))) - }, - csch(x) { - // csch(n) = 2 / (eⁿ - e⁻ⁿ) - const num = Rnl.toNumber(x); - return Rnl.fromNumber(2 / (Math.exp(num) - Math.exp(-num))) - }, - coth(x) { - // coth(n) = (eⁿ + e⁻ⁿ) / (eⁿ - e⁻ⁿ) - const num = Rnl.toNumber(x); - return Rnl.fromNumber( - (Math.exp(num) + Math.exp(-num)) / (Math.exp(num) - Math.exp(-num)) - ) - }, - acosh(x) { - // acosh(x) = log( x + sqrt(x - 1) × sqrt(x + 1) ) - const num = Rnl.toNumber(x); - return Rnl.fromNumber(Math.log( num + Math.sqrt(num - 1) * Math.sqrt(num + 1) )) - }, - asinh(x) { - // asinh(x) = log(x + sqrt(x² + 1)) - const num = Rnl.toNumber(x); - return Rnl.fromNumber(Math.log(num + Math.sqrt(Math.pow(num, 2) + 1))) - }, - atanh(x) { - // atanh(x) = [ log(1+x) - log(1-x) ] / 2 - const num = Rnl.toNumber(x); - return Rnl.fromNumber((Math.log(1 + num) - Math.log(1 - num) ) / 2) - }, - asech(x) { - // asech(x) = log( [sqrt(-x * x + 1) + 1] / x ) - if (Rnl.isZero(x)) { return errorOprnd("DIV") } - const num = Rnl.toNumber(x); - return Rnl.fromNumber(Math.log((Math.sqrt(-num * num + 1) + 1) / num)) - }, - ascsh(x) { - // acsch(x) = log( sqrt(1 + 1/x²) + 1/x ) - if (Rnl.isZero(x)) { return errorOprnd("DIV") } - const num = Rnl.toNumber(x); - return Rnl.fromNumber(Math.log(Math.sqrt(1 + 1 / Math.pow(num, 2)) + 1 / num)) - }, - acoth(x) { - // acoth(x) = [ log(1 + 1/x) - log(1 - 1/x) ] / 2 - if (Rnl.isZero(x)) { return errorOprnd("DIV") } - const num = Rnl.toNumber(x); - return Rnl.fromNumber((Math.log(1 + 1 / num) - Math.log(1 - 1 / num)) / 2) - }, - ceil(x) { - return Rnl.ceil(x) - }, - floor(x) { - return Rnl.floor(x) - }, - gamma(x) { - return gamma(x) - }, - Γ(x) { - return gamma(x) - }, - lgamma(x) { - if (Rnl.isNegative(x) || Rnl.isZero(x)) { return errorOprnd("LOGΓ") } - return lgamma(x) - }, - lfact(x) { - if (Rnl.isNegative(x) || !Rnl.isInteger(x)) { return errorOprnd("FACT") } - return lgamma(Rnl.add(x, Rnl.one)) - }, - factorial(x) { - return Rnl.factorial(x) - }, - sign(x) { - return Rnl.isPositive(x) ? Rnl.one : Rnl.isZero(x) ? Rnl.zero : negativeOne - }, - cosd(x) { - if (Rnl.areEqual(x, ninety)) { return Rnl.zero } - if (Rnl.areEqual(x, sixty)) { return oneHalf } - return this.cos(Rnl.multiply(x, piOver180)) - }, - sind(x) { - if (Rnl.areEqual(x, thirty)) { return oneHalf } - return this.sin(Rnl.multiply(x, piOver180)) - }, - tand(x) { - if (Rnl.areEqual(x, fortyFive)) { return Rnl.one } - if (Rnl.areEqual(x, ninety)) { return errorOprnd("TAN90", "90°") } - return this.tan(Rnl.multiply(x, piOver180)) - }, - cotd(x) { - return this.cot(Rnl.multiply(x, piOver180)) - }, - cscd(x) { - return this.csc(Rnl.multiply(x, piOver180)) - }, - secd(x) { - return this.sec(Rnl.multiply(x, piOver180)) - }, - acosd(x) { - const y = this.acos(x); - return y.dtype ? y : Rnl.divide(y, piOver180) - }, - asind(x) { - const y = this.asin(x); - return y.dtype ? y : Rnl.divide(y, piOver180) - }, - atand(x) { - return Rnl.divide(this.atan(x), piOver180) - }, - acotd(x) { - const y = this.acot(x); - return y.dtype ? y : Rnl.divide(y, piOver180) - }, - acscd(x) { - const y = this.acsc(x); - return y.dtype ? y : Rnl.divide(y, piOver180) - }, - asecd(x) { - const y = this.asec(x); - return y.dtype ? y : Rnl.divide(y, piOver180) - }, - Char(x) { - return String.fromCodePoint(Rnl.toNumber(x)) - }, - sqrt(x) { - const y = [BigInt(1), BigInt(2)]; - return Cpx.isComplex(x) || (Rnl.isNegative(x)) - ? Cpx.power([x, Rnl.zero], y) - : Rnl.power(x, y) - }, - round(x) { - return Rnl.fromString(Rnl.toString(x, 0)) - } - }, - complex: { - // Functions that take one complex argument. - abs(z) { return Cpx.abs(z) }, - angle(z) { return Cpx.angle(z) }, - real(z) { return z[0] }, - imag(z) { return z[1] }, - conj(z) { return Cpx.conjugate(z) }, - cos(z) { return Cpx.cos(z) }, - sin(z) { return Cpx.sin(z) }, - asin(z) { return Cpx.asin(z) }, - atan(z) { return Cpx.atan(z) }, - acos(z) { return Cpx.subtract([halfPi, Rnl.zero], Cpx.asin(z))}, // π/2 - arcsin(z) - tan(z) { return Cpx.divide(Cpx.sin(z), Cpx.cos(z)) }, - cot(z) { return Cpx.divide(Cpx.cos(z), Cpx.sin(z)) }, - sec(z) { - const c = Cpx.cos(z); - return c.dtype ? c : Cpx.inverse(c) - }, - csc(z) { - const s = Cpx.sin(z); - return s.dtype ? s : Cpx.inverse(s) - }, - asec(z) { - // acos(inverse(z)) - const inv = Cpx.inverse(z); - return Cpx.subtract([halfPi, Rnl.zero], Cpx.asin(inv)) - }, - acot(z) { return Cpx.atan(Cpx.inverse(z)) }, - acsc(z) { - return Cpx.asin(Cpx.inverse(z)) - }, - exp(z) { - return Cpx.exp(z) - }, - log(z) { - return Cpx.log(z) - }, - ln(z) { - return Cpx.log(z) - }, - log10(z) { - return Rnl.fromNumber(Math.log10(Rnl.toNumber(z))) - }, - log2(z) { - return Rnl.fromNumber(Math.log2(Rnl.toNumber(z))) - }, - cosh(z) { - // cosh(z) = (eᶻ + e⁻ᶻ) / 2 - return Cpx.divide(Cpx.add(Cpx.exp(z), Cpx.exp(Cpx.negate(z))), [Rnl.two, Rnl.zero]) - }, - sinh(z) { - // sinh(z) = (eᶻ - e⁻ᶻ) / 2 - return Cpx.divide(Cpx.subtract(Cpx.exp(z), Cpx.exp(Cpx.negate(z))), [Rnl.two, Rnl.zero]) - }, - tanh(z) { - // tanh(z) = (eᶻ - e⁻ᶻ) / (eᶻ + e⁻ᶻ) - const ez = Cpx.exp(z); - const eMinuxZ = Cpx.exp(Cpx.negate(z)); - return Cpx.divide(Cpx.subtract(ez, eMinuxZ), Cpx.add(ez, eMinuxZ)) - }, - sech(z) { - // sech(z) = 2 / (eᶻ + e⁻ᶻ) - return Cpx.divide([Rnl.two, Rnl.zero], Cpx.add(Cpx.exp(z), Cpx.exp(Cpx.negate(z)))) - }, - csch(z) { - // csch(z) = 2 / (eᶻ - e⁻ᶻ) - return Cpx.divide([Rnl.two, Rnl.zero], Cpx.subtract(Cpx.exp(z), Cpx.exp(Cpx.negate(z)))) - }, - coth(z) { - // coth(z) = (eᶻ + e⁻ᶻ) / (eᶻ - e⁻ᶻ) - const ez = Cpx.exp(z); - const eMinuxZ = Cpx.exp(Cpx.negate(z)); - return Cpx.divide(Cpx.add(ez, eMinuxZ), Cpx.subtract(ez, eMinuxZ)) - }, - acosh(z) { - return Cpx.acosh(z) - }, - asinh(z) { - return Cpx.asinh(z) - }, - atanh(z) { - return Cpx.atanh(z) - }, - asech(z) { - return Cpx.acosh(Cpx.inverse(z)) - }, - acsch(z) { - return Cpx.asinh(Cpx.inverse(z)) - }, - acoth(z) { - return Cpx.atanh(Cpx.inverse(z)) - }, - ceil(z) { - return errorOprnd("NA_COMPL_OP", "ceil") - }, - floor(z) { - return errorOprnd("NA_COMPL_OP", "ceil") - }, - gamma(z) { - return Cpx.gamma(z) - }, - Γ(z) { - return Cpx.gamma(z) - }, - lgamma(z) { - // TODO: complex log of gamma() - return errorOprnd("NA_COMPL_OP", "lgamma") - }, - factorial(z) { - return errorOprnd("NA_COMPL_OP", "factorial") - }, - sign(z) { - if (Rnl.isZero(z[1]) && Rnl.isPositive(z[0])) { - return Rnl.one - } else if (Rnl.isZero(z[1]) && Rnl.isNegative(z[0])) { - return Rnl.negate(Rnl.one) - } else { - return Cpx.divide(z, [Cpx.abs(z), Rnl.zero]) - } - }, - round(z) { - // TODO: complex round function - return errorOprnd("NA_COMPL_OP", "round") - } - } -}; - -const binary$1 = { - logn([n, x]) { - return Rnl.fromNumber(Math.log(Rnl.toNumber(x)) / Math.log(Rnl.toNumber(n))) - }, - roundFixed([x, n]) { - return Rnl.fromString(Rnl.toString(x, n)) - }, - roundSignificant([x, n]) { - return Rnl.fromString(Rnl.toStringSignificant(x, n)) - }, - stringFixed([x, n]) { - return Rnl.toString(x, n) - }, - stringSignificant([x, n]) { - return Rnl.toStringSignificant(x, n) - }, - atan2([x, y]) { - return Rnl.fromNumber(Math.atan2(Rnl.toNumber(y), Rnl.toNumber(x))) - }, - hypot([x, y]) { - // sqrt(x^2) - // https://www.johndcook.com/blog/2010/06/02/whats-so-hard-about-finding-a-hypotenuse/ - const max = Rnl.max(x, y); - const r = Rnl.divide(Rnl.min(x, y), max); - return Rnl.multiply(max, Rnl.sqrt(Rnl.increment(Rnl.multiply(r, r)))) - }, - gcd([m, n]) { - return Rnl.gcd(m, n) - }, - rms([x, y]) { - return this.hypot(x, y) - }, - binomial([x, y]) { - return binomial(x, y) - }, - ones([m, n]) { - return Matrix.ones(Rnl.toNumber(m), Rnl.toNumber(n)) - }, - zeros([m, n]) { - return Matrix.zeros(Rnl.toNumber(m), Rnl.toNumber(n)) - }, - mod([x, y]) { - return Rnl.mod(x, y) - }, - rem([x, y]) { - return Rnl.rem(x, y) - } -}; - -const reduce = { - max(list) { - return list.reduce((max, e) => Rnl.max(max, e)) - }, - min(list) { - return list.reduce((min, e) => Rnl.min(min, e)) - }, - sum(list) { - return list.reduce((sum, e) => Rnl.add(sum, e)) - }, - product(list) { - return list.reduce((sum, e) => Rnl.multiply(sum, e)) - }, - mean(list) { - const sum = this.sum(list); - return Rnl.divide(sum, Rnl.fromNumber(list.length)) - }, - median(list) { - const max = this.max(list); - const min = this.min(list); - return Rnl.divide(Rnl.add(max, min), Rnl.two) - }, - range(list) { - return Rnl.subtract(this.max(list), this.min(list)) - }, - variance(list) { - const sum = this.sum(list); - const mean = Rnl.divide(sum, Rnl.fromNumber(list.length)); - const num = list.reduce((num, e) => Rnl.add(num, Rnl.pow(Rnl.subtract(e, mean), Rnl.two))); - return Rnl.divide(num, Rnl.subtract(Rnl.fromNumber(list.length), Rnl.one)) - }, - stddev(list) { - const variance = this.variance(list); - return Rnl.power(variance, oneHalf) - }, - accumulate(list) { - const v = new Array(list.length).fill(0); - v[0] = list[0]; - for (let i = 1; i < list.length; i++) { - v[i] = Rnl.add(v[i - 1], list[i]); - } - return v - } -}; - -const lerp = (args, unitAware) => { - // linear interpolation - for (let i = 0; i < 3; i++) { - if (!(args[i].dtype & dt.RATIONAL)) { return errorOprnd("") } - } - let expos = allZeros; - if (unitAware) { - if (args[0].expos !== args[1].expos) { return errorOprnd("") } - if (args[1].expos !== args[2].expos) { return errorOprnd("") } - expos = args[0].expos; - } - const output = Object.create(null); - output.unit = Object.create(null); - output.unit.expos = expos; - output.dtype = dt.RATIONAL; - - const v0 = args[0].value; // a vector - const v1 = args[1].value; // another vector - const x = args[2].value; // the input value - // TODO: Use binary search - for (let i = 0; i < v0.length - 1; i++) { - if (Rnl.lessThanOrEqualTo(v0[i], x) & Rnl.lessThanOrEqualTo(x, v0[i + 1])) { - const slope = Rnl.divide((Rnl.subtract(v1[i + 1], v1[i])), - (Rnl.subtract(v0[i + 1], v0[i]))); - output.value = Rnl.add(v1[i], Rnl.multiply(slope, (Rnl.subtract(x, v0[i])))); - return Object.freeze(output) - } - } -}; - -const Functions = Object.freeze({ - functionExpos, - unary: unary$1, - binary: binary$1, - reduce, - lerp -}); - -const multivarFunction = (arity, functionName, args) => { - // Deal with a function that may have multiple arguments. - - if (args.length === 1) { - const list = isVector(args[0]) - ? args[0].value - : (args.dtype & dt.MATRIX) - // TODO: fix the next line. - ? args[0].value.flat() - : args[0].value; - - const value = Functions[arity][functionName](list); - - let dtype = args[0].dtype; - if (arity === "reduce" && functionName !== "accumulate") { - // Mask off any matrix or vector indicator from the dtype - if (dtype & dt.MATRIX) { dtype -= dt.MATRIX; } - if (dtype & dt.ROWVECTOR) { dtype -= dt.ROWVECTOR; } - if (dtype & dt.COLUMNVECTOR) { dtype -= dt.COLUMNVECTOR; } - } - - return [value, dtype] - - } else if (functionName === "sum" && args.length === 2 && isMatrix(args[0]) - && args[1].dtype === dt.RATIONAL) { - if (Rnl.areEqual(args[1].value, Rnl.two)) { - const dtype = dt.COLUMNVECTOR + dt.RATIONAL; - const result = args[0].value.map(row => row.reduce((sum, e) => Rnl.add(sum, e))); - return [ result, dtype ] - } else if (Rnl.areEqual(args[1].value, Rnl.one)) { - const dtype = dt.ROWVECTOR + dt.RATIONAL; - const result = Matrix.transpose(args[0]).value.map( - row => row.reduce((sum, e) => Rnl.add(sum, e)) - ); - return [ result, dtype ] - } else { - return [errorOprnd("BAD_SUM"), dt.ERROR] - } - } else { - // We have multiple arguments. - // Is one of them a vector or a matrix? - let iArg = 0; - let gotVector = false; - let gotMatrix = false; - let dtype = args[0].dtype; - - for (iArg = 0; iArg < args.length; iArg++) { - if (isVector(args[iArg])) { - gotVector = true; - dtype = args[iArg].dtype; - break - } else if (isMatrix(args[iArg])) { - gotMatrix = true; - dtype = args[iArg].dtype; - break - } - } - const list = args.map(e => e.value); - if (!(gotVector || gotMatrix)) { - const result = Functions[arity][functionName](list); - return functionName === "zeros" || functionName === "ones" - ? [result.value, result.dtype] - : [result, args[0].dtype] - - } else { - const result = []; - if (gotVector) { - const listClone = clone(list); - for (let i = 0; i < list[iArg].length; i++) { - listClone[iArg] = list[iArg][i]; - result.push(Functions[arity][functionName](listClone)); - } - } else { - const listClone = clone(list); - for (let i = 0; i < list[iArg].length; i++) { - result.push([]); - for (let j = 0; j < list[iArg][0].length; j++) { - listClone[iArg] = list[iArg][i][j]; - result[i].push(Functions[arity][functionName](listClone)); - } - } - } - return [ result, dtype ] - } - } -}; - -// compare.js - -const equals = (x, y) => { - if (Rnl.isRational(x) && Rnl.isRational(y)) { - return Rnl.areEqual(x, y) - } else { - return x === y - } -}; - -const compare = (op, x, y, yPrev) => { - // If yPrev is defined, then this is part of a chained comparison, e.g.: a < b < c - if (x === false && yPrev) { return false } // The chain is false if any part is false. - if (x === true && yPrev) { x = yPrev; } // Compare this link in the chain. - - switch (op) { - case "=": - return errorOprnd("BAD_EQ") - - case "==": - case "⩵": - return equals(x, y) - - case "≠": - case "!=": - case "/=": - if (Rnl.isRational(x) && Rnl.isRational(y)) { - return !Rnl.areEqual(x, y) - } else { - return x !== y - } - - case ">": - if (Rnl.isRational(x) && Rnl.isRational(y)) { - return Rnl.greaterThan(x, y) - } else { - return x > y - } - - case "<": - if (Rnl.isRational(x) && Rnl.isRational(y)) { - return Rnl.lessThan(x, y) - } else { - return x < y - } - - case "≥": - case ">=": - if (Rnl.isRational(x) && Rnl.isRational(y)) { - return Rnl.greaterThanOrEqualTo(x, y) - } else { - return x >= y - } - - case "≤": - case "<=": - if (Rnl.isRational(x) && Rnl.isRational(y)) { - return Rnl.lessThanOrEqualTo(x, y) - } else { - return x <= y - } - - case "∈": - case "in": - if (typeof x === "string" && typeof y === "string") { - if (Array.from(x).length > 1) { return false } - return y.indexOf(x) > -1 - } else if (Array.isArray(y) && Rnl.isRational(y[0]) && Rnl.isRational(x)) { - for (let i = 0; i < y.length; i++) { - if (Rnl.areEqual(x, y[i])) { return true } - } - return false - } else if (Array.isArray(y) && !Array.isArray(x)) { - for (let i = 0; i < y.length; i++) { - if (equals(x, y[i])) { return true } - } - return false - } else if (y instanceof Map) { - return y.has(x) - } else if (typeof x === "string" && typeof y === "object" && - Object.hasOwnProperty.call(y, "headings")) { - // Is x a property of dataframe y? - return Boolean(y.headings.includes(x) || - (y.rowMap && Object.hasOwnProperty.call(y.rowMap, x))) - } else { - return errorOprnd("NOT_ARRAY") - } - - case "∋": - if (typeof x === "string" && typeof y === "string") { - if (Array.from(x).length > 1) { return false } - return y.indexOf(x) > -1 - } else if (x instanceof Map) { - return x.has(y) - } else if (typeof x === "object" && typeof y === "string" && - Object.hasOwnProperty.call(x, "headings")) { - // Is y a property of dataframe x? - return Boolean(x.headings.includes(y) || - (x.rowMap && Object.hasOwnProperty.call(x.rowMap, y))) - } else { - return errorOprnd("NO_PROP", x.name) - } - - case "⊃": - if (typeof x === "string" && typeof y === "string") { - return x.indexOf(y) > -1 - } else if (Array.isArray(x) && Array.isArray(y)) { - for (let i = 0; i < x.length; i++) { - // We test for a contiguous subset - if (equals(y[0], x[i])) { - if (i + y.length > x.length) { return false } - for (let j = 1; j < y.length; j++) { - if (!equals(y[j], x[i + j])) { return false } - } - return true - } - } - return false - } else { - return errorOprnd("NOT_ARRAY") - } - - case "∉": - case "!in": - if (typeof x === "string" && typeof y === "string") { - if (Array.from(x).length === 1) { return false } - return y.indexOf(x) === -1 - } else if (Array.isArray(y) && Rnl.isRational(y[0]) && Rnl.isRational(x)) { - for (let i = 0; i < y.length; i++) { - if (Rnl.areEqual(x, y[i])) { return false } - } - return true - } else if (Array.isArray(y)) { - for (let i = 0; i < y.length; i++) { - if (x === y[i]) { return false } - } - return true - } else if (y instanceof Map) { - return !y.has(x) - } else if (typeof x === "string" && typeof y === "object" && - Object.hasOwnProperty.call(y, "headings")) { - // Is x a property of dataframe x? - return !(y.headings.includes(x) || - (y.rowMap && Object.hasOwnProperty.call(y.rowMap, x))) - } else { - return errorOprnd("NOT_ARRAY") - } - - case "∌": - if (typeof x === "string" && typeof y === "string") { - if (Array.from(y).length === 1) { return false } - return x.indexOf(y) === -1 - } else if (x instanceof Map) { - return !x.has(y) - } else if (typeof x === "object" && typeof y === "string" && - Object.hasOwnProperty.call(x, "headings")) { - // Is y a property of dataframe x? - return !(x.headings.includes(y) || - (x.rowMap && Object.hasOwnProperty.call(x.rowMap, y))) - } else { - return errorOprnd("NO_PROP", x.name) - } - - case "⊄": - if (typeof x === "string" && typeof y === "string") { - return y.indexOf(x) === -1 - } else if (Array.isArray(x) && Array.isArray(y)) { - // We test for a contiguous subset - for (let i = 0; i < y.length; i++) { - if (equals(x[0], y[i])) { - if (i + x.length > y.length) { continue } - let provisional = true; - for (let j = 1; j < x.length; j++) { - if (!equals(x[j], y[i + j])) { - provisional = false; - continue - } - } - if (!provisional) { continue } - return true - } - } - return false - } else { - return errorOprnd("NOT_ARRAY") - } - - case "⊅": - if (typeof x === "string" && typeof y === "string") { - return x.indexOf(y) === -1 - } else if (Array.isArray(x) && Array.isArray(y)) { - // We test for a contiguous subset - for (let i = 0; i < x.length; i++) { - if (equals(y[0], x[i])) { - if (i + y.length > x.length) { continue } - let provisional = true; - for (let j = 1; j < y.length; j++) { - if (!equals(y[j], x[i + j])) { - provisional = false; - continue - } - } - if (!provisional) { continue } - return true - } - } - return false - } else { - return errorOprnd("NOT_ARRAY") - } - } -}; - -// Hurmet math operators are overloaded to handle operands of various shapes. -// Those shapes being scalars, vectors, matrices, and maps. -// This file implements the overloading. - -// Some helper functions -const dotProduct$1 = (a, b) => { - return a.map((e, j) => Rnl.multiply(e, b[j])).reduce((m, n) => Rnl.add(m, n)) -}; -const sumOfSquares = vector => { - return vector.map((e) => Rnl.multiply(e, e)).reduce((m, n) => Rnl.add(m, n)) -}; -const oneTenth = [BigInt(1), BigInt(100)]; - -// From the object below, calculations.js will call operators using statements -// that look like this: -// resultValue = Operations.unary[shape][operator](inputValue) - -const unary = { - scalar: { - abs(x) { return Rnl.abs(x) }, - norm(x) { return Rnl.abs(x) }, - negate(x) { return Rnl.negate(x) }, - exp(x) { return Rnl.exp(x) }, - floor(x) { return Rnl.floor(x) }, - ceil(x) { return Rnl.ceil(x) }, - percent(x) { return Rnl.multiply(oneTenth, x) }, - factorial(x) { return Rnl.factorial(x) }, - doubleFactorial(x) { return Rnl.doubleFactorial(x) }, - not(x) { return !x } - }, - - complex: { - abs(z) { return Cpx.abs(z) }, - norm(z) { return Cpx.abs(z) }, - conjugate(z) { return Cpx.conjugate(z) }, - negate(z) { return Cpx.negate(z) }, - exp(z) { return Cpx.exp(z) }, - floor(z) { return errorOprnd("NA_COMPL_OP", "floor") }, - ceil(z) { return errorOprnd("NA_COMPL_OP", "ceil") }, - percent(z) { return errorOprnd("NA_COMPL_OP", "percent") }, - factorial(z) { return errorOprnd("NA_COMPL_OP", "factorial") }, - doubleFactorial(z) { return errorOprnd("NA_COMPL_OP", "factorial") }, - not(z) { return errorOprnd("NA_COMPL_OP", "not") } - }, - - vector: { - abs(v) { return Rnl.sqrt(sumOfSquares(v)) }, // magnitude of a vector - norm(v) { return Rnl.sqrt(sumOfSquares(v)) }, // ditto - negate(v) { return v.map(e => Rnl.negate(e)) }, - exp(v) { return v.map(e => Rnl.exp(e)) }, - floor(v) { return v.map(e => Rnl.floor(e)) }, - ceil(v) { return v.map(e => Rnl.ceil(e)) }, - percent(v) { return v.map(e => Rnl.multiply(oneTenth, e)) }, - factorial(v) { return v.map(e => Rnl.factorial(e)) }, - doubleFactorial(v) { return v.map(e => Rnl.doubleFactorial(e)) }, - not(v) { return v.map(e => !e) } - }, - - matrix: { - abs(m) { return Matrix.invert(m, true) }, - norm(m) { - if (m.length === m[0].length) { - let sum = Rnl.zero; - for (let i = 0; i < m.length; i++) { - sum = Rnl.add(sum, sumOfSquares(m[i])); - } - return sum.sqrt() - } - }, - negate(m) { return m.map(row => row.map(e => Rnl.negate(e))) }, - exp(m) { return m.map(row => row.map(e => Rnl.exp(e))) }, - floor(m) { return m.map(row => row.map(e => Rnl.floor(e))) }, - ceil(m) { return m.map(row => row.map(e => Rnl.ceil(e))) }, - percent(m) { return m.map(row => row.map(e => Rnl.multiply(oneTenth, e))) }, - factorial(m) { return m.map(row => row.map(e => Rnl.factorial(e))) }, - doubleFactorial(m) { return m.map(row => row.map(e => Rnl.doubleFactorial(e))) }, - not(m) { return m.map(row => row.map(e => !e)) } - }, - - map: { - abs(map) { - map.data = map.data.map(column => Rnl.isRational(column[0]) - ? column.map(e => Rnl.abs(e)) - : column - ); - return map - }, - negate(map) { - map.data = map.data.map(column => Rnl.isRational(column[0]) - ? column.map(e => Rnl.negate(e)) - : column - ); - return map - }, - exp(map) { - map.data = map.data.map(column => Rnl.isRational(column[0]) - ? column.map(e => Rnl.exp(e)) - : column - ); - return map - }, - floor(map) { - map.data = map.data.map(column => Rnl.isRational(column[0]) - ? column.map(e => Rnl.floor(e)) - : column - ); - return map - }, - ceil(map) { - map.data = map.data.map(column => Rnl.isRational(column[0]) - ? column.map(e => Rnl.ceil(e)) - : column); - return map - }, - percent(map) { - map.data = map.data.map(column => Rnl.isRational(column[0]) - ? column.map(e => Rnl.multiply(oneTenth, e)) - : column - ); - return map - }, - factorial(map) { - map.data = map.data.map(column => Rnl.isRational(column[0]) - ? column.map(e => Rnl.factorial(e)) - : column - ); - return map - }, - doubleFactorial(map) { - map.data = map.data.map(column => Rnl.isRational(column[0]) - ? column.map(e => Rnl.doubleFactorial(e)) - : column - ); - return map - }, - not(map) { - map.data = map.data.map(column => typeof column[0] === "boolean" - ? column.map(e => !e) - : column - ); - return map - } - } -}; - -const condition = { - // Deal with booleans. Return a single value, true or false. - // If a vector or matrix is received, all elements must be - // true in order to return a true. Otherwise return a false. - scalar(x) { return x }, - vector(v) { return v.reduce((prev, curr) => prev && curr, true) }, - matrix(m) { - const row = new Array(m.length); - for (let i = 0; i < m.length; i++) { - row[i] = m[i].reduce((prev, curr) => prev && curr, true); - } - return row.reduce((prev, curr) => prev && curr, true) - } -}; - -const dtype = { - // Given the shapes which are operands to a binary operator, - // return the resulting data type. - scalar: { - scalar(t0, t1, tkn) { - return (tkn === "&" || tkn === "hcat" || tkn === "hcat") - ? t0 + ((tkn === "&" || tkn === "hcat") ? dt.ROWVECTOR : dt.COLUMNVECTOR ) - : t0 - }, - complex(t0, t1, tkn) { return t1 }, - vector(t0, t1, tkn) { return t1 }, - matrix(t0, t1, tkn) { return t1 }, - dataFrame(t0, t1, tkn) { return t1 }, - map(t0, t1, tkn) { return t1 } - }, - complex: { - scalar(t0, t1, tkn) { return t0 }, - complex(t0, t1, tkn) { return t0 } - }, - vector: { - scalar(t0, t1, tkn) { return t0 }, - map(t0, t1, tkn) { return t1 + (t0 & dt.ROWVECTOR) + (t0 & dt.COLUMNVECTOR) } - }, - rowVector: { - rowVector(t0, t1, tkn) { return tkn === "vcat" ? t0 - dt.ROWVECTOR + dt.MATRIX : t0 }, - columnVector(t0, t1, tkn) { return t0 }, - matrix(t0, t1, tkn) { return tkn === "multiply" ? t0 : t1 } - }, - columnVector: { - rowVector(t0, t1, op) { - return op === "dot" - ? dt.RATIONAL - : op === "cross" - ? t0 - : t0 - dt.COLUMNVECTOR + dt.MATRIX - }, - columnVector(t0, t1, tkn) { return tkn === "&" ? t0 - dt.COLUMNVECTOR + dt.MATRIX : t0 }, - matrix(t0, t1, tkn) { return t1 } - }, - matrix: { - scalar(t0, t1, tkn) { return t0 }, - rowVector(t0, t1, tkn) { return t0 }, - columnVector(t0, t1, tkn) { return tkn === "*" || tkn === "⌧" ? t1 : t0 }, - matrix(t0, t1, tkn) { return t0 }, - map(t0, t1, tkn) { return 0 } - }, - dataFrame: { - scalar(t0, t1, tkn) { return t0 } - }, - map: { - scalar(t0, t1, tkn) { return t0 }, - vector(t0, t1, tkn) { return t0 }, - matrix(t0, t1, tkn) { return 0 }, - map(t0, t1, tkn) { return t0 } - } -}; - - -// The binary operators below are called like this: -// resultValue = Operations.binary[shape_0][shape_1][operator](input_0, input_1) - -const binary = { - scalar: { - scalar: { - // Binary operations on two scalars - add(x, y) { return Rnl.add(x, y) }, - subtract(x, y) { return Rnl.subtract(x, y) }, - multiply(x, y) { return Rnl.multiply(x, y) }, - divide(x, y) { return Rnl.divide(x, y) }, - power(x, y) { - // eslint-disable-next-line max-len - return Cpx.isComplex(x) || (Rnl.isNegative(x) && Rnl.isPositive(y) && Rnl.lessThan(y, Rnl.one)) - ? Cpx.power([x, Rnl.zero], y) - : Rnl.power(x, y) - }, - hypot(x, y) { return Rnl.hypot(x, y) }, - rem(x, y) { return Rnl.rem(x, y) }, - and(x, y) { return x && y }, - or(x, y) { return x || y }, - xor(x, y) { return x !== y }, - concat(x, y) { return [x, y] }, - unshift(x, y) { return [x, y] } - }, - complex: { - add(x, z) { return [Rnl.add(x, z[0]), z[1]] }, - subtract(x, z) { return [Rnl.subtract(x, z[0]), Rnl.negate(z[1])] }, - multiply(x, z) { return [Rnl.multiply(x, z[0]), Rnl.multiply(x, z[1])] }, - divide(x, z) { return Cpx.divide([x, Rnl.zero], z) }, - power(x, z) { return Cpx.power([x, Rnl.zero], z) }, - rem(x, z) { return errorOprnd("NA_COMPL_OP", "rem") }, - and(x, z) { return errorOprnd("NA_COMPL_OP", "and") }, - or(x, z) { return errorOprnd("NA_COMPL_OP", "or") }, - xor(x, z) { return errorOprnd("NA_COMPL_OP", "xor") } - }, - vector: { - // Binary operations with a scalar and a vector. - // Perform element-wise operations. - add(x, v) { return v.map(e => Rnl.add(x, e)) }, - subtract(x, v) { return v.map(e => Rnl.subtract(x, e)) }, - multiply(x, v) { return v.map(e => Rnl.multiply(x, e)) }, - divide(x, v) { return v.map(e => Rnl.divide(x, e)) }, - power(x, v) { return v.map(e => Rnl.power(x, e)) }, - rem(x, v) { return v.map(e => Rnl.rem(x, e)) }, - and(x, v) { return v.map(e => x && e) }, - or(x, v) { return v.map(e => x || e) }, - xor(x, v) { return v.map(e => x !== e) }, - concat(x, v) { return [x, ...v] } - }, - matrix: { - // Binary operations with a scalar and a matrix. - // Perform element-wise operations. - add(x, m) { return m.map(row => row.map(e => Rnl.add(x, e))) }, - subtract(x, m) { return m.map(row => row.map(e => Rnl.subtract(x, e))) }, - multiply(x, m) { return m.map(row => row.map(e => Rnl.multiply(x, e))) }, - divide(x, m) { return m.map(row => row.map(e => Rnl.divide(x, e))) }, - power(x, m) { return m.map(row => row.map(e => Rnl.power(x, e))) }, - rem(x, m) { return m.map(row => row.map(e => Rnl.rem(x, e))) }, - and(x, m) { return m.map(row => row.map(e => x && e)) }, - or(x, m) { return m.map(row => row.map(e => x || e)) }, - xor(x, m) { return m.map(row => row.map(e => x !== e)) }, - concat(x, m) { return errorOprnd("BAD_CONCAT") } - }, - dataFrame: { - multiply(x, df) { - df.data = df.data.map(col => isNaN(col[0]) ? col : col.map(e => { - let L = e.length; - if (e.indexOf(".")) { L -= 1; } - return Rnl.toStringSignificant(Rnl.multiply(x, Rnl.fromString(e)), L) - })); - return df - }, - divide(x, df) { - df.data = df.data.map(col => isNaN(col[0]) ? col : col.map(e => { - let L = e.length; - if (e.indexOf(".")) { L -= 1; } - return Rnl.toStringSignificant(Rnl.divide(x, Rnl.fromString(e)), L) - })); - return df - } - }, - map: { - // Binary operations with a scalar and a map. - // Perform element-wise operations. - add(scalar, map) { - map.data = map.data.map(col => Rnl.isRational(col[0]) - ? col.map(e => Rnl.add(scalar, e)) - : col - ); - return map - }, - subtract(scalar, map) { - map.data = map.data.map(col => Rnl.isRational(col[0]) - ? col.map(e => Rnl.subtract(scalar, e)) - : col - ); - return map - }, - multiply(scalar, map) { - map.data = map.data.map(col => Rnl.isRational(col[0]) - ? col.map(e => Rnl.multiply(scalar, e)) - : col - ); - return map - }, - divide(scalar, map) { - map.data = map.data.map(col => Rnl.isRational(col[0]) - ? col.map(e => Rnl.divide(scalar, e)) - : col - ); - return map - }, - power(scalar, map) { - map.data = map.data.map(col => Rnl.isRational(col[0]) - ? col.map(e => Rnl.power(scalar, e)) - : col - ); - return map - }, - rem(scalar, map) { - map.data = map.data.map(col => Rnl.isRational(col[0]) - ? col.map(e => Rnl.rem(scalar, e)) - : col - ); - return map - }, - and(scalar, map) { - map.data = map.data.map(col => typeof col[0] === "boolean" - ? col.map(e => scalar && e) - : col - ); - return map - }, - or(scalar, map) { - map.data = map.data.map(col => typeof col[0] === "boolean" - ? col.map(e => scalar || e) - : col - ); - return map - }, - xor(scalar, map) { - map.data = map.data.map(col => typeof col[0] === "boolean" - ? col.map(e => scalar !== e) - : col - ); - return map - } - } - }, - - complex: { - scalar: { - add(z, y) { return [Rnl.add(z[0], y), z[1]] }, - subtract(z, y) { return [Rnl.subtract(z[0], y), z[1]] }, - multiply(z, y) { return [Rnl.multiply(z[0], y), Rnl.multiply(z[1], y) ] }, - divide(z, y) { return Cpx.divide(z, [y, Rnl.zero]) }, - power(z, y) { return Cpx.power(z, [y, Rnl.zero]) }, - rem(z, y) { return errorOprnd("NA_COMPL_OP", "rem") }, - and(z, y) { return errorOprnd("NA_COMPL_OP", "and") }, - or(z, y) { return errorOprnd("NA_COMPL_OP", "or") }, - xor(z, y) { return errorOprnd("NA_COMPL_OP", "xor") } - }, - complex: { - add(x, y) { return [Rnl.add(x[0], y[0]), Rnl.add(x[1], y[1])] }, - subtract(x, y) { return [Rnl.subtract(x[0], y[0]), Rnl.subtract(x[1], y[1])] }, - multiply(x, y) { return Cpx.multiply(x, y) }, - divide(x, y) { return Cpx.divide(x, y) }, - power(x, y) { return Cpx.power(x, y) }, - rem(x, y) { return errorOprnd("NA_COMPL_OP", "rem") }, - and(x, y) { return errorOprnd("NA_COMPL_OP", "and") }, - or(x, y) { return errorOprnd("NA_COMPL_OP", "or") }, - xor(x, y) { return errorOprnd("NA_COMPL_OP", "xor") } - - } - }, - - vector: { - scalar: { - // Binary operations with a vector and a scalar. - // Perform element-wise operations. - add(v, x) { return v.map(e => Rnl.add(e, x)) }, - subtract(v, x) { return v.map(e => Rnl.subtract(e, x)) }, - multiply(v, x) { return v.map(e => Rnl.multiply(e, x)) }, - divide(v, x) { return v.map(e => Rnl.divide(e, x)) }, - power(v, x) { return v.map(e => Rnl.power(e, x)) }, - rem(v, x) { return v.map(e => Rnl.rem(e, x)) }, - and(v, x) { return v.map(e => e && x) }, - or(v, x) { return v.map(e => e || x) }, - xor(v, x) { return v.map(e => e !== x) }, - concat(v, x) { return [...v, x]} - } - }, - - rowVector: { - rowVector: { - // Binary operations on two row vectors. - add(x, y) { - // element-wise addition - if (x.length !== y.length) { return errorOprnd("MIS_ELNUM") } - return x.map((e, i) => Rnl.add(e, y[i])) - }, - subtract(x, y) { - if (x.length !== y.length) { return errorOprnd("MIS_ELNUM") } - return x.map((e, i) => Rnl.subtract(e, y[i])) - }, - divide(x, y) { - if (x.length !== y.length) { return errorOprnd("MIS_ELNUM") } - return x.map((e, i) => Rnl.divide(e, y[i])) - }, - dot(x, y) { - if (x.length !== y.length) { return errorOprnd("MIS_ELNUM") } - return dotProduct$1(x, y) - }, - cross(x, y) { - if (x.length !== 3 || y.length !== 3) { return errorOprnd("CROSS") } - const v = [Rnl.zero, Rnl.zero, Rnl.zero]; - v[0] = Rnl.subtract(Rnl.multiply(x[1], y[2]), Rnl.multiply(x[2], y[1])); - v[1] = Rnl.subtract(Rnl.multiply(x[2], y[0]), Rnl.multiply(x[0], y[2])); - v[2] = Rnl.subtract(Rnl.multiply(x[0], y[1]), Rnl.multiply(x[1], y[0])); - return v - }, - multiply(x, y) { - if (x.length === 1 && y.length === 1) { return [Rnl.multiply(x[0], y[0])] } - return errorOprnd("MIS_ELNUM") - }, - circ(x, y) { - // Element-wise multiplication - if (x.length !== y.length) { return errorOprnd("MIS_ELNUM") } - return x.map((e, i) => Rnl.multiply(e, y[i])) - }, - power(x, y) { - if (x.length !== y.length) { return errorOprnd("MIS_ELNUM") } - return x.map((e, i) => Rnl.power(e, y[i])) - }, - modulo(x, y) { - if (x.length !== y.length) { return errorOprnd("MIS_ELNUM") } - return x.map((e, i) => Rnl.modulo(e, y[i])) - }, - and(x, y) { - if (x.length !== y.length) { return errorOprnd("MIS_ELNUM") } - return x.map((e, i) => e && y[i]) - }, - or(x, y) { - if (x.length !== y.length) { return errorOprnd("MIS_ELNUM") } - return x.map((e, i) => e || y[i]) - }, - xor(x, y) { - if (x.length !== y.length) { return errorOprnd("MIS_ELNUM") } - return x.map((e, i) => e !== y[i]) - }, - concat(x, y) { return x.concat(y) }, - unshift(x, y) { return [x, y] } - }, - columnVector: { - // Binary operations on a row vector and a column vector. - // Except for multiplication, these work only if both vectors have only one element. - add(x, y) { - if (x.length === 1 && y.length === 1) { return [Rnl.add(x[0], y[0])] } - return errorOprnd("MIS_ELNUM") - }, - subtract(x, y) { - if (x.length === 1 && y.length === 1) { return [Rnl.subtract(x[0], y[0])] } - return errorOprnd("MIS_ELNUM") - }, - dot(x, y) { - if (x.length !== y.length) { return errorOprnd("MIS_ELNUM") } - return dotProduct$1(x, y) - }, - cross(x, y) { - if (x.length !== 3 || y.length !== 3) { return errorOprnd("CROSS") } - const v = [Rnl.zero, Rnl.zero, Rnl.zero]; - v[0] = Rnl.subtract(Rnl.multiply(x[1], y[2]), Rnl.multiply(x[2], y[1])); - v[1] = Rnl.subtract(Rnl.multiply(x[2], y[0]), Rnl.multiply(x[0], y[2])); - v[2] = Rnl.subtract(Rnl.multiply(x[0], y[1]), Rnl.multiply(x[1], y[0])); - return v - }, - multiply(x, y) { - if (x.length !== y.length) { return errorOprnd("MIS_ELNUM") } - return dotProduct$1(x, y) - }, - circ(x, y) { - if (x.length !== y.length) { return errorOprnd("MIS_ELNUM") } - return x.map((e, i) => Rnl.multiply(e, y[i])) - }, - power(x, y) { - if (x.length === 1 && y.length === 1) { return [Rnl.power(x[0], y[0])] } - return errorOprnd("MIS_ELNUM") - }, - modulo(x, y) { - if (x.length === 1 && y.length === 1) { return [Rnl.modulo(x[0], y[0])] } - return errorOprnd("MIS_ELNUM") - }, - and(x, y) { - if (x.length === 1 && y.length === 1) { return [x[0] && y[0]] } - return errorOprnd("MIS_ELNUM") - }, - or(x, y) { - if (x.length === 1 && y.length === 1) { return [x[0] || y[0]] } - return errorOprnd("MIS_ELNUM") - }, - xor(x, y) { - if (x.length === 1 && y.length === 1) { return [x[0] !== y[0]] } - return errorOprnd("MIS_ELNUM") - }, - concat(x, y) { return "BAD_CONCAT" }, - unshift(x, y) { return "BAD_CONCAT" } - }, - matrix: { - // Binary operations on a row vector and a 2-D matrix. - add(v, m) { - // Add the row vector to each row in the matrix - if (v.length !== m[0].length) { return errorOprnd("MIS_ELNUM") } - return m.map(row => row.map((e, i) => Rnl.add(v[i], e))) - }, - subtract(v, m) { - if (v.length !== m[0].length) { return errorOprnd("MIS_ELNUM") } - return m.map(row => row.map((e, i) => Rnl.subtract(v[i], e))) - }, - multiply(v, m) { - if (v.length !== m[0].length) { return errorOprnd("MIS_ELNUM") } - m = m[0].map((x, i) => m.map(y => y[i])); // Transpose m - return m.map(row => dotProduct$1(v, row)) - }, - circ(v, m) { - if (v.length !== m[0].length) { return errorOprnd("MIS_ELNUM") } - return m.map(row => row.map((e, i) => Rnl.multiply(v[i], e))) - }, - divide(v, m) { - if (v.length !== m[0].length) { return errorOprnd("MIS_ELNUM") } - return m.map(row => row.map((e, i) => Rnl.divide(v[i], e))) - }, - power(v, m) { - if (v.length !== m[0].length) { return errorOprnd("MIS_ELNUM") } - return m.map(row => row.map((e, i) => Rnl.power(v[i], e))) - }, - concat(v, m) { - if (v.length !== m[0].length) { return errorOprnd("BAD_CONCAT") } - return m.map((row, i) => [v[i], ...row]) - }, - unshift(v, m) { - if (v.length !== m[0].length) { return errorOprnd("BAD_CONCAT") } - return [v, ...m] - } - } - }, - - columnVector: { - rowVector: { - // Binary operations on a column vector and a row vector. - // Except for multiplication, these work only if both vectors have only one element. - add(x, y) { - if (x.length === 1 && y.length === 1) { return [Rnl.add(x[0], y[0])] } - return errorOprnd("MIS_ELNUM") - }, - subtract(x, y) { - if (x.length === 1 && y.length === 1) { return [Rnl.subtract(x[0], y[0])] } - return errorOprnd("MIS_ELNUM") - }, - dot(x, y) { - if (x.length !== y.length) { return errorOprnd("MIS_ELNUM") } - return dotProduct$1(x, y) - }, - cross(x, y) { - if (x.length !== 3 || y.length !== 3) { return errorOprnd("CROSS") } - const v = [Rnl.zero, Rnl.zero, Rnl.zero]; - v[0] = Rnl.subtract(Rnl.multiply(x[1], y[2]), Rnl.multiply(x[2], y[1])); - v[1] = Rnl.subtract(Rnl.multiply(x[2], y[0]), Rnl.multiply(x[0], y[2])); - v[2] = Rnl.subtract(Rnl.multiply(x[0], y[1]), Rnl.multiply(x[1], y[0])); - return v - }, - multiply(x, y) { - if (x[0].length !== y.length) { return errorOprnd("MIS_ELNUM") } - return x.map(row => y.map(e => Rnl.multiply(row, e))) - }, - divide(x, y) { - return x.map(m => y.map(e => Rnl.divide(m, e))) - }, - circ(x, y) { - if (x.length !== y.length) { return errorOprnd("MIS_ELNUM") } - return x.map((e, i) => Rnl.multiply(e, y[i])) - }, - power(x, y) { - if (x.length === 1 && y.length === 1) { return [Rnl.power(x[0], y[0])] } - return errorOprnd("MIS_ELNUM") - }, - modulo(x, y) { - if (x.length === 1 && y.length === 1) { return [Rnl.modulo(x[0], y[0])] } - return errorOprnd("MIS_ELNUM") - }, - and(x, y) { - if (x.length === 1 && y.length === 1) { return [x[0] && y[0]] } - return errorOprnd("MIS_ELNUM") - }, - or(x, y) { - if (x.length === 1 && y.length === 1) { return [x[0] || y[0]] } - return errorOprnd("MIS_ELNUM") - }, - xor(x, y) { - if (x.length === 1 && y.length === 1) { return [x[0] !== y[0]] } - return errorOprnd("MIS_ELNUM") - }, - concat(x, y) { return "BAD_CONCAT" }, - unshift(x, y) { return "BAD_CONCAT" } - }, - columnVector: { - // Binary operations on two column vectors. - add(x, y) { - // element-wise addition - if (x.length !== y.length) { return errorOprnd("MIS_ELNUM") } - return x.map((e, i) => Rnl.add(e, y[i])) - }, - subtract(x, y) { - if (x.length !== y.length) { return errorOprnd("MIS_ELNUM") } - return x.map((e, i) => Rnl.subtract(e, y[i])) - }, - divide(x, y) { - if (x.length !== y.length) { return errorOprnd("MIS_ELNUM") } - return x.map((e, i) => Rnl.divide(e, y[i])) - }, - dot(x, y) { - if (x.length !== y.length) { return errorOprnd("MIS_ELNUM") } - return dotProduct$1(x, y) - }, - cross(x, y) { - if (x.length !== 3 || y.length !== 3) { return errorOprnd("CROSS") } - const v = [Rnl.zero, Rnl.zero, Rnl.zero]; - v[0] = Rnl.subtract(Rnl.multiply(x[1], y[2]), Rnl.multiply(x[2], y[1])); - v[1] = Rnl.subtract(Rnl.multiply(x[2], y[0]), Rnl.multiply(x[0], y[2])); - v[2] = Rnl.subtract(Rnl.multiply(x[0], y[1]), Rnl.multiply(x[1], y[0])); - return v - }, - multiply(x, y) { - if (x.length === 1 && y.length === 1) { return [Rnl.multiply(x[0], y[0])] } - return errorOprnd("MIS_ELNUM") - }, - circ(x, y) { - // Element-wise multiplication - if (x.length !== y.length) { return errorOprnd("MIS_ELNUM") } - return x.map((e, i) => Rnl.multiply(e, y[i])) - }, - power(x, y) { - if (x.length !== y.length) { return errorOprnd("MIS_ELNUM") } - return x.map((e, i) => Rnl.power(e, y[i])) - }, - rem(x, y) { - if (x.length !== y.length) { return errorOprnd("MIS_ELNUM") } - return x.map((e, i) => Rnl.rem(e, y[i])) - }, - and(x, y) { - if (x.length !== y.length) { return errorOprnd("MIS_ELNUM") } - return x.map((e, i) => e && y[i]) - }, - or(x, y) { - if (x.length !== y.length) { return errorOprnd("MIS_ELNUM") } - return x.map((e, i) => e || y[i]) - }, - xor(x, y) { - if (x.length !== y.length) { return errorOprnd("MIS_ELNUM") } - return x.map((e, i) => e !== y[i]) - }, - concat(x, y) { - if (x.length !== y.length) { return errorOprnd("MIS_ELNUM") } - return x.map((e, i) => [e, y[i]]) - }, - unshift(x, y) { return x.concat(y) } - }, - matrix: { - // Binary operations on a column vector and a 2-D matrix. - add(v, m) { - if (v.length !== m.length) { return errorOprnd("MIS_ELNUM") } - return m.map((row, i) => row.map(e => Rnl.add(v[i], e))) - }, - subtract(v, m) { - if (v.length !== m.length) { return errorOprnd("MIS_ELNUM") } - return m.map((row, i) => row.map(e => Rnl.subtract(v[i], e))) - }, - multiply(v, m) { - if (m.length !== 1) { return errorOprnd("MIS_ELNUM") } - return m.map((row, i) => row.map(e => Rnl.multiply(v[i], e))) - }, - circ(v, m) { - if (v.length !== m.length) { return errorOprnd("MIS_ELNUM") } - return m.map((row, i) => row.map(e => Rnl.multiply(v[i], e))) - }, - divide(v, m) { - if (v.length !== m.length) { return errorOprnd("MIS_ELNUM") } - return m.map((row, i) => row.map(e => Rnl.divide(v[i], e))) - }, - power(v, m) { - if (v.length !== m.length) { return errorOprnd("MIS_ELNUM") } - return m.map((row, i) => row.map(e => Rnl.power(v[i], e))) - }, - concat(v, m) { - if (v.length !== m.length) { return errorOprnd("MIS_ELNUM") } - return m.map((row, i) => [v[i], ...row]) - }, - unshift(x, y) { return "BAD_CONCAT" } - }, - map: { - // Binary operations between a column vector and a map - add(vector, map) { - map.data = map.data.map(col => Rnl.isRational(col[0]) - ? col.map((e, i) => Rnl.add(vector[i], e)) - : col - ); - return map - }, - subtract(vector, map) { - map.data = map.data.map(col => Rnl.isRational(col[0]) - ? col.map((e, i) => Rnl.subtract(vector[i], e)) - : col - ); - return map - }, - multiply(vector, map) { - map.data = map.data.map(col => Rnl.isRational(col[0]) - ? col.map((e, i) => Rnl.multiply(vector[i], e)) - : col - ); - return map - }, - divide(vector, map) { - map.data = map.data.map(col => Rnl.isRational(col[0]) - ? col.map((e, i) => Rnl.divide(vector[i], e)) - : col - ); - return map - }, - power(vector, map) { - map.data = map.data.map(col => Rnl.isRational(col[0]) - ? col.map((e, i) => Rnl.power(vector[i], e)) - : col - ); - return map - }, - rem(vector, map) { - map.data = map.data.map(col => Rnl.isRational(col[0]) - ? col.map((e, i) => Rnl.rem(vector[i], e)) - : col - ); - return map - }, - and(vector, map) { - map.data = map.data.map(col => typeof col[0] === "boolean" - ? col.map((e, i) => vector[i] && e) - : col - ); - return map - }, - or(vector, map) { - map.data = map.data.map(col => typeof col[0] === "boolean" - ? col.map((e, i) => vector[i] || e) - : col - ); - return map - }, - xor(vector, map) { - map.data = map.data.map(col => typeof col[0] === "boolean" - ? col.map((e, i) => vector[i] !== e) - : col - ); - return map - } - } - }, - - matrix: { - scalar: { - // Binary operations with a matrix and a scalar. - // Perform element-wise operations. - add(m, x) { return m.map(row => row.map(e => Rnl.add(e, x))) }, - subtract(m, x) { return m.map(row => row.map(e => Rnl.subtract(e, x))) }, - multiply(m, x) { return m.map(row => row.map(e => Rnl.multiply(e, x))) }, - divide(m, x) { return m.map(row => row.map(e => Rnl.divide(e, x))) }, - power(m, x) { - if (m.length === m[0].length && Rnl.areEqual(x, [BigInt(-1), BigInt(1)])) { - return Matrix.invert(m) - } - return m.map(row => row.map(e => Rnl.power(e, x))) - }, - rem(m, x) { return m.map(row => row.map(e => Rnl.rem(e, x))) } - }, - rowVector: { - add(m, v) { return m.map(row => row.map((e, i) => Rnl.add(e, v[i]) )) }, - subtract(m, v) { return m.map(row => row.map((e, i) => Rnl.subtract(e, v[i]) )) }, - multiply(m, v) { return m.map(row => row.map((e, i) => Rnl.multiply(e, v[i]) )) }, - circ(m, v) { return m.map(row => row.map((e, i) => Rnl.multiply(e, v[i]) )) }, - divide(m, v) { return m.map(row => row.map((e, i) => Rnl.divide(e, v[i]) )) }, - power(m, v) { return m.map(row => row.map((e, i) => Rnl.power(e, v[i]) )) }, - modulo(m, v) { return m.map(row => row.map((e, i) => Rnl.modulo(e, v[i]) )) }, - unshift(m, v) { - if (m[0].length !== v.length) { return errorOprnd("MIS_ELNUM") } - return [...m, v] - } - }, - columnVector: { - add(m, v) { return m.map((row, i) => row.map(e => Rnl.add(e, v[i]) )) }, - subtract(m, v) { return m.map((row, i) => row.map(e => Rnl.subtract(e, v[i]) )) }, - multiply(m, v) { - // Multiply a matrix times a column vector - if (m[0].length !== v.length) { return errorOprnd("MIS_ELNUM") } - return m.map(row => dotProduct$1(row, v)) - }, - circ(m, v) { return m.map((row, i) => row.map(e => Rnl.multiply(e, v[i]) )) }, - divide(m, v) { return m.map((row, i) => row.map(e => Rnl.divide(e, v[i]) )) }, - power(m, v) { return m.map((row, i) => row.map(e => Rnl.power(e, v[i]) )) }, - rem(m, v) { return m.map((row, i) => row.map(e => Rnl.rem(e, v[i]) )) }, - concat(m, v) { - if (m.length !== v.length) { return errorOprnd("MIS_ELNUM") } - return m.map((row, i) => [...row, v[i]]) - } - }, - matrix: { - // Binary operations on two 2-D matrices. - add(x, y) { - if (x.length !== y.length) { return errorOprnd("MIS_ELNUM") } - if (x[0].length !== y[0].length) { return errorOprnd("MIS_ELNUM") } - return x.map((m, i) => m.map((n, j) => Rnl.add(n, y[i][j]))) - }, - subtract(x, y) { - if (x.length !== y.length) { return errorOprnd("MIS_ELNUM") } - if (x[0].length !== y[0].length) { return errorOprnd("MIS_ELNUM") } - return x.map((m, i) => m.map((n, j) => Rnl.subtract(n, y[i][j]))) - }, - dot(x, y) { - if (x.length !== y.length) { return errorOprnd("MIS_ELNUM") } - if (x[0].length !== y[0].length) { return errorOprnd("MIS_ELNUM") } - return x.map((row, i) => dotProduct$1(row, y[i])).reduce((m, n) => Rnl.add(m, n)) - }, - cross(x, y) { - return errorOprnd("CROSS") - }, - multiply(x, y) { - - }, - circ(x, y) { - // Element-wise multiplication - if (x.length !== y.length) { return errorOprnd("MIS_ELNUM") } - if (x[0].length !== y[0].length) { return errorOprnd("MIS_ELNUM") } - return x.map((m, i) => m.map((n, j) => Rnl.multiply(n, y[i][j]))) - }, - divide(x, y) { - if (x.length !== y.length) { return errorOprnd("MIS_ELNUM") } - if (x[0].length !== y[0].length) { return errorOprnd("MIS_ELNUM") } - return x.map((m, i) => m.map((n, j) => Rnl.divide(n, y[i][j]))) - }, - power(x, y) { - if (x.length !== y.length) { return errorOprnd("MIS_ELNUM") } - if (x[0].length !== y[0].length) { return errorOprnd("MIS_ELNUM") } - return x.map((m, i) => m.map((n, j) => Rnl.power(n, y[i][j]))) - }, - rem(x, y) { - if (x.length !== y.length) { return errorOprnd("MIS_ELNUM") } - if (x[0].length !== y[0].length) { return errorOprnd("MIS_ELNUM") } - return x.map((m, i) => m.map((n, j) => Rnl.rem(n, y[i][j]))) - }, - and(x, y) { - if (x.length !== y.length) { return errorOprnd("MIS_ELNUM") } - if (x[0].length !== y[0].length) { return errorOprnd("MIS_ELNUM") } - return x.map((m, i) => m.map((n, j) => n && y[i][j])) - }, - or(x, y) { - if (x.length !== y.length) { return errorOprnd("MIS_ELNUM") } - if (x[0].length !== y[0].length) { return errorOprnd("MIS_ELNUM") } - return x.map((m, i) => m.map((n, j) => n || y[i][j])) - }, - xor(x, y) { - if (x.length !== y.length) { return errorOprnd("MIS_ELNUM") } - if (x[0].length !== y[0].length) { return errorOprnd("MIS_ELNUM") } - return x.map((m, i) => m.map((n, j) => n !== y[i][j])) - }, - concat(x, y) { - if (x.length !== y.length) { return errorOprnd("MIS_ELNUM") } - return x.map((row, i) => row.concat(y[i])) - }, - unshift(x, y) { - if (x[0].length !== y[0].length) { return errorOprnd("MIS_ELNUM") } - return x.concat(y) - } - }, - map: { - - } - }, - - dataFrame: { - multiply(df, scalar) { - df.data = df.data.map(col => isNaN(col[0]) ? col : col.map(e => { - let L = e.length; - if (e.indexOf(".")) { L -= 1; } - return Rnl.toStringSignificant(Rnl.multiply(scalar, Rnl.fromString(e)), L) - })); - return df - }, - divide(df, scalar) { - df.data = df.data.map(col => isNaN(col[0]) ? col : col.map(e => { - let L = e.length; - if (e.indexOf(".")) { L -= 1; } - return Rnl.toStringSignificant(Rnl.divide(scalar, Rnl.fromString(e)), L) - })); - return df - } - }, - - map: { - scalar: { - // Binary opertions on a map and a scalar - add(map, scalar) { - map.data = map.data.map(col => Rnl.isRational(col[0]) - ? col.map(e => Rnl.add(e, scalar)) - : col - ); - return map - }, - subtract(map, scalar) { - map.data = map.data.map(col => Rnl.isRational(col[0]) - ? col.map(e => Rnl.subtract(e, scalar)) - : col - ); - return map - }, - multiply(map, scalar) { - map.data = map.data.map(col => Rnl.isRational(col[0]) - ? col.map(e => Rnl.multiply(e, scalar)) - : col - ); - return map - }, - divide(map, scalar) { - map.data = map.data.map(col => Rnl.isRational(col[0]) - ? col.map(e => Rnl.divide(e, scalar)) - : col - ); - return map - }, - power(map, scalar) { - map.data = map.data.map(col => Rnl.isRational(col[0]) - ? col.map(e => Rnl.power(e, scalar)) - : col - ); - return map - }, - rem(map, scalar) { - map.data = map.data.map(col => Rnl.isRational(col[0]) - ? col.map(e => Rnl.rem(e, scalar)) - : col - ); - return map - }, - and(map, scalar) { - map.data = map.data.map(col => typeof col[0] === "boolean" - ? col.map(e => e && scalar) - : col - ); - return map - }, - or(map, scalar) { - map.data = map.data.map(col => typeof col[0] === "boolean" - ? col.map(e => e || scalar) - : col - ); - return map - }, - xor(map, scalar) { - map.data = map.data.map(col => typeof col[0] === "boolean" - ? col.map(e => e !== scalar) - : col - ); - return map - } - }, - columnVector: { - add(map, vector) { - map.data = map.data.map(col => Rnl.isRational(col[0]) - ? col.map((e, i) => Rnl.add(e, vector[i])) - : col - ); - return map - }, - subtract(map, vector) { - map.data = map.data.map(col => Rnl.isRational(col[0]) - ? col.map((e, i) => Rnl.subtract(e, vector[i])) - : col - ); - return map - }, - multiply(map, vector) { - map.data = map.data.map(col => Rnl.isRational(col[0]) - ? col.map((e, i) => Rnl.multiply(e, vector[i])) - : col - ); - return map - }, - divide(map, vector) { - map.data = map.data.map(col => Rnl.isRational(col[0]) - ? col.map((e, i) => Rnl.divide(e, vector[i])) - : col - ); - return map - }, - power(map, vector) { - map.data = map.data.map(col => Rnl.isRational(col[0]) - ? col.map((e, i) => Rnl.power(e, vector[i])) - : col - ); - return map - }, - rem(map, vector) { - map.data = map.data.map(col => Rnl.isRational(col[0]) - ? col.map((e, i) => Rnl.rem(e, vector[i])) - : col - ); - return map - }, - and(map, vector) { - map.data = map.data.map(col => typeof col[0] === "boolean" - ? col.map((e, i) => e && vector[i]) - : col - ); - return map - }, - or(map, vector) { - map.data = map.data.map(col => typeof col[0] === "boolean" - ? col.map((e, i) => e || vector[i]) - : col - ); - return map - }, - xor(map, vector) { - map.data = map.data.map(col => typeof col[0] === "boolean" - ? col.map((e, i) => e !== vector[i]) - : col - ); - return map - } - }, - matrix: { - - }, - map: { - - } - } -}; - -// Binary relations get their own object, separate from other binary operations. -// That's because Hurmet allows chained comparisons, as in a < b < c. -// So we have to pass yPrev as well as the two current operands. - -const strOps = ["∈", "in", "∋", "⊇", "∉", "!in", "∌", "⊈", "⊉"]; - -const relations = { - scalar: { - scalar: { - relate(op, x, y, yPrev) { return compare(op, x, y, yPrev) } - }, - vector: { - relate(op, x, v, yPrev) { - if (yPrev === undefined) { - return v.map(e => compare(op, x, e, undefined)) - } else if (typeof yPrev !== "object") { - return v.map(e => compare(op, x, e, yPrev)) - } else if (Array.isArray(yPrev)) { - return v.map((e, i) => compare(op, x, e, yPrev[i])) - } else ; - } - }, - matrix: { - relate(op, x, m, yPrev) { - if (yPrev === undefined) { - return m.map(row => row.map(e => compare(op, x, e, undefined))) - } else if (typeof yPrev !== "object") { - return m.map(row => row.map(e => compare(op, x, e, yPrev))) - } else if (Array.isArray(yPrev)) { - return m.map((row, i) => row.map((e, j) => compare(op, x, e, yPrev[i][j]))) - } else ; - } - }, - map: { - relate(op, x, map, yPrev) { - if (yPrev === undefined) { - map.data = map.data.map((column, j) => - j > 0 || typeof column[0] !== "string" || strOps.includes(op) - ? column.map(e => compare(op, x, e, undefined)) - : column - ); - return map - } - } - } - }, - vector: { - scalar: { - relate(op, v, y, yPrev) { - if (yPrev === undefined) { - return v.map(e => compare(op, e, y, undefined)) - } else if (typeof yPrev !== "object") { - return v.map(e => compare(op, e, y, yPrev)) - } else if (Array.isArray(yPrev)) { - return v.map((e, i) => compare(op, e, y, yPrev[i])) - } else ; - } - } - }, - rowVector: { - rowVector: { - relate(op, x, y, yPrev) { - if (yPrev === undefined) { - return x.map((e, i) => compare(op, e, y[i], undefined)) - } - } - }, - matrix: { - relate(op, v, m, yPrev) { - if (yPrev === undefined) { - if (v.length !== m[0].length) { return errorOprnd("MIS_ELNUM") } - return m.map(row => row.map((e, i) => compare(op, v[i], e, undefined))) - } - } - } - }, - columnVector: { - columnVector: { - relate(op, x, y, yPrev) { - if (yPrev === undefined) { - return x.map((e, i) => compare(op, e, y[i], undefined)) - } - } - }, - map: { - relate(op, v, map, yPrev) { - if (yPrev === undefined) { - map.data = map.data.map((column, j) => - j > 0 || typeof column[0] !== "string" || strOps.includes(op) - ? column.map((e, i) => compare(op, v[i], e, undefined)) - : column - ); - return map - } - } - } - }, - matrix: { - scalar: { - relate(op, m, y, yPrev) { - if (yPrev === undefined) { - return m.map(row => row.map(e => compare(op, e, y, undefined))) - } else if (typeof yPrev !== "object") { - return m.map(row => row.map(e => compare(op, e, y, yPrev))) - } else if (Array.isArray(yPrev)) { - return m.map((row, i) => row.map((e, j) => compare(op, e, y, yPrev[i][j]))) - } else ; - } - }, - matrix: { - relate(op, m1, m2, yPrev) { - if (yPrev === undefined) { - return m1.map((e, i) => compare(op, e, m2[i], undefined)) - } - } - } - } -}; - -const isDivByZero = (quotient, shape) => { - switch (shape) { - case "scalar": - return quotient[1] === BigInt(0) - case "vector": - for (let i = 0; i < quotient.length; i++) { - if (quotient[i][1] === BigInt(0)) { return true } - } - return false - case "matrix": - for (let i = 0; i < quotient.length; i++) { - for (let j = 0; j < quotient[0].length; j++) { - if (quotient[i][j][1] === BigInt(0)) { return true } - } - } - return false - case "map": - for (let j = 0; j < quotient.data[0].length; j++) { - if (Rnl.isRational(quotient.data[j][0])) { - for (let i = 0; i < quotient.data.length; i++) { - if (quotient.data[i][j][1] === BigInt(0)) { return true } - } - } - } - return false - default: - return false - } -}; - -const Operators = Object.freeze({ - unary, - binary, - relations, - condition, - dtype -}); - -const wideCharRegEx = /[\uD800-\uDBFF][\uDC00-\uDFFF][\uFE00\uFE01]?/g; - -const findfirst = (searchString, str) => { - const index = str.value.indexOf(searchString.value); - const wideCharMatches = arrayOfRegExMatches(wideCharRegEx, str.value.slice(0, index)); - return Rnl.fromNumber(index + wideCharMatches.length + 1) -}; - -const textRange = (str, index) => { - // Find a range of the string str - if (index.dtype !== dt.RATIONAL && index.dtype !== dt.RANGE) { - return errorOprnd("STR_INDEX") - } - - const strArray = Array.from(str); - let value = ""; - if (index.dtype === dt.RATIONAL) { - const pos = Rnl.toNumber(index.value) - 1; - value = strArray.at(pos); - } else if (index.dtype === dt.RANGE) { - const start = Rnl.toNumber(index.value[0]); - const step = Rnl.toNumber(index.value[1]); - const end = index.value[2] === "∞" - ? str.length - : Rnl.toNumber(index.value[2]); - if (step === 1) { - value = strArray.slice(start - 1, end).join(""); - } else { - for (let i = start - 1; i < end; i += step) { - value += strArray.at(i); - } - - } - } - - return { value, unit: null, dtype: dt.STRING } -}; - -/** - * md2ast() returns an AST that matches the memory structure of a Hurmet.org document. - * Elsewhere, Hurmet uses the AST to create either a live Hurmet doc or a static HTML doc. - * - * ## Restrictions - * - * 1. **_bold-italic_** must use both * & _ delimiters. Hurmet will fail on ***wat***. - * 2. "Shortcut" reference links [ref] are not recognized. - * - * ## Extensions - * - * 1. Hurmet inline calculation is delimited ¢`…`. - * Hurmet display calculation is delimited ¢¢…¢¢. - * 2. LaTeX inline math is delimited $…$. - * No space allowed after 1st $ or before 2nd $. No digit after 2nd $. - * LaTeX display math is delimited $$ … $$. - * 3. ~subscript~ - * 4. ~~strikethrough~~ - * 5. Pipe tables as per Github Flavored Markdown (GFM). - * 6. Grid tables as per Pandoc and reStructuredText - * 7. Empty paragraphs: A line consisting only of "¶". - * 8. Attributes for reference link definitions - * [id]: target - * {.class #id width=number} - * 9. Figure/Caption for images. Format is a paragraph that consists entirely of: - * !![caption][id] - * 10. Table directives. They are placed on the line after the table. The format is: - * {.class #id width="num1 num2 …" caption} - * 11. 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) - * 12. Alerts per GFM - * > [!note] or [!tip] or [!important] or [!warning] or [!epigraph] - * > Content of note - * 13. Fenced divs, similar to Pandoc. - * ::: (centered|right_justified|comment|indented|boxed|header) - * Block elements - * ::: - * Nested divs are distinguished by number of colons. Minimum three. - * 14. Table of Contents - * {.toc start=N end=N} - * 15. Definition lists, per Pandoc. (future) - * 16. [^1] is a reference to a footnote. - * [^1]: The body of the footnote is deferred, similar to reference links. - * 17. [#1] is a reference to a citation. (future) - * [#1]: The body of the citation is deferred, similar to reference links. - * 18. Line blocks begin with "| ", as per Pandoc. (future) - * - * hurmetMark.js copyright (c) 2021 - 2023 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 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-]+)(?: |$)/; -const leadingSpaceRegEx$1 = /^ +/; -const trailingSpaceRegEx = / +$/; - -// Turn various whitespace into easy-to-process whitespace -const preprocess = function(source) { - return source.replace(CR_NEWLINE_R, "\n").replace(FORMFEED_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 = !/\n\n/.test(str.replace(/\n*$/, "")); - 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 contentStr = 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 = contentStr.replace(LIST_ITEM_END_R, ""); - const content = parse(adjustedContent, state); - const result = isTight - ? { type: "tight_list_item", content: [{ "type": "paragraph", "content": content }] } - : { type: "list_item", content }; - - // 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 pipeRegEx = /(? 0 && tableRow[i - 1].type === "tableSeparator") { - node.text = node.text.replace(leadingSpaceRegEx$1, ""); - } - if (i < tableRow.length - 1) { - node.text = node.text.replace(trailingSpaceRegEx, ""); - } - } - 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; } - if (colWidths && state.inHtml) { - let sum = 0; - colWidths.forEach(el => { sum += Number(el); } ); - table.attrs.style = `width: ${sum}px`; - const colGroup = { type: "colGroup", content: [] }; - for (const width of colWidths) { - colGroup.content.push({ type: "col", attrs: [{ style: `width: ${width}px` }] }); - } - table.content.push(colGroup); - } - if (!/^\|+$/.test(capture[1])) { - 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 gridSplit = / *\n/g; - const cellCornerRegEx = /^\+[-=:]+\+[+=:-]+\+$/g; - - const parseGridTable = function() { - return function(capture, state) { - const topBorder = capture[2]; - const lines = capture[1].slice(0, -1).split(gridSplit); - - // 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 - } - } - - // Get column justification - const alignrow = headerExists ? lines[headerSepLine] : topBorder.slice(1); - const align = parseTableAlign(alignrow); - const [myClass, myID, colWidths] = tableDirectives(capture[3], align); - - // Read the top & left borders to find a first draft of cell corner locations. - const colSeps = [0]; - for (let j = 1; j < topBorder.length; j++) { - if (topBorder.charAt(j) === "+") { colSeps.push(j); } - } - const rowSeps = [0]; - for (let i = 1; i < lines.length; i++) { - if (lines[i].charAt(0) === "+") { rowSeps.push(i); } - } - - // Look for the cell corner locations that don't appear on top or left border - let rowSepIndex = 0; - while (rowSepIndex < rowSeps.length) { - // Find the next row separator - let nextRow = 0; - const isValid = new Array(colSeps.length).fill(true); - for (let i = rowSeps[rowSepIndex] + 1; i < lines.length; i++) { - for (let k = 0; k < colSeps.length; k++) { - if (!isValid[k]) { continue } - if ("+|".indexOf(lines[i][colSeps[k]]) === -1) { isValid[k] = false; continue } - if (lines[i][colSeps[k]] === "+") { - nextRow = i; - break - } - } - if (nextRow !== 0) { break } - } - if (!rowSeps.includes(nextRow)) { - rowSeps.splice(rowSepIndex + 1, 0, nextRow); - } - - // Check the next horizontal border for new cell corners - rowSepIndex += 1; - const border = lines[nextRow]; - for (let j = 0; j < colSeps.length - 1; j++) { - let cellBorder = border.slice(colSeps[j], colSeps[j + 1] + 1); - if (cellCornerRegEx.test(cellBorder)) { - cellBorder = cellBorder.slice(1, -1); - let pos = cellBorder.indexOf("+") + 1; - let k = 1; - while (pos > 0) { - colSeps.splice(j + k, 0, colSeps[j] + pos); - pos = cellBorder.indexOf("+", pos) + 1; - k += 1; - } - } - } - } - - const numCols = colSeps.length - 1; - const numRows = rowSeps.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[rowSeps[i + 1] - 1]; - for (let k = j + 1; k < colSeps.length; k++) { - if (lastTextRow.charAt(colSeps[k]) === "|") { break } - cell.colspan += 1; - row[k].rowspan = 0; - } - for (let k = i + 1; k < rowSeps.length; k++) { - const ch = lines[rowSeps[k]].charAt(colSeps[j] + 1); - if ("-=:".indexOf(ch) > -1) { 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 = colSeps[j] + 2; - const xEnd = colSeps[j + cell.colspan] - 1; - const yStart = rowSeps[i] + 1; - const yEnd = rowSeps[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. - const cellWidth = cell.colspan === 0 ? null : []; - for (let k = 0; k < cell.colspan; k++) { - cellWidth.push(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; } - let k = 0; - if (colWidths && state.inHtml) { - let sum = 0; - colWidths.forEach(el => { sum += Number(el); } ); - table.attrs.style = `width: ${sum}px`; - const colGroup = { type: "colGroup", attrs: null, content: [] }; - for (const width of colWidths) { - colGroup.content.push({ type: "col", attrs: [{ style: `width: ${width}px` }] }); - } - table.content.push(colGroup); - k = 1; - } - 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 = parse(cell.blob, state); - if (state.inHtml && content.length === 1 && content[0].type === "paragraph") { - content = content[0].content; - } - if (content.length === 1 && content[0].type === "null") { - content = [{ type: "paragraph", content: [] }]; - } - table.content[i + k].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 } - } -}; - -// Pattern to find Hurmet calculation results. -// This will be replaced in the entry with the display selector. -const resultRegEx = /〔[^〕]*〕/; - -const parseRef = function(capture, state, refNode) { - // Handle implicit refs: [title][], ![alt or caption][] - let ref = capture[2] ? capture[2] : capture[1]; - ref = ref.replace(/\s+/g, " "); - - // We store defs in state._defs (_ to deconflict with client-defined state). - if (state._defs && state._defs[ref]) { - const def = state._defs[ref]; - if (refNode.type === "figure") { - refNode = { type: "figure", content: [ - { type: "figimg", attrs: def.attrs }, - { type: "figcaption", content: parseInline(refNode.attrs.alt, state) } - ] }; - refNode.content[0].attrs.src = def.target; - } else if (refNode.type === "image") { - if (def.target.indexOf("\n") > -1) { - refNode = { type: "calculation", attrs: { entry: def.target } }; - } else { - refNode.attrs = def.attrs; - refNode.attrs.src = def.target; - } - } else { - // refNode is a link - refNode.attrs.href = def.target; - } - } - return refNode; -}; - -const parseTextMark = (capture, state, mark) => { - const text = parseInline(capture, state); - if (Array.isArray(text) && text.length === 0) { return text } - consolidate(text); - for (const range of text) { - if (range.marks) { - range.marks.push({ type: mark }); - } else { - range.marks = [{ type: mark }]; - } - } - return text -}; - -const BLOCK_HTML = /^ *(?:<(head|h[1-6]|p|pre|script|style|table)[\s>][\s\S]*?(?:<\/\1>[^\n]*\n)|<(?:\/?(?:!DOCTYPE html|body|li|br|hr|(?:div|article|details|input|label|ul|ol|dl|main|nav)(?: (?:class|for|id|style|type)=(["'])[A-Za-z0-9_.:;\- ]+\2){0,2})|\/?html(?: lang=(["'])[a-z]+\3)?)>[^\n]*?(?:\n|$))/; - -// 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("htmlComment", { - isLeaf: true, - match: blockRegex(/^ *[^\n]*\n/), - parse: function(capture, state) { - return { type: "null" } - } -}), -rules.set("lheading", { - isLeaf: false, - match: blockRegex(/^([^\n]+)\n *(=|-){3,} *(?:\n *)+\n/), - parse: function(capture, state) { - return { - type: "heading", - attrs: { level: capture[2] === '=' ? 1 : 2 }, - content: parseInline(capture[1].trim(), state) - }; - } -}); -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("codeBlock", { - isLeaf: true, - match: blockRegex(/^(?:(?:\t| {4})[^\n]+\n*)+(?:\n *)+\n/), - parse: function(capture, state) { - const content = capture[0].replace(/^(\t| {4})/gm, '').replace(/\n+$/, ''); - return { - type: "code_block", - content: [{ type: "text", text: content }] - }; - } -}); -rules.set("fence", { - isLeaf: true, - match: blockRegex(/^(```|~~~) *(?:(\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("alert", { - isLeaf: false, - match: blockRegex(/^(?: *> \[!(NOTE|TIP|IMPORTANT|WARNING|EPIGRAPH)\])((?:\n *>(?! *\[!)[^\n]*)+)(?:\n *)+\n/), - // Alert for note |tip | important | warning |epigraph - parse: function(capture, state) { - const cap = capture[2].replace(/\n *> ?/gm, "\n").replace(/^\n/, ""); - const content = parse(cap, state); - return { type: capture[1].toLowerCase(), content } - } -}); -rules.set("blockquote", { - isLeaf: false, - match: blockRegex(/^>([^\n]*(?:\n *>[^\n]*)*)(?:\n *)+\n/), - parse: function(capture, state) { - const content = capture[1].replace(/\n *> ?/gm, "\n"); - return { content: parse(content, state) }; - } -}); -rules.set("ordered_list", { - isLeaf: false, - // Hurmet accepts lists w/o a preceding blank line, so the list RegEx - // is an anyScopeRegex. parse() will test if a list is a the beginning of a line. - match: anyScopeRegex(/^( {0,3})(\d{1,9}[.)]) [\s\S]+?(?:\n{2,}(?! )(?!\1(?:\d{1,9}\.) )\n*|\s*$)/), - parse: function(capture, state) { - const start = Number(capture[2].replace(/\) *$/, "").trim()); - return { attrs: { order: start }, content: parseList(capture[0], state, capture[1]) } - } -}); -rules.set("bullet_list", { - isLeaf: false, - // See note above re: anyScopeRegex - match: anyScopeRegex(/^( {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(/^(:{3,}) ?(indented|comment|centered|right_justified|boxed|header|hidden) *\n([\s\S]+?)\n+\1 *(?:\n{2,}|\s*$)/), - // indented or centered or right-justified or boxed or comment div, or
- parse: function(capture, state) { - const content = parse(capture[3], state); - return { type: capture[2], content }; - } -}); -rules.set("figure", { - isLeaf: true, - match: blockRegex(/^!!\[((?:(?:\\[\s\S]|[^\\])+?)?)\]\[([^\]]*)\] *(?:\n *)+\n/), - parse: function(capture, state) { - return parseRef(capture, state, { - type: "figure", - attrs: { alt: capture[1] } - }); - } -}); -rules.set("def", { - isLeaf: true, - match: blockRegex(/^\[([^\]\n]+)\]: *(?:¢(`+)([\s\S]*?[^`])\2(?!`)|]*)>? *(?:\n\{([^\n}]*)\})?)/), - // Link reference definitions were handled in md2ast(). - parse: function(capture, state) { return { type: "null" } } -}); -rules.set("toc", { - isLeaf: true, - match: blockRegex(/^{\.toc start=(\d) end=(\d)}\n/), - parse: function(capture, state) { - return { attrs: { start: Number(capture[1]), end: Number(capture[2]), body: [] } } - } -}); -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("displayTeX", { - isLeaf: true, - match: blockRegex(/^\$\$\n?((?:\\[\s\S]|[^\\])+?)\n?\$\$ *(?:\n|$)/), - parse: function(capture, state) { - const tex = capture[1].trim(); - return { type: "tex", attrs: { tex, displayMode: true } } - } -}); -rules.set("newline", { - isLeaf: true, - match: blockRegex(/^(?:\n *)*\n/), - parse: function() { return { type: "null" } } -}); -rules.set("emptyParagraph", { - isLeaf: true, - match: blockRegex(/^¶(?:\n *)+\n/), - parse: function(capture, state) { - return { type: "paragraph", content: [] } - } -}); -rules.set("paragraph", { - isLeaf: false, - match: blockRegex(/^((?:[^\n]|\n(?! *\n))+)(?:\n *)+\n/), - parse: function(capture, state) { - return { type: "paragraph", 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("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 defIndex = capture[2] ? capture[2] : capture[1]; - const textNode = parseTextMark(capture[1], state, "link" )[0]; - const i = linkIndex(textNode.marks); - textNode.marks[i].attrs = { href: state._defs[defIndex].target }; - return textNode - } -}); -rules.set("footnote", { - isLeaf: true, - match: inlineRegex(/^\[\^(\d+)\]/), - parse: function(capture, state) { - const index = Number(capture[1]) - 1; - return { type: "footnote", content: parseInline(state.footnotes[index], state) } - } -}); -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("autolink", { - isLeaf: true, - match: inlineRegex(/^<([^: >]+:\/[^ >]+)>/), - parse: function(capture, state) { - const textNode = parseTextMark(capture[1], state, "link" )[0]; - const i = linkIndex(textNode.marks); - textNode.marks[i].attrs = { href: unescapeUrl(capture[1]) }; - return textNode - } -}); -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" }] }] - } -}); -rules.set("tex", { - isLeaf: true, - match: inlineRegex(/^(?:\$\$((?:\\[\s\S]|[^\\])+?)\$\$|\$(?!\s|$)((?:(?:\\[\s\S]|[^\\])+?)?)(?<=[^\s\\$])\$(?![0-9$]))/), - parse: function(capture, state) { - if (capture[1]) { - const tex = capture[1].trim(); - return { type: "tex", attrs: { tex, displayMode: true } } - } else { - const tex = capture[2].trim(); - return { type: "tex", attrs: { tex, displayMode: false } } - } - } -}); -rules.set("calculation", { - isLeaf: true, - match: anyScopeRegex(/^(?:¢(\?\?|\?|%%|%|@@|@)?(`+)([\s\S]*?[^`])\2(?!`)|¢¢(\?\?|\?|%%|%|@@|@)?\n?((?:\\[\s\S]|[^\\])+?)\n?¢¢)/), - parse: function(capture, state) { - if (capture[3]) { - let entry = capture[3].trim(); - if (capture[1]) { - entry = entry.replace(resultRegEx, capture[1]); - } - if (!/^(?:function|draw\()/.test(entry) && entry.indexOf("``") === -1) { - entry = entry.replace(/\n/g, " "); - } - return { attrs: { entry } } - } else { - let entry = capture[5].trim(); - if (capture[4]) { - entry = entry.replace(resultRegEx, capture[4]); - } - return { attrs: { entry, displayMode: true } } - } - } -}); -rules.set("em", { - isLeaf: true, - match: inlineRegex(/^([_*])(?!\s|\1)((?:\\[\s\S]|[^\\])+?)\1/), - parse: function(capture, state) { - return parseTextMark(capture[2], state, "em" ) - } -}); -rules.set("strong", { - isLeaf: true, - match: inlineRegex(/^(\*\*|__)(?=\S)((?:\\[\s\S]|[^\\])+?)\1/), - parse: function(capture, state) { - return parseTextMark(capture[2], state, "strong" ) - } -}); -rules.set("del", { - isLeaf: true, - match: inlineRegex(/^([\s\S]*?)<\/del>/), - parse: function(capture, state) { - return parseTextMark(capture[1], state, "strikethru" ) - } -}); -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("tilde", { - isLeaf: true, - match: inlineRegex(/^~((?:\\[\s\S]|[^\\])+?)~/), - 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(/^(\\| {2})\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(/^|\\\-+=![({$¢¶<~+:]|\n\n| {2,}\n|\d+[.)]|\w+:\S|$)/), - parse: function(capture, state) { - return { - text: capture[0].replace(/\n/g, " ") - }; - } -}); - -const lists = ["bullet_list", "ordered_list"]; -const LIST_LOOKBEHIND_R = /(?:\n)( *)$/; - -const parse = (source, state) => { - 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) { - capture = currRule.match(source, state); - if (capture) { - rule = currRule; - ruleName = currRuleName; - - if (lists.includes(ruleName)) { - // Lists are complicated because we do not require a blank line before a list. - const prevCaptureStr = state.prevCapture == null ? "" : state.prevCapture; - const isStartOfLineCapture = LIST_LOOKBEHIND_R.test(prevCaptureStr); - if (isStartOfLineCapture) { - if (state.inline) { - // We matched a list that does not have a preceding blank line. - // Finish the current block element before beginning the list. - state.remainder = capture[0]; - return result - } else { - break - } - } - } else { - 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); - } - state.prevCapture = capture[0]; - source = source.substring(capture[0].length); - if (state.remainder) { - // Prepend a list. - source = state.remainder + "\n\n" + source; - state.remainder = ""; - } - } - 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 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 ((node.type === 'indented' && prevNode.type === 'indented') || - (node.type === 'centered' && prevNode.type === 'centered')) { - prevNode.content = prevNode.content.concat(node.content); - arr.splice(i, 1); - } else if (node.type === "null") { - 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 populateTOC = ast => { - let tocNode; - for (const node of ast) { - if (node.type === "toc") { tocNode = node; break } - } - if (!tocNode) { return } - const start = tocNode.attrs.start; - const end = tocNode.attrs.end; - for (const node of ast) { - if (node.type === "heading") { - const level = node.attrs.level; - if (start <= level && level <= end) { - const tocEntry = []; - let str = ""; - for (const range of node.content) { str += range.text; } - tocEntry.push(str); - tocEntry.push(level); - tocEntry.push(0); // page number unknown - tocEntry.push(0); // element number unknown - tocNode.attrs.body.push(tocEntry); - } - } - } -}; - -const metadataRegEx = /^---+\n((?:[A-Za-z0-9][A-Za-z0-9 _-]*:[^\n]+\n(?:[ \t]+[^\n]+\n)*)+)---+\n/; -const metadataItemRegEx = /^[A-Za-z0-9][A-Za-z0-9 _-]*:[^\n]+\n(?:[ \t]+[^\n]+\n)*/; -const hurmetMetadataNames = ["decimalFormat", "fontSize", "pageSize"]; - -const parseMetadata = str => { - const metadata = {}; - let capture = str.match(metadataItemRegEx); - while (capture) { - const item = capture[0].split(":"); - const key = item[0].trim().replace(/ /g, ""); - if (hurmetMetadataNames.includes(key)) { - const value = item[1].slice(0, -1).trim().replace(/ *\n[ \t]*/g, " "); - metadata[key] = value; - } - str = str.slice(capture[0].length); - capture = str.match(metadataItemRegEx); - } - return metadata -}; - -const dateMessageRegEx = /^date:([^\n]+)\nmessage:([^\n]+)\n/; - -const inlineMd2ast = md => { - const state = { inline: true, _defs: {}, prevCapture: "", remainder: "", inHtml: false }; - const ast = parse(md, state); - if (Array.isArray(ast) && ast.length > 0 && ast[0].type === "null") { - ast.shift(); - } - consolidate(ast); - return ast -}; - -const md2ast = (md, inHtml = false) => { - // First, check for a metadata preamble - let metadata = false; - if (metadataRegEx.test(md)) { - const match = metadataRegEx.exec(md); - metadata = parseMetadata(match[1]); - md = md.slice(match[0].length); - } - - // Second, get all the link reference definitions - const state = { - inline: false, - _defs: {}, - footnotes: [], - prevCapture: "", - remainder: "", - inHtml - }; - const defRegEx = /\n *\[([^\]\n]+)\]: *(?:¢(`+)([\s\S]*?[^`])\2(?!`)|]*)>? *(?:\n\{([^\n}]*)\})?)(?=\n)/gm; - const footnoteDefRegEx = /\n *\[\^\d+\]: *([^\n]*)(?=\n)/gm; - let capture; - while ((capture = defRegEx.exec(md)) !== null) { - const def = capture[1].replace(/\s+/g, " "); - const target = capture[4] || capture[3].trim(); - const directives = capture[5] || ""; - - const attrs = { alt: def }; - if (directives) { - const matchClass = CLASS_R.exec(directives); - const matchWidth = WIDTH_R.exec(directives); - const matchID = ID_R.exec(directives); - if (matchClass) { attrs.class = matchClass[1]; } - if (matchWidth) { attrs.width = matchWidth[1]; } - if (matchID) { attrs.id = matchID[1]; } - } - state._defs[def] = { target, attrs }; - } - - // Next, get all the footnote definitions - capture = null; - while ((capture = footnoteDefRegEx.exec(md)) !== null) { - state.footnotes.push(capture[1].trim()); - } - - // Find out if there are any snapshots. - let snapshotStrings = []; - let gotSnapshot = false; - if (metadata) { - snapshotStrings = md.split("\n"); - if (snapshotStrings.length > 1) { - gotSnapshot = true; - md = snapshotStrings.shift(); - } - } - - // Find out if there are any fallbacks for fetched files - let fallbackStrings = []; - if (metadata) { - fallbackStrings = md.split("\n"); - if (fallbackStrings.length > 1) { - md = fallbackStrings.shift(); - } else { - fallbackStrings = null; - } - } - - // Proceed to parse the document. - const ast = parse(md, state); - if (Array.isArray(ast) && ast.length > 0 && ast[0].type === "null") { - ast.shift(); - } - consolidate(ast); - populateTOC(ast); - if (metadata) { - if (fallbackStrings) { - metadata.fallbacks = JSON.parse(fallbackStrings.pop().trim()); - } - if (gotSnapshot) { - const snapshots = []; - for (const str of snapshotStrings) { - const capture = dateMessageRegEx.exec(str); - snapshots.push({ - date: capture[1] ? Date.parse(capture[1].trim()) : undefined, - message: capture[2] ? capture[2].trim() : undefined, - content: capture ? str.slice(capture[0].length) : str - }); - } - metadata.snapshots = snapshots; - } - return { type: "doc", attrs: metadata, content: ast } - } else { - return ast - } -}; - -const startSvg = _ => { - return { - tag: 'svg', - children: [], - attrs: { - xmlns: "http://www.w3.org/2000/svg", - width: 250, - height: 250, - style: "display: inline;" - }, - temp: { - width: 250, - height: 250, - xmin: 0, - xmax: 5, - ymin: 0, - ymax: 5, - xunitlength: 20, // px - yunitlength: 20, // px - origin: [0, 0], // in px (default is bottom left corner) - stroke: "black", - strokewidth: 1, - strokedasharray: null, - fill: "none", - fontstyle: "normal", - fontfamily: "sans-serif", - fontsize: 13.33, // px, ~10 pt - fontweight: "normal", - markerstrokewidth: 1, - markerstroke: "black", - markerfill: "yellow", - markersize: 4, - marker: "none", - dotradius: 4, - axesstroke: "black", - gridstroke: "grey", - isDim: false - } - } -}; - -// Helpers -const setStrokeAndFill = (node, attrs) => { - node.attrs["stroke-width"] = attrs.strokewidth; - node.attrs.stroke = attrs.stroke; - node.attrs.fill = attrs.fill; - if (attrs.strokedasharray != null && attrs.strokedasharray !== "none") { - node.attrs["stroke-dasharray"] = attrs.strokedasharray; - } -}; - -const pointZeroRegEx = /\.0+$/; -const chopZ = str => { - const k = str.indexOf("."); - if (k === -1) { return str } - if (pointZeroRegEx.test(str)) { return str.replace(pointZeroRegEx, "") } - let i; - for (i = str.length - 1; i > k && str.charAt(i) === "0"; i--) { - if (i === k) { i--; } - } - return str.slice(0, i + 1) -}; - -const markerDot = (center, attrs, s, f) => { // coordinates in units, radius in pixel - if (s == null) { s = attrs.stroke; } - if (f == null) { f = attrs.fill; } - const node = { tag: "circle", attrs: {} }; - node.attrs.cx = center[0] * attrs.xunitlength + attrs.origin[0]; - node.attrs.cy = attrs.height - center[1] * attrs.yunitlength - attrs.origin[1]; - node.attrs.r = attrs.markersize; - node.attrs["stroke-width"] = attrs.strokewidth; - node.attrs.stroke = s; - node.attrs.fill = f; - return node -}; - -const rationals2numbers = array => { - const newArray = []; - for (let i = 0; i < array.length; i++) { - const element = array[i]; - if (element.dtype) { - newArray[i] = rationals2numbers(element.value); - } else if (Rnl.isRational(element)) { - newArray[i] = Rnl.toNumber(element); - } else { - newArray[i] = rationals2numbers(element); - } - } - return newArray -}; - -const arrowhead = (svg, p, q) => { // draw arrowhead at q (in units) - const attrs = svg.temp; - const v = [p[0] * attrs.xunitlength + attrs.origin[0], attrs.height - - p[1] * attrs.yunitlength - attrs.origin[1]]; - const w = [q[0] * attrs.xunitlength + attrs.origin[0], attrs.height - - q[1] * attrs.yunitlength - attrs.origin[1]]; - let u = [w[0] - v[0], w[1] - v[1]]; - const d = Math.sqrt(u[0] * u[0] + u[1] * u[1]); - if (d > 0.00000001) { - u = [u[0] / d, u[1] / d]; - const z = attrs.marker === "markerdot" ? 3 : attrs.isDim ? 0 : 1; - const up = [-u[1], u[0]]; - const L = d > 12 ? 12.5 : 7.8125; - const S = d > 12 ? 3 : 1.875; - const node = { tag: "path", attrs: {} }; - node.attrs.d = "M " + (w[0] - L * u[0] - S * up[0]) + "," + - (w[1] - L * u[1] - S * up[1]) + " L " + (w[0] - z * u[0]) + "," + (w[1] - z * u[1]) + - " L " + (w[0] - L * u[0] + S * up[0]) + "," + (w[1] - L * u[1] + S * up[1]) + " z"; - if (attrs.isDim) { - node.attrs.stroke = "none"; - } else { - node.attrs["stroke-width"] = attrs.markerstrokewidth; - node.attrs.stroke = attrs.stroke; - } - node.attrs.fill = attrs.stroke; - svg.children.push(node); - } -}; - -const markAttribute = { - em: ["font-style", "italic"], - strong: ["font-weight", "bold"], - code: ["font-family", "monospace"], - strikethru: ["text-decoration", "line-through"], - subscript: ["font-size", "0.8em"] -}; - -const textLocal = (svg, p, str, pos) => { - const attrs = svg.temp; - let textanchor = "middle"; - let dx = 0; - let dy = attrs.fontsize / 3; - if (pos != null) { - if (pos.slice(0, 5) === "above") { dy = -attrs.fontsize / 2; } - if (pos.slice(0, 5) === "below") { dy = 1.25 * attrs.fontsize; } - if (pos.slice(0, 5) === "right" || pos.slice(5, 10) === "right") { - textanchor = "start"; - dx = attrs.fontsize / 2; - } - if (pos.slice(0, 4) === "left" || pos.slice(5, 9) === "left") { - textanchor = "end"; - dx = -attrs.fontsize / 2; - } - } - const textNode = { tag: "text", children: [], attrs: {} }; - textNode.attrs["text"] = str; - textNode.attrs.x = p[0] * attrs.xunitlength + attrs.origin[0] + dx; - textNode.attrs.y = attrs.height - p[1] * attrs.yunitlength - attrs.origin[1] + dy; - textNode.attrs["font-family"] = attrs.fontfamily; - textNode.attrs["font-size"] = attrs.fontsize; - textNode.attrs["text-anchor"] = textanchor; - // Load Markdown into an AST - const ast = inlineMd2ast(str); - // Load content of AST into nodes. - if (Array.isArray(ast)) { - let prevNodeContainedSubscript = false; - for (const markNode of ast) { - const tspan = { tag: "tspan", text: markNode.text }; - let currentNodeContainsSubscript = false; - if (markNode.marks) { - tspan.attrs = {}; - for (const mark of markNode.marks) { - const markAttr = markAttribute[mark.type]; - tspan.attrs[markAttr[0]] = markAttr[1]; - if (mark.type === "subscript") { currentNodeContainsSubscript = true; } - } - } - if (currentNodeContainsSubscript) { - if (!prevNodeContainedSubscript) { tspan.attrs.dy = "2"; } - } else if (prevNodeContainedSubscript) { - if (!markNode.marks) { tspan.attrs = {}; } - tspan.attrs.dy = "-2"; - } - prevNodeContainedSubscript = currentNodeContainsSubscript; - textNode.children.push(tspan); - } - } - svg.children.push(textNode); - return svg -}; - -const pointText = (point, attrs) => { - return (point[0] * attrs.xunitlength + attrs.origin[0]).toFixed(4) + "," - + (attrs.height - point[1] * attrs.yunitlength - attrs.origin[1]).toFixed(4) -}; - -const functions$1 = { - // Set attributes - stroke(svgOprnd, color) { - svgOprnd.value.temp.stroke = color.value; - return svgOprnd - }, - - strokewidth(svgOprnd, num) { - svgOprnd.value.temp.strokewidth = Rnl.toNumber(num.value); - return svgOprnd - }, - - strokedasharray(svgOprnd, str) { - svgOprnd.value.temp.strokedasharray = str.value; - return svgOprnd - }, - - fill(svgOprnd, color) { - svgOprnd.value.temp.fill = color.value; - return svgOprnd - }, - - fontsize(svgOprnd, size) { - svgOprnd.value.temp.fontsize = Rnl.toNumber(size.value); - return svgOprnd - }, - - fontfamily(svgOprnd, str) { - svgOprnd.value.temp.fontfamily = str.value; // "sansserif"|"serif"|"fixed"|"monotype" - return svgOprnd - }, - - marker(svgOprnd, str) { - svgOprnd.value.temp.marker = str.value; // "none" | "dot" | "arrow" | "arrowdot" - return svgOprnd - }, - - // Initialize the svg. - - title(svgOprnd, strOprnd) { - svgOprnd.value.children.push( { tag: "title", attrs: { text: strOprnd.value } }); - return svgOprnd - }, - - frame(svgOprnd, width = 250, height = 250, position = "inline") { - const svg = svgOprnd.value; - const attrs = svg.temp; - attrs.width = typeof width === "number" ? width : Rnl.toNumber(width.value); - svg.attrs.width = attrs.width; - attrs.height = typeof height === "number" ? height : Rnl.toNumber(height.value); - svg.attrs.height = attrs.height; - if (typeof position !== "string") { position = position.value; } - if (position !== "inline") { svg.attrs.float = position; } - attrs.xunitlength = attrs.width / (attrs.xmax - attrs.xmin); - attrs.yunitlength = attrs.height / (attrs.ymax - attrs.ymin); - attrs.origin = [-attrs.xmin * attrs.xunitlength, -attrs.ymin * attrs.yunitlength]; - return { value: svg, unit: null, dtype: dt.DRAWING } - }, - - view(svgOprnd, xmin = 0, xmax = 5, ymin, ymax) { - const svg = svgOprnd.value; - const attrs = svg.temp; - attrs.xmin = typeof xmin === "number" ? xmin : Rnl.toNumber(xmin.value); - attrs.xmax = typeof xmax === "number" ? xmax : Rnl.toNumber(xmax.value); - attrs.xunitlength = attrs.width / (attrs.xmax - attrs.xmin); - attrs.yunitlength = attrs.xunitlength; // This may change below. - if (ymin == null) { - attrs.origin = [-attrs.xmin * attrs.xunitlength, attrs.height / 2]; - attrs.ymin = -attrs.height / (2 * attrs.yunitlength); - attrs.ymax = -attrs.ymin; - } else { - attrs.ymin = Rnl.toNumber(ymin.value); - if (ymax != null) { - attrs.ymax = Rnl.toNumber(ymax.value); - attrs.yunitlength = attrs.height / (attrs.ymax - attrs.ymin); - } else { - attrs.ymax = attrs.height / attrs.yunitlength + attrs.ymin; - } - attrs.origin = [-attrs.xmin * attrs.xunitlength, -attrs.ymin * attrs.yunitlength]; - } - return { value: svg, unit: null, dtype: dt.DRAWING } - }, - - // Draw things - - grid(svgOprnd, gdx, gdy, isLocal) { - const svg = svgOprnd.value; - const attrs = svg.temp; - gdx = gdx == null ? attrs.xunitlength : Rnl.toNumber(gdx.value) * attrs.xunitlength; - gdy = gdy == null ? gdx : Rnl.toNumber(gdy.value) * attrs.yunitlength; - const pnode = { tag: "path", attrs: {} }; - let str = ""; - for (let x = attrs.origin[0]; x < attrs.width; x += gdx) { - str += " M" + x + ",0 " + x + "," + attrs.height; - } - for (let x = attrs.origin[0] - gdx; x > 0; x -= gdx) { - str += " M" + x + ",0 " + x + "," + attrs.height; - } - for (let y = attrs.height - attrs.origin[1]; y < attrs.height; y += gdy) { - str += " M0," + y + " " + attrs.width + "," + y; - } - for (let y = attrs.height - attrs.origin[1] - gdy; y > 0; y -= gdy) { - str += " M0," + y + " " + attrs.width + "," + y; - } - pnode.attrs.d = str; - pnode.attrs["stroke-width"] = 0.5; - pnode.attrs.stroke = attrs.gridstroke; - pnode.attrs.fill = attrs.fill; - svg.children.push(pnode); - if (!isLocal) { - return { value: svg, unit: null, dtype: dt.DRAWING } - } - }, - - axes(svgOprnd, dx, dy, labels, gdx, gdy) { - let svg = svgOprnd.value; - const attrs = svg.temp; - dx = (dx == null ? attrs.xunitlength : Rnl.toNumber(dx.value) * attrs.xunitlength); - dy = (dy == null ? dx : Rnl.toNumber(dy.value) * attrs.yunitlength); - const parentFontsize = attrs.fontsize; - attrs.fontsize = Math.min(dx / 2, dy / 2, 10); - const ticklength = attrs.fontsize / 4; - if (gdx != null) { - this.grid(svgOprnd, gdx, gdy, true); - } - const pnode = { tag: "path", attrs: {} }; - let str = "M0," + (attrs.height - attrs.origin[1]) + " " + attrs.width + "," + - (attrs.height - attrs.origin[1]) + " M" + attrs.origin[0] + ",0 " + - attrs.origin[0] + "," + attrs.height; - for (let x = attrs.origin[0] + dx; x < attrs.width; x += dx) { - str += " M" + x + " " + (attrs.height - attrs.origin[1] + ticklength) + " " + x - + "," + (attrs.height - attrs.origin[1] - ticklength); - } - for (let x = attrs.origin[0] - dx; x > 0; x -= dx) { - str += " M" + x + "," + (attrs.height - attrs.origin[1] + ticklength) + " " + x - + "," + (attrs.height - attrs.origin[1] - ticklength); - } - for (let y = attrs.height - attrs.origin[1] + dy; y < attrs.height; y += dy) { - str += " M" + (attrs.origin[0] + ticklength) + "," + y + " " + - (attrs.origin[0] - ticklength) + "," + y; - } - for (let y = attrs.height - attrs.origin[1] - dy; y > 0; y -= dy) { - str += " M" + (attrs.origin[0] + ticklength) + "," + y + " " + - (attrs.origin[0] - ticklength) + "," + y; - } - if (labels != null) { - const ldx = dx / attrs.xunitlength; - const ldy = dy / attrs.yunitlength; - const lx = (attrs.xmin > 0 || attrs.xmax < 0 ? attrs.xmin : 0); - const ly = (attrs.ymin > 0 || attrs.ymax < 0 ? attrs.ymin : 0); - const lxp = (ly === 0 ? "below" : "above"); - const lyp = (lx === 0 ? "left" : "right"); - const ddx = Math.floor(1.1 - Math.log(ldx) / Math.log(10)) + 1; - const ddy = Math.floor(1.1 - Math.log(ldy) / Math.log(10)) + 1; - for (let x = ldx; x <= attrs.xmax; x += ldx) { - svg = textLocal(svg, [x, ly], chopZ(x.toFixed(ddx)), lxp); - } - for (let x = -ldx; attrs.xmin <= x; x -= ldx) { - svg = textLocal(svg, [x, ly], chopZ(x.toFixed(ddx)), lxp); - } - for (let y = ldy; y <= attrs.ymax; y += ldy) { - svg = textLocal(svg, [lx, y], chopZ(y.toFixed(ddy)), lyp); - } - for (let y = -ldy; attrs.ymin <= y; y -= ldy) { - svg = textLocal(svg, [lx, y], chopZ(y.toFixed(ddy)), lyp); - } - } - pnode.attrs.d = str; - pnode.attrs["stroke-width"] = 0.5; - pnode.attrs.stroke = attrs.axesstroke; - pnode.attrs.fill = attrs.fill; - svg.temp.fontsize = parentFontsize; - svg.children.push(pnode); - return { value: svg, unit: null, dtype: dt.DRAWING } - }, - - line(svgOprnd, m) { // segment connecting points p,q (coordinates in units) - const svg = svgOprnd.value; - const attrs = svg.temp; - const node = { tag: "path", attrs: {} }; - const p = [Rnl.toNumber(m.value[0][0]), Rnl.toNumber(m.value[0][1])]; - const q = [Rnl.toNumber(m.value[1][0]), Rnl.toNumber(m.value[1][1])]; - node.attrs.d = "M" + (p[0] * attrs.xunitlength + attrs.origin[0]) + "," + - (attrs.height - p[1] * attrs.yunitlength - attrs.origin[1]) + " " + - (q[0] * attrs.xunitlength + attrs.origin[0]) + "," + (attrs.height - - q[1] * attrs.yunitlength - attrs.origin[1]); - setStrokeAndFill(node, attrs); - svg.children.push(node); - if (attrs.marker === "dot" || attrs.marker === "arrowdot") { - svg.children.push(markerDot(p, attrs, attrs.markerstroke, attrs.markerfill)); - if (attrs.marker === "arrowdot") { arrowhead(svg, p, q); } - svg.children.push(markerDot(q, attrs, attrs.markerstroke, attrs.markerfill)); - } else if (attrs.marker === "arrow") { - arrowhead(svg, p, q); - } - return { value: svg, unit: null, dtype: dt.DRAWING } - }, - - path(svgOprnd, args) { - const svg = svgOprnd.value; - const attrs = svg.temp; - if (args[0].dtype !== dt.STRING) { - args = rationals2numbers(args); - } - const node = { tag: "path", attrs: {} }; - // Get the "d" attribute of a path - let str = ""; - for (let i = 0; i < args.length; i++) { - const el = args[i]; - if (i === 0) { - if (el.dtype && el.dtype === dt.STRING) { - str = args[i].value; - } else { - str += "M" + pointText(el, attrs); - } - } else if (typeof el[0] === "number") { - if (el.length === 2) { - str += " L" + pointText(el, attrs); - } else if (el.length === 3) { - str += " M" + pointText(el, attrs); - } else if (el.length === 5) { - const r = String(el[2] * attrs.xunitlength); - const sweep = String(el[3]); - str += ` A${r},${r} 0 0 ${sweep} ${pointText(el, attrs)}`; - } - } else if (el[0].length === 2) { - for (let j = 0; j < el.length; j++) { - str += " L" + pointText(el[j], attrs); - } - } else if (el[0].length === 5) { - for (let j = 0; j < el.length; j++) { - const r = String(el[j][2] * attrs.xunitlength); - const sweep = String(el[j][3]); - str += ` A${r},${r} 0 0 ${sweep} ${pointText(el[j], attrs)}`; - } - } - } - node.attrs.d = str; - node.attrs["stroke-width"] = attrs.strokewidth; - if (attrs.strokedasharray != null) { - node.attrs["stroke-dasharray"] = attrs.strokedasharray; - } - node.attrs.stroke = attrs.stroke; - node.attrs.fill = attrs.fill; - if (attrs.marker === "dot") { - for (let i = 0; i < args.length; i++) { - const el = args[i]; - if (typeof el[0] === "number") { - svg.children.push(markerDot(el, attrs, attrs.markerstroke, attrs.markerfill)); - } else { - for (const row of el) { - svg.children.push(markerDot(row, attrs, attrs.markerstroke, attrs.markerfill)); - } - } - } - } else if (attrs.marker === "arrow" || attrs.marker === "arrowdot") { - const lastEl = args[args.length - 1]; - if (typeof lastEl[0] !== "number") { - const end = lastEl[lastEl.length - 1]; - arrowhead(svg, lastEl[lastEl.length - 2], end); - if (attrs.marker === "arrowdot") { - svg.children.push(markerDot(end, attrs, attrs.markerstroke, attrs.markerfill)); - } - } else if (typeof lastEl[0] === "number") { - const prevEl = args[args.length - 2]; - const end = lastEl; - let start; - if (typeof prevEl[0] === "number") { - start = prevEl; - } else { - start = prevEl[prevEl.length - 1]; - } - arrowhead(svg, start, end); - if (attrs.marker === "arrowdot") { - svg.children.push(markerDot(end, attrs, attrs.markerstroke, attrs.markerfill)); - } - } - } - svg.children.push(node); - return { value: svg, unit: null, dtype: dt.DRAWING } - }, - - rect(svgOprnd, m, r) { // opposite corners in units, rounded by radius - const svg = svgOprnd.value; - const attrs = svg.temp; - const node = { tag: "rect", attrs: {} }; - const p = [Rnl.toNumber(m.value[0][0]), Rnl.toNumber(m.value[0][1])]; - const q = [Rnl.toNumber(m.value[1][0]), Rnl.toNumber(m.value[1][1])]; - node.attrs.x = Math.min(p[0], q[0]) * attrs.xunitlength + attrs.origin[0]; - node.attrs.y = attrs.height - Math.max(p[1], q[1]) * attrs.yunitlength - attrs.origin[1]; - node.attrs.width = Math.abs((q[0] - p[0]) * attrs.xunitlength); - node.attrs.height = Math.abs((q[1] - p[1]) * attrs.yunitlength); - if (r != null) { - const rNum = Rnl.toNumber(r.value) * attrs.xunitlength; - node.attrs.rx = rNum; - node.attrs.ry = rNum; - } - setStrokeAndFill(node, attrs); - svg.children.push(node); - return { value: svg, unit: null, dtype: dt.DRAWING } - }, - - circle(svgOprnd, center, radius) { // coordinates in units - const svg = svgOprnd.value; - const attrs = svg.temp; - const node = { tag: "circle", attrs: {} }; - node.attrs.cx = Rnl.toNumber(center.value[0]) * attrs.xunitlength + attrs.origin[0]; - node.attrs.cy = attrs.height - Rnl.toNumber(center.value[1]) * attrs.yunitlength - - attrs.origin[1]; - node.attrs.r = Rnl.toNumber(radius.value) * attrs.xunitlength; - setStrokeAndFill(node, attrs); - svg.children.push(node); - return { value: svg, unit: null, dtype: dt.DRAWING } - }, - - ellipse(svgOprnd, center, rx, ry) { // coordinates in units - const svg = svgOprnd.value; - const attrs = svg.temp; - const node = { tag: "ellipse", attrs: {} }; - node.attrs.cx = Rnl.toNumber(center.value[0]) * attrs.xunitlength + attrs.origin[0]; - node.attrs.cy = attrs.height - Rnl.toNumber(center.value[1]) * attrs.yunitlength - - attrs.origin[1]; - node.attrs.rx = Rnl.toNumber(rx.value) * attrs.xunitlength; - node.attrs.ry = Rnl.toNumber(ry.value) * attrs.yunitlength; - setStrokeAndFill(node, attrs); - svg.children.push(node); - return { value: svg, unit: null, dtype: dt.DRAWING } - }, - - arc(svgOprnd, m, radius) { // coordinates in units - const svg = svgOprnd.value; - const attrs = svg.temp; - const node = { tag: "path", attrs: {} }; - const start = [Rnl.toNumber(m.value[0][0]), Rnl.toNumber(m.value[0][1])]; - const end = [Rnl.toNumber(m.value[1][0]), Rnl.toNumber(m.value[1][1])]; - if (radius == null) { - const v = [end[0] - start[0], end[1] - start[1]]; - radius = (Math.sqrt(v[0] * v[0] + v[1] * v[1])) * attrs.yunitlength; - } else if (isVector(radius)) { - radius = radius.value.map(e => Rnl.toNumber(e) * attrs.yunitlength); - } else { - radius = Rnl.toNumber(radius.value) * attrs.yunitlength; - } - let str = "M" + (start[0] * attrs.xunitlength + attrs.origin[0]) + "," + - (attrs.height - start[1] * attrs.yunitlength - attrs.origin[1]) + " A"; - str += Array.isArray(radius) ? radius[0] + "," + radius[1] : radius + "," + radius; - str += " 0 0,0 " + (end[0] * attrs.xunitlength + attrs.origin[0]) + "," + - (attrs.height - end[1] * attrs.yunitlength - attrs.origin[1]); - node.attrs.d = str; - setStrokeAndFill(node, attrs); - let v = 0; - if (attrs.marker === "arrow" || attrs.marker === "arrowdot") { - const u = [(end[1] - start[1]) / 4, (start[0] - end[0]) / 4]; - v = [(end[0] - start[0]) / 2, (end[1] - start[1]) / 2]; - v = [start[0] + v[0] + u[0], start[1] + v[1] + u[1]]; - } else { - v = [start[0], start[1]]; - } - if (attrs.marker === "dot" || attrs.marker === "arrowdot") { - svg.children.push(markerDot(start, attrs, attrs.markerstroke, attrs.markerfill)); - if (attrs.marker === "arrowdot") { arrowhead(svg, v, end); } - svg.children.push(markerDot(end, attrs, attrs.markerstroke, attrs.markerfill)); - } else if (attrs.marker === "arrow") { - arrowhead(svg, v, end); - } - svg.children.push(node); - return { value: svg, unit: null, dtype: dt.DRAWING } - }, - - text(svgOprnd, p, str, pos) { - const svg = textLocal( - svgOprnd.value, - [Rnl.toNumber(p.value[0]), Rnl.toNumber(p.value[1])], - str.value, - pos == null ? null : pos.value - ); - return { value: svg, unit: null, dtype: dt.DRAWING } - }, - - dot(svgOprnd, center, typ, label, pos) { - let svg = svgOprnd.value; - const attrs = svg.temp; - let node; - const cx = Rnl.toNumber(center.value[0]) * attrs.xunitlength + attrs.origin[0]; - const cy = attrs.height - Rnl.toNumber(center.value[1]) * attrs.yunitlength - - attrs.origin[1]; - if (typ.value === "+" || typ.value === "-" || typ.value === "|") { - node = { tag: "path", attrs: {} }; - if (typ.value === "+") { - node.attrs.d = " M " + (cx - attrs.ticklength) + "," + cy - + " L " + ( cx + attrs.ticklength) + "," + cy - + " M " + cx + "," + (cy - attrs.ticklength) + " L " + cx - + "," + (cy + attrs.ticklength); - node.attrs["stroke-width"] = 0.5; - node.attrs.stroke = attrs.axesstroke; - } else { - if (typ.value === "-") { - node.attrs.d = " M " + (cx - attrs.ticklength) + "," + cy - + " L " + (cx + attrs.ticklength) + "," + cy; - } else { - node.attrs.d = " M " + cx + "," + (cy - attrs.ticklength) - + " L " + cx + "," + (cy + attrs.ticklength); - } - node.attrs["stroke-width"] = attrs.strokewidth; - node.attrs["stroke"] = attrs.stroke; - } - } else { - node = { tag: "circle", attrs: {} }; - node.attrs.cx = cx; - node.attrs.cy = cy; - node.attrs.r = attrs.dotradius; - node.attrs["stroke-width"] = attrs.strokewidth; - node.attrs.stroke = attrs.stroke; - node.attrs.fill = (typ.value === "open" ? "white" : attrs.stroke); - } - svg.children.push(node); - if (label != null) { - svg = textLocal( - svg, - [Rnl.toNumber(center.value[0]), Rnl.toNumber(center.value[1])], - label.value, - (pos == null ? "below" : pos.value) - ); - } - return { value: svg, unit: null, dtype: dt.DRAWING } - }, - - leader(svgOprnd, plistOprnd, label) { - const marker = svgOprnd.value.temp.marker; - svgOprnd.value.temp.marker = "arrow"; - svgOprnd.value.temp.isDim = true; - const startPoint = { - value: clone(plistOprnd.value[plistOprnd.value.length - 1]), - unit: null, - dtype: dt.RATIONAL + dt.ROWVECTOR - }; - const plistCopy = clone(plistOprnd); // Copy to an un-frozen object. - plistCopy.value.pop(); - plistCopy.value.reverse(); - svgOprnd = this.path(svgOprnd, [startPoint, plistCopy]); - const p = rationals2numbers(startPoint.value); - const q = rationals2numbers(plistCopy.value[0]); - let pos = "right"; - if (Math.abs(p[0] - q[0]) >= Math.abs(p[1] - q[1])) { - pos = p[0] >= q[0] ? "right" : "left"; - } else { - pos = p[1] < q[1] ? "below" : "above"; - } - const svg = textLocal(svgOprnd.value, p, label.value, pos); - svg.temp.marker = marker; - svg.temp.isDim = false; - return { value: svg, unit: null, dtype: dt.DRAWING } - }, - - dimension(svgOprnd, plistOprnd, label) { - const p = clone(plistOprnd.value); - const q = p.pop(); - const origstrokewidth = svgOprnd.value.temp.strokewidth; - svgOprnd.value.temp.strokewidth = 0.5; - svgOprnd.value.temp.isDim = true; // set small arrowhead - let six = Rnl.fromNumber(6 / svgOprnd.value.temp.xunitlength); - const pEnd = p[p.length - 1]; - let svg; - // Is the label y-coord between the y-coords of the end points? - if ((Rnl.lessThan(p[0][1], q[1]) && Rnl.lessThan(q[1], pEnd[1])) || - (Rnl.lessThan(pEnd[1], q[1]) && Rnl.lessThan(q[1], p[0][1]))) { - if (!Rnl.lessThan(pEnd[0], q[0])) { six = Rnl.negate(six); } - p.forEach(e => { - svgOprnd = this.line(svgOprnd, { value: [ - [Rnl.add(e[0], six), e[1]], - [Rnl.add(q[0], six), e[1]] - ] }); - }); - svgOprnd.value.temp.marker = "arrow"; - const pos = Rnl.lessThanOrEqualTo(pEnd[0], q[0]) ? "right" : "left"; - for (let i = 0; i < p.length - 1; i++) { - svgOprnd = this.line(svgOprnd, { value : [[q[0], p[i][1]], [q[0], p[i + 1][1]]], - unit: null, dtype: dt.MATRIX }); - svgOprnd = this.line(svgOprnd, { value : [[q[0], p[i + 1][1]], [q[0], p[i][1]]], - unit: null, dtype: dt.MATRIX }); - const p3 = [ - Rnl.toNumber(q[0]), - (Rnl.toNumber(p[i][1]) + Rnl.toNumber(p[i + 1][1])) / 2 - ]; - const str = p.length === 2 ? label.value : label.value[i]; - svg = textLocal(svgOprnd.value, p3, str, pos); - } - } else { - if (!Rnl.lessThan(pEnd[1], q[1])) { six = Rnl.negate(six); } - p.forEach(e => { - svgOprnd = this.line(svgOprnd, { value: [ - [e[0], Rnl.add(e[1], six)], - [e[0], Rnl.add(q[1], six)] - ] }); - }); - svgOprnd.value.temp.marker = "arrow"; - const pos = Rnl.lessThanOrEqualTo(pEnd[1], q[1]) ? "above" : "below"; - for (let i = 0; i < p.length - 1; i++) { - svgOprnd = this.line(svgOprnd, { value: [ [p[i][0], q[1]], [ p[i + 1][0], q[1]] ], - unit: null, dtype: dt.MATRIX }); - svgOprnd = this.line(svgOprnd, { value: [ [ p[i + 1][0], q[1]], [p[i][0], q[1]] ], - unit: null, dtype: dt.MATRIX }); - const p3 = [ - (Rnl.toNumber(p[i][0]) + Rnl.toNumber(p[i + 1][0])) / 2, - Rnl.toNumber(q[1]) - ]; - const str = p.length === 2 ? label.value : label.value[i]; - svg = textLocal(svgOprnd.value, p3, str, pos); - } - } - svg.temp.strokewidth = origstrokewidth; - svg.temp.marker = "none"; - svg.temp.isDim = false; - return { value: svg, unit: null, dtype: dt.DRAWING } - } - -}; - -const draw = Object.freeze({ - startSvg, - functions: functions$1 -}); - -// Some helper functions and objects. - -// Lengths and x-coordinates are written as rational numbers, not floating point. -// That way, we can make a lessThanOrEqualTo comparison w/o floating point errors. - -const ord = ["first", "second", "third", "fourth", "fifth", "sixth", "seventh", "eighth"]; - -const loadTypesFromInput = factorInput => { - let doLiveLoadPatterns = false; - const headings = factorInput.headings || null; - const loadTypeMap = Object.create(null); - const getsPattern = new Array(9).fill(false); - if (factorInput === "service" || !factorInput) { - return [null, getsPattern, 1, doLiveLoadPatterns] - } - for (let i = 0; i < headings.length; i++) { - const loadName = headings[i].replace("*", ""); - loadTypeMap[loadName] = i + 1; - if (headings[i].indexOf("*") > -1) { - doLiveLoadPatterns = true; - getsPattern[i + 1] = true; - } - } - return [loadTypeMap, getsPattern, headings.length, doLiveLoadPatterns] -}; - -const combinationsFromInput = (factorInput, loadTypeMap) => { - const data = factorInput.data; - const headings = factorInput.headings; - const combinations = []; - for (let i = 0; i < data[0].length; i++) { - const factors = new Array(10).fill(0); - for (let j = 0; j < headings.length; j++) { - const type = loadTypeMap[headings[j].replace("*", "")]; - factors[type] = Rnl.toNumber(data[j][i]); - } - combinations.push(factors); - } - return combinations -}; - -const newNode = (fixity, k, xCoordinate) => { - return { - fixity, - k: (fixity === "spring" ? k : 0), - x: xCoordinate, - P: [0, 0, 0, 0, 0, 0, 0, 0, 0], - M: [0, 0, 0, 0, 0, 0, 0, 0, 0], - Pr: [0, 0, 0, 0, 0, 0, 0, 0, 0], // "r" stands for reaction - PrMin: [0, 0, 0, 0, 0, 0, 0, 0, 0], - Mr: [0, 0, 0, 0, 0, 0, 0, 0, 0], - MrMin: [0, 0, 0, 0, 0, 0, 0, 0, 0] - } -}; - -const incrementDegreesOfFreedom = fixity => { - switch (fixity) { - case "pinned": - return 1 - case "fixed": - return 0 - case "hinge": - return 3 - default: - return 2 - } -}; - -const newSegment = (length, xOfLeftEnd) => { - // A "segment" is a beam section between points of load discontinuity. - return { - length, - xOfLeftEnd, - // Point load applied at left end of segments. - // Array dim'ed to 9 for different load types, e.g., dead, live, wind, etc. - P: [0, 0, 0, 0, 0, 0, 0, 0, 0], - M: [0, 0, 0, 0, 0, 0, 0, 0, 0], // point moment - Pf: 0, // factored point load at left end - Mf: 0, - w1: [0, 0, 0, 0, 0, 0, 0, 0, 0], // distributed load at left end of segments. - w2: [0, 0, 0, 0, 0, 0, 0, 0, 0], // at right end. - Vmax: { - left: { value: 0, case: 0 }, - mid: { value: 0, case: 0, x: 0 }, - right: { value: 0, case: 0 } - }, - Vmin: { - left: { value: 0, case: 0 }, - mid: { value: 0, case: 0, x: 0 }, - right: { value: 0, case: 0 } - }, - Mmax: { - left: { value: 0, case: 0 }, - mid: { value: 0, case: 0, x: 0 }, - right: { value: 0, case: 0 } - }, - Mmin: { - left: { value: 0, case: 0 }, - mid: { value: 0, case: 0, x: 0 }, - right: { value: 0, case: 0 } - } - } -}; - -const identifySegment = (xGlobal, span) => { - // Which segment contains xGlobal? - for (let i = 0; i < span.segments.length; i++) { - const xSegEnd = Rnl.add(span.segments[i].xOfLeftEnd, span.segments[i].length); - if (Rnl.lessThanOrEqualTo(xGlobal, xSegEnd)) { return i } - } - return -1 -}; - -const splitSegment = (segments, iSeg, xGlobal) => { - // segments` is an array. - // We need to split the element at segments[iSeg] into two elements. - const length = Rnl.subtract(xGlobal, segments[iSeg].xOfLeftEnd); - if (iSeg === 0) { - segments.unshift(newSegment(length, segments[0].xOfLeftEnd)); - } else { - const s1 = segments.slice(0, iSeg); - s1.push(newSegment(length, segments[iSeg].xOfLeftEnd)); - segments = s1.concat(segments.slice(iSeg)); - } - const seg = segments[iSeg + 1]; - const newSeg = segments[iSeg]; - for (let i = 0; i < 9; i++) { - const slope = (seg.w2[i] - seg.w1[i]) / Rnl.toNumber(seg.length); - newSeg.w1[i] = seg.w1[i]; - newSeg.w2[i] = seg.w1[i]; - seg.w1[i] = seg.w1[i] + slope * Rnl.toNumber(length); - newSeg.P[i] = seg.P[i]; - seg.P[i] = 0; - newSeg.M[i] = seg.M[i]; - seg.M[i] = 0; - } - seg.xOfLeftEnd = xGlobal; - seg.length = Rnl.subtract(seg.length, newSeg.length); - return segments -}; - -// Here's the main function of this module. -// Take the raw input strings, validate them, and load them -// into data structures for use by the analyze function. -function populateData(input, factorInput) { - const errorMsg = ""; - const beam = { - E: 0, // modulus of elasticity - I: 0, // moment of inertia - k: 0, // spring constant - convention: input.convention - ? input.convention - : 1, // Plot + moment on comp or tension side. - SI: input.SI || false, // boolean. Are we using SI units? - doLiveLoadPatterns: input.patterns, - gotType: [false, false, false, false, false, false, false, false, false], - wMax: 0, // default line load maximum - x: 180, // x coordinate of the beam's left end inside the SVG, in px - allLoadsAreUniform: true // subject to change below - }; - - if (input.E === 1 || input.E === 0) { - // We don't know E or I, so we won't do a deflection diagram. - // But we will still do the shear and moment diagrams. - beam.E = 1; - beam.I = 1; - beam.k = 0; - } else { - beam.E = input.E; // Modulus of elasticity - beam.I = input.I; // Moment of inertia, I - beam.k = input.k; // Spring constant - } - if (beam.E === 1 && beam.I === 1 && input.k !== 0) { - return ["E and I are necessary for an analysis with spring supports."] - } - beam.EI = beam.E * beam.I; - - // Load in node data and span data. - // Definitions - // (1) A "span" is a section of beam between two user-defined nodes. - // (2) A "segment" is a section of beam between nodes or points of load discontinuity. - // Each span thus consists of one or more segments. - let i = 0; - let cummulativeLength = Rnl.zero; - const nodes = []; - const spans = []; - beam.numDegreesOfFreedom = 0; - // eslint-disable-next-line max-len - const [loadTypeMap, getsPattern, numLoadTypes, doLiveLoadPatterns] = loadTypesFromInput(factorInput); - beam.numLoadTypes = numLoadTypes; - beam.getsPattern = getsPattern; - beam.doLiveLoadPatterns = doLiveLoadPatterns; - - for (i = 0; i < input.nodes.length; i++) { - // Process node input. - const fixity = input.nodes[i]; - if (!fixity) { return [`The ${ord[i]} node designation is invalid.`] } - if (fixity === "spring" && input.k === 0) { - return ["Error. A model with a spring needs a spring constant, k."] - } - nodes.push(newNode(fixity, beam.k, cummulativeLength)); - beam.numDegreesOfFreedom += incrementDegreesOfFreedom(fixity); - if (i < input.spanLength.length) { - // Process span input. - const length = input.spanLength[i]; - spans.push({ - length, - segments: Array(1).fill(newSegment(length, cummulativeLength)) - }); - cummulativeLength = Rnl.add(cummulativeLength, length); - } - } - if (spans.length === 0) { return [`No span lengths.`] } - const numSpans = spans.length; - beam.numSegments = numSpans; - beam.length = nodes[nodes.length - 1].x; - - // Point Loads - for (i = 0; i < input.loads.length; i++) { - const load = input.loads[i]; - if (load.shape === "w") { - // Skip the distributed loads for now. We'll pick them up later. - continue - } - if (load.from === 0) { continue } - let type = load.type === "none" - ? 0 - : loadTypeMap - ? loadTypeMap[load.type] - : 1; - if (type === 0) { - if (beam.comboName !== "service") { - return [`The ${ord[i]} load must have a load type defined.`] - } else { - type = 1; // In a service load analysis, treat unlabled loads as Dead loads. - } - } - - const P = input.loads[i].P; - const M = input.loads[i].M; - const x = input.loads[i].from; - - let foundAHome = false; - for (let j = 0; j < nodes.length; j++) { - if (Rnl.areEqual(x, nodes[j].x)) { - nodes[j].P[0] += P; - nodes[j].M[0] += M; - if (type !== 0) { nodes[j].P[type] += P; } - foundAHome = true; - break - } - } - if (foundAHome) { continue } - - for (let j = 0; j < spans.length; j++) { - if (Rnl.greaterThan(x, nodes[j].x) && Rnl.lessThan(x, nodes[j + 1].x)) { - const span = spans[j]; - const iSeg = identifySegment(x, span); - if (Rnl.greaterThan(x, span.segments[iSeg].xOfLeftEnd)) { - span.segments = splitSegment(span.segments, iSeg, x); - beam.numSegments += 1; - } - beam.gotType[0] = true; - span.segments[iSeg + 1].P[0] += P; // add to sum of service loads - span.segments[iSeg + 1].M[0] += M; - if (type !== 0) { - beam.gotType[type] = true; - span.segments[iSeg + 1].P[type] += P; - span.segments[iSeg + 1].M[type] += M; - } - } - } - } - - // Distributed loads - beam.allLoadsAreUniform = true; // initialize the variable - for (i = 0; i < input.loads.length; i++) { - const load = input.loads[i]; - if (load.shape !== "w") { continue } - let type = load.type === "none" ? 0 : loadTypeMap ? loadTypeMap[load.type] : 1; - if (type === 0) { - if (beam.comboName !== "service") { - return [`The ${ord[i]} load must have a load type defined.`] - } else { - type = 1; // In a service load analysis, treat unlabled loads as Dead loads. - } - } - - const wStart = load.wStart; - const wEnd = load.wEnd; - - if (Math.abs(wStart) > beam.wMax) { beam.wMax = Math.abs(wStart); } - if (Math.abs(wEnd) > beam.wMax) { beam.wMax = Math.abs(wEnd); } - - const xStart = load.from; - const xEnd = Rnl.isZero(load.to) - ? cummulativeLength - : load.to; - - const slope = (wEnd - wStart) / Rnl.toNumber(Rnl.subtract(xEnd, xStart)); - if (slope !== 0) {beam.allLoadsAreUniform = false;} - - let iStartSpan = 0; - let iEndSpan = 0; - let iStartSeg = 0; - let iEndSeg = 0; - - // If necessary, split segments at points of load discontinuity. - for (let j = 0; j < spans.length; j++) { - if (Rnl.areEqual(xStart, nodes[j].x)) { - iStartSpan = j; - iStartSeg = 0; - break - } - if (Rnl.greaterThan(xStart, nodes[j].x) && Rnl.lessThan(xStart, nodes[j + 1].x)) { - for (let k = 0; k < spans[j].segments.length; k++) { - const seg = spans[j].segments[k]; - if (Rnl.areEqual(xStart, seg.xOfLeftEnd)) { - iStartSpan = j; - iStartSeg = k; - break - } - const segEnd = k < spans[j].segments.length - 1 - ? spans[j].segments[k + 1].xOfLeftEnd - : nodes[j + 1].x; - if (Rnl.greaterThan(xStart, seg.xOfLeftEnd) && Rnl.lessThan(xStart, segEnd)) { - spans[j].segments = splitSegment(spans[j].segments, k, xStart); - beam.numSegments += 1; - iStartSpan = j; - iStartSeg = k + 1; - break - } - } - } - } - - for (let j = 0; j < spans.length; j++) { - if (Rnl.areEqual(xEnd, nodes[j + 1].x)) { - iEndSpan = j; - iEndSeg = spans[j].segments.length - 1; - break - } - if (Rnl.greaterThan(xEnd, nodes[j].x) && Rnl.lessThan(xEnd, nodes[j + 1].x)) { - for (let k = 0; k < spans[j].segments.length; k++) { - const seg = spans[j].segments[k]; - const segEnd = k < spans[j].segments.length - 1 - ? spans[j].segments[k + 1].xOfLeftEnd - : nodes[j + 1].x; - if (Rnl.areEqual(xEnd, segEnd)) { - iEndSpan = j; - iEndSeg = k; - break - } - if (Rnl.greaterThan(xEnd, seg.xOfLeftEnd) && Rnl.lessThan(xEnd, segEnd)) { - spans[j].segments = splitSegment(spans[j].segments, k, xEnd); - beam.numSegments += 1; - iEndSpan = j; - iEndSeg = k; - break - } - } - } - } - - // Now apply distributed loads - for (let iSpan = iStartSpan; iSpan <= iEndSpan; iSpan++) { - const span = spans[iSpan]; - const startSeg = (iSpan === iStartSpan ? iStartSeg : 0); - const endSeg = (iSpan === iEndSpan ? iEndSeg : spans[iSpan].segments.length - 1); - for (let iSeg = startSeg; iSeg <= endSeg; iSeg++) { - const xLeft = span.segments[iSeg].xOfLeftEnd; - const w1 = wStart + slope * Rnl.toNumber(Rnl.subtract(xLeft, xStart)); - const xRight = Rnl.add(span.segments[iSeg].xOfLeftEnd, span.segments[iSeg].length); - const w2 = wStart + slope * Rnl.toNumber(Rnl.subtract(xRight, xStart)); - // add to sum of service loads - span.segments[iSeg].w1[0] += w1; - span.segments[iSeg].w2[0] += w2; - // add to specific load type, e.g., dead, live, etc. - span.segments[iSeg].w1[type] += w1; - span.segments[iSeg].w2[type] += w2; - } - } - - beam.gotType[0] = true; - if (type !== 0) { - beam.gotType[type] = true; - } - } - - // Henceforward there are no <= comparisons. - // Change lengths into floating point numbers. - for (let i = 0; i < nodes.length; i++) { - nodes[i].x = Rnl.toNumber(nodes[i].x); - } - for (let i = 0; i < spans.length; i++) { - spans[i].length = Rnl.toNumber(spans[i].length); - for (let j = 0; j < spans[i].segments.length; j++) { - spans[i].segments[j].length = Rnl.toNumber(spans[i].segments[j].length); - spans[i].segments[j].xOfLeftEnd = Rnl.toNumber(spans[i].segments[j].xOfLeftEnd); - } - } - beam.length = Rnl.toNumber(beam.length); - - const combinations = typeof factorInput === "string" - ? "service" - : combinationsFromInput(factorInput, loadTypeMap); - - return [errorMsg, beam, nodes, spans, combinations] - -} - -// Each of the methods in this module draws some item. - -const circle = (x, y, radius) => { - return { tag: "circle", attrs: { cx: x, cy: y, r: radius } } -}; - -const restraint = (node, beam) => { - const value = []; - const x = beam.xDiagram + beam.xScale * node.x; - if (node.fixity === "hinge" || node.fixity === "proppedHinge") { - value.push(circle(beam.xDiagram + beam.xScale * node.x, beam.yLoad, 4)); - } - const path = { tag: "path", attrs: { d: "" } }; - if (node.fixity === "pinned" || node.fixity === "proppedHinge") { - // draw a triangle - const y = node.fixity === "pinned" ? beam.yLoad + 0.75 : beam.yLoad + 4; - path.attrs.d = `M${x} ${y} l5 10 h-10 z`; - path.attrs.style = "fill:#fff; stroke:#000"; - } else if (node.fixity === "fixed") { - const xd = (node.x === 0 ? -1 : 1) * 7; - // eslint-disable-next-line max-len - path.attrs.d = `M${x} ${beam.yLoad - 7} v14 m0 -14 l${xd} 7 M${x} ${beam.yLoad} l${xd} 7 M${x} ${beam.yLoad + 7} l${xd} 7`; - } else if (node.fixity === "spring") { - const y = beam.yLoad + .75; - path.attrs.d = `M${x} ${y} v3 l6 1.5 -12 3 12 3 -12 3 6 1.5 v3 m-6 0 h12`; - } - value.push(path); - return value -}; - -const pointForce = (x, y, load, fixity, isReaction = false) => { - const sgn = (load < 0 ? -1 : 1); // -1 is down - const lengthAdjustment = fixity === "fixed" - ? 7 - : fixity === "pinned" && isReaction - ? 10 - : fixity === "proppedHinge" && isReaction - ? 18 - : fixity === "hinge" - ? 4 - : fixity === "spring" && isReaction - ? 18 - : 0; - const length = 40 - lengthAdjustment; - // Reactions are drawn below the beam line. Imposed loads are drawn above the beam line. - const yText = y + (isReaction ? 55 : -45); - // Set x and y at the tip of the arrowhead - if (isReaction) { y += lengthAdjustment + 0.75; } else { y -= 0.75; } - if (sgn === -1 && isReaction) { y += length; } - if (sgn === 1 && !isReaction) { y -= length; } - const arrow = { - tag: "path", - attrs: { - style: "fill: #000; fill-opacity:1.0", - // eslint-disable-next-line max-len - d: `M${x} ${y} l${sgn * 4} ${sgn * 8} h${-sgn * 3.5} v${sgn * (length - 8)} h${-sgn * 1} v${-sgn * (length - 8)} h${-sgn * 3}z` - } - }; - const text = textNode(String(Math.abs(load)), x, yText, "middle"); - return [arrow, text] -}; - -const pointMoment = (x, y, load, isReaction = false) => { - let isCounterClockwise = load >= 0; // = (load < 0 ? -1 : 1) // 1 is counter-clockwise - load = Math.abs(load); - let arrow; - let text; - if (!isReaction) { - arrow = momentArrow(x, y, (isCounterClockwise ? 165 : 15), 150, isCounterClockwise); - text = textNode(String(load), x, y - 25, "middle"); - } else { - // The moment is a reaction - isCounterClockwise = !isCounterClockwise; - if (x < 100) { // left end - arrow = momentArrow(x, y, (isCounterClockwise ? 260 : 100), 140, isCounterClockwise); - text = textNode(String(load), x - 15, y - 15, "end"); - } else { - arrow = momentArrow(x, y, (isCounterClockwise ? 80 : 280), 140, isCounterClockwise); - text = textNode(String(load), x + 16, y - 15); - } - } - return [...arrow, text] -}; - -const momentArrow = (xCtr, yCtr, thetaAtArrowPoint, subtendedAngle, isCounterClockwise) => { - // Draw a circular arc with an arrowhead. - // Find startAngle and endAngle: the begining and ending of the arc - // theta = 0 at 3 o'clock. theta is + for counterclockwise - const startAngle = thetaAtArrowPoint * (Math.PI / 180); - const sgn = isCounterClockwise ? 1 : -1; - const endAngle = startAngle - sgn * subtendedAngle * (Math.PI / 180); - // sgn = 1 for counterclockwise, -1 for clockwise - const diameter = 35; - const r = diameter / 2; // radius - const arrowHeadLength = 8; - const startAnglePrime = startAngle - sgn * (2 * 0.9 * arrowHeadLength / diameter); - const largeArcFlag = endAngle - startAngle <= 180 ? "0" : "1"; - - let xStart = 0; - let yStart = 0; - let xEnd = 0; - let yEnd = 0; - if (sgn > 0) { - xEnd = (xCtr + r * Math.cos(startAnglePrime)).toFixed(2); // arrow end - yEnd = (yCtr - r * Math.sin(startAnglePrime)).toFixed(2); - xStart = (xCtr + r * Math.cos(endAngle)).toFixed(2); - yStart = (yCtr - r * Math.sin(endAngle)).toFixed(2); - } else { - xStart = (xCtr + r * Math.cos(startAnglePrime)).toFixed(2); - yStart = (yCtr - r * Math.sin(startAnglePrime)).toFixed(2); - xEnd = (xCtr + r * Math.cos(endAngle)).toFixed(2); - yEnd = (yCtr - r * Math.sin(endAngle)).toFixed(2); - } - - const path = { - tag: "path", - attrs: { d: `M${xStart} ${yStart}A${r} ${r} 0 ${largeArcFlag} 0 ${xEnd} ${yEnd}` } - }; - - // Draw the arrow head - const xTip = xCtr + r * Math.cos(startAngle); - const yTip = yCtr - r * Math.sin(startAngle); - const alpha = startAngle - sgn * 100 / 180 * Math.PI; // rotate by 100° - const beta = 22.5 * Math.PI / 180; // angle subtended by half-arrowhead - const x = Array(3).fill(""); - const y = Array(3).fill(""); - x[0] = xTip.toFixed(2); - y[0] = yTip.toFixed(2); - x[1] = (xTip + arrowHeadLength * Math.cos(alpha - beta)).toFixed(2); - y[1] = (yTip - arrowHeadLength * Math.sin(alpha - beta)).toFixed(2); - x[2] = (xTip + arrowHeadLength * Math.cos(alpha + beta)).toFixed(2); - y[2] = (yTip - arrowHeadLength * Math.sin(alpha + beta)).toFixed(2); - - let points = ""; - for (let i = 0; i < x.length; i++) { - points += `${x[i]} ${y[i]} `; - } - const polygon = { tag: "polygon", attrs: { points } }; - return [path, polygon] -}; - -const polyline = (x, y) => { - let d = `M${x[0]} ${y[0]}`; - for (let i = 1; i < x.length; i++) { - d += ` L${x[i]} ${y[i]}`; - } - return { tag: "path", attrs: { d, stroke: "black", "fill-opacity": "0.0" } } -}; - -const textNode = (str, x, y, horizAlign) => { - const node = { tag: "text", attrs: { x: String(x), y: String(y) } }; - if (horizAlign === "middle" || horizAlign === "end") { - node.attrs["text-anchor"] = horizAlign; - } - node.children = [{ tag: "tspan", text: str }]; - return node -}; - -const Draw = Object.freeze({ - pointForce, - pointMoment, - polyline, - restraint, - textNode -}); - -const round$1 = (num, prec) => { - // Round a number to prec significant digits. - // Return a string. This is used for display of numbers on the diagram. - const str = num.toPrecision(prec); - if (str.indexOf("e") === -1) { return str } - const pos = str.indexOf("e"); - const significand = Number.parseFloat(str.slice(0, pos)); - const exponent = Number.parseFloat(str.slice(pos + 1)); - return (significand * 10 ** exponent).toString() -}; - -function createLoadDiagram(beam, nodes, spans) { - beam.xDiagram = 90; // x coordinate at left end of diagram line, px - beam.yLoad = 80; // y coordiate of load diagram - beam.xScale = 300 / nodes[nodes.length - 1].x; - const lengthFactor = beam.SI ? 1 : 0.3048; - const forceFactor = beam.SI ? 1000 : 4448.2216152605; - const momentFactor = beam.SI ? 1000 : 4448.2216152605 * 0.3048; - const lineLoadFactor = beam.SI ? 1000 : 4448.2216152605 / 0.3048; - - // Begin the diagram. - let diagram = []; - diagram.push({ tag: "title", attrs: { text: "Beam Diagram" } }); - diagram.push({ - tag: "defs", - attrs: {}, - style: `svg { background-color: #fff; } -text, tspan { font: 12px Arial; }` - }); - diagram.push(Draw.textNode("loads", 20, beam.yLoad + 2)); - diagram.push(Draw.textNode(`(${beam.SI ? 'kN, m' : 'kips, ft'})`, 20, beam.yLoad + 16)); - diagram.push({ - tag: "path", - attrs: { stroke: "black", "stroke-width": "1.5px", - d: `M${beam.xDiagram} ${beam.yLoad} h300` } - }); - - // Draw restraints - for (let i = 0; i < nodes.length; i++) { - if (nodes[i].fixity !== "continuous") { - diagram = diagram.concat(Draw.restraint(nodes[i], beam)); - } - } - - // Write the span length below each span, but only if there are no loads in the way. - for (let i = 0; i < spans.length; i++) { - let okay = true; // initialize - if (spans[i].length * beam.xScale < 30) { continue } - if (okay) { - for (let j = 1; j < spans[i].segments.length; j++) { - if (spans[i].segments[j].P[0] > 0) { okay = false; break } - } - } - if (okay) { - const x = beam.xDiagram + beam.xScale * (nodes[i].x + spans[i].length / 2); - const unit = beam.SI ? "" : "′"; - const sText = round$1(spans[i].length / lengthFactor, 3); - diagram.push(Draw.textNode(`${sText}${unit}`, x, beam.yLoad + 15)); - } - } - - // Draw nodal loads - for (let i = 0; i < nodes.length; i++) { - const x = beam.xDiagram + beam.xScale * nodes[i].x; - if (Math.abs(nodes[i].P[0]) > 0) { - const sText = round$1(nodes[i].P[0] / forceFactor, 3); - diagram = diagram.concat(Draw.pointForce(x, beam.yLoad, sText, nodes[i].fixity)); - } - if (Math.abs(nodes[i].M[0]) > 0) { - const sText = round$1(nodes[i].M[0] / momentFactor, 3); - diagram = diagram.concat(Draw.pointMoment(x, beam.yLoad, sText)); - } - } - - // Draw span loads - const wScale = 20 / beam.wMax; - let wPrev = 0; - let d = `M${beam.xDiagram} ${beam.yLoad}`; - for (let i = 0; i < spans.length; i++) { - for (let j = 0; j < spans[i].segments.length; j++) { - const seg = spans[i].segments[j]; - const x = beam.xDiagram + beam.xScale * seg.xOfLeftEnd; - if (Math.abs(seg.P[0]) > 0) { - const sText = round$1(seg.P[0] / forceFactor, 3); - diagram = diagram.concat(Draw.pointForce(x, beam.yLoad, sText, "continuous")); - } - if (Math.abs(seg.M[0]) > 0) { - const sText = round$1(seg.M[0] / momentFactor, 3); - diagram = diagram.concat(Draw.pointMoment(x, beam.yLoad, sText)); - } - // Draw a line segment for the service load. - const xEnd = x + beam.xScale * seg.length; - if (seg.w1[0] !== wPrev) { - d += `V${beam.yLoad + seg.w1[0] * wScale}`; // vertical load discontinuiy. - } - const yEnd = beam.yLoad + seg.w2[0] * wScale; - d += `L${xEnd} ${yEnd}`; - wPrev = seg.w2[0]; - } - } - if (wPrev !== 0) { d += `V${beam.yLoad}`; } - diagram.push({ tag: "path", attrs: { d, stroke: "black", "fill-opacity": "0.0" } }); - - // Write in the line load values - let lastSegUniform = false; - let firstSegment; - let xFirstSegment = 0; - const segments = []; - for (let i = 0; i < spans.length; i++) { - for (let j = 0; j < spans[i].segments.length; j++) { - segments.push(spans[i].segments[j]); - } - } - const numSegments = segments.length; - for (let i = 0; i < segments.length; i++) { - const seg = segments[i]; - if (seg.w1[0] === seg.w2[0] && Math.abs(seg.w1[0]) > 0) { - lastSegUniform = true; - if (i === 0 || seg.w1[0] !== segments[i - 1].w1[0] || lastSegUniform === false) { - firstSegment = i; - xFirstSegment = beam.xScale * seg.xOfLeftEnd; - } - if (i === numSegments - 1 || segments[i + 1].w1[0] !== segments[i + 1].w2[0] - || seg.w1[0] !== segments[i + 1].w1[0]) { - // This segment is the end of a uniform load. - // Find a place to write the load value - const lenSegLoad = i < numSegments - 1 - ? segments[i + 1].xOfLeftEnd - segments[firstSegment].xOfLeftEnd - : beam.length - segments[firstSegment].xOfLeftEnd; - if (lenSegLoad * beam.xScale > 30) { - let noBust = true; // initialize the value - const fudge = seg.w1[0] > 0 ? 10 : -4; - const yy = beam.yLoad + wScale * seg.w1[0] + fudge; - const str = round$1(Math.abs(seg.w1[0] / lineLoadFactor), 3); - // try the middle of the uniform load. See if there is a point load there - for (let j = firstSegment + 1; j <= i; j++) { - if (beam.xScale * (Math.abs(segments[j].xOfLeftEnd - - (segments[firstSegment].xOfLeftEnd + lenSegLoad / 2))) < 35) { - if (segments[j].M[0] || segments[j].P[0] !== 0) { - noBust = false; - break - } - } - } - if (noBust) { - const x = beam.xDiagram + xFirstSegment + beam.xScale * lenSegLoad / 2; - diagram.push(Draw.textNode(str, x, yy)); - } else { - // try the 1/3 point - noBust = true; - for (let j = firstSegment + 1; j <= i; j++) { - if (beam.xScale * (Math.abs(segments[j].xOfLeftEnd - - (segments[firstSegment].xOfLeftEnd + lenSegLoad / 3))) < 35) { - if (segments[j].M[0] || segments[j].P[0] !== 0) { - noBust = false; - break - } - } - } - if (noBust) { - const x = beam.xDiagram + xFirstSegment + beam.xScale * lenSegLoad / 3 - 17; - diagram.push(Draw.textNode(str, x, yy)); - } else { - // try the 2/3 point - noBust = true; - for (let j = firstSegment + 1; j <= i; j++) { - if (beam.xScale * (Math.abs(segments[j].xOfLeftEnd - - (segments[firstSegment].xOfLeftEnd + 2 * lenSegLoad / 3))) < 5) { - if (segments[j].M[0] || segments[j].P[0] !== 0) { - noBust = false; - break - } - } - } - if (noBust) { - const x = beam.xDiagram + xFirstSegment + beam.xScale * 2 * lenSegLoad / 3; - diagram.push(Draw.textNode(str, x, yy)); - } else { - if (i === 0) { - diagram.push(Draw.textNode(str, beam.xDiagram - 35, yy)); - } - } - } - } - } - } - } else { - // We've got a distributed sloping load - lastSegUniform = false; - const s = i === 0 - ? 0 - : (segments[i - 1].w2[0] - segments[i - 1].w1[0]) / segments[i - 1].length; - const s2 = (seg.w2[0] - seg.w1[0]) / seg.length; - const s3 = i === numSegments - 1 - ? 0 - : (segments[i + 1].w2[0] - segments[i + 1].w1[0]) / segments[i + 1].length; - if (Math.abs(s2 - s) > 0.05 || i === 0) { - if (Math.abs(seg.w1[0]) > 0.05) { - if (seg.length * beam.xScale > 20) { - const str = round$1(Math.abs(seg.w1[0] / lineLoadFactor), 3); - const x = beam.xDiagram + beam.xScale * seg.xOfLeftEnd; - const fudge = seg.w1[0] > 0 ? 10 : -5; - const yy = beam.yLoad + wScale * seg.w1[0] + fudge; - diagram.push(Draw.textNode(str, x, yy)); - } - } - } - if (Math.abs(s2 - s3) > 0.05 || i === numSegments - 1 - || Math.abs(seg.w2[0] - segments[i + 1].w1[0]) > 0) { - if (Math.abs(seg.w2[0]) > 0.05) { - if (seg.length * beam.xScale > 20) { - const str = round$1(Math.abs(seg.w2[0] / lineLoadFactor), 3); - const x = beam.xDiagram + beam.xScale * (seg.xOfLeftEnd + seg.length) - 30; - const fudge = seg.w2[0] > 0 ? 10 : -5; - const yy = beam.yLoad + wScale * seg.w2[0] + fudge; - diagram.push(Draw.textNode(str, x, yy)); - } - } - } - } - } - - return diagram -} - -const ftRegEx = /′/g; -const numberRegEx$3 = new RegExp(Rnl.numberPattern); -const lengths = ["ft", "m", "cm", "mm"]; -const metricLengths = ["m", "cm", "mm"]; - -const readNumber = str => { - const matches = numberRegEx$3.exec(str); - if (matches) { - const numStr = matches[0]; - return [Rnl.fromString(numStr), numStr.length]; - } else { - return ["Error", null] - } -}; - -const convertToBaseUnit = (num, unitName) => { - const unit = unitFromUnitName(unitName); - return Rnl.multiply(Rnl.add(num, unit.gauge), unit.factor) -}; - -const readInputData = data => { - const input = Object.create(null); - // Set some defaults - input.nodes = []; - input.spanLength = []; - input.loads = []; - input.E = 1; - input.I = 1; - input.k = 0; - input.SI = false; - input.convention = 1; - // Read the input and overwrite the defaults. - - // Read the top line of data. - // It contains the geometry, connectivity, and node fixity. - const layout = data[1][0].trim(); - if (numberRegEx$3.test(layout)) { input.nodes.push("continuous"); } - const elements = layout.split(/ +/g); - for (let k = 0; k < elements.length; k++) { - switch (elements[k]) { - case "p": - case "△": - input.nodes.push("pinned"); - break - case "f": - case "⫢": - input.nodes.push("fixed"); - break - case "h": - case "∘": - input.nodes.push("hinged"); - break - case "ph": - case "⫯": - case "⧊": - input.nodes.push("proppedHinge"); - break - case "s": - case "⌇": - input.nodes.push("spring"); - break - case "-": - input.nodes.push("continuous"); - break - default: { - const element = elements[k].replace(ftRegEx, "ft"); - const [L, pos] = readNumber(element); - if (typeof L === "string") { return "Error. Non-numeric length." } - let unitName = element.slice(pos).trim(); - if (unitName === "") { - if (lengths.includes(elements[k + 1])) { - unitName = elements[k + 1]; - k += 1; - } else { - unitName = "mm"; - } - } - if (metricLengths.includes(unitName)) { input.SI = true; } - input.spanLength.push(convertToBaseUnit(L, unitName)); - break - } - } - } - if (numberRegEx$3.test(elements[elements.length - 1])) { input.nodes.push("continuous"); } - - // Read the rest of the data. - for (let i = 1; i < data[0].length; i++) { - const item = data[0][i].trim(); - let datum = data[1][i].trim(); - switch (item) { - case "E": { - const [E, pos] = readNumber(datum); - if (typeof E === "string") { return "Error. Non-numeric E." } - const unitName = datum.slice(pos).trim(); - input.E = Rnl.toNumber(convertToBaseUnit(E, unitName)); - break - } - - case "I": { - const [I, pos] = readNumber(datum); - if (typeof I === "string") { return "Error. Non-numeric I." } - const unitName = datum.slice(pos).trim(); - input.I = Rnl.toNumber(convertToBaseUnit(I, unitName)); - break - } - - case "k": { - const [k, pos] = readNumber(datum); - if (typeof k === "string") { return "Error. Non-numeric k." } - const unitName = datum.slice(pos).trim(); - input.k = Rnl.toNumber(convertToBaseUnit(k, unitName)); - break - } - - case "+M": { - input.convention = datum.charAt(0).toLowerCase() === "←→" ? 1 : -1; - break - } - - default: { - // Treat as a load - const load = Object.create(null); - datum = datum.replace(ftRegEx, "ft"); - const elements = datum.split(","); - let str = elements[0]; - load.type = item; - load.from = Rnl.zero; - load.to = Rnl.zero; - load.P = 0; - load.M = 0; - load.wStart = 0; - load.wEnd = 0; - let [num1, pos] = readNumber(str); // eslint-disable-line prefer-const - if (typeof num1 === "string") { return "Error. Non-numeric load." } - let num2 = num1; - str = str.slice(pos).trim(); - if (str.slice(0, 1) === ":") { - str = str.slice(1).trim(); - [num2, pos] = readNumber(str); - str = str.slice(pos).trim(); - } - const unitName = str.trim(); - const unit = unitFromUnitName(unitName); - // Read the load from & to points, if any - let L1 = 0; - let L2 = 0; - let lengthUnitName = ""; - if (elements.length > 1) { - str = elements[1].trim(); - [L1, pos] = readNumber(str); - str = str.slice(pos).trim(); - if (str.slice(0, 1) === ":") { - str = str.slice(1).trim(); - [L2, pos] = readNumber(str); - str = str.slice(pos).trim(); - } else { - L2 = L1; - } - lengthUnitName = str.trim(); - if (lengthUnitName === "") { lengthUnitName = "mm"; } - } - const expos = unit.expos.join(""); - if (expos === "01-200000") { - load.shape = "w"; - load.wStart = Rnl.toNumber(convertToBaseUnit(num1, unitName)); - load.wEnd = Rnl.toNumber(convertToBaseUnit(num2, unitName)); - } else if (expos === "11-200000") { - load.shape = "P"; - load.P = Rnl.toNumber(convertToBaseUnit(num1, unitName)); - } else if (expos === "21-200000") { - load.shape = "M"; - load.M = Rnl.toNumber(convertToBaseUnit(num1, unitName)); - } else { - return `Error. ${unitName} is not a force, line load, or moment.` - } - if (L1 !== 0) { load.from = convertToBaseUnit(L1, lengthUnitName); } - if (L2 !== 0) { load.to = convertToBaseUnit(L2, lengthUnitName); } - input.loads.push(load); - } - } - } - return input -}; - -const dotProduct = (a, b) => a.map((e, i) => (e * b[i])).reduce((m, n) => m + n); -const isLiveish = (loadType, beam) => beam.getsPattern[loadType]; - - -function doAnalysis(beam, nodes, spans) { - const numNodes = nodes.length; - const numSpans = spans.length; - const gotType = beam.gotType; - const numDegreesOfFreedom = beam.numDegreesOfFreedom; - const numEndActions = 4 * numSpans + numNodes; // include the node spring actions. - beam.numEndActions = numEndActions; - const EI = beam.EI; - - // The Direct Stiffness Method employs matrix methods to solve indeterminate structures. - // Textbooks describe the Direct Stiffness Method with one-based matrices. - // To avoid confusion, the code below employs arrays as if they were one-based. - // Since JavaScript arrays are actually zero-based, we will dimension each array with one - // element more than it needs. Then we'll leave array[0] unused. All our loops will be - // written as if we had one-based arrays. - - // Prepend elements to arrays `nodes` & `spans` so that they act like 1-based arrays. - nodes.unshift(0); - spans.unshift(0); - - // Find the Span Stiffness Matrix, SSM - // Imagine that a fixed-end span undergoes a displacement, Δ, down at its right end. - // (Notice that rotation, θ, is zero at both ends) - // ▄ █ - // █ █ - // █▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,█──────┬── - // █ ▀▀▀▀▀▀▀▄▄▄▄ █ │ - // █ ▀▀▀▄▄▄▄▄ █ │ Δ - // █ ▀▀▀▀▄▄▄▄▄▄ █ │ - // ▀▀▀▀▀▀▀▀▀▀▀▀▀▀█──────┴── - // █ - // If we draw the free-body diagram of the span, we would see these forces: - // V_left = 6EIΔ/L², upward - // M_left = 12EIΔ/L³, clockwise - // V_right = 6EIΔ/L², downward - // M_right = 12EIΔ/L³, clockwise - // The Span Stiffness Matrix is populated, for each span, with just those stiffnesses. - - const ssm = []; // Span Stiffnes Matrix, not yet the Stiffness Matrix. - ssm.push([0, 0, 0, 0, 0]); - for (let i = 1; i <= numSpans; i++) { - const subMatrix = [ - [0, 0, 0, 0, 0], - [0, 0, 0, 0, 0], - [0, 0, 0, 0, 0], - [0, 0, 0, 0, 0], - [0, 0, 0, 0, 0] - ]; - subMatrix[1][1] = EI * 12 / spans[i].length ** 3; - subMatrix[1][2] = EI * 6 / spans[i].length ** 2; - subMatrix[1][3] = -EI * 12 / spans[i].length ** 3; - subMatrix[1][4] = EI * 6 / spans[i].length ** 2; - subMatrix[2][1] = EI * 6 / spans[i].length ** 2; - subMatrix[2][2] = EI * 4 / spans[i].length; - subMatrix[2][3] = -EI * 6 / spans[i].length ** 2; - subMatrix[2][4] = EI * 2 / spans[i].length; - subMatrix[3][1] = -EI * 12 / spans[i].length ** 3; - subMatrix[3][2] = -EI * 6 / spans[i].length ** 2; - subMatrix[3][3] = EI * 12 / spans[i].length ** 3; - subMatrix[3][4] = -EI * 6 / spans[i].length ** 2; - subMatrix[4][1] = EI * 6 / spans[i].length ** 2; - subMatrix[4][2] = EI * 2 / spans[i].length; - subMatrix[4][3] = -EI * 6 / spans[i].length ** 2; - subMatrix[4][4] = EI * 4 / spans[i].length; - ssm.push(subMatrix); - } - - //Find dtm, the Displacement Transformation Matrix - const dtm = new Array(numEndActions + 1).fill(0).map(e => { - return new Array(numDegreesOfFreedom + 1).fill(0) - }); - let j = 0; - for (let i = 1; i <= numNodes; i++) { - if (i === 1) { - if (nodes[i].fixity === "continuous" || nodes[i].fixity === "spring") { - dtm[1][1] = 1; - dtm[2][1] = 1; - dtm[3][2] = 1; - j = 2; - } else if (nodes[i].fixity === "fixed") ; else if (nodes[i].fixity === "pinned") { - dtm[3][1] = 1; - j = 1; - } - } else if (i === numNodes) { - if (nodes[i].fixity === "continuous" || nodes[i].fixity === "spring") { - j = j + 1; - dtm[5 * numSpans - 1][j] = 1; - j = j + 1; - dtm[5 * numSpans][j] = 1; - dtm[5 * numSpans + 1][j - 1] = 1; - } else if (nodes[i].fixity === "fixed") ; else if (nodes[i].fixity === "pinned") { - j = j + 1; - dtm[5 * numSpans][j] = 1; - } - } else { - if (nodes[i].fixity === "continuous" || nodes[i].fixity === "spring") { - j = j + 1; - dtm[5 * (i - 1) - 1][j] = 1; - dtm[5 * (i - 1) + 1][j] = 1; - dtm[5 * (i - 1) + 2][j] = 1; - j = j + 1; - dtm[5 * (i - 1)][j] = 1; - dtm[5 * (i - 1) + 3][j] = 1; - } else if (nodes[i].fixity === "hinge") { - j = j + 1; - dtm[5 * (i - 1) - 1][j] = 1; - dtm[5 * (i - 1) + 1][j] = 1; - dtm[5 * (i - 1) + 2][j] = 1; - j = j + 1; - dtm[5 * (i - 1)][j] = 1; - j = j + 1; - dtm[5 * (i - 1) + 3][j] = 1; - } else if (nodes[i].fixity === "proppedHinge") { - j = j + 1; - dtm[5 * (i - 1)][j] = 1; - j = j + 1; - dtm[5 * (i - 1) + 3][j] = 1; - } else if (nodes[i].fixity === "fixed") ; else if (nodes[i].fixity === "pinned") { - j = j + 1; - dtm[5 * (i - 1)][j] = 1; - dtm[5 * (i - 1) + 3][j] = 1; - } - } - } - - //Now do the first matrix operations - const lsmDtm = createLsmDtm(ssm, dtm, nodes, numEndActions, numDegreesOfFreedom); - // Create the Stiffness Matrix. - const [sm, bandWidth] = createSM(dtm, lsmDtm, numDegreesOfFreedom); - - let diag = []; - let ltm = []; - if (numDegreesOfFreedom > 1) { - [diag, ltm] = luDecomposition(sm, bandWidth); - } - - //Find the number of load patterns - beam.containsLive = false; - for (let i = 1; i <= beam.numLoadTypes; i++) { - if (beam.getsPattern[i]) { beam.containsLive = true; break } - } - const numPatterns = !beam.containsLive - ? 1 - : !beam.doLiveLoadPatterns - ? 1 - : numSpans > 7 - ? beam.patterns - : 2; - - // Initialize some variables - const feam = new Array(numEndActions + 1).fill(0); // Fixed End Action Matrix - const nfm = new Array(numDegreesOfFreedom + 1).fill(0); // Nodal Force Matrix - let mam; // Member Action Matrix - let dm; // Displacement Matrix - const actions = new Array(beam.numLoadTypes); - const deflections = new Array(beam.numLoadTypes); - for (let i = 0; i <= beam.numLoadTypes; i++) { - if (beam.getsPattern[i]) { - actions[i] = new Array(numEndActions + 1).fill(0); - for (let j = 0; j < actions[i].length; j++) { - actions[i][j] = new Array(numDegreesOfFreedom).fill(0); - } - deflections[i] = new Array(numDegreesOfFreedom + 1).fill(0); - for (let j = 0; j < deflections[i].length; j++) { - deflections[i][j] = Array(numSpans + 1).fill(0); - } - } else { - actions[i] = new Array(numEndActions).fill(0); - deflections[i] = new Array(numDegreesOfFreedom).fill(0); - } - } - - //Find a Member end Action Matrix, mam for each type of load, Service, D, L, S, W, E, etc - //For the live loads, find a different mam due to loads on each individual span. - for (let loadType = 0; loadType <= 9; loadType++) { - if (loadType === 0 || gotType[loadType]) { - let lastK = 0; - let doPatterns = false; // patterned live loads - if (loadType === 0) { - doPatterns = false; - lastK = 1; - } else if (isLiveish(loadType, beam) && numPatterns > 1) { - doPatterns = true; - // To do load patterns, we have to get a Member Action Matrix, mam, for each span. - lastK = numSpans; - } else { - doPatterns = false; - lastK = 1; - } - - for (let k = 1; k <= lastK; k++) { - for (let i = 1; i <= numSpans; i++) { - const L = spans[i].length; - const iSpring = 5 * i - 4; - const i1 = 5 * i - 3; - const i2 = 5 * i - 2; - const i3 = 5 * i - 1; - const i4 = 5 * i; - - // Find the fixed end actions - feam[iSpring] = 0; - feam[i1] = 0; //The left end reaction if this segment were a fixed/fixed beam. - feam[i2] = 0; //The left fixed end moment - feam[i3] = 0; //The right end reaction - feam[i4] = 0; //The right fixed end moment - let applyLoadsFromThisSpan = false; - if (!doPatterns) { - // We are not doing live load patterns. - // So make one pass thru the beam and get a MAM that is the result of all loads. - applyLoadsFromThisSpan = true; - } else { - // We are doing live load patterns. - // k = number of spans. - // Make k passes thru the beam. - // In the kth pass, we calclate a MAM for the entire beam that results from - // live loads on just the kth span. - // The other spans have FEAM = [0, 0, etc] as their contribution to this MAM. - // Having k MAMs will enable us later to superimpose forces for each pattern. - applyLoadsFromThisSpan = i === k; - } - - if (applyLoadsFromThisSpan) { - for (let iSeg = 0; iSeg < spans[i].segments.length; iSeg++) { - const seg = spans[i].segments[iSeg]; - // In the next few lines, - // a is the distance from the beginning of the span to the load point. - // b is the length of the load. - // c is the distance from the end of the load to the right edge of the span. - // e is the distance from the left edge of the load to the right end of the span. - // d is the distance from the right edge of the load to the left edge of the span - let w = 0; - let s = 0; - const a = seg.xOfLeftEnd - nodes[i].x; - let b = seg.length; - let c = L - a - b; - let d = a + b; - const e = b + c; - let gotOppSigns = false; - let a2 = 0; - let b2 = 0; - let c2 = 0; - let d2 = 0; - let e2 = 0; - - if (Math.abs(seg.w1[loadType]) < 0.000000001) { seg.w1[loadType] = 0; } - if (Math.abs(seg.w2[loadType]) < 0.000000001) { seg.w2[loadType] = 0; } - - if (seg.w1[loadType] !== 0 && seg.w2[loadType] !== 0 && - Math.sign(seg.w1[loadType]) !== Math.sign(seg.w2[loadType])) { - gotOppSigns = true; - w = 0; - s = (seg.w2[loadType] - seg.w1[loadType]) / b; //slope of line load - a2 = a - seg.w1[loadType] / s; - b2 = d - a2; - c2 = c; - d2 = d; - e2 = d2 - b2; - b = a2 - a; - d = a + b; - c = L - d; - - } else { - gotOppSigns = false; - w = Math.abs(seg.w1[loadType]) < Math.abs(seg.w2[loadType]) - ? seg.w1[loadType] - : seg.w2[loadType]; - } - - if (a === 0) { - feam[iSpring] = seg.P[loadType]; - } else { - //FEA for point loads - feam[i2] = feam[i2] + seg.P[loadType] * a * e ** 2 / L ** 2; - feam[i4] = feam[i4] - seg.P[loadType] * a ** 2 * e / L ** 2; - feam[i2] = feam[i2] - seg.M[loadType] * (-1 + 4 * a / L - 3 * a ** 2 / L ** 2); - feam[i4] = feam[i4] - seg.M[loadType] * a / L * (2 - 3 * a / L); - feam[i1] = feam[i1] + seg.P[loadType] * e ** 2 / L ** 3 * (3 * a + e); - feam[i3] = feam[i3] + seg.P[loadType] * a ** 2 / L ** 3 * (a + 3 * e); - feam[i1] = feam[i1] - 6 * seg.M[loadType] * a / L ** 2 * (1 - a / L); - feam[i3] = feam[i3] + 6 * seg.M[loadType] * a / L ** 2 * (1 - a / L); - } - - //FEA for uniform loads - if (w !== 0) { - const mA = (w * b / (12 * L ** 2 * b)) * (e ** 3 * (4 * L - 3 * e) - - c ** 3 * (4 * L - 3 * c)); - feam[i2] = feam[i2] + mA; - const mB = (w * b / (12 * L ** 2 * b)) * (d ** 3 * (4 * L - 3 * d) - - a ** 3 * (4 * L - 3 * a)); - feam[i4] = feam[i4] - mB; - feam[i1] = feam[i1] + (w * b / (2 * L)) * (2 * c + b) + (mA - mB) / L; - feam[i3] = feam[i3] + (w * b / (2 * L)) * (2 * a + b) + (mB - mA) / L; - } - - //FEA for triangular loads - if (Math.abs(seg.w1[loadType]) > Math.abs(seg.w2[loadType]) || gotOppSigns) { - const wL = seg.w1[loadType] - w; - // const wR = 0 - const wT = wL; - const centerOfTriangle = a + b / 3; - const wF = wT * d / b; - const mA = (wF * L ** 2 / 60) * (d / L) ** 2 * (10 - 10 * d / L - + 3 * d ** 2 / L ** 2) - - ((wF - wT) * L ** 2 / 60) * (a / L) ** 2 - * (10 - 10 * a / L + 3 * a ** 2 / L ** 2) - - (wT * L ** 2 / 12) * (a / L) ** 2 * (6 - 8 * a / L + 3 * a ** 2 / L ** 2); - feam[i2] = feam[i2] + mA; - const mB = (wF * L ** 2 / 60) * (d / L) ** 3 * (5 - 3 * d / L) - - ((wF - wT) * L ** 2 / 60) * (a / L) ** 3 * (5 - 3 * a / L) - - (wT * L ** 2 / 12) * (a / L) ** 3 * (4 - 3 * a / L); - feam[i4] = feam[i4] - mB; - feam[i1] = feam[i1] - + 0.5 * (wT * b) * (L - centerOfTriangle) / L + (mA - mB) / L; - feam[i3] = feam[i3] + 0.5 * (wT * b) * centerOfTriangle / L + (mB - mA) / L; - - } else if (Math.abs(seg.w2[loadType]) > Math.abs(seg.w1[loadType])) { - // const wL = 0 - const wR = seg.w2[loadType] - w; - const wT = wR; - const centerOfTriangle = a + 2 * b / 3; - const wF = wT * e / b; - const mA = (wF * L ** 2 / 60) * (e / L) ** 3 * (5 - 3 * e / L) - - ((wF - wT) * L ** 2 / 60) * (c / L) ** 3 * (5 - 3 * c / L) - - (wT * L ** 2 / 12) * (c / L) ** 3 * (4 - 3 * c / L); - feam[i2] = feam[i2] + mA; - const mB = (wF * L ** 2 / 60) * (e / L) ** 2 - * (10 - 10 * e / L + 3 * e ** 2 / L ** 2) - - ((wF - wT) * L ** 2 / 60) * (c / L) ** 2 - * (10 - 10 * c / L + 3 * c ** 2 / L ** 2) - - (wT * L ** 2 / 12) * (c / L) ** 2 * (6 - 8 * c / L + 3 * c ** 2 / L ** 2); - feam[i4] = feam[i4] - mB; - feam[i1] = feam[i1] - + 0.5 * (wT * b) * (L - centerOfTriangle) / L + (mA - mB) / L; - feam[i3] = feam[i3] + 0.5 * (wT * b) * centerOfTriangle / L + (mB - mA) / L; - } - if (gotOppSigns) { - //Do the right-hand triangle load - // const wL = 0 - // const wR = seg.w2[loadType] - const wT = seg.w2[loadType]; - const centerOfTriangle = a2 + 2 * b2 / 3; - const wF = wT * e2 / b2; - const mA = (wF * L ** 2 / 60) * (e2 / L) ** 3 * (5 - 3 * e2 / L) - - ((wF - wT) * L ** 2 / 60) * (c2 / L) ** 3 * (5 - 3 * c2 / L) - - (wT * L ** 2 / 12) * (c2 / L) ** 3 * (4 - 3 * c2 / L); - feam[i2] = feam[i2] + mA; - const mB = (wF * L ** 2 / 60) * (e2 / L) ** 2 - * (10 - 10 * e2 / L + 3 * e2 ** 2 / L ** 2) - - ((wF - wT) * L ** 2 / 60) * (c2 / L) ** 2 - * (10 - 10 * c2 / L + 3 * c2 ** 2 / L ** 2) - // eslint-disable-next-line max-len - - (wT * L ** 2 / 12) * (c2 / L) ** 2 * (6 - 8 * c2 / L + 3 * c2 ** 2 / L ** 2); - feam[i4] = feam[i4] - mB; - feam[i1] = feam[i1] - + 0.5 * (wT * b2) * (L - centerOfTriangle) / L + (mA - mB) / L; - feam[i3] = feam[i3] + 0.5 * (wT * b2) * centerOfTriangle / L + (mB - mA) / L; - } - } - } - } - - //Find the Nodal Force Matrix, NFM - let j = 0; - for (let i = 1; i <= numNodes; i++) { - if (i === 1) { - if (nodes[i].fixity === "continuous" || nodes[i].fixity === "spring") { - nfm[1] = -feam[1] - feam[2]; - nfm[2] = -feam[3]; - if (isLiveish(loadType, beam) && numPatterns > 1) { - if (k === 0) { - nfm[1] = nfm[1] - nodes[1].P[loadType]; - nfm[2] = nfm[2] - nodes[1].M[loadType]; - } - } else { - nfm[1] = nfm[1] - nodes[1].P[loadType]; - nfm[2] = nfm[2] - nodes[1].M[loadType]; - } - - j = 2; - } else if (nodes[i].fixity === "fixed") ; else if (nodes[i].fixity === "pinned") { - j += 1; - nfm[1] = -feam[3]; - if (isLiveish(loadType, beam) && numPatterns > 1) { - if (k === 1) { - nfm[j] = nfm[j] - nodes[1].M[loadType]; - } - } else { - nfm[j] = nfm[j] - nodes[1].M[loadType]; - } - } - } else if (i === numNodes) { - if (nodes[i].fixity === "continuous" || nodes[i].fixity === "spring") { - j += 1; - nfm[j] = -feam[5 * numSpans - 1] - feam[5 * numSpans + 1]; - j += 1; - nfm[j] = -feam[5 * numSpans]; - if (isLiveish(loadType, beam) && numPatterns > 1) { - if (k === numSpans) { - nfm[j - 1] = nfm[j - 1] - nodes[numNodes].P[loadType]; - nfm[j] = nfm[j] - nodes[numNodes].M[loadType]; - } - } else { - nfm[j - 1] = nfm[j - 1] - nodes[numNodes].P[loadType]; - nfm[j] = nfm[j] - nodes[numNodes].M[loadType]; - } - } else if (nodes[i].fixity === "fixed") ; else if (nodes[i].fixity === "pinned") { - j += 1; - nfm[j] = -feam[5 * numSpans]; - if (isLiveish(loadType, beam) && numPatterns > 1) { - if (k === numSpans) { - nfm[j] = nfm[j] - nodes[numNodes].M[loadType]; - } - } else { - nfm[j] = nfm[j] - nodes[numNodes].M[loadType]; - } - } - } else { - if (nodes[i].fixity === "continuous" || nodes[i].fixity === "spring") { - j += 1; - nfm[j] = -feam[5 * (i - 1) - 1] - feam[5 * (i - 1) + 1] - feam[5 * (i - 1) + 2]; - j += 1; - nfm[j] = -feam[5 * (i - 1)] - feam[5 * (i - 1) + 3]; - if ((loadType === 3 || loadType === 5 || loadType === 6) && numPatterns > 1) { - if (k === i) { - nfm[j - 1] = nfm[j - 1] - nodes[i].P[loadType]; - nfm[j] = nfm[j] - nodes[i].M[loadType]; - } - } else { - nfm[j - 1] = nfm[j - 1] - nodes[i].P[loadType]; - nfm[j] = nfm[j] - nodes[i].M[loadType]; - } - } else if (nodes[i].fixity === "hinge") { - j += 1; - nfm[j] = -feam[5 * (i - 1) - 1] - feam[5 * (i - 1) + 1] - feam[5 * (i - 1) + 2]; - j += 1; - nfm[j] = -feam[5 * (i - 1)]; - if ((loadType === 3 || loadType === 5 || loadType === 6) && numPatterns > 1) { - if (k === i) { - nfm[j - 1] = nfm[j - 1] - nodes[i].P[loadType]; - nfm[j] = nfm[j] - nodes[i].M[loadType]; - } - } else { - nfm[j - 1] = nfm[j - 1] - nodes[i].P[loadType]; - nfm[j] = nfm[j] - nodes[i].M[loadType]; - } - - j += 1; - nfm[j] = -feam[5 * (i - 1) + 3]; - } else if (nodes[i].fixity === "proppedHinge") { - j += 1; - nfm[j] = -feam[5 * (i - 1)]; - j += 1; - nfm[j] = -feam[5 * (i - 1) + 3]; - } else if (nodes[i].fixity === "fixed") ; else if (nodes[i].fixity === "pinned") { - j += 1; - nfm[j] = -feam[5 * (i - 1)] - feam[5 * (i - 1) + 3]; - if ((loadType === 3 || loadType === 5 || loadType === 6) && numPatterns > 1) { - if (k === i) { - nfm[j] = nfm[j] - nodes[i].M[loadType]; - } - } else { - nfm[j] = nfm[j] - nodes[i].M[loadType]; - } - } - } - } - - //Now do the rest of the matrix operations for the current load type - if (numDegreesOfFreedom === 0) { - dm = [0]; - } else if (numDegreesOfFreedom === 1) { - dm = [0, nfm[1] / sm[1][1]]; - } else { - dm = solveViaLDLt(diag, ltm, nfm, bandWidth); - } - - // Get the Member Action Matrix, MAM. - // Multiply lsmDtm times dm, then add the resulting column vector to the FEAM - mam = lsmDtm.map(row => dotProduct(row, dm)).map((e, i) => e + feam[i]); - - //Set elements of mam = 0 where fixity so dictates - for (let i = 1; i <= numEndActions; i++) { - if (Math.abs(mam[i]) < 0.00000000000001) { mam[i] = 0; } - } - - if ((!beam.getsPattern[loadType]) || typeof actions[loadType][0] === "number") { - actions[loadType] = clone(mam); - if (EI !== 1) { deflections[loadType] = clone(dm); } - } else { - for (let j = 1; j < 5 * numSpans + 1; j++) { - actions[loadType][j][k - 1] = mam[j]; //mam for live loads on span k - } - if (EI !== 1) { - for (let j = 1; j <= numDegreesOfFreedom; j++) { - deflections[loadType][j][k] = dm[j]; - } - } - } - - // Find the reactions - if (numPatterns === 1 || !(beam.containsLive && isLiveish(loadType, beam))) { - if (nodes[1].fixity === "fixed") { - nodes[1].Mr[loadType] = mam[3] + nodes[1].M[loadType]; - } - if (nodes[1].fixity === "spring") { - nodes[1].Pr[loadType] = mam[1]; - } else if (nodes[1].fixity !== "continuous") { - nodes[1].Pr[loadType] = -mam[2] - nodes[1].P[loadType]; - } - - for (let j = 2; j <= numSpans; j++) { - if (nodes[j].fixity === "fixed") { - nodes[j].Mr[loadType] = mam[5 * (j - 1)] - + mam[5 * (j - 1) + 3] + nodes[j].M[loadType]; - } - if (nodes[j].fixity === "spring") { - nodes[j].Pr[loadType] = mam[5 * (j - 1) + 1]; - } else if (nodes[j].fixity !== "continuous") { - nodes[j].Pr[loadType] = -mam[5 * (j - 1) - 1] - mam[5 * (j - 1) + 2] - - nodes[j].P[loadType]; - } - } - - if (nodes[numNodes].fixity === "fixed") { - nodes[numNodes].Mr[loadType] = mam[5 * numSpans] + nodes[numNodes].M[loadType]; - } - if (nodes[numNodes].fixity === "spring") { - nodes[numNodes].Pr[loadType] = mam[5 * numSpans + 1]; - } else if (nodes[numNodes].fixity !== "continuous") { - nodes[numNodes].Pr[loadType] = -mam[5 * numSpans - 1] - nodes[numNodes].P[loadType]; - } - } else { - let mTest = 0; - if (nodes[1].fixity === "fixed") { - mTest = mam[3] + nodes[1].M[loadType]; - if (mTest > 0) { nodes[1].Mr[loadType] = nodes[1].Mr[loadType] + mTest; } - if (mTest < 0) { nodes[1].MrMin[loadType] = nodes[1].MrMin[loadType] + mTest; } - } - let pTest = 0; - if (nodes[1].fixity === "spring") { - pTest = mam[1]; - } else if (nodes[1].fixity !== "continuous") { - pTest = -mam[2] - nodes[1].P[loadType]; - } - if (pTest > 0) { nodes[1].Pr[loadType] = nodes[1].Pr[loadType] + pTest; } - if (pTest < 0) { nodes[1].PrMin[loadType] = nodes[1].PrMin[loadType] + pTest; } - - for (let j = 1; j < numSpans; j++) { - if (nodes[j].fixity === "fixed") { - mTest = mam[5 * (j - 1)] + mam[5 * (j - 1) + 3] + nodes[j].M[loadType]; - if (mTest > 0) { nodes[j].Mr[loadType] = nodes[j].Mr[loadType] + mTest; } - if (mTest < 0) { nodes[j].MrMin[loadType] = nodes[j].MrMin[loadType] + mTest; } - } - pTest = 0; - if (nodes[j].fixity === "spring") { - nodes[j].Pr[loadType] = nodes[j].Pr[loadType] + mam[5 * (j - 1) + 1]; - } else if (nodes[j].fixity !== "continuous") { - pTest = -mam[5 * (j - 1) - 1] - mam[5 * (j - 1) + 2] - nodes[j].P[loadType]; - } - if (pTest > 0) { nodes[j].Pr[loadType] = nodes[j].Pr[loadType] + pTest; } - if (pTest < 0) { nodes[j].PrMin[loadType] = nodes[j].PrMin[loadType] + pTest; } - } - - if (nodes[numNodes].fixity === "fixed") { - mTest = mam[5 * numSpans] + nodes[numSpans].M[loadType]; - if (mTest > 0) { - nodes[numNodes].Mr[loadType] = nodes[numNodes].Mr[loadType] + mTest; - } - if (mTest < 0) { - nodes[numNodes].MrMin[loadType] = nodes[numNodes].MrMin[loadType] + mTest; - } - } - - pTest = 0; - if (nodes[numNodes].fixity === "spring") { - nodes[numNodes].Pr[loadType] = nodes[numNodes].Pr[loadType] + mam[5 * numSpans + 1]; - } else if (nodes[numNodes].fixity !== "continuous") { - pTest = -mam[5 * numSpans - 1] - nodes[j].P[loadType]; - } - if (pTest > 0) { - nodes[numNodes].Pr[loadType] = nodes[numNodes].Pr[loadType] + pTest; - } - if (pTest < 0) { - nodes[numNodes].PrMin[loadType] = nodes[numNodes].PrMin[loadType] + pTest; - } - } //finished finding the reactions - - } - } - } - return [actions, deflections] -} - -const createLsmDtm = (ssm, dtm, nodes, numEndActions, numDegreesOfFreedom) => { -// Create LSM × DTM - - let lsmDtm = new Array(numEndActions + 1).fill(0); - lsmDtm = lsmDtm.map(e => new Array(numDegreesOfFreedom + 1).fill(0)); - - for (let i = 1; i <= numEndActions; i++) { - const iSpan = Math.trunc((i - 1) / 5) + 1; - const g = i - 1 - 5 * (iSpan - 1); - - for (let j = 1; j <= numDegreesOfFreedom; j++) { - if (g === 0) { - lsmDtm[i][j] = nodes[iSpan].k * dtm[i][j]; - } else { - const kStart = 5 * iSpan - 3; - const kEnd = 5 * iSpan; - let h = 0; - for (let k = kStart; k <= kEnd; k++) { - h += 1; - lsmDtm[i][j] = lsmDtm[i][j] + ssm[iSpan][g][h] * dtm[k][j]; - } - } - } - } - return lsmDtm -}; - -const createSM = (dtm, lsmDtm, numDegreesOfFreedom) => { - // Create the Stiffness Matrix, SM. - // SM = DTM**T × LsmDtm - let sm = Array(numDegreesOfFreedom + 1).fill(0); - sm = sm.map(e => Array(numDegreesOfFreedom + 1).fill(0)); - const h = lsmDtm.length - 1; - let bandWidth = 1; - for (let i = 1; i < dtm[0].length; i++) { - for (let j = 1; j <= i; j++) { // Only the lower half of SM. - for (let k = 1; k <= h; k++) { - sm[i][j] = sm[i][j] + dtm[k][i] * lsmDtm[k][j]; // DTM**T, not DTM. - } - if (sm[i][j] !== 0 && i - j > bandWidth) { bandWidth = i - j;} // lower band width - } - } - return [sm, bandWidth] -}; - -const luDecomposition = (sm, bandWidth) => { - // Perform the LU Decomposition of the stiffness matrix, SM. - // This is in preparation for the LDL**T matrix solution to come later. - - const diag = new Array(sm.length).fill(0); - // Lower Triangular matrix, ltm - let ltm = new Array(sm.length).fill(0); - ltm = ltm.map(e => new Array(sm.length - 1).fill(0)); - - const n = sm.length - 1; // number of equations - - for (let j = 1; j <= n; j++) { - let kStar = Math.max(j - bandWidth, 1); - diag[j] = sm[j][j]; - for (let k = kStar; k <= j - 1; k++) { - diag[j] = diag[j] - diag[k] * ltm[j][k] * ltm[j][k]; - } - - const iMax = Math.min(j + bandWidth, n); - for (let i = j + 1; i <= iMax; i++) { - kStar = Math.max(i - bandWidth, 1); - let sum = 0; - for (let k = kStar; k <= j - 1; k++) { - sum = sum + diag[k] * ltm[j][k] * ltm[i][k]; - } - ltm[i][j] = (sm[i][j] - sum) / diag[j]; - } - } - return [diag, ltm] -}; - -const solveViaLDLt = (diag, ltm, b, bandWidth) => { - // Solve for dm() in a system of equations expressed by matrices: SM() × dm() = NFM() - - // This sub// s method is a banded version of the LDL**T solver. - // LDL**T takes advantage of the fact that SM is a symmetric, positive-definite matrix. - // The algorithm will overwrite b(), which starts out as NFM and ends as dm. - // We already have the diag & ltm matrices, so we can go directly to the LU solution. - - const n = b.length - 1; // number of equations - - // Forward substitution - for (let i = 2; i <= n; i++) { - const kStar = i - bandWidth < 1 ? 1 : i - bandWidth; - for (let k = kStar; k <= i - 1; k++) { - b[i] = b[i] - ltm[i][k] * b[k]; - } - } - - // Diagonal scaling and backward substitution - b[n] = b[n] / diag[n]; - for (let i = n - 1; i >= 1; i--) { - b[i] = b[i] / diag[i]; - const kStar = Math.min(n, i + bandWidth); - for (let k = i + 1; k <= kStar; k++) { - b[i] = b[i] - ltm[k][i] * b[k]; - } - } - - return b -}; - -function getLoadPatterns(beam, numSpans) { - if (!beam.containsLive || !beam.doLiveLoadPatterns) { - // Just one pattern. It includes each span. - const pattern = [1]; - for (let i = 2; i <= numSpans; i++) { - pattern.push(i); - } - return [pattern] - } else if (beam.numPatterns === 2 || numSpans > 7) { - // Do 2 patterns. One with all live load on, and one with all live load off. - const pattern = [1]; - for (let i = 2; i <= numSpans; i++) { - pattern.push(i); - } - return [pattern, []] - } else { - switch (numSpans) { - case 1: - return [[1], []] - case 2: - return [[1, 2], [], [1], [2]] - case 3: - return [[1, 2, 3], [], [1], [2], [3], [1, 2], [1, 3], [2, 3]] - case 4: - // eslint-disable-next-line max-len - return [[1, 2, 3, 4], [], [1], [2], [3], [4], [1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4], [1, 2, 3], [1, 2, 4], [1, 3, 4], [2, 3, 4]] - case 5: - // eslint-disable-next-line max-len - return [[1, 2, 3, 4, 5], [], [1], [2], [3], [4], [5], [1, 2], [1, 3], [1, 4], [1, 5], [2, 3], [2, 4], [2, 5], [3, 4], [3, 5], [4, 5], [1, 2, 3], [1, 2, 4], [1, 2, 5], [1, 3, 4], [1, 3, 5], [1, 4, 5], [2, 3, 4], [2, 3, 5], [2, 4, 5], [3, 4, 5], [1, 2, 3, 4], [1, 2, 3, 5], [1, 2, 4, 5], [1, 3, 4, 5], [2, 3, 4, 5]] - case 6: - // eslint-disable-next-line max-len - return [[1, 2, 3, 4, 5, 6], [], [1], [2], [3], [4], [5], [6], [1, 2], [1, 3], [1, 4], [1, 5], [1, 6], [2, 3], [2, 4], [2, 5], [2, 6], [3, 4], [3, 5], [3, 6], [4, 5], [4, 6], [5, 6], [1, 2, 3], [1, 2, 4], [1, 2, 5], [1, 2, 6], [1, 3, 4], [1, 3, 5], [1, 3, 6], [1, 4, 5], [1, 4, 6], [1, 5, 6], [2, 3, 4], [2, 3, 5], [2, 3, 6], [2, 4, 5], [2, 4, 6], [2, 5, 6], [3, 4, 5], [3, 4, 6], [3, 5, 6], [4, 5, 6], [1, 2, 3, 4], [1, 2, 3, 5], [1, 2, 3, 6], [1, 2, 4, 5], [1, 2, 4, 6], [1, 2, 5, 6], [1, 3, 4, 5], [1, 3, 4, 6], [1, 3, 5, 6], [1, 4, 5, 6], [2, 3, 4, 5], [2, 3, 4, 6], [2, 3, 5, 6], [2, 4, 5, 6], [3, 4, 5, 6], [1, 2, 3, 4, 5], [1, 2, 3, 4, 6], [1, 2, 3, 5, 6], [1, 2, 4, 5, 6], [1, 3, 4, 5, 6], [2, 3, 4, 5, 6]] - case 7: - // eslint-disable-next-line max-len - return [[1, 2, 3, 4, 5, 6, 7], [], [1], [2], [3], [4], [5], [6], [7], [1, 2], [1, 3], [1, 4], [1, 5], [1, 6], [1, 7], [2, 3], [2, 4], [2, 5], [2, 6], [2, 7], [3, 4], [3, 5], [3, 6], [3, 7], [4, 5], [4, 6], [4, 7], [5, 6], [5, 7], [6, 7], [1, 2, 3], [1, 2, 4], [1, 2, 5], [1, 2, 6], [1, 2, 7], [1, 3, 4], [1, 3, 5], [1, 3, 6], [1, 3, 7], [1, 4, 5], [1, 4, 6], [1, 4, 7], [1, 5, 6], [1, 5, 7], [1, 6, 7], [2, 3, 4], [2, 3, 5], [2, 3, 6], [2, 3, 7], [2, 4, 5], [2, 4, 6], [2, 4, 7], [2, 5, 6], [2, 5, 7], [2, 6, 7], [3, 4, 5], [3, 4, 6], [3, 4, 7], [3, 5, 6], [3, 5, 7], [3, 6, 7], [4, 5, 6], [4, 5, 7], [4, 6, 7], [5, 6, 7], [1, 2, 3, 4], [1, 2, 3, 5], [1, 2, 3, 6], [1, 2, 3, 7], [1, 2, 4, 5], [1, 2, 4, 6], [1, 2, 4, 7], [1, 2, 5, 6], [1, 2, 5, 7], [1, 2, 6, 7], [1, 3, 4, 5], [1, 3, 4, 6], [1, 3, 4, 7], [1, 3, 5, 6], [1, 3, 5, 7], [1, 3, 6, 7], [1, 4, 5, 6], [1, 4, 5, 7], [1, 4, 6, 7], [1, 5, 6, 7], [2, 3, 4, 5], [2, 3, 4, 6], [2, 3, 4, 7], [2, 3, 5, 6], [2, 3, 5, 7], [2, 3, 6, 7], [2, 4, 5, 6], [2, 4, 5, 7], [2, 4, 6, 7], [2, 5, 6, 7], [3, 4, 5, 6], [3, 4, 5, 7], [3, 4, 6, 7], [3, 5, 6, 7], [4, 5, 6, 7], [1, 2, 3, 4, 5], [1, 2, 3, 4, 6], [1, 2, 3, 4, 7], [1, 2, 3, 5, 6], [1, 2, 3, 5, 7], [1, 2, 3, 6, 7], [1, 2, 4, 5, 6], [1, 2, 4, 5, 7], [1, 2, 4, 6, 7], [1, 2, 5, 6, 7], [1, 3, 4, 5, 6], [1, 3, 4, 5, 7], [1, 3, 4, 6, 7], [1, 3, 5, 6, 7], [1, 4, 5, 6, 7], [2, 3, 4, 5, 6], [2, 3, 4, 5, 7], [2, 3, 4, 6, 7], [2, 3, 5, 6, 7], [2, 4, 5, 6, 7], [3, 4, 5, 6, 7], [1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 7], [1, 2, 3, 4, 6, 7], [1, 2, 3, 5, 6, 7], [1, 2, 4, 5, 6, 7], [1, 3, 4, 5, 6, 7], [2, 3, 4, 5, 6, 7]] - // We cannot get here. - } - } -} - -function populateMAM(loadFactors, combern, loadPattern, beam, nodes, spans, actions) { - let mam = new Array(beam.numEndActions).fill(0); // Member end Action Matrix - const numSpans = spans.length - 1; - const numNodes = nodes.length - 1; - const numPatterns = beam.numPatterns; - const didNode = new Array(numNodes); - - // Fill mam with dead load - const deadLoadFactor = loadFactors[1]; - mam = mam.map((e, i) => deadLoadFactor * actions[1][i]); - for (let i = 1; i <= numSpans; i++) { - nodes[i].Pf = deadLoadFactor * nodes[i].P[1]; - nodes[i].Mf = deadLoadFactor * nodes[i].M[1]; - for (let j = 0; j < spans[i].segments.length; j++) { - const seg = spans[i].segments[j]; - seg.w1f[combern] = deadLoadFactor * seg.w1[1]; - seg.w2f = deadLoadFactor * seg.w2[1]; - seg.Pf = deadLoadFactor * seg.P[1]; - seg.Mf = deadLoadFactor * seg.M[1]; - } - } - - // Superimpose the other load types onto mam. - for (let iLoadType = 2; iLoadType <= 9; iLoadType++) { - const loadFactor = loadFactors[iLoadType]; - if (loadFactor > 0 && beam.gotType[iLoadType]) { - if (!beam.getsPattern[iLoadType] || numPatterns === 1) { - mam = mam.map((e, i) => e + loadFactor * actions[iLoadType][i]); - for (let i = 1; i <= numSpans; i++) { - nodes[i].Pf = nodes[i].Pf + loadFactor * nodes[i].P[iLoadType]; - nodes[i].Mf = nodes[i].Mf + loadFactor * nodes[i].M[iLoadType]; - for (let j = 0; j < spans[i].segments.length; j++) { - const seg = spans[i].segments[j]; - seg.w1f[combern] = seg.w1f[combern] + loadFactor * seg.w1[iLoadType]; - seg.w2f = seg.w2f + loadFactor * seg.w2[iLoadType]; - seg.Pf = seg.Pf + loadFactor * seg.P[iLoadType]; - seg.Mf = seg.Mf + loadFactor * seg.M[iLoadType]; - } - } - } else { - // load case includes live load patterns - for (let k = 1; k <= numSpans; k++) { - if (loadPattern.includes(k)) { - let ii = 0; - for (let j = 1; j <= numSpans; j++) { - ii = 5 * j - 4; - mam[ii] = mam[ii] + loadFactor * actions[iLoadType][ii][k - 1]; - mam[ii + 1] = mam[ii + 1] + loadFactor * actions[iLoadType][ii + 1][k - 1]; - mam[ii + 2] = mam[ii + 2] + loadFactor * actions[iLoadType][ii + 2][k - 1]; - mam[ii + 3] = mam[ii + 3] + loadFactor * actions[iLoadType][ii + 3][k - 1]; - mam[ii + 4] = mam[ii + 4] + loadFactor * actions[iLoadType][ii + 4][k - 1]; - } - mam[ii + 5] = mam[ii + 5] + loadFactor * actions[iLoadType][ii + 5][k - 1]; - } - } - - // Do node loads. - // Include a node load if the span on either side is in the load pattern. - didNode.fill(false); - for (let i = 1; i <= numSpans; i++) { - if (loadPattern.includes(i)) { - if (!didNode[i]) { - nodes[i].Pf = nodes[i].Pf + loadFactor * nodes[i].P[iLoadType]; - nodes[i].Mf = nodes[i].Mf + loadFactor * nodes[i].M[iLoadType]; - didNode[i] = true; - } - if (!didNode[i + 1]) { - nodes[i + 1].Pf = nodes[i + 1].Pf + loadFactor * nodes[i + 1].P[iLoadType]; - nodes[i + 1].Mf = nodes[i + 1].Mf + loadFactor * nodes[i + 1].M[iLoadType]; - didNode[i + 1] = true; - } - } - for (let j = 0; j < spans[i].segments.length; j++) { - const seg = spans[i].segments[j]; - if (loadPattern.includes(i)) { - seg.w1f[combern] = seg.w1f[combern] + loadFactor * seg.w1[iLoadType]; - seg.w2f = seg.w2f + loadFactor * seg.w2[iLoadType]; - seg.Pf = seg.Pf + loadFactor * seg.P[iLoadType]; - seg.Mf = seg.Mf + loadFactor * seg.M[iLoadType]; - } - } - } - } - } - } - - for (let i = 1; i <= numSpans; i++) { - for (let j = 0; j < spans[i].segments.length; j++) { - const seg = spans[i].segments[j]; - if (seg.length !== 0) { - seg.slope[combern] = (seg.w2f - seg.w1f[combern]) / seg.length; - } - } - } - return mam -} - -function combine(beam, nodes, spans, actions, deflections, comboSet) { - // We already have member end actions for each load type on each span. - // In this function, we superimpose the load combinations and live load patterns and - // find the maximum and minimum shears and moments. - const numSpans = spans.length - 1; - const isService = comboSet === "service"; - if (isService) { comboSet = [[0, 1, 1, 1, 1, 1, 1, 1, 1, 1]]; } - const liveLoadPatterns = getLoadPatterns(beam, numSpans); - const numPatterns = liveLoadPatterns.length; - - let vMin = 0; - let vMax = 0; - let mMin = 0; - let mMax = 0; - let deflectionMax = 0; - let deflMaxCase = 0; - let deflectionMin = 0; - let deflMinCase = 0; - - // Get ready to do lots of different load combinations. - // Definition: "combern" is a conflation of the words "combination" and "pattern". - const numComberns = getNumComberns(comboSet, isService, beam, numPatterns); - - for (let i = 1; i <= numSpans; i++) { - for (let j = 0; j < spans[i].segments.length; j++) { - const seg = spans[i].segments[j]; - seg.w1f = new Array(numComberns).fill(0); - seg.w2f = 0; - seg.slope = new Array(numComberns).fill(0); - seg.V1 = new Array(numComberns).fill(0); - seg.M1 = new Array(numComberns).fill(0); - if (beam.EI !== 1) { - seg.theta1 = new Array(numPatterns).fill(0); - seg.delta1 = new Array(numPatterns).fill(0); - } - } - } - - // The number of interations through this next loop will be a function of - // both the number of load combinations and the number of load patterns. - // I define "combern" as a conflation of the words "combination" & "pattern" - // "combern" will be the loop index as we look at unique combinations of both - // load combinations and live load patterns. - // Each time through the loop, we;ll get the factored loads and the factored MAM - // To do this, we'll make much use of a subroutine called "PopulateMAM" - // It's called as: PopulateMAM loadFactors, combern, iPattern - // The load factors are factors from the ASCE or NBCC load combinations - - // As you can see below, we'll find a unique MAM for each iCombo and live load pattern. - // Then, we'll use the MAM to find the segment shears, moments, etc. - - let combern = 0; - - // iCombo 0 is for deflections only. We'll go thru each load pattern. - // iCombo 1 thru comboSet.length is for finding shear and moment extremes. As code - // requires, this often means testing many load combinations. - - for (let iCombo = 0; iCombo <= comboSet.length; iCombo++) { - const isReqd = iCombo === 0 && beam.EI !== 0 - ? true // Go thru each load pattern and find deflection extremes. - : isService - ? true - : isReqdCombo(comboSet[iCombo - 1], beam.gotType); - - if (isReqd) { - const loadFactors = iCombo === 0 && beam.EI !== 0 - ? [0, 1, 1, 1, 1, 1, 1, 1, 1, 1] - : comboSet[iCombo - 1]; - - for (let iPattern = 0; iPattern < numPatterns; iPattern++) { - const loadPattern = liveLoadPatterns[iPattern]; - - // Get the Member Action Matrix, MAM, for this combern. - // A MAM contains the end shears and end moments for each span. - const mam = populateMAM(loadFactors, combern, loadPattern, beam, nodes, spans, actions); - - let dm; - if (iCombo === 0 && beam.EI !== 1) { - // Create a Displacement Matrix, DM, for this load combination and load pattern. - dm = new Array(beam.numDegreesOfFreedom + 1).fill(0); - for (let iLoadType = 1; iLoadType < 10; iLoadType++) { - if (beam.gotType[iLoadType]) { - if (beam.getsPattern[iLoadType]) { - dm = getLiveDM(dm, deflections[iLoadType], loadPattern, numSpans); - } else { - dm = dm.map((e, i) => e + deflections[iLoadType][i]); - } - } - } - } - - let iDM = 0; - for (let iSpan = 1; iSpan <= numSpans; iSpan++) { - let vMid = 0; - let vEnd = 0; - let mMid = 0; - let mEnd = 0; - let slopeEnd = 0; - let deflectionEnd = 0; - let deflectionMid = 0; - for (let k = 0; k < spans[iSpan].segments.length; k++) { - const seg = spans[iSpan].segments[k]; - - if (k === 0) { - // The first segment in this span. - seg.V1[combern] = -mam[5 * iSpan - 3]; - seg.M1[combern] = mam[5 * iSpan - 2]; - if (iCombo === 0 && beam.EI !== 1) { - iDM = getThetaAndDelta(nodes[iSpan].fixity, dm, seg, combern, iDM); - } - } else { - // Subsequent segments. - seg.V1[combern] = vEnd + seg.Pf; - seg.M1[combern] = mEnd - seg.Mf; - if (iCombo === 0 && beam.EI !== 1) { - seg.theta1[combern] = slopeEnd; - seg.delta1[combern] = deflectionEnd; - } - } - - vEnd = seg.V1[combern] + seg.w1f[combern] * seg.length - + 0.5 * seg.slope[combern] * seg.length ** 2; - if (Math.abs(vEnd) < 0.00000000000001) { vEnd = 0; } - - mEnd = seg.M1[combern] + seg.V1[combern] * seg.length - + 0.5 * seg.w1f[combern] * seg.length ** 2 - + seg.slope[combern] * seg.length ** 3 / 6; - if (Math.abs(mEnd) < 0.00000000000001) { mEnd = 0; } - - if (iCombo === 0) { - // Check if this load pattern contains a deflection extreme. - if (beam.EI !== 1) { - slopeEnd = seg.theta1[combern] + (seg.M1[combern] * seg.length - + 0.5 * seg.V1[combern] * seg.length ** 2 - + seg.w1f[combern] * seg.length ** 3 / 6 - + seg.slope[combern] * seg.length ** 4 / 24) / beam.EI; - deflectionMid = seg.delta1[combern] + seg.theta1[combern] * 0.5 * seg.length - + (0.5 * seg.M1[combern] * (0.5 * seg.length) ** 2 - + seg.V1[combern] * (0.5 * seg.length) ** 3 / 6 - + seg.w1f[combern] * (0.5 * seg.length) ** 4 / 24 - + seg.slope[combern] * (0.5 * seg.length) ** 5 / 120) / beam.EI; - deflectionEnd = seg.delta1[combern] + seg.theta1[combern] * seg.length - + (0.5 * seg.M1[combern] * seg.length ** 2 - + seg.V1[combern] * seg.length ** 3 / 6 - + seg.w1f[combern] * seg.length ** 4 / 24 - + seg.slope[combern] * seg.length ** 5 / 120) / beam.EI; - if (seg.delta1[combern] > deflectionMax) { - deflectionMax = seg.delta1[combern]; - deflMaxCase = combern; - } - if (seg.delta1[combern] < deflectionMin) { - deflectionMin = seg.delta1[combern]; - deflMaxCase = combern; - } - if (deflectionEnd > deflectionMax) { - deflectionMax = deflectionEnd; - deflMaxCase = combern; - } - if (deflectionEnd < deflectionMin) { - deflectionMin = deflectionEnd; - deflMinCase = combern; - } - if (deflectionMid > deflectionMax) { - deflectionMax = deflectionMid; - deflMaxCase = combern; - } - if (deflectionMid < deflectionMin) { - deflectionMin = deflectionMid; - deflMinCase = combern; - } - } - } else { - // Determine if this combern contains a shear or moment extreme. - // Start by finding the shear value in the middle of the segment - let xCross = 0; // initialze the variable - if (seg.slope[combern] !== 0) { - xCross = -1 * seg.w1f[combern] / seg.slope[combern]; - if (xCross > 0 && xCross < seg.length) { - vMid = seg.V1[combern] + seg.w1f[combern] * xCross - + 0.5 * seg.slope[combern] * xCross ** 2; - } else { - vMid = seg.V1[combern] + seg.w1f[combern] * (seg.length / 2) - + 0.5 * seg.slope[combern] * (seg.length / 2) ** 2; - } - } else { - vMid = seg.V1[combern] + seg.w1f[combern] * (seg.length / 2) - + 0.5 * seg.slope[combern] * (seg.length / 2) ** 2; - } - - // Find the moment in the middle of the segment - xCross = 0; // initialze the variable - if (seg.slope[combern] === 0) { - if (seg.w1f[combern] !== 0) { - xCross = -seg.V1[combern] / seg.w1f[combern]; - } - } else { - if ((seg.w1f[combern] ** 2 - 2 * seg.slope[combern] * seg.V1[combern]) > 0) { - xCross = -(seg.w1f[combern] + Math.sqrt(seg.w1f[combern] ** 2 - - 2 * seg.slope[combern] * seg.V1[combern])) / seg.slope[combern]; - } - } - if (xCross > 0 && xCross < seg.length) { - mMid = seg.M1[combern] + seg.V1[combern] * xCross - + 0.5 * seg.w1f[combern] * xCross ** 2 - + seg.slope[combern] * xCross ** 3 / 6; - } else { - mMid = seg.M1[combern] + seg.V1[combern] * (seg.length / 2) - + 0.5 * seg.w1f[combern] * (seg.length / 2) ** 2 - + seg.slope[combern] * (seg.length / 2) ** 3 / 6; - } - - // Check for local maximums and minimums - if (seg.V1[combern] > seg.Vmax.left.value && seg.V1[combern] > 0.01) { - seg.Vmax.left.value = seg.V1[combern]; - seg.Vmax.left.case = combern; // This is a case that we// ll want to plot - if (seg.V1[combern] > vMax) { vMax = seg.V1[combern]; } - } - - if (vMid > seg.Vmax.mid.value && vMid > 0.01) { - seg.Vmax.mid.value = vMid; - seg.Vmax.mid.case = combern; - if (vMid > vMax) { vMax = vMid; } - } - - if (vEnd > seg.Vmax.right.value && vEnd > 0.01) { - seg.Vmax.right.value = vEnd; - seg.Vmax.right.case = combern; - if (vEnd > vMax) { vMax = vEnd; } - } - - if (seg.V1[combern] < seg.Vmin.left.value && seg.V1[combern] < -0.01) { - seg.Vmin.left.value = seg.V1[combern]; - seg.Vmin.left.case = combern; - if (seg.V1[combern] < vMin) { vMin = seg.V1[combern]; } - } - - if (vMid < seg.Vmin.mid.value && vMid < -0.01) { - seg.Vmin.mid.value = vMid; - seg.Vmin.mid.case = combern; - if (vMid < vMin) { vMin = vMid; } - } - - if (vEnd < seg.Vmin.right.value && vEnd < -0.01) { - seg.Vmin.right.value = vEnd; - seg.Vmin.right.case = combern; - if (vEnd < vMin) { vMin = vEnd; } - } - - if (seg.M1[combern] > seg.Mmax.left.value && seg.M1[combern] > 0.01) { - seg.Mmax.left.value = seg.M1[combern]; - seg.Mmax.left.case = combern; - if (seg.M1[combern] > mMax) { mMax = seg.M1[combern]; } - } - - if (mMid > seg.Mmax.mid.value && mMid > 0.01) { - seg.Mmax.mid.value = mMid; - seg.Mmax.mid.case = combern; - seg.Mmax.mid.x = seg.xOfLeftEnd + xCross; - if (mMid > mMax) { mMax = mMid; } - } - - if (mEnd > seg.Mmax.right.value && mEnd > 0.01) { - seg.Mmax.right.value = mEnd; - seg.Mmax.right.case = combern; - if (mEnd > mMax) { mMax = mEnd; } - } - - if (seg.M1[combern] < seg.Mmin.left.value && seg.M1[combern] < -0.01) { - seg.Mmin.left.value = seg.M1[combern]; - seg.Mmin.left.case = combern; - if (seg.M1[combern] < mMin) { mMin = seg.M1[combern]; } - } - - if (mMid < seg.Mmin.mid.value && mMid < -0.01) { - seg.Mmin.mid.value = mMid; - seg.Mmin.mid.case = combern; - seg.Mmin.mid.x = seg.xOfLeftEnd + xCross; - if (mMid < mMin) { mMin = mMid; } - } - - if (mEnd < seg.Mmin.right.value && mEnd < -0.01) { - seg.Mmin.right.value = mEnd; - seg.Mmin.right.case = combern; - if (mEnd < mMin) { mMin = mEnd; } - } - } - - } - } - combern += 1; - } - } - } - return [vMax, vMin, mMax, mMin, deflectionMax, deflectionMin, - deflMaxCase, deflMinCase, numComberns] -} - -const isReqdCombo = (combo, gotType) => { - let isDeadLoadOnly = true; - for (let j = 2; j < combo.length; j++) { - if (combo[j] > 0) { - isDeadLoadOnly = false; - if (gotType[j]) { return true } - } - } - return isDeadLoadOnly -}; - -/*const comboContainsLive = (combo, beam) => { - for (let i = 1; i <= beam.numLoadTypes; i++) { - if (beam.getsPattern[i] && combo[i] !== 0) { return true } - } - return false -}*/ - -const getNumComberns = (comboSet, isService, beam, numPatterns) => { - // We'll do a superposition of forces for each load combination and each live load pattern. - // How many is that? - // First, count the number of comberns needed to do the deflection superpositions. - let numComberns = beam.EI === 1 ? 1 : numPatterns; - // Then add a combern for each superposition done to get shears and moments. - for (let i = 0; i < comboSet.length; i++) { - if (isService || isReqdCombo(comboSet[i], beam.gotType)) { - numComberns += numPatterns; - } - } - return numComberns -}; - -const getLiveDM = (a, b, loadPattern, numSpans) => { - if (Array.isArray(b[1])) { - for (let k = 1; k <= numSpans; k++) { - if (loadPattern.includes(k)) { - a = a.map((e, i) => e + b[i][k]); - } - } - } else { - a = a.map((e, i) => e + b[i]); - } - return a -}; - -const getThetaAndDelta = (fixity, dm, seg, i, iDM) => { - if (fixity === "fixed") { - seg.delta1[i] = 0; - seg.theta1[i] = 0; - } else if (fixity === "pinned") { - seg.delta1[i] = 0; - iDM = iDM + 1; - seg.theta1[i] = -dm[iDM]; - } else if (fixity === "continuous") { - iDM = iDM + 1; - seg.delta1[i] = -dm[iDM]; - iDM = iDM + 1; - seg.theta1[i] = -dm[iDM]; - } else if (fixity === "spring") { - iDM = iDM + 1; - seg.delta1[i] = -dm[iDM]; - iDM = iDM + 1; - seg.theta1[i] = -dm[iDM]; - } else if (fixity === "proppedHinge") { - iDM = iDM + 1; - seg.delta1[i] = 0; - iDM = iDM + 1; - seg.theta1[i] = -dm[iDM]; - } else if (fixity === "hinge") { - iDM = iDM + 1; - seg.delta1[i] = -dm[iDM]; - iDM = iDM + 1; - iDM = iDM + 1; - seg.theta1[i] = -dm[iDM]; - } - return iDM -}; - -// Review the segments. Find out which comberns should be displayed -function selectCases(spans) { - const shearCases = []; - const bendingCases = []; - for (let i = 1; i < spans.length; i++) { - for (let j = 0; j < spans[i].segments.length; j++) { - const seg = spans[i].segments[j]; - if (seg.Vmax.left.value > 0) { - if (!shearCases.includes(seg.Vmax.left.case)) { - shearCases.push(seg.Vmax.left.case); - } - } - if (seg.Vmin.left.value < 0) { - if (!shearCases.includes(seg.Vmin.left.case)) { - shearCases.push(seg.Vmin.left.case); - } - } - if (seg.Mmax.left.value > 0) { - if (!bendingCases.includes(seg.Mmax.left.case)) { - bendingCases.push(seg.Mmax.left.case); - } - } - if (seg.Mmin.left.value < 0) { - if (!bendingCases.includes(seg.Mmin.left.case)) { - bendingCases.push(seg.Mmin.left.case); - } - } - if (seg.Vmax.mid.value > 0) { - if (!shearCases.includes(seg.Vmax.mid.case)) { - shearCases.push(seg.Vmax.mid.case); - } - } - if (seg.Vmin.mid.value < 0) { - if (!shearCases.includes(seg.Vmin.mid.case)) { - shearCases.push(seg.Vmin.mid.case); - } - } - if (seg.Mmax.mid.value > 0) { - if (!bendingCases.includes(seg.Mmax.mid.case)) { - bendingCases.push(seg.Mmax.mid.case); - } - } - if (seg.Mmin.mid.value < 0) { - if (!bendingCases.includes(seg.Mmin.mid.case)) { - bendingCases.push(seg.Mmin.mid.case); - } - } - if (seg.Vmax.right.value > 0) { - if (!shearCases.includes(seg.Vmax.right.case)) { - shearCases.push(seg.Vmax.right.case); - } - } - if (seg.Vmin.right.value < 0) { - if (!shearCases.includes(seg.Vmin.right.case)) { - shearCases.push(seg.Vmin.right.case); - } - } - if (seg.Mmax.right.value > 0) { - if (!bendingCases.includes(seg.Mmax.right.case)) { - bendingCases.push(seg.Mmax.right.case); - } - } - if (seg.Mmin.right.value < 0) { - if (!bendingCases.includes(seg.Mmin.right.case)) { - bendingCases.push(seg.Mmin.right.case); - } - } - } - } - return [shearCases, bendingCases] -} - -function locateDiagrams(beam, extremes) { - // Find the y-coordinates for the shear, moment, and deflection diagrams. - - // First, find out how many reaction vectors will be written onto the load diagram. - const [vMax, vMin, mMax, mMin, deflectionMax, deflectionMin, , , ] = extremes; - - const vScale = vMax - vMin > 0 ? 60 / (vMax - vMin) : 0; - const mScale = mMax - mMin > 0 ? 60 / (mMax - mMin) : 0; - const reactionTextHeight = 16; - - let yV = vMax > 0.0005 - ? beam.yLoad + 12 + reactionTextHeight + vMax * vScale + 70 - : beam.yLoad + 12 + reactionTextHeight; - yV = Math.round(yV); - const botOfV = vMin < -0.0005 - ? yV + vMin * vScale + 50 - : yV + 70; - const momentMax = beam.convention === 1 ? mMax : Math.abs(mMin); - const momentMin = beam.convention === 1 ? Math.abs(mMin) : mMax; - let yM = momentMax > 0.0005 - ? botOfV + 12 + momentMax * mScale + 40 - : botOfV + 12; - yM = Math.round(yM); - let yMax = yM; - - // Get yText for moment - let yText = yM - mScale * mMin; - if (yText > yMax) { yMax = yText; } - - let yDeflection = 0; - let deflectionScale = 0; - if (beam.EI !== 1) { - // eslint-disable-next-line max-len - if (deflectionMax > deflectionMin) { deflectionScale = 30 / (deflectionMax - deflectionMin); } - const botOfM = momentMin > (0.05 * momentMax) - ? yM + momentMin * mScale + 14 - : yM + 14; - yDeflection = botOfM + 60 + deflectionMax * deflectionScale; - yDeflection = Math.round(yDeflection); - yMax = yDeflection; - if (Math.abs(deflectionMin) > 0.2 * (deflectionMax - deflectionMin)) { - yText = yDeflection - deflectionScale * deflectionMin; - if (yText > yMax) { yMax = yText; } - } - } - yMax += 20; - - return [yV, yM, yDeflection, vScale, mScale, deflectionScale, yMax] - -} - -function drawDiagrams(beam, nodes, spans, cases, yCoords, extremes, combinations) { - let diagram = []; - // Now go thru the comberns again. Draw the line work this time. - const numSpans = spans.length - 1; - const [vMax, vMin, mMax, mMin, , , deflMaxCase, deflMinCase, numComberns] = extremes; - const [shearCases, bendingCases] = cases; - const [yV, yM, yDeflection, vScale, mScale, deflectionScale] = yCoords; - const vSmall = 0.01 * (vMax - vMin); - const mSmall = 0.05 * (mMax - mMin); - let deflectionMax = 0; - let deflectionMin = 0; - let xDeflectionMax = 0; - let xDeflectionMin = 0; - const xIncrement = beam.length / 50; - const wV = []; - const wVx = []; - const wM = []; - const wMx = []; - const horizAlign = "middle"; - - // Draw the horizontal lines for the shear and moment diagrams - diagram.push(Draw.textNode("shear", 20, yV + 2)); - diagram.push(Draw.textNode(`(${beam.SI ? "kN" : "kips"})`, 20, yV + 16)); - diagram.push({ - tag: "path", - attrs: { d: `M${beam.xDiagram} ${yV} h300`, stroke: "black", "stroke-width": '1.5px' } - }); - diagram.push(Draw.textNode("bending", 20, yM + 2)); - diagram.push(Draw.textNode(`(${beam.SI ? "kN-m" : "kip-ft"})`, 20, yM + 16)); - diagram.push({ - tag: "path", - attrs: { d: `M${beam.xDiagram} ${yM} h300`, stroke: "black", "stroke-width": '1.5px' } - }); - - if (combinations !== "service") { - diagram.push(Draw.textNode("factored", 20, yV - 12)); - diagram.push(Draw.textNode("factored", 20, yM - 12)); - } - - // Draw the reactions. - let f = 0; - for (let i = 1; i < nodes.length; i++) { - const x = beam.xDiagram + beam.xScale * nodes[i].x; - if (Math.abs(nodes[i].Pr[0]) > 0) { - f = 1 / (beam.SI ? 1000 : 4448.2216152605); - const sText = round$1(nodes[i].Pr[0] * f, 3); - diagram = diagram.concat(Draw.pointForce(x, beam.yLoad, sText, nodes[i].fixity, true)); - } - if (Math.abs(nodes[i].Mr[0]) > 0) { - f = 1 / (beam.SI ? 1000 : 4448.2216152605 * 0.3048); - const sText = round$1(nodes[i].Mr[0] * f, 3); - diagram = diagram.concat(Draw.pointMoment(x, beam.yLoad, sText, true)); - } - } - - for (let combern = 0; combern <= numComberns; combern++) { - // Are we in a deflection combern? - const inaDeflCase = (deflMinCase === combern || deflMaxCase === combern) && beam.EI !== 1; - // Should we plot this combern? - if (!(shearCases.includes(combern) || bendingCases.includes(combern) || inaDeflCase)) { - continue // Skip this combern. - } - // This is a combern for which we should plot the line work - // Find detailed shear and moments for the diagrams. And we check local maximums to see - // if we should write their values onto the diagram. - let lastVend = 0; - let lastW2f = 0; - const x = inaDeflCase ? [] : [0]; - const deflection = []; - const v = []; - const m = []; - if (!inaDeflCase) { - v.push(0); - m.push(0); - } - let k = 0; - for (let i = 1; i <= numSpans; i++) { - for (let j = 0; j < spans[i].segments.length; j++) { - const seg = spans[i].segments[j]; - const vEnd = seg.V1[combern] + seg.w1f[combern] * seg.length - + 0.5 * seg.slope[combern] * seg.length ** 2; - const mEnd = seg.M1[combern] + seg.V1[combern] * seg.length - + 0.5 * seg.w1f[combern] * seg.length ** 2 + seg.slope[combern] * seg.length ** 3 / 6; - const w2f = seg.w1f[combern] + seg.slope[combern] * seg.length; - let deflectionEnd = 0; - if (inaDeflCase) { - deflectionEnd = seg.delta1[combern] + seg.theta1[combern] * seg.length - + (0.5 * seg.M1[combern] * seg.length ** 2 + seg.V1[combern] * seg.length ** 3 / 6 - + seg.w1f[combern] * seg.length ** 4 / 24 - + seg.slope[combern] * seg.length ** 5 / 120) / beam.EI; - } - // Details for line work - let xLocal = 0; - k += 1; - x.push(seg.xOfLeftEnd); - if (inaDeflCase) { - deflection.push(seg.delta1[combern]); - if (seg.delta1[combern] > deflectionMax) { - deflectionMax = seg.delta1[combern]; - xDeflectionMax = seg.xOfLeftEnd; - } - if (seg.delta1[combern] < deflectionMin) { - deflectionMin = seg.delta1[combern]; - xDeflectionMin = seg.xOfLeftEnd; - } - if (deflectionEnd > deflectionMax) { - deflectionMax = deflectionEnd; - xDeflectionMax = seg.xOfLeftEnd + seg.length; - } - if (deflectionEnd < deflectionMin) { - deflectionMin = deflectionEnd; - xDeflectionMin = seg.xOfLeftEnd + seg.length; - } - } else { - v.push(seg.V1[combern]); - m.push(seg.M1[combern]); - } - - for (let ii = 1; ii <= Math.trunc(seg.length / xIncrement); ii++) { - k = k + 1; - x.push(x[x.length - 1] + xIncrement); - xLocal += xIncrement; - if (inaDeflCase) { - deflection.push(seg.delta1[combern] + seg.theta1[combern] * xLocal - + (0.5 * seg.M1[combern] * xLocal ** 2 - + seg.V1[combern] * xLocal ** 3 / 6 + seg.w1f[combern] * xLocal ** 4 / 24 - + seg.slope[combern] * xLocal ** 5 / 120) / beam.EI); - if (deflection[deflection.length - 1] > deflectionMax) { - deflectionMax = deflection[deflection.length - 1]; - xDeflectionMax = seg.xOfLeftEnd + xLocal; - } - if (deflection[deflection.length - 1] < deflectionMin) { - deflectionMin = deflection[deflection.length - 1]; - xDeflectionMin = seg.xOfLeftEnd + xLocal; - } - } else { - v.push(seg.V1[combern] + seg.w1f[combern] * xLocal - + 0.5 * seg.slope[combern] * xLocal ** 2); - m.push(seg.M1[combern] + seg.V1[combern] * xLocal - + 0.5 * seg.w1f[combern] * xLocal ** 2 + seg.slope[combern] * xLocal ** 3 / 6); - } - } - - k += 1; - x.push(seg.xOfLeftEnd + seg.length); - if (inaDeflCase) { - deflection.push(deflectionEnd); - } else { - v.push(vEnd); - m.push(mEnd); - } - - // Check for local maximums and minimums - if (seg.Vmax.left.case === combern || seg.Vmin.left.case === combern) { - // Do we also want to write this value onto the shear diagram? - if (i === 1 && j === 0) { - if (Math.abs(seg.V1[combern]) > vSmall) { - checkVs(seg.V1[combern], 0, wV, wVx, spans, beam.length); - } - } else if (!(lastW2f === seg.w1f[combern] && - Math.abs(seg.V1[combern] - lastVend) < vSmall)) { - checkVs(seg.V1[combern], seg.xOfLeftEnd, wV, wVx, spans, beam.length); - } - } - - if (seg.Vmax.mid.case === combern || seg.Vmin.mid.case === combern) { - let xCross = 0; - if (seg.slope[combern] !== 0) { - xCross = -1 * seg.w1f[combern] / seg.slope[combern]; - if (xCross > 0 && xCross < seg.length) { - const vMid = seg.V1[combern] + seg.w1f[combern] * xCross - + 0.5 * seg.slope[combern] * xCross ** 2; - checkVs(vMid, seg.xOfLeftEnd + xCross, wV, wVx, spans, beam.length); - } - } - } - - if (seg.Vmax.right.case === combern || seg.Vmin.right.case === combern) { - if (Math.abs(vEnd) > vSmall) { - checkVs(vEnd, seg.xOfLeftEnd + seg.length, wV, wVx, spans, beam.length); - } - } - - if (seg.Mmax.left.case === combern || seg.Mmin.left.case === combern) { - if (i === 1 && j === 0) { - if (Math.abs(seg.M1[combern]) > mSmall) { - checkMs(seg.M1[combern], 0, wM, wMx, spans, beam.length, mSmall); - } - } else { - checkMs(seg.M1[combern], seg.xOfLeftEnd, wM, - wMx, spans, beam.length, mSmall); - } - } - - if (seg.Mmax.mid.case === combern || seg.Mmin.mid.case === combern) { - let xCross = 0; // initialze the variable - let mMid = 0; - if (seg.slope[combern] === 0) { - if (seg.w1f[combern] !== 0) { - xCross = -seg.V1[combern] / seg.w1f[combern]; - if (xCross > 0 && xCross < seg.length) { - mMid = seg.M1[combern] + seg.V1[combern] * xCross - + 0.5 * seg.w1f[combern] * xCross ** 2 + seg.slope[combern] * xCross ** 3 / 6; - checkMs(mMid, seg.xOfLeftEnd + xCross, wM, wMx, spans, beam.length, mSmall); - } - } - } else { - let mMid1 = 0; - let mMid2 = 0; - let xCross1 = 0; - let xCross2 = 0; - if ((seg.w1f[combern] ** 2 - 2 * seg.slope[combern] * seg.V1[combern]) > 0) { - const determinant = Math.sqrt(seg.w1f[combern] ** 2 - - 2 * seg.slope[combern] * seg.V1[combern]); - xCross1 = -(seg.w1f[combern] - determinant) / seg.slope[combern]; - xCross2 = -(seg.w1f[combern] + determinant) / seg.slope[combern]; - if (xCross1 > 0 && xCross1 < seg.length) { - xCross = xCross1; - mMid1 = seg.M1[combern] + seg.V1[combern] * xCross - + 0.5 * seg.w1f[combern] * xCross ** 2 + seg.slope[combern] * xCross ** 3 / 6; - } - if (xCross2 > 0 && xCross2 < seg.length) { - xCross = xCross2; - mMid2 = seg.M1[combern] + seg.V1[combern] * xCross - + 0.5 * seg.w1f[combern] * xCross ** 2 + seg.slope[combern] * xCross ** 3 / 6; - } - } - if (mMid1 > 0 || mMid2 > 0) { - if (mMid1 > mMid2) { - mMid = mMid1; - xCross = xCross1; - } else { - mMid = mMid2; - xCross = xCross2; - } - } - if (xCross > 0 && xCross < seg.length) { - mMid = seg.M1[combern] + seg.V1[combern] * xCross - + 0.5 * seg.w1f[combern] * xCross ** 2 + seg.slope[combern] * xCross ** 3 / 6; - checkMs(mMid, seg.xOfLeftEnd + xCross, wM, wMx, spans, beam.length, mSmall); - } - } - } - - if (seg.Mmax.right.case === combern || seg.Mmin.right.case === combern) { - checkMs(mEnd, seg.xOfLeftEnd + seg.length, wM, wMx, spans, beam.length, mSmall); - } - - lastW2f = w2f; - lastVend = vEnd; - } - } - - // Plot diagrams - const numDataPoints = k; - - // Draw the shear diagrams - if (shearCases.includes(combern)) { - let xPoly; - let yPoly; - - if (beam.allLoadsAreUniform) { - // Make the shear diagram out of straight lines. - let linearV = new Array(2 * beam.numSegments + 3).fill(0); - linearV = linearV.map(e => [0, 0]); - k = 1; - linearV[k][0] = beam.xDiagram; - linearV[k][1] = yV; - for (let i = 1; i <= numSpans; i++) { - for (let j = 0; j < spans[i].segments.length; j++) { - const seg = spans[i].segments[j]; - k = k + 1; - linearV[k][0] = beam.xDiagram + beam.xScale * seg.xOfLeftEnd; - linearV[k][1] = yV - vScale * seg.V1[combern]; - k = k + 1; - linearV[k][0] = beam.xDiagram + beam.xScale * (seg.xOfLeftEnd + seg.length); - const vEnd = seg.V1[combern] + seg.w1f[combern] * seg.length - + 0.5 * seg.slope[combern] * seg.length ** 2; - linearV[k][1] = yV - vScale * vEnd; - } - } - k = k + 1; - linearV[k][0] = beam.xDiagram + beam.xScale * beam.length; - linearV[k][1] = yV; - const numOfShearDataPoints = k; - - xPoly = new Array(numOfShearDataPoints - 1); - yPoly = new Array(numOfShearDataPoints - 1); - for (let ii = 1; ii <= numOfShearDataPoints; ii++) { - xPoly[ii - 1] = linearV[ii][0].toFixed(2); - yPoly[ii - 1] = linearV[ii][1].toFixed(2); - } - - } else { - xPoly = new Array(numDataPoints + 1).fill(0); - yPoly = new Array(numDataPoints + 1).fill(0); - for (let ii = 0; ii < numDataPoints; ii++) { - xPoly[ii] = (beam.xDiagram + beam.xScale * x[ii]).toFixed(2); // x(ii) - yPoly[ii] = (yV - vScale * v.shift()).toFixed(2); - } - xPoly[numDataPoints] = beam.xDiagram + 300; - yPoly[numDataPoints] = yV; - } - diagram.push(Draw.polyline(xPoly, yPoly)); - } - - // Draw the moment diagram - if (bendingCases.includes(combern)) { - const xPoly = new Array(numDataPoints + 1).fill(0); - const yPoly = new Array(numDataPoints + 1).fill(0); - for (let ii = 0; ii <= numDataPoints; ii++) { - xPoly[ii] = (beam.xDiagram + beam.xScale * x[ii]).toFixed(2); // x(ii) - yPoly[ii] = (yM - beam.convention * mScale * m.shift()).toFixed(2); // M(ii) - } - xPoly[numDataPoints + 1] = beam.xDiagram + 300; - yPoly[numDataPoints + 1] = yM; - diagram.push(Draw.polyline(xPoly, yPoly)); - } - - if (inaDeflCase) { - // Draw the deflection diagram - diagram.push(Draw.textNode("deflection", 20, yDeflection + 2)); - diagram.push({ - tag: "path", - attrs: { d: `M${beam.xDiagram} ${yDeflection} h300`, - stroke: "black", "stroke-width": '1.5px' } - }); - const xPoly = new Array(numDataPoints - 1).fill(0); - const yPoly = new Array(numDataPoints - 1).fill(0); - xPoly[0] = beam.xDiagram.toFixed(2); - yPoly[0] = yDeflection.toFixed(2); - for (let ii = 1; ii <= numDataPoints - 1; ii++) { - xPoly[ii] = (beam.xDiagram + beam.xScale * x[ii]).toFixed(2); // x(ii) - yPoly[ii] = (yDeflection - deflectionScale * deflection[ii]).toFixed(2); - } - diagram.push(Draw.polyline(xPoly, yPoly)); - } - } - - // Write the values of the local shear maximums onto the diagrams. - f = 1 / (beam.SI ? 1000 : 4448.2216152605); // conversion factor for N to kips or MN - while (wV.length > 0) { - const xText = (beam.xDiagram + beam.xScale * wVx.shift()).toFixed(2); - const fudge = wV[0] > 0 ? -2 : 13; - const yText = (yV - vScale * wV[0] + fudge).toFixed(2); - // horizAlign is middle - diagram.push(Draw.textNode(round$1(wV.shift() * f, 3), xText, yText, horizAlign)); - } - - // Write the values of the local bending maximums onto the diagrams. - f = beam.convention / (beam.SI ? 1000 : 4448.2216152605 * 0.3048); - while (wM.length > 0) { - const xText = (beam.xDiagram + beam.xScale * wMx.shift()).toFixed(2); - const fudge = beam.convention * wM[0] > 0 ? -2 : 13; - const yText = (yM - beam.convention * mScale * wM[0] + fudge).toFixed(2); - const sText = round$1(wM.shift() * f, 3); - diagram.push(Draw.textNode(sText, xText, yText, horizAlign)); - } - - if (beam.EI !== 1) { - // Insert the max and min deflection values - beam.deflectionMax = Math.max(Math.abs(deflectionMax), Math.abs(deflectionMin)); - f = beam.SI ? 1000 : (12 / 0.3048); - let sText = ""; - let xText = 0; - let yText = 0; - if (deflectionMax > 0.2 * (deflectionMax - deflectionMin)) { - xText = beam.xDiagram + beam.xScale * xDeflectionMax; - yText = yDeflection - deflectionScale * deflectionMax - 2; - if (beam.SI) { - sText = round$1(deflectionMax * f, 1) + " mm"; - } else { - sText = round$1(deflectionMax * f, 2) + '″'; - } - diagram.push(Draw.textNode(sText, xText, yText, horizAlign)); - } - if (Math.abs(deflectionMin) > 0.2 * (deflectionMax - deflectionMin)) { - xText = beam.xDiagram + beam.xScale * xDeflectionMin; - yText = yDeflection - deflectionScale * deflectionMin + 13; - if (beam.SI) { - sText = round$1(f * deflectionMin, 1) + " mm"; - } else { - sText = round$1(f * deflectionMin, 2) + '″'; - } - diagram.push(Draw.textNode(sText, xText, yText, horizAlign)); - } - } - - return diagram -} - -const checkVs = (v, x, wV, wVx, spans, beamLength) => { - // Check if we should write this value onto the shear diagram - let gottaWrite = true; // initialize the variable - const shortDistance = 0.15 * beamLength; - - for (let i = 1; i < spans.length; i++) { - for (let k = 0; k < spans[i].segments.length; k++) { - const seg = spans[i].segments[k]; - const xOfRightEnd = seg.xOfLeftEnd + seg.length; - if (xOfRightEnd < x - shortDistance) { continue } - if (seg.xOfLeftEnd > x + shortDistance) { continue } - - if (Math.abs(seg.xOfLeftEnd - x) < shortDistance) { - if (v > 0) { - if (seg.Vmax.left.value > v) { - gottaWrite = false; - break - } - } else if (seg.Vmin.left.value < v) { - gottaWrite = false; - break - } - } - - const xRightEnd = seg.xOfLeftEnd + seg.length; - if (Math.abs(x - xRightEnd < shortDistance)) { - if (v > 0) { - if (seg.Vmax.right.value > v) { - gottaWrite = false; - break - } - } else if (seg.Vmin.right.value < v) { - gottaWrite = false; - break - } - } - } - } - - if (gottaWrite) { - wV.push(v); - wVx.push(x); - } -}; - -const checkMs = (m, x, wM, wMx, spans, beamLength, mSmall) => { - // Check if we should write this value onto the moment diagram - if (Math.abs(m) < mSmall) { return false } - let gottaWrite = true; // initialize the variable - const shortDistance = 0.15 * beamLength; - - for (let i = 1; i < spans.length; i++) { - for (let k = 0; k < spans[i].segments.length; k++) { - const seg = spans[i].segments[k]; - const xOfRightEnd = seg.xOfLeftEnd + seg.length; - if (xOfRightEnd < x - shortDistance) { continue } - if (seg.xOfLeftEnd > x + shortDistance) { continue } - - if (Math.abs(seg.xOfLeftEnd - x) < shortDistance) { - if (m > 0) { - if (seg.Mmax.left.value > m) { - gottaWrite = false; - break - } - } else if (seg.Mmin.left.value < m) { - gottaWrite = false; - break - } - } - - if (m > 0 && Math.abs(seg.Mmax.mid.x - x) < shortDistance) { - if (seg.Mmax.mid.value > m) { - gottaWrite = false; - break - } - } - if (m < 0 && Math.abs(seg.Mmin.mid.x - x) < shortDistance) { - if (seg.Mmin.mid.value < m) { - gottaWrite = false; - break - } - } - - const xRightEnd = seg.xOfLeftEnd + seg.length; - if (Math.abs(x - xRightEnd < shortDistance)) { - if (m > 0) { - if (seg.Mmax.right.value > m) { - gottaWrite = false; - break - } - } else if (seg.Mmin.right.value < m) { - gottaWrite = false; - break - } - } - } - } - - if (gottaWrite) { - wM.push(m); - wMx.push(x); - } -}; - -function error(msg) { - if (msg === "") { return { value: "Error", unit: null, dtype: dt.ERROR } } - return { value: msg, unit: null, dtype: dt.ERROR } -} - -const beamDiagram = (beamInputData, loadFactorInput) => { - // This is the main analysis function. - - // Get raw data from the input dataframe. - const beamInput = readInputData(beamInputData); - if (typeof beamInput === "string") { return error(beamInput) } - - // Validate input and populate data structures. - const [errorMsg, beam, nodes, spans, combinations] = populateData(beamInput, loadFactorInput); - if (errorMsg) { return error(errorMsg) } - - // Start the SVG - const svg = { tag: 'svg', children: [], attrs: { float: "right" } }; - - // Create the first diagram. Show fixities, lengths, and loads. - const loadDiagram = createLoadDiagram(beam, nodes, spans); - svg.children = svg.children.concat(loadDiagram); - - // Do the linear algebra. For each load type, get member end actions and node displacements. - const [actions, deflections] = doAnalysis(beam, nodes, spans); - - // Determine shear, moment, and deflection maximums and minimums by superimposing - // the relevent load combinations and live load patterns. - const extremes = combine(beam, nodes, spans, actions, deflections, combinations); - - // Decide which combinations get plotted. - const cases = selectCases(spans); - - // Find the y coordinates for the shear, moment, and deflection diagrams. - const yCoords = locateDiagrams(beam, extremes); - const yMax = yCoords[6]; // Diagram overall height in local coords. - - const diagrams = drawDiagrams(beam, nodes, spans, cases, yCoords, extremes, combinations); - svg.children = svg.children.concat(diagrams); - - // Set the outer dimensions of the diagram. - svg.attrs.width = "375"; // px - svg.attrs.height = (375 / 450 * yMax).toFixed(0); - svg.attrs.viewBox = `0 0 450 ${yMax.toFixed(0)}`; - - return svg - -}; - -// evaluate.js - -/* - * This module receives an RPN string and a object containing Hurmet variables. - * It does the calculation, doing unit-compatibility checks along the way. - * It returns a result in two formats: (1) a TeX string that can be displayed and - * (2) numeric and unit data that can used for calculations by other cells. - * - * Hurmet does automatic unit conversions and checks for unit compatibility. - * Compatibility checks are done by keeping track of the unit exponents. - * So for instance if we divide an area by a length, the unit exponent calculation runs as: - * LENGTH^2 / LENGTH^1 = LENGTH^(2-1) = LENGTH^1 - * We keep track of unit exponents for each of 9 base dimensions. That's why - * you see an array of 9 integers occuring in the code below. - * - * Inside evalRpn(), Hurmet operands are each an object with three fields: - * value: the value of the operand - * unit: holds unit info, either unit name, an array of exponents, or a unitMap - * dtype: an integer indicating data type. - * - * Note that an operand can be two data types at once, such as RATIONAL and MATRIX. - * In such cases, dtype is the sum of the two underlying integers. - * So, in constants.js, we have enumerated the data types in powers of two. - * That way, we can use a bit-wise "&" operator to test for an individual type. - * - * Numeric matrices and numeric maps can have math operations done to them. - * We distinguish numeric matrices from other matrices by the fact that - * (oprnd.dtype & dt.RATIONAL) returns a true if the matrix is numeric. - * - * File operands.js contains further explanation of Hurmet operands. - */ - -// Some helper functions - -const setComparisons = ["in", "!in", "∈", "∉", "∋", "∌", "⊂", "⊄", "⊃", "⊅"]; - -const shapeOf = oprnd => { - return oprnd.dtype === dt.COMPLEX - ? "complex" - : oprnd.dtype < 128 - ? "scalar" - : isVector(oprnd) - ? "vector" - : (oprnd.dtype & dt.MATRIX) - ? "matrix" - : oprnd.dtype === dt.DATAFRAME - ? "dataFrame" - : (oprnd.dtype & dt.MAP) - ? "map" - : "other" -}; - -const binaryShapesOf = (o1, o2) => { - let shape1 = shapeOf(o1); - let shape2 = shapeOf(o2); - let needsMultBreakdown = false; - if ((isMatrix(o1) || (o1.dtyp & dt.MAP)) && (isMatrix(o2) || (o2.dtype & dt.MAP))) { - // If both operands are matrices, we need to return more information. - // That enables the various ways to multiply two matrices. - needsMultBreakdown = true; - if (shape1 === "vector") { - shape1 = (o1.dtype & dt.ROWVECTOR) ? "rowVector" : "columnVector"; - } - if (shape2 === "vector") { - shape2 = (o2.dtype & dt.ROWVECTOR) ? "rowVector" : "columnVector"; - } - } - return [shape1, shape2, needsMultBreakdown] -}; - -const matrixMults = { "×": "cross", "·": "dot", "∘": "circ", ".*": "circ", - "*": "multiply", "∗": "multiply", "⌧": "multiply" }; - -const nextToken = (tokens, i) => { - if (tokens.length < i + 2) { return undefined } - return tokens[i + 1] -}; - -// array of function names that return a real number from a complex argument. -const arfn = ["abs", "angle", "imag", "real", "Γ", "gamma"]; - -const stringFromOperand = (oprnd, decimalFormat) => { - return oprnd.dtype === dt.STRING - ? oprnd.value - : oprnd.dtype === dt.RATIONAL - ? format(oprnd.value, "h15", decimalFormat) - : isMatrix(oprnd.dtype) - ? Matrix.displayAlt(oprnd, "h15", decimalFormat) - : (oprnd.dtype & dt.MAP) - ? DataFrame.displayAlt(oprnd.value, "h15", decimalFormat) - : oprnd.value -}; - -const evalRpn = (rpn, vars, decimalFormat, unitAware, lib) => { - // This is the function that does calculations with the rpn string. - const tokens = rpn.split("\u00A0"); - const stack = []; - let oPrev; - for (let i = 0; i < tokens.length; i++) { - const tkn = tokens[i]; - const ch = tkn.charAt(0); - - if (ch === "®") { - // A rational number. - const r = new Array(2); - const pos = tkn.indexOf("/"); - r[0] = BigInt(tkn.slice(1, pos)); // numerator - r[1] = BigInt(tkn.slice(pos + 1)); // denominator - const num = Object.create(null); - num.value = r; - num.unit = Object.create(null); - num.unit.expos = allZeros; - num.dtype = dt.RATIONAL; - stack.push(Object.freeze(num)); - - } else if (ch === "©") { - // A complex number. - const ints = tkn.slice(1).split(","); - const z = new Array(2); - z[0] = [BigInt(ints[0]), BigInt(ints[1])]; // real part - z[1] = [BigInt(ints[2]), BigInt(ints[3])]; // imaginary part - const num = Object.create(null); - num.value = z; - num.unit = Object.create(null); - num.unit.expos = allZeros; - num.dtype = dt.COMPLEX; - stack.push(Object.freeze(num)); - - } else if (ch === "¿") { - // A variable. Get the value from vars - const varName = tkn.substring(1); - let oprnd = Object.create(null); - if (varName === "undefined") { - oprnd.value = undefined; - oprnd.unit = null; - oprnd.dtype = 0; - } else if (varName === "T" && nextToken(tokens, i) === "^" && - stack.length > 0 && isMatrix(stack[stack.length - 1])) { - i += 1; - oprnd = Matrix.transpose(stack.pop()); - } else if (varName === "j" && !vars.j) { - oprnd.value = [Rnl.zero, Rnl.one]; - oprnd.unit = Object.create(null); - oprnd.unit.expos = allZeros; - oprnd.dtype = dt.COMPLEX; - } else { - const cellAttrs = vars[varName]; - if (!cellAttrs) { return errorOprnd("V_NAME", varName) } - oprnd = fromAssignment(cellAttrs, unitAware); - if (oprnd.dtype === dt.ERROR) { return oprnd } - } - stack.push(Object.freeze(oprnd)); - - } else if (ch === '"') { - // A string literal. - const chEnd = tkn.charAt(tkn.length - 1); - const str = ch === '"' && chEnd === '"' ? tkn.slice(1, -1) : tkn; - stack.push(Object.freeze({ value: str, unit: null, dtype: dt.STRING })); - - } else if (/^``/.test(tkn)) { - stack.push(DataFrame.dataFrameFromTSV(tablessTrim(tkn.slice(2, -2)), vars)); - - } else if (ch === '`') { - // A rich text literal - const chEnd = tkn.charAt(tkn.length - 1); - const str = ch === '`' && chEnd === '`' ? tkn.slice(1, -1).trim() : tkn.trim(); - stack.push(Object.freeze({ value: str, unit: null, dtype: dt.RICHTEXT })); - - } else { - switch (tkn) { - case "true": - case "false": { - const bool = Object.create(null); - bool.value = tkn === "true"; - bool.unit = null; - bool.dtype = dt.BOOLEAN; - stack.push(Object.freeze(bool)); - break - } - - case "pi": - case "π": { - const pi = Object.create(null); - pi.value = Rnl.pi; - pi.dtype = dt.RATIONAL; - pi.unit = Object.create(null); - pi.unit.expos = allZeros; - stack.push(Object.freeze(pi)); - break - } - - case "e": { - const e = Object.create(null); - e.value = "e"; - e.dtype = dt.RATIONAL; - e.unit = Object.create(null); - e.unit.expos = allZeros; - stack.push(Object.freeze(e)); - break - } - - case "ℏ": { - // Reduced Plank constant - const hbar = Object.create(null); - hbar.value = Rnl.hbar; - hbar.dtype = dt.RATIONAL; - hbar.unit = Object.create(null); - hbar.unit.expos = Object.freeze(unitAware ? [2, 1, -1, 0, 0, 0, 0, 0] : allZeros); - stack.push(Object.freeze(hbar)); - break - } - - case "∠": { - // Complex number in polar notation. - const o2 = stack.pop(); - const o1 = stack.pop(); - if (o1.dtype !== dt.RATIONAL || o2.dtype !== dt.RATIONAL) { - return errorOprnd("NAN_OP") - } - const theta = Rnl.toNumber(o2.value); - const z = Object.create(null); - z.value = [ - Rnl.multiply(o1.value, Rnl.fromNumber(Math.cos(theta))), // real part - Rnl.multiply(o1.value, Rnl.fromNumber(Math.sin(theta))) // imaginary part - ]; - z.unit = Object.create(null); - z.unit.expos = allZeros; - z.dtype = dt.COMPLEX; - stack.push(Object.freeze(z)); - break - } - - case "+": - case ".+": - case "-": - case ".-": { - const o2 = stack.pop(); - const o1 = stack.pop(); - const op = tkn === "+" || tkn === ".+" ? "add" : "subtract"; - if (!(((o1.dtype & dt.RATIONAL) || (o1.dtype & dt.COMPLEX)) && - ((o2.dtype & dt.RATIONAL) || (o2.dtype & dt.COMPLEX)))) { - return errorOprnd("NAN_OP") - } - if (unitAware) { - if (!unitsAreCompatible(o1.unit.expos, o2.unit.expos)) { - return errorOprnd("UNIT_ADD") - } - } - const [shape1, shape2, _] = binaryShapesOf(o1, o2); - const sum = Object.create(null); - // See file operations.js for an explanation of what goes on in the next line. - sum.value = Operators.binary[shape1][shape2][op](o1.value, o2.value); - if (sum.value.dtype && sum.value.dtype === dt.ERROR) { return sum.value } - sum.unit = o1.unit; - sum.dtype = Operators.dtype[shape1][shape2](o1.dtype, o2.dtype, tkn); - stack.push(Object.freeze(sum)); - break - } - - case "~": { - // Unary minus - const o1 = stack.pop(); - if (!((o1.dtype & dt.RATIONAL) || o1.dtype === dt.COMPLEX)) { - return errorOprnd("NAN_OP") - } - const neg = Object.create(null); - neg.value = Operators.unary[shapeOf(o1)]["negate"](o1.value); - if (neg.value.dtype && neg.value.dtype === dt.ERROR) { return neg.value } - neg.unit = o1.unit; - neg.dtype = o1.dtype; - stack.push(Object.freeze(neg)); - break - } - - case "×": - case "·": - case "*": - case "∗": - case "∘": - case "⌧": { - const oprnd2 = stack.pop(); - const o2 = oprnd2.dtype === dt.DATAFRAME ? clone(oprnd2) : oprnd2; - const o1 = stack.pop(); - if ((tkn === "*" || tkn === "∗") - && o1.dtype === dt.STRING && o1.dtype === dt.STRING) { - // Julia's string concatenation operator - const str1 = stringFromOperand(o1, decimalFormat); - const str2 = stringFromOperand(o2, decimalFormat); - return { value: str1 + str2, unit: null, dtype: dt.STRING } - } - if (!(((o1.dtype & dt.RATIONAL) || (o1.dtype & dt.COMPLEX)) && - ((o2.dtype & dt.RATIONAL) || (o2.dtype & dt.COMPLEX) || - o2.dtype === dt.DATAFRAME))) { - return errorOprnd("NAN_OP") - } - const product = Object.create(null); - let unit = Object.create(null); - if (unitAware) { - if ((o1.dtype === dt.DATAFRAME && o2.dtype === dt.RATIONAL) || - (o1.dtype === dt.RATIONAL && o2.dtype === dt.DATAFRAME)) { - unit = o1.dtype === dt.DATAFRAME ? o1.unit : o2.unit; - } else { - unit.expos = o1.unit.expos.map((e, j) => e + o2.unit.expos[j]); - } - } else { - unit.expos = allZeros; - } - product.unit = o2.dtype === dt.DATAFRAME ? clone(o2.unit) : Object.freeze(unit); - - const [shape1, shape2, needsMultBreakdown] = binaryShapesOf(o1, o2); - const op = needsMultBreakdown ? matrixMults[tkn] : "multiply"; - - product.dtype = (tkn === "∘" || shape1 === "scalar" || shape1 === "map" || - shape1 === "complex" || shape2 === "scalar" || - shape2 === "map" || shape2 === "complex") - ? Operators.dtype[shape1][shape2](o1.dtype, o2.dtype, op) - : tkn === "·" - ? dt.RATIONAL - : tkn === "×" - ? dt.COLUMNVECTOR - : Matrix.multResultType(o1, o2); - - product.value = Operators.binary[shape1][shape2][op](o1.value, o2.value); - if (product.value.dtype && product.value.dtype === dt.ERROR) { - return product.value - } - - stack.push(Object.freeze(product)); - break - } - - case "/": - case "./": - case "//": - case "///": - case "\u2215": { - const o2 = stack.pop(); - const o1 = stack.pop(); - if (!(((o1.dtype & dt.RATIONAL) || o1.dtype === dt.COMPLEX) && - ((o2.dtype & dt.RATIONAL) || o2.dtype === dt.COMPLEX))) { - return errorOprnd("NAN_OP") - } - const quotient = Object.create(null); - const unit = Object.create(null); - unit.expos = unitAware - ? o1.unit.expos.map((e, j) => e - o2.unit.expos[j]) - : allZeros; - quotient.unit = Object.freeze(unit); - const [shape1, shape2, _] = binaryShapesOf(o1, o2); - quotient.value = Operators.binary[shape1][shape2]["divide"](o1.value, o2.value); - if (quotient.value.dtype && quotient.value.dtype === dt.ERROR) { - return quotient.value - } - quotient.dtype = Operators.dtype[shape1][shape2](o1.dtype, o2.dtype, "divide"); - if (isDivByZero(quotient.value, shapeOf(quotient))) { return errorOprnd("DIV") } - stack.push(Object.freeze(quotient)); - break - } - - case "^": - case ".^": { - const o2 = stack.pop(); - const o1 = stack.pop(); - if (!(((o1.dtype & dt.RATIONAL) || o1.dtype === dt.COMPLEX) && - ((o2.dtype & dt.RATIONAL) || o2.dtype === dt.COMPLEX) || - (isMatrix(o1) && o2.value === "T"))) { - return errorOprnd("NAN_OP") - } - const power = Object.create(null); - const unit = Object.create(null); - unit.expos = allZeros; - if (unitAware) { - // TODO: lots to do here - const d = typeof o2.unit === "number" ? o2.unit : Rnl.toNumber(o2.value); - unit.expos = o1.unit.expos.map(e => e * d); - } - power.unit = Object.freeze(unit); - const [shape1, shape2, _] = binaryShapesOf(o1, o2); - power.value = Operators.binary[shape1][shape2]["power"](o1.value, o2.value); - if (power.value.dtype) { return power.value } // Error - power.dtype = Cpx.isComplex(power.value) - ? dt.COMPLEX - : Operators.dtype[shape1][shape2](o1.dtype, o2.dtype, tkn); - stack.push(Object.freeze(power)); - break - } - - case "&": - case "hcat": - case "vcat": { - // Concatenation - const o2 = stack.pop(); - const o1 = stack.pop(); - const opName = tkn === "vcat" ? "unshift" : "concat"; - const [shape1, shape2, _] = binaryShapesOf(o1, o2); - let o3 = Object.create(null); - if (o1.dtype === dt.STRING && o1.dtype === dt.STRING) { - const str1 = stringFromOperand(o1, decimalFormat); - const str2 = stringFromOperand(o2, decimalFormat); - o3.value = str1 + str2; - o3.unit = null; - o3.dtype = dt.STRING; - } else if ((o1.dtype & dt.DATAFRAME) && isVector(o2) && tkn !== "vcat") { - o3 = DataFrame.append(o1, o2, vars.format.value, unitAware); - if (o3.dtype === dt.ERROR) { return o3 } - } else if (((o1.dtype & dt.DATAFRAME) && shape2 === "scalar") || - (shape1 === "scalar" && (o2.dtype & dt.DATAFRAME))) { - o3 = DataFrame.append(o1, o2, vars.format.value, unitAware); - if (o3.dtype === dt.ERROR) { return o3 } - } else if ((o1.dtype & dt.MAP) || (o2.dtype & dt.MAP)) { - o3 = map.append(o1, o2, shape1, shape2); - if (o3.dtype === dt.ERROR) { return o3 } - } else { - if (unitAware) { - if (!unitsAreCompatible(o1.unit.expos, o2.unit.expos)) { - return errorOprnd("UNIT_ADD") - } - } - o3.value = Operators.binary[shape1][shape2][opName](o1.value, o2.value); - if (o3.value.dtype) { return o3.value } // Error - o3.dtype = Operators.dtype[shape1][shape2](o1.dtype, o2.dtype, tkn); - if (o1.dtype === dt.COLUMNVECTOR && shape2 === "scalar") { - // Appending an element to an empty column vector - o3.dtype = o1.dtype + o2.dtype; - } - o3.unit = o1.unit; - } - stack.push(Object.freeze(o3)); - break - } - - case "√": - case "∛": - case "∜": { - const index = tkn.charCodeAt(0) - 8728; - const pow = [BigInt(1), BigInt(index)]; - const o1 = stack.pop(); - if (!((o1.dtype & dt.RATIONAL) || (o1.dtype & dt.COMPLEX))) { - return errorOprnd("NAN_OP") - } - const root = Object.create(null); - const unit = Object.create(null); - unit.expos = allZeros; - if (unitAware) { unit.expos = o1.unit.expos.map(e => e / index); } - root.unit = Object.freeze(unit); - - const shape1 = shapeOf(o1); - root.value = Operators.binary[shape1]["scalar"]["power"](o1.value, pow); - if (root.value.dtype && root.value.dtype === dt.ERROR) { return root.value } - - root.dtype = Cpx.isComplex(root.value) - ? dt.COMPLEX - : Operators.dtype[shape1]["scalar"](o1.dtype, dt.RATIONAL, tkn); - - stack.push(Object.freeze(root)); - break - } - - case "root": { - const o2 = stack.pop(); - const o1 = stack.pop(); - if (!((o1.dtype & dt.RATIONAL) & (o2.dtype & dt.RATIONAL))) { - return errorOprnd("NAN_OP") - } - const root = Object.create(null); - const unit = Object.create(null); - unit.expos = allZeros; - if (unitAware) { unit.expos = o2.unit.expos.map(e => e / Number(o1.value[0])); } - root.unit = Object.freeze(unit); - - const pow = Rnl.reciprocal(o1.value); - const shape1 = shapeOf(o1); - root.value = Operators.binary[shape1]["scalar"]["power"](o2.value, pow); - if (root.value.dtype && root.value.dtype === dt.ERROR) { return root.value } - - root.dtype = Operators.dtype[shape1]["scalar"](o1.dtype, dt.RATIONAL, tkn); - stack.push(Object.freeze(root)); - break - } - - case ".": { - // Accessor of a object's property in dot notation - const o2 = stack.pop(); - const o1 = stack.pop(); - const property = propertyFromDotAccessor(o1, o2, unitAware); - if (property.dtype === dt.ERROR) { return property } - stack.push(Object.freeze(property)); - break - } - - case "[]": { - // Bracket accessor to a data frame, matrix, string, map, or module. - const numArgs = Number(tokens[i + 1]); - i += 1; - const args = []; - for (let j = 0; j < numArgs; j++) { args.unshift(stack.pop()); } - const o1 = stack.pop(); - let property; - if (o1.dtype & dt.DATAFRAME) { - property = DataFrame.range(o1, args, unitAware); - - } else if (o1.dtype & dt.MAP) { - property = map.range(o1, args, unitAware); - - } else if (o1.dtype === dt.STRING) { - property = textRange(o1.value, args[0]); - - } else if (o1.dtype === dt.MODULE) { - if (numArgs === 1) { - property = fromAssignment(o1.value[args[0].value], unitAware); - } else { - // Multiple assignment. - property = { value: new Map(), unit: null, dtype: dt.TUPLE }; - for (let j = 0; j < args.length; j++) { - const name = args[j].value; - property.value.set(name, fromAssignment(o1.value[name], unitAware)); - } - } - - } else { - // o1 is a matrix or a data frame - const rowIndex = args[0]; - const colIndex = (numArgs === 2) - ? args[1] - : isVector(o1) - ? null - : { value: Rnl.zero, unit: allZeros, dtype: dt.RATIONAL }; - property = (o1.dtype & dt.DATAFRAME) - ? DataFrame.range(o1, rowIndex, colIndex, unitAware) - : Matrix.submatrix(o1, rowIndex, colIndex); - } - if (property.dtype === dt.ERROR) { return property } - stack.push(Object.freeze(property)); - break - } - - case ":": { - // range separator. - const end = stack.pop(); - const o1 = stack.pop(); - if (!(o1.dtype === dt.RATIONAL || o1.dtype === dt.RANGE)) { - return errorOprnd("NAN_OP") - } - const range = Object.create(null); - range.unit = null; - range.dtype = dt.RANGE; - const step = o1.dtype !== dt.RATIONAL - ? o1.value[2] - : end.value === "∞" || Rnl.lessThanOrEqualTo(o1.value, end.value) - ? Rnl.one - : Rnl.negate(Rnl.one); - range.value = o1.dtype === dt.RATIONAL - ? [o1.value, step, end.value] - : [o1.value[0], o1.value[2], end.value]; - stack.push((Object.freeze(range))); - break - } - - case "normal": - case "uniform": - case "lognormal": { - // eslint-disable-next-line no-unused-vars - stack.pop(); - // eslint-disable-next-line no-unused-vars - stack.pop(); - // low and high define a probablility distribution. They are the ends of a - // uniform distribution or they mark the 90% confidence interval of (log)normal. - // TODO: Implement probability distributions as a data type. - break - } - - case "!": - case "‼": - case "!!": { - // TODO: "!!" and "¡" - const o1 = stack.pop(); - if (!(o1.dtype & dt.RATIONAL)) { return errorOprnd("NAN_OP") } - if (unitAware) { - if (!unitsAreCompatible(o1.unit.expos, allZeros)) { return errorOprnd("FACT") } - } - const x = o1.value; - if (!Rnl.isInteger(x) || Rnl.isNegative(x)) { return errorOprnd("FACT") } - const factorial = Object.create(null); - factorial.unit = allZeros; - factorial.dtype = dt.RATIONAL; - factorial.value = tkn === "!" - ? Operators.unary[shapeOf(o1)]["factorial"](x) - : Operators.unary[shapeOf(o1)]["doubleFactorial"](x); - if (factorial.value.dtype) { return factorial.value } // Error - stack.push(Object.freeze(factorial)); - break - } - - case "%": { - // TODO: per thousand, ‰ - const o1 = stack.pop(); - if (!(o1.dtype & dt.RATIONAL)) { return errorOprnd("NAN_OP") } - const percentage = Object.create(null); - percentage.unit = o1.unit; - percentage.dtype = o1.dtype; - percentage.value = Operators.unary[shapeOf(o1)]["percent"](o1.value); - if (percentage.value) { return percentage.value } // Error - stack.push(Object.freeze(percentage)); - break - } - - case "|": - case "‖": { - // Find |x| or ‖x‖ - const o1 = stack.pop(); - if (!((o1.dtype & dt.RATIONAL) || o1.dtype === dt.COMPLEX)) { - return errorOprnd("NAN_OP") - } - const op = tkn === "|" ? "abs" : "norm"; - const abs = Object.create(null); - abs.unit = o1.unit; - abs.dtype = dt.RATIONAL; - abs.value = Operators.unary[shapeOf(o1)][op](o1.value); - if (abs.value.dtype && abs.value.dtype === dt.ERROR) { return abs.value } - stack.push(Object.freeze(abs)); - break - } - - case "matrix": { - // matrix - const numRows = Number(tokens[i + 1]); - const numCols = Number(tokens[i + 2]); - i += 2; - - const result = (stack.length > 0 && stack[stack.length - 1].dtype === dt.RANGE) - ? Matrix.operandFromRange(stack.pop().value) // Input was [start:step:end...] - : Matrix.operandFromTokenStack(stack, numRows, numCols); - if (result.dtype === dt.ERROR) { return result } - stack.push(result); - break - } - - case "tuple": { - const numItems = Number(tokens[i + 1]); - i += 1; - const oprnd = { value: [], unit: null, dtype: dt.TUPLE }; - for (let j = 0; j < numItems; j++) { - oprnd.value.unshift(stack.pop()); - } - stack.push(oprnd); - break - } - - case "startSvg": - stack.push({ value: draw.startSvg(), unit: null, dtype: dt.DRAWING }); - break - - case "beamDiagram": { - const numArgs = Number(tokens[i + 1]); - i += 1; - let combinations = "service"; - if (numArgs === 2) { combinations = stack.pop().value; } - const beam = stack.pop(); - if (!(beam.dtype & dt.MAP)) { return errorOprnd("BAD_TYPE", "beamDiagram") } - const diagram = beamDiagram(beam.value.data, combinations); - if (diagram.dtype && diagram.dtype === dt.ERROR) { return diagram } - stack.push({ value: diagram, resultdisplay: diagram, unit: null, dtype: dt.DRAWING }); - break - } - - case "abs": - case "cos": - case "sin": - case "tan": - case "acos": - case "asin": - case "atan": - case "sec": - case "csc": - case "cot": - case "asec": - case "acsc": - case "acot": - case "exp": - case "log": - case "ln": - case "log10": - case "log2": - case "cosh": - case "sinh": - case "tanh": - case "sech": - case "csch": - case "coth": - case "acosh": - case "asinh": - case "atanh": - case "asech": - case "acsch": - case "acoth": - case "gamma": - case "Γ": - case "lgamma": - case "lfact": - case "factorial": - case "cosd": - case "sind": - case "tand": - case "acosd": - case "asind": - case "atand": - case "secd": - case "cscd": - case "cotd": - case "asecd": - case "acscd": - case "acotd": - case "real": - case "imag": - case "angle": - case "conj": - case "ceil": - case "floor": - case "Char": - case "round": - case "sqrt": - case "sign": { - // Functions with one real or complex argument. - const arg = stack.pop(); - if (!((arg.dtype & dt.RATIONAL) || (arg.dtype & dt.COMPLEX))) { - return errorOprnd("UNREAL", tkn) - } - - const output = Object.create(null); - const unit = Object.create(null); - unit.expos = unitAware ? Functions.functionExpos(tkn, [arg]) : allZeros; - if (unit.expos.dtype && unit.expos.dtype === dt.ERROR) { return unit.expos } - output.unit = tkn === "Char" ? null : Object.freeze(unit); - - const shape = (arg.dtype & dt.RATIONAL) ? "scalar" : "complex"; - let value; - if (arg.dtype & dt.MAP) { - value = arg.value; - value.data = value.data.map(col => Rnl.isRational(col[0]) - ? col.map(e => Functions.unary[shape][tkn](e)) - : col - ); - } else { - value = isVector(arg) - ? arg.value.map(e => Functions.unary[shape][tkn](e)) - : isMatrix(arg) - ? arg.value.map(row => row.map(e => Functions.unary[shape][tkn](e))) - : Functions.unary[shape][tkn](arg.value); - } - if (value.dtype && value.dtype === dt.ERROR) { return value } - output.value = Object.freeze(value); - - output.dtype = tkn === "Char" - ? arg.dtype - dt.RATIONAL + dt.STRING - : (arg.dtype & dt.COMPLEX) && arfn.includes(tkn) - ? arg.dtype - dt.COMPLEX + dt.RATIONAL - : arg.dtype; - - stack.push(Object.freeze(output)); - break - } - - case "logn": - case "atan2": - case "hypot": - case "gcd": - case "rms": - case "binomial": - case "ones": - case "zeros": - case "mod": - case "rem": { - // Functions with two real arguments. - const args = []; - args.push(stack.pop()); - args.unshift(stack.pop()); - if (!(args[0].dtype & dt.RATIONAL)) { return errorOprnd("") } - - const output = Object.create(null); - const unit = Object.create(null); - unit.expos = unitAware ? Functions.functionExpos(tkn, args) : allZeros; - if (unit.dtype && unit.dtype === dt.ERROR) { return unit } - output.unit = Object.freeze(unit); - - const [value, dtype] = multivarFunction("binary", tkn, args); - if (dtype === dt.ERROR) { return value } - output.value = Object.freeze(value); - output.dtype = dtype; - stack.push(Object.freeze(output)); - break - } - - case "Int": { - const arg = stack.pop(); - const output = Object.create(null); - output.unit = { expos: allZeros }; - if (!(arg.dtype & dt.BOOLEAN)) { return errorOprnd("LOGIC", "Int") } - output.value = isVector(arg) - ? arg.value.map(e => Rnl.fromNumber(Number(e))) - : isMatrix(arg) - ? arg.value.map(row => row.map(e => Rnl.fromNumber(Number(e)))) - : Rnl.fromNumber(Number(arg.value)); - output.dtype = arg.dtype - dt.BOOLEAN + dt.RATIONAL; - stack.push(Object.freeze(output)); - break - } - - case "number": { - const arg = stack.pop(); - const output = Object.create(null); - output.unit = { expos: allZeros }; - if (!(arg.dtype & dt.STRING)) { return errorOprnd("STRING") } - output.value = isVector(arg) - ? arg.value.map(e => Rnl.fromString(e)) - : isMatrix(arg) - ? arg.value.map(row => row.map(e => Rnl.fromString(e))) - : Rnl.fromString(arg.value); - output.dtype = arg.dtype - dt.STRING + dt.RATIONAL; - stack.push(Object.freeze(output)); - break - } - - case "findmax": { - const arg = stack.pop(); - let max = arg.value[0]; - let index = 1; - if (!(isVector(arg) && (arg.dtype & dt.RATIONAL))) { - return errorOprnd("NOT_VECTOR", "findmax") - } - for (let i = 1; i < arg.value.length; i++) { - if (Rnl.greaterThan(arg.value[i], max)) { - max = arg.value[i]; - index = Rnl.fromNumber(i + 1); - } - } - const tuple = { value: new Map(), unit: null, dtype: dt.TUPLE }; - tuple.value.set("max", { value: max, unit: allZeros, dtype: dt.RATIONAL }); - tuple.value.set("index", { value: index, unit: allZeros, dtype: dt.RATIONAL }); - stack.push(tuple); - break - } - - case "findfirst": { - const numArgs = Number(tokens[i + 1]); - i += 1; - const args = []; - args.push(stack.pop()); - if (numArgs === 2) {args.unshift(stack.pop()); } - const isString = numArgs === 2 && (args[1].dtype & dt.STRING); - const output = Object.create(null); - output.unit = { expos: allZeros }; - output.value = isString && isVector(args[1]) - ? args[1].value.map(e => findfirst(args[0], e)) - : isString && isMatrix(args[1]) - ? args[1].value.map(row => row.map(e => findfirst(args[0], e))) - : isString - ? findfirst(args[0], args[1]) - : numArgs === 1 - ? Matrix.findfirst(true, args[0]) - : isVector(args[1]) - ? Matrix.findfirst(args[0].value, args[1]) - : errorOprnd("ERR_FUNC", "Error. Did not understand arguments"); - if (isString) { - output.dtype = args[1].dtype - dt.STRING + dt.RATIONAL; - } else { - output.dtype = dt.RATIONAL; - } - stack.push(Object.freeze(output)); - break - } - - case "roundn": - case "string": { - // Round a numeric value. - const spec = stack.pop(); - const num = stack.pop(); - if (!(num.dtype & dt.RATIONAL)) { return errorOprnd("") } - if (!(spec.dtype & dt.STRING)) { return errorOprnd("") } - if (!/(?:[fr])\d+/.test(spec.value)) { return errorOprnd("") } - let funcName = ""; - const output = Object.create(null); - if (tkn === "string") { - funcName = spec.value.charAt() === "f" ? "stringFixed" : "stringSignificant"; - output.unit = null; - output.dtype = num.dtype - dt.RATIONAL + dt.STRING; - } else { - funcName = spec.value.charAt() === "f" ? "roundFixed" : "roundSignificant"; - output.unit = num.unit; - output.dtype = num.dtype; - } - const n = Number(spec.value.slice(1)); - let value; - if (num.dtype & dt.MAP) { - value = num.value; - value.data = value.data.map( - col => Rnl.isRational(col[0]) - ? col.map(e => Functions.binary[funcName][tkn]([e, n])) - : col - ); - } else { - value = isVector(num) - ? num.value.map(e => Functions.binary[funcName]([e, n])) - : isMatrix(num) - ? num.value.map(row => row.map(e => Functions.binary[funcName]([e, n]))) - : Functions.binary[funcName]([num.value, n]); - } - if (value.dtype && value.dtype === dt.ERROR) { return value } - output.value = Object.freeze(value); - if (num.name) { output.name = num.name; } - stack.push(Object.freeze(output)); - break - } - - case "dataframe": - case "max": - case "min": - case "sum": - case "product": - case "range": - case "mean": - case "median": - case "variance": - case "stddev": - case "accumulate": { - // Functions that reduce multiple arguments to one result. - // TODO: unit-aware reducing functions. - const numArgs = Number(tokens[i + 1]); - i += 1; - const args = []; - for (let j = 0; j < numArgs; j++) { - const datum = stack.pop(); - if (tkn !== "dataframe" && !(datum.dtype & dt.RATIONAL)) { - return errorOprnd("NANARG", tkn) - } - args.unshift(datum); - } - - if (tkn === "dataframe") { - const df = DataFrame.dataFrameFromVectors(args, vars.format.value); - if (df.dtype && df.dtype === dt.ERROR) { return df } - stack.push(df); - break - } - - const output = Object.create(null); - const unit = Object.create(null); - unit.expos = unitAware ? Functions.functionExpos(tkn, args) : allZeros; - if (unit.dtype && unit.dtype === dt.ERROR) { return errorOprnd("") } - output.unit = Object.freeze(unit); - - const [value, dtype] = multivarFunction("reduce", tkn, args); - if (dtype === dt.ERROR) { return value } - output.value = Object.freeze(value); - output.dtype = dtype; - stack.push(Object.freeze(output)); - break - } - - case "rand": { - const numArgs = Number(tokens[i + 1]); - i += 1; - if (numArgs === 0) { - const value = Rnl.fromNumber(Math.random()); - stack.push({ value, unit: allZeros, dtype: dt.RATIONAL }); - } else if (numArgs === 1) { - const n = Rnl.toNumber(stack.pop().value); - if (!Number.isInteger(n)) { return errorOprnd("INT_ARG", "rand") } - const value = new Array(n).fill(0) - .map(e => Rnl.fromNumber(Math.random())); - stack.push({ value, unit: allZeros, dtype: dt.RATIONAL + dt.COLUMNVECTOR }); - } else if (numArgs === 2) { - const n = Rnl.toNumber(stack.pop().value); - if (!Number.isInteger(n)) { return errorOprnd("INT_ARG", "rand") } - const m = Rnl.toNumber(stack.pop().value); - if (!Number.isInteger(m)) { return errorOprnd("INT_ARG", "rand") } - let value = new Array(m).fill(new Array(n).fill(0)); - value = value.map(row => row.map(e => Rnl.fromNumber(Math.random()))); - stack.push({ value, unit: allZeros, dtype: dt.RATIONAL + dt.MATRIX }); - } else { - return errorOprnd("BAD_ARGS", "rand") - } - break - } - - case "isnan": { - const oprnd = stack.pop(); - const output = Object.create(null); - output.value = !(oprnd.dtype & dt.RATIONAL); - output.unit = null; - output.dtype = dt.BOOLEAN; - stack.push(Object.freeze(output)); - break - } - - case "length": { - const arg = stack.pop(); - const value = arg.value; - const length = isVector(arg) - ? value.length - : (arg.dtype & dt.MATRIX) - ? value.length * value[0].length - : (arg.dtype === dt.STRING) - ? Array.from(value).length - : (arg.dtype & dt.MAP) - ? arg.keys().value.length - : 0; - const output = Object.create(null); - output.value = Object.freeze(Rnl.fromNumber(length)); - output.unit = Object.create(null); - output.unit.expos = allZeros; - output.dtype = dt.RATIONAL; - stack.push(Object.freeze(output)); - break - } - - case "count": { - const pattern = stack.pop(); - const str = stack.pop(); - if (pattern.dtype !== dt.STRING || str.dtype !== dt.STRING) { - return errorOprnd("COUNT") - } - const output = Object.create(null); - output.value = Object.freeze( - Rnl.fromNumber(str.value.split(pattern.value).length - 1) - ); - output.unit = Object.create(null); - output.unit.expos = allZeros; - output.dtype = dt.RATIONAL; - stack.push(Object.freeze(output)); - break - } - - case "format": { - const formatSpec = stack.pop().value; - const str = format(stack.pop().value, formatSpec); - stack.push({ value: str, unit: null, dtype: dt.STRING }); - break - } - - case "lerp": { - // linear interpolation function - const args = new Array(3); - args[2] = stack.pop(); - args[1] = stack.pop(); - args[0] = stack.pop(); - const result = Functions.lerp(args, unitAware); - if (result.dtype === dt.ERROR) { return result } - stack.push(result); - break - } - - case "matrix2table": { - const numArgs = Number(tokens[i + 1]); - i += 1; - const rowNames = numArgs === 3 ? stack.pop().value : []; - const colNames = stack.pop().value; - const matrix = stack.pop(); - const result = DataFrame.matrix2table(matrix, colNames, rowNames); - if (result.dtype === dt.ERROR) { return result } - stack.push(result); - break - } - - case "transpose": - stack.push(Matrix.transpose(stack.pop())); - break - - case "trace": - stack.push(Matrix.trace(stack.pop())); - break - - case "fetch": - // fetch() is handled in updateCalculations.js. - // It's easier from there to coordinate an async function with ProseMirror. - // So if control flow get here, we have an error. - return errorOprnd("FETCH") - - case "function": { - // User defined function. - const functionName = tokens[i + 1]; - const numArgs = Number(tokens[i + 2]); - i += 2; - const args = new Array(numArgs); - for (let j = numArgs - 1; j >= 0; j--) { - args[j] = stack.pop(); - } - let oprnd; - if (vars.svg && (functionName === "plot" || (draw.functions[functionName]))) { - if (functionName === "plot") { - args.splice(1, 0, decimalFormat); - oprnd = plot(...args); - } else if (functionName === "path") { - oprnd = draw.functions[functionName](args[0], args.slice(1)); - } else { - oprnd = draw.functions[functionName](...args); - } - } else if (nextToken(tokens, i) === ".") { - // Function from a module - let lib = stack.pop().value; // remote module - if (lib.value) { lib = lib.value; } // local module - const udf = lib[functionName]; - if (udf === undefined) { return errorOprnd("F_NAME", functionName) } - if (udf.dtype === dt.ERROR) { return udf } - oprnd = evalCustomFunction(udf, args, decimalFormat, unitAware, lib); - i += 1; - } else if (lib && lib[functionName]) { - // A module, "lib", was passed to this instance of evalRpn(). - const udf = lib[functionName]; - oprnd = evalCustomFunction(udf, args, decimalFormat, unitAware, lib); - } else if (vars[functionName] && vars[functionName].dtype === dt.MODULE) { - // User-defined function from a calculation node. - const udf = vars[functionName]["value"]; - oprnd = evalCustomFunction(udf, args, decimalFormat, unitAware); - } else { - return errorOprnd("BAD_FUN_NM", functionName) - } - if (oprnd.dtype === dt.ERROR) { return oprnd } - stack.push(oprnd); - break - } - - case "=": - case "==": - case "⩵": - case "<": - case ">": - case "<=": - case "≤": - case ">=": - case "≥": - case "≠": - case "!=": - case "∈": - case "in": - case "∉": - case "!in": - case "∋": - case "∌": - case "⊂": - case "⊄": - case "⊃": - case "⊅": { - const o2 = stack.pop(); - const o1 = stack.pop(); - if (unitAware && - !((o1.dtype & dt.STRING) || (o2.dtype & dt.STRING) || - o1.dtype === dt.NULL || o2.dtype === dt.NULL)) { - if (!unitsAreCompatible(o1.unit.expos, o2.unit.expos)) { - return errorOprnd("UNIT_COMP") - } - } - const bool = Object.create(null); - bool.unit = null; - const prevValue = (o1.dtype === dt.BOOLEANFROMCOMPARISON) ? oPrev.value : undefined; - - if (setComparisons.includes(tkn)) { - bool.value = compare(tkn, o1.value, o2.value, prevValue); - bool.dtype = o1.dtype + dt.BOOLEANFROMCOMPARISON; - } else { - const [shape1, shape2, _] = binaryShapesOf(o1, o2); - bool.value = Operators.relations[shape1][shape2].relate(tkn, o1.value, - o2.value, prevValue); - bool.dtype = Operators.dtype[shape1][shape2](o1.dtype, o2.dtype, tkn) - + dt.BOOLEANFROMCOMPARISON; - } - if (bool.value.dtype && bool.value.dtype === dt.ERROR) { return bool.value } - if (bool.dtype & dt.RATIONAL) { bool.dtype -= dt.RATIONAL; } - if (bool.dtype & dt.COMPLEX) { bool.dtype -= dt.COMPLEX; } - if (bool.dtype & dt.STRING) { bool.dtype -= dt.STRING; } - oPrev = o2; - stack.push(Object.freeze(bool)); - break - } - - case "and": - case "&&": - case "or": - case "||": - case "∧": - case "∨": - case "⊻": { - const o2 = stack.pop(); - const o1 = stack.pop(); - if (!(o1.dtype & dt.BOOLEAN) || !(o2.dtype & dt.BOOLEAN)) { - return errorOprnd("LOGIC", tokens[i]) - } - const op = { "and": "and", "&&": "and", "or": "or", "∧": "and", - "||": "or", "∨": "or", "⊻": "xor" }[tkn]; - const [shape1, shape2, _] = binaryShapesOf(o1, o2); - - const bool = Object.create(null); - bool.unit = null; - bool.value = Operators.binary[shape1][shape2][op](o1.value, o2.value); - if (bool.value.dtype && bool.value.dtype === dt.ERROR) { return bool.value } - - bool.dtype = Operators.dtype[shape1][shape2](o1.dtype, o2.dtype, tkn); - stack.push(Object.freeze(bool)); - break - } - - case "not": - case "¬": { - const o1 = stack.pop(); - if (!(o1.dtype & dt.BOOLEAN)) { return errorOprnd("LOGIC", tkn) } - const bool = Object.create(null); - bool.unit = null; - bool.value = Operators.unary[shapeOf(o1)]["not"](o1.value); - if (bool.value.dtype && bool.value.dtype === dt.ERROR) { return bool.value } - bool.dtype = dt.BOOLEAN; - stack.push(Object.freeze(bool)); - break - } - - case "cases": { - // A multi-line cases expression. Hurmet's ternary expression. - const numArgs = Number(tokens[i + 1]); - i += 1; - // We evaluate cases expressions lazily. Pop the conditions into an array. - const conditions = new Array(numArgs); - for (let j = numArgs - 1; j >= 0; j--) { - conditions[j] = stack.pop(); - } - // Check each condition. - // When we reach the first true condition, evaluate the corresponding expression. - for (let j = 0; j < numArgs; j++) { - if ((conditions[j].dtype & dt.BOOLEAN) === 0) { - return errorOprnd("LOGIC", "if") - } - const val = Operators.condition[shapeOf(conditions[j])](conditions[j].value); - if (val) { - const rpnLocal = tokens[i + j + 1].replace(/§/g, "\u00A0"); - const oprnd = evalRpn(rpnLocal, vars, decimalFormat, unitAware, lib); - if (oprnd.dtype === dt.ERROR) { return oprnd } - stack.push(oprnd); - break - } - } - i += numArgs; // Discard the unused expressions - break - } - - case "applyUnit": { - // Pop a magnitude off the stack and apply a unit. - // This happens where a user writes a QUANTITY literal. - if (!unitAware) { return errorOprnd("UNIT_AWARE", tokens[i + 1]) } - const o1 = stack.pop(); - if (!(o1.dtype & dt.RATIONAL)) { return errorOprnd("QUANT_NUM") } - const unitName = tokens[i + 1]; - i += 1; - const output = Object.create(null); - output.unit = Object.create(null); - output.dtype = o1.dtype; - if (!unitAware) { - output.value = o1.value; - if (o1.dtype & dt.MAP) { - output.unit = unitFromUnitName(unitName); - } else { - output.unit.name = unitName; - } - } else { - // Convert the magnitude to base units. - const unit = unitFromUnitName(unitName); - if (unit.dtype && unit.dtype === dt.ERROR) { return unit } - if (isMatrix(o1)) { - output.unit.expos = o1.unit.expos.map((e, j) => e + unit.expos[j]); - output.value = Matrix.convertToBaseUnits(o1, unit.gauge, unit.factor); - } else if (o1.dtype & dt.MAP) { - output.unit = unitFromUnitName(o1.unit); - output.value = o1.value; - } else { - output.unit.expos = o1.unit.expos.map((e, j) => e + unit.expos[j]); - output.value = Rnl.multiply(Rnl.add(o1.value, unit.gauge), unit.factor); - } - } - stack.push(Object.freeze(output)); - break - } - - case "rem%": { - const o2 = stack.pop(); - const o1 = stack.pop(); - if (!((o1.dtype & dt.RATIONAL) & (o2.dtype & dt.RATIONAL))) { - return errorOprnd("NAN_OP") - } - const [shape1, shape2, _] = binaryShapesOf(o1, o2); - const mod = Object.create(null); - mod.unit = Object.create(null); - mod.unit.expos = allZeros; - mod.value = Operators.binary[shape1][shape2]["rem"](o1.value, o2.value); - if (mod.value.dtype && mod.value.dtype === dt.ERROR) { return mod.value } - mod.dtype = Operators.dtype[shape1][shape2](o1.dtype, o2.dtype, tkn); - stack.push(Object.freeze(mod)); - break - } - - case "⎾⏋": - case "⎿⏌": { - // ceiling or floor - const o1 = stack.pop(); - if (!(o1.dtype & dt.RATIONAL)) { return errorOprnd("NAN_OP") } - if (unitAware) { - if (!unitsAreCompatible(o1.unit.expos, allZeros)) { - // TODO: Write an error message. - { return errorOprnd("") } - } - } - const op = tkn === "⎾⏋" ? "ceil" : "floor"; - const output = Object.create(null); - output.value = Operators.unary[shapeOf(o1)][op](o1.value); - if (output.value.dtype && output.value.dtype === dt.ERROR) { return output.value } - output.unit = o1.unit; - output.dtype = o1.dtype; - stack.push(Object.freeze(output)); - break - } - - case "()": { - // binomial - const args = []; - args.unshift(stack.pop()); - args.unshift(stack.pop()); - if (unitAware) { - if (!unitsAreCompatible(args[0].unit.expos, allZeros) || - !unitsAreCompatible(args[1].unit.expos, allZeros)) { - return errorOprnd("BINOM") - } - } - const binom = Object.create(null); - binom.unit = Object.create(null); - binom.unit.expos = allZeros; - const [value, dtype] = multivarFunction("binary", "binomial", args); - binom.value = value; - binom.dtype = dtype; - stack.push(Object.freeze(binom)); - break - } - - case "→": { - // Anonymous function, e.g., x → cos x - const rpnLocal = stack.pop().value.replace(/§/g, "\xa0"); - const parameter = stack.pop().value; - stack.push({ - dtype: dt.MODULE, - unit: null, - value: { - parameters: [ { name: parameter }], - statements: [{ rpn: rpnLocal, stype: "return" }] - } }); - break - } - - case "∑": { - const rpnLocal = stack.pop().value.replace(/§/g, "\xa0"); - const endOfRange = stack.pop().value; - let index = stack.pop().value; - const parameter = stack.pop().value; - let sum = Rnl.zero; - while (Rnl.lessThanOrEqualTo(index, endOfRange)) { - vars[parameter] = { value: index, unit: allZeros, dtype: dt.RATIONAL }; - const localResult = evalRpn(rpnLocal, vars, decimalFormat, false); - sum = Rnl.add(sum, localResult.value); - index = Rnl.add(index, Rnl.one); - } - delete vars[parameter]; - stack.push({ value: sum, unit: allZeros, dtype: dt.RATIONAL }); - break - } - - case "throw": - return { value: stack.pop().value, unit: null, dtype: dt.ERROR } - - case "\\blue": - case "\\gray": - case "\\green": - case "\\orange": - case "\\pink": - case "\\purple": - case "\\red": { - const color = clone(stack.pop()); - if (color.dtype === dt.STRING) { color.unit = tkn.slice(1); } - stack.push(color); - break - } - // TODO: Write an error message - } - } - } // next i - - const oprnd = stack.pop(); - if (stack.length > 0) { - return errorOprnd("ERROR") - } - - return oprnd -}; - -const plot = (svg, decimalFormat, fun, numPoints, xMin, xMax) => { - // Plot a function. - // To avoid a circular reference, this function has to be here instead of in draw.js. - const attrs = svg.value.temp; - numPoints = (numPoints == null) ? Rnl.fromNumber(250) : numPoints.value; - const min = (xMin == null) ? Rnl.fromNumber(attrs.xmin) : xMin.value; - const max = (xMax == null) ? Rnl.fromNumber(attrs.xmax) : xMax.value; - // Vectorize the evaluation. Start by finding a vector of the input. - const step = Rnl.divide(Rnl.subtract(max, min), numPoints); - const vector = Matrix.operandFromRange([min, step, max]); - // Transpose the row vector into a column vector. - const arg = { value: vector.value, unit: null, dtype: dt.COLUMNVECTOR + dt.RATIONAL }; - // Run the function on the vector. - let funResult; - let pathValue; - if (fun.value.dtype && fun.value.dtype === dt.MODULE) { - funResult = evalCustomFunction(fun.value, [arg], decimalFormat, false); - pathValue = arg.value.map((e, i) => [e, funResult.value[i]]); - } else if (fun.dtype === dt.STRING) { - if (/§matrix§1§2$/.test(fun.value)) { - arg.name = "t"; - pathValue = evalRpn(fun.value.replace(/§/g, "\xa0"), { t: arg }, decimalFormat, false).value; - } else { - arg.name = "x"; - funResult = evalRpn(fun.value.replace(/§/g, "\xa0"), { x: arg }, decimalFormat, false); - pathValue = arg.value.map((e, i) => [e, funResult.value[i]]); - } - } else ; - const point = { value: pathValue[0], unit: null, dtype: dt.ROWVECTOR + dt.RATIONAL }; - const pth = { value: pathValue.slice(1), unit: null, dtype: dt.MATRIX + dt.RATIONAL }; - return draw.functions.path(svg, [point, pth]) -}; - -const elementFromIterable = (iterable, index, step) => { - // A helper function. This is called by `for` loops in evalCustomFunction() - let value; - let nextIndex = Rnl.increment(index); - let dtype = 0; - if (iterable.dtype === dt.RANGE) { - value = index; - nextIndex = Rnl.add(index, step); - dtype = dt.RATIONAL; - } else if ((iterable.dtype === dt.STRING) && - iterable.value[Rnl.fromNumber(index)] === "\uD835") { - value = Rnl.fromNumber(iterable.value[index] + iterable.value[index + 1]); - nextIndex = Rnl.add(index, 2); - dtype = dt.STRING; - } else { - value = iterable.value[Rnl.toNumber(index)]; - dtype = (iterable.dtype & dt.STRING) - ? dt.STRING - : (iterable.dtype & dt.ROWVECTOR) - ? iterable.dtype - dt.ROWVECTOR - : (iterable.dtype & dt.COLUMNVECTOR) - ? iterable.dtype - dt.COLUMNVECTOR - : iterable.dtype - dt.MATRIX; - } - const oprnd = { value: value, unit: iterable.unit, dtype: dtype }; - return [oprnd, nextIndex] -}; - -const loopTypes = ["while", "for"]; - -const evalCustomFunction = (udf, args, decimalFormat, isUnitAware, lib) => { - // UDF stands for "user-defined function" - // lib is short for library. If not omitted, it contains a module with more functions. - - if (udf.dtype === dt.ERROR) { - return udf - } - - // Populate the function parameters. - if (args.length > udf.parameters.length) { return errorOprnd("NUMARGS", udf.name) } - const vars = Object.create(null); - for (let i = 0; i < args.length; i++) { - vars[udf.parameters[i].name] = args[i]; - } - if (udf.parameters.length > args.length) { - for (let i = args.length; i < udf.parameters.length; i++) { - vars[udf.parameters[i].name] = udf.parameters[i].default; - } - } - if (udf.dtype === dt.DRAWING) { - vars["svg"] = { value: draw.startSvg(), unit: null, dtype: dt.DRAWING }; - } - - // Execute the function statements. - // There will be nested flow of control, of course. So we'll create a - // "control" stack. The topmost element contains info about the control - // that applies to the current nesting level. - const control = [{ type: "if", condition: true, endOfBlock: udf.statements.length - 1 }]; - for (let i = 0; i < udf.statements.length; i++) { - const statement = udf.statements[i]; - const stype = statement.stype; - const level = control.length - 1; - switch (stype) { - case "statement": { - if (control[level].condition) { - const result = evalRpn(statement.rpn, vars, decimalFormat, isUnitAware, lib); - if (result.dtype === dt.ERROR) { - // eslint-disable-next-line no-console - console.log(statement.rpn); - return result - } - if (statement.name) { - statement.resultdisplay = isUnitAware ? "!!" : "!"; - const [stmt, _] = conditionResult(statement, result, isUnitAware); - insertOneHurmetVar(vars, stmt, null, decimalFormat); - } - } - break - } - - case "if": { - if (control[level].condition) { - const result = evalRpn(statement.rpn, vars, decimalFormat, isUnitAware, lib); - if (result.dtype === dt.ERROR) { return result } - const val = Operators.condition[shapeOf(result)](result.value); - control.push({ - type: "if", - condition: val, - endOfBlock: statement.endOfBlock - }); - } else { - // Skip this block - i = statement.endOfBlock; - } - break - } - - case "elseif": { - if (control[level].type === "if" && control[level].condition) { - i = control[level].endOfBlock; - control.pop(); - } else { - const result = evalRpn(statement.rpn, vars, decimalFormat, isUnitAware, lib); - if (result.dtype === dt.ERROR) { return result } - const val = Operators.condition[shapeOf(result)](result.value); - control[control.length - 1].condition = val; - } - break - } - - case "else": - if (control[level].type === "if" && control[level].condition) { - i = control[level].endOfBlock; - control.pop(); - } else { - control[level].condition = true; - } - break - - case "while": { - if (control[level].condition) { - const cntrl = { - type: "while", - startStatement: i, - rpn: statement.rpn, - endOfBlock: statement.endOfBlock - }; - const result = evalRpn(statement.rpn, vars, decimalFormat, isUnitAware, lib); - if (result.dtype === dt.ERROR) { return result } - const val = Operators.condition[shapeOf(result)](result.value); - cntrl.condition = val; - if (cntrl.condition === true) { - control.push(cntrl); - } else { - i = statement.endOfBlock; - } - } else { - i = statement.endOfBlock; - } - break - } - - case "for": { - if (control[level].condition) { - const ctrl = { - type: "for", - condition: true, - startStatement: i, - endOfBlock: statement.endOfBlock - }; - const tokens = statement.rpn.split("\u00A0"); - ctrl.dummyVariable = tokens.shift().slice(1); - const iterable = evalRpn(tokens.join("\u00A0"), vars, - decimalFormat, isUnitAware, lib); - ctrl.index = (iterable.dtype & dt.RANGE) ? iterable.value[0] : Rnl.fromNumber(0); - ctrl.step = (iterable.dtype & dt.RANGE) ? iterable.value[1] : Rnl.fromNumber(0); - ctrl.endIndex = (iterable.dtype & dt.RANGE) - ? iterable.value[2] - : Rnl.fromNumber(iterable.value.length - 1); - const [oprnd, nextIndex] = elementFromIterable(iterable, ctrl.index, ctrl.step); - ctrl.nextIndex = nextIndex; - ctrl.iterable = iterable; - control.push(ctrl); - vars[ctrl.dummyVariable] = oprnd; - } else { - i = statement.endOfBlock; - } - break - } - - case "break": { - if (control[level].condition) { - // Find the enclosing loop and pop out of it. - for (let j = control.length - 1; j > 0; j--) { - if (loopTypes.includes(control[j].type) || j === 0) { - i = control[j].endOfBlock; - control.pop(); - break - } else { - control.pop(); - } - } - } - break - } - - case "end": { - // end of code block - if (control[level].type === "if" && i >= control[level].endOfBlock) { - control.pop(); - } else if (control[level].type === "if" && control[level].condition) { - // Jump ahead to end of if block - if (i < control[level].endOfBlock) { i = control[level].endOfBlock; } - control.pop(); - } else if (control[level].type === "while") { - const result = evalRpn(control[level].rpn, vars, decimalFormat, isUnitAware, lib); - if (result.dtype === dt.ERROR) { return result } - control[level].condition = result.value; - if (control[level].condition) { - i = control[level].startStatement; - } else { - control.pop(); - } - } else if (control[level].type === "for") { - control[level].index = control[level].nextIndex; - const proceed = Rnl.isRational(control[level].index) - && Rnl.isPositive(control[level].step) - ? Rnl.lessThanOrEqualTo(control[level].index, control[level].endIndex) - : Rnl.isRational(control[level].index) - ? Rnl.greaterThanOrEqualTo(control[level].index, control[level].endIndex) - : control[level].index <= control[level].endIndex; - if (proceed) { - const [oprnd, nextIndex] = elementFromIterable( - control[level].iterable, - control[level].index, control[level].step - ); - vars[control[level].dummyVariable] = oprnd; - control[level].nextIndex = nextIndex; - i = control[level].startStatement; - } else { - control.pop(); - } - } - break - } - - case "return": - if (control[level].condition) { - if (statement.rpn) { - const result = evalRpn(statement.rpn, vars, decimalFormat, isUnitAware, lib); - return result - } else { - return { value: Rnl.zero, unit: allZeros, dtype: dt.RATIONAL } - } - } - break - - case "print": - if (control[level].condition) { - if (statement.rpn) { - const result = evalRpn(statement.rpn, vars, decimalFormat, isUnitAware, lib); - if (result.dtype === dt.ERROR) { return result } - const msg = result.dtype === dt.RATIONAL - ? Rnl.toNumber(result.value) - : result.dtype === dt.STRING || result.dtype === dt.BOOLEAN - ? result.value - : isVector(result) && (result.dtype & dt.RATIONAL) - ? result.value.map(e => Rnl.toNumber(e)) - : result.dtype === dt.MATRIX + dt.RATIONAL - ? result.value.map(row => row.map(e => Rnl.toNumber(e))) - : result.value; - // eslint-disable-next-line no-console - console.log(msg); - } - } - break - - case "throw": - if (control[level].condition) { - if (statement.rpn) { - const result = evalRpn(statement.rpn, vars, decimalFormat, isUnitAware, lib); - return { value: result.value, unit: null, dtype: dt.ERROR } - } else { - return { value: statement.rpn, unit: null, dtype: dt.ERROR } - } - } - break - // TODO: Error message. - } - } -}; - -const errorResult = (stmt, result) => { - stmt.value = null; - stmt.resultDisplay = "\\textcolor{firebrick}{\\text{" + result.value.replace(/%/g, "\\%") + "}}"; - stmt.altResultDisplay = result.value; - stmt.error = true; - stmt.dtype = dt.ERROR; - if (stmt.resulttemplate.indexOf("!") > -1) { - stmt.tex += "= " + stmt.resultDisplay; - stmt.alt += result.value; - } else if (stmt.resulttemplate.indexOf("@") > -1) { - stmt.tex = stmt.resulttemplate.replace(/@@?/, stmt.resultDisplay); - stmt.alt = stmt.altresulttemplate.replace(/@@?/, stmt.altResultDisplay); - } else { - stmt.tex = stmt.tex.replace(/[?%] *[?%]|[?%]/, stmt.resultDisplay); - stmt.alt = stmt.alt.replace(/[?%] *[?%]|[?%]/, stmt.altResultDisplay); - } - return [stmt, result] -}; - -const conditionResult = (stmt, oprnd, unitAware) => { - let result = Object.create(null); - result.value = oprnd.dtype === dt.DATAFRAME - ? oprnd.value - : clone(oprnd.value); - result.unit = clone(oprnd.unit); - result.dtype = oprnd.dtype; - - if (result.dtype === dt.COMPLEX && Rnl.isZero(Cpx.imag(result.value))) { - result.value = Cpx.real(result.value); - result.dtype = 1; - } - - // Check unit compatibility. - if (result.dtype !== dt.ERROR && unitAware && stmt.resultdisplay.indexOf("!") === -1 && - (stmt.unit && stmt.unit.expos || - (result.unit && result.unit.expos && Array.isArray(result.unit.expos)))) { - const expos = (stmt.unit && stmt.unit.expos) ? stmt.unit.expos : allZeros; - if (!unitsAreCompatible(result.unit.expos, expos)) { - const message = stmt.unit.expos ? "UNIT_RES" : "UNIT_MISS"; - result = errorOprnd(message); - } - } - if (result.dtype === dt.ERROR) { return errorResult(stmt, result) } - - // Check for a valid display indicator. - if (stmt.resulttemplate && stmt.resulttemplate.indexOf("!") > -1 && - !(result.dtype === dt.DATAFRAME || (result.dtype & dt.MAP) || isMatrix(result) - || (result.dtype & dt.TUPLE))) { - return errorResult(stmt, errorOprnd("BAD_DISPLAY")) - } - - if (result.dtype & dt.RATIONAL) { - if (result.dtype & dt.MAP) { - result.value.data = result.value.data.map(column => Rnl.isRational(column[0]) - ? column.map(e => Rnl.normalize(e)) - : column); - } else { - result.value = isVector(result) - ? result.value.map(e => Rnl.normalize(e)) - : isMatrix(result) - ? result.value.map(row => row.map(e => Rnl.normalize(e))) - : result.dtype === dt.RATIONAL - ? Rnl.normalize(result.value) - : result.value; - } - } else if (result.dtype === dt.COMPLEX) { - result.value = [Rnl.normalize(result.value[0]), Rnl.normalize(result.value[1])]; - } - stmt.dtype = result.dtype; - - // If unit-aware, convert result to desired result units. - const unitInResultSpec = (stmt.unit && stmt.unit.factor && - (!Rnl.areEqual(stmt.unit.factor, Rnl.one) || stmt.unit.gauge)); - if ((result.dtype & dt.DATAFRAME) || - (typeof stmt.resultdisplay === "string" && stmt.resultdisplay.indexOf("!") > -1)) { - stmt.unit = result.unit; - } else if (unitAware && (result.dtype & dt.RATIONAL)) { - if (!unitInResultSpec & unitsAreCompatible(result.unit.expos, allZeros)) { - stmt.unit = { factor: Rnl.one, gauge: Rnl.zero, expos: allZeros }; - } - if (result.dtype & dt.MAP) { - result.value.data = { - plain: map.convertFromBaseUnits(result.value.data, stmt.unit.gauge, stmt.unit.factor), - inBaseUnits: result.value.data - }; - } else { - result.value = { - plain: (isMatrix(result)) - ? Matrix.convertFromBaseUnits( - { value: result.value, dtype: result.dtype }, - stmt.unit.gauge, - stmt.unit.factor - ) - : Rnl.subtract(Rnl.divide(result.value, stmt.unit.factor), stmt.unit.gauge), - inBaseUnits: result.value - }; - } - stmt.dtype += dt.QUANTITY; - stmt.expos = result.unit.expos; - } else if (unitInResultSpec) { - // A non-unit aware calculation, but with a unit attached to the result. - if (result.dtype & dt.MAP) { - const data = { - plain: result.value.data, - inBaseUnits: map.convertToBaseUnits(result.value.data, - stmt.unit.gauge, stmt.unit.factor) - }; - result.value.data = data; - } else { - result.value = { - plain: result.value, - inBaseUnits: (isMatrix(result)) - ? Matrix.convertToBaseUnits( - { value: result.value, dtype: result.dtype }, - stmt.unit.gauge, - stmt.unit.factor - ) - : Rnl.multiply(Rnl.add(result.value, stmt.unit.gauge), stmt.unit.factor) - }; - } - stmt.dtype += dt.QUANTITY; - - } else if ((result.dtype & dt.RATIONAL) || (result.dtype & dt.COMPLEX) ) { - // A numeric result with no unit specified. - stmt.unit = { expos: allZeros }; - } - if (Object.prototype.hasOwnProperty.call(result, "value")) { - stmt.value = result.value; - } - return [stmt, result] -}; - -const evaluateDrawing = (stmt, vars, decimalFormat = "1,000,000.") => { - // eslint-disable-next-line no-prototype-builtins - const udf = stmt.value; - const args = []; - for (let i = 0; i < udf.parameters.length; i++) { - const argName = udf.parameters[i].name; - args.push(evalRpn("¿" + argName, vars, decimalFormat, false, {})); - } - const funcResult = evalCustomFunction(udf, args, decimalFormat, false, {}); - if (funcResult.dtype === dt.ERROR) { - stmt.error = true; - stmt.tex = "\\textcolor{firebrick}{\\text{" + funcResult.value + "}}"; - stmt.value = null; - stmt.dtype = dt.ERROR; - } else { - stmt.resultdisplay = funcResult.value; - delete stmt.resultdisplay.temp; - } - return stmt -}; - -const evaluate = (stmt, vars, decimalFormat = "1,000,000.") => { - stmt.tex = stmt.template; - stmt.alt = stmt.altTemplate; - const isUnitAware = /\?\?|!!|%%|@@|¡¡/.test(stmt.resulttemplate); - - const formatSpec = vars.format ? vars.format.value : "h15"; - - if (stmt.tex.indexOf("〖") > -1) { - // eslint-disable-next-line max-len - const eqnWithVals = plugValsIntoEcho(stmt.tex, vars, isUnitAware, formatSpec, decimalFormat); - if (eqnWithVals.dtype && eqnWithVals.dtype === dt.ERROR) { - const [newStmt, _] = errorResult(stmt, eqnWithVals); - return newStmt - } else { - stmt.tex = eqnWithVals; - } - } - - if (stmt.rpn) { - let oprnd = evalRpn(stmt.rpn, vars, decimalFormat, isUnitAware); - if (oprnd.dtype === dt.ERROR) { [stmt, oprnd] = errorResult(stmt, oprnd); return stmt} - let result; - [stmt, result] = conditionResult(stmt, oprnd, isUnitAware); - if (stmt.error) { return stmt } - const assert = vars.assert ? vars.assert : null; - stmt = formatResult(stmt, result, formatSpec, decimalFormat, assert, isUnitAware); - } - return stmt -}; - -const numberRegEx$2 = new RegExp(Rnl.numberPattern); -const matrixRegEx = /^[([] *(?:(?:-?[0-9.]+|"[^"]+"|true|false) *[,;\t]? *)+[)\]]/; -/* eslint-disable max-len */ - -const numStr = "(-?(?:0x[0-9A-Fa-f]+|[0-9]+(?: [0-9]+\\/[0-9]+|(?:\\.[0-9]+)?(?:e[+-]?[0-9]+|%)?)))"; -const nonNegNumStr = "(0x[0-9A-Fa-f]+|[0-9]+(?: [0-9]+\\/[0-9]+|(?:\\.[0-9]+)?(?:e[+-]?[0-9]+|%)?))"; -const complexRegEx = new RegExp("^" + numStr + "(?: *([+-]) *(?: j *" + nonNegNumStr + "|" + nonNegNumStr + " *∠" + numStr + "(°)?))"); -// const complexRegEx = /^(number)(?: *([+-]) *(non-negative number) *j(number)(°)?)/ -/* eslint-enable max-len */ -// Capturing groups: -// [1] First number, either a in a ± b im, or r in r∠θ -// [2] + or -. Gives the sign of the imaginary part in an a ± b im. -// [3] b, the imaginary part in an a ± b im expression -// [4] theta, the argument (phase angle ) of an r∠θ expression -// [5] °, optional trailing degree sign in an r∠θ expression - -const unitFromString = str => { - if (str.length === 0) { return ["", ""] } - const unitName = str.replace(/'/g, "").trim(); - const unit = unitFromUnitName(unitName); - const unitDisplay = (unit.dtype && unit.dtype === dt.ERROR) - ? "" - : unitTeXFromString(unitName); - return [unit, unitDisplay] -}; - -const literalWithUnit = (oprnd, tex, unitStr) => { - let unit = (oprnd.dtype & dt.RATIONAL) ? { expos: allZeros } : null; - let unitDisplay = ""; - let value = oprnd.value; - if (unitStr.length > 0) { - [unit, unitDisplay] = unitFromString(unitStr); - if (unit.dtype && unit.dtype === dt.ERROR) { - return [0, null, dt.ERROR, ""] - } - value = oprnd.dtype === dt.RATIONAL - ? { - plain: oprnd.value, - inBaseUnits: Rnl.multiply(Rnl.add(oprnd.value, unit.gauge), unit.factor) - } - : { - plain: oprnd.value, - inBaseUnits: Matrix.convertToBaseUnits(oprnd, unit.gauge, unit.factor) - }; - } - let dtype = oprnd.dtype; - if (unitDisplay.length > 0) { - dtype += dt.QUANTITY; - return [value, unit, dtype, tex + "\\," + unitDisplay] - } else { - return [value, unit, dtype, tex] - } -}; - -const valueFromLiteral = (str, name, decimalFormat) => { - // Read a literal string and return a value - // The return should take the form: [value, unit, dtype, resultDisplay] - - if (/^[({[].* to /.test(str)) { - // str defines a quantity distribution, (a to b). That is handled by calculation.js. - // This is not a valid literal. - return [0, null, dt.ERROR, ""] - - } else if (str === "true" || str === "false") { - return [Boolean(str), null, dt.BOOLEAN, `\\mathord{\\text{${str}}}`] - - } else if (str.length > 3 && str.slice(0, 3) === '"""') { - // str contains a macro - return [str.slice(3, -3), undefined, dt.MACRO, ""] - - } else if (/^\x22.+\x22/.test(str)) { - // str contains text between quotation marks - if (name === "format") { - return parseFormatSpec(str.slice(1, -1).trim()) - } else { - const tex = parse$1(str, decimalFormat); - return [str.slice(1, -1), undefined, dt.STRING, tex] - } - - } else if (matrixRegEx.test(str)) { - // We're processing a matrix - const matrixStr = matrixRegEx.exec(str)[0]; - const [tex, rpn, _] = parse$1(matrixStr, decimalFormat, true); - const oprnd = evalRpn(rpn, {}, decimalFormat, false, {}); - const unitStr = str.slice(matrixStr.length).trim(); - return literalWithUnit(oprnd, tex, unitStr) - - } else if (/^``/.test(str)) { - // A TSV between double back ticks. - // Read the TSV into a data frame. - const pos = str.indexOf("``", 2); - const tsv = tablessTrim(str.slice(2, pos)); - const oprnd = DataFrame.dataFrameFromTSV(tsv); - if (oprnd.dtype === dt.DATAFRAME) { - return [oprnd.value, oprnd.unit, dt.DATAFRAME, - DataFrame.display(oprnd.value, "h3", decimalFormat)] - } else { - // It's a Hurmet Map - const unitStr = str.slice(pos + 2).trim(); - let unit; - let unitDisplay = ""; - if (unitStr.length > 0) { - [unit, unitDisplay] = unitFromString(unitStr); - if (unit.dtype && unit.dtype === dt.ERROR) { return [0, null, dt.ERROR, ""] } - oprnd.unit = unit; - oprnd.dtype = dt.MAP + dt.RATIONAL + dt.QUANTITY; - oprnd.value.data = { - plain: oprnd.value.data, - inBaseUnits: map.convertToBaseUnits(oprnd.value.data, unit.gauge, unit.factor) - }; - } - return [oprnd.value, unit, oprnd.dtype, - DataFrame.display(oprnd.value, "h3", decimalFormat) + "\\;" + unitDisplay] - } - - } else if (complexRegEx.test(str)) { - // str is a complex number. - const resultDisplay = parse$1(str, decimalFormat); - const parts = str.match(complexRegEx); - let realPart; - let imPart; - if (parts[3]) { - // a + b im expression - realPart = Rnl.fromString(parts[1]); - imPart = Rnl.fromString(parts[3]); - if (parts[2] === "-") { imPart = Rnl.negate(imPart); } - } else { - // r∠θ expression - const r = Rnl.fromString(parts[1]); - let theta = Rnl.fromString(parts[4]); - if (parts[5]) { theta = Rnl.divide(Rnl.multiply(theta, Rnl.pi), Rnl.fromNumber(180)); } - realPart = Rnl.multiply(r, Rnl.fromNumber(Math.cos(Rnl.toNumber(theta)))); - imPart = Rnl.multiply(r, Rnl.fromNumber(Math.sin(Rnl.toNumber(theta)))); - } - return [[realPart, imPart], allZeros, dt.COMPLEX, resultDisplay] - - } else { - const match = numberRegEx$2.exec(str); - if (match) { - // str begins with a number. - const numStr = match[0]; - const unitStr = str.slice(numStr.length).trim(); - const [tex, rpn, _] = parse$1(numStr, decimalFormat, true); - const oprnd = evalRpn(rpn, {}, decimalFormat, false, {}); - return literalWithUnit(oprnd, tex, unitStr) - - } else { - // TODO: Preceding currency symbol, e.g., $25.20 - return [0, null, dt.ERROR, ""] - } - } -}; - -const isValidIdentifier = /^(?:[A-Za-zıȷ\u0391-\u03C9\u03D5\u210B\u210F\u2110\u2112\u2113\u211B\u212C\u2130\u2131\u2133]|(?:\uD835[\uDC00-\udc33\udc9c-\udcb5]))[A-Za-z0-9_\u0391-\u03C9\u03D5\u0300-\u0308\u030A\u030C\u0332\u20d0\u20d1\u20d6\u20d7\u20e1]*′*$/; -const keywordRegEx = /^(if|elseif|else|return|throw|while|for|break|print|end)(\u2002|\b)/; -const drawCommandRegEx = /^(title|frame|view|axes|grid|stroke|strokewidth|strokedasharray|fill|fontsize|fontweight|fontstyle|fontfamily|marker|line|path|plot|curve|rect|circle|ellipse|arc|text|dot|leader|dimension)\b/; -const leadingSpaceRegEx = /^[\t ]+/; -const oneLinerRegEx = /^( *)if ([^\n`]+) +(return|throw|print|break)\b([^\n]+)?(?: end)? *\n/gm; - -// If you change functionRegEx, then also change it in mathprompt.js. -// It isn't called from there in order to avoid duplicating Hurmet code inside ProseMirror.js. -const functionRegEx = /^function (?:[A-Za-zıȷ\u0391-\u03C9\u03D5\u210B\u210F\u2110\u2112\u2113\u211B\u212C\u2130\u2131\u2133]|(?:\uD835[\uDC00-\udc33\udc9c-\udcb5]))[A-Za-z0-9_\u0391-\u03C9\u03D5\u0300-\u0308\u030A\u030C\u0332\u20d0\u20d1\u20d6\u20d7\u20e1]*′*\(/; -const moduleRegEx = /^module ([A-Za-z][A-Za-z0-9]*)/; -const drawRegEx = /^draw\(/; -const startSvgRegEx = /^startSvg\(\)/; -const lexRegEx = /"[^"]*"|``.*|`[^`]*`|'[^']*'|#|[^"`'#]+/g; - -const testForStatement = str => { - const pos = str.indexOf("="); - if (pos === -1) { return false } - const leadStr = str.slice(0, pos).replace(leadingSpaceRegEx, "").trim(); - if (isValidIdentifier.test(leadStr)) { return true } - if (leadStr.indexOf(",") === -1) { return false } - let result = true; - const arry = leadStr.split(","); - arry.forEach(e => { - if (!isValidIdentifier.test(e.trim())) { result = false; } - }); - return result -}; - -const stripComment = str => { - // Strip the comment, if any, from the end of a code line. - const matches = arrayOfRegExMatches(lexRegEx, str); - for (let i = 0; i < matches.length; i++) { - if (matches[i].value === "#") { - str = str.slice(0, matches[i].index); - break - } - } - return str.trim() -}; - -const scanModule = (str, decimalFormat) => { - // Scan the code and break it down into individual lines of code. - // Assemble the lines into functions and assign each function to parent. - const parent = Object.create(null); - - // Expand one-liners into if ... end blocks. - str = str.replace(oneLinerRegEx, "$1if\u2002$2\n$1 $3\u2002$4\n$1end\n"); - - // Statements end at a newline. - const lines = str.split(/\r?\n/g); - - for (let i = 0; i < lines.length; i++) { - // Get a single line of code and strip off any comments. - const line = stripComment(lines[i]); - if (line.length === 0) { continue } - - if (functionRegEx.test(line) || drawRegEx.test(line)) { - // This line starts a new function. - const [funcObj, endLineNum] = scanFunction(lines, decimalFormat, i); - if (funcObj.dtype && funcObj.dtype === dt.ERROR) { return funcObj } - parent[funcObj.name] = funcObj; - i = endLineNum; - } else if (testForStatement(line)) { - // This line starts a Hurmet assignment. - const [stmt, endLineNum] = scanAssignment(lines, decimalFormat, i); - parent[stmt.name] = stmt; - i = endLineNum; - } - } - return { value: parent, unit: null, dtype: dt.MODULE } - -}; - -const handleTSV = (expression, lines, startLineNum) => { - for (let i = startLineNum + 1; i < lines.length; i++) { - const line = tablessTrim(lines[i]); - if (line.length === 0) { continue } - expression += "\n" + line; - if (line.slice(-2) === "``") { return [expression, i] } - } -}; - -const scanFunction = (lines, decimalFormat, startLineNum) => { - const line1 = stripComment(lines[startLineNum]); - let isDraw = line1.charAt(0) === "d"; - const posParen = line1.indexOf("("); - let functionName = ""; - if (isDraw) { - functionName = "draw"; - } else { - const posFn = line1.indexOf("function"); - functionName = line1.slice(posFn + 8, posParen).trim(); - } - - const parameterString = line1.slice(posParen + 1, -1).trim(); - const parameterSplit = parameterString.length === 0 ? [] : parameterString.split(/ *[,;] */g); - const parameters = []; - for (const param of parameterSplit) { - const parts = param.split(/ *= */); - const name = parts[0]; - let defaultVal = { name, value: null, dtype: null }; - if (parts[1]) { - const [value, unit, dtype, resultDisplay] = valueFromLiteral(parts[1], "", decimalFormat); - defaultVal = { name, value, unit, dtype, resultDisplay }; - } - parameters.push({ name, default: defaultVal }); - } - - const funcObj = { - name: functionName, - dtype: isDraw ? dt.DRAWING : dt.MODULE, - parameters, - statements: [] - }; - - const stackOfCtrls = []; - let expression = ""; - let prevLineEndedInContinuation = false; - let prevLine = ""; - let name = ""; - let isStatement = false; - - let j = startLineNum; - for (let i = startLineNum + 1; i < lines.length; i++) { - j += 1; - let line = stripComment(lines[i]); - if (line.length === 0) { continue } - - if (prevLineEndedInContinuation) { - // Check if the previous character is a semi-colon just before a matrix literal closes. - const lastChar = prevLine.slice(-1); - line = lastChar === ";" && "})]".indexOf(line.charAt(0)) > -1 - ? prevLine.slice(0, -1).trim() + line - : lastChar === ";" || lastChar === "," - ? prevLine + " " + line - : prevLine + line; - } - - // Line continuation characters are: { ( [ , ; + - - if (/[{([,;]$/.test(line)) { - prevLineEndedInContinuation = true; - prevLine = line; - continue - } else if (lines.length > i + 1 && /^\s*[+\-)\]}]/.test(lines[i + 1])) { - prevLineEndedInContinuation = true; - prevLine = line; - continue - } - - let isFromOneLiner = false; - const keyword = keywordRegEx.exec(line); - if (keyword) { - name = keyword[1]; - if (keyword[2]) { isFromOneLiner = true; } - expression = line.slice(name.length).trim(); - if (expression.length > 0 && /^``/.test(expression)) { - [expression, i] = handleTSV(expression, lines, i); - } - } else if (isDraw && drawCommandRegEx.test(line)) { - name = "svg"; - expression = line.indexOf(" ") === -1 - ? line + "(svg)" - : line.replace(" ", "(svg, ") + ")"; - isStatement = true; - } else { - if (testForStatement(line)) { - // We have an "=" assignment operator. - const posEq = line.indexOf("="); - name = line.slice(0, posEq - 1).trim(); - expression = line.slice(posEq + 1).trim(); - if (/^``/.test(expression)) { [expression, i] = handleTSV(expression, lines, i); } - if (startSvgRegEx.test(expression)) { isDraw = true; } - isStatement = true; - } else { - // TODO: We shouldn't get here. Write an error. - return [errorOprnd("FUNC_LINE", functionName + ", line " + (j + 1) + "\n" + line), i] - } - } - if (isFromOneLiner) { j -= 1; } - let rpn = ""; - let _; - if (expression) { - [, rpn, _] = parse$1(expression, decimalFormat, true); - if (name === "for") { rpn = rpn.replace(/\u00a0in\u00a0/, "\u00a0"); } - } - const stype = isStatement ? "statement" : name; - if (isStatement && /[,;]/.test(name)) { - name = name.split(/[,;]/).map(e => e.trim()); - } - funcObj.statements.push({ name, rpn, stype }); - if (stype === "if" || stype === "while" || stype === "for") { - stackOfCtrls.push({ type: stype, statementNum: funcObj.statements.length - 1 }); - } else if (stype === "end") { - if (stackOfCtrls.length === 0) { - // Finished the current function. - if (isDraw) { - funcObj.statements.splice(-1, 0, { name: "return", rpn: "¿svg", stype: "return" }); - } - return [funcObj, i] - } - const ctrl = stackOfCtrls[stackOfCtrls.length - 1]; - funcObj.statements[ctrl.statementNum].endOfBlock = funcObj.statements.length - 1; - stackOfCtrls.pop(); - } - - // Reset for next statement - isStatement = false; - prevLineEndedInContinuation = false; - prevLine = ""; - name = ""; - expression = ""; - } - return [errorOprnd("END_MISS", functionName), 0] -}; - -const scanAssignment = (lines, decimalFormat, iStart) => { - let prevLineEndedInContinuation = false; - let str = ""; - let iEnd = iStart; - for (let i = iStart; i < lines.length; i++) { - const line = stripComment(lines[i]); - if (line.length === 0) { continue } - - if (prevLineEndedInContinuation) { - // Check if the previous character is a semi-colon just before a matrix literal closes. - str = str.slice(-1) === ";" && "})]".indexOf(line.charAt(0)) > -1 - ? str.slice(0, -1).trim() + line - : str + line; - } else { - str = line; - } - - // Line continuation characters are: { ( [ , ; + - - if (/[{([,;]$/.test(str)) { - prevLineEndedInContinuation = true; - } else if (lines.length > i + 1 && /^\s*[+\-)\]}]/.test(lines[i + 1])) { - prevLineEndedInContinuation = true; - } else { - iEnd = i; - break - } - } - - const posEquals = str.indexOf("="); - let name = str.slice(0, posEquals).trim(); - if (/[,;]/.test(name)) { - name = name.split(/[,;]/).map(e => e.trim()); - } - let trailStr = str.slice(posEquals + 1).trim(); - if (trailStr.length > 3 && trailStr.slice(0, 3) === '"""') { - // We're at a macro, which extends beyond normal line endings. - let j = iEnd; - let pos = trailStr.indexOf('"""', 3); - while (pos < 0 && j < lines.length - 1) { - j += 1; - trailStr += "\n" + lines[j]; - pos = trailStr.indexOf('"""', 3); - } - iEnd = j; - } - const [value, unit, dtype, resultDisplay] = valueFromLiteral(trailStr, name, decimalFormat); - const stmt = { name, value, unit, dtype, resultDisplay }; - return [stmt, iEnd] -}; - -/* compile.js - * - * This module is called when: (1) an author submits a Hurmet calculation dialog box, or - * (2) when a new document is opened, or (3) when recalculate-all is called. - * Here we do some preparation in a calculation cell prior to calculation. - * - * This module does NOT calculate the result of an expression. It stops just short of that. - * How do we choose where to draw the line between tasks done here and tasks done later? - * We do as much here as we can without knowing the values that other cells have assigned - * to variables. The goal is to minimize the amount of work done by each dependent cell - * when an author changes an assigned value. Later, calculation updates will not have to - * repeat the work done in this module, so updates will be faster. - * - * Variable inputStr contains the string that an author wrote into mathPrompt(). - * - * From that entry this module will: - * 1. Determine the name of the cell, as in "x" from "x = 12" - * 2. Parse the entry string into TeX, to be passed later to Temml for rendering. - * 3. If the input asks for a calculation: - * a. Parse the expression into an echo string (in TeX) with placeholders that will be - * filled in later with values when the calculation is done. - * b. Compile the expression into RPN (postfix) to be passed later to evaluateRPN(). - * c. Process the unit of measure, if any, of the result. Save it for later calculation. - * 4. If an assigned value is static, not dynamically calculated, find its value. - * 5. Append all the display strings together. - * 6. Return the result. Hurmet will attach it to ProseMirror "attrs" of that node. - */ - -const containsOperator = /[+\-×·*∘⌧/^%‰&√!¡|‖&=<>≟≠≤≥∈∉⋐∧∨⊻¬]|\xa0(function|mod|\\atop|root|sum|abs|cos|sin|tan|acos|asin|atan|sec|csc|cot|asec|acsc|acot|exp|log|ln|log10|log2|cosh|sinh|tanh|sech|csch|coth|acosh|asinh|atanh|asech|acsch|acoth|gamma|Γ|lgamma|logΓ|lfact|cosd|sind|tand|acosd|asind|atand|secd|cscd|cotd|asecd|acscd|acotd|real|imag|angle|Char|round|sqrt|sign|\?{}|%|⎾⏋|⎿⏌|\[\]|\(\))\xa0/; -const mustDoCalculation = /^(``.+``|[$$£¥\u20A0-\u20CF]?(\?{1,2}|@{1,2}|%{1,2}|!{1,2})[^=!(?@%!{})]*)$/; -const assignDataFrameRegEx = /^[^=]+=\s*``[\s\S]+`` *\n/; -const currencyRegEx = /^[$£¥\u20A0-\u20CF]/; -const matrixOfNames = /^[([](?:[A-Za-zıȷ\u0391-\u03C9\u03D5\u210B\u210F\u2110\u2112\u2113\u211B\u212C\u2130\u2131\u2133]|(?:\uD835[\uDC00-\udc33\udc9c-\udcb5]))[A-Za-z0-9_\u0391-\u03C9\u03D5\u0300-\u0308\u030A\u030C\u0332\u20d0\u20d1\u20d6\u20d7\u20e1]*′*[,;].+[)\]]$/; -const isKeyWord = /^(π|true|false|root|if|else|elseif|and|or|otherwise|mod|for|while|break|return|throw)$/; -const testRegEx = /^(@{1,2})test /; - -const shortcut = (str, decimalFormat) => { - // No calculation in str. Parse it just for presentation. - const tex = parse$1(str, decimalFormat); - return { entry: str, tex, alt: str } -}; - -const compile = (inputStr, decimalFormat = "1,000,000.") => { - let leadStr = ""; - let mainStr = ""; - let trailStr = ""; - let isCalc = false; - let suppressResultDisplay = false; - let displayResultOnly = false; - let omitEcho = false; - let mustAlign = false; - let posOfFirstEquals = 0; - let expression = ""; - let echo = ""; - let rpn = ""; - let dependencies = []; - let resultDisplay = ""; - let name = ""; - let leadsWithCurrency = false; - let value; - let unit; - let dtype; - let str = ""; - - const isModule = moduleRegEx.test(inputStr); - const isDraw = drawRegEx.test(inputStr); - if (functionRegEx.test(inputStr) || isDraw || isModule) { - // This cell contains a custom function. - let name = ""; - if (isDraw) { - name = "draw"; - } else if (isModule) { - name = moduleRegEx.exec(inputStr)[1].trim(); - } else if (!isModule) { - const posFn = inputStr.indexOf("function"); - const posParen = inputStr.indexOf("("); - name = inputStr.slice(posFn + 8, posParen).trim(); - } - const module = scanModule(inputStr, decimalFormat); - const isError = module.dtype && module.dtype === dt.ERROR; - if (isError) { - // eslint-disable-next-line no-alert - window.alert(module.value); - } - const attrs = { - entry: inputStr, - name, - value: (isError || isModule) ? module.value : module.value[name], - // TODO: what to do with comma decimals? - resultdisplay: "\\text{" + name + "}", - dtype: isError ? dt.ERROR : name === "draw" ? dt.DRAWING : dt.MODULE, - error: isError - }; - return attrs - } - - str = inputStr; - - if (testRegEx.test(inputStr)) { - str = str.replace(testRegEx, "").trim(); - const [_, rpn, dependencies] = parse$1(str, decimalFormat, true); - const resulttemplate = testRegEx.exec(inputStr)[1]; - return { entry: inputStr, template: "", rpn, dependencies, resulttemplate, - altresulttemplate: resulttemplate, resultdisplay: "" } - } - - const isDataFrameAssigment = assignDataFrameRegEx.test(str); - const posOfLastEquals = isDataFrameAssigment - ? str.indexOf("=") + 1 - : str.lastIndexOf("=") + 1; - - if (posOfLastEquals > 1) { - // input has form: mainStr = trailStr - mainStr = str.substring(0, posOfLastEquals - 1).replace(/ +$/, ""); - if (mainStr.length > 0 && /;\s*$/.test(mainStr)) { - mustAlign = true; - mainStr = mainStr.replace(/;\s*$/, ""); - } - mainStr = mainStr.trim(); - trailStr = str.substring(posOfLastEquals).trim(); - - if (mustDoCalculation.test(trailStr)) { - // trailStr contains a ? or a @ or a % or a !. In other words, - // input has form: mainStr = something [?@%!] something - // The [?@%!] signals that the author wants a calculation done. - isCalc = true; - - // A ! tells us to calculate and save the result, but to NOT display the result. - suppressResultDisplay = trailStr.indexOf("!") > -1; - - // A @ tells us to display only the result. - displayResultOnly = trailStr.indexOf("@") > -1; - - omitEcho = trailStr.indexOf("%") > -1; - - posOfFirstEquals = mainStr.indexOf("=") + 1; - if (posOfFirstEquals) { - // input has form: leadStr = something = trailStr - leadStr = mainStr.slice(0, posOfFirstEquals - 1).trim(); - - // Input has form: name = expression = trailStr, or - // name1, name2, = expression = trailStr - expression = mainStr.substring(posOfFirstEquals).trim(); - if (matrixOfNames.test(leadStr)) { leadStr = leadStr.slice(1, -1).trim(); } - if (/[,;]/.test(leadStr)) { - const potentialIdentifiers = leadStr.split(/[,;]/); - for (let i = 0; i < potentialIdentifiers.length; i++) { - const candidate = potentialIdentifiers[i].trim(); - if (isKeyWord.test(candidate) || !isValidIdentifier$1.test(candidate)) { - // leadStr is not a list of valid identifiers. - // So this isn't a valid calculation statement. Let's finish early. - return shortcut(str, decimalFormat) - } - } - // multiple assignment. - name = potentialIdentifiers.map(e => e.trim()); - - } else { - if (isValidIdentifier$1.test(leadStr) && !isKeyWord.test(leadStr)) { - name = leadStr; - } else { - // The "=" sign is inside an expression. There is no lead identifier. - // This statement does not assign a value to a variable. But it may do a calc. - // input has form: expression = trailStr - expression = mainStr; - } - } - } else { - // This calculation string contains only one "=" character. - // input has form: expression = trailStr - expression = mainStr; - } - } else if (isDataFrameAssigment) { - name = mainStr; - expression = trailStr; - } else if (isValidIdentifier$1.test(mainStr) && !isKeyWord.test(mainStr)) { - // No calculation display selector is present, - // but there is one "=" and a valid idendtifier. - // It may be an assignment statement. - // input has form: name = trailStr - name = mainStr; - if (trailStr === "") { - const tex = parse$1(str, decimalFormat); - return { entry: str, tex, alt: str } - } - } else { - // input has form: mainStr = trailStr. - // It almost works as an assignment statment, but mainStr is not a valid identifier. - // So we'll finish early. - return shortcut(str, decimalFormat) - } - } else { - // str contains no "=" character. Let's fnish early. - return shortcut(str, decimalFormat) - } - - if (expression.length > 0) { - // The author may want a calculation done on the expression. - if (/^\s*fetch\(/.test(expression)) { - // fetch() functions are handled in updateCalculations.js, not here. - // It's easier from there to send a fetch() callback to a ProseMirror transaction. - echo = ""; - - } else { - // Parse the expression. Stop short of doing the calculation. - [echo, rpn, dependencies] = parse$1(expression, decimalFormat, true); - - // Shoulld we display an echo of the expression, with values shown for each variable? - if (suppressResultDisplay || displayResultOnly || echo.indexOf("〖") === -1 - || /\u00a0for\u00a0/.test(rpn)) { - // No. - echo = ""; - } else if (omitEcho) { - echo = ""; - } else { - // The expression calls a variable. - // If it also contains an operator or a function, then we need to show the echo. - if (containsOperator.test("\xa0" + rpn + "\xa0")) { - echo = "\\textcolor{#0000ff}{" + echo + "}"; - } else { - echo = ""; - } - } - } - } - - // Now let's turn our attention from the expression to the trailStr. - if (currencyRegEx.test(trailStr)) { - leadsWithCurrency = true; - unit = trailStr.charAt(0); - } - - if (isCalc) { - // trailStr contains a display selector. - value = null; - - if (!leadsWithCurrency) { - // Check for a unit, even if it isn't a unit-aware calculation - unit = trailStr.replace(/[?@%!']/g, "").trim(); - } - - if (suppressResultDisplay) { - resultDisplay = trailStr; - } else { - if (unit) { - resultDisplay = trailStr.trim().replace(/([^ ?!@%]+)$/, "'" + "$1" + "'"); - resultDisplay = parse$1(resultDisplay, decimalFormat).replace(/\\%/g, "%").replace("@ @", "@@"); - } else { - resultDisplay = parse$1(trailStr, decimalFormat).replace(/\\%/g, "%").replace("@ @", "@@"); - } - resultDisplay = resultDisplay.replace(/\\text\{(\?\??|%%?)\}/, "$1"); - resultDisplay = resultDisplay.replace(/([?%]) ([?%])/, "$1" + "$2"); - } - - } else { - // trailStr may be a static value in an assignment statement. - // Check if trailStr is a valid literal. - [value, unit, dtype, resultDisplay] = valueFromLiteral(trailStr, name, decimalFormat); - - if (dtype === dt.ERROR) { return shortcut(str, decimalFormat) } - rpn = ""; - } - - // Assemble the equation to display - let eqn = ""; - let altEqn = ""; - if (!displayResultOnly) { - eqn = parse$1(mainStr, decimalFormat); - if (mustAlign) { - eqn = "\\begin{aligned}" + eqn; - const pos = eqn.indexOf("="); - eqn = eqn.slice(0, pos) + "&" + eqn.slice(pos); - } - const alignChar = mustAlign ? "\\\\ &" : ""; - altEqn = mainStr; - if (echo.length > 0 && !omitEcho) { - eqn += ` ${alignChar}= ` + echo; - } - if (!suppressResultDisplay) { - eqn += " " + (mustAlign ? "\\\\&" : "") + "= " + resultDisplay; - altEqn += " = " + trailStr; - } - if (mustAlign) { eqn += "\\end{aligned}"; } - } - - // Populate the object to be returned. - // It will eventually be attached to ProseMirror schema attrs, so call it "attrs". - const attrs = { - entry: str, - template: eqn, - altTemplate: altEqn, - resultdisplay: resultDisplay, - dtype: dtype, - error: false - }; - - if (name) { attrs.name = name; } - if (isCalc) { - attrs.resulttemplate = resultDisplay; - attrs.altresulttemplate = trailStr; - } else { - attrs.tex = eqn; - attrs.alt = altEqn; - } - if (rpn) { attrs.rpn = rpn; } - if (dependencies.length > 0) { attrs.dependencies = dependencies; } - if (value) { attrs.value = value; } - if (unit) { - if (rpn && !attrs.value) { - attrs.unit = typeof unit === "string" - ? unitFromUnitName(unit) - : { factor: 1, gauge: 0, expos: allZeros }; - } else { - attrs.unit = Array.isArray(unit) ? { expos: unit } : unit; - } - } - - return attrs -}; - -// This function is not used by the hurmet.org page. -// It is provided for use by unit tests and by the demo box in the manual page. -// If you are looking for the app's main calculation module, try evaluate.js. -const calculate = ( - entry, - vars = {}, - inDraftMode = false, - decimalFormat = "1,000,000." -) => { - let attrs = compile(entry, decimalFormat); - if (attrs.rpn) { - attrs = evaluate(clone(attrs), vars, decimalFormat); - } else if (attrs.dtype && attrs.dtype === dt.DRAWING) { - attrs = evaluateDrawing(attrs, vars, decimalFormat); - } - if (attrs.name) { - insertOneHurmetVar(vars, attrs); - } - return attrs.dtype && attrs.dtype === dt.DRAWING - ? attrs - : inDraftMode - ? attrs.alt - : attrs.tex -}; - -/* - * This module organizes one or two passes through the data structure of a Hurmet - * document, calling for a calculation to be done on each Hurmet calculation cell. - * If you are looking for the calculation itself, look at evaluate.js. - * - * To be more precise, this module is called: - * 1. When an author submits one calculation cell, or - * 2. When a new Hurmet.org instance has opened (from index.js), or - * 3. When a user has opened a new file (from openFile.js), or - * 4. When a recalculate-all has been called, possibly after a paste. (from menu.js) - * - * Case 1 calculates the submitted cell and all dependent calculation cells. - * Cases 2 thru 4 re-calculate the entire document. I.e., isCalcAll is set to true. - * After calculation is complete, we send the results to ProseMirror to be - * rendered in the document. - * - * This module's main exported function is updateCalculations(…) - */ - -/* -* Note 1: state.selection shenanigans -* -* Before creating a ProseMirror (PM) transaction, this module first changes `state.selection`. -* That is to say, I change the PM state without running that change thru a PM transaction. -* PM docs advise against that, so I want to explain why I do so. -* -* For Undo purposes, a calculation should be atomic. -* An Undo of a calculation should return the doc to the condition before the -* calculation cell was edited. That will feel natural to people accustomed to Excel. -* When a calculation is submitted, Hurmet creates a single PM transaction and into it, -* Hurmet collects all the changes that the calculation makes to the original cell and -* also all the changes to dependent cells. -* When a user submits a calculation, the cell is open, so a PM Undo would ordinarily return -* the state to a condition that once again has the cell open. -* -* But now consider a user who wants to Undo twice. The first Undo retreats to a condition in -* which a cell is open. The user thinks a second Undo will change the PM document. But no! -* Because the cell is open, the CodeMirror plain text editor is active and the Undo is captured -* by CodeMirror. An Undo affects CodeMirror but not the outer document. It's very confusing! -* So the Undo should return to a condition in which the cell is closed. That's why I change -* the PM state.selection object _before_ I create the PM transaction. I don't want an Undo to -* open that cell and so I don't want the Undo to finish with the selection point inside the -* cell. Before creating the transaction, I move the selection point to just after the cell. -*/ - -const fetchRegEx = /^(?:[A-Za-zıȷ\u0391-\u03C9\u03D5\u210B\u210F\u2110\u2112\u2113\u211B\u212C\u2130\u2131\u2133]|(?:\uD835[\uDC00-\udc33\udc9c-\udcb5]))[A-Za-z0-9_\u0391-\u03C9\u03D5\u0300-\u0308\u030A\u030C\u0332\u20d0\u20d1\u20d6\u20d7\u20e1]*′* *= *(?:fetch|import)\(/; -const importRegEx = /^[^=]+= *import/; -const fileErrorRegEx = /^Error while reading file. Status Code: \d*$/; -const textRegEx = /\\text{[^}]+}/; - -const urlFromEntry = entry => { - // Get the URL from the entry input string. - const str = entry.replace(/^[^()]+\("?/, ""); - return str.replace(/"?\).*$/, "").trim() -}; - -// Helper function. -const processFetchedString = (entry, text, hurmetVars, decimalFormat) => { - const attrs = Object.create(null); - attrs.entry = entry; - attrs.name = entry.replace(/=.+$/, "").trim(); - let str = parse$1(entry.replace(/\s*=\s*[$$£¥\u20A0-\u20CF]?(?:!{1,2}).*$/, ""), decimalFormat); - const url = urlFromEntry(entry); - if (/\.(?:tsv|txt)$/.test(url)) { - // Shorten the URL. - const fileName = url.replace(/.+\//, ""); - const match = textRegEx.exec(str); - str = str.slice(0, match.index) + "\\text{" + addTextEscapes(fileName) + "})"; - } - attrs.tex = str; - attrs.alt = entry; - if (text === "File not found." || fileErrorRegEx.test(text)) { - attrs.dtype = dt.ERROR; - attrs.tex += ` = \\red{\\text{${text}}}`; - attrs.alt = " = " + text; - attrs.value = null; - return attrs - } - const data = importRegEx.test(entry) - ? scanModule(text, decimalFormat) // import code - : DataFrame.dataFrameFromTSV(text); // fetch data - - // Append the data to attrs - attrs.value = data.value; - attrs.dtype = data.dtype; - attrs.unit = data.unit; - attrs.isFetch = true; - attrs.fallback = data.dtype === dt.MODULE ? text : ""; - if (data.dtype === dt.MODULE && /^importedParameters *=/.test(entry)) { - // Assign to multiple variables, not one namespace. - let nameTex = "\\begin{matrix}"; - let i = 0; - Object.entries(data.value).forEach(([key, value]) => { - hurmetVars[key] = value; - nameTex += parse$1(value.name) + " & "; - i += 1; - if (i === 5) { - nameTex = nameTex.slice(0, -1) + "\\\\ "; - i = 0; - } - }); - nameTex = nameTex.slice(0, (i === 0 ? -2 : -1)) + "\\end{matrix}"; - attrs.tex = attrs.tex.replace("\\mathrm{importedParameters}", nameTex); - } - return attrs -}; - -const mustCalc = (attrs, hurmetVars, changedVars, isCalcAll, isFormat) => { - if (isCalcAll || isFormat) { return true } - if (attrs.rpn && !(attrs.name && hurmetVars[attrs.name] && hurmetVars[attrs.name].isFetch)) { - for (const varName of attrs.dependencies) { - if (changedVars.has(varName)) { return true } - } - } - if (attrs.dtype && attrs.dtype === dt.DRAWING && attrs.value.parameters && - attrs.value.parameters.length > 0) { - for (const parameter of attrs.value.parameters) { - if (changedVars.has(parameter)) { return true } - } - } - return false -}; - -const workWithFetchedTexts = ( - view, - doc, - inDraftMode, - decimalFormat, - calcNodeSchema, - isCalcAll, - nodeAttrs, - curPos, - hurmetVars, - fetchPositions, - texts -) => { - // At this point, we have the text of each Hurmet fetch and import. - // Create a ProseMirror transaction. - // Each node update below will be one step in the transaction. - const state = view.state; - if (state.selection.to === curPos + 1) { - // See Note 1 above for an explanation of the state.selection shenanigans. - state.selection = state.selection.constructor.near(state.doc.resolve(curPos + 1)); - } - const tr = state.tr; - - // Load in the data from the fetch statements - for (let i = 0; i < texts.length; i++) { - const pos = fetchPositions[i]; - const entry = isCalcAll - ? doc.nodeAt(pos).attrs.entry - : nodeAttrs.entry; - const attrs = processFetchedString(entry, texts[i], hurmetVars, decimalFormat); - attrs.inDraftMode = inDraftMode; - tr.replaceWith(pos, pos + 1, calcNodeSchema.createAndFill(attrs)); - if (attrs.name) { - insertOneHurmetVar(hurmetVars, attrs, null, decimalFormat); - } - } - // There. Fetches are done and are loaded into the document. - // Now proceed to the rest of the work. - proceedAfterFetch(view, calcNodeSchema, isCalcAll, nodeAttrs, curPos, hurmetVars, tr); - -}; - -const workAsync = ( - view, - calcNodeSchema, - isCalcAll, - nodeAttrs, - curPos, - hurmetVars, - urls, - fetchPositions -) => { - - // Here we fetch the remote data. - const doc = view.state.doc; - const inDraftMode = doc.attrs.inDraftMode; - const decimalFormat = doc.attrs.decimalFormat; - - if (!navigator.onLine) { - const texts = []; - for (const url of urls) { - Object.keys(doc.attrs.fallbacks).forEach(function(key) { - if (doc.attrs.fallbacks[key].url === url) { - texts.push(doc.attrs.fallbacks[key].text); - } - }); - } - workWithFetchedTexts(view, doc, inDraftMode, decimalFormat, calcNodeSchema, isCalcAll, - nodeAttrs, curPos, hurmetVars, fetchPositions, texts); - } else { - Promise.all( - urls.map(url => fetch(url, { - method: "GET", - headers: { "Content-Type": "text/plain;charset=UTF-8" }, - mode: "cors" - })) - ).then(fetchResponses => { - // The fetch promises have resolved. Now we extract their text. - return Promise.all(fetchResponses.map(r => { - if (r.status !== 200 && r.status !== 0) { - // The fetch failed. Try for a fallback. - Object.keys(doc.attrs.fallbacks).forEach(function(key) { - if (doc.attrs.fallbacks[key].url === r.url) { - return doc.attrs.fallbacks[key].text - } - }); - return r.status === 404 - ? 'File not found.' - : 'Error while reading file. Status Code: ' + r.status - } - return r.text() - })) - }).then((texts) => { - workWithFetchedTexts(view, doc, inDraftMode, decimalFormat, calcNodeSchema, isCalcAll, - nodeAttrs, curPos, hurmetVars, fetchPositions, texts); - }); - } -}; - -const proceedAfterFetch = ( - view, - calcNodeSchema, - isCalcAll, - nodeAttrs, - curPos, - hurmetVars, - tr -) => { - // This function happens either - // 1. After remote, fetched data has been processed, or - // 2. After we know that no fetch statements need be processed. - const doc = view.state.doc; - const decimalFormat = doc.attrs.decimalFormat; - // Create a set to track which variable have a changed value. - const changedVars = isCalcAll ? null : new Set(); - - if (!isCalcAll && (nodeAttrs.name || nodeAttrs.rpn || - (nodeAttrs.dtype && nodeAttrs.dtype === dt.DRAWING))) { - // Load hurmetVars with values from earlier in the document. - doc.nodesBetween(0, curPos, function(node) { - if (node.type.name === "calculation") { - const attrs = node.attrs; - if (attrs.name) { - if (attrs.name === "importedParameters") { - Object.entries(attrs.value).forEach(([key, value]) => { - hurmetVars[key] = value; - }); - } else { - insertOneHurmetVar(hurmetVars, attrs, null, decimalFormat); - } - } - } - }); - - // Hoist any user-defined functions located below the selection. - doc.nodesBetween(curPos + 1, doc.content.size, function(node, pos) { - if (node.type.name === "calculation" && node.attrs.dtype === dt.MODULE) { - insertOneHurmetVar(hurmetVars, node.attrs, null, decimalFormat); - } - }); - - // Calculate the current node. - if (!fetchRegEx.test(nodeAttrs.entry)) { - // This is the typical calculation statement. We'll evalutate it. - let attrs = clone(nodeAttrs); // compile was already run in mathprompt.js. - // The mathPrompt dialog box did not have accesss to hurmetVars, so it - // did not do unit conversions on the result template. Do that first. - try { - // Proceed to do the calculation of the cell. - if (attrs.rpn || (nodeAttrs.dtype && nodeAttrs.dtype === dt.DRAWING)) { - attrs = attrs.dtype && attrs.dtype === dt.DRAWING - ? evaluateDrawing(attrs, hurmetVars, decimalFormat) - : evaluate(attrs, hurmetVars, decimalFormat); - } - if (attrs.name) { insertOneHurmetVar(hurmetVars, attrs, changedVars, decimalFormat); } - //attrs.displayMode = nodeAttrs.displayMode - } catch (err) { - attrs.tex = "\\text{" + attrs.entry + " = " + err + "}"; - } - tr.replaceWith(curPos, curPos + 1, calcNodeSchema.createAndFill(attrs)); - } - } - - // Finally, update calculations after startPos. - const startPos = isCalcAll ? 0 : (curPos + 1); - const isFormat = (nodeAttrs && nodeAttrs.name && nodeAttrs.name === "format"); - doc.nodesBetween(startPos, doc.content.size, function(node, pos) { - if (node.type.name === "calculation") { - const notFetched = isCalcAll ? !fetchRegEx.test(node.attrs.entry) : !node.attrs.isFetch; - if (notFetched) { - const entry = node.attrs.entry; - let attrs = isCalcAll - ? compile(entry, decimalFormat) - : clone(node.attrs); - attrs.displayMode = node.attrs.displayMode; - const mustRedraw = attrs.dtype && attrs.dtype === dt.DRAWING && - (attrs.rpn || (attrs.value.parameters.length > 0 || isCalcAll)); - if (mustCalc(attrs, hurmetVars, changedVars, isCalcAll, isFormat)) { - try { - if (attrs.rpn || mustRedraw) { - attrs.error = false; - attrs = attrs.rpn // attrs.dtype && attrs.dtype === dt.DRAWING - ? evaluate(attrs, hurmetVars, decimalFormat) - : evaluateDrawing(attrs, hurmetVars, decimalFormat); - } - if (attrs.name) { - insertOneHurmetVar(hurmetVars, attrs, changedVars, decimalFormat); - } - } catch (err) { - attrs.tex = "\\text{" + attrs.entry + " = " + err + "}"; - } - if (isCalcAll || attrs.rpn || mustRedraw) { - tr.replaceWith(pos, pos + 1, calcNodeSchema.createAndFill(attrs)); - } - } else if (attrs.name && attrs.value) { - insertOneHurmetVar(hurmetVars, attrs, null, decimalFormat); - } - } else if (node.attrs.name && !(isCalcAll && node.attrs.isFetch)) { - if (node.attrs.name) { - if (node.attrs.name === "importedParameters") { - Object.entries(node.attrs.value).forEach(([key, value]) => { - hurmetVars[key] = value; - }); - } else { - insertOneHurmetVar(hurmetVars, node.attrs, null, decimalFormat); - } - } - } - } - }); - - // All the steps are now loaded into the transaction. - // Dispatch the transaction to ProseMirror, which will re-render the document. - if (!isCalcAll) { - tr.setSelection(view.state.selection.constructor.near(tr.doc.resolve(curPos + 1))); - } - view.dispatch(tr); - view.focus(); -}; - -function updateCalculations( - view, - calcNodeSchema, - isCalcAll = false, - nodeAttrs, - curPos -) { - const doc = view.state.doc; - - if (!(isCalcAll || nodeAttrs.name || nodeAttrs.rpn || - (nodeAttrs.dtype && nodeAttrs.dtype === dt.DRAWING))) { - // No calculation is required. Just render the node and get out. - const state = view.state; - if (state.selection.to === curPos + 1) { - // See Note 1 above for an explanation of the state.selection shenanigans. - state.selection = state.selection.constructor.near(state.doc.resolve(curPos + 1)); - } - const tr = state.tr; - try { - tr.replaceWith(curPos, curPos + 1, calcNodeSchema.createAndFill(nodeAttrs)); - } catch (err) { - // nada - } finally { - view.dispatch(tr); - view.focus(); - } - return - } - - // Create an object in which we'll hold variable values. - const hurmetVars = Object.create(null); - hurmetVars.format = { value: "h15" }; // default rounding format - - // Get an array of all the URLs called by fetch statements. - const urls = []; - const fetchPositions = []; - if (!isCalcAll) { - // The author has submitted a single calculation cell. - const entry = nodeAttrs.entry; - if (fetchRegEx.test(entry)) { - urls.push(urlFromEntry(entry)); - fetchPositions.push(curPos); - } - } else { - // We're updating the entire document. - doc.nodesBetween(0, doc.content.size, function(node, pos) { - if (node.type.name === "calculation" && !node.attrs.value) { - const entry = node.attrs.entry; - if (fetchRegEx.test(entry)) { - urls.push(urlFromEntry(entry)); - fetchPositions.push(pos); - } else if (/^function /.test(entry)) { - node.attrs = compile(entry, doc.attrs.decimalFormat); - insertOneHurmetVar(hurmetVars, node.attrs, null, doc.attrs.decimalFormat); - } - } else if (node.attrs.isFetch || (node.attrs.dtype && node.attrs.dtype === dt.MODULE)) { - insertOneHurmetVar(hurmetVars, node.attrs, null, doc.attrs.decimalFormat); - } - }); - } - - if (urls.length > 0) { - // We have to fetch some remote data. Asynchronous work ahead. - workAsync(view, calcNodeSchema, isCalcAll, nodeAttrs, curPos, - hurmetVars, urls, fetchPositions); - } else { - // Skip the fetches and go directly to work that we can do synchronously. - const state = view.state; - if (state.selection.to === curPos + 1) { - // See Note 1 above for an explanation of the state.selection shenanigans. - state.selection = state.selection.constructor.near(state.doc.resolve(curPos + 1)); - } - const tr = state.tr; - proceedAfterFetch(view, calcNodeSchema, isCalcAll, nodeAttrs, curPos, hurmetVars, tr); - } -} - -const helpers = Object.freeze({ - fetchRegEx, - textRegEx, - urlFromEntry, - processFetchedString -}); - -async function fetchTexts(urls) { - // Here we fetch remote data. - return Promise.all( - urls.map(url => fetch(url, { - method: "GET", - headers: { "Content-Type": "text/plain;charset=UTF-8" }, - mode: "cors" - })) - ).then(fetchResponses => { - // The fetch promises have resolved. Now we extract their text. - return Promise.all(fetchResponses.map(r => { - if (r.status !== 200 && r.status !== 0) { - return r.status === 404 - ? 'File not found.' - : 'Error while reading file. Status Code: ' + r.status - } - return r.text() - })) - }).then((texts) => { - // At this point, we have the text of each Hurmet fetch and import. - return texts - }) -} - -async function getRemoteTexts(urls) { - // This is necessary to return text, not just a promise of text. - return await fetchTexts(urls) -} - -const getCalcNodes = (ast, calcNodes) => { - // Create an array of calculation nodes. - if (Array.isArray(ast)) { - for (let i = 0; i < ast.length; i++) { - getCalcNodes(ast[i], calcNodes); - } - } else if (ast && ast.type === "calculation") { - calcNodes.push(ast); - // eslint-disable-next-line no-prototype-builtins - } else if (ast.hasOwnProperty("content")) { - for (let j = 0; j < ast.content.length; j++) { - getCalcNodes(ast.content[j], calcNodes); - } - } -}; - -async function updateCalcs(doc) { - // This function is a lot like what updateCalculations.js does for the Hurmet web site. - - // Create an object in which we'll hold variable values. - const hurmetVars = Object.create(null); - hurmetVars.format = { value: "h15" }; // default rounding format - const decimalFormat = doc.attrs ? doc.attrs.decimalFormat : '1,000,000.'; - - // Create an array of all the calculation nodes in the document - const calcNodes = []; - getCalcNodes(Array.isArray(doc) ? doc : doc.content, calcNodes); - if (calcNodes.length === 0) { return doc } - - // Get an array of all the URLs called by fetch statements. - const urls = []; - const callers = []; - for (const node of calcNodes) { - const entry = node.attrs.entry; - if (helpers.fetchRegEx.test(entry)) { - urls.push(helpers.urlFromEntry(entry)); - callers.push(node); - } else if (/^function /.test(entry)) { - node.attrs = compile(entry, decimalFormat); - insertOneHurmetVar(hurmetVars, node.attrs, null, decimalFormat); - } - } - - if (urls.length > 0) { - // We have to fetch some remote data. - const texts = await getRemoteTexts(urls); - // Fetches are now complete. Load in the data. - for (let i = 0; i < texts.length; i++) { - const node = callers[i]; - const entry = node.attrs.entry; - // When we modify a node, we are also mutating the container doc. - node.attrs = helpers.processFetchedString(entry, texts[i], hurmetVars, decimalFormat); - if (node.attrs.name) { - if (node.attrs.name === "importedParameters") { - Object.entries(node.attrs.value).forEach(([key, value]) => { - hurmetVars[key] = value; - }); - } else { - insertOneHurmetVar(hurmetVars, node.attrs, null, decimalFormat); - } - } - } - } - - // Fetches, if any, are now complete and loaded into hurmetVars. - // Make a pass through the calculation nodes and calculate each result. - try { - for (const node of calcNodes) { - if (!helpers.fetchRegEx.test(node.attrs.entry)) { - const entry = node.attrs.entry; - let attrs = compile(entry, decimalFormat); - attrs.displayMode = node.attrs.displayMode; - const mustDraw = attrs.dtype && attrs.dtype === dt.DRAWING; - if (attrs.rpn || mustDraw) { - attrs = attrs.rpn - ? evaluate(attrs, hurmetVars, decimalFormat) - : evaluateDrawing(attrs, hurmetVars, decimalFormat); - } - if (attrs.name) { insertOneHurmetVar(hurmetVars, attrs, null, decimalFormat); } - // When we modify a node, we are also mutating the container doc. - node.attrs = attrs; - } - } - return doc - } catch (err) { - console.log(err); // eslint-disable-line no-console - } -} - -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) { - const sanitizedAttribute = attr === "src" - ? attribute.replace(//g, "%3E") - : sanitizeText(attribute); - attributeString += " " + sanitizeText(attr) + '="' + sanitizedAttribute + '"'; - } - } - } - - const unclosedTag = "<" + tagName + attributeString + ">"; - - if (isClosed) { - if (content.charAt(content.length - 1) === "\n") { - content = content.slice(0, -1); - } - 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 quoteRegEx = /"/g; -const dataStr = str => { - if (str.indexOf("'") === -1) { - return `'${str}'` - } else if (str.indexOf('"') === -1) { - return `"${str}"` - } else { - return `"${str.replace(quoteRegEx, """)}"` - } -}; - -const writeSVG = dwg => { - let svg = ' { - svg += ` ${key}='${dwg.attrs[key]}'`; - }); - svg += ">\n"; - dwg.children.forEach(el => { - svg += `<${el.tag}`; - Object.keys(el.attrs).forEach(attr => { - if (el.tag !== "title") { - svg += ` ${attr}='${el.attrs[attr]}'`; - } - }); - svg += ">\n"; - if (el.tag === "text") { - el.children.forEach(child => { - svg += ' { - svg += ` ${mark}='${child.attrs[mark]}'`; - }); - } - svg += `>${sanitizeText(child.text)}`; - }); - } else if (el.tag === "defs") { - svg += ``; - } else if (el.tag === "title") { - svg += sanitizeText(el.attrs.text); - } - svg += `\n`; - }); - svg += ""; - return svg -}; - -const functionOrModuleRegEx = /^ *(?:function|module) /; - -const writeTOC = node => { - let toc = "
    \n"; - for (const item of node.attrs.body) { - let li = " 0) { li += ` style= 'margin-left: ${String(1.5 * item[1])}em'`; } - li += `>${item[0]}0\n`; - toc += li; - } - return toc + "
\n" -}; - -const headingText = content => { - let str = ""; - for (const node of content) { - if (node.type && node.type === "text") { - str += node.text; - } - } - return sanitizeText(str) -}; - -const headings = []; - -const nodes = { - html(node) { return node.text }, - heading(node) { - const text = headingText(node.content); - let tag = "h" + node.attrs.level; - tag = htmlTag(tag, text); - if (!headings.includes(text)) { - // Add an id so others can link to it. - tag = tag.slice(0, 3) + " id='" + text.toLowerCase().replace(/,/g, "").replace(/\s+/g, '-') + "'" + tag.slice(3); - headings.push(text); - } - return tag + "\n" - }, - paragraph(node) { return htmlTag("p", ast2html(node.content)) + "\n" }, - blockquote(node) { return htmlTag("blockquote", ast2html(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", ast2html(node.content), attributes) + "\n" - }, - bullet_list(node) { return htmlTag("ul", ast2html(node.content)) + "\n" }, - list_item(node) { return htmlTag("li", ast2html(node.content)) + "\n" }, - tight_list_item(node) { - return htmlTag("li", ast2html(node.content), { class: "tight" }) + "\n" - }, - table(node) { return htmlTag("table", ast2html(node.content), node.attrs) + "\n" }, - colGroup(node) { - return "\n" + htmlTag("colgroup", ast2html(node.content), node.attrs) + "\n" - }, - col(node) { return htmlTag("col", "", node.attrs[0], false) }, - table_row(node) { return htmlTag("tr", ast2html(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; } - return htmlTag("th", ast2html(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; } - return htmlTag("td", ast2html(node.content), attributes) - }, - link(node) { - const attributes = { href: sanitizeUrl(node.attrs.href), title: node.attrs.title }; - return htmlTag("a", ast2html(node.content), attributes); - }, - image(node) { - const attributes = { src: node.attrs.src }; - if (node.attrs.alt) { attributes.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); - }, - figure(node) { return htmlTag("figure", ast2html(node.content)) + "\n" }, - figcaption(node) { return htmlTag("figcaption", ast2html(node.content)) }, - figimg(node) { - const attributes = { src: node.attrs.src, class: "figimg" }; - if (node.attrs.alt) { attributes.alt = node.attrs.alt; } - if (node.attrs.id) { attributes.id = node.attrs.id; } - if (node.attrs.width) { attributes.width = node.attrs.width; } - return htmlTag("img", "", attributes, false) + "\n"; - }, - footnote(node) { return htmlTag("footnote", "") }, - calculation(node) { - if (node.attrs.dtype && node.attrs.dtype === dt.DRAWING) { - const svg = writeSVG(node.attrs.resultdisplay); - const style = svg.indexOf('float="right"' > -1) ? " style='float: right;'" : ""; - return `` + - `${svg}` - } else if (node.attrs.dtype && node.attrs.dtype === dt.MODULE && - functionOrModuleRegEx.test(node.attrs.entry)) { - return `` - + `${sanitizeText(node.attrs.entry)}` - } else { - const tex = node.attrs.tex ? node.attrs.tex : parse$1(node.attrs.entry); - // eslint-disable-next-line no-undef - const mathML = globalThis.temml.renderToString( - tex, - { trust: true, wrap: "=", displayMode: (node.attrs.displayMode || false) } - ); - const tag = node.attrs.displayMode ? "p" : "span"; - return `<${tag} class='hurmet-calc' data-entry=${dataStr(node.attrs.entry)}>` + - `${mathML}` - } - }, - tex(node) { - // eslint-disable-next-line no-undef - const mathML = globalThis.temml.renderToString( - node.attrs.tex, - { trust: true, displayMode: (node.attrs.displayMode || false) } - ); - const tag = node.attrs.displayMode ? "p" : "span"; - return `<${tag} class='hurmet-tex' data-entry=${dataStr(node.attrs.tex)}>` + - `${mathML}` - }, - indented(node) { - return htmlTag("div", ast2html(node.content), { class: 'indented' }) + "\n" - }, - boxed(node) { - return htmlTag("div", ast2html(node.content), { class: 'boxed' }) + "\n" - }, - centered(node) { - return htmlTag("div", ast2html(node.content), { class: 'centered' }) + "\n" - }, - right_justified(node) { - return htmlTag("div", ast2html(node.content), { class: 'right_justified' }) + "\n" - }, - hidden(node) { - return htmlTag("div", ast2html(node.content), { class: 'hidden' }) + "\n" - }, - epigraph(node) { - return htmlTag("blockquote", ast2html(node.content), { class: 'epigraph' }) + "\n" - }, - note(node) { - return htmlTag("div", ast2html(node.content), { class: 'note' }) + "\n" - }, - tip(node) { - return htmlTag("div", ast2html(node.content), { class: 'tip' }) + "\n" - }, - important(node) { - return htmlTag("div", ast2html(node.content), { class: 'important' }) + "\n" - }, - warning(node) { - return htmlTag("div", ast2html(node.content), { class: 'warning' }) + "\n" - }, - header(node) { - return htmlTag("header", ast2html(node.content)) + "\n" - }, - toc(node) { return writeTOC(node) }, - comment(node) { - return htmlTag("aside", ast2html(node.content), { class: 'comment' }) + "\n" - }, - dt(node) { - let text = ast2html(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", ast2html(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 getTOCitems = (ast, tocArray, start, end, node) => { - if (Array.isArray(ast)) { - for (let i = 0; i < ast.length; i++) { - getTOCitems(ast[i], tocArray, start, end, node); - } - } else if (ast && ast.type === "heading") { - const level = ast.attrs.level; - if (start <= level && level <= end) { - tocArray.push([headingText(ast.content), level - start]); - } - } else if (ast.type === "toc") { - node.push(ast); - // eslint-disable-next-line no-prototype-builtins - } else if (ast.hasOwnProperty("content")) { - for (let j = 0; j < ast.content.length; j++) { - getTOCitems(ast.content[j], tocArray, start, end, node); - } - } -}; - -const getFootnotes = (ast, footnotes) => { - if (Array.isArray(ast)) { - for (let i = 0; i < ast.length; i++) { - getFootnotes(ast[i], footnotes); - } - } else if (ast && ast.type === "footnote") { - footnotes.push(ast.content); - // eslint-disable-next-line no-prototype-builtins - } else if (ast.hasOwnProperty("content")) { - for (let j = 0; j < ast.content.length; j++) { - getFootnotes(ast.content[j], footnotes); - } - } -}; - -const ast2html = ast => { - // Return HTML. - let html = ""; - if (Array.isArray(ast)) { - for (let i = 0; i < ast.length; i++) { - html += ast2html(ast[i]); - } - } else if (ast && ast.type === "doc") { - html += ast2html(ast.content); - } else if (ast && ast.type !== "null") { - html += nodes[ast.type](ast); - } - return html -}; - -const wrapWithHead = (html, title, attrs) => { - title = title ? title : "Hurmet doc"; - const fontClass = attrs && attrs.fontSize - ? { "10": "long-primer", "12": "pica", "18": "great-primer" }[attrs.fontSize] - : "long-primer"; - const head = ` - - - - - ${title} - - - -
-
-`; - return head + html + "\n
\n\n" -}; - -async function md2html(md, title = "", inHtml = false) { - // Convert the Markdown to an AST that matches the Hurmet internal data structure. - let ast = md2ast(md, inHtml); - - // Populate a Table of Contents, if any exists. - const tocCapture = /\n *\n{\.toc start=(\d) end=(\d)}\n/.exec(md); - if (tocCapture) { - const start = Number(tocCapture[1]); - const end = Number(tocCapture[2]); - const tocArray = []; - const node = []; - getTOCitems(ast, tocArray, start, end, node); - node[0].attrs.body = tocArray; - } - - // Perform calculations - ast = await updateCalcs(ast); - - // Write the HTML - let html = ast2html(ast); - - // Write the footnotes, if any. - const footnotes = []; - getFootnotes(ast, footnotes); - if (footnotes.length > 0) { - html += "\n
\n
    \n"; - for (const footnote of footnotes) { - html += "
  1. " + ast2html(footnote) + "

  2. \n"; - } - html += "
\n"; - } - - if (title.length > 0) { - html = wrapWithHead(html, title, ast.attrs); - } - - return html -} - -/** - * 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. - */ - -/** - * 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), or `null` if URL has invalid protocol - * (so should be outright rejected). - */ -const protocolFromUrl = function(url) { - // Check for possible leading protocol. - // https://url.spec.whatwg.org/#url-parsing strips leading whitespace - // (\x00) or C0 control (\x00-\x1F) characters. - // eslint-disable-next-line no-control-regex - const protocol = /^[\x00-\x20]*([^\\/#?]*?)(:|�*58|�*3a|&colon)/i.exec(url); - if (!protocol) { - return "_relative"; - } - // Reject weird colons - if (protocol[2] !== ":") { - return null; - } - // Reject invalid characters in scheme according to - // https://datatracker.ietf.org/doc/html/rfc3986#section-3.1 - if (!/^[a-zA-Z][a-zA-Z0-9+\-.]*$/.test(protocol[1])) { - return null; - } - // Lowercase the protocol - return protocol[1].toLowerCase(); -}; - -/** - * 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 = { - 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.leqno = utils.deflt(options.leqno, false); // boolean - this.throwOnError = utils.deflt(options.throwOnError, false); // boolean - this.errorColor = utils.deflt(options.errorColor, "#b22222"); // string - this.macros = options.macros || {}; - this.wrap = utils.deflt(options.wrap, "tex"); // "tex" | "=" - 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) { - const protocol = utils.protocolFromUrl(context.url); - if (protocol == null) { - return false - } - context.protocol = protocol; - } - 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 this.classes.includes(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 this.classes.includes(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 itself). - */ - 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. - */ - -// TODO: Remove when Chromium stretches \widetilde & \widehat -const estimatedWidth = node => { - let width = 0; - if (node.body) { - for (const item of node.body) { - width += estimatedWidth(item); - } - } else if (node.type === "supsub") { - width += estimatedWidth(node.base); - if (node.sub) { width += 0.7 * estimatedWidth(node.sub); } - if (node.sup) { width += 0.7 * estimatedWidth(node.sup); } - } else if (node.type === "mathord" || node.type === "textord") { - for (const ch of node.text.split('')) { - const codePoint = ch.codePointAt(0); - if ((0x60 < codePoint && codePoint < 0x7B) || (0x03B0 < codePoint && codePoint < 0x3CA)) { - width += 0.56; // lower case latin or greek. Use advance width of letter n - } else if (0x2F < codePoint && codePoint < 0x3A) { - width += 0.50; // numerals. - } else { - width += 0.92; // advance width of letter M - } - } - } else { - width += 1.0; - } - return width -}; - -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 -}; - -const crookedWides = ["\\widetilde", "\\widehat", "\\widecheck", "\\utilde"]; - -// TODO: Remove when Chromium stretches \widetilde & \widehat -const accentNode = (group) => { - const mo = mathMLnode(group.label); - if (crookedWides.includes(group.label)) { - const width = estimatedWidth(group.base); - if (1 < width && width < 1.6) { - mo.classes.push("tml-crooked-2"); - } else if (1.6 <= width && width < 2.5) { - mo.classes.push("tml-crooked-3"); - } else if (2.5 <= width) { - mo.classes.push("tml-crooked-4"); - } - } - return mo -}; - -var stretchy = { - mathMLnode, - accentNode -}; - -/** - * 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, "\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"); -// unicodemath -defineSymbol(math, rel, "\u2a75", "\\eqeq", true); -defineSymbol(math, rel, "\u2a76", "\\eqeqeq", true); -// 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); -// ∇ is actually a unary operator, not binary. But this works. -defineSymbol(math, bin, "\u2207", "\\nabla", true); -defineSymbol(math, textord, "\u266d", "\\flat", true); -defineSymbol(math, textord, "\u2113", "\\ell", true); -defineSymbol(math, textord, "\u266e", "\\natural", true); -defineSymbol(math, textord, "Å", "\\Angstrom", true); -defineSymbol(text, textord, "Å", "\\Angstrom", 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 -defineSymbol(math, bin, "\u2AFD", "\\sslash", true); // from stmaryrd - -// 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, "\u21a4", "\\mapsfrom", 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, "\u220E", "\\QED", true); -defineSymbol(math, mathord, "\u2030", "\\permil", true); -defineSymbol(text, textord, "\u2030", "\\permil"); -defineSymbol(math, mathord, "\u2609", "\\astrosun", true); -defineSymbol(math, mathord, "\u263c", "\\sun", true); -defineSymbol(math, mathord, "\u263e", "\\leftmoon", true); -defineSymbol(math, mathord, "\u263d", "\\rightmoon", true); -defineSymbol(math, mathord, "\u2295", "\\Earth"); - -// 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, "\u2036", "\\backdprime"); -defineSymbol(math, textord, "\u2037", "\\backtrprime"); -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, "\u22ab", "\\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, "\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); -defineSymbol(math, bin, "\u22c8", "\\bowtie", true); -defineSymbol(math, bin, "\u22c8", "\\Join"); -defineSymbol(math, bin, "\u27d5", "\\leftouterjoin", true); -defineSymbol(math, bin, "\u27d6", "\\rightouterjoin", true); -defineSymbol(math, bin, "\u27d7", "\\fullouterjoin", true); - -// stix Binary Operators -defineSymbol(math, bin, "\u2238", "\\dotminus", true); -defineSymbol(math, bin, "\u27D1", "\\wedgedot", true); -defineSymbol(math, bin, "\u27C7", "\\veedot", true); -defineSymbol(math, bin, "\u2A62", "\\doublebarvee", true); -defineSymbol(math, bin, "\u2A63", "\\veedoublebar", true); -defineSymbol(math, bin, "\u2A5F", "\\wedgebar", true); -defineSymbol(math, bin, "\u2A60", "\\wedgedoublebar", true); -defineSymbol(math, bin, "\u2A54", "\\Vee", true); -defineSymbol(math, bin, "\u2A53", "\\Wedge", true); -defineSymbol(math, bin, "\u2A43", "\\barcap", true); -defineSymbol(math, bin, "\u2A42", "\\barcup", true); -defineSymbol(math, bin, "\u2A48", "\\capbarcup", true); -defineSymbol(math, bin, "\u2A40", "\\capdot", true); -defineSymbol(math, bin, "\u2A47", "\\capovercup", true); -defineSymbol(math, bin, "\u2A46", "\\cupovercap", true); -defineSymbol(math, bin, "\u2A4D", "\\closedvarcap", true); -defineSymbol(math, bin, "\u2A4C", "\\closedvarcup", true); -defineSymbol(math, bin, "\u2A2A", "\\minusdot", true); -defineSymbol(math, bin, "\u2A2B", "\\minusfdots", true); -defineSymbol(math, bin, "\u2A2C", "\\minusrdots", true); -defineSymbol(math, bin, "\u22BB", "\\Xor", true); -defineSymbol(math, bin, "\u22BC", "\\Nand", true); -defineSymbol(math, bin, "\u22BD", "\\Nor", true); -defineSymbol(math, bin, "\u22BD", "\\barvee"); -defineSymbol(math, bin, "\u2AF4", "\\interleave", true); -defineSymbol(math, bin, "\u29E2", "\\shuffle", true); -defineSymbol(math, bin, "\u2AF6", "\\threedotcolon", true); -defineSymbol(math, bin, "\u2982", "\\typecolon", true); -defineSymbol(math, bin, "\u223E", "\\invlazys", true); -defineSymbol(math, bin, "\u2A4B", "\\twocaps", true); -defineSymbol(math, bin, "\u2A4A", "\\twocups", true); -defineSymbol(math, bin, "\u2A4E", "\\Sqcap", true); -defineSymbol(math, bin, "\u2A4F", "\\Sqcup", true); -defineSymbol(math, bin, "\u2A56", "\\veeonvee", true); -defineSymbol(math, bin, "\u2A55", "\\wedgeonwedge", true); -defineSymbol(math, bin, "\u29D7", "\\blackhourglass", true); -defineSymbol(math, bin, "\u29C6", "\\boxast", true); -defineSymbol(math, bin, "\u29C8", "\\boxbox", true); -defineSymbol(math, bin, "\u29C7", "\\boxcircle", true); -defineSymbol(math, bin, "\u229C", "\\circledequal", true); -defineSymbol(math, bin, "\u29B7", "\\circledparallel", true); -defineSymbol(math, bin, "\u29B6", "\\circledvert", true); -defineSymbol(math, bin, "\u29B5", "\\circlehbar", true); -defineSymbol(math, bin, "\u27E1", "\\concavediamond", true); -defineSymbol(math, bin, "\u27E2", "\\concavediamondtickleft", true); -defineSymbol(math, bin, "\u27E3", "\\concavediamondtickright", true); -defineSymbol(math, bin, "\u22C4", "\\diamond", true); -defineSymbol(math, bin, "\u29D6", "\\hourglass", true); -defineSymbol(math, bin, "\u27E0", "\\lozengeminus", true); -defineSymbol(math, bin, "\u233D", "\\obar", true); -defineSymbol(math, bin, "\u29B8", "\\obslash", true); -defineSymbol(math, bin, "\u2A38", "\\odiv", true); -defineSymbol(math, bin, "\u29C1", "\\ogreaterthan", true); -defineSymbol(math, bin, "\u29C0", "\\olessthan", true); -defineSymbol(math, bin, "\u29B9", "\\operp", true); -defineSymbol(math, bin, "\u2A37", "\\Otimes", true); -defineSymbol(math, bin, "\u2A36", "\\otimeshat", true); -defineSymbol(math, bin, "\u22C6", "\\star", true); -defineSymbol(math, bin, "\u25B3", "\\triangle", true); -defineSymbol(math, bin, "\u2A3A", "\\triangleminus", true); -defineSymbol(math, bin, "\u2A39", "\\triangleplus", true); -defineSymbol(math, bin, "\u2A3B", "\\triangletimes", true); -defineSymbol(math, bin, "\u27E4", "\\whitesquaretickleft", true); -defineSymbol(math, bin, "\u27E5", "\\whitesquaretickright", true); -defineSymbol(math, bin, "\u2A33", "\\smashtimes", 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, "¢", "\\cent"); -defineSymbol(text, textord, "¢", "\\cent"); -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, "\u2033", "\\dprime"); -defineSymbol(math, textord, "\u2034", "\\trprime"); -defineSymbol(math, textord, "\u2057", "\\qprime"); -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, "\u2300", "\\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", "/", true); -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, "\u27ea", "\\lAngle", true); -defineSymbol(math, open, "\u2989", "\\llangle", 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, "\u27eb", "\\rAngle", true); -defineSymbol(math, close, "\u298a", "\\rrangle", 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"); -defineSymbol(math, bin, "\u22bb", "\\veebar"); -defineSymbol(math, bin, "\u2299", "\\odot", true); -// Firefox turns ⊕ into an emoji. So append \uFE0E. Define Unicode character in macros, not here. -defineSymbol(math, bin, "\u2295\uFE0E", "\\oplus"); -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, "\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(math, open, "⦇", "\\llparenthesis", true); -defineSymbol(math, close, "⦈", "\\rrparenthesis", 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, "\u2a09", "\\bigtimes"); -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, "\u2026", "\\dddot"); -defineSymbol(math, accent, "\u2026\u002e", "\\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, "\u2192", "\\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"); -defineSymbol(math, textord, "\u2300", "\\diameter", true); -defineSymbol(text, textord, "\u2300", "\\diameter"); - -// 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. - * - * The default is for 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. - * - * An option is for soft line breaks before an "=" sign. That changes the s. - * - * 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. - */ - -const openDelims = "([{⌊⌈⟨⟮⎰⟦⦃"; -const closeDelims = ")]}⌋⌉⟩⟯⎱⟦⦄"; - -function setLineBreaks(expression, wrapMode, isDisplayMode) { - const mtrs = []; - let mrows = []; - let block = []; - let numTopLevelEquals = 0; - let i = 0; - let level = 0; - while (i < expression.length) { - while (expression[i] instanceof DocumentFragment) { - expression.splice(i, 1, ...expression[i].children); // Expand the fragment. - } - const node = expression[i]; - if (node.attributes && node.attributes.linebreak && - node.attributes.linebreak === "newline") { - // A hard line break. Create a for the current block. - if (block.length > 0) { - mrows.push(new mathMLTree.MathNode("mrow", block)); - } - mrows.push(node); - block = []; - const mtd = new mathMLTree.MathNode("mtd", mrows); - mtd.style.textAlign = "left"; - mtrs.push(new mathMLTree.MathNode("mtr", [mtd])); - mrows = []; - i += 1; - continue - } - block.push(node); - if (node.type && node.type === "mo" && node.children.length === 1 && - !Object.hasOwn(node.attributes, "movablelimits")) { - const ch = node.children[0].text; - if (openDelims.indexOf(ch) > -1) { - level += 1; - } else if (closeDelims.indexOf(ch) > -1) { - level -= 1; - } else if (level === 0 && wrapMode === "=" && ch === "=") { - numTopLevelEquals += 1; - if (numTopLevelEquals > 1) { - block.pop(); - // Start a new block. (Insert a soft linebreak.) - const element = new mathMLTree.MathNode("mrow", block); - mrows.push(element); - block = [node]; - } - } else if (level === 0 && wrapMode === "tex" && ch !== "∇") { - // 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("mrow", block); - mrows.push(element); - block = []; - } - } - } - i += 1; - } - if (block.length > 0) { - const element = new mathMLTree.MathNode("mrow", block); - mrows.push(element); - } - if (mtrs.length > 0) { - const mtd = new mathMLTree.MathNode("mtd", mrows); - mtd.style.textAlign = "left"; - 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 corresponding 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); -}; - -const consolidateText = mrow => { - // If possible, consolidate adjacent elements into a single element. - if (mrow.type !== "mrow" && mrow.type !== "mstyle") { return mrow } - if (mrow.children.length === 0) { return mrow } // empty group, e.g., \text{} - if (!mrow.children[0].attributes || mrow.children[0].type !== "mtext") { return mrow } - const variant = mrow.children[0].attributes.mathvariant || ""; - const mtext = new mathMLTree.MathNode( - "mtext", - [new mathMLTree.TextNode(mrow.children[0].children[0].text)] - ); - 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; - } - } - // 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"; - } - for (const [key, value] of Object.entries(mrow.attributes)) { - mtext.attributes[key] = value; - } - return mtext -}; - -const numberRegEx$1 = /^[0-9]$/; -const isDotOrComma = (node, followingNode) => { - return ((node.type === "textord" && node.text === ".") || - (node.type === "atom" && node.text === ",")) && - // Don't consolidate if there is a space after the comma. - node.loc && followingNode.loc && node.loc.end === followingNode.loc.start -}; -const consolidateNumbers = expression => { - // Consolidate adjacent numbers. We want to return 1,506.3, - // not 1,506.3 - if (expression.length < 2) { return } - const nums = []; - let inNum = false; - // Find adjacent numerals - for (let i = 0; i < expression.length; i++) { - const node = expression[i]; - if (node.type === "textord" && numberRegEx$1.test(node.text)) { - if (!inNum) { nums.push({ start: i }); } - inNum = true; - } else { - if (inNum) { nums[nums.length - 1].end = i - 1; } - inNum = false; - } - } - if (inNum) { nums[nums.length - 1].end = expression.length - 1; } - - // Determine if numeral groups are separated by a comma or dot. - for (let i = nums.length - 1; i > 0; i--) { - if (nums[i - 1].end === nums[i].start - 2 && - isDotOrComma(expression[nums[i].start - 1], expression[nums[i].start])) { - // Merge the two groups. - nums[i - 1].end = nums[i].end; - nums.splice(i, 1); - } - } - - // Consolidate the number nodes - for (let i = nums.length - 1; i >= 0; i--) { - for (let j = nums[i].start + 1; j <= nums[i].end; j++) { - expression[nums[i].start].text += expression[j].text; - } - expression.splice(nums[i].start + 1, nums[i].end - nums[i].start); - // Check if the is followed by a numeric base in a supsub, e.g. the "3" in 123^4 - // If so, merge the first into the base. - if (expression.length > nums[i].start + 1) { - const nextTerm = expression[nums[i].start + 1]; - if (nextTerm.type === "supsub" && nextTerm.base && nextTerm.base.type === "textord" && - numberRegEx$1.test(nextTerm.base.text)) { - nextTerm.base.text = expression[nums[i].start].text + nextTerm.base.text; - expression.splice(nums[i].start, 1); - } - } - } -}; - -/** - * 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, semisimple = false) { - if (body.length === 1 && !(body[0] instanceof DocumentFragment)) { - return body[0]; - } else if (!semisimple) { - // Suppress spacing on nodes at both ends of the row. - if (body[0] instanceof MathNode && body[0].type === "mo" && !body[0].attributes.fence) { - body[0].attributes.lspace = "0em"; - body[0].attributes.rspace = "0em"; - } - const end = body.length - 1; - if (body[end] instanceof MathNode && body[end].type === "mo" && !body[end].attributes.fence) { - body[end].attributes.lspace = "0em"; - body[end].attributes.rspace = "0em"; - } - } - 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, semisimple = false) { - if (!semisimple && expression.length === 1) { - const group = buildGroup$1(expression[0], style); - if (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]; - } - - consolidateNumbers(expression); - - 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, semisimple = false) { - return makeRow(buildExpression(expression, style, semisimple), semisimple); -}; - -/** - * 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$1 = _ => { - return new mathMLTree.MathNode("mtd", [], [], { padding: "0", width: "50%" }) -}; - -const taggedExpression = (expression, tag, style, leqno) => { - tag = buildExpressionRow(tag[0].body, style); - tag = consolidateText(tag); - tag.classes.push("tml-tag"); - - expression = new mathMLTree.MathNode("mtd", [expression]); - const rowArray = [glue$1(), expression, glue$1()]; - rowArray[leqno ? 0 : 2].classes.push(leqno ? "tml-left" : "tml-right"); - rowArray[leqno ? 0 : 2].children.push(tag); - const mtr = new mathMLTree.MathNode("mtr", rowArray, ["tml-tageqn"]); - const table = new mathMLTree.MathNode("mtable", [mtr]); - table.style.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 wrap = (settings.displayMode || settings.annotate) ? "none" : settings.wrap; - - const n1 = expression.length === 0 ? null : expression[0]; - let wrapper = expression.length === 1 && tag === null && (n1 instanceof MathNode) - ? expression[0] - : setLineBreaks(expression, wrap, settings.displayMode); - - if (tag) { - wrapper = taggedExpression(wrapper, tag, style, settings.leqno); - } - - 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"); - wrapper = new mathMLTree.MathNode("semantics", [wrapper, annotation]); - } - - const math = 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"); - math.style.display = "block math"; // necessary in Chromium. - // Firefox and Safari do not recognize display: "block math". - // Set a class so that the CSS file can set display: block. - math.classes = ["tml-display"]; - } - return math; -} - -const smalls = "acegıȷmnopqrsuvwxyzαγεηικμνοπρςστυχωϕ𝐚𝐜𝐞𝐠𝐦𝐧𝐨𝐩𝐪𝐫𝐬𝐮𝐯𝐰𝐱𝐲𝐳"; -const talls = "ABCDEFGHIJKLMNOPQRSTUVWXYZbdfhkltΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩβδλζφθψ" - + "𝐀𝐁𝐂𝐃𝐄𝐅𝐆𝐇𝐈𝐉𝐊𝐋𝐌𝐍𝐎𝐏𝐐𝐑𝐒𝐓𝐔𝐕𝐖𝐗𝐘𝐙𝐛𝐝𝐟𝐡𝐤𝐥𝐭"; -const longSmalls = new Set(["\\alpha", "\\gamma", "\\delta", "\\epsilon", "\\eta", "\\iota", - "\\kappa", "\\mu", "\\nu", "\\pi", "\\rho", "\\sigma", "\\tau", "\\upsilon", "\\chi", "\\psi", - "\\omega", "\\imath", "\\jmath"]); -const longTalls = new Set(["\\Gamma", "\\Delta", "\\Sigma", "\\Omega", "\\beta", "\\delta", - "\\lambda", "\\theta", "\\psi"]); - -const mathmlBuilder$a = (group, style) => { - const accentNode = group.isStretchy - ? stretchy.accentNode(group) - : new mathMLTree.MathNode("mo", [makeText(group.label, group.mode)]); - - if (group.label === "\\vec") { - accentNode.style.transform = "scale(0.75) translate(10%, 30%)"; - } else { - accentNode.style.mathStyle = "normal"; - accentNode.style.mathDepth = "0"; - if (needWebkitShift.has(group.label) && utils.isCharacterBox(group.base)) { - let shift = ""; - const ch = group.base.text; - if (smalls.indexOf(ch) > -1 || longSmalls.has(ch)) { shift = "tml-xshift"; } - if (talls.indexOf(ch) > -1 || longTalls.has(ch)) { shift = "tml-capshift"; } - if (shift) { accentNode.classes.push(shift); } - } - } - if (!group.isStretchy) { - accentNode.setAttribute("stretchy", "false"); - } - - const node = new mathMLTree.MathNode((group.label === "\\c" ? "munder" : "mover"), - [buildGroup$1(group.base, style), accentNode] - ); - - return node; -}; - -const nonStretchyAccents = new Set([ - "\\acute", - "\\grave", - "\\ddot", - "\\dddot", - "\\ddddot", - "\\tilde", - "\\bar", - "\\breve", - "\\check", - "\\hat", - "\\vec", - "\\dot", - "\\mathring" -]); - -const needWebkitShift = new Set([ - "\\acute", - "\\bar", - "\\breve", - "\\check", - "\\dot", - "\\ddot", - "\\grave", - "\\hat", - "\\mathring", - "\\'", "\\^", "\\~", "\\=", "\\u", "\\.", '\\"', "\\r", "\\H", "\\v" -]); - -// 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 = !nonStretchyAccents.has(context.funcName); - - return { - type: "accent", - mode: context.parser.mode, - label: context.funcName, - isStretchy: isStretchy, - 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, - 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.accentNode(group); - accentNode.style["math-depth"] = 0; - const node = new mathMLTree.MathNode("munder", [ - buildGroup$1(group.base, style), - accentNode - ]); - 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 padding$2 = width => { - const node = new mathMLTree.MathNode("mspace"); - node.setAttribute("width", width + "em"); - return node -}; - -const paddedNode = (group, lspace = 0.3, rspace = 0) => { - if (group == null && rspace === 0) { return padding$2(lspace) } - const row = group ? [group] : []; - if (lspace !== 0) { row.unshift(padding$2(lspace)); } - if (rspace > 0) { row.push(padding$2(rspace)); } - return new mathMLTree.MathNode("mrow", row) -}; - -const labelSize = (size, scriptLevel) => Number(size) / emScale(scriptLevel); - -const munderoverNode = (fName, body, below, style) => { - const arrowNode = stretchy.mathMLnode(fName); - // Is this the short part of a mhchem equilibrium arrow? - const isEq = fName.slice(1, 3) === "eq"; - const minWidth = fName.charAt(1) === "x" - ? "1.75" // mathtools extensible arrows are ≥ 1.75em long - : fName.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 - // TODO: When Firefox supports minsize, use the next line. - //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 label dimensions accordingly. - const labelStyle = style.withLevel(style.level < 2 ? 2 : 3); - const minArrowWidth = labelSize(minWidth, labelStyle.level); - // The dummyNode will be inside a inside a - // So it will be at scriptlevel 3 - const dummyWidth = labelSize(minWidth, 3); - const emptyLabel = paddedNode(null, minArrowWidth.toFixed(4), 0); - const dummyNode = paddedNode(null, dummyWidth.toFixed(4), 0); - // The arrow is a little longer than the label. Set a spacer length. - const space = labelSize((isEq ? 0 : 0.3), labelStyle.level).toFixed(4); - let upperNode; - let lowerNode; - - const gotUpper = (body && body.body && - // \hphantom visible content - (body.body.body || body.body.length > 0)); - if (gotUpper) { - let label = buildGroup$1(body, labelStyle); - label = paddedNode(label, space, space); - // Since Firefox does not support minsize, stack a invisible node - // on top of the label. Its width will serve as a min-width. - // TODO: Refactor this after Firefox supports minsize. - upperNode = new mathMLTree.MathNode("mover", [label, dummyNode]); - } - const gotLower = (below && below.body && - (below.body.body || below.body.length > 0)); - if (gotLower) { - let label = buildGroup$1(below, labelStyle); - label = paddedNode(label, space, space); - lowerNode = new mathMLTree.MathNode("munder", [label, dummyNode]); - } - - let node; - if (!gotUpper && !gotLower) { - node = new mathMLTree.MathNode("mover", [arrowNode, emptyLabel]); - } else if (gotUpper && gotLower) { - node = new mathMLTree.MathNode("munderover", [arrowNode, lowerNode, upperNode]); - } else if (gotUpper) { - node = new mathMLTree.MathNode("mover", [arrowNode, upperNode]); - } else { - node = new mathMLTree.MathNode("munder", [arrowNode, lowerNode]); - } - if (minWidth === "3.0") { node.style.height = "1em"; } // CD environment - node.setAttribute("accent", "false"); // Necessary for MS Word - 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 5 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 row = [node]; - row.unshift(padding$2(0.2778)); - row.push(padding$2(0.2778)); - return new mathMLTree.MathNode("mrow", row) - } -}); - -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", - [padding$2(0.2778), botNode, raiseNode, padding$2(0.2778)] - ); - } else { - raiseNode.setAttribute("width", (group.name === "\\equilibriumRight" ? "0.5em" : "0")); - wrapper = new mathMLTree.MathNode( - "mpadded", - [padding$2(0.2778), raiseNode, botArrow, padding$2(0.2778)] - ); - } - - wrapper.setAttribute("voffset", "-0.18em"); - wrapper.setAttribute("height", "-0.18em"); - wrapper.setAttribute("depth", "+0.18em"); - return wrapper - } -}); - -/** - * 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], - semisimple: true - }; - 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); - } - body.pop(); - - // End row group - parser.gullet.endGroup(); - // End array group defining \\ - parser.gullet.endGroup(); - - return { - type: "array", - mode: "math", - body, - envClasses: ["jot", "cd"], - cols: [], - 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(Number((num * 255).toFixed(0))); - }); - } - 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) => { - // In LaTeX, color is not supposed to change the spacing of any node. - // So instead of wrapping the group in an , we apply - // the color individually to each node and return a document fragment. - let expr = buildExpression(group.body, style.withColor(group.color)); - expr = expr.map(e => { - e.style.color = group.color; - return e - }); - return mathMLTree.newDocumentFragment(expr) -}; - -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, breakOnTokenText, 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); - } - - // Parse out the implicit body that should be colored. - const body = parser.parseExpression(true, breakOnTokenText, true); - - 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: 0, - allowedInText: true - }, - - handler({ parser }, args, optArgs) { - const size = parser.gullet.future().text === "[" ? parser.parseSizeGroup(true) : null; - 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 globalMap = { - "\\global": "\\global", - "\\long": "\\\\globallong", - "\\\\globallong": "\\\\globallong", - "\\def": "\\gdef", - "\\gdef": "\\gdef", - "\\edef": "\\xdef", - "\\xdef": "\\xdef", - "\\let": "\\\\globallet", - "\\futurelet": "\\\\globalfuture" -}; - -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, global) => { - 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, global); -}; - -// -> | -// -> |\global -// -> | -// -> \global|\long|\outer -defineFunction({ - type: "internal", - names: [ - "\\global", - "\\long", - "\\\\globallong" // can’t be entered directly - ], - props: { - numArgs: 0, - allowedInText: true - }, - handler({ parser, funcName }) { - parser.consumeSpaces(); - const token = parser.fetch(); - if (globalMap[token.text]) { - // Temml doesn't have \par, so ignore \long - if (funcName === "\\global" || funcName === "\\\\globallong") { - token.text = globalMap[token.text]; - } - return assertNodeType(parser.parseFunction(), "internal"); - } - throw new ParseError(`Invalid token after macro prefix`, token); - } -}); - -// Basic support for macro definitions: \def, \gdef, \edef, \xdef -// -> -// -> \def|\gdef|\edef|\xdef -// -> -defineFunction({ - type: "internal", - names: ["\\def", "\\gdef", "\\edef", "\\xdef"], - 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" || funcName === "\\xdef") { - tokens = parser.gullet.expandTokens(tokens); - if (tokens.length > parser.gullet.settings.maxExpand) { - throw new ParseError("Too many expansions in an " + funcName); - } - tokens.reverse(); // to fit in with stack order - } - // Final arg is the expansion of the macro - parser.gullet.macros.set( - name, - { tokens, numArgs, delimiters }, - funcName === globalMap[funcName] - ); - return { type: "internal", mode: parser.mode }; - } -}); - -// -> -// -> \futurelet -// | \let -// -> |= -defineFunction({ - type: "internal", - names: [ - "\\let", - "\\\\globallet" // can’t be entered directly - ], - 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, funcName === "\\\\globallet"); - return { type: "internal", mode: parser.mode }; - } -}); - -// ref: https://www.tug.org/TUGboat/tb09-3/tb22bechtolsheim.pdf -defineFunction({ - type: "internal", - names: [ - "\\futurelet", - "\\\\globalfuture" // can’t be entered directly - ], - 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, funcName === "\\\\globalfuture"); - 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 }, - !parser.settings.strict - ); - - 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", - "⦇", - "\\llparenthesis", - "⦈", - "\\rrparenthesis", - "\\lfloor", - "\\rfloor", - "\u230a", - "\u230b", - "\\lceil", - "\\rceil", - "\u2308", - "\u2309", - "<", - ">", - "\\langle", - "\u27e8", - "\\rangle", - "\u27e9", - "\\lAngle", - "\u27ea", - "\\rAngle", - "\u27eb", - "\\llangle", - "⦉", - "\\rrangle", - "⦊", - "\\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", - "." -]; - -// Export isDelimiter for benefit of parser. -const dels = ["}", "\\left", "\\middle", "\\right"]; -const isDelimiter = str => str.length > 0 && - (delimiters.includes(str) || delimiterSizes[str] || dels.includes(str)); - -// 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) { - const symDelim = checkSymbolNodeType(delim); - if (symDelim && delimiters.includes(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 (["/", "\u2044"].includes(symDelim.text)) { symDelim.text = "\u2215"; } - if (["<", "\\lt"].includes(symDelim.text)) { symDelim.text = "⟨"; } - if ([">", "\\gt"].includes(symDelim.text)) { symDelim.text = "⟩"; } - 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" || group.delim === "\\vert" || - group.delim === "|" || group.delim.indexOf("arrow") > -1) { - // 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) => { - return { - type: "leftright-right", - mode: context.parser.mode, - delim: checkDelimiter(args[0], context).text - }; - } -}); - -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' or `\\middle` - let body = parser.parseExpression(false, null, true); - let nextToken = parser.fetch(); - while (nextToken.text === "\\middle") { - // `\middle`, from the ε-TeX package, ends one group and starts another group. - // We had to parse this expression with `breakOnMiddle` enabled in order - // to get TeX-compliant parsing of \over. - // But we do not want, at this point, to end on \middle, so continue - // to parse until we fetch a `\right`. - parser.consume(); - const middle = parser.fetch().text; - if (!symbols.math[middle]) { - throw new ParseError(`Invalid delimiter '${middle}' after '\\middle'`); - } - checkDelimiter({ type: "atom", mode: "math", text: middle }, { funcName: "\\middle" }); - body.push({ type: "middle", mode: "math", delim: middle }); - parser.consume(); - body = body.concat(parser.parseExpression(false, null, true)); - nextToken = parser.fetch(); - } - --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 - }; - }, - 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" || group.left.indexOf("arrow") > -1) { - 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" || group.right.indexOf("arrow") > -1) { - rightNode.setAttribute("stretchy", "true"); - } - 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"); - if (group.delim.indexOf("arrow") > -1) { - middleNode.setAttribute("stretchy", "true"); - } - // The next line is not semantically correct, but - // Chromium fails to stretch if it is not there. - middleNode.setAttribute("form", "prefix"); - // 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 padding$1 = _ => { - const node = new mathMLTree.MathNode("mspace"); - node.setAttribute("width", "3pt"); - return node -}; - -const mathmlBuilder$8 = (group, style) => { - let node; - if (group.label.indexOf("colorbox") > -1 || group.label === "\\boxed") { - // MathML core does not support +width attribute in . - // Firefox does not reliably add side padding. - // Insert - node = new mathMLTree.MathNode("mrow", [ - padding$1(), - buildGroup$1(group.body, style), - padding$1() - ]); - } else { - node = new mathMLTree.MathNode("mrow", [buildGroup$1(group.body, style)]); - } - switch (group.label) { - case "\\overline": - node.style.padding = "0.1em 0 0 0"; - node.style.borderTop = "0.065em solid"; - break - case "\\underline": - node.style.padding = "0 0 0.1em 0"; - node.style.borderBottom = "0.065em solid"; - break - case "\\cancel": - // We can't use an inline background-gradient. It does not work client-side. - // So set a class and put the rule in the external CSS file. - node.classes.push("tml-cancel"); - break - case "\\bcancel": - node.classes.push("tml-bcancel"); - break - /* - case "\\longdiv": - node.setAttribute("notation", "longdiv"); - break - case "\\phase": - node.setAttribute("notation", "phasorangle"); - break */ - case "\\angl": - node.style.padding = "0.03889em 0.03889em 0 0.03889em"; - node.style.borderTop = "0.049em solid"; - node.style.borderRight = "0.049em solid"; - node.style.marginRight = "0.03889em"; - break - case "\\sout": - node.style.backgroundImage = 'linear-gradient(black, black)'; - node.style.backgroundRepeat = 'no-repeat'; - node.style.backgroundSize = '100% 1.5px'; - node.style.backgroundPosition = '0 center'; - break - case "\\boxed": - // \newcommand{\boxed}[1]{\fbox{\m@th$\displaystyle#1$}} from amsmath.sty - node.style = { padding: "3pt 0 3pt 0", border: "1px solid" }; - node.setAttribute("scriptlevel", "0"); - node.setAttribute("displaystyle", "true"); - break - case "\\fbox": - node.style = { padding: "3pt", border: "1px solid" }; - 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("height", `+${2 * fboxsep}pt`) - //node.setAttribute("voffset", `${fboxsep}pt`) - const style = { padding: "3pt 0 3pt 0" }; - - if (group.label === "\\fcolorbox") { - style.border = "0.06em solid " + String(group.borderColor); - } - node.style = style; - break - } - case "\\xcancel": - node.classes.push("tml-xcancel"); - 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: ["\\angl", "\\cancel", "\\bcancel", "\\xcancel", "\\sout", "\\overline", "\\boxed"], - // , "\\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 -}); - -defineFunction({ - type: "enclose", - names: ["\\underline"], - props: { - numArgs: 1, - allowedInText: true - }, - 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; - if (nxt === "\\relax") { - parser.consume(); - parser.consumeSpaces(); - 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, true); - tag.classes = ["tml-tag"]; - } else { - // \notag. Return an empty span. - tag = new mathMLTree.MathNode("mtext", [], []); - return tag - } - } else if (group.envClasses.includes("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("mtext", [], []); - return tag - } else { - // AMS automatcally numbered equaton. - // Insert a class so the element can be populated by a CSS counter. - // WebKit will display the CSS counter only inside a span. - tag = new mathMLTree.MathNode("mtext", [new Span(["tml-eqn"])]); - } - 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, - { - cols, // [{ type: string , align: l|c|r|null }] - envClasses, // align(ed|at|edat) | array | cases | cd | small | 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", "\\@ifstar\\envtag@literal\\envtag@paren"); - parser.gullet.macros.set("\\envtag@paren", "\\env@tag{{(\\text{#1})}}"); - parser.gullet.macros.set("\\envtag@literal", "\\env@tag{\\text{#1}}"); - parser.gullet.macros.set("\\notag", "\\env@notag"); - parser.gullet.macros.set("\\nonumber", "\\env@notag"); - } - - // 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, - semisimple: true - }; - row.push(cell); - const next = parser.fetch().text; - if (next === "&") { - if (maxNumCols && row.length === maxNumCols) { - if (envClasses.includes("array")) { - if (parser.settings.strict) { - throw new ParseError("Too few columns " + "specified in the {array} column argument.", - parser.nextToken) - } - } else if (maxNumCols === 2) { - throw new ParseError("The split environment accepts no more than two columns", - 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, - body, - cols, - rowGaps, - hLinesBeforeRow, - envClasses, - addEqnNum, - scriptLevel, - tags, - leqno - }; -} - -// 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 glue = group => { - const glueNode = new mathMLTree.MathNode("mtd", []); - glueNode.style = { padding: "0", width: "50%" }; - if (group.envClasses.includes("multline")) { - glueNode.style.width = "7.5%"; - } - return glueNode -}; - -const mathmlBuilder$7 = function(group, style) { - const tbl = []; - const numRows = group.body.length; - const hlines = group.hLinesBeforeRow; - - for (let i = 0; i < numRows; i++) { - const rw = group.body[i]; - const row = []; - const cellLevel = 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(cellLevel))] - ); - - if (group.envClasses.includes("multline")) { - const align = i === 0 ? "left" : i === numRows - 1 ? "right" : "center"; - mtd.setAttribute("columnalign", align); - if (align !== "center") { - mtd.classes.push("tml-" + align); - } - } - row.push(mtd); - } - if (group.addEqnNum) { - row.unshift(glue(group)); - row.push(glue(group)); - const tag = getTag(group, style.withLevel(cellLevel), i); - if (group.leqno) { - row[0].children.push(tag); - row[0].classes.push("tml-left"); - } else { - row[row.length - 1].children.push(tag); - row[row.length - 1].classes.push("tml-right"); - } - } - const mtr = new mathMLTree.MathNode("mtr", row, []); - // Write horizontal rules - if (i === 0 && hlines[0].length > 0) { - if (hlines[0].length === 2) { - mtr.children.forEach(cell => { cell.style.borderTop = "0.15em double"; }); - } else { - mtr.children.forEach(cell => { - cell.style.borderTop = hlines[0][0] ? "0.06em dashed" : "0.06em solid"; - }); - } - } - if (hlines[i + 1].length > 0) { - if (hlines[i + 1].length === 2) { - mtr.children.forEach(cell => { cell.style.borderBottom = "0.15em double"; }); - } else { - mtr.children.forEach(cell => { - cell.style.borderBottom = hlines[i + 1][0] ? "0.06em dashed" : "0.06em solid"; - }); - } - } - tbl.push(mtr); - } - - if (group.envClasses.length > 0) { - const pad = group.envClasses.includes("jot") - ? "0.7" // 0.5ex + 0.09em top & bot padding - : group.envClasses.includes("small") - ? "0.35" - : "0.5"; // 0.5ex default top & bot padding - const sidePadding = group.envClasses.includes("abut") - ? "0" - : group.envClasses.includes("cases") - ? "0" - : group.envClasses.includes("small") - ? "0.1389" - : group.envClasses.includes("cd") - ? "0.25" - : "0.4"; // default side padding - - const numCols = tbl.length === 0 ? 0 : tbl[0].children.length; - - const sidePad = (j, hand) => { - if (j === 0 && hand === 0) { return "0" } - if (j === numCols - 1 && hand === 1) { return "0" } - if (group.envClasses[0] !== "align") { return sidePadding } - if (hand === 1) { return "0" } - if (group.addEqnNum) { - return (j % 2) ? "1" : "0" - } else { - return (j % 2) ? "0" : "1" - } - }; - - // Padding - for (let i = 0; i < tbl.length; i++) { - for (let j = 0; j < tbl[i].children.length; j++) { - tbl[i].children[j].style.padding = `${pad}ex ${sidePad(j, 1)}em ${pad}ex ${sidePad(j, 0)}em`; - } - } - - // Justification - const align = group.envClasses.includes("align") || group.envClasses.includes("alignat"); - for (let i = 0; i < tbl.length; i++) { - const row = tbl[i]; - if (align) { - for (let j = 0; j < row.children.length; j++) { - // Chromium does not recognize text-align: left. Use -webkit- - // TODO: Remove -webkit- when Chromium no longer needs it. - row.children[j].classes = ["tml-" + (j % 2 ? "left" : "right")]; - } - if (group.addEqnNum) { - const k = group.leqno ? 0 : row.children.length - 1; - row.children[k].classes = ["tml-" + (group.leqno ? "left" : "right")]; - } - } - if (row.children.length > 1 && group.envClasses.includes("cases")) { - row.children[1].style.padding = row.children[1].style.padding.replace(/0em$/, "1em"); - } - - if (group.envClasses.includes("cases") || group.envClasses.includes("subarray")) { - for (const cell of row.children) { - cell.classes.push("tml-left"); - } - } - } - } else { - // Set zero padding on side of the matrix - for (let i = 0; i < tbl.length; i++) { - tbl[i].children[0].style.paddingLeft = "0em"; - if (tbl[i].children.length === tbl[0].children.length) { - tbl[i].children[tbl[i].children.length - 1].style.paddingRight = "0em"; - } - } - } - - let table = new mathMLTree.MathNode("mtable", tbl); - if (group.scriptLevel === "display") { table.setAttribute("displaystyle", "true"); } - - if (group.addEqnNum || group.envClasses.includes("multline")) { - table.style.width = "100%"; - } - - // Column separator lines and column alignment - let align = ""; - - if (group.cols && group.cols.length > 0) { - const cols = group.cols; - let prevTypeWasAlign = false; - let iStart = 0; - let iEnd = cols.length; - - while (cols[iStart].type === "separator") { - iStart += 1; - } - while (cols[iEnd - 1].type === "separator") { - iEnd -= 1; - } - - if (cols[0].type === "separator") { - const sep = cols[1].type === "separator" - ? "0.15em double" - : cols[0].separator === "|" - ? "0.06em solid " - : "0.06em dashed "; - for (const row of table.children) { - row.children[0].style.borderLeft = sep; - } - } - let iCol = group.addEqnNum ? 0 : -1; - for (let i = iStart; i < iEnd; i++) { - if (cols[i].type === "align") { - const colAlign = alignMap[cols[i].align]; - align += colAlign; - iCol += 1; - for (const row of table.children) { - if (colAlign.trim() !== "center" && iCol < row.children.length) { - row.children[iCol].classes = ["tml-" + colAlign.trim()]; - } - } - 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) { - const sep = cols[i + 1].type === "separator" - ? "0.15em double" - : cols[i].separator === "|" - ? "0.06em solid" - : "0.06em dashed"; - for (const row of table.children) { - if (iCol < row.children.length) { - row.children[iCol].style.borderRight = sep; - } - } - } - prevTypeWasAlign = false; - } - } - if (cols[cols.length - 1].type === "separator") { - const sep = cols[cols.length - 2].type === "separator" - ? "0.15em double" - : cols[cols.length - 1].separator === "|" - ? "0.06em solid" - : "0.06em dashed"; - for (const row of table.children) { - row.children[row.children.length - 1].style.borderRight = sep; - row.children[row.children.length - 1].style.paddingRight = "0.4em"; - } - } - } - if (group.addEqnNum) { - // allow for glue cells on each side - align = "left " + (align.length > 0 ? align : "center ") + "right "; - } - if (align) { - // Firefox reads this attribute, not the -webkit-left|right written above. - // TODO: When Chrome no longer needs "-webkit-", use CSS and delete the next line. - table.setAttribute("columnalign", align.trim()); - } - - if (group.envClasses.includes("small")) { - // A small array. Wrap in scriptstyle. - table = new mathMLTree.MathNode("mstyle", [table]); - table.setAttribute("scriptlevel", "1"); - } - - return table -}; - -// Convenience function for align, align*, aligned, alignat, alignat*, alignedat, split. -const alignedHandler = function(context, args) { - if (context.envName.indexOf("ed") === -1) { - validateAmsEnvironmentContext(context); - } - const cols = []; - const res = parseArray( - context.parser, - { - cols, - addEqnNum: context.envName === "align" || context.envName === "alignat", - emptySingleRow: true, - envClasses: ["abut", "jot"], // set row spacing & provisional column spacing - 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; - const isAlignedAt = context.envName.indexOf("at") > -1; - if (args[0] && isAlignedAt) { - // alignat environment takes an argument w/ number of columns - let arg0 = ""; - for (let i = 0; i < args[0].body.length; i++) { - const textord = assertNodeType(args[0].body[i], "textord"); - arg0 += textord.text; - } - if (isNaN(arg0)) { - throw new ParseError("The alignat enviroment requires a numeric first argument.") - } - numMaths = Number(arg0); - numCols = numMaths * 2; - } - res.body.forEach(function(row) { - if (isAlignedAt) { - // 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 - }; - } - if (context.envName === "split") ; else if (isAlignedAt) { - res.envClasses.push("alignat"); // Sets justification - } else { - res.envClasses[0] = "align"; // Sets column spacing & justification - } - 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, - envClasses: ["array"], - 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 = { - envClasses: [], - cols: [] - }; - 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 = []; - } - } - const res = parseArray(context.parser, payload, "text"); - res.cols = new Array(res.body[0].length).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 = { type: "small" }; - const res = parseArray(context.parser, payload, "script"); - res.envClasses = ["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, - envClasses: ["small"] - }; - 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: [], - envClasses: ["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. -defineEnvironment({ - type: "array", - names: ["align", "align*", "aligned", "split"], - props: { - numArgs: 0 - }, - handler: alignedHandler, - 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 where spacing occurs. -defineEnvironment({ - type: "array", - names: ["alignat", "alignat*", "alignedat"], - props: { - numArgs: 1 - }, - 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 (context.envName !== "gathered") { - validateAmsEnvironmentContext(context); - } - const res = { - cols: [], - envClasses: ["abut", "jot"], - addEqnNum: context.envName === "gather", - emptySingleRow: true, - leqno: context.parser.settings.leqno - }; - return parseArray(context.parser, res, "display"); - }, - 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, - envClasses: ["align"], - 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, - envClasses: ["jot", "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 isLongVariableName = (group, font) => { - if (font !== "mathrm" || group.body.type !== "ordgroup" || group.body.body.length === 1) { - return false - } - if (group.body.body[0].type !== "mathord") { return false } - for (let i = 1; i < group.body.body.length; i++) { - const parseNodeType = group.body.body[i].type; - if (!(parseNodeType === "mathord" || - (parseNodeType === "textord" && !isNaN(group.body.body[i].text)))) { - return false - } - } - return true -}; - -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", "mrow"].includes(mathGroup.type)) { - mathGroup.style.fontWeight = "bold"; - return mathGroup - } - // Check if it is possible to consolidate elements into a single element. - if (isLongVariableName(group, font)) { - // This is a \mathrm{…} group. It gets special treatment because symbolsOrd.js - // wraps elements with s to work around a Firefox bug. - const mi = mathGroup.children[0].children[0]; - delete mi.attributes.mathvariant; - for (let i = 1; i < mathGroup.children.length; i++) { - mi.children[0].text += mathGroup.children[i].type === "mn" - ? mathGroup.children[i].children[0].text - : mathGroup.children[i].children[0].children[0].text; - } - // Wrap in a to prevent the same Firefox bug. - const bogus = new mathMLTree.MathNode("mtext", new mathMLTree.TextNode("\u200b")); - return new mathMLTree.MathNode("mrow", [bogus, mi]) - } - 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 (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", - - // 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, true); - 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 -}); - -// \hbox is provided for compatibility with LaTeX functions that act on a box. -// This function by itself doesn't do anything but set scriptlevel to \textstyle -// and 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 newStyle = style.withLevel(StyleLevel.TEXT); - const mrow = buildExpressionRow(group.body, newStyle); - return consolidateText(mrow) - } -}); - -const mathmlBuilder$4 = (group, style) => { - const accentNode = stretchy.mathMLnode(group.label); - accentNode.style["math-depth"] = 0; - 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); - if (dimension.number < 0) { - node.style.marginLeft = 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 - let strut; - if (group.alignment === "llap") { - // We need an invisible strut with the same depth as the group. - // We can't just read the depth, so we use \vphantom methods. - const phantomInner = buildExpression(ordargument(group.body), style); - const phantom = new mathMLTree.MathNode("mphantom", phantomInner); - strut = new mathMLTree.MathNode("mpadded", [phantom]); - strut.setAttribute("width", "0px"); - } - - const inner = buildGroup$1(group.body, style); - let node; - if (group.alignment === "llap") { - inner.style.position = "absolute"; - inner.style.right = "0"; - inner.style.bottom = `0`; // If we could have read the ink depth, it would go here. - node = new mathMLTree.MathNode("mpadded", [strut, inner]); - } else { - node = new mathMLTree.MathNode("mpadded", [inner]); - } - - 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"); - if (group.alignment === "llap") { - node.style.position = "relative"; - } else { - node.style.display = "flex"; - node.style.justifyContent = "center"; - } - } - 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"]; - -const padding = width => { - const node = new mathMLTree.MathNode("mspace"); - node.setAttribute("width", width + "em"); - return node -}; - -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"; - if (node.children.length === 1 && node.children[0].text && node.children[0].text === "∇") { - node.setAttribute("mathvariant", "normal"); - } - } else { - node = new mathMLTree.MathNode("mi", inner); - } - } else { - node = new mathMLTree.MathNode("mrow", inner); - 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("mrow", 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 (node.type === "mrow") { - if (doSpacing ) { - if (group.mclass === "mbin") { - // medium space - node.children.unshift(padding(0.2222)); - node.children.push(padding(0.2222)); - } else if (group.mclass === "mrel") { - // thickspace - node.children.unshift(padding(0.2778)); - node.children.push(padding(0.2778)); - } else if (group.mclass === "mpunct") { - node.children.push(padding(0.1667)); - } else if (group.mclass === "minner") { - node.children.unshift(padding(0.0556)); // 1 mu is the most likely option - node.children.push(padding(0.0556)); - } - } - } else { - 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 (symbols[parser.mode][arg.text]) { - mord.text += symbols[parser.mode][arg.text].replace; - } else 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, true); - return inner[0] - } else { - return buildExpressionRow(group.body, style) - } - } -}); - -// 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"]; - -// 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 setSpacing = node => { - // The user wrote a \mathop{…} function. Change spacing from default to OP spacing. - // The most likely spacing for an OP is a thin space per TeXbook p170. - node.attributes.lspace = "0.1667em"; - node.attributes.rspace = "0.1667em"; -}; - -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 (noSuccessor.includes(group.name)) { - node.setAttribute("largeop", "false"); - } else { - node.setAttribute("movablelimits", "false"); - } - if (group.fromMathOp) { setSpacing(node); } - } else if (group.body) { - // This is an operator with children. Add them. - node = new MathNode("mo", buildExpression(group.body, style)); - if (group.fromMathOp) { setSpacing(node); } - } 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")]); - const row = [node, operator]; - // Set spacing - if (group.needsLeadingSpace) { - const lead = new MathNode("mspace"); - lead.setAttribute("width", "0.1667em"); // thin space. - row.unshift(lead); - } - if (!group.isFollowedByDelimiter) { - const trail = new MathNode("mspace"); - trail.setAttribute("width", "0.1667em"); // thin space. - row.push(trail); - } - node = new MathNode("mrow", row); - } - } - - 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", - "\u2a09": "\\bigtimes" -}; - -defineFunction({ - type: "op", - names: [ - "\\coprod", - "\\bigvee", - "\\bigwedge", - "\\biguplus", - "\\bigcap", - "\\bigcup", - "\\intop", - "\\prod", - "\\sum", - "\\bigotimes", - "\\bigoplus", - "\\bigodot", - "\\bigsqcap", - "\\bigsqcup", - "\\bigtimes", - "\\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, - fromMathOp: true, - 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 && ordTypes.includes(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 && ordTypes.includes(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++) { - let node = expression[i]; - if (node instanceof mathMLTree.MathNode) { - if (node.type === "mrow" && node.children.length === 1 && - node.children[0] instanceof mathMLTree.MathNode) { - node = node.children[0]; - } - 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 - && ["mover", "munder"].includes(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); - if (expression[0].text.length === 1) { - 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")]); - const fragment = [wrapper, operator]; - 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. - fragment.unshift(space); - } - if (!group.isFollowedByDelimiter) { - const trail = new mathMLTree.MathNode("mspace"); - trail.setAttribute("width", "0.1667em"); // thin space. - fragment.push(trail); - } - return mathMLTree.newDocumentFragment(fragment) - } - - 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; - const next = parser.gullet.future().text; - return { - type: "operatorname", - mode: parser.mode, - body: ordargument(body), - alwaysHandleSupSub: (funcName === "\\operatornamewithlimits"), - limits: false, - parentIsSupSub: false, - isFollowedByDelimiter: isDelimiter(next), - needsLeadingSpace: prevAtomType.length > 0 && ordTypes.includes(prevAtomType) - }; - }, - mathmlBuilder: mathmlBuilder$1 -}); - -defineMacro("\\operatorname", - "\\@ifstar\\operatornamewithlimits\\operatorname@"); - -defineFunctionBuilders({ - type: "ordgroup", - mathmlBuilder(group, style) { - return buildExpressionRow(group.body, style, group.semisimple); - } -}); - -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; - } -}); - -// In LaTeX, \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 font-weight:bold. - -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", "font-weight:bold"); - return node - } -}); - -// \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); - // Add padding, which acts to increase height in Chromium. - // TODO: Figure out some way to change height in Firefox w/o breaking Chromium. - if (dy.number > 0) { - node.style.padding = dy.number + dy.unit + " 0 0 0"; - } else { - node.style.padding = "0 0 " + Math.abs(dy.number) + dy.unit + " 0"; - } - 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: "reflect", - names: ["\\reflectbox"], - props: { - numArgs: 1, - argTypes: ["hbox"], - allowedInText: true - }, - handler({ parser }, args) { - return { - type: "reflect", - mode: parser.mode, - body: args[0] - }; - }, - mathmlBuilder(group, style) { - const node = buildGroup$1(group.body, style); - node.style.transform = "scaleX(-1)"; - 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, true); - 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, true); - - 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 appendSpace = 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; - appendSpace = appendApplyFunction && !group.isFollowedByDelimiter; - 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) { - const sup = buildGroup$1(group.sup, childStyle); - const testNode = sup.type === "mrow" ? sup.children[0] : sup; - if ((testNode.type === "mo" && testNode.classes.includes("tml-prime")) - && group.base && group.base.text && group.base.text === "f") { - // Chromium does not address italic correction on prime. Prevent f′ from overlapping. - testNode.classes.push("prime-pad"); - } - children.push(sup); - } - - 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]); - } - if (appendSpace) { - const space = new mathMLTree.MathNode("mspace"); - space.setAttribute("width", "0.1667em"); // thin space. - node.children.push(space); - } - } 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"]; - -const arrows = ["\\Rsh", "\\Lsh", "\\restriction"]; - -const isArrow = str => { - if (str.length === 1) { - const codePoint = str.codePointAt(0); - return (0x218f < codePoint && codePoint < 0x2200) - } - return str.indexOf("arrow") > -1 || str.indexOf("harpoon") > -1 || arrows.includes(str) -}; - -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 (group.family === "rel" && isArrow(group.text)) { - 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" -}; - -/** - * 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" - } - - 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 0x1D317 }, - "italic": ch => { return 0x1D351 }, - // \boldsymbol actually returns upright bold for upperCaseGreek - "bold-italic": ch => { return 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 0x1D3C5 }, - "sans-serif-bold": ch => { return 0x1D3C5 }, - "sans-serif-italic": ch => { return 0 }, - "sans-serif-bold-italic": ch => { return 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) - ? "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,.]*\d)?$/; -const latinRegEx = /[A-Ba-z]/; -const primes = new Set(["\\prime", "\\dprime", "\\trprime", "\\qprime", - "\\backprime", "\\backdprime", "\\backtrprime"]); - -const italicNumber = (text, variant, tag) => { - const mn = new mathMLTree.MathNode(tag, [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("mrow", [node]); - } - } - 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 (numberRegEx.test(group.text)) { - const tag = group.mode === "text" ? "mtext" : "mn"; - if (variant === "italic" || variant === "bold-italic") { - return italicNumber(text, variant, tag) - } else { - if (variant !== "normal") { - text.text = text.text.split("").map(c => variantChar(c, variant)).join(""); - } - node = new mathMLTree.MathNode(tag, [text]); - } - } else if (group.mode === "text") { - if (variant !== "normal") { - text.text = variantChar(text.text, variant); - } - node = new mathMLTree.MathNode("mtext", [text]); - } else if (primes.has(group.text)) { - node = new mathMLTree.MathNode("mo", [text]); - // TODO: If/when Chromium uses ssty variant for prime, remove the next line. - node.classes.push("tml-prime"); - } 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 consolidateText(mrow) - } -}); - -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 - "([!-\\[\\]-\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(tokenRegexString, '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 local `set` take constant time, while global - * `set` takes time proportional to the depth of group nesting. - */ - -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 optionally set it globally too. - * Local set() sets the current value and (when appropriate) adds an undo - * operation to the undo stack. Global set() may change the undo - * operation at every level, so takes time linear in their number. - */ - set(name, value, global = false) { - if (global) { - // Global set is equivalent to setting in all groups. Simulate this - // by destroying any undos currently scheduled for this name, - // and adding an undo with the *new* value (in case it later gets - // locally reset within this environment). - for (let i = 0; i < this.undefStack.length; i++) { - delete this.undefStack[i][name]; - } - if (this.undefStack.length > 0) { - this.undefStack[this.undefStack.length - 1][name] = value; - } - } else { - // 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}}`; -}); - -function recreateArgStr(context) { - // Recreate the macro's original argument string from the array of parse tokens. - const tokens = context.consumeArgs(1)[0]; - let str = ""; - let expectedLoc = tokens[tokens.length - 1].loc.start; - for (let i = tokens.length - 1; i >= 0; i--) { - const actualLoc = tokens[i].loc.start; - if (actualLoc > expectedLoc) { - // context.consumeArgs has eaten a space. - str += " "; - expectedLoc = actualLoc; - } - str += tokens[i].text; - expectedLoc += tokens[i].text.length; - } - return str -} - -// The Latin Modern font renders at the wrong vertical alignment. -// This macro provides a better rendering. -defineMacro("\\surd", '\\sqrt{\\vphantom{|}}'); - -// See comment for \oplus in symbols.js. -defineMacro("\u2295", "\\oplus"); - -// 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", "{\\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}"); - -// \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", - "\\bigtimes": "\\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 (["bin", "rel"].includes(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"); - -defineMacro("\\AA", "\\TextOrMath{\\Angstrom}{\\mathring{A}}\\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}"); - -////////////////////////////////////////////////////////////////////// -// MnSymbol.sty - -defineMacro("\\leftmodels", "\\mathop{\\reflectbox{$\\models$}}"); - -////////////////////////////////////////////////////////////////////// -// 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"); -// A helper for \Braket and \Set -const replaceVert = (argStr, match) => { - const ch = match[0] === "|" ? "\\vert" : "\\Vert"; - const replaceStr = `}\\,\\middle${ch}\\,{`; - return argStr.slice(0, match.index) + replaceStr + argStr.slice(match.index + match[0].length) -}; -defineMacro("\\Braket", function(context) { - let argStr = recreateArgStr(context); - const regEx = /\|\||\||\\\|/g; - let match; - while ((match = regEx.exec(argStr)) !== null) { - argStr = replaceVert(argStr, match); - } - return "\\left\\langle{" + argStr + "}\\right\\rangle" -}); -defineMacro("\\Set", function(context) { - let argStr = recreateArgStr(context); - const match = /\|\||\||\\\|/.exec(argStr); - if (match) { - argStr = replaceVert(argStr, match); - } - return "\\left\\{\\:{" + argStr + "}\\:\\right\\}" -}); -defineMacro("\\set", function(context) { - const argStr = recreateArgStr(context); - return "\\{{" + argStr.replace(/\|/, "}\\mid{") + "}\\}" -}); - -////////////////////////////////////////////////////////////////////// -// 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) ; 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: - throw ["MhchemBugT", "mhchem bug T. Please report."]; // Missing texify rule or unknown MhchemParser output - } - 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: - 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: - 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: - throw ["MhchemBugT", "mhchem bug T. Please report."]; - } - } - }; - -/* 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 the number of such tokens will be - * returned. This number might be zero or positive. - * - * If not, the return value is `false`, and the next token remains at the - * top of the stack. - * - * In either case, the next token will be on the top of the stack, - * or the stack will be empty (in case of empty expansion - * and no other tokens). - * - * 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 false; - } - 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.length; - } - - /** - * 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 (;;) { - if (this.expandOnce() === false) { // fully expanded - const token = this.stack.pop(); - // The token after \noexpand is interpreted as if its meaning were ‘\relax’ - if (token.treatAsRelax) { - token.text = "\\relax"; - } - return token - } - } - - // 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) { - // Expand only expandable tokens - if (this.expandOnce(true) === false) { // fully expanded - const token = this.stack.pop(); - if (token.treatAsRelax) { - // the expansion of \noexpand is the token itself - token.noexpand = false; - token.treatAsRelax = false; - } - output.push(token); - } - } - 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; - } -} - -// 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': 'θ' -}); - -// Used for Unicode input of calligraphic and script letters -const asciiFromScript = Object.freeze({ - "\ud835\udc9c": "A", - "\u212c": "B", - "\ud835\udc9e": "C", - "\ud835\udc9f": "D", - "\u2130": "E", - "\u2131": "F", - "\ud835\udca2": "G", - "\u210B": "H", - "\u2110": "I", - "\ud835\udca5": "J", - "\ud835\udca6": "K", - "\u2112": "L", - "\u2133": "M", - "\ud835\udca9": "N", - "\ud835\udcaa": "O", - "\ud835\udcab": "P", - "\ud835\udcac": "Q", - "\u211B": "R", - "\ud835\udcae": "S", - "\ud835\udcaf": "T", - "\ud835\udcb0": "U", - "\ud835\udcb1": "V", - "\ud835\udcb2": "W", - "\ud835\udcb3": "X", - "\ud835\udcb4": "Y", - "\ud835\udcb5": "Z" -}); - -// 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 binLeftCancellers = ["bin", "op", "open", "punct", "rel"]; - -/** - * 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", "&"]; - } - - /** - * Fully parse a separate sequence of tokens as a separate job. - * Tokens should be specified in reverse order, as in a MacroDefinition. - */ - subparse(tokens) { - // Save the next token from the current job. - const oldToken = this.nextToken; - this.consume(); - - // Run the new job, terminating it with an excess '}' - this.gullet.pushToken(new Token("}")); - this.gullet.pushTokens(tokens); - const parse = this.parseExpression(false); - this.expect("}"); - - // Restore the next token from the current job. - this.nextToken = oldToken; - - return parse; - } - -/** - * 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 precedence 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. - * - * `breakOnMiddle`: \color, \over, and old styling functions work on an implicit group. - * These groups end just before the usual tokens, but they also - * end just before `\middle`. - */ - parseExpression(breakOnInfix, breakOnTokenText, breakOnMiddle) { - 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 (breakOnMiddle && lex.text === "\\middle") { - 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. - const isSub = unicodeSubRegEx.test(lex.text); - const subsupTokens = []; - subsupTokens.push(new Token(uSubsAndSups[lex.text])); - this.consume(); - // Continue fetching tokens to fill out the group. - while (true) { - const token = this.fetch().text; - if (!(uSubsAndSups[token])) { break } - if (unicodeSubRegEx.test(token) !== isSub) { break } - subsupTokens.unshift(new Token(uSubsAndSups[token])); - this.consume(); - } - // Now create a (sub|super)script. - const body = this.subparse(subsupTokens); - 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 - const isFollowedByDelimiter = (!base || base.type !== "op" && base.type !== "operatorname") - ? undefined - : isDelimiter(this.nextToken.text); - return { - type: "supsub", - mode: this.mode, - base: base, - sup: superscript, - sub: subscript, - isFollowedByDelimiter - } - } - } 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 (true) { - const ch = this.fetch().text; - // \ufe0e is the Unicode variation selector to supress emoji. Ignore it. - if (ch === " " || ch === "\u00a0" || ch === "\ufe0e") { - this.consume(); - } else { - break - } - } - } - - /** - * 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/ - 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]) { - let group = symbols[this.mode][text].group; - if (group === "bin" && binLeftCancellers.includes(this.prevAtomType)) { - // Change from a binary operator to a unary (prefix) operator - group = "open"; - } - 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 { - if (asciiFromScript[text]) { - // Unicode 14 disambiguates chancery from roundhand. - // See https://www.unicode.org/charts/PDF/U1D400.pdf - this.consume(); - const nextCode = this.fetch().text.charCodeAt(0); - // mathcal is Temml default. Use mathscript if called for. - const font = nextCode === 0xfe01 ? "mathscr" : "mathcal"; - if (nextCode === 0xfe00 || nextCode === 0xfe01) { this.consume(); } - return { - type: "font", - mode: "math", - font, - body: { type: "mathord", mode: "math", loc, text: asciiFromScript[text] } - } - } - // Default ord character. No disambiguation necessary. - s = { - type: group, - mode: this.mode, - loc, - text - }; - } - symbol = s; - } else if (text.charCodeAt(0) >= 0x80) { - // no symbol for e.g. ^ - if (this.settings.strict && 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, - 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, - * 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.10.23"; - -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 */ - -/** - * @type {import('./temml').render} - * Parse and build an expression, and place that expression in the DOM node - * given. - */ -let render$1 = function(expression, baseNode, options = {}) { - baseNode.textContent = ""; - const alreadyInMathElement = baseNode.tagName.toLowerCase() === "math"; - if (alreadyInMathElement) { options.wrap = "none"; } - const math = renderToMathMLTree(expression, options); - if (alreadyInMathElement) { - // The element already exists. Populate it. - baseNode.textContent = ""; - math.children.forEach(e => { baseNode.appendChild(e.toNode()); }); - } else if (math.children.length > 1) { - 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$1 = function() { - throw new ParseError("Temml doesn't work in quirks mode."); - }; - } -} - -/** - * @type {import('./temml').renderToString} - * Parse and build an expression, and return the markup for that. - */ -const renderToString = function(expression, options) { - const markup = renderToMathMLTree(expression, options).toMarkup(); - return markup; -}; - -/** - * @type {import('./temml').generateParseTree} - * Parse an expression and return the parse tree. - */ -const generateParseTree = function(expression, options) { - const settings = new Settings(options); - return parseTree(expression, settings); -}; - -/** - * @type {import('./temml').definePreamble} - * 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; -}; - -/** - * @type {import('./temml').renderToMathMLTree} - * 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); - } -}; - -/** @type {import('./temml').default} */ -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: render$1, - /** - * 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 -}; - -/* - * This file bundles together and exposes the calculation parts of Hurmet. - * I use Rollup to create a UMD module from this code. - * That way, one file can expose the same functionality to (1) the Hurmet.org web page, - * (2) the REPL in the reference manual, (3) the script that transpiles - * the Hurmet reference manual from Markdown to HTML, and (4) unit testing. - * - * Some of Hurmet’s exported functions are valuable only to the Hurmet.org web page. - * If you wish to use Hurmet’s math parsing and/or calculation abilities, - * the two functions you want are: - * parse(entry: string, decimalFormat?: string) - * calculate(entry: string, vars?: Object, draftMode?: boolean, decimalFormat?: string) - * - * parse() returns a TeX string. - * calculate() returns either a TeX string or a string in Hurmet calculation syntax. - */ - -const render = (tex, dom, options) => { - temml.render(tex, dom, options); -}; - -var hurmet = { - parse: parse$1, - calculate, - compile, - md2ast, - md2html, - scanModule, - updateCalculations, - render, - Rnl -}; - -module.exports = hurmet; 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. - */ - -/** - * 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), or `null` if URL has invalid protocol - * (so should be outright rejected). - */ -const protocolFromUrl = function(url) { - // Check for possible leading protocol. - // https://url.spec.whatwg.org/#url-parsing strips leading whitespace - // (\x00) or C0 control (\x00-\x1F) characters. - // eslint-disable-next-line no-control-regex - const protocol = /^[\x00-\x20]*([^\\/#?]*?)(:|�*58|�*3a|&colon)/i.exec(url); - if (!protocol) { - return "_relative"; - } - // Reject weird colons - if (protocol[2] !== ":") { - return null; - } - // Reject invalid characters in scheme according to - // https://datatracker.ietf.org/doc/html/rfc3986#section-3.1 - if (!/^[a-zA-Z][a-zA-Z0-9+\-.]*$/.test(protocol[1])) { - return null; - } - // Lowercase the protocol - return protocol[1].toLowerCase(); -}; - -/** - * 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 = { - 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.leqno = utils.deflt(options.leqno, false); // boolean - this.throwOnError = utils.deflt(options.throwOnError, false); // boolean - this.errorColor = utils.deflt(options.errorColor, "#b22222"); // string - this.macros = options.macros || {}; - this.wrap = utils.deflt(options.wrap, "tex"); // "tex" | "=" - 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) { - const protocol = utils.protocolFromUrl(context.url); - if (protocol == null) { - return false - } - context.protocol = protocol; - } - 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 this.classes.includes(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 this.classes.includes(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 itself). - */ - 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. - */ - -// TODO: Remove when Chromium stretches \widetilde & \widehat -const estimatedWidth = node => { - let width = 0; - if (node.body) { - for (const item of node.body) { - width += estimatedWidth(item); - } - } else if (node.type === "supsub") { - width += estimatedWidth(node.base); - if (node.sub) { width += 0.7 * estimatedWidth(node.sub); } - if (node.sup) { width += 0.7 * estimatedWidth(node.sup); } - } else if (node.type === "mathord" || node.type === "textord") { - for (const ch of node.text.split('')) { - const codePoint = ch.codePointAt(0); - if ((0x60 < codePoint && codePoint < 0x7B) || (0x03B0 < codePoint && codePoint < 0x3CA)) { - width += 0.56; // lower case latin or greek. Use advance width of letter n - } else if (0x2F < codePoint && codePoint < 0x3A) { - width += 0.50; // numerals. - } else { - width += 0.92; // advance width of letter M - } - } - } else { - width += 1.0; - } - return width -}; - -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 -}; - -const crookedWides = ["\\widetilde", "\\widehat", "\\widecheck", "\\utilde"]; - -// TODO: Remove when Chromium stretches \widetilde & \widehat -const accentNode = (group) => { - const mo = mathMLnode(group.label); - if (crookedWides.includes(group.label)) { - const width = estimatedWidth(group.base); - if (1 < width && width < 1.6) { - mo.classes.push("tml-crooked-2"); - } else if (1.6 <= width && width < 2.5) { - mo.classes.push("tml-crooked-3"); - } else if (2.5 <= width) { - mo.classes.push("tml-crooked-4"); - } - } - return mo -}; - -var stretchy = { - mathMLnode, - accentNode -}; - -/** - * 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, "\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"); -// unicodemath -defineSymbol(math, rel, "\u2a75", "\\eqeq", true); -defineSymbol(math, rel, "\u2a76", "\\eqeqeq", true); -// 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); -// ∇ is actually a unary operator, not binary. But this works. -defineSymbol(math, bin, "\u2207", "\\nabla", true); -defineSymbol(math, textord, "\u266d", "\\flat", true); -defineSymbol(math, textord, "\u2113", "\\ell", true); -defineSymbol(math, textord, "\u266e", "\\natural", true); -defineSymbol(math, textord, "Å", "\\Angstrom", true); -defineSymbol(text, textord, "Å", "\\Angstrom", 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 -defineSymbol(math, bin, "\u2AFD", "\\sslash", true); // from stmaryrd - -// 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, "\u21a4", "\\mapsfrom", 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, "\u220E", "\\QED", true); -defineSymbol(math, mathord, "\u2030", "\\permil", true); -defineSymbol(text, textord, "\u2030", "\\permil"); -defineSymbol(math, mathord, "\u2609", "\\astrosun", true); -defineSymbol(math, mathord, "\u263c", "\\sun", true); -defineSymbol(math, mathord, "\u263e", "\\leftmoon", true); -defineSymbol(math, mathord, "\u263d", "\\rightmoon", true); -defineSymbol(math, mathord, "\u2295", "\\Earth"); - -// 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, "\u2036", "\\backdprime"); -defineSymbol(math, textord, "\u2037", "\\backtrprime"); -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, "\u22ab", "\\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, "\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); -defineSymbol(math, bin, "\u22c8", "\\bowtie", true); -defineSymbol(math, bin, "\u22c8", "\\Join"); -defineSymbol(math, bin, "\u27d5", "\\leftouterjoin", true); -defineSymbol(math, bin, "\u27d6", "\\rightouterjoin", true); -defineSymbol(math, bin, "\u27d7", "\\fullouterjoin", true); - -// stix Binary Operators -defineSymbol(math, bin, "\u2238", "\\dotminus", true); -defineSymbol(math, bin, "\u27D1", "\\wedgedot", true); -defineSymbol(math, bin, "\u27C7", "\\veedot", true); -defineSymbol(math, bin, "\u2A62", "\\doublebarvee", true); -defineSymbol(math, bin, "\u2A63", "\\veedoublebar", true); -defineSymbol(math, bin, "\u2A5F", "\\wedgebar", true); -defineSymbol(math, bin, "\u2A60", "\\wedgedoublebar", true); -defineSymbol(math, bin, "\u2A54", "\\Vee", true); -defineSymbol(math, bin, "\u2A53", "\\Wedge", true); -defineSymbol(math, bin, "\u2A43", "\\barcap", true); -defineSymbol(math, bin, "\u2A42", "\\barcup", true); -defineSymbol(math, bin, "\u2A48", "\\capbarcup", true); -defineSymbol(math, bin, "\u2A40", "\\capdot", true); -defineSymbol(math, bin, "\u2A47", "\\capovercup", true); -defineSymbol(math, bin, "\u2A46", "\\cupovercap", true); -defineSymbol(math, bin, "\u2A4D", "\\closedvarcap", true); -defineSymbol(math, bin, "\u2A4C", "\\closedvarcup", true); -defineSymbol(math, bin, "\u2A2A", "\\minusdot", true); -defineSymbol(math, bin, "\u2A2B", "\\minusfdots", true); -defineSymbol(math, bin, "\u2A2C", "\\minusrdots", true); -defineSymbol(math, bin, "\u22BB", "\\Xor", true); -defineSymbol(math, bin, "\u22BC", "\\Nand", true); -defineSymbol(math, bin, "\u22BD", "\\Nor", true); -defineSymbol(math, bin, "\u22BD", "\\barvee"); -defineSymbol(math, bin, "\u2AF4", "\\interleave", true); -defineSymbol(math, bin, "\u29E2", "\\shuffle", true); -defineSymbol(math, bin, "\u2AF6", "\\threedotcolon", true); -defineSymbol(math, bin, "\u2982", "\\typecolon", true); -defineSymbol(math, bin, "\u223E", "\\invlazys", true); -defineSymbol(math, bin, "\u2A4B", "\\twocaps", true); -defineSymbol(math, bin, "\u2A4A", "\\twocups", true); -defineSymbol(math, bin, "\u2A4E", "\\Sqcap", true); -defineSymbol(math, bin, "\u2A4F", "\\Sqcup", true); -defineSymbol(math, bin, "\u2A56", "\\veeonvee", true); -defineSymbol(math, bin, "\u2A55", "\\wedgeonwedge", true); -defineSymbol(math, bin, "\u29D7", "\\blackhourglass", true); -defineSymbol(math, bin, "\u29C6", "\\boxast", true); -defineSymbol(math, bin, "\u29C8", "\\boxbox", true); -defineSymbol(math, bin, "\u29C7", "\\boxcircle", true); -defineSymbol(math, bin, "\u229C", "\\circledequal", true); -defineSymbol(math, bin, "\u29B7", "\\circledparallel", true); -defineSymbol(math, bin, "\u29B6", "\\circledvert", true); -defineSymbol(math, bin, "\u29B5", "\\circlehbar", true); -defineSymbol(math, bin, "\u27E1", "\\concavediamond", true); -defineSymbol(math, bin, "\u27E2", "\\concavediamondtickleft", true); -defineSymbol(math, bin, "\u27E3", "\\concavediamondtickright", true); -defineSymbol(math, bin, "\u22C4", "\\diamond", true); -defineSymbol(math, bin, "\u29D6", "\\hourglass", true); -defineSymbol(math, bin, "\u27E0", "\\lozengeminus", true); -defineSymbol(math, bin, "\u233D", "\\obar", true); -defineSymbol(math, bin, "\u29B8", "\\obslash", true); -defineSymbol(math, bin, "\u2A38", "\\odiv", true); -defineSymbol(math, bin, "\u29C1", "\\ogreaterthan", true); -defineSymbol(math, bin, "\u29C0", "\\olessthan", true); -defineSymbol(math, bin, "\u29B9", "\\operp", true); -defineSymbol(math, bin, "\u2A37", "\\Otimes", true); -defineSymbol(math, bin, "\u2A36", "\\otimeshat", true); -defineSymbol(math, bin, "\u22C6", "\\star", true); -defineSymbol(math, bin, "\u25B3", "\\triangle", true); -defineSymbol(math, bin, "\u2A3A", "\\triangleminus", true); -defineSymbol(math, bin, "\u2A39", "\\triangleplus", true); -defineSymbol(math, bin, "\u2A3B", "\\triangletimes", true); -defineSymbol(math, bin, "\u27E4", "\\whitesquaretickleft", true); -defineSymbol(math, bin, "\u27E5", "\\whitesquaretickright", true); -defineSymbol(math, bin, "\u2A33", "\\smashtimes", 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, "¢", "\\cent"); -defineSymbol(text, textord, "¢", "\\cent"); -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, "\u2033", "\\dprime"); -defineSymbol(math, textord, "\u2034", "\\trprime"); -defineSymbol(math, textord, "\u2057", "\\qprime"); -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, "\u2300", "\\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", "/", true); -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, "\u27ea", "\\lAngle", true); -defineSymbol(math, open, "\u2989", "\\llangle", 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, "\u27eb", "\\rAngle", true); -defineSymbol(math, close, "\u298a", "\\rrangle", 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"); -defineSymbol(math, bin, "\u22bb", "\\veebar"); -defineSymbol(math, bin, "\u2299", "\\odot", true); -// Firefox turns ⊕ into an emoji. So append \uFE0E. Define Unicode character in macros, not here. -defineSymbol(math, bin, "\u2295\uFE0E", "\\oplus"); -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, "\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(math, open, "⦇", "\\llparenthesis", true); -defineSymbol(math, close, "⦈", "\\rrparenthesis", 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, "\u2a09", "\\bigtimes"); -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, "\u2026", "\\dddot"); -defineSymbol(math, accent, "\u2026\u002e", "\\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, "\u2192", "\\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"); -defineSymbol(math, textord, "\u2300", "\\diameter", true); -defineSymbol(text, textord, "\u2300", "\\diameter"); - -// 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. - * - * The default is for 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. - * - * An option is for soft line breaks before an "=" sign. That changes the s. - * - * 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. - */ - -const openDelims = "([{⌊⌈⟨⟮⎰⟦⦃"; -const closeDelims = ")]}⌋⌉⟩⟯⎱⟦⦄"; - -function setLineBreaks(expression, wrapMode, isDisplayMode) { - const mtrs = []; - let mrows = []; - let block = []; - let numTopLevelEquals = 0; - let i = 0; - let level = 0; - while (i < expression.length) { - while (expression[i] instanceof DocumentFragment) { - expression.splice(i, 1, ...expression[i].children); // Expand the fragment. - } - const node = expression[i]; - if (node.attributes && node.attributes.linebreak && - node.attributes.linebreak === "newline") { - // A hard line break. Create a for the current block. - if (block.length > 0) { - mrows.push(new mathMLTree.MathNode("mrow", block)); - } - mrows.push(node); - block = []; - const mtd = new mathMLTree.MathNode("mtd", mrows); - mtd.style.textAlign = "left"; - mtrs.push(new mathMLTree.MathNode("mtr", [mtd])); - mrows = []; - i += 1; - continue - } - block.push(node); - if (node.type && node.type === "mo" && node.children.length === 1 && - !Object.hasOwn(node.attributes, "movablelimits")) { - const ch = node.children[0].text; - if (openDelims.indexOf(ch) > -1) { - level += 1; - } else if (closeDelims.indexOf(ch) > -1) { - level -= 1; - } else if (level === 0 && wrapMode === "=" && ch === "=") { - numTopLevelEquals += 1; - if (numTopLevelEquals > 1) { - block.pop(); - // Start a new block. (Insert a soft linebreak.) - const element = new mathMLTree.MathNode("mrow", block); - mrows.push(element); - block = [node]; - } - } else if (level === 0 && wrapMode === "tex" && ch !== "∇") { - // 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("mrow", block); - mrows.push(element); - block = []; - } - } - } - i += 1; - } - if (block.length > 0) { - const element = new mathMLTree.MathNode("mrow", block); - mrows.push(element); - } - if (mtrs.length > 0) { - const mtd = new mathMLTree.MathNode("mtd", mrows); - mtd.style.textAlign = "left"; - 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 corresponding 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); -}; - -const consolidateText = mrow => { - // If possible, consolidate adjacent elements into a single element. - if (mrow.type !== "mrow" && mrow.type !== "mstyle") { return mrow } - if (mrow.children.length === 0) { return mrow } // empty group, e.g., \text{} - if (!mrow.children[0].attributes || mrow.children[0].type !== "mtext") { return mrow } - const variant = mrow.children[0].attributes.mathvariant || ""; - const mtext = new mathMLTree.MathNode( - "mtext", - [new mathMLTree.TextNode(mrow.children[0].children[0].text)] - ); - 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; - } - } - // 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"; - } - for (const [key, value] of Object.entries(mrow.attributes)) { - mtext.attributes[key] = value; - } - return mtext -}; - -const numberRegEx$1 = /^[0-9]$/; -const isDotOrComma = (node, followingNode) => { - return ((node.type === "textord" && node.text === ".") || - (node.type === "atom" && node.text === ",")) && - // Don't consolidate if there is a space after the comma. - node.loc && followingNode.loc && node.loc.end === followingNode.loc.start -}; -const consolidateNumbers = expression => { - // Consolidate adjacent numbers. We want to return 1,506.3, - // not 1,506.3 - if (expression.length < 2) { return } - const nums = []; - let inNum = false; - // Find adjacent numerals - for (let i = 0; i < expression.length; i++) { - const node = expression[i]; - if (node.type === "textord" && numberRegEx$1.test(node.text)) { - if (!inNum) { nums.push({ start: i }); } - inNum = true; - } else { - if (inNum) { nums[nums.length - 1].end = i - 1; } - inNum = false; - } - } - if (inNum) { nums[nums.length - 1].end = expression.length - 1; } - - // Determine if numeral groups are separated by a comma or dot. - for (let i = nums.length - 1; i > 0; i--) { - if (nums[i - 1].end === nums[i].start - 2 && - isDotOrComma(expression[nums[i].start - 1], expression[nums[i].start])) { - // Merge the two groups. - nums[i - 1].end = nums[i].end; - nums.splice(i, 1); - } - } - - // Consolidate the number nodes - for (let i = nums.length - 1; i >= 0; i--) { - for (let j = nums[i].start + 1; j <= nums[i].end; j++) { - expression[nums[i].start].text += expression[j].text; - } - expression.splice(nums[i].start + 1, nums[i].end - nums[i].start); - // Check if the is followed by a numeric base in a supsub, e.g. the "3" in 123^4 - // If so, merge the first into the base. - if (expression.length > nums[i].start + 1) { - const nextTerm = expression[nums[i].start + 1]; - if (nextTerm.type === "supsub" && nextTerm.base && nextTerm.base.type === "textord" && - numberRegEx$1.test(nextTerm.base.text)) { - nextTerm.base.text = expression[nums[i].start].text + nextTerm.base.text; - expression.splice(nums[i].start, 1); - } - } - } -}; - -/** - * 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, semisimple = false) { - if (body.length === 1 && !(body[0] instanceof DocumentFragment)) { - return body[0]; - } else if (!semisimple) { - // Suppress spacing on nodes at both ends of the row. - if (body[0] instanceof MathNode && body[0].type === "mo" && !body[0].attributes.fence) { - body[0].attributes.lspace = "0em"; - body[0].attributes.rspace = "0em"; - } - const end = body.length - 1; - if (body[end] instanceof MathNode && body[end].type === "mo" && !body[end].attributes.fence) { - body[end].attributes.lspace = "0em"; - body[end].attributes.rspace = "0em"; - } - } - 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, semisimple = false) { - if (!semisimple && expression.length === 1) { - const group = buildGroup$1(expression[0], style); - if (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]; - } - - consolidateNumbers(expression); - - 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, semisimple = false) { - return makeRow(buildExpression(expression, style, semisimple), semisimple); -}; - -/** - * 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$1 = _ => { - return new mathMLTree.MathNode("mtd", [], [], { padding: "0", width: "50%" }) -}; - -const taggedExpression = (expression, tag, style, leqno) => { - tag = buildExpressionRow(tag[0].body, style); - tag = consolidateText(tag); - tag.classes.push("tml-tag"); - - expression = new mathMLTree.MathNode("mtd", [expression]); - const rowArray = [glue$1(), expression, glue$1()]; - rowArray[leqno ? 0 : 2].classes.push(leqno ? "tml-left" : "tml-right"); - rowArray[leqno ? 0 : 2].children.push(tag); - const mtr = new mathMLTree.MathNode("mtr", rowArray, ["tml-tageqn"]); - const table = new mathMLTree.MathNode("mtable", [mtr]); - table.style.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 wrap = (settings.displayMode || settings.annotate) ? "none" : settings.wrap; - - const n1 = expression.length === 0 ? null : expression[0]; - let wrapper = expression.length === 1 && tag === null && (n1 instanceof MathNode) - ? expression[0] - : setLineBreaks(expression, wrap, settings.displayMode); - - if (tag) { - wrapper = taggedExpression(wrapper, tag, style, settings.leqno); - } - - 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"); - wrapper = new mathMLTree.MathNode("semantics", [wrapper, annotation]); - } - - const math = 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"); - math.style.display = "block math"; // necessary in Chromium. - // Firefox and Safari do not recognize display: "block math". - // Set a class so that the CSS file can set display: block. - math.classes = ["tml-display"]; - } - return math; -} - -const smalls = "acegıȷmnopqrsuvwxyzαγεηικμνοπρςστυχωϕ𝐚𝐜𝐞𝐠𝐦𝐧𝐨𝐩𝐪𝐫𝐬𝐮𝐯𝐰𝐱𝐲𝐳"; -const talls = "ABCDEFGHIJKLMNOPQRSTUVWXYZbdfhkltΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩβδλζφθψ" - + "𝐀𝐁𝐂𝐃𝐄𝐅𝐆𝐇𝐈𝐉𝐊𝐋𝐌𝐍𝐎𝐏𝐐𝐑𝐒𝐓𝐔𝐕𝐖𝐗𝐘𝐙𝐛𝐝𝐟𝐡𝐤𝐥𝐭"; -const longSmalls = new Set(["\\alpha", "\\gamma", "\\delta", "\\epsilon", "\\eta", "\\iota", - "\\kappa", "\\mu", "\\nu", "\\pi", "\\rho", "\\sigma", "\\tau", "\\upsilon", "\\chi", "\\psi", - "\\omega", "\\imath", "\\jmath"]); -const longTalls = new Set(["\\Gamma", "\\Delta", "\\Sigma", "\\Omega", "\\beta", "\\delta", - "\\lambda", "\\theta", "\\psi"]); - -const mathmlBuilder$a = (group, style) => { - const accentNode = group.isStretchy - ? stretchy.accentNode(group) - : new mathMLTree.MathNode("mo", [makeText(group.label, group.mode)]); - - if (group.label === "\\vec") { - accentNode.style.transform = "scale(0.75) translate(10%, 30%)"; - } else { - accentNode.style.mathStyle = "normal"; - accentNode.style.mathDepth = "0"; - if (needWebkitShift.has(group.label) && utils.isCharacterBox(group.base)) { - let shift = ""; - const ch = group.base.text; - if (smalls.indexOf(ch) > -1 || longSmalls.has(ch)) { shift = "tml-xshift"; } - if (talls.indexOf(ch) > -1 || longTalls.has(ch)) { shift = "tml-capshift"; } - if (shift) { accentNode.classes.push(shift); } - } - } - if (!group.isStretchy) { - accentNode.setAttribute("stretchy", "false"); - } - - const node = new mathMLTree.MathNode((group.label === "\\c" ? "munder" : "mover"), - [buildGroup$1(group.base, style), accentNode] - ); - - return node; -}; - -const nonStretchyAccents = new Set([ - "\\acute", - "\\grave", - "\\ddot", - "\\dddot", - "\\ddddot", - "\\tilde", - "\\bar", - "\\breve", - "\\check", - "\\hat", - "\\vec", - "\\dot", - "\\mathring" -]); - -const needWebkitShift = new Set([ - "\\acute", - "\\bar", - "\\breve", - "\\check", - "\\dot", - "\\ddot", - "\\grave", - "\\hat", - "\\mathring", - "\\'", "\\^", "\\~", "\\=", "\\u", "\\.", '\\"', "\\r", "\\H", "\\v" -]); - -// 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 = !nonStretchyAccents.has(context.funcName); - - return { - type: "accent", - mode: context.parser.mode, - label: context.funcName, - isStretchy: isStretchy, - 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, - 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.accentNode(group); - accentNode.style["math-depth"] = 0; - const node = new mathMLTree.MathNode("munder", [ - buildGroup$1(group.base, style), - accentNode - ]); - 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 padding$2 = width => { - const node = new mathMLTree.MathNode("mspace"); - node.setAttribute("width", width + "em"); - return node -}; - -const paddedNode = (group, lspace = 0.3, rspace = 0) => { - if (group == null && rspace === 0) { return padding$2(lspace) } - const row = group ? [group] : []; - if (lspace !== 0) { row.unshift(padding$2(lspace)); } - if (rspace > 0) { row.push(padding$2(rspace)); } - return new mathMLTree.MathNode("mrow", row) -}; - -const labelSize = (size, scriptLevel) => Number(size) / emScale(scriptLevel); - -const munderoverNode = (fName, body, below, style) => { - const arrowNode = stretchy.mathMLnode(fName); - // Is this the short part of a mhchem equilibrium arrow? - const isEq = fName.slice(1, 3) === "eq"; - const minWidth = fName.charAt(1) === "x" - ? "1.75" // mathtools extensible arrows are ≥ 1.75em long - : fName.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 - // TODO: When Firefox supports minsize, use the next line. - //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 label dimensions accordingly. - const labelStyle = style.withLevel(style.level < 2 ? 2 : 3); - const minArrowWidth = labelSize(minWidth, labelStyle.level); - // The dummyNode will be inside a inside a - // So it will be at scriptlevel 3 - const dummyWidth = labelSize(minWidth, 3); - const emptyLabel = paddedNode(null, minArrowWidth.toFixed(4), 0); - const dummyNode = paddedNode(null, dummyWidth.toFixed(4), 0); - // The arrow is a little longer than the label. Set a spacer length. - const space = labelSize((isEq ? 0 : 0.3), labelStyle.level).toFixed(4); - let upperNode; - let lowerNode; - - const gotUpper = (body && body.body && - // \hphantom visible content - (body.body.body || body.body.length > 0)); - if (gotUpper) { - let label = buildGroup$1(body, labelStyle); - label = paddedNode(label, space, space); - // Since Firefox does not support minsize, stack a invisible node - // on top of the label. Its width will serve as a min-width. - // TODO: Refactor this after Firefox supports minsize. - upperNode = new mathMLTree.MathNode("mover", [label, dummyNode]); - } - const gotLower = (below && below.body && - (below.body.body || below.body.length > 0)); - if (gotLower) { - let label = buildGroup$1(below, labelStyle); - label = paddedNode(label, space, space); - lowerNode = new mathMLTree.MathNode("munder", [label, dummyNode]); - } - - let node; - if (!gotUpper && !gotLower) { - node = new mathMLTree.MathNode("mover", [arrowNode, emptyLabel]); - } else if (gotUpper && gotLower) { - node = new mathMLTree.MathNode("munderover", [arrowNode, lowerNode, upperNode]); - } else if (gotUpper) { - node = new mathMLTree.MathNode("mover", [arrowNode, upperNode]); - } else { - node = new mathMLTree.MathNode("munder", [arrowNode, lowerNode]); - } - if (minWidth === "3.0") { node.style.height = "1em"; } // CD environment - node.setAttribute("accent", "false"); // Necessary for MS Word - 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 5 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 row = [node]; - row.unshift(padding$2(0.2778)); - row.push(padding$2(0.2778)); - return new mathMLTree.MathNode("mrow", row) - } -}); - -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", - [padding$2(0.2778), botNode, raiseNode, padding$2(0.2778)] - ); - } else { - raiseNode.setAttribute("width", (group.name === "\\equilibriumRight" ? "0.5em" : "0")); - wrapper = new mathMLTree.MathNode( - "mpadded", - [padding$2(0.2778), raiseNode, botArrow, padding$2(0.2778)] - ); - } - - wrapper.setAttribute("voffset", "-0.18em"); - wrapper.setAttribute("height", "-0.18em"); - wrapper.setAttribute("depth", "+0.18em"); - return wrapper - } -}); - -/** - * 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], - semisimple: true - }; - 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); - } - body.pop(); - - // End row group - parser.gullet.endGroup(); - // End array group defining \\ - parser.gullet.endGroup(); - - return { - type: "array", - mode: "math", - body, - envClasses: ["jot", "cd"], - cols: [], - 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(Number((num * 255).toFixed(0))); - }); - } - 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) => { - // In LaTeX, color is not supposed to change the spacing of any node. - // So instead of wrapping the group in an , we apply - // the color individually to each node and return a document fragment. - let expr = buildExpression(group.body, style.withColor(group.color)); - expr = expr.map(e => { - e.style.color = group.color; - return e - }); - return mathMLTree.newDocumentFragment(expr) -}; - -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, breakOnTokenText, 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); - } - - // Parse out the implicit body that should be colored. - const body = parser.parseExpression(true, breakOnTokenText, true); - - 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: 0, - allowedInText: true - }, - - handler({ parser }, args, optArgs) { - const size = parser.gullet.future().text === "[" ? parser.parseSizeGroup(true) : null; - 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 globalMap = { - "\\global": "\\global", - "\\long": "\\\\globallong", - "\\\\globallong": "\\\\globallong", - "\\def": "\\gdef", - "\\gdef": "\\gdef", - "\\edef": "\\xdef", - "\\xdef": "\\xdef", - "\\let": "\\\\globallet", - "\\futurelet": "\\\\globalfuture" -}; - -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, global) => { - 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, global); -}; - -// -> | -// -> |\global -// -> | -// -> \global|\long|\outer -defineFunction({ - type: "internal", - names: [ - "\\global", - "\\long", - "\\\\globallong" // can’t be entered directly - ], - props: { - numArgs: 0, - allowedInText: true - }, - handler({ parser, funcName }) { - parser.consumeSpaces(); - const token = parser.fetch(); - if (globalMap[token.text]) { - // Temml doesn't have \par, so ignore \long - if (funcName === "\\global" || funcName === "\\\\globallong") { - token.text = globalMap[token.text]; - } - return assertNodeType(parser.parseFunction(), "internal"); - } - throw new ParseError(`Invalid token after macro prefix`, token); - } -}); - -// Basic support for macro definitions: \def, \gdef, \edef, \xdef -// -> -// -> \def|\gdef|\edef|\xdef -// -> -defineFunction({ - type: "internal", - names: ["\\def", "\\gdef", "\\edef", "\\xdef"], - 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" || funcName === "\\xdef") { - tokens = parser.gullet.expandTokens(tokens); - if (tokens.length > parser.gullet.settings.maxExpand) { - throw new ParseError("Too many expansions in an " + funcName); - } - tokens.reverse(); // to fit in with stack order - } - // Final arg is the expansion of the macro - parser.gullet.macros.set( - name, - { tokens, numArgs, delimiters }, - funcName === globalMap[funcName] - ); - return { type: "internal", mode: parser.mode }; - } -}); - -// -> -// -> \futurelet -// | \let -// -> |= -defineFunction({ - type: "internal", - names: [ - "\\let", - "\\\\globallet" // can’t be entered directly - ], - 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, funcName === "\\\\globallet"); - return { type: "internal", mode: parser.mode }; - } -}); - -// ref: https://www.tug.org/TUGboat/tb09-3/tb22bechtolsheim.pdf -defineFunction({ - type: "internal", - names: [ - "\\futurelet", - "\\\\globalfuture" // can’t be entered directly - ], - 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, funcName === "\\\\globalfuture"); - 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 }, - !parser.settings.strict - ); - - 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", - "⦇", - "\\llparenthesis", - "⦈", - "\\rrparenthesis", - "\\lfloor", - "\\rfloor", - "\u230a", - "\u230b", - "\\lceil", - "\\rceil", - "\u2308", - "\u2309", - "<", - ">", - "\\langle", - "\u27e8", - "\\rangle", - "\u27e9", - "\\lAngle", - "\u27ea", - "\\rAngle", - "\u27eb", - "\\llangle", - "⦉", - "\\rrangle", - "⦊", - "\\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", - "." -]; - -// Export isDelimiter for benefit of parser. -const dels = ["}", "\\left", "\\middle", "\\right"]; -const isDelimiter = str => str.length > 0 && - (delimiters.includes(str) || delimiterSizes[str] || dels.includes(str)); - -// 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) { - const symDelim = checkSymbolNodeType(delim); - if (symDelim && delimiters.includes(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 (["/", "\u2044"].includes(symDelim.text)) { symDelim.text = "\u2215"; } - if (["<", "\\lt"].includes(symDelim.text)) { symDelim.text = "⟨"; } - if ([">", "\\gt"].includes(symDelim.text)) { symDelim.text = "⟩"; } - 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" || group.delim === "\\vert" || - group.delim === "|" || group.delim.indexOf("arrow") > -1) { - // 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) => { - return { - type: "leftright-right", - mode: context.parser.mode, - delim: checkDelimiter(args[0], context).text - }; - } -}); - -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' or `\\middle` - let body = parser.parseExpression(false, null, true); - let nextToken = parser.fetch(); - while (nextToken.text === "\\middle") { - // `\middle`, from the ε-TeX package, ends one group and starts another group. - // We had to parse this expression with `breakOnMiddle` enabled in order - // to get TeX-compliant parsing of \over. - // But we do not want, at this point, to end on \middle, so continue - // to parse until we fetch a `\right`. - parser.consume(); - const middle = parser.fetch().text; - if (!symbols.math[middle]) { - throw new ParseError(`Invalid delimiter '${middle}' after '\\middle'`); - } - checkDelimiter({ type: "atom", mode: "math", text: middle }, { funcName: "\\middle" }); - body.push({ type: "middle", mode: "math", delim: middle }); - parser.consume(); - body = body.concat(parser.parseExpression(false, null, true)); - nextToken = parser.fetch(); - } - --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 - }; - }, - 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" || group.left.indexOf("arrow") > -1) { - 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" || group.right.indexOf("arrow") > -1) { - rightNode.setAttribute("stretchy", "true"); - } - 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"); - if (group.delim.indexOf("arrow") > -1) { - middleNode.setAttribute("stretchy", "true"); - } - // The next line is not semantically correct, but - // Chromium fails to stretch if it is not there. - middleNode.setAttribute("form", "prefix"); - // 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 padding$1 = _ => { - const node = new mathMLTree.MathNode("mspace"); - node.setAttribute("width", "3pt"); - return node -}; - -const mathmlBuilder$8 = (group, style) => { - let node; - if (group.label.indexOf("colorbox") > -1 || group.label === "\\boxed") { - // MathML core does not support +width attribute in . - // Firefox does not reliably add side padding. - // Insert - node = new mathMLTree.MathNode("mrow", [ - padding$1(), - buildGroup$1(group.body, style), - padding$1() - ]); - } else { - node = new mathMLTree.MathNode("mrow", [buildGroup$1(group.body, style)]); - } - switch (group.label) { - case "\\overline": - node.style.padding = "0.1em 0 0 0"; - node.style.borderTop = "0.065em solid"; - break - case "\\underline": - node.style.padding = "0 0 0.1em 0"; - node.style.borderBottom = "0.065em solid"; - break - case "\\cancel": - // We can't use an inline background-gradient. It does not work client-side. - // So set a class and put the rule in the external CSS file. - node.classes.push("tml-cancel"); - break - case "\\bcancel": - node.classes.push("tml-bcancel"); - break - /* - case "\\longdiv": - node.setAttribute("notation", "longdiv"); - break - case "\\phase": - node.setAttribute("notation", "phasorangle"); - break */ - case "\\angl": - node.style.padding = "0.03889em 0.03889em 0 0.03889em"; - node.style.borderTop = "0.049em solid"; - node.style.borderRight = "0.049em solid"; - node.style.marginRight = "0.03889em"; - break - case "\\sout": - node.style.backgroundImage = 'linear-gradient(black, black)'; - node.style.backgroundRepeat = 'no-repeat'; - node.style.backgroundSize = '100% 1.5px'; - node.style.backgroundPosition = '0 center'; - break - case "\\boxed": - // \newcommand{\boxed}[1]{\fbox{\m@th$\displaystyle#1$}} from amsmath.sty - node.style = { padding: "3pt 0 3pt 0", border: "1px solid" }; - node.setAttribute("scriptlevel", "0"); - node.setAttribute("displaystyle", "true"); - break - case "\\fbox": - node.style = { padding: "3pt", border: "1px solid" }; - 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("height", `+${2 * fboxsep}pt`) - //node.setAttribute("voffset", `${fboxsep}pt`) - const style = { padding: "3pt 0 3pt 0" }; - - if (group.label === "\\fcolorbox") { - style.border = "0.06em solid " + String(group.borderColor); - } - node.style = style; - break - } - case "\\xcancel": - node.classes.push("tml-xcancel"); - 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: ["\\angl", "\\cancel", "\\bcancel", "\\xcancel", "\\sout", "\\overline", "\\boxed"], - // , "\\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 -}); - -defineFunction({ - type: "enclose", - names: ["\\underline"], - props: { - numArgs: 1, - allowedInText: true - }, - 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; - if (nxt === "\\relax") { - parser.consume(); - parser.consumeSpaces(); - 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, true); - tag.classes = ["tml-tag"]; - } else { - // \notag. Return an empty span. - tag = new mathMLTree.MathNode("mtext", [], []); - return tag - } - } else if (group.envClasses.includes("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("mtext", [], []); - return tag - } else { - // AMS automatcally numbered equaton. - // Insert a class so the element can be populated by a CSS counter. - // WebKit will display the CSS counter only inside a span. - tag = new mathMLTree.MathNode("mtext", [new Span(["tml-eqn"])]); - } - 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, - { - cols, // [{ type: string , align: l|c|r|null }] - envClasses, // align(ed|at|edat) | array | cases | cd | small | 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", "\\@ifstar\\envtag@literal\\envtag@paren"); - parser.gullet.macros.set("\\envtag@paren", "\\env@tag{{(\\text{#1})}}"); - parser.gullet.macros.set("\\envtag@literal", "\\env@tag{\\text{#1}}"); - parser.gullet.macros.set("\\notag", "\\env@notag"); - parser.gullet.macros.set("\\nonumber", "\\env@notag"); - } - - // 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, - semisimple: true - }; - row.push(cell); - const next = parser.fetch().text; - if (next === "&") { - if (maxNumCols && row.length === maxNumCols) { - if (envClasses.includes("array")) { - if (parser.settings.strict) { - throw new ParseError("Too few columns " + "specified in the {array} column argument.", - parser.nextToken) - } - } else if (maxNumCols === 2) { - throw new ParseError("The split environment accepts no more than two columns", - 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, - body, - cols, - rowGaps, - hLinesBeforeRow, - envClasses, - addEqnNum, - scriptLevel, - tags, - leqno - }; -} - -// 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 glue = group => { - const glueNode = new mathMLTree.MathNode("mtd", []); - glueNode.style = { padding: "0", width: "50%" }; - if (group.envClasses.includes("multline")) { - glueNode.style.width = "7.5%"; - } - return glueNode -}; - -const mathmlBuilder$7 = function(group, style) { - const tbl = []; - const numRows = group.body.length; - const hlines = group.hLinesBeforeRow; - - for (let i = 0; i < numRows; i++) { - const rw = group.body[i]; - const row = []; - const cellLevel = 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(cellLevel))] - ); - - if (group.envClasses.includes("multline")) { - const align = i === 0 ? "left" : i === numRows - 1 ? "right" : "center"; - mtd.setAttribute("columnalign", align); - if (align !== "center") { - mtd.classes.push("tml-" + align); - } - } - row.push(mtd); - } - if (group.addEqnNum) { - row.unshift(glue(group)); - row.push(glue(group)); - const tag = getTag(group, style.withLevel(cellLevel), i); - if (group.leqno) { - row[0].children.push(tag); - row[0].classes.push("tml-left"); - } else { - row[row.length - 1].children.push(tag); - row[row.length - 1].classes.push("tml-right"); - } - } - const mtr = new mathMLTree.MathNode("mtr", row, []); - // Write horizontal rules - if (i === 0 && hlines[0].length > 0) { - if (hlines[0].length === 2) { - mtr.children.forEach(cell => { cell.style.borderTop = "0.15em double"; }); - } else { - mtr.children.forEach(cell => { - cell.style.borderTop = hlines[0][0] ? "0.06em dashed" : "0.06em solid"; - }); - } - } - if (hlines[i + 1].length > 0) { - if (hlines[i + 1].length === 2) { - mtr.children.forEach(cell => { cell.style.borderBottom = "0.15em double"; }); - } else { - mtr.children.forEach(cell => { - cell.style.borderBottom = hlines[i + 1][0] ? "0.06em dashed" : "0.06em solid"; - }); - } - } - tbl.push(mtr); - } - - if (group.envClasses.length > 0) { - const pad = group.envClasses.includes("jot") - ? "0.7" // 0.5ex + 0.09em top & bot padding - : group.envClasses.includes("small") - ? "0.35" - : "0.5"; // 0.5ex default top & bot padding - const sidePadding = group.envClasses.includes("abut") - ? "0" - : group.envClasses.includes("cases") - ? "0" - : group.envClasses.includes("small") - ? "0.1389" - : group.envClasses.includes("cd") - ? "0.25" - : "0.4"; // default side padding - - const numCols = tbl.length === 0 ? 0 : tbl[0].children.length; - - const sidePad = (j, hand) => { - if (j === 0 && hand === 0) { return "0" } - if (j === numCols - 1 && hand === 1) { return "0" } - if (group.envClasses[0] !== "align") { return sidePadding } - if (hand === 1) { return "0" } - if (group.addEqnNum) { - return (j % 2) ? "1" : "0" - } else { - return (j % 2) ? "0" : "1" - } - }; - - // Padding - for (let i = 0; i < tbl.length; i++) { - for (let j = 0; j < tbl[i].children.length; j++) { - tbl[i].children[j].style.padding = `${pad}ex ${sidePad(j, 1)}em ${pad}ex ${sidePad(j, 0)}em`; - } - } - - // Justification - const align = group.envClasses.includes("align") || group.envClasses.includes("alignat"); - for (let i = 0; i < tbl.length; i++) { - const row = tbl[i]; - if (align) { - for (let j = 0; j < row.children.length; j++) { - // Chromium does not recognize text-align: left. Use -webkit- - // TODO: Remove -webkit- when Chromium no longer needs it. - row.children[j].classes = ["tml-" + (j % 2 ? "left" : "right")]; - } - if (group.addEqnNum) { - const k = group.leqno ? 0 : row.children.length - 1; - row.children[k].classes = ["tml-" + (group.leqno ? "left" : "right")]; - } - } - if (row.children.length > 1 && group.envClasses.includes("cases")) { - row.children[1].style.padding = row.children[1].style.padding.replace(/0em$/, "1em"); - } - - if (group.envClasses.includes("cases") || group.envClasses.includes("subarray")) { - for (const cell of row.children) { - cell.classes.push("tml-left"); - } - } - } - } else { - // Set zero padding on side of the matrix - for (let i = 0; i < tbl.length; i++) { - tbl[i].children[0].style.paddingLeft = "0em"; - if (tbl[i].children.length === tbl[0].children.length) { - tbl[i].children[tbl[i].children.length - 1].style.paddingRight = "0em"; - } - } - } - - let table = new mathMLTree.MathNode("mtable", tbl); - if (group.scriptLevel === "display") { table.setAttribute("displaystyle", "true"); } - - if (group.addEqnNum || group.envClasses.includes("multline")) { - table.style.width = "100%"; - } - - // Column separator lines and column alignment - let align = ""; - - if (group.cols && group.cols.length > 0) { - const cols = group.cols; - let prevTypeWasAlign = false; - let iStart = 0; - let iEnd = cols.length; - - while (cols[iStart].type === "separator") { - iStart += 1; - } - while (cols[iEnd - 1].type === "separator") { - iEnd -= 1; - } - - if (cols[0].type === "separator") { - const sep = cols[1].type === "separator" - ? "0.15em double" - : cols[0].separator === "|" - ? "0.06em solid " - : "0.06em dashed "; - for (const row of table.children) { - row.children[0].style.borderLeft = sep; - } - } - let iCol = group.addEqnNum ? 0 : -1; - for (let i = iStart; i < iEnd; i++) { - if (cols[i].type === "align") { - const colAlign = alignMap[cols[i].align]; - align += colAlign; - iCol += 1; - for (const row of table.children) { - if (colAlign.trim() !== "center" && iCol < row.children.length) { - row.children[iCol].classes = ["tml-" + colAlign.trim()]; - } - } - 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) { - const sep = cols[i + 1].type === "separator" - ? "0.15em double" - : cols[i].separator === "|" - ? "0.06em solid" - : "0.06em dashed"; - for (const row of table.children) { - if (iCol < row.children.length) { - row.children[iCol].style.borderRight = sep; - } - } - } - prevTypeWasAlign = false; - } - } - if (cols[cols.length - 1].type === "separator") { - const sep = cols[cols.length - 2].type === "separator" - ? "0.15em double" - : cols[cols.length - 1].separator === "|" - ? "0.06em solid" - : "0.06em dashed"; - for (const row of table.children) { - row.children[row.children.length - 1].style.borderRight = sep; - row.children[row.children.length - 1].style.paddingRight = "0.4em"; - } - } - } - if (group.addEqnNum) { - // allow for glue cells on each side - align = "left " + (align.length > 0 ? align : "center ") + "right "; - } - if (align) { - // Firefox reads this attribute, not the -webkit-left|right written above. - // TODO: When Chrome no longer needs "-webkit-", use CSS and delete the next line. - table.setAttribute("columnalign", align.trim()); - } - - if (group.envClasses.includes("small")) { - // A small array. Wrap in scriptstyle. - table = new mathMLTree.MathNode("mstyle", [table]); - table.setAttribute("scriptlevel", "1"); - } - - return table -}; - -// Convenience function for align, align*, aligned, alignat, alignat*, alignedat, split. -const alignedHandler = function(context, args) { - if (context.envName.indexOf("ed") === -1) { - validateAmsEnvironmentContext(context); - } - const cols = []; - const res = parseArray( - context.parser, - { - cols, - addEqnNum: context.envName === "align" || context.envName === "alignat", - emptySingleRow: true, - envClasses: ["abut", "jot"], // set row spacing & provisional column spacing - 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; - const isAlignedAt = context.envName.indexOf("at") > -1; - if (args[0] && isAlignedAt) { - // alignat environment takes an argument w/ number of columns - let arg0 = ""; - for (let i = 0; i < args[0].body.length; i++) { - const textord = assertNodeType(args[0].body[i], "textord"); - arg0 += textord.text; - } - if (isNaN(arg0)) { - throw new ParseError("The alignat enviroment requires a numeric first argument.") - } - numMaths = Number(arg0); - numCols = numMaths * 2; - } - res.body.forEach(function(row) { - if (isAlignedAt) { - // 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 - }; - } - if (context.envName === "split") ; else if (isAlignedAt) { - res.envClasses.push("alignat"); // Sets justification - } else { - res.envClasses[0] = "align"; // Sets column spacing & justification - } - 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, - envClasses: ["array"], - 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 = { - envClasses: [], - cols: [] - }; - 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 = []; - } - } - const res = parseArray(context.parser, payload, "text"); - res.cols = new Array(res.body[0].length).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 = { type: "small" }; - const res = parseArray(context.parser, payload, "script"); - res.envClasses = ["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, - envClasses: ["small"] - }; - 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: [], - envClasses: ["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. -defineEnvironment({ - type: "array", - names: ["align", "align*", "aligned", "split"], - props: { - numArgs: 0 - }, - handler: alignedHandler, - 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 where spacing occurs. -defineEnvironment({ - type: "array", - names: ["alignat", "alignat*", "alignedat"], - props: { - numArgs: 1 - }, - 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 (context.envName !== "gathered") { - validateAmsEnvironmentContext(context); - } - const res = { - cols: [], - envClasses: ["abut", "jot"], - addEqnNum: context.envName === "gather", - emptySingleRow: true, - leqno: context.parser.settings.leqno - }; - return parseArray(context.parser, res, "display"); - }, - 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, - envClasses: ["align"], - 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, - envClasses: ["jot", "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 isLongVariableName = (group, font) => { - if (font !== "mathrm" || group.body.type !== "ordgroup" || group.body.body.length === 1) { - return false - } - if (group.body.body[0].type !== "mathord") { return false } - for (let i = 1; i < group.body.body.length; i++) { - const parseNodeType = group.body.body[i].type; - if (!(parseNodeType === "mathord" || - (parseNodeType === "textord" && !isNaN(group.body.body[i].text)))) { - return false - } - } - return true -}; - -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", "mrow"].includes(mathGroup.type)) { - mathGroup.style.fontWeight = "bold"; - return mathGroup - } - // Check if it is possible to consolidate elements into a single element. - if (isLongVariableName(group, font)) { - // This is a \mathrm{…} group. It gets special treatment because symbolsOrd.js - // wraps elements with s to work around a Firefox bug. - const mi = mathGroup.children[0].children[0]; - delete mi.attributes.mathvariant; - for (let i = 1; i < mathGroup.children.length; i++) { - mi.children[0].text += mathGroup.children[i].type === "mn" - ? mathGroup.children[i].children[0].text - : mathGroup.children[i].children[0].children[0].text; - } - // Wrap in a to prevent the same Firefox bug. - const bogus = new mathMLTree.MathNode("mtext", new mathMLTree.TextNode("\u200b")); - return new mathMLTree.MathNode("mrow", [bogus, mi]) - } - 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 (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", - - // 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, true); - 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 -}); - -// \hbox is provided for compatibility with LaTeX functions that act on a box. -// This function by itself doesn't do anything but set scriptlevel to \textstyle -// and 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 newStyle = style.withLevel(StyleLevel.TEXT); - const mrow = buildExpressionRow(group.body, newStyle); - return consolidateText(mrow) - } -}); - -const mathmlBuilder$4 = (group, style) => { - const accentNode = stretchy.mathMLnode(group.label); - accentNode.style["math-depth"] = 0; - 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); - if (dimension.number < 0) { - node.style.marginLeft = 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 - let strut; - if (group.alignment === "llap") { - // We need an invisible strut with the same depth as the group. - // We can't just read the depth, so we use \vphantom methods. - const phantomInner = buildExpression(ordargument(group.body), style); - const phantom = new mathMLTree.MathNode("mphantom", phantomInner); - strut = new mathMLTree.MathNode("mpadded", [phantom]); - strut.setAttribute("width", "0px"); - } - - const inner = buildGroup$1(group.body, style); - let node; - if (group.alignment === "llap") { - inner.style.position = "absolute"; - inner.style.right = "0"; - inner.style.bottom = `0`; // If we could have read the ink depth, it would go here. - node = new mathMLTree.MathNode("mpadded", [strut, inner]); - } else { - node = new mathMLTree.MathNode("mpadded", [inner]); - } - - 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"); - if (group.alignment === "llap") { - node.style.position = "relative"; - } else { - node.style.display = "flex"; - node.style.justifyContent = "center"; - } - } - 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"]; - -const padding = width => { - const node = new mathMLTree.MathNode("mspace"); - node.setAttribute("width", width + "em"); - return node -}; - -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"; - if (node.children.length === 1 && node.children[0].text && node.children[0].text === "∇") { - node.setAttribute("mathvariant", "normal"); - } - } else { - node = new mathMLTree.MathNode("mi", inner); - } - } else { - node = new mathMLTree.MathNode("mrow", inner); - 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("mrow", 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 (node.type === "mrow") { - if (doSpacing ) { - if (group.mclass === "mbin") { - // medium space - node.children.unshift(padding(0.2222)); - node.children.push(padding(0.2222)); - } else if (group.mclass === "mrel") { - // thickspace - node.children.unshift(padding(0.2778)); - node.children.push(padding(0.2778)); - } else if (group.mclass === "mpunct") { - node.children.push(padding(0.1667)); - } else if (group.mclass === "minner") { - node.children.unshift(padding(0.0556)); // 1 mu is the most likely option - node.children.push(padding(0.0556)); - } - } - } else { - 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 (symbols[parser.mode][arg.text]) { - mord.text += symbols[parser.mode][arg.text].replace; - } else 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, true); - return inner[0] - } else { - return buildExpressionRow(group.body, style) - } - } -}); - -// 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"]; - -// 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 setSpacing = node => { - // The user wrote a \mathop{…} function. Change spacing from default to OP spacing. - // The most likely spacing for an OP is a thin space per TeXbook p170. - node.attributes.lspace = "0.1667em"; - node.attributes.rspace = "0.1667em"; -}; - -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 (noSuccessor.includes(group.name)) { - node.setAttribute("largeop", "false"); - } else { - node.setAttribute("movablelimits", "false"); - } - if (group.fromMathOp) { setSpacing(node); } - } else if (group.body) { - // This is an operator with children. Add them. - node = new MathNode("mo", buildExpression(group.body, style)); - if (group.fromMathOp) { setSpacing(node); } - } 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")]); - const row = [node, operator]; - // Set spacing - if (group.needsLeadingSpace) { - const lead = new MathNode("mspace"); - lead.setAttribute("width", "0.1667em"); // thin space. - row.unshift(lead); - } - if (!group.isFollowedByDelimiter) { - const trail = new MathNode("mspace"); - trail.setAttribute("width", "0.1667em"); // thin space. - row.push(trail); - } - node = new MathNode("mrow", row); - } - } - - 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", - "\u2a09": "\\bigtimes" -}; - -defineFunction({ - type: "op", - names: [ - "\\coprod", - "\\bigvee", - "\\bigwedge", - "\\biguplus", - "\\bigcap", - "\\bigcup", - "\\intop", - "\\prod", - "\\sum", - "\\bigotimes", - "\\bigoplus", - "\\bigodot", - "\\bigsqcap", - "\\bigsqcup", - "\\bigtimes", - "\\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, - fromMathOp: true, - 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 && ordTypes.includes(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 && ordTypes.includes(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++) { - let node = expression[i]; - if (node instanceof mathMLTree.MathNode) { - if (node.type === "mrow" && node.children.length === 1 && - node.children[0] instanceof mathMLTree.MathNode) { - node = node.children[0]; - } - 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 - && ["mover", "munder"].includes(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); - if (expression[0].text.length === 1) { - 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")]); - const fragment = [wrapper, operator]; - 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. - fragment.unshift(space); - } - if (!group.isFollowedByDelimiter) { - const trail = new mathMLTree.MathNode("mspace"); - trail.setAttribute("width", "0.1667em"); // thin space. - fragment.push(trail); - } - return mathMLTree.newDocumentFragment(fragment) - } - - 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; - const next = parser.gullet.future().text; - return { - type: "operatorname", - mode: parser.mode, - body: ordargument(body), - alwaysHandleSupSub: (funcName === "\\operatornamewithlimits"), - limits: false, - parentIsSupSub: false, - isFollowedByDelimiter: isDelimiter(next), - needsLeadingSpace: prevAtomType.length > 0 && ordTypes.includes(prevAtomType) - }; - }, - mathmlBuilder: mathmlBuilder$1 -}); - -defineMacro("\\operatorname", - "\\@ifstar\\operatornamewithlimits\\operatorname@"); - -defineFunctionBuilders({ - type: "ordgroup", - mathmlBuilder(group, style) { - return buildExpressionRow(group.body, style, group.semisimple); - } -}); - -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; - } -}); - -// In LaTeX, \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 font-weight:bold. - -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", "font-weight:bold"); - return node - } -}); - -// \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); - // Add padding, which acts to increase height in Chromium. - // TODO: Figure out some way to change height in Firefox w/o breaking Chromium. - if (dy.number > 0) { - node.style.padding = dy.number + dy.unit + " 0 0 0"; - } else { - node.style.padding = "0 0 " + Math.abs(dy.number) + dy.unit + " 0"; - } - 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: "reflect", - names: ["\\reflectbox"], - props: { - numArgs: 1, - argTypes: ["hbox"], - allowedInText: true - }, - handler({ parser }, args) { - return { - type: "reflect", - mode: parser.mode, - body: args[0] - }; - }, - mathmlBuilder(group, style) { - const node = buildGroup$1(group.body, style); - node.style.transform = "scaleX(-1)"; - 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, true); - 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, true); - - 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 appendSpace = 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; - appendSpace = appendApplyFunction && !group.isFollowedByDelimiter; - 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) { - const sup = buildGroup$1(group.sup, childStyle); - const testNode = sup.type === "mrow" ? sup.children[0] : sup; - if ((testNode && testNode.type === "mo" && testNode.classes.includes("tml-prime")) - && group.base && group.base.text && group.base.text === "f") { - // Chromium does not address italic correction on prime. Prevent f′ from overlapping. - testNode.classes.push("prime-pad"); - } - children.push(sup); - } - - 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]); - } - if (appendSpace) { - const space = new mathMLTree.MathNode("mspace"); - space.setAttribute("width", "0.1667em"); // thin space. - node.children.push(space); - } - } 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"]; - -const arrows = ["\\Rsh", "\\Lsh", "\\restriction"]; - -const isArrow = str => { - if (str.length === 1) { - const codePoint = str.codePointAt(0); - return (0x218f < codePoint && codePoint < 0x2200) - } - return str.indexOf("arrow") > -1 || str.indexOf("harpoon") > -1 || arrows.includes(str) -}; - -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 (group.family === "rel" && isArrow(group.text)) { - 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" -}; - -/** - * 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" - } - - 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 0x1D317 }, - "italic": ch => { return 0x1D351 }, - // \boldsymbol actually returns upright bold for upperCaseGreek - "bold-italic": ch => { return 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 0x1D3C5 }, - "sans-serif-bold": ch => { return 0x1D3C5 }, - "sans-serif-italic": ch => { return 0 }, - "sans-serif-bold-italic": ch => { return 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) - ? "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,.]*\d)?$/; -const latinRegEx = /[A-Ba-z]/; -const primes = new Set(["\\prime", "\\dprime", "\\trprime", "\\qprime", - "\\backprime", "\\backdprime", "\\backtrprime"]); - -const italicNumber = (text, variant, tag) => { - const mn = new mathMLTree.MathNode(tag, [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("mrow", [node]); - } - } - 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 (numberRegEx.test(group.text)) { - const tag = group.mode === "text" ? "mtext" : "mn"; - if (variant === "italic" || variant === "bold-italic") { - return italicNumber(text, variant, tag) - } else { - if (variant !== "normal") { - text.text = text.text.split("").map(c => variantChar(c, variant)).join(""); - } - node = new mathMLTree.MathNode(tag, [text]); - } - } else if (group.mode === "text") { - if (variant !== "normal") { - text.text = variantChar(text.text, variant); - } - node = new mathMLTree.MathNode("mtext", [text]); - } else if (primes.has(group.text)) { - node = new mathMLTree.MathNode("mo", [text]); - // TODO: If/when Chromium uses ssty variant for prime, remove the next line. - node.classes.push("tml-prime"); - } 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 consolidateText(mrow) - } -}); - -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 - "([!-\\[\\]-\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(tokenRegexString, '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 local `set` take constant time, while global - * `set` takes time proportional to the depth of group nesting. - */ - -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 optionally set it globally too. - * Local set() sets the current value and (when appropriate) adds an undo - * operation to the undo stack. Global set() may change the undo - * operation at every level, so takes time linear in their number. - */ - set(name, value, global = false) { - if (global) { - // Global set is equivalent to setting in all groups. Simulate this - // by destroying any undos currently scheduled for this name, - // and adding an undo with the *new* value (in case it later gets - // locally reset within this environment). - for (let i = 0; i < this.undefStack.length; i++) { - delete this.undefStack[i][name]; - } - if (this.undefStack.length > 0) { - this.undefStack[this.undefStack.length - 1][name] = value; - } - } else { - // 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}}`; -}); - -function recreateArgStr(context) { - // Recreate the macro's original argument string from the array of parse tokens. - const tokens = context.consumeArgs(1)[0]; - let str = ""; - let expectedLoc = tokens[tokens.length - 1].loc.start; - for (let i = tokens.length - 1; i >= 0; i--) { - const actualLoc = tokens[i].loc.start; - if (actualLoc > expectedLoc) { - // context.consumeArgs has eaten a space. - str += " "; - expectedLoc = actualLoc; - } - str += tokens[i].text; - expectedLoc += tokens[i].text.length; - } - return str -} - -// The Latin Modern font renders at the wrong vertical alignment. -// This macro provides a better rendering. -defineMacro("\\surd", '\\sqrt{\\vphantom{|}}'); - -// See comment for \oplus in symbols.js. -defineMacro("\u2295", "\\oplus"); - -// 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", "{\\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}"); - -// \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", - "\\bigtimes": "\\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 (["bin", "rel"].includes(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"); - -defineMacro("\\AA", "\\TextOrMath{\\Angstrom}{\\mathring{A}}\\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}"); - -////////////////////////////////////////////////////////////////////// -// MnSymbol.sty - -defineMacro("\\leftmodels", "\\mathop{\\reflectbox{$\\models$}}"); - -////////////////////////////////////////////////////////////////////// -// 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"); -// A helper for \Braket and \Set -const replaceVert = (argStr, match) => { - const ch = match[0] === "|" ? "\\vert" : "\\Vert"; - const replaceStr = `}\\,\\middle${ch}\\,{`; - return argStr.slice(0, match.index) + replaceStr + argStr.slice(match.index + match[0].length) -}; -defineMacro("\\Braket", function(context) { - let argStr = recreateArgStr(context); - const regEx = /\|\||\||\\\|/g; - let match; - while ((match = regEx.exec(argStr)) !== null) { - argStr = replaceVert(argStr, match); - } - return "\\left\\langle{" + argStr + "}\\right\\rangle" -}); -defineMacro("\\Set", function(context) { - let argStr = recreateArgStr(context); - const match = /\|\||\||\\\|/.exec(argStr); - if (match) { - argStr = replaceVert(argStr, match); - } - return "\\left\\{\\:{" + argStr + "}\\:\\right\\}" -}); -defineMacro("\\set", function(context) { - const argStr = recreateArgStr(context); - return "\\{{" + argStr.replace(/\|/, "}\\mid{") + "}\\}" -}); - -////////////////////////////////////////////////////////////////////// -// 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 analysis - // 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 the number of such tokens will be - * returned. This number might be zero or positive. - * - * If not, the return value is `false`, and the next token remains at the - * top of the stack. - * - * In either case, the next token will be on the top of the stack, - * or the stack will be empty (in case of empty expansion - * and no other tokens). - * - * 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 false; - } - 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.length; - } - - /** - * 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 (;;) { - if (this.expandOnce() === false) { // fully expanded - const token = this.stack.pop(); - // The token after \noexpand is interpreted as if its meaning were ‘\relax’ - if (token.treatAsRelax) { - token.text = "\\relax"; - } - return token - } - } - - // 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) { - // Expand only expandable tokens - if (this.expandOnce(true) === false) { // fully expanded - const token = this.stack.pop(); - if (token.treatAsRelax) { - // the expansion of \noexpand is the token itself - token.noexpand = false; - token.treatAsRelax = false; - } - output.push(token); - } - } - 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; - } -} - -// 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': 'θ' -}); - -// Used for Unicode input of calligraphic and script letters -const asciiFromScript = Object.freeze({ - "\ud835\udc9c": "A", - "\u212c": "B", - "\ud835\udc9e": "C", - "\ud835\udc9f": "D", - "\u2130": "E", - "\u2131": "F", - "\ud835\udca2": "G", - "\u210B": "H", - "\u2110": "I", - "\ud835\udca5": "J", - "\ud835\udca6": "K", - "\u2112": "L", - "\u2133": "M", - "\ud835\udca9": "N", - "\ud835\udcaa": "O", - "\ud835\udcab": "P", - "\ud835\udcac": "Q", - "\u211B": "R", - "\ud835\udcae": "S", - "\ud835\udcaf": "T", - "\ud835\udcb0": "U", - "\ud835\udcb1": "V", - "\ud835\udcb2": "W", - "\ud835\udcb3": "X", - "\ud835\udcb4": "Y", - "\ud835\udcb5": "Z" -}); - -// 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 binLeftCancellers = ["bin", "op", "open", "punct", "rel"]; - -/** - * 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", "&"]; - } - - /** - * Fully parse a separate sequence of tokens as a separate job. - * Tokens should be specified in reverse order, as in a MacroDefinition. - */ - subparse(tokens) { - // Save the next token from the current job. - const oldToken = this.nextToken; - this.consume(); - - // Run the new job, terminating it with an excess '}' - this.gullet.pushToken(new Token("}")); - this.gullet.pushTokens(tokens); - const parse = this.parseExpression(false); - this.expect("}"); - - // Restore the next token from the current job. - this.nextToken = oldToken; - - return parse; - } - -/** - * 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 precedence 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. - * - * `breakOnMiddle`: \color, \over, and old styling functions work on an implicit group. - * These groups end just before the usual tokens, but they also - * end just before `\middle`. - */ - parseExpression(breakOnInfix, breakOnTokenText, breakOnMiddle) { - 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 (breakOnMiddle && lex.text === "\\middle") { - 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. - const isSub = unicodeSubRegEx.test(lex.text); - const subsupTokens = []; - subsupTokens.push(new Token(uSubsAndSups[lex.text])); - this.consume(); - // Continue fetching tokens to fill out the group. - while (true) { - const token = this.fetch().text; - if (!(uSubsAndSups[token])) { break } - if (unicodeSubRegEx.test(token) !== isSub) { break } - subsupTokens.unshift(new Token(uSubsAndSups[token])); - this.consume(); - } - // Now create a (sub|super)script. - const body = this.subparse(subsupTokens); - 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 - const isFollowedByDelimiter = (!base || base.type !== "op" && base.type !== "operatorname") - ? undefined - : isDelimiter(this.nextToken.text); - return { - type: "supsub", - mode: this.mode, - base: base, - sup: superscript, - sub: subscript, - isFollowedByDelimiter - } - } - } 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 (true) { - const ch = this.fetch().text; - // \ufe0e is the Unicode variation selector to supress emoji. Ignore it. - if (ch === " " || ch === "\u00a0" || ch === "\ufe0e") { - this.consume(); - } else { - break - } - } - } - - /** - * 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/ - 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]) { - let group = symbols[this.mode][text].group; - if (group === "bin" && binLeftCancellers.includes(this.prevAtomType)) { - // Change from a binary operator to a unary (prefix) operator - group = "open"; - } - 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 { - if (asciiFromScript[text]) { - // Unicode 14 disambiguates chancery from roundhand. - // See https://www.unicode.org/charts/PDF/U1D400.pdf - this.consume(); - const nextCode = this.fetch().text.charCodeAt(0); - // mathcal is Temml default. Use mathscript if called for. - const font = nextCode === 0xfe01 ? "mathscr" : "mathcal"; - if (nextCode === 0xfe00 || nextCode === 0xfe01) { this.consume(); } - return { - type: "font", - mode: "math", - font, - body: { type: "mathord", mode: "math", loc, text: asciiFromScript[text] } - } - } - // Default ord character. No disambiguation necessary. - s = { - type: group, - mode: this.mode, - loc, - text - }; - } - symbol = s; - } else if (text.charCodeAt(0) >= 0x80) { - // no symbol for e.g. ^ - if (this.settings.strict && 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, - 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, - * 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.10.25"; - -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 */ - -/** - * @type {import('./temml').render} - * Parse and build an expression, and place that expression in the DOM node - * given. - */ -let render = function(expression, baseNode, options = {}) { - baseNode.textContent = ""; - const alreadyInMathElement = baseNode.tagName.toLowerCase() === "math"; - if (alreadyInMathElement) { options.wrap = "none"; } - const math = renderToMathMLTree(expression, options); - if (alreadyInMathElement) { - // The element already exists. Populate it. - baseNode.textContent = ""; - math.children.forEach(e => { baseNode.appendChild(e.toNode()); }); - } else if (math.children.length > 1) { - 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."); - }; - } -} - -/** - * @type {import('./temml').renderToString} - * Parse and build an expression, and return the markup for that. - */ -const renderToString = function(expression, options) { - const markup = renderToMathMLTree(expression, options).toMarkup(); - return markup; -}; - -/** - * @type {import('./temml').generateParseTree} - * Parse an expression and return the parse tree. - */ -const generateParseTree = function(expression, options) { - const settings = new Settings(options); - return parseTree(expression, settings); -}; - -/** - * @type {import('./temml').definePreamble} - * 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; -}; - -/** - * @type {import('./temml').renderToMathMLTree} - * 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); - } -}; - -/** @type {import('./temml').default} */ -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 3dd035d4..00000000 --- a/utils/temml.mjs +++ /dev/null @@ -1,13529 +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. - */ - -/** - * 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), or `null` if URL has invalid protocol - * (so should be outright rejected). - */ -const protocolFromUrl = function(url) { - // Check for possible leading protocol. - // https://url.spec.whatwg.org/#url-parsing strips leading whitespace - // (\x00) or C0 control (\x00-\x1F) characters. - // eslint-disable-next-line no-control-regex - const protocol = /^[\x00-\x20]*([^\\/#?]*?)(:|�*58|�*3a|&colon)/i.exec(url); - if (!protocol) { - return "_relative"; - } - // Reject weird colons - if (protocol[2] !== ":") { - return null; - } - // Reject invalid characters in scheme according to - // https://datatracker.ietf.org/doc/html/rfc3986#section-3.1 - if (!/^[a-zA-Z][a-zA-Z0-9+\-.]*$/.test(protocol[1])) { - return null; - } - // Lowercase the protocol - return protocol[1].toLowerCase(); -}; - -/** - * 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 = { - 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.leqno = utils.deflt(options.leqno, false); // boolean - this.throwOnError = utils.deflt(options.throwOnError, false); // boolean - this.errorColor = utils.deflt(options.errorColor, "#b22222"); // string - this.macros = options.macros || {}; - this.wrap = utils.deflt(options.wrap, "tex"); // "tex" | "=" - 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) { - const protocol = utils.protocolFromUrl(context.url); - if (protocol == null) { - return false - } - context.protocol = protocol; - } - 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 this.classes.includes(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 this.classes.includes(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 itself). - */ - 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. - */ - -// TODO: Remove when Chromium stretches \widetilde & \widehat -const estimatedWidth = node => { - let width = 0; - if (node.body) { - for (const item of node.body) { - width += estimatedWidth(item); - } - } else if (node.type === "supsub") { - width += estimatedWidth(node.base); - if (node.sub) { width += 0.7 * estimatedWidth(node.sub); } - if (node.sup) { width += 0.7 * estimatedWidth(node.sup); } - } else if (node.type === "mathord" || node.type === "textord") { - for (const ch of node.text.split('')) { - const codePoint = ch.codePointAt(0); - if ((0x60 < codePoint && codePoint < 0x7B) || (0x03B0 < codePoint && codePoint < 0x3CA)) { - width += 0.56; // lower case latin or greek. Use advance width of letter n - } else if (0x2F < codePoint && codePoint < 0x3A) { - width += 0.50; // numerals. - } else { - width += 0.92; // advance width of letter M - } - } - } else { - width += 1.0; - } - return width -}; - -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 -}; - -const crookedWides = ["\\widetilde", "\\widehat", "\\widecheck", "\\utilde"]; - -// TODO: Remove when Chromium stretches \widetilde & \widehat -const accentNode = (group) => { - const mo = mathMLnode(group.label); - if (crookedWides.includes(group.label)) { - const width = estimatedWidth(group.base); - if (1 < width && width < 1.6) { - mo.classes.push("tml-crooked-2"); - } else if (1.6 <= width && width < 2.5) { - mo.classes.push("tml-crooked-3"); - } else if (2.5 <= width) { - mo.classes.push("tml-crooked-4"); - } - } - return mo -}; - -var stretchy = { - mathMLnode, - accentNode -}; - -/** - * 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, "\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"); -// unicodemath -defineSymbol(math, rel, "\u2a75", "\\eqeq", true); -defineSymbol(math, rel, "\u2a76", "\\eqeqeq", true); -// 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); -// ∇ is actually a unary operator, not binary. But this works. -defineSymbol(math, bin, "\u2207", "\\nabla", true); -defineSymbol(math, textord, "\u266d", "\\flat", true); -defineSymbol(math, textord, "\u2113", "\\ell", true); -defineSymbol(math, textord, "\u266e", "\\natural", true); -defineSymbol(math, textord, "Å", "\\Angstrom", true); -defineSymbol(text, textord, "Å", "\\Angstrom", 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 -defineSymbol(math, bin, "\u2AFD", "\\sslash", true); // from stmaryrd - -// 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, "\u21a4", "\\mapsfrom", 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, "\u220E", "\\QED", true); -defineSymbol(math, mathord, "\u2030", "\\permil", true); -defineSymbol(text, textord, "\u2030", "\\permil"); -defineSymbol(math, mathord, "\u2609", "\\astrosun", true); -defineSymbol(math, mathord, "\u263c", "\\sun", true); -defineSymbol(math, mathord, "\u263e", "\\leftmoon", true); -defineSymbol(math, mathord, "\u263d", "\\rightmoon", true); -defineSymbol(math, mathord, "\u2295", "\\Earth"); - -// 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, "\u2036", "\\backdprime"); -defineSymbol(math, textord, "\u2037", "\\backtrprime"); -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, "\u22ab", "\\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, "\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); -defineSymbol(math, bin, "\u22c8", "\\bowtie", true); -defineSymbol(math, bin, "\u22c8", "\\Join"); -defineSymbol(math, bin, "\u27d5", "\\leftouterjoin", true); -defineSymbol(math, bin, "\u27d6", "\\rightouterjoin", true); -defineSymbol(math, bin, "\u27d7", "\\fullouterjoin", true); - -// stix Binary Operators -defineSymbol(math, bin, "\u2238", "\\dotminus", true); -defineSymbol(math, bin, "\u27D1", "\\wedgedot", true); -defineSymbol(math, bin, "\u27C7", "\\veedot", true); -defineSymbol(math, bin, "\u2A62", "\\doublebarvee", true); -defineSymbol(math, bin, "\u2A63", "\\veedoublebar", true); -defineSymbol(math, bin, "\u2A5F", "\\wedgebar", true); -defineSymbol(math, bin, "\u2A60", "\\wedgedoublebar", true); -defineSymbol(math, bin, "\u2A54", "\\Vee", true); -defineSymbol(math, bin, "\u2A53", "\\Wedge", true); -defineSymbol(math, bin, "\u2A43", "\\barcap", true); -defineSymbol(math, bin, "\u2A42", "\\barcup", true); -defineSymbol(math, bin, "\u2A48", "\\capbarcup", true); -defineSymbol(math, bin, "\u2A40", "\\capdot", true); -defineSymbol(math, bin, "\u2A47", "\\capovercup", true); -defineSymbol(math, bin, "\u2A46", "\\cupovercap", true); -defineSymbol(math, bin, "\u2A4D", "\\closedvarcap", true); -defineSymbol(math, bin, "\u2A4C", "\\closedvarcup", true); -defineSymbol(math, bin, "\u2A2A", "\\minusdot", true); -defineSymbol(math, bin, "\u2A2B", "\\minusfdots", true); -defineSymbol(math, bin, "\u2A2C", "\\minusrdots", true); -defineSymbol(math, bin, "\u22BB", "\\Xor", true); -defineSymbol(math, bin, "\u22BC", "\\Nand", true); -defineSymbol(math, bin, "\u22BD", "\\Nor", true); -defineSymbol(math, bin, "\u22BD", "\\barvee"); -defineSymbol(math, bin, "\u2AF4", "\\interleave", true); -defineSymbol(math, bin, "\u29E2", "\\shuffle", true); -defineSymbol(math, bin, "\u2AF6", "\\threedotcolon", true); -defineSymbol(math, bin, "\u2982", "\\typecolon", true); -defineSymbol(math, bin, "\u223E", "\\invlazys", true); -defineSymbol(math, bin, "\u2A4B", "\\twocaps", true); -defineSymbol(math, bin, "\u2A4A", "\\twocups", true); -defineSymbol(math, bin, "\u2A4E", "\\Sqcap", true); -defineSymbol(math, bin, "\u2A4F", "\\Sqcup", true); -defineSymbol(math, bin, "\u2A56", "\\veeonvee", true); -defineSymbol(math, bin, "\u2A55", "\\wedgeonwedge", true); -defineSymbol(math, bin, "\u29D7", "\\blackhourglass", true); -defineSymbol(math, bin, "\u29C6", "\\boxast", true); -defineSymbol(math, bin, "\u29C8", "\\boxbox", true); -defineSymbol(math, bin, "\u29C7", "\\boxcircle", true); -defineSymbol(math, bin, "\u229C", "\\circledequal", true); -defineSymbol(math, bin, "\u29B7", "\\circledparallel", true); -defineSymbol(math, bin, "\u29B6", "\\circledvert", true); -defineSymbol(math, bin, "\u29B5", "\\circlehbar", true); -defineSymbol(math, bin, "\u27E1", "\\concavediamond", true); -defineSymbol(math, bin, "\u27E2", "\\concavediamondtickleft", true); -defineSymbol(math, bin, "\u27E3", "\\concavediamondtickright", true); -defineSymbol(math, bin, "\u22C4", "\\diamond", true); -defineSymbol(math, bin, "\u29D6", "\\hourglass", true); -defineSymbol(math, bin, "\u27E0", "\\lozengeminus", true); -defineSymbol(math, bin, "\u233D", "\\obar", true); -defineSymbol(math, bin, "\u29B8", "\\obslash", true); -defineSymbol(math, bin, "\u2A38", "\\odiv", true); -defineSymbol(math, bin, "\u29C1", "\\ogreaterthan", true); -defineSymbol(math, bin, "\u29C0", "\\olessthan", true); -defineSymbol(math, bin, "\u29B9", "\\operp", true); -defineSymbol(math, bin, "\u2A37", "\\Otimes", true); -defineSymbol(math, bin, "\u2A36", "\\otimeshat", true); -defineSymbol(math, bin, "\u22C6", "\\star", true); -defineSymbol(math, bin, "\u25B3", "\\triangle", true); -defineSymbol(math, bin, "\u2A3A", "\\triangleminus", true); -defineSymbol(math, bin, "\u2A39", "\\triangleplus", true); -defineSymbol(math, bin, "\u2A3B", "\\triangletimes", true); -defineSymbol(math, bin, "\u27E4", "\\whitesquaretickleft", true); -defineSymbol(math, bin, "\u27E5", "\\whitesquaretickright", true); -defineSymbol(math, bin, "\u2A33", "\\smashtimes", 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, "¢", "\\cent"); -defineSymbol(text, textord, "¢", "\\cent"); -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, "\u2033", "\\dprime"); -defineSymbol(math, textord, "\u2034", "\\trprime"); -defineSymbol(math, textord, "\u2057", "\\qprime"); -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, "\u2300", "\\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", "/", true); -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, "\u27ea", "\\lAngle", true); -defineSymbol(math, open, "\u2989", "\\llangle", 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, "\u27eb", "\\rAngle", true); -defineSymbol(math, close, "\u298a", "\\rrangle", 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"); -defineSymbol(math, bin, "\u22bb", "\\veebar"); -defineSymbol(math, bin, "\u2299", "\\odot", true); -// Firefox turns ⊕ into an emoji. So append \uFE0E. Define Unicode character in macros, not here. -defineSymbol(math, bin, "\u2295\uFE0E", "\\oplus"); -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, "\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(math, open, "⦇", "\\llparenthesis", true); -defineSymbol(math, close, "⦈", "\\rrparenthesis", 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, "\u2a09", "\\bigtimes"); -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, "\u2026", "\\dddot"); -defineSymbol(math, accent, "\u2026\u002e", "\\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, "\u2192", "\\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"); -defineSymbol(math, textord, "\u2300", "\\diameter", true); -defineSymbol(text, textord, "\u2300", "\\diameter"); - -// 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. - * - * The default is for 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. - * - * An option is for soft line breaks before an "=" sign. That changes the s. - * - * 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. - */ - -const openDelims = "([{⌊⌈⟨⟮⎰⟦⦃"; -const closeDelims = ")]}⌋⌉⟩⟯⎱⟦⦄"; - -function setLineBreaks(expression, wrapMode, isDisplayMode) { - const mtrs = []; - let mrows = []; - let block = []; - let numTopLevelEquals = 0; - let i = 0; - let level = 0; - while (i < expression.length) { - while (expression[i] instanceof DocumentFragment) { - expression.splice(i, 1, ...expression[i].children); // Expand the fragment. - } - const node = expression[i]; - if (node.attributes && node.attributes.linebreak && - node.attributes.linebreak === "newline") { - // A hard line break. Create a for the current block. - if (block.length > 0) { - mrows.push(new mathMLTree.MathNode("mrow", block)); - } - mrows.push(node); - block = []; - const mtd = new mathMLTree.MathNode("mtd", mrows); - mtd.style.textAlign = "left"; - mtrs.push(new mathMLTree.MathNode("mtr", [mtd])); - mrows = []; - i += 1; - continue - } - block.push(node); - if (node.type && node.type === "mo" && node.children.length === 1 && - !Object.hasOwn(node.attributes, "movablelimits")) { - const ch = node.children[0].text; - if (openDelims.indexOf(ch) > -1) { - level += 1; - } else if (closeDelims.indexOf(ch) > -1) { - level -= 1; - } else if (level === 0 && wrapMode === "=" && ch === "=") { - numTopLevelEquals += 1; - if (numTopLevelEquals > 1) { - block.pop(); - // Start a new block. (Insert a soft linebreak.) - const element = new mathMLTree.MathNode("mrow", block); - mrows.push(element); - block = [node]; - } - } else if (level === 0 && wrapMode === "tex" && ch !== "∇") { - // 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("mrow", block); - mrows.push(element); - block = []; - } - } - } - i += 1; - } - if (block.length > 0) { - const element = new mathMLTree.MathNode("mrow", block); - mrows.push(element); - } - if (mtrs.length > 0) { - const mtd = new mathMLTree.MathNode("mtd", mrows); - mtd.style.textAlign = "left"; - 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 corresponding 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); -}; - -const consolidateText = mrow => { - // If possible, consolidate adjacent elements into a single element. - if (mrow.type !== "mrow" && mrow.type !== "mstyle") { return mrow } - if (mrow.children.length === 0) { return mrow } // empty group, e.g., \text{} - if (!mrow.children[0].attributes || mrow.children[0].type !== "mtext") { return mrow } - const variant = mrow.children[0].attributes.mathvariant || ""; - const mtext = new mathMLTree.MathNode( - "mtext", - [new mathMLTree.TextNode(mrow.children[0].children[0].text)] - ); - 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; - } - } - // 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"; - } - for (const [key, value] of Object.entries(mrow.attributes)) { - mtext.attributes[key] = value; - } - return mtext -}; - -const numberRegEx$1 = /^[0-9]$/; -const isDotOrComma = (node, followingNode) => { - return ((node.type === "textord" && node.text === ".") || - (node.type === "atom" && node.text === ",")) && - // Don't consolidate if there is a space after the comma. - node.loc && followingNode.loc && node.loc.end === followingNode.loc.start -}; -const consolidateNumbers = expression => { - // Consolidate adjacent numbers. We want to return 1,506.3, - // not 1,506.3 - if (expression.length < 2) { return } - const nums = []; - let inNum = false; - // Find adjacent numerals - for (let i = 0; i < expression.length; i++) { - const node = expression[i]; - if (node.type === "textord" && numberRegEx$1.test(node.text)) { - if (!inNum) { nums.push({ start: i }); } - inNum = true; - } else { - if (inNum) { nums[nums.length - 1].end = i - 1; } - inNum = false; - } - } - if (inNum) { nums[nums.length - 1].end = expression.length - 1; } - - // Determine if numeral groups are separated by a comma or dot. - for (let i = nums.length - 1; i > 0; i--) { - if (nums[i - 1].end === nums[i].start - 2 && - isDotOrComma(expression[nums[i].start - 1], expression[nums[i].start])) { - // Merge the two groups. - nums[i - 1].end = nums[i].end; - nums.splice(i, 1); - } - } - - // Consolidate the number nodes - for (let i = nums.length - 1; i >= 0; i--) { - for (let j = nums[i].start + 1; j <= nums[i].end; j++) { - expression[nums[i].start].text += expression[j].text; - } - expression.splice(nums[i].start + 1, nums[i].end - nums[i].start); - // Check if the is followed by a numeric base in a supsub, e.g. the "3" in 123^4 - // If so, merge the first into the base. - if (expression.length > nums[i].start + 1) { - const nextTerm = expression[nums[i].start + 1]; - if (nextTerm.type === "supsub" && nextTerm.base && nextTerm.base.type === "textord" && - numberRegEx$1.test(nextTerm.base.text)) { - nextTerm.base.text = expression[nums[i].start].text + nextTerm.base.text; - expression.splice(nums[i].start, 1); - } - } - } -}; - -/** - * 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, semisimple = false) { - if (body.length === 1 && !(body[0] instanceof DocumentFragment)) { - return body[0]; - } else if (!semisimple) { - // Suppress spacing on nodes at both ends of the row. - if (body[0] instanceof MathNode && body[0].type === "mo" && !body[0].attributes.fence) { - body[0].attributes.lspace = "0em"; - body[0].attributes.rspace = "0em"; - } - const end = body.length - 1; - if (body[end] instanceof MathNode && body[end].type === "mo" && !body[end].attributes.fence) { - body[end].attributes.lspace = "0em"; - body[end].attributes.rspace = "0em"; - } - } - 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, semisimple = false) { - if (!semisimple && expression.length === 1) { - const group = buildGroup$1(expression[0], style); - if (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]; - } - - consolidateNumbers(expression); - - 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, semisimple = false) { - return makeRow(buildExpression(expression, style, semisimple), semisimple); -}; - -/** - * 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$1 = _ => { - return new mathMLTree.MathNode("mtd", [], [], { padding: "0", width: "50%" }) -}; - -const taggedExpression = (expression, tag, style, leqno) => { - tag = buildExpressionRow(tag[0].body, style); - tag = consolidateText(tag); - tag.classes.push("tml-tag"); - - expression = new mathMLTree.MathNode("mtd", [expression]); - const rowArray = [glue$1(), expression, glue$1()]; - rowArray[leqno ? 0 : 2].classes.push(leqno ? "tml-left" : "tml-right"); - rowArray[leqno ? 0 : 2].children.push(tag); - const mtr = new mathMLTree.MathNode("mtr", rowArray, ["tml-tageqn"]); - const table = new mathMLTree.MathNode("mtable", [mtr]); - table.style.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 wrap = (settings.displayMode || settings.annotate) ? "none" : settings.wrap; - - const n1 = expression.length === 0 ? null : expression[0]; - let wrapper = expression.length === 1 && tag === null && (n1 instanceof MathNode) - ? expression[0] - : setLineBreaks(expression, wrap, settings.displayMode); - - if (tag) { - wrapper = taggedExpression(wrapper, tag, style, settings.leqno); - } - - 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"); - wrapper = new mathMLTree.MathNode("semantics", [wrapper, annotation]); - } - - const math = 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"); - math.style.display = "block math"; // necessary in Chromium. - // Firefox and Safari do not recognize display: "block math". - // Set a class so that the CSS file can set display: block. - math.classes = ["tml-display"]; - } - return math; -} - -const smalls = "acegıȷmnopqrsuvwxyzαγεηικμνοπρςστυχωϕ𝐚𝐜𝐞𝐠𝐦𝐧𝐨𝐩𝐪𝐫𝐬𝐮𝐯𝐰𝐱𝐲𝐳"; -const talls = "ABCDEFGHIJKLMNOPQRSTUVWXYZbdfhkltΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩβδλζφθψ" - + "𝐀𝐁𝐂𝐃𝐄𝐅𝐆𝐇𝐈𝐉𝐊𝐋𝐌𝐍𝐎𝐏𝐐𝐑𝐒𝐓𝐔𝐕𝐖𝐗𝐘𝐙𝐛𝐝𝐟𝐡𝐤𝐥𝐭"; -const longSmalls = new Set(["\\alpha", "\\gamma", "\\delta", "\\epsilon", "\\eta", "\\iota", - "\\kappa", "\\mu", "\\nu", "\\pi", "\\rho", "\\sigma", "\\tau", "\\upsilon", "\\chi", "\\psi", - "\\omega", "\\imath", "\\jmath"]); -const longTalls = new Set(["\\Gamma", "\\Delta", "\\Sigma", "\\Omega", "\\beta", "\\delta", - "\\lambda", "\\theta", "\\psi"]); - -const mathmlBuilder$a = (group, style) => { - const accentNode = group.isStretchy - ? stretchy.accentNode(group) - : new mathMLTree.MathNode("mo", [makeText(group.label, group.mode)]); - - if (group.label === "\\vec") { - accentNode.style.transform = "scale(0.75) translate(10%, 30%)"; - } else { - accentNode.style.mathStyle = "normal"; - accentNode.style.mathDepth = "0"; - if (needWebkitShift.has(group.label) && utils.isCharacterBox(group.base)) { - let shift = ""; - const ch = group.base.text; - if (smalls.indexOf(ch) > -1 || longSmalls.has(ch)) { shift = "tml-xshift"; } - if (talls.indexOf(ch) > -1 || longTalls.has(ch)) { shift = "tml-capshift"; } - if (shift) { accentNode.classes.push(shift); } - } - } - if (!group.isStretchy) { - accentNode.setAttribute("stretchy", "false"); - } - - const node = new mathMLTree.MathNode((group.label === "\\c" ? "munder" : "mover"), - [buildGroup$1(group.base, style), accentNode] - ); - - return node; -}; - -const nonStretchyAccents = new Set([ - "\\acute", - "\\grave", - "\\ddot", - "\\dddot", - "\\ddddot", - "\\tilde", - "\\bar", - "\\breve", - "\\check", - "\\hat", - "\\vec", - "\\dot", - "\\mathring" -]); - -const needWebkitShift = new Set([ - "\\acute", - "\\bar", - "\\breve", - "\\check", - "\\dot", - "\\ddot", - "\\grave", - "\\hat", - "\\mathring", - "\\'", "\\^", "\\~", "\\=", "\\u", "\\.", '\\"', "\\r", "\\H", "\\v" -]); - -// 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 = !nonStretchyAccents.has(context.funcName); - - return { - type: "accent", - mode: context.parser.mode, - label: context.funcName, - isStretchy: isStretchy, - 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, - 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.accentNode(group); - accentNode.style["math-depth"] = 0; - const node = new mathMLTree.MathNode("munder", [ - buildGroup$1(group.base, style), - accentNode - ]); - 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 padding$2 = width => { - const node = new mathMLTree.MathNode("mspace"); - node.setAttribute("width", width + "em"); - return node -}; - -const paddedNode = (group, lspace = 0.3, rspace = 0) => { - if (group == null && rspace === 0) { return padding$2(lspace) } - const row = group ? [group] : []; - if (lspace !== 0) { row.unshift(padding$2(lspace)); } - if (rspace > 0) { row.push(padding$2(rspace)); } - return new mathMLTree.MathNode("mrow", row) -}; - -const labelSize = (size, scriptLevel) => Number(size) / emScale(scriptLevel); - -const munderoverNode = (fName, body, below, style) => { - const arrowNode = stretchy.mathMLnode(fName); - // Is this the short part of a mhchem equilibrium arrow? - const isEq = fName.slice(1, 3) === "eq"; - const minWidth = fName.charAt(1) === "x" - ? "1.75" // mathtools extensible arrows are ≥ 1.75em long - : fName.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 - // TODO: When Firefox supports minsize, use the next line. - //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 label dimensions accordingly. - const labelStyle = style.withLevel(style.level < 2 ? 2 : 3); - const minArrowWidth = labelSize(minWidth, labelStyle.level); - // The dummyNode will be inside a inside a - // So it will be at scriptlevel 3 - const dummyWidth = labelSize(minWidth, 3); - const emptyLabel = paddedNode(null, minArrowWidth.toFixed(4), 0); - const dummyNode = paddedNode(null, dummyWidth.toFixed(4), 0); - // The arrow is a little longer than the label. Set a spacer length. - const space = labelSize((isEq ? 0 : 0.3), labelStyle.level).toFixed(4); - let upperNode; - let lowerNode; - - const gotUpper = (body && body.body && - // \hphantom visible content - (body.body.body || body.body.length > 0)); - if (gotUpper) { - let label = buildGroup$1(body, labelStyle); - label = paddedNode(label, space, space); - // Since Firefox does not support minsize, stack a invisible node - // on top of the label. Its width will serve as a min-width. - // TODO: Refactor this after Firefox supports minsize. - upperNode = new mathMLTree.MathNode("mover", [label, dummyNode]); - } - const gotLower = (below && below.body && - (below.body.body || below.body.length > 0)); - if (gotLower) { - let label = buildGroup$1(below, labelStyle); - label = paddedNode(label, space, space); - lowerNode = new mathMLTree.MathNode("munder", [label, dummyNode]); - } - - let node; - if (!gotUpper && !gotLower) { - node = new mathMLTree.MathNode("mover", [arrowNode, emptyLabel]); - } else if (gotUpper && gotLower) { - node = new mathMLTree.MathNode("munderover", [arrowNode, lowerNode, upperNode]); - } else if (gotUpper) { - node = new mathMLTree.MathNode("mover", [arrowNode, upperNode]); - } else { - node = new mathMLTree.MathNode("munder", [arrowNode, lowerNode]); - } - if (minWidth === "3.0") { node.style.height = "1em"; } // CD environment - node.setAttribute("accent", "false"); // Necessary for MS Word - 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 5 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 row = [node]; - row.unshift(padding$2(0.2778)); - row.push(padding$2(0.2778)); - return new mathMLTree.MathNode("mrow", row) - } -}); - -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", - [padding$2(0.2778), botNode, raiseNode, padding$2(0.2778)] - ); - } else { - raiseNode.setAttribute("width", (group.name === "\\equilibriumRight" ? "0.5em" : "0")); - wrapper = new mathMLTree.MathNode( - "mpadded", - [padding$2(0.2778), raiseNode, botArrow, padding$2(0.2778)] - ); - } - - wrapper.setAttribute("voffset", "-0.18em"); - wrapper.setAttribute("height", "-0.18em"); - wrapper.setAttribute("depth", "+0.18em"); - return wrapper - } -}); - -/** - * 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], - semisimple: true - }; - 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); - } - body.pop(); - - // End row group - parser.gullet.endGroup(); - // End array group defining \\ - parser.gullet.endGroup(); - - return { - type: "array", - mode: "math", - body, - envClasses: ["jot", "cd"], - cols: [], - 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(Number((num * 255).toFixed(0))); - }); - } - 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) => { - // In LaTeX, color is not supposed to change the spacing of any node. - // So instead of wrapping the group in an , we apply - // the color individually to each node and return a document fragment. - let expr = buildExpression(group.body, style.withColor(group.color)); - expr = expr.map(e => { - e.style.color = group.color; - return e - }); - return mathMLTree.newDocumentFragment(expr) -}; - -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, breakOnTokenText, 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); - } - - // Parse out the implicit body that should be colored. - const body = parser.parseExpression(true, breakOnTokenText, true); - - 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: 0, - allowedInText: true - }, - - handler({ parser }, args, optArgs) { - const size = parser.gullet.future().text === "[" ? parser.parseSizeGroup(true) : null; - 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 globalMap = { - "\\global": "\\global", - "\\long": "\\\\globallong", - "\\\\globallong": "\\\\globallong", - "\\def": "\\gdef", - "\\gdef": "\\gdef", - "\\edef": "\\xdef", - "\\xdef": "\\xdef", - "\\let": "\\\\globallet", - "\\futurelet": "\\\\globalfuture" -}; - -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, global) => { - 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, global); -}; - -// -> | -// -> |\global -// -> | -// -> \global|\long|\outer -defineFunction({ - type: "internal", - names: [ - "\\global", - "\\long", - "\\\\globallong" // can’t be entered directly - ], - props: { - numArgs: 0, - allowedInText: true - }, - handler({ parser, funcName }) { - parser.consumeSpaces(); - const token = parser.fetch(); - if (globalMap[token.text]) { - // Temml doesn't have \par, so ignore \long - if (funcName === "\\global" || funcName === "\\\\globallong") { - token.text = globalMap[token.text]; - } - return assertNodeType(parser.parseFunction(), "internal"); - } - throw new ParseError(`Invalid token after macro prefix`, token); - } -}); - -// Basic support for macro definitions: \def, \gdef, \edef, \xdef -// -> -// -> \def|\gdef|\edef|\xdef -// -> -defineFunction({ - type: "internal", - names: ["\\def", "\\gdef", "\\edef", "\\xdef"], - 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" || funcName === "\\xdef") { - tokens = parser.gullet.expandTokens(tokens); - if (tokens.length > parser.gullet.settings.maxExpand) { - throw new ParseError("Too many expansions in an " + funcName); - } - tokens.reverse(); // to fit in with stack order - } - // Final arg is the expansion of the macro - parser.gullet.macros.set( - name, - { tokens, numArgs, delimiters }, - funcName === globalMap[funcName] - ); - return { type: "internal", mode: parser.mode }; - } -}); - -// -> -// -> \futurelet -// | \let -// -> |= -defineFunction({ - type: "internal", - names: [ - "\\let", - "\\\\globallet" // can’t be entered directly - ], - 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, funcName === "\\\\globallet"); - return { type: "internal", mode: parser.mode }; - } -}); - -// ref: https://www.tug.org/TUGboat/tb09-3/tb22bechtolsheim.pdf -defineFunction({ - type: "internal", - names: [ - "\\futurelet", - "\\\\globalfuture" // can’t be entered directly - ], - 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, funcName === "\\\\globalfuture"); - 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 }, - !parser.settings.strict - ); - - 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", - "⦇", - "\\llparenthesis", - "⦈", - "\\rrparenthesis", - "\\lfloor", - "\\rfloor", - "\u230a", - "\u230b", - "\\lceil", - "\\rceil", - "\u2308", - "\u2309", - "<", - ">", - "\\langle", - "\u27e8", - "\\rangle", - "\u27e9", - "\\lAngle", - "\u27ea", - "\\rAngle", - "\u27eb", - "\\llangle", - "⦉", - "\\rrangle", - "⦊", - "\\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", - "." -]; - -// Export isDelimiter for benefit of parser. -const dels = ["}", "\\left", "\\middle", "\\right"]; -const isDelimiter = str => str.length > 0 && - (delimiters.includes(str) || delimiterSizes[str] || dels.includes(str)); - -// 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) { - const symDelim = checkSymbolNodeType(delim); - if (symDelim && delimiters.includes(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 (["/", "\u2044"].includes(symDelim.text)) { symDelim.text = "\u2215"; } - if (["<", "\\lt"].includes(symDelim.text)) { symDelim.text = "⟨"; } - if ([">", "\\gt"].includes(symDelim.text)) { symDelim.text = "⟩"; } - 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" || group.delim === "\\vert" || - group.delim === "|" || group.delim.indexOf("arrow") > -1) { - // 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) => { - return { - type: "leftright-right", - mode: context.parser.mode, - delim: checkDelimiter(args[0], context).text - }; - } -}); - -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' or `\\middle` - let body = parser.parseExpression(false, null, true); - let nextToken = parser.fetch(); - while (nextToken.text === "\\middle") { - // `\middle`, from the ε-TeX package, ends one group and starts another group. - // We had to parse this expression with `breakOnMiddle` enabled in order - // to get TeX-compliant parsing of \over. - // But we do not want, at this point, to end on \middle, so continue - // to parse until we fetch a `\right`. - parser.consume(); - const middle = parser.fetch().text; - if (!symbols.math[middle]) { - throw new ParseError(`Invalid delimiter '${middle}' after '\\middle'`); - } - checkDelimiter({ type: "atom", mode: "math", text: middle }, { funcName: "\\middle" }); - body.push({ type: "middle", mode: "math", delim: middle }); - parser.consume(); - body = body.concat(parser.parseExpression(false, null, true)); - nextToken = parser.fetch(); - } - --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 - }; - }, - 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" || group.left.indexOf("arrow") > -1) { - 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" || group.right.indexOf("arrow") > -1) { - rightNode.setAttribute("stretchy", "true"); - } - 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"); - if (group.delim.indexOf("arrow") > -1) { - middleNode.setAttribute("stretchy", "true"); - } - // The next line is not semantically correct, but - // Chromium fails to stretch if it is not there. - middleNode.setAttribute("form", "prefix"); - // 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 padding$1 = _ => { - const node = new mathMLTree.MathNode("mspace"); - node.setAttribute("width", "3pt"); - return node -}; - -const mathmlBuilder$8 = (group, style) => { - let node; - if (group.label.indexOf("colorbox") > -1 || group.label === "\\boxed") { - // MathML core does not support +width attribute in . - // Firefox does not reliably add side padding. - // Insert - node = new mathMLTree.MathNode("mrow", [ - padding$1(), - buildGroup$1(group.body, style), - padding$1() - ]); - } else { - node = new mathMLTree.MathNode("mrow", [buildGroup$1(group.body, style)]); - } - switch (group.label) { - case "\\overline": - node.style.padding = "0.1em 0 0 0"; - node.style.borderTop = "0.065em solid"; - break - case "\\underline": - node.style.padding = "0 0 0.1em 0"; - node.style.borderBottom = "0.065em solid"; - break - case "\\cancel": - // We can't use an inline background-gradient. It does not work client-side. - // So set a class and put the rule in the external CSS file. - node.classes.push("tml-cancel"); - break - case "\\bcancel": - node.classes.push("tml-bcancel"); - break - /* - case "\\longdiv": - node.setAttribute("notation", "longdiv"); - break - case "\\phase": - node.setAttribute("notation", "phasorangle"); - break */ - case "\\angl": - node.style.padding = "0.03889em 0.03889em 0 0.03889em"; - node.style.borderTop = "0.049em solid"; - node.style.borderRight = "0.049em solid"; - node.style.marginRight = "0.03889em"; - break - case "\\sout": - node.style.backgroundImage = 'linear-gradient(black, black)'; - node.style.backgroundRepeat = 'no-repeat'; - node.style.backgroundSize = '100% 1.5px'; - node.style.backgroundPosition = '0 center'; - break - case "\\boxed": - // \newcommand{\boxed}[1]{\fbox{\m@th$\displaystyle#1$}} from amsmath.sty - node.style = { padding: "3pt 0 3pt 0", border: "1px solid" }; - node.setAttribute("scriptlevel", "0"); - node.setAttribute("displaystyle", "true"); - break - case "\\fbox": - node.style = { padding: "3pt", border: "1px solid" }; - 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("height", `+${2 * fboxsep}pt`) - //node.setAttribute("voffset", `${fboxsep}pt`) - const style = { padding: "3pt 0 3pt 0" }; - - if (group.label === "\\fcolorbox") { - style.border = "0.06em solid " + String(group.borderColor); - } - node.style = style; - break - } - case "\\xcancel": - node.classes.push("tml-xcancel"); - 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: ["\\angl", "\\cancel", "\\bcancel", "\\xcancel", "\\sout", "\\overline", "\\boxed"], - // , "\\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 -}); - -defineFunction({ - type: "enclose", - names: ["\\underline"], - props: { - numArgs: 1, - allowedInText: true - }, - 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; - if (nxt === "\\relax") { - parser.consume(); - parser.consumeSpaces(); - 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, true); - tag.classes = ["tml-tag"]; - } else { - // \notag. Return an empty span. - tag = new mathMLTree.MathNode("mtext", [], []); - return tag - } - } else if (group.envClasses.includes("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("mtext", [], []); - return tag - } else { - // AMS automatcally numbered equaton. - // Insert a class so the element can be populated by a CSS counter. - // WebKit will display the CSS counter only inside a span. - tag = new mathMLTree.MathNode("mtext", [new Span(["tml-eqn"])]); - } - 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, - { - cols, // [{ type: string , align: l|c|r|null }] - envClasses, // align(ed|at|edat) | array | cases | cd | small | 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", "\\@ifstar\\envtag@literal\\envtag@paren"); - parser.gullet.macros.set("\\envtag@paren", "\\env@tag{{(\\text{#1})}}"); - parser.gullet.macros.set("\\envtag@literal", "\\env@tag{\\text{#1}}"); - parser.gullet.macros.set("\\notag", "\\env@notag"); - parser.gullet.macros.set("\\nonumber", "\\env@notag"); - } - - // 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, - semisimple: true - }; - row.push(cell); - const next = parser.fetch().text; - if (next === "&") { - if (maxNumCols && row.length === maxNumCols) { - if (envClasses.includes("array")) { - if (parser.settings.strict) { - throw new ParseError("Too few columns " + "specified in the {array} column argument.", - parser.nextToken) - } - } else if (maxNumCols === 2) { - throw new ParseError("The split environment accepts no more than two columns", - 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, - body, - cols, - rowGaps, - hLinesBeforeRow, - envClasses, - addEqnNum, - scriptLevel, - tags, - leqno - }; -} - -// 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 glue = group => { - const glueNode = new mathMLTree.MathNode("mtd", []); - glueNode.style = { padding: "0", width: "50%" }; - if (group.envClasses.includes("multline")) { - glueNode.style.width = "7.5%"; - } - return glueNode -}; - -const mathmlBuilder$7 = function(group, style) { - const tbl = []; - const numRows = group.body.length; - const hlines = group.hLinesBeforeRow; - - for (let i = 0; i < numRows; i++) { - const rw = group.body[i]; - const row = []; - const cellLevel = 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(cellLevel))] - ); - - if (group.envClasses.includes("multline")) { - const align = i === 0 ? "left" : i === numRows - 1 ? "right" : "center"; - mtd.setAttribute("columnalign", align); - if (align !== "center") { - mtd.classes.push("tml-" + align); - } - } - row.push(mtd); - } - if (group.addEqnNum) { - row.unshift(glue(group)); - row.push(glue(group)); - const tag = getTag(group, style.withLevel(cellLevel), i); - if (group.leqno) { - row[0].children.push(tag); - row[0].classes.push("tml-left"); - } else { - row[row.length - 1].children.push(tag); - row[row.length - 1].classes.push("tml-right"); - } - } - const mtr = new mathMLTree.MathNode("mtr", row, []); - // Write horizontal rules - if (i === 0 && hlines[0].length > 0) { - if (hlines[0].length === 2) { - mtr.children.forEach(cell => { cell.style.borderTop = "0.15em double"; }); - } else { - mtr.children.forEach(cell => { - cell.style.borderTop = hlines[0][0] ? "0.06em dashed" : "0.06em solid"; - }); - } - } - if (hlines[i + 1].length > 0) { - if (hlines[i + 1].length === 2) { - mtr.children.forEach(cell => { cell.style.borderBottom = "0.15em double"; }); - } else { - mtr.children.forEach(cell => { - cell.style.borderBottom = hlines[i + 1][0] ? "0.06em dashed" : "0.06em solid"; - }); - } - } - tbl.push(mtr); - } - - if (group.envClasses.length > 0) { - const pad = group.envClasses.includes("jot") - ? "0.7" // 0.5ex + 0.09em top & bot padding - : group.envClasses.includes("small") - ? "0.35" - : "0.5"; // 0.5ex default top & bot padding - const sidePadding = group.envClasses.includes("abut") - ? "0" - : group.envClasses.includes("cases") - ? "0" - : group.envClasses.includes("small") - ? "0.1389" - : group.envClasses.includes("cd") - ? "0.25" - : "0.4"; // default side padding - - const numCols = tbl.length === 0 ? 0 : tbl[0].children.length; - - const sidePad = (j, hand) => { - if (j === 0 && hand === 0) { return "0" } - if (j === numCols - 1 && hand === 1) { return "0" } - if (group.envClasses[0] !== "align") { return sidePadding } - if (hand === 1) { return "0" } - if (group.addEqnNum) { - return (j % 2) ? "1" : "0" - } else { - return (j % 2) ? "0" : "1" - } - }; - - // Padding - for (let i = 0; i < tbl.length; i++) { - for (let j = 0; j < tbl[i].children.length; j++) { - tbl[i].children[j].style.padding = `${pad}ex ${sidePad(j, 1)}em ${pad}ex ${sidePad(j, 0)}em`; - } - } - - // Justification - const align = group.envClasses.includes("align") || group.envClasses.includes("alignat"); - for (let i = 0; i < tbl.length; i++) { - const row = tbl[i]; - if (align) { - for (let j = 0; j < row.children.length; j++) { - // Chromium does not recognize text-align: left. Use -webkit- - // TODO: Remove -webkit- when Chromium no longer needs it. - row.children[j].classes = ["tml-" + (j % 2 ? "left" : "right")]; - } - if (group.addEqnNum) { - const k = group.leqno ? 0 : row.children.length - 1; - row.children[k].classes = ["tml-" + (group.leqno ? "left" : "right")]; - } - } - if (row.children.length > 1 && group.envClasses.includes("cases")) { - row.children[1].style.padding = row.children[1].style.padding.replace(/0em$/, "1em"); - } - - if (group.envClasses.includes("cases") || group.envClasses.includes("subarray")) { - for (const cell of row.children) { - cell.classes.push("tml-left"); - } - } - } - } else { - // Set zero padding on side of the matrix - for (let i = 0; i < tbl.length; i++) { - tbl[i].children[0].style.paddingLeft = "0em"; - if (tbl[i].children.length === tbl[0].children.length) { - tbl[i].children[tbl[i].children.length - 1].style.paddingRight = "0em"; - } - } - } - - let table = new mathMLTree.MathNode("mtable", tbl); - if (group.scriptLevel === "display") { table.setAttribute("displaystyle", "true"); } - - if (group.addEqnNum || group.envClasses.includes("multline")) { - table.style.width = "100%"; - } - - // Column separator lines and column alignment - let align = ""; - - if (group.cols && group.cols.length > 0) { - const cols = group.cols; - let prevTypeWasAlign = false; - let iStart = 0; - let iEnd = cols.length; - - while (cols[iStart].type === "separator") { - iStart += 1; - } - while (cols[iEnd - 1].type === "separator") { - iEnd -= 1; - } - - if (cols[0].type === "separator") { - const sep = cols[1].type === "separator" - ? "0.15em double" - : cols[0].separator === "|" - ? "0.06em solid " - : "0.06em dashed "; - for (const row of table.children) { - row.children[0].style.borderLeft = sep; - } - } - let iCol = group.addEqnNum ? 0 : -1; - for (let i = iStart; i < iEnd; i++) { - if (cols[i].type === "align") { - const colAlign = alignMap[cols[i].align]; - align += colAlign; - iCol += 1; - for (const row of table.children) { - if (colAlign.trim() !== "center" && iCol < row.children.length) { - row.children[iCol].classes = ["tml-" + colAlign.trim()]; - } - } - 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) { - const sep = cols[i + 1].type === "separator" - ? "0.15em double" - : cols[i].separator === "|" - ? "0.06em solid" - : "0.06em dashed"; - for (const row of table.children) { - if (iCol < row.children.length) { - row.children[iCol].style.borderRight = sep; - } - } - } - prevTypeWasAlign = false; - } - } - if (cols[cols.length - 1].type === "separator") { - const sep = cols[cols.length - 2].type === "separator" - ? "0.15em double" - : cols[cols.length - 1].separator === "|" - ? "0.06em solid" - : "0.06em dashed"; - for (const row of table.children) { - row.children[row.children.length - 1].style.borderRight = sep; - row.children[row.children.length - 1].style.paddingRight = "0.4em"; - } - } - } - if (group.addEqnNum) { - // allow for glue cells on each side - align = "left " + (align.length > 0 ? align : "center ") + "right "; - } - if (align) { - // Firefox reads this attribute, not the -webkit-left|right written above. - // TODO: When Chrome no longer needs "-webkit-", use CSS and delete the next line. - table.setAttribute("columnalign", align.trim()); - } - - if (group.envClasses.includes("small")) { - // A small array. Wrap in scriptstyle. - table = new mathMLTree.MathNode("mstyle", [table]); - table.setAttribute("scriptlevel", "1"); - } - - return table -}; - -// Convenience function for align, align*, aligned, alignat, alignat*, alignedat, split. -const alignedHandler = function(context, args) { - if (context.envName.indexOf("ed") === -1) { - validateAmsEnvironmentContext(context); - } - const cols = []; - const res = parseArray( - context.parser, - { - cols, - addEqnNum: context.envName === "align" || context.envName === "alignat", - emptySingleRow: true, - envClasses: ["abut", "jot"], // set row spacing & provisional column spacing - 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; - const isAlignedAt = context.envName.indexOf("at") > -1; - if (args[0] && isAlignedAt) { - // alignat environment takes an argument w/ number of columns - let arg0 = ""; - for (let i = 0; i < args[0].body.length; i++) { - const textord = assertNodeType(args[0].body[i], "textord"); - arg0 += textord.text; - } - if (isNaN(arg0)) { - throw new ParseError("The alignat enviroment requires a numeric first argument.") - } - numMaths = Number(arg0); - numCols = numMaths * 2; - } - res.body.forEach(function(row) { - if (isAlignedAt) { - // 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 - }; - } - if (context.envName === "split") ; else if (isAlignedAt) { - res.envClasses.push("alignat"); // Sets justification - } else { - res.envClasses[0] = "align"; // Sets column spacing & justification - } - 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, - envClasses: ["array"], - 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 = { - envClasses: [], - cols: [] - }; - 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 = []; - } - } - const res = parseArray(context.parser, payload, "text"); - res.cols = new Array(res.body[0].length).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 = { type: "small" }; - const res = parseArray(context.parser, payload, "script"); - res.envClasses = ["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, - envClasses: ["small"] - }; - 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: [], - envClasses: ["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. -defineEnvironment({ - type: "array", - names: ["align", "align*", "aligned", "split"], - props: { - numArgs: 0 - }, - handler: alignedHandler, - 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 where spacing occurs. -defineEnvironment({ - type: "array", - names: ["alignat", "alignat*", "alignedat"], - props: { - numArgs: 1 - }, - 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 (context.envName !== "gathered") { - validateAmsEnvironmentContext(context); - } - const res = { - cols: [], - envClasses: ["abut", "jot"], - addEqnNum: context.envName === "gather", - emptySingleRow: true, - leqno: context.parser.settings.leqno - }; - return parseArray(context.parser, res, "display"); - }, - 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, - envClasses: ["align"], - 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, - envClasses: ["jot", "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 isLongVariableName = (group, font) => { - if (font !== "mathrm" || group.body.type !== "ordgroup" || group.body.body.length === 1) { - return false - } - if (group.body.body[0].type !== "mathord") { return false } - for (let i = 1; i < group.body.body.length; i++) { - const parseNodeType = group.body.body[i].type; - if (!(parseNodeType === "mathord" || - (parseNodeType === "textord" && !isNaN(group.body.body[i].text)))) { - return false - } - } - return true -}; - -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", "mrow"].includes(mathGroup.type)) { - mathGroup.style.fontWeight = "bold"; - return mathGroup - } - // Check if it is possible to consolidate elements into a single element. - if (isLongVariableName(group, font)) { - // This is a \mathrm{…} group. It gets special treatment because symbolsOrd.js - // wraps elements with s to work around a Firefox bug. - const mi = mathGroup.children[0].children[0]; - delete mi.attributes.mathvariant; - for (let i = 1; i < mathGroup.children.length; i++) { - mi.children[0].text += mathGroup.children[i].type === "mn" - ? mathGroup.children[i].children[0].text - : mathGroup.children[i].children[0].children[0].text; - } - // Wrap in a to prevent the same Firefox bug. - const bogus = new mathMLTree.MathNode("mtext", new mathMLTree.TextNode("\u200b")); - return new mathMLTree.MathNode("mrow", [bogus, mi]) - } - 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 (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", - - // 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, true); - 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 -}); - -// \hbox is provided for compatibility with LaTeX functions that act on a box. -// This function by itself doesn't do anything but set scriptlevel to \textstyle -// and 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 newStyle = style.withLevel(StyleLevel.TEXT); - const mrow = buildExpressionRow(group.body, newStyle); - return consolidateText(mrow) - } -}); - -const mathmlBuilder$4 = (group, style) => { - const accentNode = stretchy.mathMLnode(group.label); - accentNode.style["math-depth"] = 0; - 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); - if (dimension.number < 0) { - node.style.marginLeft = 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 - let strut; - if (group.alignment === "llap") { - // We need an invisible strut with the same depth as the group. - // We can't just read the depth, so we use \vphantom methods. - const phantomInner = buildExpression(ordargument(group.body), style); - const phantom = new mathMLTree.MathNode("mphantom", phantomInner); - strut = new mathMLTree.MathNode("mpadded", [phantom]); - strut.setAttribute("width", "0px"); - } - - const inner = buildGroup$1(group.body, style); - let node; - if (group.alignment === "llap") { - inner.style.position = "absolute"; - inner.style.right = "0"; - inner.style.bottom = `0`; // If we could have read the ink depth, it would go here. - node = new mathMLTree.MathNode("mpadded", [strut, inner]); - } else { - node = new mathMLTree.MathNode("mpadded", [inner]); - } - - 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"); - if (group.alignment === "llap") { - node.style.position = "relative"; - } else { - node.style.display = "flex"; - node.style.justifyContent = "center"; - } - } - 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"]; - -const padding = width => { - const node = new mathMLTree.MathNode("mspace"); - node.setAttribute("width", width + "em"); - return node -}; - -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"; - if (node.children.length === 1 && node.children[0].text && node.children[0].text === "∇") { - node.setAttribute("mathvariant", "normal"); - } - } else { - node = new mathMLTree.MathNode("mi", inner); - } - } else { - node = new mathMLTree.MathNode("mrow", inner); - 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("mrow", 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 (node.type === "mrow") { - if (doSpacing ) { - if (group.mclass === "mbin") { - // medium space - node.children.unshift(padding(0.2222)); - node.children.push(padding(0.2222)); - } else if (group.mclass === "mrel") { - // thickspace - node.children.unshift(padding(0.2778)); - node.children.push(padding(0.2778)); - } else if (group.mclass === "mpunct") { - node.children.push(padding(0.1667)); - } else if (group.mclass === "minner") { - node.children.unshift(padding(0.0556)); // 1 mu is the most likely option - node.children.push(padding(0.0556)); - } - } - } else { - 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 (symbols[parser.mode][arg.text]) { - mord.text += symbols[parser.mode][arg.text].replace; - } else 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, true); - return inner[0] - } else { - return buildExpressionRow(group.body, style) - } - } -}); - -// 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"]; - -// 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 setSpacing = node => { - // The user wrote a \mathop{…} function. Change spacing from default to OP spacing. - // The most likely spacing for an OP is a thin space per TeXbook p170. - node.attributes.lspace = "0.1667em"; - node.attributes.rspace = "0.1667em"; -}; - -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 (noSuccessor.includes(group.name)) { - node.setAttribute("largeop", "false"); - } else { - node.setAttribute("movablelimits", "false"); - } - if (group.fromMathOp) { setSpacing(node); } - } else if (group.body) { - // This is an operator with children. Add them. - node = new MathNode("mo", buildExpression(group.body, style)); - if (group.fromMathOp) { setSpacing(node); } - } 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")]); - const row = [node, operator]; - // Set spacing - if (group.needsLeadingSpace) { - const lead = new MathNode("mspace"); - lead.setAttribute("width", "0.1667em"); // thin space. - row.unshift(lead); - } - if (!group.isFollowedByDelimiter) { - const trail = new MathNode("mspace"); - trail.setAttribute("width", "0.1667em"); // thin space. - row.push(trail); - } - node = new MathNode("mrow", row); - } - } - - 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", - "\u2a09": "\\bigtimes" -}; - -defineFunction({ - type: "op", - names: [ - "\\coprod", - "\\bigvee", - "\\bigwedge", - "\\biguplus", - "\\bigcap", - "\\bigcup", - "\\intop", - "\\prod", - "\\sum", - "\\bigotimes", - "\\bigoplus", - "\\bigodot", - "\\bigsqcap", - "\\bigsqcup", - "\\bigtimes", - "\\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, - fromMathOp: true, - 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 && ordTypes.includes(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 && ordTypes.includes(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++) { - let node = expression[i]; - if (node instanceof mathMLTree.MathNode) { - if (node.type === "mrow" && node.children.length === 1 && - node.children[0] instanceof mathMLTree.MathNode) { - node = node.children[0]; - } - 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 - && ["mover", "munder"].includes(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); - if (expression[0].text.length === 1) { - 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")]); - const fragment = [wrapper, operator]; - 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. - fragment.unshift(space); - } - if (!group.isFollowedByDelimiter) { - const trail = new mathMLTree.MathNode("mspace"); - trail.setAttribute("width", "0.1667em"); // thin space. - fragment.push(trail); - } - return mathMLTree.newDocumentFragment(fragment) - } - - 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; - const next = parser.gullet.future().text; - return { - type: "operatorname", - mode: parser.mode, - body: ordargument(body), - alwaysHandleSupSub: (funcName === "\\operatornamewithlimits"), - limits: false, - parentIsSupSub: false, - isFollowedByDelimiter: isDelimiter(next), - needsLeadingSpace: prevAtomType.length > 0 && ordTypes.includes(prevAtomType) - }; - }, - mathmlBuilder: mathmlBuilder$1 -}); - -defineMacro("\\operatorname", - "\\@ifstar\\operatornamewithlimits\\operatorname@"); - -defineFunctionBuilders({ - type: "ordgroup", - mathmlBuilder(group, style) { - return buildExpressionRow(group.body, style, group.semisimple); - } -}); - -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; - } -}); - -// In LaTeX, \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 font-weight:bold. - -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", "font-weight:bold"); - return node - } -}); - -// \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); - // Add padding, which acts to increase height in Chromium. - // TODO: Figure out some way to change height in Firefox w/o breaking Chromium. - if (dy.number > 0) { - node.style.padding = dy.number + dy.unit + " 0 0 0"; - } else { - node.style.padding = "0 0 " + Math.abs(dy.number) + dy.unit + " 0"; - } - 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: "reflect", - names: ["\\reflectbox"], - props: { - numArgs: 1, - argTypes: ["hbox"], - allowedInText: true - }, - handler({ parser }, args) { - return { - type: "reflect", - mode: parser.mode, - body: args[0] - }; - }, - mathmlBuilder(group, style) { - const node = buildGroup$1(group.body, style); - node.style.transform = "scaleX(-1)"; - 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, true); - 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, true); - - 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 appendSpace = 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; - appendSpace = appendApplyFunction && !group.isFollowedByDelimiter; - 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) { - const sup = buildGroup$1(group.sup, childStyle); - const testNode = sup.type === "mrow" ? sup.children[0] : sup; - if ((testNode && testNode.type === "mo" && testNode.classes.includes("tml-prime")) - && group.base && group.base.text && group.base.text === "f") { - // Chromium does not address italic correction on prime. Prevent f′ from overlapping. - testNode.classes.push("prime-pad"); - } - children.push(sup); - } - - 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]); - } - if (appendSpace) { - const space = new mathMLTree.MathNode("mspace"); - space.setAttribute("width", "0.1667em"); // thin space. - node.children.push(space); - } - } 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"]; - -const arrows = ["\\Rsh", "\\Lsh", "\\restriction"]; - -const isArrow = str => { - if (str.length === 1) { - const codePoint = str.codePointAt(0); - return (0x218f < codePoint && codePoint < 0x2200) - } - return str.indexOf("arrow") > -1 || str.indexOf("harpoon") > -1 || arrows.includes(str) -}; - -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 (group.family === "rel" && isArrow(group.text)) { - 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" -}; - -/** - * 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" - } - - 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 0x1D317 }, - "italic": ch => { return 0x1D351 }, - // \boldsymbol actually returns upright bold for upperCaseGreek - "bold-italic": ch => { return 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 0x1D3C5 }, - "sans-serif-bold": ch => { return 0x1D3C5 }, - "sans-serif-italic": ch => { return 0 }, - "sans-serif-bold-italic": ch => { return 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) - ? "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,.]*\d)?$/; -const latinRegEx = /[A-Ba-z]/; -const primes = new Set(["\\prime", "\\dprime", "\\trprime", "\\qprime", - "\\backprime", "\\backdprime", "\\backtrprime"]); - -const italicNumber = (text, variant, tag) => { - const mn = new mathMLTree.MathNode(tag, [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("mrow", [node]); - } - } - 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 (numberRegEx.test(group.text)) { - const tag = group.mode === "text" ? "mtext" : "mn"; - if (variant === "italic" || variant === "bold-italic") { - return italicNumber(text, variant, tag) - } else { - if (variant !== "normal") { - text.text = text.text.split("").map(c => variantChar(c, variant)).join(""); - } - node = new mathMLTree.MathNode(tag, [text]); - } - } else if (group.mode === "text") { - if (variant !== "normal") { - text.text = variantChar(text.text, variant); - } - node = new mathMLTree.MathNode("mtext", [text]); - } else if (primes.has(group.text)) { - node = new mathMLTree.MathNode("mo", [text]); - // TODO: If/when Chromium uses ssty variant for prime, remove the next line. - node.classes.push("tml-prime"); - } 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 consolidateText(mrow) - } -}); - -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 - "([!-\\[\\]-\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(tokenRegexString, '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 local `set` take constant time, while global - * `set` takes time proportional to the depth of group nesting. - */ - -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 optionally set it globally too. - * Local set() sets the current value and (when appropriate) adds an undo - * operation to the undo stack. Global set() may change the undo - * operation at every level, so takes time linear in their number. - */ - set(name, value, global = false) { - if (global) { - // Global set is equivalent to setting in all groups. Simulate this - // by destroying any undos currently scheduled for this name, - // and adding an undo with the *new* value (in case it later gets - // locally reset within this environment). - for (let i = 0; i < this.undefStack.length; i++) { - delete this.undefStack[i][name]; - } - if (this.undefStack.length > 0) { - this.undefStack[this.undefStack.length - 1][name] = value; - } - } else { - // 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}}`; -}); - -function recreateArgStr(context) { - // Recreate the macro's original argument string from the array of parse tokens. - const tokens = context.consumeArgs(1)[0]; - let str = ""; - let expectedLoc = tokens[tokens.length - 1].loc.start; - for (let i = tokens.length - 1; i >= 0; i--) { - const actualLoc = tokens[i].loc.start; - if (actualLoc > expectedLoc) { - // context.consumeArgs has eaten a space. - str += " "; - expectedLoc = actualLoc; - } - str += tokens[i].text; - expectedLoc += tokens[i].text.length; - } - return str -} - -// The Latin Modern font renders at the wrong vertical alignment. -// This macro provides a better rendering. -defineMacro("\\surd", '\\sqrt{\\vphantom{|}}'); - -// See comment for \oplus in symbols.js. -defineMacro("\u2295", "\\oplus"); - -// 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", "{\\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}"); - -// \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", - "\\bigtimes": "\\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 (["bin", "rel"].includes(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"); - -defineMacro("\\AA", "\\TextOrMath{\\Angstrom}{\\mathring{A}}\\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}"); - -////////////////////////////////////////////////////////////////////// -// MnSymbol.sty - -defineMacro("\\leftmodels", "\\mathop{\\reflectbox{$\\models$}}"); - -////////////////////////////////////////////////////////////////////// -// 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"); -// A helper for \Braket and \Set -const replaceVert = (argStr, match) => { - const ch = match[0] === "|" ? "\\vert" : "\\Vert"; - const replaceStr = `}\\,\\middle${ch}\\,{`; - return argStr.slice(0, match.index) + replaceStr + argStr.slice(match.index + match[0].length) -}; -defineMacro("\\Braket", function(context) { - let argStr = recreateArgStr(context); - const regEx = /\|\||\||\\\|/g; - let match; - while ((match = regEx.exec(argStr)) !== null) { - argStr = replaceVert(argStr, match); - } - return "\\left\\langle{" + argStr + "}\\right\\rangle" -}); -defineMacro("\\Set", function(context) { - let argStr = recreateArgStr(context); - const match = /\|\||\||\\\|/.exec(argStr); - if (match) { - argStr = replaceVert(argStr, match); - } - return "\\left\\{\\:{" + argStr + "}\\:\\right\\}" -}); -defineMacro("\\set", function(context) { - const argStr = recreateArgStr(context); - return "\\{{" + argStr.replace(/\|/, "}\\mid{") + "}\\}" -}); - -////////////////////////////////////////////////////////////////////// -// 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 analysis - // 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 the number of such tokens will be - * returned. This number might be zero or positive. - * - * If not, the return value is `false`, and the next token remains at the - * top of the stack. - * - * In either case, the next token will be on the top of the stack, - * or the stack will be empty (in case of empty expansion - * and no other tokens). - * - * 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 false; - } - 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.length; - } - - /** - * 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 (;;) { - if (this.expandOnce() === false) { // fully expanded - const token = this.stack.pop(); - // The token after \noexpand is interpreted as if its meaning were ‘\relax’ - if (token.treatAsRelax) { - token.text = "\\relax"; - } - return token - } - } - - // 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) { - // Expand only expandable tokens - if (this.expandOnce(true) === false) { // fully expanded - const token = this.stack.pop(); - if (token.treatAsRelax) { - // the expansion of \noexpand is the token itself - token.noexpand = false; - token.treatAsRelax = false; - } - output.push(token); - } - } - 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; - } -} - -// 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': 'θ' -}); - -// Used for Unicode input of calligraphic and script letters -const asciiFromScript = Object.freeze({ - "\ud835\udc9c": "A", - "\u212c": "B", - "\ud835\udc9e": "C", - "\ud835\udc9f": "D", - "\u2130": "E", - "\u2131": "F", - "\ud835\udca2": "G", - "\u210B": "H", - "\u2110": "I", - "\ud835\udca5": "J", - "\ud835\udca6": "K", - "\u2112": "L", - "\u2133": "M", - "\ud835\udca9": "N", - "\ud835\udcaa": "O", - "\ud835\udcab": "P", - "\ud835\udcac": "Q", - "\u211B": "R", - "\ud835\udcae": "S", - "\ud835\udcaf": "T", - "\ud835\udcb0": "U", - "\ud835\udcb1": "V", - "\ud835\udcb2": "W", - "\ud835\udcb3": "X", - "\ud835\udcb4": "Y", - "\ud835\udcb5": "Z" -}); - -// 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 binLeftCancellers = ["bin", "op", "open", "punct", "rel"]; - -/** - * 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", "&"]; - } - - /** - * Fully parse a separate sequence of tokens as a separate job. - * Tokens should be specified in reverse order, as in a MacroDefinition. - */ - subparse(tokens) { - // Save the next token from the current job. - const oldToken = this.nextToken; - this.consume(); - - // Run the new job, terminating it with an excess '}' - this.gullet.pushToken(new Token("}")); - this.gullet.pushTokens(tokens); - const parse = this.parseExpression(false); - this.expect("}"); - - // Restore the next token from the current job. - this.nextToken = oldToken; - - return parse; - } - -/** - * 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 precedence 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. - * - * `breakOnMiddle`: \color, \over, and old styling functions work on an implicit group. - * These groups end just before the usual tokens, but they also - * end just before `\middle`. - */ - parseExpression(breakOnInfix, breakOnTokenText, breakOnMiddle) { - 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 (breakOnMiddle && lex.text === "\\middle") { - 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. - const isSub = unicodeSubRegEx.test(lex.text); - const subsupTokens = []; - subsupTokens.push(new Token(uSubsAndSups[lex.text])); - this.consume(); - // Continue fetching tokens to fill out the group. - while (true) { - const token = this.fetch().text; - if (!(uSubsAndSups[token])) { break } - if (unicodeSubRegEx.test(token) !== isSub) { break } - subsupTokens.unshift(new Token(uSubsAndSups[token])); - this.consume(); - } - // Now create a (sub|super)script. - const body = this.subparse(subsupTokens); - 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 - const isFollowedByDelimiter = (!base || base.type !== "op" && base.type !== "operatorname") - ? undefined - : isDelimiter(this.nextToken.text); - return { - type: "supsub", - mode: this.mode, - base: base, - sup: superscript, - sub: subscript, - isFollowedByDelimiter - } - } - } 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 (true) { - const ch = this.fetch().text; - // \ufe0e is the Unicode variation selector to supress emoji. Ignore it. - if (ch === " " || ch === "\u00a0" || ch === "\ufe0e") { - this.consume(); - } else { - break - } - } - } - - /** - * 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/ - 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]) { - let group = symbols[this.mode][text].group; - if (group === "bin" && binLeftCancellers.includes(this.prevAtomType)) { - // Change from a binary operator to a unary (prefix) operator - group = "open"; - } - 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 { - if (asciiFromScript[text]) { - // Unicode 14 disambiguates chancery from roundhand. - // See https://www.unicode.org/charts/PDF/U1D400.pdf - this.consume(); - const nextCode = this.fetch().text.charCodeAt(0); - // mathcal is Temml default. Use mathscript if called for. - const font = nextCode === 0xfe01 ? "mathscr" : "mathcal"; - if (nextCode === 0xfe00 || nextCode === 0xfe01) { this.consume(); } - return { - type: "font", - mode: "math", - font, - body: { type: "mathord", mode: "math", loc, text: asciiFromScript[text] } - } - } - // Default ord character. No disambiguation necessary. - s = { - type: group, - mode: this.mode, - loc, - text - }; - } - symbol = s; - } else if (text.charCodeAt(0) >= 0x80) { - // no symbol for e.g. ^ - if (this.settings.strict && 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, - 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, - * 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.10.25"; - -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 */ - -/** - * @type {import('./temml').render} - * Parse and build an expression, and place that expression in the DOM node - * given. - */ -let render = function(expression, baseNode, options = {}) { - baseNode.textContent = ""; - const alreadyInMathElement = baseNode.tagName.toLowerCase() === "math"; - if (alreadyInMathElement) { options.wrap = "none"; } - const math = renderToMathMLTree(expression, options); - if (alreadyInMathElement) { - // The element already exists. Populate it. - baseNode.textContent = ""; - math.children.forEach(e => { baseNode.appendChild(e.toNode()); }); - } else if (math.children.length > 1) { - 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."); - }; - } -} - -/** - * @type {import('./temml').renderToString} - * Parse and build an expression, and return the markup for that. - */ -const renderToString = function(expression, options) { - const markup = renderToMathMLTree(expression, options).toMarkup(); - return markup; -}; - -/** - * @type {import('./temml').generateParseTree} - * Parse an expression and return the parse tree. - */ -const generateParseTree = function(expression, options) { - const settings = new Settings(options); - return parseTree(expression, settings); -}; - -/** - * @type {import('./temml').definePreamble} - * 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; -}; - -/** - * @type {import('./temml').renderToMathMLTree} - * 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); - } -}; - -/** @type {import('./temml').default} */ -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/yarn.lock b/yarn.lock deleted file mode 100644 index 72e75671..00000000 --- a/yarn.lock +++ /dev/null @@ -1,1864 +0,0 @@ -# This file is generated by running "yarn install" inside your project. -# Manual changes might be lost - proceed with caution! - -__metadata: - version: 6 - cacheKey: 8 - -"@aashutoshrathi/word-wrap@npm:^1.2.3": - version: 1.2.6 - resolution: "@aashutoshrathi/word-wrap@npm:1.2.6" - checksum: ada901b9e7c680d190f1d012c84217ce0063d8f5c5a7725bb91ec3c5ed99bb7572680eb2d2938a531ccbaec39a95422fcd8a6b4a13110c7d98dd75402f66a0cd - languageName: node - linkType: hard - -"@eslint-community/eslint-utils@npm:^4.2.0": - version: 4.4.0 - resolution: "@eslint-community/eslint-utils@npm:4.4.0" - dependencies: - eslint-visitor-keys: ^3.3.0 - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - checksum: cdfe3ae42b4f572cbfb46d20edafe6f36fc5fb52bf2d90875c58aefe226892b9677fef60820e2832caf864a326fe4fc225714c46e8389ccca04d5f9288aabd22 - languageName: node - linkType: hard - -"@eslint-community/regexpp@npm:^4.6.1": - version: 4.10.0 - resolution: "@eslint-community/regexpp@npm:4.10.0" - checksum: 2a6e345429ea8382aaaf3a61f865cae16ed44d31ca917910033c02dc00d505d939f10b81e079fa14d43b51499c640138e153b7e40743c4c094d9df97d4e56f7b - languageName: node - linkType: hard - -"@eslint/eslintrc@npm:^2.1.2": - version: 2.1.2 - resolution: "@eslint/eslintrc@npm:2.1.2" - dependencies: - ajv: ^6.12.4 - debug: ^4.3.2 - espree: ^9.6.0 - globals: ^13.19.0 - ignore: ^5.2.0 - import-fresh: ^3.2.1 - js-yaml: ^4.1.0 - minimatch: ^3.1.2 - strip-json-comments: ^3.1.1 - checksum: bc742a1e3b361f06fedb4afb6bf32cbd27171292ef7924f61c62f2aed73048367bcc7ac68f98c06d4245cd3fabc43270f844e3c1699936d4734b3ac5398814a7 - languageName: node - linkType: hard - -"@eslint/js@npm:8.52.0": - version: 8.52.0 - resolution: "@eslint/js@npm:8.52.0" - checksum: 490893b8091a66415f4ac98b963d23eb287264ea3bd6af7ec788f0570705cf64fd6ab84b717785980f55e39d08ff5c7fde6d8e4391ccb507169370ce3a6d091a - languageName: node - linkType: hard - -"@humanwhocodes/config-array@npm:^0.11.13": - version: 0.11.13 - resolution: "@humanwhocodes/config-array@npm:0.11.13" - dependencies: - "@humanwhocodes/object-schema": ^2.0.1 - debug: ^4.1.1 - minimatch: ^3.0.5 - checksum: f8ea57b0d7ed7f2d64cd3944654976829d9da91c04d9c860e18804729a33f7681f78166ef4c761850b8c324d362f7d53f14c5c44907a6b38b32c703ff85e4805 - languageName: node - linkType: hard - -"@humanwhocodes/module-importer@npm:^1.0.1": - version: 1.0.1 - resolution: "@humanwhocodes/module-importer@npm:1.0.1" - checksum: 0fd22007db8034a2cdf2c764b140d37d9020bbfce8a49d3ec5c05290e77d4b0263b1b972b752df8c89e5eaa94073408f2b7d977aed131faf6cf396ebb5d7fb61 - languageName: node - linkType: hard - -"@humanwhocodes/object-schema@npm:^2.0.1": - version: 2.0.1 - resolution: "@humanwhocodes/object-schema@npm:2.0.1" - checksum: 24929487b1ed48795d2f08346a0116cc5ee4634848bce64161fb947109352c562310fd159fc64dda0e8b853307f5794605191a9547f7341158559ca3c8262a45 - languageName: node - linkType: hard - -"@isaacs/cliui@npm:^8.0.2": - version: 8.0.2 - resolution: "@isaacs/cliui@npm:8.0.2" - dependencies: - string-width: ^5.1.2 - string-width-cjs: "npm:string-width@^4.2.0" - strip-ansi: ^7.0.1 - strip-ansi-cjs: "npm:strip-ansi@^6.0.1" - wrap-ansi: ^8.1.0 - wrap-ansi-cjs: "npm:wrap-ansi@^7.0.0" - checksum: 4a473b9b32a7d4d3cfb7a614226e555091ff0c5a29a1734c28c72a182c2f6699b26fc6b5c2131dfd841e86b185aea714c72201d7c98c2fba5f17709333a67aeb - languageName: node - linkType: hard - -"@jridgewell/gen-mapping@npm:^0.3.0": - version: 0.3.3 - resolution: "@jridgewell/gen-mapping@npm:0.3.3" - dependencies: - "@jridgewell/set-array": ^1.0.1 - "@jridgewell/sourcemap-codec": ^1.4.10 - "@jridgewell/trace-mapping": ^0.3.9 - checksum: 4a74944bd31f22354fc01c3da32e83c19e519e3bbadafa114f6da4522ea77dd0c2842607e923a591d60a76699d819a2fbb6f3552e277efdb9b58b081390b60ab - languageName: node - linkType: hard - -"@jridgewell/resolve-uri@npm:^3.1.0": - version: 3.1.1 - resolution: "@jridgewell/resolve-uri@npm:3.1.1" - checksum: f5b441fe7900eab4f9155b3b93f9800a916257f4e8563afbcd3b5a5337b55e52bd8ae6735453b1b745457d9f6cdb16d74cd6220bbdd98cf153239e13f6cbb653 - languageName: node - linkType: hard - -"@jridgewell/set-array@npm:^1.0.1": - version: 1.1.2 - resolution: "@jridgewell/set-array@npm:1.1.2" - checksum: 69a84d5980385f396ff60a175f7177af0b8da4ddb81824cb7016a9ef914eee9806c72b6b65942003c63f7983d4f39a5c6c27185bbca88eb4690b62075602e28e - languageName: node - linkType: hard - -"@jridgewell/source-map@npm:^0.3.3": - version: 0.3.5 - resolution: "@jridgewell/source-map@npm:0.3.5" - dependencies: - "@jridgewell/gen-mapping": ^0.3.0 - "@jridgewell/trace-mapping": ^0.3.9 - checksum: 1ad4dec0bdafbade57920a50acec6634f88a0eb735851e0dda906fa9894e7f0549c492678aad1a10f8e144bfe87f238307bf2a914a1bc85b7781d345417e9f6f - languageName: node - linkType: hard - -"@jridgewell/sourcemap-codec@npm:^1.4.10, @jridgewell/sourcemap-codec@npm:^1.4.14": - version: 1.4.15 - resolution: "@jridgewell/sourcemap-codec@npm:1.4.15" - checksum: b881c7e503db3fc7f3c1f35a1dd2655a188cc51a3612d76efc8a6eb74728bef5606e6758ee77423e564092b4a518aba569bbb21c9bac5ab7a35b0c6ae7e344c8 - languageName: node - linkType: hard - -"@jridgewell/trace-mapping@npm:^0.3.9": - version: 0.3.20 - resolution: "@jridgewell/trace-mapping@npm:0.3.20" - dependencies: - "@jridgewell/resolve-uri": ^3.1.0 - "@jridgewell/sourcemap-codec": ^1.4.14 - checksum: cd1a7353135f385909468ff0cf20bdd37e59f2ee49a13a966dedf921943e222082c583ade2b579ff6cd0d8faafcb5461f253e1bf2a9f48fec439211fdbe788f5 - languageName: node - linkType: hard - -"@nodelib/fs.scandir@npm:2.1.5": - version: 2.1.5 - resolution: "@nodelib/fs.scandir@npm:2.1.5" - dependencies: - "@nodelib/fs.stat": 2.0.5 - run-parallel: ^1.1.9 - checksum: a970d595bd23c66c880e0ef1817791432dbb7acbb8d44b7e7d0e7a22f4521260d4a83f7f9fd61d44fda4610105577f8f58a60718105fb38352baed612fd79e59 - languageName: node - linkType: hard - -"@nodelib/fs.stat@npm:2.0.5": - version: 2.0.5 - resolution: "@nodelib/fs.stat@npm:2.0.5" - checksum: 012480b5ca9d97bff9261571dbbec7bbc6033f69cc92908bc1ecfad0792361a5a1994bc48674b9ef76419d056a03efadfce5a6cf6dbc0a36559571a7a483f6f0 - languageName: node - linkType: hard - -"@nodelib/fs.walk@npm:^1.2.8": - version: 1.2.8 - resolution: "@nodelib/fs.walk@npm:1.2.8" - dependencies: - "@nodelib/fs.scandir": 2.1.5 - fastq: ^1.6.0 - checksum: 190c643f156d8f8f277bf2a6078af1ffde1fd43f498f187c2db24d35b4b4b5785c02c7dc52e356497b9a1b65b13edc996de08de0b961c32844364da02986dc53 - languageName: node - linkType: hard - -"@npmcli/fs@npm:^3.1.0": - version: 3.1.0 - resolution: "@npmcli/fs@npm:3.1.0" - dependencies: - semver: ^7.3.5 - checksum: a50a6818de5fc557d0b0e6f50ec780a7a02ab8ad07e5ac8b16bf519e0ad60a144ac64f97d05c443c3367235d337182e1d012bbac0eb8dbae8dc7b40b193efd0e - languageName: node - linkType: hard - -"@pkgjs/parseargs@npm:^0.11.0": - version: 0.11.0 - resolution: "@pkgjs/parseargs@npm:0.11.0" - checksum: 6ad6a00fc4f2f2cfc6bff76fb1d88b8ee20bc0601e18ebb01b6d4be583733a860239a521a7fbca73b612e66705078809483549d2b18f370eb346c5155c8e4a0f - languageName: node - linkType: hard - -"@tootallnate/once@npm:2": - version: 2.0.0 - resolution: "@tootallnate/once@npm:2.0.0" - checksum: ad87447820dd3f24825d2d947ebc03072b20a42bfc96cbafec16bff8bbda6c1a81fcb0be56d5b21968560c5359a0af4038a68ba150c3e1694fe4c109a063bed8 - languageName: node - linkType: hard - -"@ungap/structured-clone@npm:^1.2.0": - version: 1.2.0 - resolution: "@ungap/structured-clone@npm:1.2.0" - checksum: 4f656b7b4672f2ce6e272f2427d8b0824ed11546a601d8d5412b9d7704e83db38a8d9f402ecdf2b9063fc164af842ad0ec4a55819f621ed7e7ea4d1efcc74524 - languageName: node - linkType: hard - -"abbrev@npm:^1.0.0": - version: 1.1.1 - resolution: "abbrev@npm:1.1.1" - checksum: a4a97ec07d7ea112c517036882b2ac22f3109b7b19077dc656316d07d308438aac28e4d9746dc4d84bf6b1e75b4a7b0a5f3cb30592419f128ca9a8cee3bcfa17 - languageName: node - linkType: hard - -"acorn-jsx@npm:^5.3.2": - version: 5.3.2 - resolution: "acorn-jsx@npm:5.3.2" - peerDependencies: - acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - checksum: c3d3b2a89c9a056b205b69530a37b972b404ee46ec8e5b341666f9513d3163e2a4f214a71f4dfc7370f5a9c07472d2fd1c11c91c3f03d093e37637d95da98950 - languageName: node - linkType: hard - -"acorn@npm:^8.8.2, acorn@npm:^8.9.0": - version: 8.10.0 - resolution: "acorn@npm:8.10.0" - bin: - acorn: bin/acorn - checksum: 538ba38af0cc9e5ef983aee196c4b8b4d87c0c94532334fa7e065b2c8a1f85863467bb774231aae91613fcda5e68740c15d97b1967ae3394d20faddddd8af61d - languageName: node - linkType: hard - -"agent-base@npm:6, agent-base@npm:^6.0.2": - version: 6.0.2 - resolution: "agent-base@npm:6.0.2" - dependencies: - debug: 4 - checksum: f52b6872cc96fd5f622071b71ef200e01c7c4c454ee68bc9accca90c98cfb39f2810e3e9aa330435835eedc8c23f4f8a15267f67c6e245d2b33757575bdac49d - languageName: node - linkType: hard - -"agentkeepalive@npm:^4.2.1": - version: 4.5.0 - resolution: "agentkeepalive@npm:4.5.0" - dependencies: - humanize-ms: ^1.2.1 - checksum: 13278cd5b125e51eddd5079f04d6fe0914ac1b8b91c1f3db2c1822f99ac1a7457869068997784342fe455d59daaff22e14fb7b8c3da4e741896e7e31faf92481 - languageName: node - linkType: hard - -"aggregate-error@npm:^3.0.0": - version: 3.1.0 - resolution: "aggregate-error@npm:3.1.0" - dependencies: - clean-stack: ^2.0.0 - indent-string: ^4.0.0 - checksum: 1101a33f21baa27a2fa8e04b698271e64616b886795fd43c31068c07533c7b3facfcaf4e9e0cab3624bd88f729a592f1c901a1a229c9e490eafce411a8644b79 - languageName: node - linkType: hard - -"ajv@npm:^6.12.4": - version: 6.12.6 - resolution: "ajv@npm:6.12.6" - 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 - checksum: 874972efe5c4202ab0a68379481fbd3d1b5d0a7bd6d3cc21d40d3536ebff3352a2a1fabb632d4fd2cc7fe4cbdcd5ed6782084c9bbf7f32a1536d18f9da5007d4 - languageName: node - linkType: hard - -"ansi-regex@npm:^5.0.1": - version: 5.0.1 - resolution: "ansi-regex@npm:5.0.1" - checksum: 2aa4bb54caf2d622f1afdad09441695af2a83aa3fe8b8afa581d205e57ed4261c183c4d3877cee25794443fde5876417d859c108078ab788d6af7e4fe52eb66b - languageName: node - linkType: hard - -"ansi-regex@npm:^6.0.1": - version: 6.0.1 - resolution: "ansi-regex@npm:6.0.1" - checksum: 1ff8b7667cded1de4fa2c9ae283e979fc87036864317da86a2e546725f96406746411d0d85e87a2d12fa5abd715d90006de7fa4fa0477c92321ad3b4c7d4e169 - languageName: node - linkType: hard - -"ansi-styles@npm:^4.0.0, ansi-styles@npm:^4.1.0": - version: 4.3.0 - resolution: "ansi-styles@npm:4.3.0" - dependencies: - color-convert: ^2.0.1 - checksum: 513b44c3b2105dd14cc42a19271e80f386466c4be574bccf60b627432f9198571ebf4ab1e4c3ba17347658f4ee1711c163d574248c0c1cdc2d5917a0ad582ec4 - languageName: node - linkType: hard - -"ansi-styles@npm:^6.1.0": - version: 6.2.1 - resolution: "ansi-styles@npm:6.2.1" - checksum: ef940f2f0ced1a6347398da88a91da7930c33ecac3c77b72c5905f8b8fe402c52e6fde304ff5347f616e27a742da3f1dc76de98f6866c69251ad0b07a66776d9 - languageName: node - linkType: hard - -"aproba@npm:^1.0.3 || ^2.0.0": - version: 2.0.0 - resolution: "aproba@npm:2.0.0" - checksum: 5615cadcfb45289eea63f8afd064ab656006361020e1735112e346593856f87435e02d8dcc7ff0d11928bc7d425f27bc7c2a84f6c0b35ab0ff659c814c138a24 - languageName: node - linkType: hard - -"are-we-there-yet@npm:^3.0.0": - version: 3.0.1 - resolution: "are-we-there-yet@npm:3.0.1" - dependencies: - delegates: ^1.0.0 - readable-stream: ^3.6.0 - checksum: 52590c24860fa7173bedeb69a4c05fb573473e860197f618b9a28432ee4379049336727ae3a1f9c4cb083114601c1140cee578376164d0e651217a9843f9fe83 - languageName: node - linkType: hard - -"argparse@npm:^2.0.1": - version: 2.0.1 - resolution: "argparse@npm:2.0.1" - checksum: 83644b56493e89a254bae05702abf3a1101b4fa4d0ca31df1c9985275a5a5bd47b3c27b7fa0b71098d41114d8ca000e6ed90cad764b306f8a503665e4d517ced - languageName: node - linkType: hard - -"balanced-match@npm:^1.0.0": - version: 1.0.2 - resolution: "balanced-match@npm:1.0.2" - checksum: 9706c088a283058a8a99e0bf91b0a2f75497f185980d9ffa8b304de1d9e58ebda7c72c07ebf01dadedaac5b2907b2c6f566f660d62bd336c3468e960403b9d65 - languageName: node - linkType: hard - -"brace-expansion@npm:^1.1.7": - version: 1.1.11 - resolution: "brace-expansion@npm:1.1.11" - dependencies: - balanced-match: ^1.0.0 - concat-map: 0.0.1 - checksum: faf34a7bb0c3fcf4b59c7808bc5d2a96a40988addf2e7e09dfbb67a2251800e0d14cd2bfc1aa79174f2f5095c54ff27f46fb1289fe2d77dac755b5eb3434cc07 - languageName: node - linkType: hard - -"brace-expansion@npm:^2.0.1": - version: 2.0.1 - resolution: "brace-expansion@npm:2.0.1" - dependencies: - balanced-match: ^1.0.0 - checksum: a61e7cd2e8a8505e9f0036b3b6108ba5e926b4b55089eeb5550cd04a471fe216c96d4fe7e4c7f995c728c554ae20ddfc4244cad10aef255e72b62930afd233d1 - languageName: node - linkType: hard - -"buffer-from@npm:^1.0.0": - version: 1.1.2 - resolution: "buffer-from@npm:1.1.2" - checksum: 0448524a562b37d4d7ed9efd91685a5b77a50672c556ea254ac9a6d30e3403a517d8981f10e565db24e8339413b43c97ca2951f10e399c6125a0d8911f5679bb - languageName: node - linkType: hard - -"cacache@npm:^17.0.0": - version: 17.1.4 - resolution: "cacache@npm:17.1.4" - dependencies: - "@npmcli/fs": ^3.1.0 - fs-minipass: ^3.0.0 - glob: ^10.2.2 - lru-cache: ^7.7.1 - minipass: ^7.0.3 - minipass-collect: ^1.0.2 - minipass-flush: ^1.0.5 - minipass-pipeline: ^1.2.4 - p-map: ^4.0.0 - ssri: ^10.0.0 - tar: ^6.1.11 - unique-filename: ^3.0.0 - checksum: b7751df756656954a51201335addced8f63fc53266fa56392c9f5ae83c8d27debffb4458ac2d168a744a4517ec3f2163af05c20097f93d17bdc2dc8a385e14a6 - languageName: node - linkType: hard - -"callsites@npm:^3.0.0": - version: 3.1.0 - resolution: "callsites@npm:3.1.0" - checksum: 072d17b6abb459c2ba96598918b55868af677154bec7e73d222ef95a8fdb9bbf7dae96a8421085cdad8cd190d86653b5b6dc55a4484f2e5b2e27d5e0c3fc15b3 - languageName: node - linkType: hard - -"chalk@npm:^4.0.0": - version: 4.1.2 - resolution: "chalk@npm:4.1.2" - dependencies: - ansi-styles: ^4.1.0 - supports-color: ^7.1.0 - checksum: fe75c9d5c76a7a98d45495b91b2172fa3b7a09e0cc9370e5c8feb1c567b85c4288e2b3fded7cfdd7359ac28d6b3844feb8b82b8686842e93d23c827c417e83fc - languageName: node - linkType: hard - -"chownr@npm:^2.0.0": - version: 2.0.0 - resolution: "chownr@npm:2.0.0" - checksum: c57cf9dd0791e2f18a5ee9c1a299ae6e801ff58fee96dc8bfd0dcb4738a6ce58dd252a3605b1c93c6418fe4f9d5093b28ffbf4d66648cb2a9c67eaef9679be2f - languageName: node - linkType: hard - -"clean-stack@npm:^2.0.0": - version: 2.2.0 - resolution: "clean-stack@npm:2.2.0" - checksum: 2ac8cd2b2f5ec986a3c743935ec85b07bc174d5421a5efc8017e1f146a1cf5f781ae962618f416352103b32c9cd7e203276e8c28241bbe946160cab16149fb68 - languageName: node - linkType: hard - -"color-convert@npm:^2.0.1": - version: 2.0.1 - resolution: "color-convert@npm:2.0.1" - dependencies: - color-name: ~1.1.4 - checksum: 79e6bdb9fd479a205c71d89574fccfb22bd9053bd98c6c4d870d65c132e5e904e6034978e55b43d69fcaa7433af2016ee203ce76eeba9cfa554b373e7f7db336 - languageName: node - linkType: hard - -"color-name@npm:~1.1.4": - version: 1.1.4 - resolution: "color-name@npm:1.1.4" - checksum: b0445859521eb4021cd0fb0cc1a75cecf67fceecae89b63f62b201cca8d345baf8b952c966862a9d9a2632987d4f6581f0ec8d957dfacece86f0a7919316f610 - languageName: node - linkType: hard - -"color-support@npm:^1.1.3": - version: 1.1.3 - resolution: "color-support@npm:1.1.3" - bin: - color-support: bin.js - checksum: 9b7356817670b9a13a26ca5af1c21615463b500783b739b7634a0c2047c16cef4b2865d7576875c31c3cddf9dd621fa19285e628f20198b233a5cfdda6d0793b - languageName: node - linkType: hard - -"commander@npm:^2.20.0": - version: 2.20.3 - resolution: "commander@npm:2.20.3" - checksum: ab8c07884e42c3a8dbc5dd9592c606176c7eb5c1ca5ff274bcf907039b2c41de3626f684ea75ccf4d361ba004bbaff1f577d5384c155f3871e456bdf27becf9e - languageName: node - linkType: hard - -"concat-map@npm:0.0.1": - version: 0.0.1 - resolution: "concat-map@npm:0.0.1" - checksum: 902a9f5d8967a3e2faf138d5cb784b9979bad2e6db5357c5b21c568df4ebe62bcb15108af1b2253744844eb964fc023fbd9afbbbb6ddd0bcc204c6fb5b7bf3af - languageName: node - linkType: hard - -"console-control-strings@npm:^1.1.0": - version: 1.1.0 - resolution: "console-control-strings@npm:1.1.0" - checksum: 8755d76787f94e6cf79ce4666f0c5519906d7f5b02d4b884cf41e11dcd759ed69c57da0670afd9236d229a46e0f9cf519db0cd829c6dca820bb5a5c3def584ed - languageName: node - linkType: hard - -"cross-spawn@npm:^7.0.0, cross-spawn@npm:^7.0.2": - version: 7.0.3 - resolution: "cross-spawn@npm:7.0.3" - dependencies: - path-key: ^3.1.0 - shebang-command: ^2.0.0 - which: ^2.0.1 - checksum: 671cc7c7288c3a8406f3c69a3ae2fc85555c04169e9d611def9a675635472614f1c0ed0ef80955d5b6d4e724f6ced67f0ad1bb006c2ea643488fcfef994d7f52 - languageName: node - linkType: hard - -"debug@npm:4, debug@npm:^4.1.1, debug@npm:^4.3.2, debug@npm:^4.3.3": - version: 4.3.4 - resolution: "debug@npm:4.3.4" - dependencies: - ms: 2.1.2 - peerDependenciesMeta: - supports-color: - optional: true - checksum: 3dbad3f94ea64f34431a9cbf0bafb61853eda57bff2880036153438f50fb5a84f27683ba0d8e5426bf41a8c6ff03879488120cf5b3a761e77953169c0600a708 - languageName: node - linkType: hard - -"deep-is@npm:^0.1.3": - version: 0.1.4 - resolution: "deep-is@npm:0.1.4" - checksum: edb65dd0d7d1b9c40b2f50219aef30e116cedd6fc79290e740972c132c09106d2e80aa0bc8826673dd5a00222d4179c84b36a790eef63a4c4bca75a37ef90804 - languageName: node - linkType: hard - -"delegates@npm:^1.0.0": - version: 1.0.0 - resolution: "delegates@npm:1.0.0" - checksum: a51744d9b53c164ba9c0492471a1a2ffa0b6727451bdc89e31627fdf4adda9d51277cfcbfb20f0a6f08ccb3c436f341df3e92631a3440226d93a8971724771fd - languageName: node - linkType: hard - -"doctrine@npm:^3.0.0": - version: 3.0.0 - resolution: "doctrine@npm:3.0.0" - dependencies: - esutils: ^2.0.2 - checksum: fd7673ca77fe26cd5cba38d816bc72d641f500f1f9b25b83e8ce28827fe2da7ad583a8da26ab6af85f834138cf8dae9f69b0cd6ab925f52ddab1754db44d99ce - languageName: node - linkType: hard - -"eastasianwidth@npm:^0.2.0": - version: 0.2.0 - resolution: "eastasianwidth@npm:0.2.0" - checksum: 7d00d7cd8e49b9afa762a813faac332dee781932d6f2c848dc348939c4253f1d4564341b7af1d041853bc3f32c2ef141b58e0a4d9862c17a7f08f68df1e0f1ed - languageName: node - linkType: hard - -"emoji-regex@npm:^8.0.0": - version: 8.0.0 - resolution: "emoji-regex@npm:8.0.0" - checksum: d4c5c39d5a9868b5fa152f00cada8a936868fd3367f33f71be515ecee4c803132d11b31a6222b2571b1e5f7e13890156a94880345594d0ce7e3c9895f560f192 - languageName: node - linkType: hard - -"emoji-regex@npm:^9.2.2": - version: 9.2.2 - resolution: "emoji-regex@npm:9.2.2" - checksum: 8487182da74aabd810ac6d6f1994111dfc0e331b01271ae01ec1eb0ad7b5ecc2bbbbd2f053c05cb55a1ac30449527d819bbfbf0e3de1023db308cbcb47f86601 - languageName: node - linkType: hard - -"encoding@npm:^0.1.13": - version: 0.1.13 - resolution: "encoding@npm:0.1.13" - dependencies: - iconv-lite: ^0.6.2 - checksum: bb98632f8ffa823996e508ce6a58ffcf5856330fde839ae42c9e1f436cc3b5cc651d4aeae72222916545428e54fd0f6aa8862fd8d25bdbcc4589f1e3f3715e7f - languageName: node - linkType: hard - -"env-paths@npm:^2.2.0": - version: 2.2.1 - resolution: "env-paths@npm:2.2.1" - checksum: 65b5df55a8bab92229ab2b40dad3b387fad24613263d103a97f91c9fe43ceb21965cd3392b1ccb5d77088021e525c4e0481adb309625d0cb94ade1d1fb8dc17e - languageName: node - linkType: hard - -"err-code@npm:^2.0.2": - version: 2.0.3 - resolution: "err-code@npm:2.0.3" - checksum: 8b7b1be20d2de12d2255c0bc2ca638b7af5171142693299416e6a9339bd7d88fc8d7707d913d78e0993176005405a236b066b45666b27b797252c771156ace54 - languageName: node - linkType: hard - -"escape-string-regexp@npm:^4.0.0": - version: 4.0.0 - resolution: "escape-string-regexp@npm:4.0.0" - checksum: 98b48897d93060f2322108bf29db0feba7dd774be96cd069458d1453347b25ce8682ecc39859d4bca2203cc0ab19c237bcc71755eff49a0f8d90beadeeba5cc5 - languageName: node - linkType: hard - -"eslint-scope@npm:^7.2.2": - version: 7.2.2 - resolution: "eslint-scope@npm:7.2.2" - dependencies: - esrecurse: ^4.3.0 - estraverse: ^5.2.0 - checksum: ec97dbf5fb04b94e8f4c5a91a7f0a6dd3c55e46bfc7bbcd0e3138c3a76977570e02ed89a1810c778dcd72072ff0e9621ba1379b4babe53921d71e2e4486fda3e - languageName: node - linkType: hard - -"eslint-visitor-keys@npm:^3.3.0, eslint-visitor-keys@npm:^3.4.1, eslint-visitor-keys@npm:^3.4.3": - version: 3.4.3 - resolution: "eslint-visitor-keys@npm:3.4.3" - checksum: 36e9ef87fca698b6fd7ca5ca35d7b2b6eeaaf106572e2f7fd31c12d3bfdaccdb587bba6d3621067e5aece31c8c3a348b93922ab8f7b2cbc6aaab5e1d89040c60 - languageName: node - linkType: hard - -"eslint@npm:^8.39.0": - version: 8.52.0 - resolution: "eslint@npm:8.52.0" - dependencies: - "@eslint-community/eslint-utils": ^4.2.0 - "@eslint-community/regexpp": ^4.6.1 - "@eslint/eslintrc": ^2.1.2 - "@eslint/js": 8.52.0 - "@humanwhocodes/config-array": ^0.11.13 - "@humanwhocodes/module-importer": ^1.0.1 - "@nodelib/fs.walk": ^1.2.8 - "@ungap/structured-clone": ^1.2.0 - ajv: ^6.12.4 - 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.2.2 - eslint-visitor-keys: ^3.4.3 - espree: ^9.6.1 - esquery: ^1.4.2 - esutils: ^2.0.2 - fast-deep-equal: ^3.1.3 - file-entry-cache: ^6.0.1 - find-up: ^5.0.0 - glob-parent: ^6.0.2 - globals: ^13.19.0 - graphemer: ^1.4.0 - ignore: ^5.2.0 - imurmurhash: ^0.1.4 - is-glob: ^4.0.0 - is-path-inside: ^3.0.3 - js-yaml: ^4.1.0 - json-stable-stringify-without-jsonify: ^1.0.1 - levn: ^0.4.1 - lodash.merge: ^4.6.2 - minimatch: ^3.1.2 - natural-compare: ^1.4.0 - optionator: ^0.9.3 - strip-ansi: ^6.0.1 - text-table: ^0.2.0 - bin: - eslint: bin/eslint.js - checksum: fd22d1e9bd7090e31b00cbc7a3b98f3b76020a4c4641f987ae7d0c8f52e1b88c3b268bdfdabac2e1a93513e5d11339b718ff45cbff48a44c35d7e52feba510ed - languageName: node - linkType: hard - -"esm@npm:^3.2.25": - version: 3.2.25 - resolution: "esm@npm:3.2.25" - checksum: 978aabe2de83541c105605a6d60a26ed8e627ef6bb0a7605fe15a95bbdea6b8348bd045255cb22219c054dd09a81a94823df00843d9e97f42419c92015ce3a64 - languageName: node - linkType: hard - -"espree@npm:^9.6.0, espree@npm:^9.6.1": - version: 9.6.1 - resolution: "espree@npm:9.6.1" - dependencies: - acorn: ^8.9.0 - acorn-jsx: ^5.3.2 - eslint-visitor-keys: ^3.4.1 - checksum: eb8c149c7a2a77b3f33a5af80c10875c3abd65450f60b8af6db1bfcfa8f101e21c1e56a561c6dc13b848e18148d43469e7cd208506238554fb5395a9ea5a1ab9 - languageName: node - linkType: hard - -"esquery@npm:^1.4.2": - version: 1.5.0 - resolution: "esquery@npm:1.5.0" - dependencies: - estraverse: ^5.1.0 - checksum: aefb0d2596c230118656cd4ec7532d447333a410a48834d80ea648b1e7b5c9bc9ed8b5e33a89cb04e487b60d622f44cf5713bf4abed7c97343edefdc84a35900 - languageName: node - linkType: hard - -"esrecurse@npm:^4.3.0": - version: 4.3.0 - resolution: "esrecurse@npm:4.3.0" - dependencies: - estraverse: ^5.2.0 - checksum: ebc17b1a33c51cef46fdc28b958994b1dc43cd2e86237515cbc3b4e5d2be6a811b2315d0a1a4d9d340b6d2308b15322f5c8291059521cc5f4802f65e7ec32837 - languageName: node - linkType: hard - -"estraverse@npm:^5.1.0, estraverse@npm:^5.2.0": - version: 5.3.0 - resolution: "estraverse@npm:5.3.0" - checksum: 072780882dc8416ad144f8fe199628d2b3e7bbc9989d9ed43795d2c90309a2047e6bc5979d7e2322a341163d22cfad9e21f4110597fe487519697389497e4e2b - languageName: node - linkType: hard - -"esutils@npm:^2.0.2": - version: 2.0.3 - resolution: "esutils@npm:2.0.3" - checksum: 22b5b08f74737379a840b8ed2036a5fb35826c709ab000683b092d9054e5c2a82c27818f12604bfc2a9a76b90b6834ef081edbc1c7ae30d1627012e067c6ec87 - languageName: node - linkType: hard - -"exponential-backoff@npm:^3.1.1": - version: 3.1.1 - resolution: "exponential-backoff@npm:3.1.1" - checksum: 3d21519a4f8207c99f7457287291316306255a328770d320b401114ec8481986e4e467e854cb9914dd965e0a1ca810a23ccb559c642c88f4c7f55c55778a9b48 - languageName: node - linkType: hard - -"fast-deep-equal@npm:^3.1.1, fast-deep-equal@npm:^3.1.3": - version: 3.1.3 - resolution: "fast-deep-equal@npm:3.1.3" - checksum: e21a9d8d84f53493b6aa15efc9cfd53dd5b714a1f23f67fb5dc8f574af80df889b3bce25dc081887c6d25457cce704e636395333abad896ccdec03abaf1f3f9d - languageName: node - linkType: hard - -"fast-json-stable-stringify@npm:^2.0.0": - version: 2.1.0 - resolution: "fast-json-stable-stringify@npm:2.1.0" - checksum: b191531e36c607977e5b1c47811158733c34ccb3bfde92c44798929e9b4154884378536d26ad90dfecd32e1ffc09c545d23535ad91b3161a27ddbb8ebe0cbecb - languageName: node - linkType: hard - -"fast-levenshtein@npm:^2.0.6": - version: 2.0.6 - resolution: "fast-levenshtein@npm:2.0.6" - checksum: 92cfec0a8dfafd9c7a15fba8f2cc29cd0b62b85f056d99ce448bbcd9f708e18ab2764bda4dd5158364f4145a7c72788538994f0d1787b956ef0d1062b0f7c24c - languageName: node - linkType: hard - -"fastq@npm:^1.6.0": - version: 1.15.0 - resolution: "fastq@npm:1.15.0" - dependencies: - reusify: ^1.0.4 - checksum: 0170e6bfcd5d57a70412440b8ef600da6de3b2a6c5966aeaf0a852d542daff506a0ee92d6de7679d1de82e644bce69d7a574a6c93f0b03964b5337eed75ada1a - languageName: node - linkType: hard - -"file-entry-cache@npm:^6.0.1": - version: 6.0.1 - resolution: "file-entry-cache@npm:6.0.1" - dependencies: - flat-cache: ^3.0.4 - checksum: f49701feaa6314c8127c3c2f6173cfefff17612f5ed2daaafc6da13b5c91fd43e3b2a58fd0d63f9f94478a501b167615931e7200e31485e320f74a33885a9c74 - languageName: node - linkType: hard - -"find-up@npm:^5.0.0": - version: 5.0.0 - resolution: "find-up@npm:5.0.0" - dependencies: - locate-path: ^6.0.0 - path-exists: ^4.0.0 - checksum: 07955e357348f34660bde7920783204ff5a26ac2cafcaa28bace494027158a97b9f56faaf2d89a6106211a8174db650dd9f503f9c0d526b1202d5554a00b9095 - languageName: node - linkType: hard - -"flat-cache@npm:^3.0.4": - version: 3.1.1 - resolution: "flat-cache@npm:3.1.1" - dependencies: - flatted: ^3.2.9 - keyv: ^4.5.3 - rimraf: ^3.0.2 - checksum: 4958cfe0f46acf84953d4e16676ef5f0d38eab3a92d532a1e8d5f88f11eea8b36d5d598070ff2aeae15f1fde18f8d7d089eefaf9db10b5a587cc1c9072325c7a - languageName: node - linkType: hard - -"flatted@npm:^3.2.9": - version: 3.2.9 - resolution: "flatted@npm:3.2.9" - checksum: f14167fbe26a9d20f6fca8d998e8f1f41df72c8e81f9f2c9d61ed2bea058248f5e1cbd05e7f88c0e5087a6a0b822a1e5e2b446e879f3cfbe0b07ba2d7f80b026 - languageName: node - linkType: hard - -"foreground-child@npm:^3.1.0": - version: 3.1.1 - resolution: "foreground-child@npm:3.1.1" - dependencies: - cross-spawn: ^7.0.0 - signal-exit: ^4.0.1 - checksum: 139d270bc82dc9e6f8bc045fe2aae4001dc2472157044fdfad376d0a3457f77857fa883c1c8b21b491c6caade9a926a4bed3d3d2e8d3c9202b151a4cbbd0bcd5 - languageName: node - linkType: hard - -"fs-minipass@npm:^2.0.0": - version: 2.1.0 - resolution: "fs-minipass@npm:2.1.0" - dependencies: - minipass: ^3.0.0 - checksum: 1b8d128dae2ac6cc94230cc5ead341ba3e0efaef82dab46a33d171c044caaa6ca001364178d42069b2809c35a1c3c35079a32107c770e9ffab3901b59af8c8b1 - languageName: node - linkType: hard - -"fs-minipass@npm:^3.0.0": - version: 3.0.3 - resolution: "fs-minipass@npm:3.0.3" - dependencies: - minipass: ^7.0.3 - checksum: 8722a41109130851d979222d3ec88aabaceeaaf8f57b2a8f744ef8bd2d1ce95453b04a61daa0078822bc5cd21e008814f06fe6586f56fef511e71b8d2394d802 - languageName: node - linkType: hard - -"fs.realpath@npm:^1.0.0": - version: 1.0.0 - resolution: "fs.realpath@npm:1.0.0" - checksum: 99ddea01a7e75aa276c250a04eedeffe5662bce66c65c07164ad6264f9de18fb21be9433ead460e54cff20e31721c811f4fb5d70591799df5f85dce6d6746fd0 - languageName: node - linkType: hard - -"fsevents@npm:~2.3.2": - version: 2.3.3 - resolution: "fsevents@npm:2.3.3" - dependencies: - node-gyp: latest - checksum: 11e6ea6fea15e42461fc55b4b0e4a0a3c654faa567f1877dbd353f39156f69def97a69936d1746619d656c4b93de2238bf731f6085a03a50cabf287c9d024317 - conditions: os=darwin - languageName: node - linkType: hard - -"fsevents@patch:fsevents@~2.3.2#~builtin": - version: 2.3.3 - resolution: "fsevents@patch:fsevents@npm%3A2.3.3#~builtin::version=2.3.3&hash=df0bf1" - dependencies: - node-gyp: latest - conditions: os=darwin - languageName: node - linkType: hard - -"gauge@npm:^4.0.3": - version: 4.0.4 - resolution: "gauge@npm:4.0.4" - dependencies: - aproba: ^1.0.3 || ^2.0.0 - color-support: ^1.1.3 - console-control-strings: ^1.1.0 - has-unicode: ^2.0.1 - signal-exit: ^3.0.7 - string-width: ^4.2.3 - strip-ansi: ^6.0.1 - wide-align: ^1.1.5 - checksum: 788b6bfe52f1dd8e263cda800c26ac0ca2ff6de0b6eee2fe0d9e3abf15e149b651bd27bf5226be10e6e3edb5c4e5d5985a5a1a98137e7a892f75eff76467ad2d - languageName: node - linkType: hard - -"glob-parent@npm:^6.0.2": - version: 6.0.2 - resolution: "glob-parent@npm:6.0.2" - dependencies: - is-glob: ^4.0.3 - checksum: c13ee97978bef4f55106b71e66428eb1512e71a7466ba49025fc2aec59a5bfb0954d5abd58fc5ee6c9b076eef4e1f6d3375c2e964b88466ca390da4419a786a8 - languageName: node - linkType: hard - -"glob@npm:^10.2.2": - version: 10.3.10 - resolution: "glob@npm:10.3.10" - dependencies: - foreground-child: ^3.1.0 - jackspeak: ^2.3.5 - minimatch: ^9.0.1 - minipass: ^5.0.0 || ^6.0.2 || ^7.0.0 - path-scurry: ^1.10.1 - bin: - glob: dist/esm/bin.mjs - checksum: 4f2fe2511e157b5a3f525a54092169a5f92405f24d2aed3142f4411df328baca13059f4182f1db1bf933e2c69c0bd89e57ae87edd8950cba8c7ccbe84f721cf3 - languageName: node - linkType: hard - -"glob@npm:^7.1.3, glob@npm:^7.1.4": - version: 7.2.3 - resolution: "glob@npm:7.2.3" - dependencies: - fs.realpath: ^1.0.0 - inflight: ^1.0.4 - inherits: 2 - minimatch: ^3.1.1 - once: ^1.3.0 - path-is-absolute: ^1.0.0 - checksum: 29452e97b38fa704dabb1d1045350fb2467cf0277e155aa9ff7077e90ad81d1ea9d53d3ee63bd37c05b09a065e90f16aec4a65f5b8de401d1dac40bc5605d133 - languageName: node - linkType: hard - -"globals@npm:^13.19.0": - version: 13.23.0 - resolution: "globals@npm:13.23.0" - dependencies: - type-fest: ^0.20.2 - checksum: 194c97cf8d1ef6ba59417234c2386549c4103b6e5f24b1ff1952de61a4753e5d2069435ba629de711a6480b1b1d114a98e2ab27f85e966d5a10c319c3bbd3dc3 - languageName: node - linkType: hard - -"graceful-fs@npm:^4.2.6": - version: 4.2.11 - resolution: "graceful-fs@npm:4.2.11" - checksum: ac85f94da92d8eb6b7f5a8b20ce65e43d66761c55ce85ac96df6865308390da45a8d3f0296dd3a663de65d30ba497bd46c696cc1e248c72b13d6d567138a4fc7 - languageName: node - linkType: hard - -"graphemer@npm:^1.4.0": - version: 1.4.0 - resolution: "graphemer@npm:1.4.0" - checksum: bab8f0be9b568857c7bec9fda95a89f87b783546d02951c40c33f84d05bb7da3fd10f863a9beb901463669b6583173a8c8cc6d6b306ea2b9b9d5d3d943c3a673 - languageName: node - linkType: hard - -"has-flag@npm:^4.0.0": - version: 4.0.0 - resolution: "has-flag@npm:4.0.0" - checksum: 261a1357037ead75e338156b1f9452c016a37dcd3283a972a30d9e4a87441ba372c8b81f818cd0fbcd9c0354b4ae7e18b9e1afa1971164aef6d18c2b6095a8ad - languageName: node - linkType: hard - -"has-unicode@npm:^2.0.1": - version: 2.0.1 - resolution: "has-unicode@npm:2.0.1" - checksum: 1eab07a7436512db0be40a710b29b5dc21fa04880b7f63c9980b706683127e3c1b57cb80ea96d47991bdae2dfe479604f6a1ba410106ee1046a41d1bd0814400 - languageName: node - linkType: hard - -"http-cache-semantics@npm:^4.1.1": - version: 4.1.1 - resolution: "http-cache-semantics@npm:4.1.1" - checksum: 83ac0bc60b17a3a36f9953e7be55e5c8f41acc61b22583060e8dedc9dd5e3607c823a88d0926f9150e571f90946835c7fe150732801010845c72cd8bbff1a236 - languageName: node - linkType: hard - -"http-proxy-agent@npm:^5.0.0": - version: 5.0.0 - resolution: "http-proxy-agent@npm:5.0.0" - dependencies: - "@tootallnate/once": 2 - agent-base: 6 - debug: 4 - checksum: e2ee1ff1656a131953839b2a19cd1f3a52d97c25ba87bd2559af6ae87114abf60971e498021f9b73f9fd78aea8876d1fb0d4656aac8a03c6caa9fc175f22b786 - languageName: node - linkType: hard - -"https-proxy-agent@npm:^5.0.0": - version: 5.0.1 - resolution: "https-proxy-agent@npm:5.0.1" - dependencies: - agent-base: 6 - debug: 4 - checksum: 571fccdf38184f05943e12d37d6ce38197becdd69e58d03f43637f7fa1269cf303a7d228aa27e5b27bbd3af8f09fd938e1c91dcfefff2df7ba77c20ed8dfc765 - languageName: node - linkType: hard - -"humanize-ms@npm:^1.2.1": - version: 1.2.1 - resolution: "humanize-ms@npm:1.2.1" - dependencies: - ms: ^2.0.0 - checksum: 9c7a74a2827f9294c009266c82031030eae811ca87b0da3dceb8d6071b9bde22c9f3daef0469c3c533cc67a97d8a167cd9fc0389350e5f415f61a79b171ded16 - languageName: node - linkType: hard - -"iconv-lite@npm:^0.6.2": - version: 0.6.3 - resolution: "iconv-lite@npm:0.6.3" - dependencies: - safer-buffer: ">= 2.1.2 < 3.0.0" - checksum: 3f60d47a5c8fc3313317edfd29a00a692cc87a19cac0159e2ce711d0ebc9019064108323b5e493625e25594f11c6236647d8e256fbe7a58f4a3b33b89e6d30bf - languageName: node - linkType: hard - -"ignore@npm:^5.2.0": - version: 5.2.4 - resolution: "ignore@npm:5.2.4" - checksum: 3d4c309c6006e2621659311783eaea7ebcd41fe4ca1d78c91c473157ad6666a57a2df790fe0d07a12300d9aac2888204d7be8d59f9aaf665b1c7fcdb432517ef - languageName: node - linkType: hard - -"import-fresh@npm:^3.2.1": - version: 3.3.0 - resolution: "import-fresh@npm:3.3.0" - dependencies: - parent-module: ^1.0.0 - resolve-from: ^4.0.0 - checksum: 2cacfad06e652b1edc50be650f7ec3be08c5e5a6f6d12d035c440a42a8cc028e60a5b99ca08a77ab4d6b1346da7d971915828f33cdab730d3d42f08242d09baa - languageName: node - linkType: hard - -"imurmurhash@npm:^0.1.4": - version: 0.1.4 - resolution: "imurmurhash@npm:0.1.4" - checksum: 7cae75c8cd9a50f57dadd77482359f659eaebac0319dd9368bcd1714f55e65badd6929ca58569da2b6494ef13fdd5598cd700b1eba23f8b79c5f19d195a3ecf7 - languageName: node - linkType: hard - -"indent-string@npm:^4.0.0": - version: 4.0.0 - resolution: "indent-string@npm:4.0.0" - checksum: 824cfb9929d031dabf059bebfe08cf3137365e112019086ed3dcff6a0a7b698cb80cf67ccccde0e25b9e2d7527aa6cc1fed1ac490c752162496caba3e6699612 - languageName: node - linkType: hard - -"inflight@npm:^1.0.4": - version: 1.0.6 - resolution: "inflight@npm:1.0.6" - dependencies: - once: ^1.3.0 - wrappy: 1 - checksum: f4f76aa072ce19fae87ce1ef7d221e709afb59d445e05d47fba710e85470923a75de35bfae47da6de1b18afc3ce83d70facf44cfb0aff89f0a3f45c0a0244dfd - languageName: node - linkType: hard - -"inherits@npm:2, inherits@npm:^2.0.3": - version: 2.0.4 - resolution: "inherits@npm:2.0.4" - checksum: 4a48a733847879d6cf6691860a6b1e3f0f4754176e4d71494c41f3475553768b10f84b5ce1d40fbd0e34e6bfbb864ee35858ad4dd2cf31e02fc4a154b724d7f1 - languageName: node - linkType: hard - -"ip@npm:^2.0.0": - version: 2.0.0 - resolution: "ip@npm:2.0.0" - checksum: cfcfac6b873b701996d71ec82a7dd27ba92450afdb421e356f44044ed688df04567344c36cbacea7d01b1c39a4c732dc012570ebe9bebfb06f27314bca625349 - languageName: node - linkType: hard - -"is-extglob@npm:^2.1.1": - version: 2.1.1 - resolution: "is-extglob@npm:2.1.1" - checksum: df033653d06d0eb567461e58a7a8c9f940bd8c22274b94bf7671ab36df5719791aae15eef6d83bbb5e23283967f2f984b8914559d4449efda578c775c4be6f85 - languageName: node - linkType: hard - -"is-fullwidth-code-point@npm:^3.0.0": - version: 3.0.0 - resolution: "is-fullwidth-code-point@npm:3.0.0" - checksum: 44a30c29457c7fb8f00297bce733f0a64cd22eca270f83e58c105e0d015e45c019491a4ab2faef91ab51d4738c670daff901c799f6a700e27f7314029e99e348 - languageName: node - linkType: hard - -"is-glob@npm:^4.0.0, is-glob@npm:^4.0.3": - version: 4.0.3 - resolution: "is-glob@npm:4.0.3" - dependencies: - is-extglob: ^2.1.1 - checksum: d381c1319fcb69d341cc6e6c7cd588e17cd94722d9a32dbd60660b993c4fb7d0f19438674e68dfec686d09b7c73139c9166b47597f846af387450224a8101ab4 - languageName: node - linkType: hard - -"is-lambda@npm:^1.0.1": - version: 1.0.1 - resolution: "is-lambda@npm:1.0.1" - checksum: 93a32f01940220532e5948538699ad610d5924ac86093fcee83022252b363eb0cc99ba53ab084a04e4fb62bf7b5731f55496257a4c38adf87af9c4d352c71c35 - languageName: node - linkType: hard - -"is-path-inside@npm:^3.0.3": - version: 3.0.3 - resolution: "is-path-inside@npm:3.0.3" - checksum: abd50f06186a052b349c15e55b182326f1936c89a78bf6c8f2b707412517c097ce04bc49a0ca221787bc44e1049f51f09a2ffb63d22899051988d3a618ba13e9 - languageName: node - linkType: hard - -"isexe@npm:^2.0.0": - version: 2.0.0 - resolution: "isexe@npm:2.0.0" - checksum: 26bf6c5480dda5161c820c5b5c751ae1e766c587b1f951ea3fcfc973bafb7831ae5b54a31a69bd670220e42e99ec154475025a468eae58ea262f813fdc8d1c62 - languageName: node - linkType: hard - -"jackspeak@npm:^2.3.5": - version: 2.3.6 - resolution: "jackspeak@npm:2.3.6" - dependencies: - "@isaacs/cliui": ^8.0.2 - "@pkgjs/parseargs": ^0.11.0 - dependenciesMeta: - "@pkgjs/parseargs": - optional: true - checksum: 57d43ad11eadc98cdfe7496612f6bbb5255ea69fe51ea431162db302c2a11011642f50cfad57288bd0aea78384a0612b16e131944ad8ecd09d619041c8531b54 - languageName: node - linkType: hard - -"js-yaml@npm:^4.1.0": - version: 4.1.0 - resolution: "js-yaml@npm:4.1.0" - dependencies: - argparse: ^2.0.1 - bin: - js-yaml: bin/js-yaml.js - checksum: c7830dfd456c3ef2c6e355cc5a92e6700ceafa1d14bba54497b34a99f0376cecbb3e9ac14d3e5849b426d5a5140709a66237a8c991c675431271c4ce5504151a - languageName: node - linkType: hard - -"json-buffer@npm:3.0.1": - version: 3.0.1 - resolution: "json-buffer@npm:3.0.1" - checksum: 9026b03edc2847eefa2e37646c579300a1f3a4586cfb62bf857832b60c852042d0d6ae55d1afb8926163fa54c2b01d83ae24705f34990348bdac6273a29d4581 - languageName: node - linkType: hard - -"json-schema-traverse@npm:^0.4.1": - version: 0.4.1 - resolution: "json-schema-traverse@npm:0.4.1" - checksum: 7486074d3ba247769fda17d5181b345c9fb7d12e0da98b22d1d71a5db9698d8b4bd900a3ec1a4ffdd60846fc2556274a5c894d0c48795f14cb03aeae7b55260b - languageName: node - linkType: hard - -"json-stable-stringify-without-jsonify@npm:^1.0.1": - version: 1.0.1 - resolution: "json-stable-stringify-without-jsonify@npm:1.0.1" - checksum: cff44156ddce9c67c44386ad5cddf91925fe06b1d217f2da9c4910d01f358c6e3989c4d5a02683c7a5667f9727ff05831f7aa8ae66c8ff691c556f0884d49215 - languageName: node - linkType: hard - -"keyv@npm:^4.5.3": - version: 4.5.4 - resolution: "keyv@npm:4.5.4" - dependencies: - json-buffer: 3.0.1 - checksum: 74a24395b1c34bd44ad5cb2b49140d087553e170625240b86755a6604cd65aa16efdbdeae5cdb17ba1284a0fbb25ad06263755dbc71b8d8b06f74232ce3cdd72 - languageName: node - linkType: hard - -"levn@npm:^0.4.1": - version: 0.4.1 - resolution: "levn@npm:0.4.1" - dependencies: - prelude-ls: ^1.2.1 - type-check: ~0.4.0 - checksum: 12c5021c859bd0f5248561bf139121f0358285ec545ebf48bb3d346820d5c61a4309535c7f387ed7d84361cf821e124ce346c6b7cef8ee09a67c1473b46d0fc4 - languageName: node - linkType: hard - -"locate-path@npm:^6.0.0": - version: 6.0.0 - resolution: "locate-path@npm:6.0.0" - dependencies: - p-locate: ^5.0.0 - checksum: 72eb661788a0368c099a184c59d2fee760b3831c9c1c33955e8a19ae4a21b4116e53fa736dc086cdeb9fce9f7cc508f2f92d2d3aae516f133e16a2bb59a39f5a - languageName: node - linkType: hard - -"lodash.merge@npm:^4.6.2": - version: 4.6.2 - resolution: "lodash.merge@npm:4.6.2" - checksum: ad580b4bdbb7ca1f7abf7e1bce63a9a0b98e370cf40194b03380a46b4ed799c9573029599caebc1b14e3f24b111aef72b96674a56cfa105e0f5ac70546cdc005 - languageName: node - linkType: hard - -"lru-cache@npm:^6.0.0": - version: 6.0.0 - resolution: "lru-cache@npm:6.0.0" - dependencies: - yallist: ^4.0.0 - checksum: f97f499f898f23e4585742138a22f22526254fdba6d75d41a1c2526b3b6cc5747ef59c5612ba7375f42aca4f8461950e925ba08c991ead0651b4918b7c978297 - languageName: node - linkType: hard - -"lru-cache@npm:^7.7.1": - version: 7.18.3 - resolution: "lru-cache@npm:7.18.3" - checksum: e550d772384709deea3f141af34b6d4fa392e2e418c1498c078de0ee63670f1f46f5eee746e8ef7e69e1c895af0d4224e62ee33e66a543a14763b0f2e74c1356 - languageName: node - linkType: hard - -"lru-cache@npm:^9.1.1 || ^10.0.0": - version: 10.0.1 - resolution: "lru-cache@npm:10.0.1" - checksum: 06f8d0e1ceabd76bb6f644a26dbb0b4c471b79c7b514c13c6856113879b3bf369eb7b497dad4ff2b7e2636db202412394865b33c332100876d838ad1372f0181 - languageName: node - linkType: hard - -"make-fetch-happen@npm:^11.0.3": - version: 11.1.1 - resolution: "make-fetch-happen@npm:11.1.1" - dependencies: - agentkeepalive: ^4.2.1 - cacache: ^17.0.0 - http-cache-semantics: ^4.1.1 - http-proxy-agent: ^5.0.0 - https-proxy-agent: ^5.0.0 - is-lambda: ^1.0.1 - lru-cache: ^7.7.1 - minipass: ^5.0.0 - minipass-fetch: ^3.0.0 - minipass-flush: ^1.0.5 - minipass-pipeline: ^1.2.4 - negotiator: ^0.6.3 - promise-retry: ^2.0.1 - socks-proxy-agent: ^7.0.0 - ssri: ^10.0.0 - checksum: 7268bf274a0f6dcf0343829489a4506603ff34bd0649c12058753900b0eb29191dce5dba12680719a5d0a983d3e57810f594a12f3c18494e93a1fbc6348a4540 - languageName: node - linkType: hard - -"minimatch@npm:^3.0.5, minimatch@npm:^3.1.1, minimatch@npm:^3.1.2": - version: 3.1.2 - resolution: "minimatch@npm:3.1.2" - dependencies: - brace-expansion: ^1.1.7 - checksum: c154e566406683e7bcb746e000b84d74465b3a832c45d59912b9b55cd50dee66e5c4b1e5566dba26154040e51672f9aa450a9aef0c97cfc7336b78b7afb9540a - languageName: node - linkType: hard - -"minimatch@npm:^9.0.1": - version: 9.0.3 - resolution: "minimatch@npm:9.0.3" - dependencies: - brace-expansion: ^2.0.1 - checksum: 253487976bf485b612f16bf57463520a14f512662e592e95c571afdab1442a6a6864b6c88f248ce6fc4ff0b6de04ac7aa6c8bb51e868e99d1d65eb0658a708b5 - languageName: node - linkType: hard - -"minipass-collect@npm:^1.0.2": - version: 1.0.2 - resolution: "minipass-collect@npm:1.0.2" - dependencies: - minipass: ^3.0.0 - checksum: 14df761028f3e47293aee72888f2657695ec66bd7d09cae7ad558da30415fdc4752bbfee66287dcc6fd5e6a2fa3466d6c484dc1cbd986525d9393b9523d97f10 - languageName: node - linkType: hard - -"minipass-fetch@npm:^3.0.0": - version: 3.0.4 - resolution: "minipass-fetch@npm:3.0.4" - dependencies: - encoding: ^0.1.13 - minipass: ^7.0.3 - minipass-sized: ^1.0.3 - minizlib: ^2.1.2 - dependenciesMeta: - encoding: - optional: true - checksum: af7aad15d5c128ab1ebe52e043bdf7d62c3c6f0cecb9285b40d7b395e1375b45dcdfd40e63e93d26a0e8249c9efd5c325c65575aceee192883970ff8cb11364a - languageName: node - linkType: hard - -"minipass-flush@npm:^1.0.5": - version: 1.0.5 - resolution: "minipass-flush@npm:1.0.5" - dependencies: - minipass: ^3.0.0 - checksum: 56269a0b22bad756a08a94b1ffc36b7c9c5de0735a4dd1ab2b06c066d795cfd1f0ac44a0fcae13eece5589b908ecddc867f04c745c7009be0b566421ea0944cf - languageName: node - linkType: hard - -"minipass-pipeline@npm:^1.2.4": - version: 1.2.4 - resolution: "minipass-pipeline@npm:1.2.4" - dependencies: - minipass: ^3.0.0 - checksum: b14240dac0d29823c3d5911c286069e36d0b81173d7bdf07a7e4a91ecdef92cdff4baaf31ea3746f1c61e0957f652e641223970870e2353593f382112257971b - languageName: node - linkType: hard - -"minipass-sized@npm:^1.0.3": - version: 1.0.3 - resolution: "minipass-sized@npm:1.0.3" - dependencies: - minipass: ^3.0.0 - checksum: 79076749fcacf21b5d16dd596d32c3b6bf4d6e62abb43868fac21674078505c8b15eaca4e47ed844985a4514854f917d78f588fcd029693709417d8f98b2bd60 - languageName: node - linkType: hard - -"minipass@npm:^3.0.0": - version: 3.3.6 - resolution: "minipass@npm:3.3.6" - dependencies: - yallist: ^4.0.0 - checksum: a30d083c8054cee83cdcdc97f97e4641a3f58ae743970457b1489ce38ee1167b3aaf7d815cd39ec7a99b9c40397fd4f686e83750e73e652b21cb516f6d845e48 - languageName: node - linkType: hard - -"minipass@npm:^5.0.0": - version: 5.0.0 - resolution: "minipass@npm:5.0.0" - checksum: 425dab288738853fded43da3314a0b5c035844d6f3097a8e3b5b29b328da8f3c1af6fc70618b32c29ff906284cf6406b6841376f21caaadd0793c1d5a6a620ea - languageName: node - linkType: hard - -"minipass@npm:^5.0.0 || ^6.0.2 || ^7.0.0, minipass@npm:^7.0.3": - version: 7.0.4 - resolution: "minipass@npm:7.0.4" - checksum: 87585e258b9488caf2e7acea242fd7856bbe9a2c84a7807643513a338d66f368c7d518200ad7b70a508664d408aa000517647b2930c259a8b1f9f0984f344a21 - languageName: node - linkType: hard - -"minizlib@npm:^2.1.1, minizlib@npm:^2.1.2": - version: 2.1.2 - resolution: "minizlib@npm:2.1.2" - dependencies: - minipass: ^3.0.0 - yallist: ^4.0.0 - checksum: f1fdeac0b07cf8f30fcf12f4b586795b97be856edea22b5e9072707be51fc95d41487faec3f265b42973a304fe3a64acd91a44a3826a963e37b37bafde0212c3 - languageName: node - linkType: hard - -"mkdirp@npm:^1.0.3": - version: 1.0.4 - resolution: "mkdirp@npm:1.0.4" - bin: - mkdirp: bin/cmd.js - checksum: a96865108c6c3b1b8e1d5e9f11843de1e077e57737602de1b82030815f311be11f96f09cce59bd5b903d0b29834733e5313f9301e3ed6d6f6fba2eae0df4298f - languageName: node - linkType: hard - -"ms@npm:2.1.2": - version: 2.1.2 - resolution: "ms@npm:2.1.2" - checksum: 673cdb2c3133eb050c745908d8ce632ed2c02d85640e2edb3ace856a2266a813b30c613569bf3354fdf4ea7d1a1494add3bfa95e2713baa27d0c2c71fc44f58f - languageName: node - linkType: hard - -"ms@npm:^2.0.0": - version: 2.1.3 - resolution: "ms@npm:2.1.3" - checksum: aa92de608021b242401676e35cfa5aa42dd70cbdc082b916da7fb925c542173e36bce97ea3e804923fe92c0ad991434e4a38327e15a1b5b5f945d66df615ae6d - languageName: node - linkType: hard - -"natural-compare@npm:^1.4.0": - version: 1.4.0 - resolution: "natural-compare@npm:1.4.0" - checksum: 23ad088b08f898fc9b53011d7bb78ec48e79de7627e01ab5518e806033861bef68d5b0cd0e2205c2f36690ac9571ff6bcb05eb777ced2eeda8d4ac5b44592c3d - languageName: node - linkType: hard - -"negotiator@npm:^0.6.3": - version: 0.6.3 - resolution: "negotiator@npm:0.6.3" - checksum: b8ffeb1e262eff7968fc90a2b6767b04cfd9842582a9d0ece0af7049537266e7b2506dfb1d107a32f06dd849ab2aea834d5830f7f4d0e5cb7d36e1ae55d021d9 - languageName: node - linkType: hard - -"node-gyp@npm:latest": - version: 9.4.0 - resolution: "node-gyp@npm:9.4.0" - dependencies: - env-paths: ^2.2.0 - exponential-backoff: ^3.1.1 - glob: ^7.1.4 - graceful-fs: ^4.2.6 - make-fetch-happen: ^11.0.3 - nopt: ^6.0.0 - npmlog: ^6.0.0 - rimraf: ^3.0.2 - semver: ^7.3.5 - tar: ^6.1.2 - which: ^2.0.2 - bin: - node-gyp: bin/node-gyp.js - checksum: 78b404e2e0639d64e145845f7f5a3cb20c0520cdaf6dda2f6e025e9b644077202ea7de1232396ba5bde3fee84cdc79604feebe6ba3ec84d464c85d407bb5da99 - languageName: node - linkType: hard - -"nopt@npm:^6.0.0": - version: 6.0.0 - resolution: "nopt@npm:6.0.0" - dependencies: - abbrev: ^1.0.0 - bin: - nopt: bin/nopt.js - checksum: 82149371f8be0c4b9ec2f863cc6509a7fd0fa729929c009f3a58e4eb0c9e4cae9920e8f1f8eb46e7d032fec8fb01bede7f0f41a67eb3553b7b8e14fa53de1dac - languageName: node - linkType: hard - -"npmlog@npm:^6.0.0": - version: 6.0.2 - resolution: "npmlog@npm:6.0.2" - dependencies: - are-we-there-yet: ^3.0.0 - console-control-strings: ^1.1.0 - gauge: ^4.0.3 - set-blocking: ^2.0.0 - checksum: ae238cd264a1c3f22091cdd9e2b106f684297d3c184f1146984ecbe18aaa86343953f26b9520dedd1b1372bc0316905b736c1932d778dbeb1fcf5a1001390e2a - languageName: node - linkType: hard - -"once@npm:^1.3.0": - version: 1.4.0 - resolution: "once@npm:1.4.0" - dependencies: - wrappy: 1 - checksum: cd0a88501333edd640d95f0d2700fbde6bff20b3d4d9bdc521bdd31af0656b5706570d6c6afe532045a20bb8dc0849f8332d6f2a416e0ba6d3d3b98806c7db68 - languageName: node - linkType: hard - -"optionator@npm:^0.9.3": - version: 0.9.3 - resolution: "optionator@npm:0.9.3" - dependencies: - "@aashutoshrathi/word-wrap": ^1.2.3 - deep-is: ^0.1.3 - fast-levenshtein: ^2.0.6 - levn: ^0.4.1 - prelude-ls: ^1.2.1 - type-check: ^0.4.0 - checksum: 09281999441f2fe9c33a5eeab76700795365a061563d66b098923eb719251a42bdbe432790d35064d0816ead9296dbeb1ad51a733edf4167c96bd5d0882e428a - languageName: node - linkType: hard - -"p-limit@npm:^3.0.2": - version: 3.1.0 - resolution: "p-limit@npm:3.1.0" - dependencies: - yocto-queue: ^0.1.0 - checksum: 7c3690c4dbf62ef625671e20b7bdf1cbc9534e83352a2780f165b0d3ceba21907e77ad63401708145ca4e25bfc51636588d89a8c0aeb715e6c37d1c066430360 - languageName: node - linkType: hard - -"p-locate@npm:^5.0.0": - version: 5.0.0 - resolution: "p-locate@npm:5.0.0" - dependencies: - p-limit: ^3.0.2 - checksum: 1623088f36cf1cbca58e9b61c4e62bf0c60a07af5ae1ca99a720837356b5b6c5ba3eb1b2127e47a06865fee59dd0453cad7cc844cda9d5a62ac1a5a51b7c86d3 - languageName: node - linkType: hard - -"p-map@npm:^4.0.0": - version: 4.0.0 - resolution: "p-map@npm:4.0.0" - dependencies: - aggregate-error: ^3.0.0 - checksum: cb0ab21ec0f32ddffd31dfc250e3afa61e103ef43d957cc45497afe37513634589316de4eb88abdfd969fe6410c22c0b93ab24328833b8eb1ccc087fc0442a1c - languageName: node - linkType: hard - -"parent-module@npm:^1.0.0": - version: 1.0.1 - resolution: "parent-module@npm:1.0.1" - dependencies: - callsites: ^3.0.0 - checksum: 6ba8b255145cae9470cf5551eb74be2d22281587af787a2626683a6c20fbb464978784661478dd2a3f1dad74d1e802d403e1b03c1a31fab310259eec8ac560ff - languageName: node - linkType: hard - -"path-exists@npm:^4.0.0": - version: 4.0.0 - resolution: "path-exists@npm:4.0.0" - checksum: 505807199dfb7c50737b057dd8d351b82c033029ab94cb10a657609e00c1bc53b951cfdbccab8de04c5584d5eff31128ce6afd3db79281874a5ef2adbba55ed1 - languageName: node - linkType: hard - -"path-is-absolute@npm:^1.0.0": - version: 1.0.1 - resolution: "path-is-absolute@npm:1.0.1" - checksum: 060840f92cf8effa293bcc1bea81281bd7d363731d214cbe5c227df207c34cd727430f70c6037b5159c8a870b9157cba65e775446b0ab06fd5ecc7e54615a3b8 - languageName: node - linkType: hard - -"path-key@npm:^3.1.0": - version: 3.1.1 - resolution: "path-key@npm:3.1.1" - checksum: 55cd7a9dd4b343412a8386a743f9c746ef196e57c823d90ca3ab917f90ab9f13dd0ded27252ba49dbdfcab2b091d998bc446f6220cd3cea65db407502a740020 - languageName: node - linkType: hard - -"path-scurry@npm:^1.10.1": - version: 1.10.1 - resolution: "path-scurry@npm:1.10.1" - dependencies: - lru-cache: ^9.1.1 || ^10.0.0 - minipass: ^5.0.0 || ^6.0.2 || ^7.0.0 - checksum: e2557cff3a8fb8bc07afdd6ab163a92587884f9969b05bbbaf6fe7379348bfb09af9ed292af12ed32398b15fb443e81692047b786d1eeb6d898a51eb17ed7d90 - languageName: node - linkType: hard - -"prelude-ls@npm:^1.2.1": - version: 1.2.1 - resolution: "prelude-ls@npm:1.2.1" - checksum: cd192ec0d0a8e4c6da3bb80e4f62afe336df3f76271ac6deb0e6a36187133b6073a19e9727a1ff108cd8b9982e4768850d413baa71214dd80c7979617dca827a - languageName: node - linkType: hard - -"promise-retry@npm:^2.0.1": - version: 2.0.1 - resolution: "promise-retry@npm:2.0.1" - dependencies: - err-code: ^2.0.2 - retry: ^0.12.0 - checksum: f96a3f6d90b92b568a26f71e966cbbc0f63ab85ea6ff6c81284dc869b41510e6cdef99b6b65f9030f0db422bf7c96652a3fff9f2e8fb4a0f069d8f4430359429 - languageName: node - linkType: hard - -"punycode@npm:^2.1.0": - version: 2.3.0 - resolution: "punycode@npm:2.3.0" - checksum: 39f760e09a2a3bbfe8f5287cf733ecdad69d6af2fe6f97ca95f24b8921858b91e9ea3c9eeec6e08cede96181b3bb33f95c6ffd8c77e63986508aa2e8159fa200 - languageName: node - linkType: hard - -"queue-microtask@npm:^1.2.2": - version: 1.2.3 - resolution: "queue-microtask@npm:1.2.3" - checksum: b676f8c040cdc5b12723ad2f91414d267605b26419d5c821ff03befa817ddd10e238d22b25d604920340fd73efd8ba795465a0377c4adf45a4a41e4234e42dc4 - languageName: node - linkType: hard - -"readable-stream@npm:^3.6.0": - version: 3.6.2 - resolution: "readable-stream@npm:3.6.2" - dependencies: - inherits: ^2.0.3 - string_decoder: ^1.1.1 - util-deprecate: ^1.0.1 - checksum: bdcbe6c22e846b6af075e32cf8f4751c2576238c5043169a1c221c92ee2878458a816a4ea33f4c67623c0b6827c8a400409bfb3cf0bf3381392d0b1dfb52ac8d - languageName: node - linkType: hard - -"resolve-from@npm:^4.0.0": - version: 4.0.0 - resolution: "resolve-from@npm:4.0.0" - checksum: f4ba0b8494846a5066328ad33ef8ac173801a51739eb4d63408c847da9a2e1c1de1e6cbbf72699211f3d13f8fc1325648b169bd15eb7da35688e30a5fb0e4a7f - languageName: node - linkType: hard - -"retry@npm:^0.12.0": - version: 0.12.0 - resolution: "retry@npm:0.12.0" - checksum: 623bd7d2e5119467ba66202d733ec3c2e2e26568074923bc0585b6b99db14f357e79bdedb63cab56cec47491c4a0da7e6021a7465ca6dc4f481d3898fdd3158c - languageName: node - linkType: hard - -"reusify@npm:^1.0.4": - version: 1.0.4 - resolution: "reusify@npm:1.0.4" - checksum: c3076ebcc22a6bc252cb0b9c77561795256c22b757f40c0d8110b1300723f15ec0fc8685e8d4ea6d7666f36c79ccc793b1939c748bf36f18f542744a4e379fcc - languageName: node - linkType: hard - -"rimraf@npm:^3.0.2": - version: 3.0.2 - resolution: "rimraf@npm:3.0.2" - dependencies: - glob: ^7.1.3 - bin: - rimraf: bin.js - checksum: 87f4164e396f0171b0a3386cc1877a817f572148ee13a7e113b238e48e8a9f2f31d009a92ec38a591ff1567d9662c6b67fd8818a2dbbaed74bc26a87a2a4a9a0 - languageName: node - linkType: hard - -"rollup@npm:^2.66.1": - version: 2.79.1 - resolution: "rollup@npm:2.79.1" - dependencies: - fsevents: ~2.3.2 - dependenciesMeta: - fsevents: - optional: true - bin: - rollup: dist/bin/rollup - checksum: 6a2bf167b3587d4df709b37d149ad0300692cc5deb510f89ac7bdc77c8738c9546ae3de9322b0968e1ed2b0e984571f5f55aae28fa7de4cfcb1bc5402a4e2be6 - languageName: node - linkType: hard - -"run-parallel@npm:^1.1.9": - version: 1.2.0 - resolution: "run-parallel@npm:1.2.0" - dependencies: - queue-microtask: ^1.2.2 - checksum: cb4f97ad25a75ebc11a8ef4e33bb962f8af8516bb2001082ceabd8902e15b98f4b84b4f8a9b222e5d57fc3bd1379c483886ed4619367a7680dad65316993021d - languageName: node - linkType: hard - -"safe-buffer@npm:~5.2.0": - version: 5.2.1 - resolution: "safe-buffer@npm:5.2.1" - checksum: b99c4b41fdd67a6aaf280fcd05e9ffb0813654894223afb78a31f14a19ad220bba8aba1cb14eddce1fcfb037155fe6de4e861784eb434f7d11ed58d1e70dd491 - languageName: node - linkType: hard - -"safer-buffer@npm:>= 2.1.2 < 3.0.0": - version: 2.1.2 - resolution: "safer-buffer@npm:2.1.2" - checksum: cab8f25ae6f1434abee8d80023d7e72b598cf1327164ddab31003c51215526801e40b66c5e65d658a0af1e9d6478cadcb4c745f4bd6751f97d8644786c0978b0 - languageName: node - linkType: hard - -"semver@npm:^7.3.5": - version: 7.5.4 - resolution: "semver@npm:7.5.4" - dependencies: - lru-cache: ^6.0.0 - bin: - semver: bin/semver.js - checksum: 12d8ad952fa353b0995bf180cdac205a4068b759a140e5d3c608317098b3575ac2f1e09182206bf2eb26120e1c0ed8fb92c48c592f6099680de56bb071423ca3 - languageName: node - linkType: hard - -"set-blocking@npm:^2.0.0": - version: 2.0.0 - resolution: "set-blocking@npm:2.0.0" - checksum: 6e65a05f7cf7ebdf8b7c75b101e18c0b7e3dff4940d480efed8aad3a36a4005140b660fa1d804cb8bce911cac290441dc728084a30504d3516ac2ff7ad607b02 - languageName: node - linkType: hard - -"shebang-command@npm:^2.0.0": - version: 2.0.0 - resolution: "shebang-command@npm:2.0.0" - dependencies: - shebang-regex: ^3.0.0 - checksum: 6b52fe87271c12968f6a054e60f6bde5f0f3d2db483a1e5c3e12d657c488a15474121a1d55cd958f6df026a54374ec38a4a963988c213b7570e1d51575cea7fa - languageName: node - linkType: hard - -"shebang-regex@npm:^3.0.0": - version: 3.0.0 - resolution: "shebang-regex@npm:3.0.0" - checksum: 1a2bcae50de99034fcd92ad4212d8e01eedf52c7ec7830eedcf886622804fe36884278f2be8be0ea5fde3fd1c23911643a4e0f726c8685b61871c8908af01222 - languageName: node - linkType: hard - -"signal-exit@npm:^3.0.7": - version: 3.0.7 - resolution: "signal-exit@npm:3.0.7" - checksum: a2f098f247adc367dffc27845853e9959b9e88b01cb301658cfe4194352d8d2bb32e18467c786a7fe15f1d44b233ea35633d076d5e737870b7139949d1ab6318 - languageName: node - linkType: hard - -"signal-exit@npm:^4.0.1": - version: 4.1.0 - resolution: "signal-exit@npm:4.1.0" - checksum: 64c757b498cb8629ffa5f75485340594d2f8189e9b08700e69199069c8e3070fb3e255f7ab873c05dc0b3cec412aea7402e10a5990cb6a050bd33ba062a6c549 - languageName: node - linkType: hard - -"smart-buffer@npm:^4.2.0": - version: 4.2.0 - resolution: "smart-buffer@npm:4.2.0" - checksum: b5167a7142c1da704c0e3af85c402002b597081dd9575031a90b4f229ca5678e9a36e8a374f1814c8156a725d17008ae3bde63b92f9cfd132526379e580bec8b - languageName: node - linkType: hard - -"socks-proxy-agent@npm:^7.0.0": - version: 7.0.0 - resolution: "socks-proxy-agent@npm:7.0.0" - dependencies: - agent-base: ^6.0.2 - debug: ^4.3.3 - socks: ^2.6.2 - checksum: 720554370154cbc979e2e9ce6a6ec6ced205d02757d8f5d93fe95adae454fc187a5cbfc6b022afab850a5ce9b4c7d73e0f98e381879cf45f66317a4895953846 - languageName: node - linkType: hard - -"socks@npm:^2.6.2": - version: 2.7.1 - resolution: "socks@npm:2.7.1" - dependencies: - ip: ^2.0.0 - smart-buffer: ^4.2.0 - checksum: 259d9e3e8e1c9809a7f5c32238c3d4d2a36b39b83851d0f573bfde5f21c4b1288417ce1af06af1452569cd1eb0841169afd4998f0e04ba04656f6b7f0e46d748 - languageName: node - linkType: hard - -"source-map-support@npm:~0.5.20": - version: 0.5.21 - resolution: "source-map-support@npm:0.5.21" - dependencies: - buffer-from: ^1.0.0 - source-map: ^0.6.0 - checksum: 43e98d700d79af1d36f859bdb7318e601dfc918c7ba2e98456118ebc4c4872b327773e5a1df09b0524e9e5063bb18f0934538eace60cca2710d1fa687645d137 - languageName: node - linkType: hard - -"source-map@npm:^0.6.0": - version: 0.6.1 - resolution: "source-map@npm:0.6.1" - checksum: 59ce8640cf3f3124f64ac289012c2b8bd377c238e316fb323ea22fbfe83da07d81e000071d7242cad7a23cd91c7de98e4df8830ec3f133cb6133a5f6e9f67bc2 - languageName: node - linkType: hard - -"ssri@npm:^10.0.0": - version: 10.0.5 - resolution: "ssri@npm:10.0.5" - dependencies: - minipass: ^7.0.3 - checksum: 0a31b65f21872dea1ed3f7c200d7bc1c1b91c15e419deca14f282508ba917cbb342c08a6814c7f68ca4ca4116dd1a85da2bbf39227480e50125a1ceffeecb750 - languageName: node - linkType: hard - -"string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^1.0.2 || 2 || 3 || 4, string-width@npm:^4.1.0, string-width@npm:^4.2.3": - version: 4.2.3 - resolution: "string-width@npm:4.2.3" - dependencies: - emoji-regex: ^8.0.0 - is-fullwidth-code-point: ^3.0.0 - strip-ansi: ^6.0.1 - checksum: e52c10dc3fbfcd6c3a15f159f54a90024241d0f149cf8aed2982a2d801d2e64df0bf1dc351cf8e95c3319323f9f220c16e740b06faecd53e2462df1d2b5443fb - languageName: node - linkType: hard - -"string-width@npm:^5.0.1, string-width@npm:^5.1.2": - version: 5.1.2 - resolution: "string-width@npm:5.1.2" - dependencies: - eastasianwidth: ^0.2.0 - emoji-regex: ^9.2.2 - strip-ansi: ^7.0.1 - checksum: 7369deaa29f21dda9a438686154b62c2c5f661f8dda60449088f9f980196f7908fc39fdd1803e3e01541970287cf5deae336798337e9319a7055af89dafa7193 - languageName: node - linkType: hard - -"string_decoder@npm:^1.1.1": - version: 1.3.0 - resolution: "string_decoder@npm:1.3.0" - dependencies: - safe-buffer: ~5.2.0 - checksum: 8417646695a66e73aefc4420eb3b84cc9ffd89572861fe004e6aeb13c7bc00e2f616247505d2dbbef24247c372f70268f594af7126f43548565c68c117bdeb56 - languageName: node - linkType: hard - -"strip-ansi-cjs@npm:strip-ansi@^6.0.1, strip-ansi@npm:^6.0.0, strip-ansi@npm:^6.0.1": - version: 6.0.1 - resolution: "strip-ansi@npm:6.0.1" - dependencies: - ansi-regex: ^5.0.1 - checksum: f3cd25890aef3ba6e1a74e20896c21a46f482e93df4a06567cebf2b57edabb15133f1f94e57434e0a958d61186087b1008e89c94875d019910a213181a14fc8c - languageName: node - linkType: hard - -"strip-ansi@npm:^7.0.1": - version: 7.1.0 - resolution: "strip-ansi@npm:7.1.0" - dependencies: - ansi-regex: ^6.0.1 - checksum: 859c73fcf27869c22a4e4d8c6acfe690064659e84bef9458aa6d13719d09ca88dcfd40cbf31fd0be63518ea1a643fe070b4827d353e09533a5b0b9fd4553d64d - languageName: node - linkType: hard - -"strip-json-comments@npm:^3.1.1": - version: 3.1.1 - resolution: "strip-json-comments@npm:3.1.1" - checksum: 492f73e27268f9b1c122733f28ecb0e7e8d8a531a6662efbd08e22cccb3f9475e90a1b82cab06a392f6afae6d2de636f977e231296400d0ec5304ba70f166443 - languageName: node - linkType: hard - -"supports-color@npm:^7.1.0": - version: 7.2.0 - resolution: "supports-color@npm:7.2.0" - dependencies: - has-flag: ^4.0.0 - checksum: 3dda818de06ebbe5b9653e07842d9479f3555ebc77e9a0280caf5a14fb877ffee9ed57007c3b78f5a6324b8dbeec648d9e97a24e2ed9fdb81ddc69ea07100f4a - languageName: node - linkType: hard - -"tar@npm:^6.1.11, tar@npm:^6.1.2": - version: 6.2.0 - resolution: "tar@npm:6.2.0" - dependencies: - chownr: ^2.0.0 - fs-minipass: ^2.0.0 - minipass: ^5.0.0 - minizlib: ^2.1.1 - mkdirp: ^1.0.3 - yallist: ^4.0.0 - checksum: db4d9fe74a2082c3a5016630092c54c8375ff3b280186938cfd104f2e089c4fd9bad58688ef6be9cf186a889671bf355c7cda38f09bbf60604b281715ca57f5c - languageName: node - linkType: hard - -"temml@workspace:.": - version: 0.0.0-use.local - resolution: "temml@workspace:." - dependencies: - eslint: ^8.39.0 - esm: ^3.2.25 - rollup: ^2.66.1 - terser: ^5.14.2 - languageName: unknown - linkType: soft - -"terser@npm:^5.14.2": - version: 5.22.0 - resolution: "terser@npm:5.22.0" - dependencies: - "@jridgewell/source-map": ^0.3.3 - acorn: ^8.8.2 - commander: ^2.20.0 - source-map-support: ~0.5.20 - bin: - terser: bin/terser - checksum: ee95981c54ebd381e0b7f5872c646e7a05543e53960f8e0c2f240863c368989d43a3ca80b7e9f691683c92ba199eb4b91d61785fef0b9ca4a887eb55866001f4 - languageName: node - linkType: hard - -"text-table@npm:^0.2.0": - version: 0.2.0 - resolution: "text-table@npm:0.2.0" - checksum: b6937a38c80c7f84d9c11dd75e49d5c44f71d95e810a3250bd1f1797fc7117c57698204adf676b71497acc205d769d65c16ae8fa10afad832ae1322630aef10a - languageName: node - linkType: hard - -"type-check@npm:^0.4.0, type-check@npm:~0.4.0": - version: 0.4.0 - resolution: "type-check@npm:0.4.0" - dependencies: - prelude-ls: ^1.2.1 - checksum: ec688ebfc9c45d0c30412e41ca9c0cdbd704580eb3a9ccf07b9b576094d7b86a012baebc95681999dd38f4f444afd28504cb3a89f2ef16b31d4ab61a0739025a - languageName: node - linkType: hard - -"type-fest@npm:^0.20.2": - version: 0.20.2 - resolution: "type-fest@npm:0.20.2" - checksum: 4fb3272df21ad1c552486f8a2f8e115c09a521ad7a8db3d56d53718d0c907b62c6e9141ba5f584af3f6830d0872c521357e512381f24f7c44acae583ad517d73 - languageName: node - linkType: hard - -"unique-filename@npm:^3.0.0": - version: 3.0.0 - resolution: "unique-filename@npm:3.0.0" - dependencies: - unique-slug: ^4.0.0 - checksum: 8e2f59b356cb2e54aab14ff98a51ac6c45781d15ceaab6d4f1c2228b780193dc70fae4463ce9e1df4479cb9d3304d7c2043a3fb905bdeca71cc7e8ce27e063df - languageName: node - linkType: hard - -"unique-slug@npm:^4.0.0": - version: 4.0.0 - resolution: "unique-slug@npm:4.0.0" - dependencies: - imurmurhash: ^0.1.4 - checksum: 0884b58365af59f89739e6f71e3feacb5b1b41f2df2d842d0757933620e6de08eff347d27e9d499b43c40476cbaf7988638d3acb2ffbcb9d35fd035591adfd15 - languageName: node - linkType: hard - -"uri-js@npm:^4.2.2": - version: 4.4.1 - resolution: "uri-js@npm:4.4.1" - dependencies: - punycode: ^2.1.0 - checksum: 7167432de6817fe8e9e0c9684f1d2de2bb688c94388f7569f7dbdb1587c9f4ca2a77962f134ec90be0cc4d004c939ff0d05acc9f34a0db39a3c797dada262633 - languageName: node - linkType: hard - -"util-deprecate@npm:^1.0.1": - version: 1.0.2 - resolution: "util-deprecate@npm:1.0.2" - checksum: 474acf1146cb2701fe3b074892217553dfcf9a031280919ba1b8d651a068c9b15d863b7303cb15bd00a862b498e6cf4ad7b4a08fb134edd5a6f7641681cb54a2 - languageName: node - linkType: hard - -"which@npm:^2.0.1, which@npm:^2.0.2": - version: 2.0.2 - resolution: "which@npm:2.0.2" - dependencies: - isexe: ^2.0.0 - bin: - node-which: ./bin/node-which - checksum: 1a5c563d3c1b52d5f893c8b61afe11abc3bab4afac492e8da5bde69d550de701cf9806235f20a47b5c8fa8a1d6a9135841de2596535e998027a54589000e66d1 - languageName: node - linkType: hard - -"wide-align@npm:^1.1.5": - version: 1.1.5 - resolution: "wide-align@npm:1.1.5" - dependencies: - string-width: ^1.0.2 || 2 || 3 || 4 - checksum: d5fc37cd561f9daee3c80e03b92ed3e84d80dde3365a8767263d03dacfc8fa06b065ffe1df00d8c2a09f731482fcacae745abfbb478d4af36d0a891fad4834d3 - languageName: node - linkType: hard - -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": - version: 7.0.0 - resolution: "wrap-ansi@npm:7.0.0" - dependencies: - ansi-styles: ^4.0.0 - string-width: ^4.1.0 - strip-ansi: ^6.0.0 - checksum: a790b846fd4505de962ba728a21aaeda189b8ee1c7568ca5e817d85930e06ef8d1689d49dbf0e881e8ef84436af3a88bc49115c2e2788d841ff1b8b5b51a608b - languageName: node - linkType: hard - -"wrap-ansi@npm:^8.1.0": - version: 8.1.0 - resolution: "wrap-ansi@npm:8.1.0" - dependencies: - ansi-styles: ^6.1.0 - string-width: ^5.0.1 - strip-ansi: ^7.0.1 - checksum: 371733296dc2d616900ce15a0049dca0ef67597d6394c57347ba334393599e800bab03c41d4d45221b6bc967b8c453ec3ae4749eff3894202d16800fdfe0e238 - languageName: node - linkType: hard - -"wrappy@npm:1": - version: 1.0.2 - resolution: "wrappy@npm:1.0.2" - checksum: 159da4805f7e84a3d003d8841557196034155008f817172d4e986bd591f74aa82aa7db55929a54222309e01079a65a92a9e6414da5a6aa4b01ee44a511ac3ee5 - languageName: node - linkType: hard - -"yallist@npm:^4.0.0": - version: 4.0.0 - resolution: "yallist@npm:4.0.0" - checksum: 343617202af32df2a15a3be36a5a8c0c8545208f3d3dfbc6bb7c3e3b7e8c6f8e7485432e4f3b88da3031a6e20afa7c711eded32ddfb122896ac5d914e75848d5 - languageName: node - linkType: hard - -"yocto-queue@npm:^0.1.0": - version: 0.1.0 - resolution: "yocto-queue@npm:0.1.0" - checksum: f77b3d8d00310def622123df93d4ee654fc6a0096182af8bd60679ddcdfb3474c56c6c7190817c84a2785648cdee9d721c0154eb45698c62176c322fb46fc700 - languageName: node - linkType: hard