asciimath-to-latex
Version:
AsciiMath to LaTeX converter
1,429 lines • 50.7 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const config = {
translateOnLoad: true,
mathcolor: '',
displaystyle: true,
showasciiformulaonhover: true,
decimalsign: '.',
AMdelimiter1: '`',
AMescape1: '\\\\`',
AMusedelimiter2: false,
AMdelimiter2: '$',
AMescape2: '\\\\\\$',
AMdelimiter2regexp: '\\$',
AMdocumentId: 'wikitext',
doubleblankmathdelimiter: false, // if true, x+1 is equal to `x+1`
}; // for IE this works only in <!-- -->
const CONST = 0, UNARY = 1, BINARY = 2, INFIX = 3, LEFTBRACKET = 4, RIGHTBRACKET = 5, SPACE = 6, UNDEROVER = 7, DEFINITION = 8, LEFTRIGHT = 9, TEXT = 10; // token types
const AMsqrt = {
input: 'sqrt',
tag: 'msqrt',
output: 'sqrt',
tex: null,
ttype: UNARY,
}, AMroot = {
input: 'root',
tag: 'mroot',
output: 'root',
tex: null,
ttype: BINARY,
}, AMfrac = { input: 'frac', tag: 'mfrac', output: '/', tex: null, ttype: BINARY }, AMdiv = { input: '/', tag: 'mfrac', output: '/', tex: null, ttype: INFIX }, AMover = {
input: 'stackrel',
tag: 'mover',
output: 'stackrel',
tex: null,
ttype: BINARY,
}, AMsub = { input: '_', tag: 'msub', output: '_', tex: null, ttype: INFIX }, AMsup = { input: '^', tag: 'msup', output: '^', tex: null, ttype: INFIX }, AMtext = {
input: 'text',
tag: 'mtext',
output: 'text',
tex: null,
ttype: TEXT,
}, AMmbox = {
input: 'mbox',
tag: 'mtext',
output: 'mbox',
tex: null,
ttype: TEXT,
}, AMquote = { input: '"', tag: 'mtext', output: 'mbox', tex: null, ttype: TEXT };
const AMsymbols = [
//some greek symbols
{ input: 'alpha', tag: 'mi', output: '\u03B1', tex: null, ttype: CONST },
{ input: 'beta', tag: 'mi', output: '\u03B2', tex: null, ttype: CONST },
{ input: 'chi', tag: 'mi', output: '\u03C7', tex: null, ttype: CONST },
{ input: 'delta', tag: 'mi', output: '\u03B4', tex: null, ttype: CONST },
{ input: 'Delta', tag: 'mo', output: '\u0394', tex: null, ttype: CONST },
{ input: 'epsi', tag: 'mi', output: '\u03B5', tex: 'epsilon', ttype: CONST },
{ input: 'varepsilon', tag: 'mi', output: '\u025B', tex: null, ttype: CONST },
{ input: 'eta', tag: 'mi', output: '\u03B7', tex: null, ttype: CONST },
{ input: 'gamma', tag: 'mi', output: '\u03B3', tex: null, ttype: CONST },
{ input: 'Gamma', tag: 'mo', output: '\u0393', tex: null, ttype: CONST },
{ input: 'iota', tag: 'mi', output: '\u03B9', tex: null, ttype: CONST },
{ input: 'kappa', tag: 'mi', output: '\u03BA', tex: null, ttype: CONST },
{ input: 'lambda', tag: 'mi', output: '\u03BB', tex: null, ttype: CONST },
{ input: 'Lambda', tag: 'mo', output: '\u039B', tex: null, ttype: CONST },
{ input: 'lamda', tag: 'mi', output: 'lambda', tex: null, ttype: DEFINITION },
{ input: 'Lamda', tag: 'mi', output: 'Lambda', tex: null, ttype: DEFINITION },
{ input: 'mu', tag: 'mi', output: '\u03BC', tex: null, ttype: CONST },
{ input: 'nu', tag: 'mi', output: '\u03BD', tex: null, ttype: CONST },
{ input: 'omega', tag: 'mi', output: '\u03C9', tex: null, ttype: CONST },
{ input: 'Omega', tag: 'mo', output: '\u03A9', tex: null, ttype: CONST },
{ input: 'phi', tag: 'mi', output: '\u03C6', tex: null, ttype: CONST },
{ input: 'varphi', tag: 'mi', output: '\u03D5', tex: null, ttype: CONST },
{ input: 'Phi', tag: 'mo', output: '\u03A6', tex: null, ttype: CONST },
{ input: 'pi', tag: 'mi', output: '\u03C0', tex: null, ttype: CONST },
{ input: 'Pi', tag: 'mo', output: '\u03A0', tex: null, ttype: CONST },
{ input: 'psi', tag: 'mi', output: '\u03C8', tex: null, ttype: CONST },
{ input: 'Psi', tag: 'mi', output: '\u03A8', tex: null, ttype: CONST },
{ input: 'rho', tag: 'mi', output: '\u03C1', tex: null, ttype: CONST },
{ input: 'sigma', tag: 'mi', output: '\u03C3', tex: null, ttype: CONST },
{ input: 'Sigma', tag: 'mo', output: '\u03A3', tex: null, ttype: CONST },
{ input: 'tau', tag: 'mi', output: '\u03C4', tex: null, ttype: CONST },
{ input: 'theta', tag: 'mi', output: '\u03B8', tex: null, ttype: CONST },
{ input: 'vartheta', tag: 'mi', output: '\u03D1', tex: null, ttype: CONST },
{ input: 'Theta', tag: 'mo', output: '\u0398', tex: null, ttype: CONST },
{ input: 'upsilon', tag: 'mi', output: '\u03C5', tex: null, ttype: CONST },
{ input: 'xi', tag: 'mi', output: '\u03BE', tex: null, ttype: CONST },
{ input: 'Xi', tag: 'mo', output: '\u039E', tex: null, ttype: CONST },
{ input: 'zeta', tag: 'mi', output: '\u03B6', tex: null, ttype: CONST },
//binary operation symbols
{ input: '*', tag: 'mo', output: '\u22C5', tex: 'cdot', ttype: CONST },
{ input: '**', tag: 'mo', output: '\u2217', tex: 'ast', ttype: CONST },
{ input: '***', tag: 'mo', output: '\u22C6', tex: 'star', ttype: CONST },
{
input: '//',
tag: 'mo',
output: '/',
tex: '/',
ttype: CONST,
val: true,
notexcopy: true,
},
{ input: '\\\\', tag: 'mo', output: '\\', tex: 'backslash', ttype: CONST },
{ input: 'setminus', tag: 'mo', output: '\\', tex: null, ttype: CONST },
{ input: 'xx', tag: 'mo', output: '\u00D7', tex: 'times', ttype: CONST },
{ input: '|><', tag: 'mo', output: '\u22C9', tex: 'ltimes', ttype: CONST },
{ input: '><|', tag: 'mo', output: '\u22CA', tex: 'rtimes', ttype: CONST },
{ input: '|><|', tag: 'mo', output: '\u22C8', tex: 'bowtie', ttype: CONST },
{ input: '-:', tag: 'mo', output: '\u00F7', tex: 'div', ttype: CONST },
{ input: 'divide', tag: 'mo', output: '-:', tex: null, ttype: DEFINITION },
{ input: '@', tag: 'mo', output: '\u2218', tex: 'circ', ttype: CONST },
{ input: 'o+', tag: 'mo', output: '\u2295', tex: 'oplus', ttype: CONST },
{ input: 'ox', tag: 'mo', output: '\u2297', tex: 'otimes', ttype: CONST },
{ input: 'o.', tag: 'mo', output: '\u2299', tex: 'odot', ttype: CONST },
{ input: 'sum', tag: 'mo', output: '\u2211', tex: null, ttype: UNDEROVER },
{ input: 'prod', tag: 'mo', output: '\u220F', tex: null, ttype: UNDEROVER },
{ input: '^^', tag: 'mo', output: '\u2227', tex: 'wedge', ttype: CONST },
{
input: '^^^',
tag: 'mo',
output: '\u22C0',
tex: 'bigwedge',
ttype: UNDEROVER,
},
{ input: 'vv', tag: 'mo', output: '\u2228', tex: 'vee', ttype: CONST },
{ input: 'vvv', tag: 'mo', output: '\u22C1', tex: 'bigvee', ttype: UNDEROVER },
{ input: 'nn', tag: 'mo', output: '\u2229', tex: 'cap', ttype: CONST },
{ input: 'nnn', tag: 'mo', output: '\u22C2', tex: 'bigcap', ttype: UNDEROVER },
{ input: 'uu', tag: 'mo', output: '\u222A', tex: 'cup', ttype: CONST },
{ input: 'uuu', tag: 'mo', output: '\u22C3', tex: 'bigcup', ttype: UNDEROVER },
{
input: 'overset',
tag: 'mover',
output: 'stackrel',
tex: null,
ttype: BINARY,
},
{
input: 'underset',
tag: 'munder',
output: 'stackrel',
tex: null,
ttype: BINARY,
},
//binary relation symbols
{ input: '!=', tag: 'mo', output: '\u2260', tex: 'ne', ttype: CONST },
{ input: ':=', tag: 'mo', output: ':=', tex: null, ttype: CONST },
{ input: 'lt', tag: 'mo', output: '<', tex: null, ttype: CONST },
{ input: 'gt', tag: 'mo', output: '>', tex: null, ttype: CONST },
{ input: '<=', tag: 'mo', output: '\u2264', tex: 'le', ttype: CONST },
{ input: 'lt=', tag: 'mo', output: '\u2264', tex: 'leq', ttype: CONST },
{ input: 'gt=', tag: 'mo', output: '\u2265', tex: 'geq', ttype: CONST },
{ input: '>=', tag: 'mo', output: '\u2265', tex: 'ge', ttype: CONST },
{ input: '-<', tag: 'mo', output: '\u227A', tex: 'prec', ttype: CONST },
{ input: '-lt', tag: 'mo', output: '\u227A', tex: null, ttype: CONST },
{ input: '>-', tag: 'mo', output: '\u227B', tex: 'succ', ttype: CONST },
{ input: '-<=', tag: 'mo', output: '\u2AAF', tex: 'preceq', ttype: CONST },
{ input: '>-=', tag: 'mo', output: '\u2AB0', tex: 'succeq', ttype: CONST },
{ input: 'in', tag: 'mo', output: '\u2208', tex: null, ttype: CONST },
{ input: '!in', tag: 'mo', output: '\u2209', tex: 'notin', ttype: CONST },
{ input: 'sub', tag: 'mo', output: '\u2282', tex: 'subset', ttype: CONST },
{ input: 'sup', tag: 'mo', output: '\u2283', tex: 'supset', ttype: CONST },
{ input: 'sube', tag: 'mo', output: '\u2286', tex: 'subseteq', ttype: CONST },
{ input: 'supe', tag: 'mo', output: '\u2287', tex: 'supseteq', ttype: CONST },
{ input: '-=', tag: 'mo', output: '\u2261', tex: 'equiv', ttype: CONST },
{
input: '~=',
tag: 'mo',
output: '\u2245',
tex: 'stackrel{\\sim}{=}',
ttype: CONST,
},
{ input: 'cong', tag: 'mo', output: '~=', tex: null, ttype: DEFINITION },
{ input: '~~', tag: 'mo', output: '\u2248', tex: 'approx', ttype: CONST },
{ input: 'prop', tag: 'mo', output: '\u221D', tex: 'propto', ttype: CONST },
//logical symbols
{ input: 'and', tag: 'mtext', output: 'and', tex: null, ttype: SPACE },
{ input: 'or', tag: 'mtext', output: 'or', tex: null, ttype: SPACE },
{ input: 'not', tag: 'mo', output: '\u00AC', tex: 'neg', ttype: CONST },
{ input: '=>', tag: 'mo', output: '\u21D2', tex: 'Rightarrow', ttype: CONST },
{ input: 'implies', tag: 'mo', output: '=>', tex: null, ttype: DEFINITION },
{ input: 'if', tag: 'mo', output: 'if', tex: null, ttype: SPACE },
{
input: '<=>',
tag: 'mo',
output: '\u21D4',
tex: 'Leftrightarrow',
ttype: CONST,
},
{ input: 'iff', tag: 'mo', output: '<=>', tex: null, ttype: DEFINITION },
{ input: 'AA', tag: 'mo', output: '\u2200', tex: 'forall', ttype: CONST },
{ input: 'EE', tag: 'mo', output: '\u2203', tex: 'exists', ttype: CONST },
{ input: '_|_', tag: 'mo', output: '\u22A5', tex: 'bot', ttype: CONST },
{ input: 'TT', tag: 'mo', output: '\u22A4', tex: 'top', ttype: CONST },
{ input: '|--', tag: 'mo', output: '\u22A2', tex: 'vdash', ttype: CONST },
{ input: '|==', tag: 'mo', output: '\u22A8', tex: 'models', ttype: CONST },
//grouping brackets
{
input: '(',
tag: 'mo',
output: '(',
tex: null,
ttype: LEFTBRACKET,
val: true,
},
{
input: ')',
tag: 'mo',
output: ')',
tex: null,
ttype: RIGHTBRACKET,
val: true,
},
{
input: '[',
tag: 'mo',
output: '[',
tex: null,
ttype: LEFTBRACKET,
val: true,
},
{
input: ']',
tag: 'mo',
output: ']',
tex: null,
ttype: RIGHTBRACKET,
val: true,
},
{ input: '{', tag: 'mo', output: '{', tex: 'lbrace', ttype: LEFTBRACKET },
{ input: '}', tag: 'mo', output: '}', tex: 'rbrace', ttype: RIGHTBRACKET },
{ input: '|', tag: 'mo', output: '|', tex: null, ttype: LEFTRIGHT, val: true },
//{input:"||", tag:"mo", output:"||", tex:null, ttype:LEFTRIGHT},
{ input: '(:', tag: 'mo', output: '\u2329', tex: 'langle', ttype: LEFTBRACKET },
{
input: ':)',
tag: 'mo',
output: '\u232A',
tex: 'rangle',
ttype: RIGHTBRACKET,
},
{ input: '<<', tag: 'mo', output: '\u2329', tex: 'langle', ttype: LEFTBRACKET },
{
input: '>>',
tag: 'mo',
output: '\u232A',
tex: 'rangle',
ttype: RIGHTBRACKET,
},
{
input: '{:',
tag: 'mo',
output: '{:',
tex: null,
ttype: LEFTBRACKET,
invisible: true,
},
{
input: ':}',
tag: 'mo',
output: ':}',
tex: null,
ttype: RIGHTBRACKET,
invisible: true,
},
//miscellaneous symbols
{ input: 'int', tag: 'mo', output: '\u222B', tex: null, ttype: CONST },
{ input: 'dx', tag: 'mi', output: '{:d x:}', tex: null, ttype: DEFINITION },
{ input: 'dy', tag: 'mi', output: '{:d y:}', tex: null, ttype: DEFINITION },
{ input: 'dz', tag: 'mi', output: '{:d z:}', tex: null, ttype: DEFINITION },
{ input: 'dt', tag: 'mi', output: '{:d t:}', tex: null, ttype: DEFINITION },
{ input: 'oint', tag: 'mo', output: '\u222E', tex: null, ttype: CONST },
{ input: 'del', tag: 'mo', output: '\u2202', tex: 'partial', ttype: CONST },
{ input: 'grad', tag: 'mo', output: '\u2207', tex: 'nabla', ttype: CONST },
{ input: '+-', tag: 'mo', output: '\u00B1', tex: 'pm', ttype: CONST },
{ input: 'O/', tag: 'mo', output: '\u2205', tex: 'emptyset', ttype: CONST },
{ input: 'oo', tag: 'mo', output: '\u221E', tex: 'infty', ttype: CONST },
{ input: 'aleph', tag: 'mo', output: '\u2135', tex: null, ttype: CONST },
{ input: '...', tag: 'mo', output: '...', tex: 'ldots', ttype: CONST },
{ input: ':.', tag: 'mo', output: '\u2234', tex: 'therefore', ttype: CONST },
{ input: ":'", tag: 'mo', output: '\u2235', tex: 'because', ttype: CONST },
{ input: '/_', tag: 'mo', output: '\u2220', tex: 'angle', ttype: CONST },
{ input: '/_\\', tag: 'mo', output: '\u25B3', tex: 'triangle', ttype: CONST },
{
input: '\\ ',
tag: 'mo',
output: '\u00A0',
tex: null,
ttype: CONST,
val: true,
},
{ input: 'frown', tag: 'mo', output: '\u2322', tex: null, ttype: CONST },
{ input: '%', tag: 'mo', output: '%', tex: '%', ttype: CONST, notexcopy: true },
{ input: 'quad', tag: 'mo', output: '\u00A0\u00A0', tex: null, ttype: CONST },
{
input: 'qquad',
tag: 'mo',
output: '\u00A0\u00A0\u00A0\u00A0',
tex: null,
ttype: CONST,
},
{ input: 'cdots', tag: 'mo', output: '\u22EF', tex: null, ttype: CONST },
{ input: 'vdots', tag: 'mo', output: '\u22EE', tex: null, ttype: CONST },
{ input: 'ddots', tag: 'mo', output: '\u22F1', tex: null, ttype: CONST },
{ input: 'diamond', tag: 'mo', output: '\u22C4', tex: null, ttype: CONST },
{ input: 'square', tag: 'mo', output: '\u25A1', tex: 'boxempty', ttype: CONST },
{ input: '|__', tag: 'mo', output: '\u230A', tex: 'lfloor', ttype: CONST },
{ input: '__|', tag: 'mo', output: '\u230B', tex: 'rfloor', ttype: CONST },
{ input: '|~', tag: 'mo', output: '\u2308', tex: 'lceil', ttype: CONST },
{ input: 'lceiling', tag: 'mo', output: '|~', tex: null, ttype: DEFINITION },
{ input: '~|', tag: 'mo', output: '\u2309', tex: 'rceil', ttype: CONST },
{ input: 'rceiling', tag: 'mo', output: '~|', tex: null, ttype: DEFINITION },
{
input: 'CC',
tag: 'mo',
output: '\u2102',
tex: 'mathbb{C}',
ttype: CONST,
notexcopy: true,
},
{
input: 'NN',
tag: 'mo',
output: '\u2115',
tex: 'mathbb{N}',
ttype: CONST,
notexcopy: true,
},
{
input: 'QQ',
tag: 'mo',
output: '\u211A',
tex: 'mathbb{Q}',
ttype: CONST,
notexcopy: true,
},
{
input: 'RR',
tag: 'mo',
output: '\u211D',
tex: 'mathbb{R}',
ttype: CONST,
notexcopy: true,
},
{
input: 'ZZ',
tag: 'mo',
output: '\u2124',
tex: 'mathbb{Z}',
ttype: CONST,
notexcopy: true,
},
{
input: 'f',
tag: 'mi',
output: 'f',
tex: null,
ttype: UNARY,
func: true,
val: true,
},
{
input: 'g',
tag: 'mi',
output: 'g',
tex: null,
ttype: UNARY,
func: true,
val: true,
},
{ input: "''", tag: 'mo', output: "''", tex: null, val: true },
{ input: "'''", tag: 'mo', output: "'''", tex: null, val: true },
{ input: "''''", tag: 'mo', output: "''''", tex: null, val: true },
//standard functions
{ input: 'lim', tag: 'mo', output: 'lim', tex: null, ttype: UNDEROVER },
{ input: 'Lim', tag: 'mo', output: 'Lim', tex: null, ttype: UNDEROVER },
{ input: 'sin', tag: 'mo', output: 'sin', tex: null, ttype: UNARY, func: true },
{ input: 'cos', tag: 'mo', output: 'cos', tex: null, ttype: UNARY, func: true },
{ input: 'tan', tag: 'mo', output: 'tan', tex: null, ttype: UNARY, func: true },
{
input: 'arcsin',
tag: 'mo',
output: 'arcsin',
tex: null,
ttype: UNARY,
func: true,
},
{
input: 'arccos',
tag: 'mo',
output: 'arccos',
tex: null,
ttype: UNARY,
func: true,
},
{
input: 'arctan',
tag: 'mo',
output: 'arctan',
tex: null,
ttype: UNARY,
func: true,
},
{
input: 'sinh',
tag: 'mo',
output: 'sinh',
tex: null,
ttype: UNARY,
func: true,
},
{
input: 'cosh',
tag: 'mo',
output: 'cosh',
tex: null,
ttype: UNARY,
func: true,
},
{
input: 'tanh',
tag: 'mo',
output: 'tanh',
tex: null,
ttype: UNARY,
func: true,
},
{ input: 'cot', tag: 'mo', output: 'cot', tex: null, ttype: UNARY, func: true },
{
input: 'coth',
tag: 'mo',
output: 'coth',
tex: null,
ttype: UNARY,
func: true,
},
{
input: 'sech',
tag: 'mo',
output: 'sech',
tex: null,
ttype: UNARY,
func: true,
},
{
input: 'csch',
tag: 'mo',
output: 'csch',
tex: null,
ttype: UNARY,
func: true,
},
{ input: 'sec', tag: 'mo', output: 'sec', tex: null, ttype: UNARY, func: true },
{ input: 'csc', tag: 'mo', output: 'csc', tex: null, ttype: UNARY, func: true },
{ input: 'log', tag: 'mo', output: 'log', tex: null, ttype: UNARY, func: true },
{ input: 'ln', tag: 'mo', output: 'ln', tex: null, ttype: UNARY, func: true },
{
input: 'abs',
tag: 'mo',
output: 'abs',
tex: null,
ttype: UNARY,
notexcopy: true,
rewriteleftright: ['|', '|'],
},
{
input: 'norm',
tag: 'mo',
output: 'norm',
tex: null,
ttype: UNARY,
notexcopy: true,
rewriteleftright: ['\\|', '\\|'],
},
{
input: 'floor',
tag: 'mo',
output: 'floor',
tex: null,
ttype: UNARY,
notexcopy: true,
rewriteleftright: ['\\lfloor', '\\rfloor'],
},
{
input: 'ceil',
tag: 'mo',
output: 'ceil',
tex: null,
ttype: UNARY,
notexcopy: true,
rewriteleftright: ['\\lceil', '\\rceil'],
},
{ input: 'Sin', tag: 'mo', output: 'sin', tex: null, ttype: UNARY, func: true },
{ input: 'Cos', tag: 'mo', output: 'cos', tex: null, ttype: UNARY, func: true },
{ input: 'Tan', tag: 'mo', output: 'tan', tex: null, ttype: UNARY, func: true },
{
input: 'Arcsin',
tag: 'mo',
output: 'arcsin',
tex: null,
ttype: UNARY,
func: true,
},
{
input: 'Arccos',
tag: 'mo',
output: 'arccos',
tex: null,
ttype: UNARY,
func: true,
},
{
input: 'Arctan',
tag: 'mo',
output: 'arctan',
tex: null,
ttype: UNARY,
func: true,
},
{
input: 'Sinh',
tag: 'mo',
output: 'sinh',
tex: null,
ttype: UNARY,
func: true,
},
{
input: 'Sosh',
tag: 'mo',
output: 'cosh',
tex: null,
ttype: UNARY,
func: true,
},
{
input: 'Tanh',
tag: 'mo',
output: 'tanh',
tex: null,
ttype: UNARY,
func: true,
},
{ input: 'Cot', tag: 'mo', output: 'cot', tex: null, ttype: UNARY, func: true },
{ input: 'Sec', tag: 'mo', output: 'sec', tex: null, ttype: UNARY, func: true },
{ input: 'Csc', tag: 'mo', output: 'csc', tex: null, ttype: UNARY, func: true },
{ input: 'Log', tag: 'mo', output: 'log', tex: null, ttype: UNARY, func: true },
{ input: 'Ln', tag: 'mo', output: 'ln', tex: null, ttype: UNARY, func: true },
{
input: 'Abs',
tag: 'mo',
output: 'abs',
tex: null,
ttype: UNARY,
notexcopy: true,
rewriteleftright: ['|', '|'],
},
{ input: 'det', tag: 'mo', output: 'det', tex: null, ttype: UNARY, func: true },
{ input: 'exp', tag: 'mo', output: 'exp', tex: null, ttype: UNARY, func: true },
{ input: 'dim', tag: 'mo', output: 'dim', tex: null, ttype: CONST },
{
input: 'mod',
tag: 'mo',
output: 'mod',
tex: 'text{mod}',
ttype: CONST,
notexcopy: true,
},
{ input: 'gcd', tag: 'mo', output: 'gcd', tex: null, ttype: UNARY, func: true },
{
input: 'lcm',
tag: 'mo',
output: 'lcm',
tex: 'text{lcm}',
ttype: UNARY,
func: true,
notexcopy: true,
},
{ input: 'lub', tag: 'mo', output: 'lub', tex: null, ttype: CONST },
{ input: 'glb', tag: 'mo', output: 'glb', tex: null, ttype: CONST },
{ input: 'min', tag: 'mo', output: 'min', tex: null, ttype: UNDEROVER },
{ input: 'max', tag: 'mo', output: 'max', tex: null, ttype: UNDEROVER },
//arrows
{ input: 'uarr', tag: 'mo', output: '\u2191', tex: 'uparrow', ttype: CONST },
{ input: 'darr', tag: 'mo', output: '\u2193', tex: 'downarrow', ttype: CONST },
{ input: 'rarr', tag: 'mo', output: '\u2192', tex: 'rightarrow', ttype: CONST },
{ input: '->', tag: 'mo', output: '\u2192', tex: 'to', ttype: CONST },
{
input: '>->',
tag: 'mo',
output: '\u21A3',
tex: 'rightarrowtail',
ttype: CONST,
},
{
input: '->>',
tag: 'mo',
output: '\u21A0',
tex: 'twoheadrightarrow',
ttype: CONST,
},
{
input: '>->>',
tag: 'mo',
output: '\u2916',
tex: 'twoheadrightarrowtail',
ttype: CONST,
},
{ input: '|->', tag: 'mo', output: '\u21A6', tex: 'mapsto', ttype: CONST },
{ input: 'larr', tag: 'mo', output: '\u2190', tex: 'leftarrow', ttype: CONST },
{
input: 'harr',
tag: 'mo',
output: '\u2194',
tex: 'leftrightarrow',
ttype: CONST,
},
{ input: 'rArr', tag: 'mo', output: '\u21D2', tex: 'Rightarrow', ttype: CONST },
{ input: 'lArr', tag: 'mo', output: '\u21D0', tex: 'Leftarrow', ttype: CONST },
{
input: 'hArr',
tag: 'mo',
output: '\u21D4',
tex: 'Leftrightarrow',
ttype: CONST,
},
//commands with argument
AMsqrt,
AMroot,
AMfrac,
AMdiv,
AMover,
AMsub,
AMsup,
{ input: 'cancel', tag: 'menclose', output: 'cancel', tex: null, ttype: UNARY },
{ input: 'Sqrt', tag: 'msqrt', output: 'sqrt', tex: null, ttype: UNARY },
{
input: 'hat',
tag: 'mover',
output: '\u005E',
tex: null,
ttype: UNARY,
acc: true,
},
{
input: 'bar',
tag: 'mover',
output: '\u00AF',
tex: 'overline',
ttype: UNARY,
acc: true,
},
{
input: 'vec',
tag: 'mover',
output: '\u2192',
tex: null,
ttype: UNARY,
acc: true,
},
{
input: 'tilde',
tag: 'mover',
output: '~',
tex: null,
ttype: UNARY,
acc: true,
},
{ input: 'dot', tag: 'mover', output: '.', tex: null, ttype: UNARY, acc: true },
{
input: 'ddot',
tag: 'mover',
output: '..',
tex: null,
ttype: UNARY,
acc: true,
},
{
input: 'ul',
tag: 'munder',
output: '\u0332',
tex: 'underline',
ttype: UNARY,
acc: true,
},
{
input: 'ubrace',
tag: 'munder',
output: '\u23DF',
tex: 'underbrace',
ttype: UNARY,
acc: true,
},
{
input: 'obrace',
tag: 'mover',
output: '\u23DE',
tex: 'overbrace',
ttype: UNARY,
acc: true,
},
AMtext,
AMmbox,
AMquote,
//{input:"var", tag:"mstyle", atname:"fontstyle", atval:"italic", output:"var", tex:null, ttype:UNARY},
{ input: 'color', tag: 'mstyle', ttype: BINARY, tex: null },
{
input: 'bb',
tag: 'mstyle',
atname: 'mathvariant',
atval: 'bold',
output: 'bb',
tex: 'mathbf',
ttype: UNARY,
notexcopy: true,
},
{
input: 'mathbf',
tag: 'mstyle',
atname: 'mathvariant',
atval: 'bold',
output: 'mathbf',
tex: null,
ttype: UNARY,
},
{
input: 'sf',
tag: 'mstyle',
atname: 'mathvariant',
atval: 'sans-serif',
output: 'sf',
tex: 'mathsf',
ttype: UNARY,
notexcopy: true,
},
{
input: 'mathsf',
tag: 'mstyle',
atname: 'mathvariant',
atval: 'sans-serif',
output: 'mathsf',
tex: null,
ttype: UNARY,
},
{
input: 'bbb',
tag: 'mstyle',
atname: 'mathvariant',
atval: 'double-struck',
output: 'bbb',
tex: 'mathbb',
ttype: UNARY,
notexcopy: true,
},
{
input: 'mathbb',
tag: 'mstyle',
atname: 'mathvariant',
atval: 'double-struck',
output: 'mathbb',
tex: null,
ttype: UNARY,
},
{
input: 'cc',
tag: 'mstyle',
atname: 'mathvariant',
atval: 'script',
output: 'cc',
tex: 'mathcal',
ttype: UNARY,
notexcopy: true,
},
{
input: 'mathcal',
tag: 'mstyle',
atname: 'mathvariant',
atval: 'script',
output: 'mathcal',
tex: null,
ttype: UNARY,
},
{
input: 'tt',
tag: 'mstyle',
atname: 'mathvariant',
atval: 'monospace',
output: 'tt',
tex: 'mathtt',
ttype: UNARY,
notexcopy: true,
},
{
input: 'mathtt',
tag: 'mstyle',
atname: 'mathvariant',
atval: 'monospace',
output: 'mathtt',
tex: null,
ttype: UNARY,
},
{
input: 'fr',
tag: 'mstyle',
atname: 'mathvariant',
atval: 'fraktur',
output: 'fr',
tex: 'mathfrak',
ttype: UNARY,
notexcopy: true,
},
{
input: 'mathfrak',
tag: 'mstyle',
atname: 'mathvariant',
atval: 'fraktur',
output: 'mathfrak',
tex: null,
ttype: UNARY,
},
];
const AMnames = []; //list of input symbols
function AMinitSymbols() {
let i;
const symlen = AMsymbols.length;
for (i = 0; i < symlen; i++) {
if (AMsymbols[i].tex &&
!(typeof AMsymbols[i].notexcopy === 'boolean' && AMsymbols[i].notexcopy)) {
AMsymbols.push({
input: AMsymbols[i].tex,
tag: AMsymbols[i].tag,
output: AMsymbols[i].output,
ttype: AMsymbols[i].ttype,
acc: AMsymbols[i].acc || false,
tex: null,
});
}
}
refreshSymbols();
}
function refreshSymbols() {
let i;
AMsymbols.sort((s1, s2) => {
var _a, _b;
if (((_a = s1.input) !== null && _a !== void 0 ? _a : '') > ((_b = s2.input) !== null && _b !== void 0 ? _b : ''))
return 1;
else
return -1;
});
for (i = 0; i < AMsymbols.length; i++) {
AMnames[i] = AMsymbols[i].input;
}
}
function AMremoveCharsAndBlanks(str, n) {
//remove n characters and any following blanks
let st;
if (str.charAt(n) === '\\' &&
str.charAt(n + 1) !== '\\' &&
str.charAt(n + 1) !== ' ')
st = str.slice(n + 1);
else
st = str.slice(n);
let i = 0;
for (i = 0; i < st.length && st.charCodeAt(i) <= 32; i = i + 1)
;
return st.slice(i);
}
function AMposition(arr, str, n) {
// return position >=n where str appears or would be inserted
// assumes arr is sorted
if (n === 0) {
let h, m;
n = -1;
h = arr.length;
while (n + 1 < h) {
m = (n + h) >> 1;
if (arr[m] < str)
n = m;
else
h = m;
}
return h;
}
else {
let i = n;
for (i = n; i < arr.length && arr[i] < str; i++)
;
return i; // i=arr.length || arr[i]>=str
}
}
function AMgetSymbol(str) {
//return maximal initial substring of str that appears in names
//return null if there is none
let k = 0; //new pos
let j = 0; //old pos
let mk = 0; //match pos
let st;
let tagst;
let match = '';
let more = true;
for (let i = 1; i <= str.length && more; i++) {
st = str.slice(0, i); //initial substring of length i
j = k;
k = AMposition(AMnames, st, j);
if (k < AMnames.length && str.slice(0, AMnames[k].length) === AMnames[k]) {
match = AMnames[k];
mk = k;
i = match.length;
}
more = k < AMnames.length && str.slice(0, AMnames[k].length) >= AMnames[k];
}
AMpreviousSymbol = AMcurrentSymbol;
if (match !== '') {
AMcurrentSymbol = AMsymbols[mk].ttype;
return AMsymbols[mk];
}
// if str[0] is a digit or - return maxsubstring of digits.digits
AMcurrentSymbol = CONST;
k = 1;
st = str.slice(0, 1);
let integ = true;
while ('0' <= st && st <= '9' && k <= str.length) {
st = str.slice(k, k + 1);
k++;
}
if (st === config.decimalsign) {
st = str.slice(k, k + 1);
if ('0' <= st && st <= '9') {
integ = false;
k++;
while ('0' <= st && st <= '9' && k <= str.length) {
st = str.slice(k, k + 1);
k++;
}
}
}
if ((integ && k > 1) || k > 2) {
st = str.slice(0, k - 1);
tagst = 'mn';
}
else {
k = 2;
st = str.slice(0, 1); //take 1 character
tagst = ('A' > st || st > 'Z') && ('a' > st || st > 'z') ? 'mo' : 'mi';
}
if (st === '-' && AMpreviousSymbol === INFIX) {
AMcurrentSymbol = INFIX;
return {
input: st,
tag: tagst,
output: st,
ttype: UNARY,
func: true,
val: true,
tex: null,
};
}
return {
input: st,
tag: tagst,
output: st,
ttype: CONST,
val: true,
tex: null,
}; //added val bit
}
function AMTremoveBrackets(node) {
let st;
if (node.charAt(0) === '{' && node.charAt(node.length - 1) === '}') {
let leftchop = 0;
st = node.substr(1, 5);
if (st === '\\left') {
st = node.charAt(6);
if (st === '(' || st === '[' || st === '{') {
leftchop = 7;
}
else {
st = node.substr(6, 7);
if (st === '\\lbrace') {
leftchop = 13;
}
}
}
else {
st = node.charAt(1);
if (st === '(' || st === '[') {
leftchop = 2;
}
}
if (leftchop > 0) {
//st = node.charAt(node.length-7);
st = node.substr(node.length - 8);
if (st === '\\right)}' || st === '\\right]}' || st === '\\right.}') {
node = '{' + node.substr(leftchop);
node = node.substr(0, node.length - 8) + '}';
}
else if (st === '\\rbrace}') {
node = '{' + node.substr(leftchop);
node = node.substr(0, node.length - 14) + '}';
}
}
}
return node;
}
/*Parsing ASCII math expressions with the following grammar
v ::= [A-Za-z] | greek letters | numbers | other constant symbols
u ::= sqrt | text | bb | other unary symbols for font commands
b ::= frac | root | stackrel binary symbols
l ::= ( | [ | { | (: | {: left brackets
r ::= ) | ] | } | :) | :} right brackets
S ::= v | lEr | uS | bSS Simple expression
I ::= S_S | S^S | S_S^S | S Intermediate expression
E ::= IE | I/I Expression
Each terminal symbol is translated into a corresponding mathml node.*/
let AMnestingDepth, AMpreviousSymbol, AMcurrentSymbol;
function AMTgetTeXsymbol(symb) {
let pre = '';
if (typeof symb.val === 'boolean' && symb.val) {
pre = '';
}
else {
pre = '\\';
}
if (symb.tex === null) {
//can't remember why this was here. Breaks /delta /Delta to removed
//return (pre+(pre==''?symb.input:symb.input.toLowerCase()));
return pre + symb.input;
}
else {
return pre + symb.tex;
}
}
function AMTparseSexpr(str) {
//parses str and returns [node,tailstr]
let symbol, node, result, i, st, // rightvert = false,
newFrag = '';
str = AMremoveCharsAndBlanks(str, 0);
symbol = AMgetSymbol(str); //either a token or a bracket or empty
if (symbol === null ||
(symbol.ttype === RIGHTBRACKET && AMnestingDepth > 0)) {
return [null, str];
}
if (symbol.ttype === DEFINITION) {
str = symbol.output + AMremoveCharsAndBlanks(str, symbol.input.length);
symbol = AMgetSymbol(str);
}
switch (symbol.ttype) {
case UNDEROVER:
case CONST: {
str = AMremoveCharsAndBlanks(str, symbol.input.length);
const texsymbol = AMTgetTeXsymbol(symbol);
if (texsymbol.charAt(0) === '\\' || symbol.tag === 'mo')
return [texsymbol, str];
else
return ['{' + texsymbol + '}', str];
}
case LEFTBRACKET: {
//read (expr+)
AMnestingDepth++;
str = AMremoveCharsAndBlanks(str, symbol.input.length);
result = AMTparseExpr(str, true);
AMnestingDepth--;
let leftchop = 0;
if (result[0].substr(0, 6) === '\\right') {
st = result[0].charAt(6);
if (st === ')' || st === ']' || st === '}') {
leftchop = 6;
}
else if (st === '.') {
leftchop = 7;
}
else {
st = result[0].substr(6, 7);
if (st === '\\rbrace') {
leftchop = 13;
}
}
}
if (leftchop > 0) {
result[0] = result[0].substr(leftchop);
if (typeof symbol.invisible === 'boolean' && symbol.invisible)
node = '{' + result[0] + '}';
else {
node = '{' + AMTgetTeXsymbol(symbol) + result[0] + '}';
}
}
else {
if (typeof symbol.invisible === 'boolean' && symbol.invisible)
node = '{\\left.' + result[0] + '}';
else {
node = '{\\left' + AMTgetTeXsymbol(symbol) + result[0] + '}';
}
}
return [node, result[1]];
}
case TEXT:
if (symbol !== AMquote)
str = AMremoveCharsAndBlanks(str, symbol.input.length);
if (str.charAt(0) === '{')
i = str.indexOf('}');
else if (str.charAt(0) === '(')
i = str.indexOf(')');
else if (str.charAt(0) === '[')
i = str.indexOf(']');
else if (symbol === AMquote)
i = str.slice(1).indexOf('"') + 1;
else
i = 0;
if (i === -1)
i = str.length;
st = str.slice(1, i);
if (st.charAt(0) === ' ') {
newFrag = '\\ ';
}
newFrag += '\\text{' + st + '}';
if (st.charAt(st.length - 1) === ' ') {
newFrag += '\\ ';
}
str = AMremoveCharsAndBlanks(str, i + 1);
return [newFrag, str];
case UNARY:
str = AMremoveCharsAndBlanks(str, symbol.input.length);
result = AMTparseSexpr(str);
if (result[0] === null)
return ['{' + AMTgetTeXsymbol(symbol) + '}', str];
if (typeof symbol.func === 'boolean' && symbol.func) {
// functions hack
st = str.charAt(0);
if (st === '^' ||
st === '_' ||
st === '/' ||
st === '|' ||
st === ',' ||
(symbol.input.length === 1 && symbol.input.match(/\w/) && st !== '(')) {
return ['{' + AMTgetTeXsymbol(symbol) + '}', str];
}
else {
node = '{' + AMTgetTeXsymbol(symbol) + '{' + result[0] + '}}';
return [node, result[1]];
}
}
result[0] = AMTremoveBrackets(result[0]);
if (symbol.input === 'sqrt') {
// sqrt
return ['\\sqrt{' + result[0] + '}', result[1]];
}
else if (symbol.input === 'cancel') {
// cancel
return ['\\cancel{' + result[0] + '}', result[1]];
}
else if (typeof symbol.rewriteleftright !== 'undefined') {
// abs, floor, ceil
return [
'{\\left' +
symbol.rewriteleftright[0] +
result[0] +
'\\right' +
symbol.rewriteleftright[1] +
'}',
result[1],
];
}
else if (typeof symbol.acc === 'boolean' && symbol.acc) {
// accent
//return ['{'+AMTgetTeXsymbol(symbol)+'{'+result[0]+'}}',result[1]];
return [AMTgetTeXsymbol(symbol) + '{' + result[0] + '}', result[1]];
}
else {
// font change command
return [
'{' + AMTgetTeXsymbol(symbol) + '{' + result[0] + '}}',
result[1],
];
}
case BINARY: {
str = AMremoveCharsAndBlanks(str, symbol.input.length);
result = AMTparseSexpr(str);
if (result[0] === null)
return ['{' + AMTgetTeXsymbol(symbol) + '}', str];
result[0] = AMTremoveBrackets(result[0]);
const result2 = AMTparseSexpr(result[1]);
if (result2[0] === null)
return ['{' + AMTgetTeXsymbol(symbol) + '}', str];
result2[0] = AMTremoveBrackets(result2[0]);
if (symbol.input === 'color') {
newFrag =
'{\\color{' + result[0].replace(/[{}]/g, '') + '}' + result2[0] + '}';
}
else if (symbol.input === 'root') {
newFrag = '{\\sqrt[' + result[0] + ']{' + result2[0] + '}}';
}
else {
newFrag =
'{' +
AMTgetTeXsymbol(symbol) +
'{' +
result[0] +
'}{' +
result2[0] +
'}}';
}
return [newFrag, result2[1]];
}
case INFIX:
str = AMremoveCharsAndBlanks(str, symbol.input.length);
return [symbol.output, str];
case SPACE:
str = AMremoveCharsAndBlanks(str, symbol.input.length);
return ['{\\quad\\text{' + symbol.input + '}\\quad}', str];
case LEFTRIGHT:
// if (rightvert) return [null,str]; else rightvert = true;
AMnestingDepth++;
str = AMremoveCharsAndBlanks(str, symbol.input.length);
result = AMTparseExpr(str, false);
AMnestingDepth--;
st = '';
st = result[0].charAt(result[0].length - 1);
//alert(result[0].lastChild+"***"+st);
if (st === '|') {
// its an absolute value subterm
node = '{\\left|' + result[0] + '}';
return [node, result[1]];
}
else {
// the "|" is a \mid
node = '{\\mid}';
return [node, str];
}
default:
//alert("default");
str = AMremoveCharsAndBlanks(str, symbol.input.length);
return ['{' + AMTgetTeXsymbol(symbol) + '}', str];
}
}
function AMTparseIexpr(str) {
let sym2, node, result;
str = AMremoveCharsAndBlanks(str, 0);
const sym1 = AMgetSymbol(str);
result = AMTparseSexpr(str);
node = result[0];
str = result[1];
const symbol = AMgetSymbol(str);
if (symbol.ttype === INFIX && symbol.input !== '/') {
str = AMremoveCharsAndBlanks(str, symbol.input.length);
// if (symbol.input === "/") result = AMTparseIexpr(str); else
result = AMTparseSexpr(str);
if (result[0] === null)
// show box in place of missing argument
result[0] = '{}';
else
result[0] = AMTremoveBrackets(result[0]);
str = result[1];
// if (symbol.input === "/") AMTremoveBrackets(node);
if (symbol.input === '_') {
sym2 = AMgetSymbol(str);
if (sym2.input === '^') {
str = AMremoveCharsAndBlanks(str, sym2.input.length);
const res2 = AMTparseSexpr(str);
res2[0] = AMTremoveBrackets(res2[0]);
str = res2[1];
node = '{' + node;
node += '_{' + result[0] + '}';
node += '^{' + res2[0] + '}';
node += '}';
}
else {
node += '_{' + result[0] + '}';
}
}
else {
//must be ^
//node = '{'+node+'}^{'+result[0]+'}';
node = node + '^{' + result[0] + '}';
}
if (typeof sym1.func !== 'undefined' && sym1.func) {
sym2 = AMgetSymbol(str);
if (sym2.ttype !== INFIX && sym2.ttype !== RIGHTBRACKET) {
result = AMTparseIexpr(str);
node = '{' + node + result[0] + '}';
str = result[1];
}
}
}
return [node, str];
}
function AMTparseExpr(str, rightbracket) {
let symbol, node, result, i, newFrag = '';
let addedright = false;
do {
str = AMremoveCharsAndBlanks(str, 0);
result = AMTparseIexpr(str);
node = result[0];
str = result[1];
symbol = AMgetSymbol(str);
if (symbol.ttype === INFIX && symbol.input === '/') {
str = AMremoveCharsAndBlanks(str, symbol.input.length);
result = AMTparseIexpr(str);
if (result[0] === null)
// show box in place of missing argument
result[0] = '{}';
else
result[0] = AMTremoveBrackets(result[0]);
str = result[1];
node = AMTremoveBrackets(node);
node = '\\frac' + '{' + node + '}';
node += '{' + result[0] + '}';
newFrag += node;
symbol = AMgetSymbol(str);
}
else if (node !== undefined)
newFrag += node;
} while (((symbol.ttype !== RIGHTBRACKET &&
(symbol.ttype !== LEFTRIGHT || rightbracket)) ||
AMnestingDepth === 0) &&
symbol !== null &&
symbol.output !== '');
if (symbol.ttype === RIGHTBRACKET || symbol.ttype === LEFTRIGHT) {
// if (AMnestingDepth > 0) AMnestingDepth--;
const len = newFrag.length;
if (len > 2 && newFrag.charAt(0) === '{' && newFrag.indexOf(',') > 0) {
//could be matrix (total rewrite from .js)
const right = newFrag.charAt(len - 2);
if (right === ')' || right === ']') {
const left = newFrag.charAt(6);
if ((left === '(' && right === ')' && symbol.output !== '}') ||
(left === '[' && right === ']')) {
let mxout = '\\begin{matrix}';
const pos = []; //position of commas
pos.push(0);
let matrix = true;
let mxnestingd = 0;
const subpos = [];
subpos[0] = [0];
let lastsubposstart = 0;
let mxanynestingd = 0;
for (i = 1; i < len - 1; i++) {
if (newFrag.charAt(i) === left)
mxnestingd++;
if (newFrag.charAt(i) === right) {
mxnestingd--;
if (mxnestingd === 0 &&
newFrag.charAt(i + 2) === ',' &&
newFrag.charAt(i + 3) === '{') {
pos.push(i + 2);
lastsubposstart = i + 2;
subpos[lastsubposstart] = [i + 2];
}
}
if (newFrag.charAt(i) === '[' ||
newFrag.charAt(i) === '(' ||
newFrag.charAt(i) === '{') {
mxanynestingd++;
}
if (newFrag.charAt(i) === ']' ||
newFrag.charAt(i) === ')' ||
newFrag.charAt(i) === '}') {
mxanynestingd--;
}
if (newFrag.charAt(i) === ',' && mxanynestingd === 1) {
subpos[lastsubposstart].push(i);
}
if (mxanynestingd < 0) {
//happens at the end of the row
if (lastsubposstart === i + 1) {
//if at end of row, skip to next row
i++;
}
else {
//misformed something - abandon treating as a matrix
matrix = false;
}
}
}
pos.push(len);
let lastmxsubcnt = -1;
if (mxnestingd === 0 && pos.length > 0 && matrix) {
for (i = 0; i < pos.length - 1; i++) {
let subarr = [];
if (i > 0)
mxout += '\\\\';
if (i === 0) {
if (subpos[pos[i]].length === 1) {
subarr = [
newFrag.substr(pos[i] + 7, pos[i + 1] - pos[i] - 15),
];
}
else {
subarr = [newFrag.substring(pos[i] + 7, subpos[pos[i]][1])];
for (let j = 2; j < subpos[pos[i]].length; j++) {
subarr.push(newFrag.substring(subpos[pos[i]][j - 1] + 1, subpos[pos[i]][j]));
}
subarr.push(newFrag.substring(subpos[pos[i]][subpos[pos[i]].length - 1] + 1, pos[i + 1] - 8));
}
}
else {
if (subpos[pos[i]].length === 1) {
subarr = [
newFrag.substr(pos[i] + 8, pos[i + 1] - pos[i] - 16),
];
}
else {
subarr = [newFrag.substring(pos[i] + 8, subpos[pos[i]][1])];
for (let j = 2; j < subpos[pos[i]].length; j++) {
subarr.push(newFrag.substring(subpos[pos[i]][j - 1] + 1, subpos[pos[i]][j]));
}
subarr.push(newFrag.substring(subpos[pos[i]][subpos[pos[i]].length - 1] + 1, pos[i + 1] - 8));
}
}
if (lastmxsubcnt > 0 && subarr.length !== lastmxsubcnt) {
matrix = false;
}
else if (lastmxsubcnt === -1) {
lastmxsubcnt = subarr.length;
}
mxout += subarr.join('&');
}
}
mxout += '\\end{matrix}';
if (matrix) {
newFrag = mxout;
}
}
}
}
str = AMremoveCharsAndBlanks(str, symbol.input.length);
if (typeof symbol.invisible !== 'boolean' || !symbol.invisible) {
node = '\\right' + AMTgetTeXsymbol(symbol); //AMcreateMmlNode("mo",document.createTextNode(symbol.output));
newFrag += node;
addedright = true;