@limetech/lime-elements
Version:
1,655 lines (1,513 loc) • 172 kB
JavaScript
import { r as registerInstance, c as createEvent, h, a as getElement } from './index-DBTJNfo7.js';
import { t as translate } from './translations-DVRaJQvC.js';
import { d as defaultSchema, u as unified, r as rehypeParse, a as rehypeSanitize, v as visit, b as rehypeStringify } from './index-CJ0GYrWG.js';
import './_commonjsHelpers-BFTU3MAI.js';
/**
*
* @param fileName
* @param url
*/
function detectExtension(fileName, url) {
const pathLike = fileName || url;
if (!pathLike) {
return 'unknown';
}
const extension = pathLike.split('.').pop().toLowerCase();
const extensionsToTypes = {
pdf: 'pdf',
jpg: 'image',
jpeg: 'image',
heic: 'image',
bmp: 'image',
png: 'image',
gif: 'image',
svg: 'image',
svgz: 'image',
ep: 'image',
eps: 'image',
avi: 'video',
flv: 'video',
h264: 'video',
mov: 'video',
mp4: 'video',
mwv: 'video',
mkv: 'video',
mp3: 'audio',
wav: 'audio',
wma: 'audio',
ogg: 'audio',
txt: 'text',
json: 'text',
html: 'text',
xml: 'text',
eml: 'email',
// Word
doc: 'office',
docx: 'office',
odt: 'office',
dot: 'office',
dotx: 'office',
docm: 'office', // not supported
dotm: 'office', // not yet tested
// Presentation
pot: 'office', // not tested
ppt: 'office',
pptx: 'office',
odp: 'office',
potx: 'office', // not supported
potm: 'office', // not supported
pps: 'office',
ppsx: 'office',
ppsm: 'office', // not supported
pptm: 'office', // not supported
ppam: 'office', // not tested
pages: 'office', // not supported (Apple)
// Spreadsheet
xls: 'office',
xlsx: 'office',
xlsm: 'office',
xlsb: 'office',
ods: 'office',
csv: 'office', // not supported
numbers: 'office', // not supported (Apple)
};
return extensionsToTypes[extension] || 'unknown';
}
class Fullscreen {
constructor(element) {
this.requestFullscreen = () => {
if (this.enter) {
this.enter();
}
};
this.exitFullscreen = () => {
if (this.exit) {
this.exit.bind(window.document)();
}
};
this.toggle = () => {
const doc = window.document;
const isFullscreen = doc.fullscreenElement ||
doc.mozFullScreenElement ||
doc.webkitFullscreenElement ||
doc.msFullscreenElement;
if (isFullscreen) {
this.exitFullscreen();
}
else {
this.requestFullscreen();
}
};
this.enter =
element.requestFullscreen ||
element.msRequestFullscreen ||
element.mozRequestFullScreen ||
element.webkitRequestFullscreen;
this.enter = this.enter.bind(element);
const doc = window.document;
this.exit =
doc.exitFullscreen ||
doc.msExitFullscreen ||
doc.mozCancelFullScreen ||
doc.webkitExitFullscreen;
}
isSupported() {
return !!this.requestFullscreen;
}
}
const textEncoder = new TextEncoder();
const base64Chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
// Use a lookup table to find the index.
const base64Lookup = new Uint8Array(256);
for (var i = 0; i < base64Chars.length; i++) {
base64Lookup[base64Chars.charCodeAt(i)] = i;
}
function decodeBase64(base64) {
let bufferLength = Math.ceil(base64.length / 4) * 3;
const len = base64.length;
let p = 0;
if (base64.length % 4 === 3) {
bufferLength--;
} else if (base64.length % 4 === 2) {
bufferLength -= 2;
} else if (base64[base64.length - 1] === '=') {
bufferLength--;
if (base64[base64.length - 2] === '=') {
bufferLength--;
}
}
const arrayBuffer = new ArrayBuffer(bufferLength);
const bytes = new Uint8Array(arrayBuffer);
for (let i = 0; i < len; i += 4) {
let encoded1 = base64Lookup[base64.charCodeAt(i)];
let encoded2 = base64Lookup[base64.charCodeAt(i + 1)];
let encoded3 = base64Lookup[base64.charCodeAt(i + 2)];
let encoded4 = base64Lookup[base64.charCodeAt(i + 3)];
bytes[p++] = (encoded1 << 2) | (encoded2 >> 4);
bytes[p++] = ((encoded2 & 15) << 4) | (encoded3 >> 2);
bytes[p++] = ((encoded3 & 3) << 6) | (encoded4 & 63);
}
return arrayBuffer;
}
function getDecoder(charset) {
charset = charset || 'utf8';
let decoder;
try {
decoder = new TextDecoder(charset);
} catch (err) {
decoder = new TextDecoder('windows-1252');
}
return decoder;
}
/**
* Converts a Blob into an ArrayBuffer
* @param {Blob} blob Blob to convert
* @returns {ArrayBuffer} Converted value
*/
async function blobToArrayBuffer(blob) {
if ('arrayBuffer' in blob) {
return await blob.arrayBuffer();
}
const fr = new FileReader();
return new Promise((resolve, reject) => {
fr.onload = function (e) {
resolve(e.target.result);
};
fr.onerror = function (e) {
reject(fr.error);
};
fr.readAsArrayBuffer(blob);
});
}
function getHex(c) {
if (
(c >= 0x30 /* 0 */ && c <= 0x39) /* 9 */ ||
(c >= 0x61 /* a */ && c <= 0x66) /* f */ ||
(c >= 0x41 /* A */ && c <= 0x46) /* F */
) {
return String.fromCharCode(c);
}
return false;
}
/**
* Decode a complete mime word encoded string
*
* @param {String} str Mime word encoded string
* @return {String} Decoded unicode string
*/
function decodeWord(charset, encoding, str) {
// RFC2231 added language tag to the encoding
// see: https://tools.ietf.org/html/rfc2231#section-5
// this implementation silently ignores this tag
let splitPos = charset.indexOf('*');
if (splitPos >= 0) {
charset = charset.substr(0, splitPos);
}
encoding = encoding.toUpperCase();
let byteStr;
if (encoding === 'Q') {
str = str
// remove spaces between = and hex char, this might indicate invalidly applied line splitting
.replace(/=\s+([0-9a-fA-F])/g, '=$1')
// convert all underscores to spaces
.replace(/[_\s]/g, ' ');
let buf = textEncoder.encode(str);
let encodedBytes = [];
for (let i = 0, len = buf.length; i < len; i++) {
let c = buf[i];
if (i <= len - 2 && c === 0x3d /* = */) {
let c1 = getHex(buf[i + 1]);
let c2 = getHex(buf[i + 2]);
if (c1 && c2) {
let c = parseInt(c1 + c2, 16);
encodedBytes.push(c);
i += 2;
continue;
}
}
encodedBytes.push(c);
}
byteStr = new ArrayBuffer(encodedBytes.length);
let dataView = new DataView(byteStr);
for (let i = 0, len = encodedBytes.length; i < len; i++) {
dataView.setUint8(i, encodedBytes[i]);
}
} else if (encoding === 'B') {
byteStr = decodeBase64(str.replace(/[^a-zA-Z0-9\+\/=]+/g, ''));
} else {
// keep as is, convert ArrayBuffer to unicode string, assume utf8
byteStr = textEncoder.encode(str);
}
return getDecoder(charset).decode(byteStr);
}
function decodeWords(str) {
let joinString = true;
while (true) {
let result = (str || '')
.toString()
// find base64 words that can be joined
.replace(
/(=\?([^?]+)\?[Bb]\?([^?]*)\?=)\s*(?==\?([^?]+)\?[Bb]\?[^?]*\?=)/g,
(match, left, chLeft, encodedLeftStr, chRight) => {
if (!joinString) {
return match;
}
// only mark b64 chunks to be joined if charsets match and left side does not end with =
if (chLeft === chRight && encodedLeftStr.length % 4 === 0 && !/=$/.test(encodedLeftStr)) {
// set a joiner marker
return left + '__\x00JOIN\x00__';
}
return match;
}
)
// find QP words that can be joined
.replace(
/(=\?([^?]+)\?[Qq]\?[^?]*\?=)\s*(?==\?([^?]+)\?[Qq]\?[^?]*\?=)/g,
(match, left, chLeft, chRight) => {
if (!joinString) {
return match;
}
// only mark QP chunks to be joined if charsets match
if (chLeft === chRight) {
// set a joiner marker
return left + '__\x00JOIN\x00__';
}
return match;
}
)
// join base64 encoded words
.replace(/(\?=)?__\x00JOIN\x00__(=\?([^?]+)\?[QqBb]\?)?/g, '')
// remove spaces between mime encoded words
.replace(/(=\?[^?]+\?[QqBb]\?[^?]*\?=)\s+(?==\?[^?]+\?[QqBb]\?[^?]*\?=)/g, '$1')
// decode words
.replace(/=\?([\w_\-*]+)\?([QqBb])\?([^?]*)\?=/g, (m, charset, encoding, text) =>
decodeWord(charset, encoding, text)
);
if (joinString && result.indexOf('\ufffd') >= 0) {
// text contains \ufffd (EF BF BD), so unicode conversion failed, retry without joining strings
joinString = false;
} else {
return result;
}
}
}
function decodeURIComponentWithCharset(encodedStr, charset) {
charset = charset || 'utf-8';
let encodedBytes = [];
for (let i = 0; i < encodedStr.length; i++) {
let c = encodedStr.charAt(i);
if (c === '%' && /^[a-f0-9]{2}/i.test(encodedStr.substr(i + 1, 2))) {
// encoded sequence
let byte = encodedStr.substr(i + 1, 2);
i += 2;
encodedBytes.push(parseInt(byte, 16));
} else if (c.charCodeAt(0) > 126) {
c = textEncoder.encode(c);
for (let j = 0; j < c.length; j++) {
encodedBytes.push(c[j]);
}
} else {
// "normal" char
encodedBytes.push(c.charCodeAt(0));
}
}
const byteStr = new ArrayBuffer(encodedBytes.length);
const dataView = new DataView(byteStr);
for (let i = 0, len = encodedBytes.length; i < len; i++) {
dataView.setUint8(i, encodedBytes[i]);
}
return getDecoder(charset).decode(byteStr);
}
function decodeParameterValueContinuations(header) {
// handle parameter value continuations
// https://tools.ietf.org/html/rfc2231#section-3
// preprocess values
let paramKeys = new Map();
Object.keys(header.params).forEach(key => {
let match = key.match(/\*((\d+)\*?)?$/);
if (!match) {
// nothing to do here, does not seem like a continuation param
return;
}
let actualKey = key.substr(0, match.index).toLowerCase();
let nr = Number(match[2]) || 0;
let paramVal;
if (!paramKeys.has(actualKey)) {
paramVal = {
charset: false,
values: []
};
paramKeys.set(actualKey, paramVal);
} else {
paramVal = paramKeys.get(actualKey);
}
let value = header.params[key];
if (nr === 0 && match[0].charAt(match[0].length - 1) === '*' && (match = value.match(/^([^']*)'[^']*'(.*)$/))) {
paramVal.charset = match[1] || 'utf-8';
value = match[2];
}
paramVal.values.push({ nr, value });
// remove the old reference
delete header.params[key];
});
paramKeys.forEach((paramVal, key) => {
header.params[key] = decodeURIComponentWithCharset(
paramVal.values
.sort((a, b) => a.nr - b.nr)
.map(a => a.value)
.join(''),
paramVal.charset
);
});
}
class PassThroughDecoder {
constructor() {
this.chunks = [];
}
update(line) {
this.chunks.push(line);
this.chunks.push('\n');
}
finalize() {
// convert an array of arraybuffers into a blob and then back into a single arraybuffer
return blobToArrayBuffer(new Blob(this.chunks, { type: 'application/octet-stream' }));
}
}
class Base64Decoder {
constructor(opts) {
opts = opts || {};
this.decoder = opts.decoder || new TextDecoder();
this.maxChunkSize = 100 * 1024;
this.chunks = [];
this.remainder = '';
}
update(buffer) {
let str = this.decoder.decode(buffer);
if (/[^a-zA-Z0-9+\/]/.test(str)) {
str = str.replace(/[^a-zA-Z0-9+\/]+/g, '');
}
this.remainder += str;
if (this.remainder.length >= this.maxChunkSize) {
let allowedBytes = Math.floor(this.remainder.length / 4) * 4;
let base64Str;
if (allowedBytes === this.remainder.length) {
base64Str = this.remainder;
this.remainder = '';
} else {
base64Str = this.remainder.substr(0, allowedBytes);
this.remainder = this.remainder.substr(allowedBytes);
}
if (base64Str.length) {
this.chunks.push(decodeBase64(base64Str));
}
}
}
finalize() {
if (this.remainder && !/^=+$/.test(this.remainder)) {
this.chunks.push(decodeBase64(this.remainder));
}
return blobToArrayBuffer(new Blob(this.chunks, { type: 'application/octet-stream' }));
}
}
// Regex patterns compiled once for performance
const VALID_QP_REGEX = /^=[a-f0-9]{2}$/i;
const QP_SPLIT_REGEX = /(?==[a-f0-9]{2})/i;
const SOFT_LINE_BREAK_REGEX = /=\r?\n/g;
const PARTIAL_QP_ENDING_REGEX = /=[a-fA-F0-9]?$/;
class QPDecoder {
constructor(opts) {
opts = opts || {};
this.decoder = opts.decoder || new TextDecoder();
this.maxChunkSize = 100 * 1024;
this.remainder = '';
this.chunks = [];
}
decodeQPBytes(encodedBytes) {
let buf = new ArrayBuffer(encodedBytes.length);
let dataView = new DataView(buf);
for (let i = 0, len = encodedBytes.length; i < len; i++) {
dataView.setUint8(i, parseInt(encodedBytes[i], 16));
}
return buf;
}
decodeChunks(str) {
// unwrap newlines
str = str.replace(SOFT_LINE_BREAK_REGEX, '');
let list = str.split(QP_SPLIT_REGEX);
let encodedBytes = [];
for (let part of list) {
if (part.charAt(0) !== '=') {
if (encodedBytes.length) {
this.chunks.push(this.decodeQPBytes(encodedBytes));
encodedBytes = [];
}
this.chunks.push(part);
continue;
}
if (part.length === 3) {
// Validate that this is actually a valid QP sequence
if (VALID_QP_REGEX.test(part)) {
encodedBytes.push(part.substr(1));
} else {
// Not a valid QP sequence, treat as literal text
if (encodedBytes.length) {
this.chunks.push(this.decodeQPBytes(encodedBytes));
encodedBytes = [];
}
this.chunks.push(part);
}
continue;
}
if (part.length > 3) {
// First 3 chars should be a valid QP sequence
const firstThree = part.substr(0, 3);
if (VALID_QP_REGEX.test(firstThree)) {
encodedBytes.push(part.substr(1, 2));
this.chunks.push(this.decodeQPBytes(encodedBytes));
encodedBytes = [];
part = part.substr(3);
this.chunks.push(part);
} else {
// Not a valid QP sequence, treat entire part as literal
if (encodedBytes.length) {
this.chunks.push(this.decodeQPBytes(encodedBytes));
encodedBytes = [];
}
this.chunks.push(part);
}
}
}
if (encodedBytes.length) {
this.chunks.push(this.decodeQPBytes(encodedBytes));
encodedBytes = [];
}
}
update(buffer) {
// expect full lines, so add line terminator as well
let str = this.decoder.decode(buffer) + '\n';
str = this.remainder + str;
if (str.length < this.maxChunkSize) {
this.remainder = str;
return;
}
this.remainder = '';
let partialEnding = str.match(PARTIAL_QP_ENDING_REGEX);
if (partialEnding) {
if (partialEnding.index === 0) {
this.remainder = str;
return;
}
this.remainder = str.substr(partialEnding.index);
str = str.substr(0, partialEnding.index);
}
this.decodeChunks(str);
}
finalize() {
if (this.remainder.length) {
this.decodeChunks(this.remainder);
this.remainder = '';
}
// convert an array of arraybuffers into a blob and then back into a single arraybuffer
return blobToArrayBuffer(new Blob(this.chunks, { type: 'application/octet-stream' }));
}
}
class MimeNode {
constructor(options) {
this.options = options || {};
this.postalMime = this.options.postalMime;
this.root = !!this.options.parentNode;
this.childNodes = [];
if (this.options.parentNode) {
this.parentNode = this.options.parentNode;
this.depth = this.parentNode.depth + 1;
if (this.depth > this.options.maxNestingDepth) {
throw new Error(`Maximum MIME nesting depth of ${this.options.maxNestingDepth} levels exceeded`);
}
this.options.parentNode.childNodes.push(this);
} else {
this.depth = 0;
}
this.state = 'header';
this.headerLines = [];
this.headerSize = 0;
// RFC 2046 Section 5.1.5: multipart/digest defaults to message/rfc822
const parentMultipartType = this.options.parentMultipartType || null;
const defaultContentType = parentMultipartType === 'digest' ? 'message/rfc822' : 'text/plain';
this.contentType = {
value: defaultContentType,
default: true
};
this.contentTransferEncoding = {
value: '8bit'
};
this.contentDisposition = {
value: ''
};
this.headers = [];
this.contentDecoder = false;
}
setupContentDecoder(transferEncoding) {
if (/base64/i.test(transferEncoding)) {
this.contentDecoder = new Base64Decoder();
} else if (/quoted-printable/i.test(transferEncoding)) {
this.contentDecoder = new QPDecoder({ decoder: getDecoder(this.contentType.parsed.params.charset) });
} else {
this.contentDecoder = new PassThroughDecoder();
}
}
async finalize() {
if (this.state === 'finished') {
return;
}
if (this.state === 'header') {
this.processHeaders();
}
// remove self from boundary listing
let boundaries = this.postalMime.boundaries;
for (let i = boundaries.length - 1; i >= 0; i--) {
let boundary = boundaries[i];
if (boundary.node === this) {
boundaries.splice(i, 1);
break;
}
}
await this.finalizeChildNodes();
this.content = this.contentDecoder ? await this.contentDecoder.finalize() : null;
this.state = 'finished';
}
async finalizeChildNodes() {
for (let childNode of this.childNodes) {
await childNode.finalize();
}
}
// Strip RFC 822 comments (parenthesized text) from structured header values
stripComments(str) {
let result = '';
let depth = 0;
let escaped = false;
let inQuote = false;
for (let i = 0; i < str.length; i++) {
const chr = str.charAt(i);
if (escaped) {
if (depth === 0) {
result += chr;
}
escaped = false;
continue;
}
if (chr === '\\') {
escaped = true;
if (depth === 0) {
result += chr;
}
continue;
}
if (chr === '"' && depth === 0) {
inQuote = !inQuote;
result += chr;
continue;
}
if (!inQuote) {
if (chr === '(') {
depth++;
continue;
}
if (chr === ')' && depth > 0) {
depth--;
continue;
}
}
if (depth === 0) {
result += chr;
}
}
return result;
}
parseStructuredHeader(str) {
// Strip RFC 822 comments before parsing
str = this.stripComments(str);
let response = {
value: false,
params: {}
};
let key = false;
let value = '';
let stage = 'value';
let quote = false;
let escaped = false;
let chr;
for (let i = 0, len = str.length; i < len; i++) {
chr = str.charAt(i);
switch (stage) {
case 'key':
if (chr === '=') {
key = value.trim().toLowerCase();
stage = 'value';
value = '';
break;
}
value += chr;
break;
case 'value':
if (escaped) {
value += chr;
} else if (chr === '\\') {
escaped = true;
continue;
} else if (quote && chr === quote) {
quote = false;
} else if (!quote && chr === '"') {
quote = chr;
} else if (!quote && chr === ';') {
if (key === false) {
response.value = value.trim();
} else {
response.params[key] = value.trim();
}
stage = 'key';
value = '';
} else {
value += chr;
}
escaped = false;
break;
}
}
// finalize remainder
value = value.trim();
if (stage === 'value') {
if (key === false) {
// default value
response.value = value;
} else {
// subkey value
response.params[key] = value;
}
} else if (value) {
// treat as key without value, see emptykey:
// Header-Key: somevalue; key=value; emptykey
response.params[value.toLowerCase()] = '';
}
if (response.value) {
response.value = response.value.toLowerCase();
}
// convert Parameter Value Continuations into single strings
decodeParameterValueContinuations(response);
return response;
}
decodeFlowedText(str, delSp) {
return (
str
.split(/\r?\n/)
// remove soft linebreaks
// soft linebreaks are added after space symbols
.reduce((previousValue, currentValue) => {
if (/ $/.test(previousValue) && !/(^|\n)-- $/.test(previousValue)) {
if (delSp) {
// delsp adds space to text to be able to fold it
// these spaces can be removed once the text is unfolded
return previousValue.slice(0, -1) + currentValue;
} else {
return previousValue + currentValue;
}
} else {
return previousValue + '\n' + currentValue;
}
})
// remove whitespace stuffing
// http://tools.ietf.org/html/rfc3676#section-4.4
.replace(/^ /gm, '')
);
}
getTextContent() {
if (!this.content) {
return '';
}
let str = getDecoder(this.contentType.parsed.params.charset).decode(this.content);
if (/^flowed$/i.test(this.contentType.parsed.params.format)) {
str = this.decodeFlowedText(str, /^yes$/i.test(this.contentType.parsed.params.delsp));
}
return str;
}
processHeaders() {
// First pass: merge folded headers (backward iteration)
for (let i = this.headerLines.length - 1; i >= 0; i--) {
let line = this.headerLines[i];
if (i && /^\s/.test(line)) {
this.headerLines[i - 1] += '\n' + line;
this.headerLines.splice(i, 1);
}
}
// Initialize rawHeaderLines to store unmodified lines
this.rawHeaderLines = [];
// Second pass: process headers (MUST be backward to maintain this.headers order)
// The existing code iterates backward and postal-mime.js calls .reverse()
// We must preserve this behavior to avoid breaking changes
for (let i = this.headerLines.length - 1; i >= 0; i--) {
let rawLine = this.headerLines[i];
// Extract key from raw line for rawHeaderLines
let sep = rawLine.indexOf(':');
let rawKey = sep < 0 ? rawLine.trim() : rawLine.substr(0, sep).trim();
// Store raw line with lowercase key
this.rawHeaderLines.push({
key: rawKey.toLowerCase(),
line: rawLine
});
// Normalize for this.headers (existing behavior - order preserved)
let normalizedLine = rawLine.replace(/\s+/g, ' ');
sep = normalizedLine.indexOf(':');
let key = sep < 0 ? normalizedLine.trim() : normalizedLine.substr(0, sep).trim();
let value = sep < 0 ? '' : normalizedLine.substr(sep + 1).trim();
this.headers.push({ key: key.toLowerCase(), originalKey: key, value });
switch (key.toLowerCase()) {
case 'content-type':
if (this.contentType.default) {
this.contentType = { value, parsed: {} };
}
break;
case 'content-transfer-encoding':
this.contentTransferEncoding = { value, parsed: {} };
break;
case 'content-disposition':
this.contentDisposition = { value, parsed: {} };
break;
case 'content-id':
this.contentId = value;
break;
case 'content-description':
this.contentDescription = value;
break;
}
}
this.contentType.parsed = this.parseStructuredHeader(this.contentType.value);
this.contentType.multipart = /^multipart\//i.test(this.contentType.parsed.value)
? this.contentType.parsed.value.substr(this.contentType.parsed.value.indexOf('/') + 1)
: false;
if (this.contentType.multipart && this.contentType.parsed.params.boundary) {
// add self to boundary terminator listing
this.postalMime.boundaries.push({
value: textEncoder.encode(this.contentType.parsed.params.boundary),
node: this
});
}
this.contentDisposition.parsed = this.parseStructuredHeader(this.contentDisposition.value);
this.contentTransferEncoding.encoding = this.contentTransferEncoding.value
.toLowerCase()
.split(/[^\w-]/)
.shift();
this.setupContentDecoder(this.contentTransferEncoding.encoding);
}
feed(line) {
switch (this.state) {
case 'header':
if (!line.length) {
this.state = 'body';
return this.processHeaders();
}
this.headerSize += line.length;
if (this.headerSize > this.options.maxHeadersSize) {
let error = new Error(`Maximum header size of ${this.options.maxHeadersSize} bytes exceeded`);
throw error;
}
this.headerLines.push(getDecoder().decode(line));
break;
case 'body': {
// add line to body
this.contentDecoder.update(line);
}
}
}
}
// Entity map from https://html.spec.whatwg.org/multipage/named-characters.html#named-character-references
const htmlEntities = {
'Æ': '\u00C6',
'Æ': '\u00C6',
'&': '\u0026',
'&': '\u0026',
'Á': '\u00C1',
'Á': '\u00C1',
'Ă': '\u0102',
'Â': '\u00C2',
'Â': '\u00C2',
'А': '\u0410',
'𝔄': '\uD835\uDD04',
'À': '\u00C0',
'À': '\u00C0',
'Α': '\u0391',
'Ā': '\u0100',
'⩓': '\u2A53',
'Ą': '\u0104',
'𝔸': '\uD835\uDD38',
'⁡': '\u2061',
'Å': '\u00C5',
'Å': '\u00C5',
'𝒜': '\uD835\uDC9C',
'≔': '\u2254',
'Ã': '\u00C3',
'Ã': '\u00C3',
'Ä': '\u00C4',
'Ä': '\u00C4',
'∖': '\u2216',
'⫧': '\u2AE7',
'⌆': '\u2306',
'Б': '\u0411',
'∵': '\u2235',
'ℬ': '\u212C',
'Β': '\u0392',
'𝔅': '\uD835\uDD05',
'𝔹': '\uD835\uDD39',
'˘': '\u02D8',
'ℬ': '\u212C',
'≎': '\u224E',
'Ч': '\u0427',
'©': '\u00A9',
'©': '\u00A9',
'Ć': '\u0106',
'⋒': '\u22D2',
'ⅅ': '\u2145',
'ℭ': '\u212D',
'Č': '\u010C',
'Ç': '\u00C7',
'Ç': '\u00C7',
'Ĉ': '\u0108',
'∰': '\u2230',
'Ċ': '\u010A',
'¸': '\u00B8',
'·': '\u00B7',
'ℭ': '\u212D',
'Χ': '\u03A7',
'⊙': '\u2299',
'⊖': '\u2296',
'⊕': '\u2295',
'⊗': '\u2297',
'∲': '\u2232',
'”': '\u201D',
'’': '\u2019',
'∷': '\u2237',
'⩴': '\u2A74',
'≡': '\u2261',
'∯': '\u222F',
'∮': '\u222E',
'ℂ': '\u2102',
'∐': '\u2210',
'∳': '\u2233',
'⨯': '\u2A2F',
'𝒞': '\uD835\uDC9E',
'⋓': '\u22D3',
'≍': '\u224D',
'ⅅ': '\u2145',
'⤑': '\u2911',
'Ђ': '\u0402',
'Ѕ': '\u0405',
'Џ': '\u040F',
'‡': '\u2021',
'↡': '\u21A1',
'⫤': '\u2AE4',
'Ď': '\u010E',
'Д': '\u0414',
'∇': '\u2207',
'Δ': '\u0394',
'𝔇': '\uD835\uDD07',
'´': '\u00B4',
'˙': '\u02D9',
'˝': '\u02DD',
'`': '\u0060',
'˜': '\u02DC',
'⋄': '\u22C4',
'ⅆ': '\u2146',
'𝔻': '\uD835\uDD3B',
'¨': '\u00A8',
'⃜': '\u20DC',
'≐': '\u2250',
'∯': '\u222F',
'¨': '\u00A8',
'⇓': '\u21D3',
'⇐': '\u21D0',
'⇔': '\u21D4',
'⫤': '\u2AE4',
'⟸': '\u27F8',
'⟺': '\u27FA',
'⟹': '\u27F9',
'⇒': '\u21D2',
'⊨': '\u22A8',
'⇑': '\u21D1',
'⇕': '\u21D5',
'∥': '\u2225',
'↓': '\u2193',
'⤓': '\u2913',
'⇵': '\u21F5',
'̑': '\u0311',
'⥐': '\u2950',
'⥞': '\u295E',
'↽': '\u21BD',
'⥖': '\u2956',
'⥟': '\u295F',
'⇁': '\u21C1',
'⥗': '\u2957',
'⊤': '\u22A4',
'↧': '\u21A7',
'⇓': '\u21D3',
'𝒟': '\uD835\uDC9F',
'Đ': '\u0110',
'Ŋ': '\u014A',
'Ð': '\u00D0',
'Ð': '\u00D0',
'É': '\u00C9',
'É': '\u00C9',
'Ě': '\u011A',
'Ê': '\u00CA',
'Ê': '\u00CA',
'Э': '\u042D',
'Ė': '\u0116',
'𝔈': '\uD835\uDD08',
'È': '\u00C8',
'È': '\u00C8',
'∈': '\u2208',
'Ē': '\u0112',
'◻': '\u25FB',
'▫': '\u25AB',
'Ę': '\u0118',
'𝔼': '\uD835\uDD3C',
'Ε': '\u0395',
'⩵': '\u2A75',
'≂': '\u2242',
'⇌': '\u21CC',
'ℰ': '\u2130',
'⩳': '\u2A73',
'Η': '\u0397',
'Ë': '\u00CB',
'Ë': '\u00CB',
'∃': '\u2203',
'ⅇ': '\u2147',
'Ф': '\u0424',
'𝔉': '\uD835\uDD09',
'◼': '\u25FC',
'▪': '\u25AA',
'𝔽': '\uD835\uDD3D',
'∀': '\u2200',
'ℱ': '\u2131',
'ℱ': '\u2131',
'Ѓ': '\u0403',
'>': '\u003E',
'>': '\u003E',
'Γ': '\u0393',
'Ϝ': '\u03DC',
'Ğ': '\u011E',
'Ģ': '\u0122',
'Ĝ': '\u011C',
'Г': '\u0413',
'Ġ': '\u0120',
'𝔊': '\uD835\uDD0A',
'⋙': '\u22D9',
'𝔾': '\uD835\uDD3E',
'≥': '\u2265',
'⋛': '\u22DB',
'≧': '\u2267',
'⪢': '\u2AA2',
'≷': '\u2277',
'⩾': '\u2A7E',
'≳': '\u2273',
'𝒢': '\uD835\uDCA2',
'≫': '\u226B',
'Ъ': '\u042A',
'ˇ': '\u02C7',
'^': '\u005E',
'Ĥ': '\u0124',
'ℌ': '\u210C',
'ℋ': '\u210B',
'ℍ': '\u210D',
'─': '\u2500',
'ℋ': '\u210B',
'Ħ': '\u0126',
'≎': '\u224E',
'≏': '\u224F',
'Е': '\u0415',
'IJ': '\u0132',
'Ё': '\u0401',
'Í': '\u00CD',
'Í': '\u00CD',
'Î': '\u00CE',
'Î': '\u00CE',
'И': '\u0418',
'İ': '\u0130',
'ℑ': '\u2111',
'Ì': '\u00CC',
'Ì': '\u00CC',
'ℑ': '\u2111',
'Ī': '\u012A',
'ⅈ': '\u2148',
'⇒': '\u21D2',
'∬': '\u222C',
'∫': '\u222B',
'⋂': '\u22C2',
'⁣': '\u2063',
'⁢': '\u2062',
'Į': '\u012E',
'𝕀': '\uD835\uDD40',
'Ι': '\u0399',
'ℐ': '\u2110',
'Ĩ': '\u0128',
'І': '\u0406',
'Ï': '\u00CF',
'Ï': '\u00CF',
'Ĵ': '\u0134',
'Й': '\u0419',
'𝔍': '\uD835\uDD0D',
'𝕁': '\uD835\uDD41',
'𝒥': '\uD835\uDCA5',
'Ј': '\u0408',
'Є': '\u0404',
'Х': '\u0425',
'Ќ': '\u040C',
'Κ': '\u039A',
'Ķ': '\u0136',
'К': '\u041A',
'𝔎': '\uD835\uDD0E',
'𝕂': '\uD835\uDD42',
'𝒦': '\uD835\uDCA6',
'Љ': '\u0409',
'<': '\u003C',
'<': '\u003C',
'Ĺ': '\u0139',
'Λ': '\u039B',
'⟪': '\u27EA',
'ℒ': '\u2112',
'↞': '\u219E',
'Ľ': '\u013D',
'Ļ': '\u013B',
'Л': '\u041B',
'⟨': '\u27E8',
'←': '\u2190',
'⇤': '\u21E4',
'⇆': '\u21C6',
'⌈': '\u2308',
'⟦': '\u27E6',
'⥡': '\u2961',
'⇃': '\u21C3',
'⥙': '\u2959',
'⌊': '\u230A',
'↔': '\u2194',
'⥎': '\u294E',
'⊣': '\u22A3',
'↤': '\u21A4',
'⥚': '\u295A',
'⊲': '\u22B2',
'⧏': '\u29CF',
'⊴': '\u22B4',
'⥑': '\u2951',
'⥠': '\u2960',
'↿': '\u21BF',
'⥘': '\u2958',
'↼': '\u21BC',
'⥒': '\u2952',
'⇐': '\u21D0',
'⇔': '\u21D4',
'⋚': '\u22DA',
'≦': '\u2266',
'≶': '\u2276',
'⪡': '\u2AA1',
'⩽': '\u2A7D',
'≲': '\u2272',
'𝔏': '\uD835\uDD0F',
'⋘': '\u22D8',
'⇚': '\u21DA',
'Ŀ': '\u013F',
'⟵': '\u27F5',
'⟷': '\u27F7',
'⟶': '\u27F6',
'⟸': '\u27F8',
'⟺': '\u27FA',
'⟹': '\u27F9',
'𝕃': '\uD835\uDD43',
'↙': '\u2199',
'↘': '\u2198',
'ℒ': '\u2112',
'↰': '\u21B0',
'Ł': '\u0141',
'≪': '\u226A',
'⤅': '\u2905',
'М': '\u041C',
' ': '\u205F',
'ℳ': '\u2133',
'𝔐': '\uD835\uDD10',
'∓': '\u2213',
'𝕄': '\uD835\uDD44',
'ℳ': '\u2133',
'Μ': '\u039C',
'Њ': '\u040A',
'Ń': '\u0143',
'Ň': '\u0147',
'Ņ': '\u0145',
'Н': '\u041D',
'​': '\u200B',
'​': '\u200B',
'​': '\u200B',
'​': '\u200B',
'≫': '\u226B',
'≪': '\u226A',
'
': '\u000A',
'𝔑': '\uD835\uDD11',
'⁠': '\u2060',
' ': '\u00A0',
'ℕ': '\u2115',
'⫬': '\u2AEC',
'≢': '\u2262',
'≭': '\u226D',
'∦': '\u2226',
'∉': '\u2209',
'≠': '\u2260',
'≂̸': '\u2242\u0338',
'∄': '\u2204',
'≯': '\u226F',
'≱': '\u2271',
'≧̸': '\u2267\u0338',
'≫̸': '\u226B\u0338',
'≹': '\u2279',
'⩾̸': '\u2A7E\u0338',
'≵': '\u2275',
'≎̸': '\u224E\u0338',
'≏̸': '\u224F\u0338',
'⋪': '\u22EA',
'⧏̸': '\u29CF\u0338',
'⋬': '\u22EC',
'≮': '\u226E',
'≰': '\u2270',
'≸': '\u2278',
'≪̸': '\u226A\u0338',
'⩽̸': '\u2A7D\u0338',
'≴': '\u2274',
'⪢̸': '\u2AA2\u0338',
'⪡̸': '\u2AA1\u0338',
'⊀': '\u2280',
'⪯̸': '\u2AAF\u0338',
'⋠': '\u22E0',
'∌': '\u220C',
'⋫': '\u22EB',
'⧐̸': '\u29D0\u0338',
'⋭': '\u22ED',
'⊏̸': '\u228F\u0338',
'⋢': '\u22E2',
'⊐̸': '\u2290\u0338',
'⋣': '\u22E3',
'⊂⃒': '\u2282\u20D2',
'⊈': '\u2288',
'⊁': '\u2281',
'⪰̸': '\u2AB0\u0338',
'⋡': '\u22E1',
'≿̸': '\u227F\u0338',
'⊃⃒': '\u2283\u20D2',
'⊉': '\u2289',
'≁': '\u2241',
'≄': '\u2244',
'≇': '\u2247',
'≉': '\u2249',
'∤': '\u2224',
'𝒩': '\uD835\uDCA9',
'Ñ': '\u00D1',
'Ñ': '\u00D1',
'Ν': '\u039D',
'Œ': '\u0152',
'Ó': '\u00D3',
'Ó': '\u00D3',
'Ô': '\u00D4',
'Ô': '\u00D4',
'О': '\u041E',
'Ő': '\u0150',
'𝔒': '\uD835\uDD12',
'Ò': '\u00D2',
'Ò': '\u00D2',
'Ō': '\u014C',
'Ω': '\u03A9',
'Ο': '\u039F',
'𝕆': '\uD835\uDD46',
'“': '\u201C',
'‘': '\u2018',
'⩔': '\u2A54',
'𝒪': '\uD835\uDCAA',
'Ø': '\u00D8',
'Ø': '\u00D8',
'Õ': '\u00D5',
'Õ': '\u00D5',
'⨷': '\u2A37',
'Ö': '\u00D6',
'Ö': '\u00D6',
'‾': '\u203E',
'⏞': '\u23DE',
'⎴': '\u23B4',
'⏜': '\u23DC',
'∂': '\u2202',
'П': '\u041F',
'𝔓': '\uD835\uDD13',
'Φ': '\u03A6',
'Π': '\u03A0',
'±': '\u00B1',
'ℌ': '\u210C',
'ℙ': '\u2119',
'⪻': '\u2ABB',
'≺': '\u227A',
'⪯': '\u2AAF',
'≼': '\u227C',
'≾': '\u227E',
'″': '\u2033',
'∏': '\u220F',
'∷': '\u2237',
'∝': '\u221D',
'𝒫': '\uD835\uDCAB',
'Ψ': '\u03A8',
'"': '\u0022',
'"': '\u0022',
'𝔔': '\uD835\uDD14',
'ℚ': '\u211A',
'𝒬': '\uD835\uDCAC',
'⤐': '\u2910',
'®': '\u00AE',
'®': '\u00AE',
'Ŕ': '\u0154',
'⟫': '\u27EB',
'↠': '\u21A0',
'⤖': '\u2916',
'Ř': '\u0158',
'Ŗ': '\u0156',
'Р': '\u0420',
'ℜ': '\u211C',
'∋': '\u220B',
'⇋': '\u21CB',
'⥯': '\u296F',
'ℜ': '\u211C',
'Ρ': '\u03A1',
'⟩': '\u27E9',
'→': '\u2192',
'⇥': '\u21E5',
'⇄': '\u21C4',
'⌉': '\u2309',
'⟧': '\u27E7',
'⥝': '\u295D',
'⇂': '\u21C2',
'⥕': '\u2955',
'⌋': '\u230B',
'⊢': '\u22A2',
'↦': '\u21A6',
'⥛': '\u295B',
'⊳': '\u22B3',
'⧐': '\u29D0',
'⊵': '\u22B5',
'⥏': '\u294F',
'⥜': '\u295C',
'↾': '\u21BE',
'⥔': '\u2954',
'⇀': '\u21C0',
'⥓': '\u2953',
'⇒': '\u21D2',
'ℝ': '\u211D',
'⥰': '\u2970',
'⇛': '\u21DB',
'ℛ': '\u211B',
'↱': '\u21B1',
'⧴': '\u29F4',
'Щ': '\u0429',
'Ш': '\u0428',
'Ь': '\u042C',
'Ś': '\u015A',
'⪼': '\u2ABC',
'Š': '\u0160',
'Ş': '\u015E',
'Ŝ': '\u015C',
'С': '\u0421',
'𝔖': '\uD835\uDD16',
'↓': '\u2193',
'←': '\u2190',
'→': '\u2192',
'↑': '\u2191',
'Σ': '\u03A3',
'∘': '\u2218',
'𝕊': '\uD835\uDD4A',
'√': '\u221A',
'□': '\u25A1',
'⊓': '\u2293',
'⊏': '\u228F',
'⊑': '\u2291',
'⊐': '\u2290',
'⊒': '\u2292',
'⊔': '\u2294',
'𝒮': '\uD835\uDCAE',
'⋆': '\u22C6',
'⋐': '\u22D0',
'⋐': '\u22D0',
'⊆': '\u2286',
'≻': '\u227B',
'⪰': '\u2AB0',
'≽': '\u227D',
'≿': '\u227F',
'∋': '\u220B',
'∑': '\u2211',
'⋑': '\u22D1',
'⊃': '\u2283',
'⊇': '\u2287',
'⋑': '\u22D1',
'Þ': '\u00DE',
'Þ': '\u00DE',
'™': '\u2122',
'Ћ': '\u040B',
'Ц': '\u0426',
'	': '\u0009',
'Τ': '\u03A4',
'Ť': '\u0164',
'Ţ': '\u0162',
'Т': '\u0422',
'𝔗': '\uD835\uDD17',
'∴': '\u2234',
'Θ': '\u0398',
'  ': '\u205F\u200A',
' ': '\u2009',
'∼': '\u223C',
'≃': '\u2243',
'≅': '\u2245',
'≈': '\u2248',
'𝕋': '\uD835\uDD4B',
'⃛': '\u20DB',
'𝒯': '\uD835\uDCAF',
'Ŧ': '\u0166',
'Ú': '\u00DA',
'Ú': '\u00DA',
'↟': '\u219F',
'⥉': '\u2949',
'Ў': '\u040E',
'Ŭ': '\u016C',
'Û': '\u00DB',
'Û': '\u00DB',
'У': '\u0423',
'Ű': '\u0170',
'𝔘': '\uD835\uDD18',
'Ù': '\u00D9',
'Ù': '\u00D9',
'Ū': '\u016A',
'_': '\u005F',
'⏟': '\u23DF',
'⎵': '\u23B5',
'⏝': '\u23DD',
'⋃': '\u22C3',
'⊎': '\u228E',
'Ų': '\u0172',
'𝕌': '\uD835\uDD4C',
'↑': '\u2191',
'⤒': '\u2912',
'⇅': '\u21C5',
'↕': '\u2195',
'⥮': '\u296E',
'⊥': '\u22A5',
'↥': '\u21A5',
'⇑': '\u21D1',
'⇕': '\u21D5',
'↖': '\u2196',
'↗': '\u2197',
'ϒ': '\u03D2',
'Υ': '\u03A5',
'Ů': '\u016E',
'𝒰': '\uD835\uDCB0',
'Ũ': '\u0168',
'Ü': '\u00DC',
'Ü': '\u00DC',
'⊫': '\u22AB',
'⫫': '\u2AEB',
'В': '\u0412',
'⊩': '\u22A9',
'⫦': '\u2AE6',
'⋁': '\u22C1',
'‖': '\u2016',
'‖': '\u2016',
'∣': '\u2223',
'|': '\u007C',
'❘': '\u2758',
'≀': '\u2240',
' ': '\u200A',
'𝔙': '\uD835\uDD19',
'𝕍': '\uD835\uDD4D',
'𝒱': '\uD835\uDCB1',
'⊪': '\u22AA',
'Ŵ': '\u0174',
'⋀': '\u22C0',
'𝔚': '\uD835\uDD1A',
'𝕎': '\uD835\uDD4E',
'𝒲': '\uD835\uDCB2',
'𝔛': '\uD835\uDD1B',
'Ξ': '\u039E',
'𝕏': '\uD835\uDD4F',
'𝒳': '\uD835\uDCB3',
'Я': '\u042F',
'Ї': '\u0407',
'Ю': '\u042E',
'Ý': '\u00DD',
'Ý': '\u00DD',
'Ŷ': '\u0176',
'Ы': '\u042B',
'𝔜': '\uD835\uDD1C',
'𝕐': '\uD835\uDD50',
'𝒴': '\uD835\uDCB4',
'Ÿ': '\u0178',
'Ж': '\u0416',
'Ź': '\u0179',
'Ž': '\u017D',
'З': '\u0417',
'Ż': '\u017B',
'​': '\u200B',
'Ζ': '\u0396',
'ℨ': '\u2128',
'ℤ': '\u2124',
'𝒵': '\uD835\uDCB5',
'á': '\u00E1',
'á': '\u00E1',
'ă': '\u0103',
'∾': '\u223E',
'∾̳': '\u223E\u0333',
'∿': '\u223F',
'â': '\u00E2',
'â': '\u00E2',
'´': '\u00B4',
'´': '\u00B4',
'а': '\u0430',
'æ': '\u00E6',
'æ': '\u00E6',
'⁡': '\u2061',
'𝔞': '\uD835\uDD1E',
'à': '\u00E0',
'à': '\u00E0',
'ℵ': '\u2135',
'ℵ': '\u2135',
'α': '\u03B1',
'ā': '\u0101',
'⨿': '\u2A3F',
'&': '\u0026',
'&': '\u0026',
'∧': '\u2227',
'⩕': '\u2A55',
'⩜': '\u2A5C',
'⩘': '\u2A58',
'⩚': '\u2A5A',
'∠': '\u2220',
'⦤': '\u29A4',
'∠': '\u2220',
'∡': '\u2221',
'⦨': '\u29A8',
'⦩': '\u29A9',
'⦪': '\u29AA',
'⦫': '\u29AB',
'⦬': '\u29AC',
'⦭': '\u29AD',
'⦮': '\u29AE',
'⦯': '\u29AF',
'∟': '\u221F',
'⊾': '\u22BE',
'⦝': '\u299D',
'∢': '\u2222',
'Å': '\u00C5',
'⍼': '\u237C',
'ą': '\u0105',
'𝕒': '\uD835\uDD52',
'≈': '\u2248',
'⩰': '\u2A70',
'⩯': '\u2A6F',
'≊': '\u224A',
'≋': '\u224B',
''': '\u0027',
'≈': '\u2248',
'≊': '\u224A',