@runeditrun/rer 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/README.md +3 -2
  2. package/cli/README.md +4 -2
  3. package/cli/contract.mjs +2 -2
  4. package/cli/deploy.mjs +17 -3
  5. package/cli/detached-server.mjs +51 -0
  6. package/cli/hosted-output.mjs +2 -2
  7. package/cli/hydration/check.mjs +2 -2
  8. package/cli/inspect.mjs +1 -1
  9. package/cli/main.mjs +1 -0
  10. package/cli/managed-server.mjs +12 -5
  11. package/cli/parse.mjs +3 -2
  12. package/cli/release.mjs +1 -0
  13. package/cli/site-bindings.mjs +291 -0
  14. package/cli/site-browser-objects.mjs +36 -0
  15. package/cli/site-check.mjs +46 -31
  16. package/cli/site-client.mjs +50 -0
  17. package/cli/site-data.mjs +54 -0
  18. package/cli/site-entities.json +1 -0
  19. package/cli/site-input-assets.mjs +58 -0
  20. package/cli/site-inputs.mjs +79 -0
  21. package/cli/site-markup.mjs +102 -0
  22. package/cli/site-private.mjs +36 -0
  23. package/cli/site-references.mjs +93 -0
  24. package/cli/site-render.mjs +7 -5
  25. package/cli/site-syntax.mjs +21 -0
  26. package/cli/site.mjs +32 -11
  27. package/global/CHANGELOG.md +25 -0
  28. package/global/README.md +3 -2
  29. package/global/main.mjs +2 -0
  30. package/global/output.mjs +12 -0
  31. package/global/rer.mjs +3 -0
  32. package/modules/deploy-kit/deploy.mjs +5 -2
  33. package/modules/deploy-kit/diagnostics.mjs +55 -0
  34. package/modules/deploy-kit/owner-cli.mjs +10 -4
  35. package/modules/deploy-kit/owner.mjs +3 -0
  36. package/modules/deploy-kit/provider.mjs +45 -6
  37. package/modules/operator-auth/accounts/native.mjs +1 -1
  38. package/modules/operator-auth/dev/badge.mjs +4 -1
  39. package/modules/operator-auth/index.d.mts +4 -9
  40. package/modules/operator-auth/page.mjs +1 -1
  41. package/modules/operator-auth/service.mjs +1 -0
  42. package/modules/operator-auth/signin/index.d.mts +11 -0
  43. package/modules/operator-auth/signin/index.mjs +10 -7
  44. package/modules/release/README.md +63 -0
  45. package/modules/release/keygen.mjs +18 -0
  46. package/modules/release/produce.mjs +9 -0
  47. package/modules/release/sign.mjs +44 -0
  48. package/modules/release/signature.mjs +336 -0
  49. package/modules/release/signing-cli.mjs +56 -0
  50. package/modules/release/signing-io.mjs +61 -0
  51. package/modules/release/signing-key.mjs +22 -0
  52. package/modules/release/statement.mjs +80 -0
  53. package/modules/release/vectors/generate.mjs +381 -0
  54. package/modules/release/vectors/release-signature-vectors.json +2305 -0
  55. package/modules/release/verify.mjs +27 -0
  56. package/onboarding/production-assets.mjs +23 -0
  57. package/onboarding/production-runtime.mjs +8 -4
  58. package/package.json +2 -1
  59. package/scripts/publish-check/README.md +27 -17
  60. package/scripts/publish-check/content_identities.py +14 -233
  61. package/scripts/publish-check/git_history.py +2 -2
  62. package/scripts/publish-check/gitleaks.toml +1 -1
  63. package/scripts/publish-check/history_scan.py +6 -4
  64. package/scripts/publish-check/hygiene_config.py +3 -1
  65. package/scripts/publish-check/public_hygiene.py +29 -5
  66. package/scripts/publish-check/publication-config.json +3 -1
  67. package/scripts/publish-check/source_metadata.py +62 -0
  68. package/scripts/publish-check/source_shapes.py +91 -0
  69. package/scripts/publish-check/tree_scan.py +2 -2
  70. package/scripts/publish-check/source_hashes.mjs +0 -6
@@ -1,6 +1,12 @@
1
1
  import { lstat, readdir, readFile } from 'node:fs/promises';
2
2
  import { join, posix } from 'node:path';
3
- import { refuse } from './errors.mjs';
3
+ import { createRequire } from 'node:module';
4
+ import { pathToFileURL } from 'node:url';
5
+ import { privateDataScanner, decodedText } from './site-data.mjs';
6
+ import { javascriptContent } from './site-references.mjs';
7
+ import { javascriptStrings } from './site-syntax.mjs';
8
+ import { markupReferences, markupStrings, htmlElements, cssStrings } from './site-markup.mjs';
9
+ import { refuse, RerError } from './errors.mjs';
4
10
  import { DEV_AI_MARKER, DEV_LAYER_MARKER } from './dev-identity.mjs';
5
11
 
6
12
  // What a run site may hold: static pages and the files they use, served as
@@ -32,6 +38,17 @@ async function files(folder) {
32
38
 
33
39
  const safeDecode = path => { try { return decodeURI(path); } catch { return path; } };
34
40
 
41
+ export function identityPattern(value) {
42
+ const escaped = value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
43
+ const word = '[\\p{L}\\p{M}\\p{N}_]', mailbox = value.includes('@');
44
+ const left = mailbox ? "[\\p{L}\\p{M}\\p{N}_.!#$%&'*+/=?^`{|}~@-]" : word;
45
+ const right = mailbox ? '[\\p{L}\\p{M}\\p{N}_@-]|\\.[\\p{L}\\p{M}\\p{N}_-]' : word;
46
+ // Paired prose quotes delimit the whole mailbox. An apostrophe inside a
47
+ // longer local part (prefix'owner@example.test) must keep its old boundary.
48
+ const quoted = mailbox ? `|(?<!\\\\)'${escaped}'` : '';
49
+ return {mailbox, pattern:new RegExp(`(?<!${left})(?:${escaped}(?!${right})${quoted})`,mailbox ? 'iu' : 'u')};
50
+ }
51
+
35
52
  /** How Cloudflare's static assets (auto-trailing-slash) answer a path, or null. */
36
53
  export function servedFile(names, pathname) {
37
54
  const path = pathname.replace(/^\/+/, '');
@@ -43,54 +60,52 @@ export function servedFile(names, pathname) {
43
60
  return null;
44
61
  }
45
62
 
46
- // href/src attributes, srcset candidates and CSS url() references.
47
- function references(text, html) {
48
- const found = [];
49
- if (html) {
50
- for (const match of text.matchAll(/<([a-z][a-z0-9-]*)\b([^>]*)>/gi)) {
51
- const [, tag, attributes] = match, rel = /\brel\s*=\s*["']?([^"'>]*)/i.exec(attributes)?.[1].toLowerCase() ?? '';
52
- for (const attribute of attributes.matchAll(/\b(href|src|srcset|action|poster|data)\s*=\s*(?:"([^"]*)"|'([^']*)')/gi)) {
53
- const name = attribute[1].toLowerCase(), value = (attribute[2] ?? attribute[3]).replace(/&amp;/g, '&');
54
- const values = name === 'srcset' ? value.split(',').map(part => part.trim().split(/\s+/)[0]).filter(Boolean) : [value];
55
- // Only a plain link or a page anchor navigates; everything else is fetched by the page.
56
- const navigates = name === 'href' && (tag.toLowerCase() === 'a' || tag.toLowerCase() === 'area' || (tag.toLowerCase() === 'link' && /\b(?:canonical|alternate|author|license|help|me)\b/.test(rel)));
57
- for (const url of values) found.push({ url, navigates });
58
- }
59
- }
60
- }
61
- for (const match of text.matchAll(/url\(\s*(?:"([^"]*)"|'([^']*)'|([^)\s]*))\s*\)/gi)) found.push({ url: match[1] ?? match[2] ?? match[3], navigates: false });
62
- return found;
63
- }
64
-
65
63
  /**
66
64
  * Refuse a run site folder that is not exactly static pages and the files they
67
65
  * use: an index and a Run page, every same-origin link resolving, no link to an
68
66
  * instance-only route, nothing fetched from another origin, no dev layer, and
69
67
  * none of the given private values (owner identity, secrets, the dev key).
70
68
  */
71
- export async function checkSite(folder, { privateValues = [] } = {}) {
69
+ export async function checkSite(folder, { privateValues = [], privateIdentities = [], root } = {}) {
72
70
  const all = await files(folder), names = new Set(all.keys());
73
71
  if (!names.has('index.html')) throw refuse('The run site has no index.html (its homepage).');
74
72
  if (!servedFile(names, '/run')) throw refuse('The run site has no /run page.');
75
73
  const markers = [DEV_LAYER_MARKER, DEV_AI_MARKER].map(value => Buffer.from(value));
76
- const secrets = privateValues.filter(value => typeof value === 'string' && value.length >= 6).map(value => Buffer.from(value));
77
- const problems = [];
74
+ const containsPrivateData = privateDataScanner(privateValues, privateIdentities);
75
+ let parse;
76
+ if (root) {
77
+ const require = createRequire(join(root, 'package.json'));
78
+ ({parseAst:parse} = await import(pathToFileURL(require.resolve('vite')).href));
79
+ }
80
+ const problems = [], unresolved = [];
78
81
  for (const [site, bytes] of all) {
79
82
  if (markers.some(marker => bytes.includes(marker))) throw refuse(`The run site file ${site} contains the local-only dev layer.`);
80
- if (secrets.some(secret => bytes.includes(secret))) throw refuse(`The run site file ${site} contains this installation's private data (owner identity or a secret). The run site renders only edition identity.`);
81
- const html = site.endsWith('.html'), css = site.endsWith('.css');
82
- if (!html && !css) continue;
83
- for (const { url, navigates } of references(bytes.toString('utf8'), html)) {
83
+ const html = /\.(?:html|svg)$/.test(site), css = site.endsWith('.css'), js = /\.[cm]?js$/.test(site);
84
+ const text = bytes.toString('utf8'), trees = js && parse ? [parse(text)] : [], literals = css ? cssStrings(text) : html ? markupStrings(text) : [];
85
+ if (html) for (const {tag, attributes, content} of htmlElements(text)) {
86
+ if (tag === 'script' && !attributes.has('src') && parse && /^(?:|module|(?:text|application)\/(?:java|ecma)script)$/i.test(attributes.get('type') ?? '')) trees.push(parse(content));
87
+ }
88
+ const scripts = trees.map(javascriptContent), strings = trees.flatMap(javascriptStrings);
89
+ if (containsPrivateData(bytes, [...literals, ...strings, ...strings.flatMap(markupStrings), ...scripts.flatMap(script => script.literals)])) throw new RerError('site_private_data', `The run site file ${site} contains this installation's private data (owner identity or a secret). The run site renders only edition identity.`, 4);
90
+ if (!html && !css && !js) continue;
91
+ const refs = [...(js ? [] : markupReferences(text, html)), ...scripts.flatMap(script => script.references)];
92
+ for (const script of scripts) for (const {kind} of script.unresolved) unresolved.push({asset:site, kind});
93
+ for (const reference of refs) {
94
+ const url = decodedText(reference.url), {navigates} = reference;
84
95
  if (!url || /^(?:#|mailto:|tel:|data:|javascript:void)/i.test(url)) continue;
85
96
  if (/^(?:[a-z][a-z0-9+.-]*:|\/\/)/i.test(url)) {
86
97
  if (!navigates) problems.push(`${site} fetches ${url} from another origin`);
87
98
  continue;
88
99
  }
89
- const pathname = posix.resolve('/' + posix.dirname(site), url.replace(/[?#].*$/, ''));
90
- if (INSTANCE_ROUTES.some(route => pathname === route || pathname.startsWith(route + '/'))) problems.push(`${site} links to ${pathname}, which exists only on an installed instance`);
91
- else if (!servedFile(names, safeDecode(pathname))) problems.push(`${site} links to ${pathname}, which the site does not have`);
100
+ const pathPrefix = safeDecode(url.replace(/[?#].*$/, ''));
101
+ const pathname = posix.resolve(reference.documentRelative ? '/' : '/' + posix.dirname(site), pathPrefix);
102
+ // An unfinished `/api` could become `/apiculture`; a slash, query or
103
+ // fragment already fixes the instance path even when its tail is runtime.
104
+ const boundary = !reference.dynamic || /[?#]/.test(url) || pathPrefix.endsWith('/');
105
+ if (INSTANCE_ROUTES.some(route => (pathname === route && boundary) || pathname.startsWith(route + '/'))) problems.push(`${site} links to ${pathname}, which exists only on an installed instance`);
106
+ else if (!reference.dynamic && !servedFile(names, safeDecode(pathname))) problems.push(`${site} links to ${pathname}, which the site does not have`);
92
107
  }
93
108
  }
94
109
  if (problems.length) throw refuse(`The run site has broken or out-of-site references: ${problems.slice(0, 8).join('; ')}${problems.length > 8 ? `; and ${problems.length - 8} more` : ''}.`);
95
- return { files: names.size, pages: [...names].filter(name => name.endsWith('.html')).length };
110
+ return { files: names.size, pages: [...names].filter(name => name.endsWith('.html')).length, references:{unresolved} };
96
111
  }
@@ -0,0 +1,50 @@
1
+ import { mkdir, writeFile, readFile, rm } from 'node:fs/promises';
2
+ import { dirname, join, resolve } from 'node:path';
3
+ import { clientInputGuard } from './site-inputs.mjs';
4
+
5
+ // A separate browser build, using the seed's plugins. Only the graph reachable
6
+ // from its named entries ships; an external server import in that graph fails.
7
+ export async function writeSiteAsset(folder, name, data) {
8
+ if (!name.startsWith('site-assets/') || name.split('/').includes('..')) throw Error('Compiled output must stay under site-assets/.');
9
+ const file = join(folder,name), bytes = Buffer.from(data);
10
+ await mkdir(dirname(file),{recursive:true});
11
+ try { await writeFile(file,bytes,{flag:'wx'}); }
12
+ catch (error) {
13
+ if (error.code !== 'EEXIST') throw error;
14
+ if (!bytes.equals(await readFile(file))) throw Error(`Conflicting compiled site asset ${name}.`);
15
+ }
16
+ }
17
+
18
+ export async function buildClients(vite, root, folder, { entries = {}, config, privatePaths = [] } = {}) {
19
+ if (!Object.keys(entries).length) return {clients:{},styles:[]};
20
+ const guard = await clientInputGuard(root, privatePaths, async code => {
21
+ await writeFile(`${folder}.refusal`, code);
22
+ throw Error(code === 'site_private_input' ? 'Run site client imports a private or outside-seed file.' : 'Run site client imports a server-only module.');
23
+ }, vite);
24
+ const scratch = `${folder}.client`;
25
+ try {
26
+ const built = await vite.build({root, plugins:[guard], configFile:config ? resolve(root,config) : false, envFile:false, logLevel:'error', mode:'production',
27
+ build:{ssr:false, lib:false, outDir:scratch, write:false, copyPublicDir:false, emptyOutDir:true, assetsDir:'site-assets', sourcemap:false, reportCompressedSize:false, watch:null,
28
+ rollupOptions:{input:Object.fromEntries(Object.entries(entries).map(([name,path]) => [name,resolve(root,path)])), output:{entryFileNames:'site-assets/[name]-[hash].js',chunkFileNames:'site-assets/[name]-[hash].js'}}}});
29
+ const output = (Array.isArray(built) ? built : [built]).flatMap(result => result.output ?? []);
30
+ const chunks = new Map(output.filter(item => item.type === 'chunk').map(item => [item.fileName,item]));
31
+ const clients = {}, shipped = new Set();
32
+ const visit = file => {
33
+ if (shipped.has(file)) return;
34
+ const chunk = chunks.get(file);
35
+ if (!chunk) throw Error(`Run site client imports ${file}, which is not bundled for the browser. Remove its server dependency or bundle it in the client config.`);
36
+ shipped.add(file);
37
+ for (const dependency of [...chunk.imports,...chunk.dynamicImports]) visit(dependency);
38
+ };
39
+ for (const name of Object.keys(entries)) {
40
+ const entry = output.find(item => item.type === 'chunk' && item.isEntry && item.name === name);
41
+ if (!entry) throw Error(`Run site client ${name} produced no entry chunk.`);
42
+ clients[name] = '/' + entry.fileName; visit(entry.fileName);
43
+ }
44
+ for (const item of output) {
45
+ if (item.type === 'chunk' && !shipped.has(item.fileName)) continue;
46
+ await writeSiteAsset(folder,item.fileName,item.type === 'chunk' ? item.code : item.source);
47
+ }
48
+ return {clients,styles:output.filter(item=>item.type==='asset'&&item.fileName.endsWith('.css')).map(item=>'/' + item.fileName)};
49
+ } finally { await rm(scratch,{recursive:true,force:true}); }
50
+ }
@@ -0,0 +1,54 @@
1
+ import { identityPattern } from './site-check.mjs';
2
+
3
+ // HTML Living Standard named character references (Python html.entities.html5).
4
+ import entities from './site-entities.json' with {type:'json'};
5
+ const numericReplacements = {128:8364,130:8218,131:402,132:8222,133:8230,134:8224,135:8225,136:710,137:8240,138:352,139:8249,140:338,142:381,145:8216,146:8217,147:8220,148:8221,149:8226,150:8211,151:8212,152:732,153:8482,154:353,155:8250,156:339,158:382,159:376};
6
+ export function decodedText(text) {
7
+ return text.replace(/&#(?:x([\da-f]+)|(\d+));?|&([a-z][a-z0-9]*;?)/gi, (match, hex, decimal, name) => {
8
+ if (name) {
9
+ for (let length = name.length; length; length--) if (entities[name.slice(0,length)] !== undefined) return entities[name.slice(0,length)] + name.slice(length);
10
+ return match;
11
+ }
12
+ const code = parseInt(hex ?? decimal, hex ? 16 : 10);
13
+ return String.fromCodePoint(numericReplacements[code] ?? (!code || code > 0x10ffff || (code >= 0xd800 && code <= 0xdfff) ? 0xfffd : code));
14
+ }).replace(/(?:%[\da-f]{2})+/gi, value => {try {return decodeURIComponent(value);} catch {return value;}})
15
+ .replace(/\\(?:x([\da-f]{2})|u([\da-f]{4})|u\{([\da-f]+)\})/gi, (match, hex, unicode, point) => {
16
+ const code = parseInt(hex ?? unicode ?? point,16); return code <= 0x10ffff ? String.fromCodePoint(code) : match;
17
+ });
18
+ }
19
+
20
+ // Scan every emitted file, including binary assets. Decode textual forms as well
21
+ // as matching base64 directly, so encoding a registered value cannot publish it.
22
+ export function privateDataScanner(values, identities) {
23
+ const secrets = values.filter(value => typeof value === 'string' && value.length);
24
+ const owners = identities.filter(value => typeof value === 'string' && value.length).map(value => ({value, ...identityPattern(value)}));
25
+ const encodedValues = [...secrets, ...owners.map(item => item.value)].flatMap(value => [Buffer.from(value).toString('base64'), Buffer.from(value).toString('base64').replace(/=+$/, ''), Buffer.from(value).toString('base64url')]);
26
+ const base64 = encodedValues.map(value => new RegExp(`(?<![A-Za-z0-9+/_-])${value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}(?![A-Za-z0-9+/_=-])`));
27
+ return (bytes, literalValues = []) => {
28
+ if (secrets.some(value => bytes.includes(Buffer.from(value)))) return true;
29
+ const raw = bytes.toString('utf8');
30
+ const forms = new Set([raw, ...literalValues]);
31
+ for (const value of [raw, ...literalValues]) {
32
+ let decoded = value;
33
+ for (let depth = 0; depth < 4; depth++) { decoded = decodedText(decoded); forms.add(decoded); }
34
+ }
35
+
36
+ for (const form of forms) {
37
+ // Complete string values preserve the whitespace that atob accepts, even
38
+ // when the payload spans lines or carries encoded whitespace.
39
+ const compact = form.replace(/[\t\n\f\r ]/g, '');
40
+ if (/^[A-Za-z0-9+/_-]{8,}={0,2}$/.test(compact) && compact.length % 4 !== 1) {
41
+ const plain = Buffer.from(compact, 'base64').toString('utf8');
42
+ forms.add(plain); forms.add(decodedText(plain));
43
+ }
44
+ if (secrets.some(value => form.includes(value)) || owners.some(({pattern}) => pattern.test(form))) return true;
45
+ if (base64.some(pattern => pattern.test(form))) return true;
46
+ // A base64 payload may include surrounding text, changing its alignment.
47
+ for (const match of form.matchAll(/[A-Za-z0-9+/_-]{8,}={0,2}/g)) {
48
+ const plain = Buffer.from(match[0], 'base64').toString('utf8');
49
+ if (secrets.some(value => plain.includes(value)) || owners.some(({pattern}) => pattern.test(plain))) return true;
50
+ }
51
+ }
52
+ return false;
53
+ };
54
+ }
@@ -0,0 +1 @@
1
+ {"AElig":"\u00c6","AElig;":"\u00c6","AMP":"&","AMP;":"&","Aacute":"\u00c1","Aacute;":"\u00c1","Abreve;":"\u0102","Acirc":"\u00c2","Acirc;":"\u00c2","Acy;":"\u0410","Afr;":"\ud835\udd04","Agrave":"\u00c0","Agrave;":"\u00c0","Alpha;":"\u0391","Amacr;":"\u0100","And;":"\u2a53","Aogon;":"\u0104","Aopf;":"\ud835\udd38","ApplyFunction;":"\u2061","Aring":"\u00c5","Aring;":"\u00c5","Ascr;":"\ud835\udc9c","Assign;":"\u2254","Atilde":"\u00c3","Atilde;":"\u00c3","Auml":"\u00c4","Auml;":"\u00c4","Backslash;":"\u2216","Barv;":"\u2ae7","Barwed;":"\u2306","Bcy;":"\u0411","Because;":"\u2235","Bernoullis;":"\u212c","Beta;":"\u0392","Bfr;":"\ud835\udd05","Bopf;":"\ud835\udd39","Breve;":"\u02d8","Bscr;":"\u212c","Bumpeq;":"\u224e","CHcy;":"\u0427","COPY":"\u00a9","COPY;":"\u00a9","Cacute;":"\u0106","Cap;":"\u22d2","CapitalDifferentialD;":"\u2145","Cayleys;":"\u212d","Ccaron;":"\u010c","Ccedil":"\u00c7","Ccedil;":"\u00c7","Ccirc;":"\u0108","Cconint;":"\u2230","Cdot;":"\u010a","Cedilla;":"\u00b8","CenterDot;":"\u00b7","Cfr;":"\u212d","Chi;":"\u03a7","CircleDot;":"\u2299","CircleMinus;":"\u2296","CirclePlus;":"\u2295","CircleTimes;":"\u2297","ClockwiseContourIntegral;":"\u2232","CloseCurlyDoubleQuote;":"\u201d","CloseCurlyQuote;":"\u2019","Colon;":"\u2237","Colone;":"\u2a74","Congruent;":"\u2261","Conint;":"\u222f","ContourIntegral;":"\u222e","Copf;":"\u2102","Coproduct;":"\u2210","CounterClockwiseContourIntegral;":"\u2233","Cross;":"\u2a2f","Cscr;":"\ud835\udc9e","Cup;":"\u22d3","CupCap;":"\u224d","DD;":"\u2145","DDotrahd;":"\u2911","DJcy;":"\u0402","DScy;":"\u0405","DZcy;":"\u040f","Dagger;":"\u2021","Darr;":"\u21a1","Dashv;":"\u2ae4","Dcaron;":"\u010e","Dcy;":"\u0414","Del;":"\u2207","Delta;":"\u0394","Dfr;":"\ud835\udd07","DiacriticalAcute;":"\u00b4","DiacriticalDot;":"\u02d9","DiacriticalDoubleAcute;":"\u02dd","DiacriticalGrave;":"`","DiacriticalTilde;":"\u02dc","Diamond;":"\u22c4","DifferentialD;":"\u2146","Dopf;":"\ud835\udd3b","Dot;":"\u00a8","DotDot;":"\u20dc","DotEqual;":"\u2250","DoubleContourIntegral;":"\u222f","DoubleDot;":"\u00a8","DoubleDownArrow;":"\u21d3","DoubleLeftArrow;":"\u21d0","DoubleLeftRightArrow;":"\u21d4","DoubleLeftTee;":"\u2ae4","DoubleLongLeftArrow;":"\u27f8","DoubleLongLeftRightArrow;":"\u27fa","DoubleLongRightArrow;":"\u27f9","DoubleRightArrow;":"\u21d2","DoubleRightTee;":"\u22a8","DoubleUpArrow;":"\u21d1","DoubleUpDownArrow;":"\u21d5","DoubleVerticalBar;":"\u2225","DownArrow;":"\u2193","DownArrowBar;":"\u2913","DownArrowUpArrow;":"\u21f5","DownBreve;":"\u0311","DownLeftRightVector;":"\u2950","DownLeftTeeVector;":"\u295e","DownLeftVector;":"\u21bd","DownLeftVectorBar;":"\u2956","DownRightTeeVector;":"\u295f","DownRightVector;":"\u21c1","DownRightVectorBar;":"\u2957","DownTee;":"\u22a4","DownTeeArrow;":"\u21a7","Downarrow;":"\u21d3","Dscr;":"\ud835\udc9f","Dstrok;":"\u0110","ENG;":"\u014a","ETH":"\u00d0","ETH;":"\u00d0","Eacute":"\u00c9","Eacute;":"\u00c9","Ecaron;":"\u011a","Ecirc":"\u00ca","Ecirc;":"\u00ca","Ecy;":"\u042d","Edot;":"\u0116","Efr;":"\ud835\udd08","Egrave":"\u00c8","Egrave;":"\u00c8","Element;":"\u2208","Emacr;":"\u0112","EmptySmallSquare;":"\u25fb","EmptyVerySmallSquare;":"\u25ab","Eogon;":"\u0118","Eopf;":"\ud835\udd3c","Epsilon;":"\u0395","Equal;":"\u2a75","EqualTilde;":"\u2242","Equilibrium;":"\u21cc","Escr;":"\u2130","Esim;":"\u2a73","Eta;":"\u0397","Euml":"\u00cb","Euml;":"\u00cb","Exists;":"\u2203","ExponentialE;":"\u2147","Fcy;":"\u0424","Ffr;":"\ud835\udd09","FilledSmallSquare;":"\u25fc","FilledVerySmallSquare;":"\u25aa","Fopf;":"\ud835\udd3d","ForAll;":"\u2200","Fouriertrf;":"\u2131","Fscr;":"\u2131","GJcy;":"\u0403","GT":">","GT;":">","Gamma;":"\u0393","Gammad;":"\u03dc","Gbreve;":"\u011e","Gcedil;":"\u0122","Gcirc;":"\u011c","Gcy;":"\u0413","Gdot;":"\u0120","Gfr;":"\ud835\udd0a","Gg;":"\u22d9","Gopf;":"\ud835\udd3e","GreaterEqual;":"\u2265","GreaterEqualLess;":"\u22db","GreaterFullEqual;":"\u2267","GreaterGreater;":"\u2aa2","GreaterLess;":"\u2277","GreaterSlantEqual;":"\u2a7e","GreaterTilde;":"\u2273","Gscr;":"\ud835\udca2","Gt;":"\u226b","HARDcy;":"\u042a","Hacek;":"\u02c7","Hat;":"^","Hcirc;":"\u0124","Hfr;":"\u210c","HilbertSpace;":"\u210b","Hopf;":"\u210d","HorizontalLine;":"\u2500","Hscr;":"\u210b","Hstrok;":"\u0126","HumpDownHump;":"\u224e","HumpEqual;":"\u224f","IEcy;":"\u0415","IJlig;":"\u0132","IOcy;":"\u0401","Iacute":"\u00cd","Iacute;":"\u00cd","Icirc":"\u00ce","Icirc;":"\u00ce","Icy;":"\u0418","Idot;":"\u0130","Ifr;":"\u2111","Igrave":"\u00cc","Igrave;":"\u00cc","Im;":"\u2111","Imacr;":"\u012a","ImaginaryI;":"\u2148","Implies;":"\u21d2","Int;":"\u222c","Integral;":"\u222b","Intersection;":"\u22c2","InvisibleComma;":"\u2063","InvisibleTimes;":"\u2062","Iogon;":"\u012e","Iopf;":"\ud835\udd40","Iota;":"\u0399","Iscr;":"\u2110","Itilde;":"\u0128","Iukcy;":"\u0406","Iuml":"\u00cf","Iuml;":"\u00cf","Jcirc;":"\u0134","Jcy;":"\u0419","Jfr;":"\ud835\udd0d","Jopf;":"\ud835\udd41","Jscr;":"\ud835\udca5","Jsercy;":"\u0408","Jukcy;":"\u0404","KHcy;":"\u0425","KJcy;":"\u040c","Kappa;":"\u039a","Kcedil;":"\u0136","Kcy;":"\u041a","Kfr;":"\ud835\udd0e","Kopf;":"\ud835\udd42","Kscr;":"\ud835\udca6","LJcy;":"\u0409","LT":"<","LT;":"<","Lacute;":"\u0139","Lambda;":"\u039b","Lang;":"\u27ea","Laplacetrf;":"\u2112","Larr;":"\u219e","Lcaron;":"\u013d","Lcedil;":"\u013b","Lcy;":"\u041b","LeftAngleBracket;":"\u27e8","LeftArrow;":"\u2190","LeftArrowBar;":"\u21e4","LeftArrowRightArrow;":"\u21c6","LeftCeiling;":"\u2308","LeftDoubleBracket;":"\u27e6","LeftDownTeeVector;":"\u2961","LeftDownVector;":"\u21c3","LeftDownVectorBar;":"\u2959","LeftFloor;":"\u230a","LeftRightArrow;":"\u2194","LeftRightVector;":"\u294e","LeftTee;":"\u22a3","LeftTeeArrow;":"\u21a4","LeftTeeVector;":"\u295a","LeftTriangle;":"\u22b2","LeftTriangleBar;":"\u29cf","LeftTriangleEqual;":"\u22b4","LeftUpDownVector;":"\u2951","LeftUpTeeVector;":"\u2960","LeftUpVector;":"\u21bf","LeftUpVectorBar;":"\u2958","LeftVector;":"\u21bc","LeftVectorBar;":"\u2952","Leftarrow;":"\u21d0","Leftrightarrow;":"\u21d4","LessEqualGreater;":"\u22da","LessFullEqual;":"\u2266","LessGreater;":"\u2276","LessLess;":"\u2aa1","LessSlantEqual;":"\u2a7d","LessTilde;":"\u2272","Lfr;":"\ud835\udd0f","Ll;":"\u22d8","Lleftarrow;":"\u21da","Lmidot;":"\u013f","LongLeftArrow;":"\u27f5","LongLeftRightArrow;":"\u27f7","LongRightArrow;":"\u27f6","Longleftarrow;":"\u27f8","Longleftrightarrow;":"\u27fa","Longrightarrow;":"\u27f9","Lopf;":"\ud835\udd43","LowerLeftArrow;":"\u2199","LowerRightArrow;":"\u2198","Lscr;":"\u2112","Lsh;":"\u21b0","Lstrok;":"\u0141","Lt;":"\u226a","Map;":"\u2905","Mcy;":"\u041c","MediumSpace;":"\u205f","Mellintrf;":"\u2133","Mfr;":"\ud835\udd10","MinusPlus;":"\u2213","Mopf;":"\ud835\udd44","Mscr;":"\u2133","Mu;":"\u039c","NJcy;":"\u040a","Nacute;":"\u0143","Ncaron;":"\u0147","Ncedil;":"\u0145","Ncy;":"\u041d","NegativeMediumSpace;":"\u200b","NegativeThickSpace;":"\u200b","NegativeThinSpace;":"\u200b","NegativeVeryThinSpace;":"\u200b","NestedGreaterGreater;":"\u226b","NestedLessLess;":"\u226a","NewLine;":"\n","Nfr;":"\ud835\udd11","NoBreak;":"\u2060","NonBreakingSpace;":"\u00a0","Nopf;":"\u2115","Not;":"\u2aec","NotCongruent;":"\u2262","NotCupCap;":"\u226d","NotDoubleVerticalBar;":"\u2226","NotElement;":"\u2209","NotEqual;":"\u2260","NotEqualTilde;":"\u2242\u0338","NotExists;":"\u2204","NotGreater;":"\u226f","NotGreaterEqual;":"\u2271","NotGreaterFullEqual;":"\u2267\u0338","NotGreaterGreater;":"\u226b\u0338","NotGreaterLess;":"\u2279","NotGreaterSlantEqual;":"\u2a7e\u0338","NotGreaterTilde;":"\u2275","NotHumpDownHump;":"\u224e\u0338","NotHumpEqual;":"\u224f\u0338","NotLeftTriangle;":"\u22ea","NotLeftTriangleBar;":"\u29cf\u0338","NotLeftTriangleEqual;":"\u22ec","NotLess;":"\u226e","NotLessEqual;":"\u2270","NotLessGreater;":"\u2278","NotLessLess;":"\u226a\u0338","NotLessSlantEqual;":"\u2a7d\u0338","NotLessTilde;":"\u2274","NotNestedGreaterGreater;":"\u2aa2\u0338","NotNestedLessLess;":"\u2aa1\u0338","NotPrecedes;":"\u2280","NotPrecedesEqual;":"\u2aaf\u0338","NotPrecedesSlantEqual;":"\u22e0","NotReverseElement;":"\u220c","NotRightTriangle;":"\u22eb","NotRightTriangleBar;":"\u29d0\u0338","NotRightTriangleEqual;":"\u22ed","NotSquareSubset;":"\u228f\u0338","NotSquareSubsetEqual;":"\u22e2","NotSquareSuperset;":"\u2290\u0338","NotSquareSupersetEqual;":"\u22e3","NotSubset;":"\u2282\u20d2","NotSubsetEqual;":"\u2288","NotSucceeds;":"\u2281","NotSucceedsEqual;":"\u2ab0\u0338","NotSucceedsSlantEqual;":"\u22e1","NotSucceedsTilde;":"\u227f\u0338","NotSuperset;":"\u2283\u20d2","NotSupersetEqual;":"\u2289","NotTilde;":"\u2241","NotTildeEqual;":"\u2244","NotTildeFullEqual;":"\u2247","NotTildeTilde;":"\u2249","NotVerticalBar;":"\u2224","Nscr;":"\ud835\udca9","Ntilde":"\u00d1","Ntilde;":"\u00d1","Nu;":"\u039d","OElig;":"\u0152","Oacute":"\u00d3","Oacute;":"\u00d3","Ocirc":"\u00d4","Ocirc;":"\u00d4","Ocy;":"\u041e","Odblac;":"\u0150","Ofr;":"\ud835\udd12","Ograve":"\u00d2","Ograve;":"\u00d2","Omacr;":"\u014c","Omega;":"\u03a9","Omicron;":"\u039f","Oopf;":"\ud835\udd46","OpenCurlyDoubleQuote;":"\u201c","OpenCurlyQuote;":"\u2018","Or;":"\u2a54","Oscr;":"\ud835\udcaa","Oslash":"\u00d8","Oslash;":"\u00d8","Otilde":"\u00d5","Otilde;":"\u00d5","Otimes;":"\u2a37","Ouml":"\u00d6","Ouml;":"\u00d6","OverBar;":"\u203e","OverBrace;":"\u23de","OverBracket;":"\u23b4","OverParenthesis;":"\u23dc","PartialD;":"\u2202","Pcy;":"\u041f","Pfr;":"\ud835\udd13","Phi;":"\u03a6","Pi;":"\u03a0","PlusMinus;":"\u00b1","Poincareplane;":"\u210c","Popf;":"\u2119","Pr;":"\u2abb","Precedes;":"\u227a","PrecedesEqual;":"\u2aaf","PrecedesSlantEqual;":"\u227c","PrecedesTilde;":"\u227e","Prime;":"\u2033","Product;":"\u220f","Proportion;":"\u2237","Proportional;":"\u221d","Pscr;":"\ud835\udcab","Psi;":"\u03a8","QUOT":"\"","QUOT;":"\"","Qfr;":"\ud835\udd14","Qopf;":"\u211a","Qscr;":"\ud835\udcac","RBarr;":"\u2910","REG":"\u00ae","REG;":"\u00ae","Racute;":"\u0154","Rang;":"\u27eb","Rarr;":"\u21a0","Rarrtl;":"\u2916","Rcaron;":"\u0158","Rcedil;":"\u0156","Rcy;":"\u0420","Re;":"\u211c","ReverseElement;":"\u220b","ReverseEquilibrium;":"\u21cb","ReverseUpEquilibrium;":"\u296f","Rfr;":"\u211c","Rho;":"\u03a1","RightAngleBracket;":"\u27e9","RightArrow;":"\u2192","RightArrowBar;":"\u21e5","RightArrowLeftArrow;":"\u21c4","RightCeiling;":"\u2309","RightDoubleBracket;":"\u27e7","RightDownTeeVector;":"\u295d","RightDownVector;":"\u21c2","RightDownVectorBar;":"\u2955","RightFloor;":"\u230b","RightTee;":"\u22a2","RightTeeArrow;":"\u21a6","RightTeeVector;":"\u295b","RightTriangle;":"\u22b3","RightTriangleBar;":"\u29d0","RightTriangleEqual;":"\u22b5","RightUpDownVector;":"\u294f","RightUpTeeVector;":"\u295c","RightUpVector;":"\u21be","RightUpVectorBar;":"\u2954","RightVector;":"\u21c0","RightVectorBar;":"\u2953","Rightarrow;":"\u21d2","Ropf;":"\u211d","RoundImplies;":"\u2970","Rrightarrow;":"\u21db","Rscr;":"\u211b","Rsh;":"\u21b1","RuleDelayed;":"\u29f4","SHCHcy;":"\u0429","SHcy;":"\u0428","SOFTcy;":"\u042c","Sacute;":"\u015a","Sc;":"\u2abc","Scaron;":"\u0160","Scedil;":"\u015e","Scirc;":"\u015c","Scy;":"\u0421","Sfr;":"\ud835\udd16","ShortDownArrow;":"\u2193","ShortLeftArrow;":"\u2190","ShortRightArrow;":"\u2192","ShortUpArrow;":"\u2191","Sigma;":"\u03a3","SmallCircle;":"\u2218","Sopf;":"\ud835\udd4a","Sqrt;":"\u221a","Square;":"\u25a1","SquareIntersection;":"\u2293","SquareSubset;":"\u228f","SquareSubsetEqual;":"\u2291","SquareSuperset;":"\u2290","SquareSupersetEqual;":"\u2292","SquareUnion;":"\u2294","Sscr;":"\ud835\udcae","Star;":"\u22c6","Sub;":"\u22d0","Subset;":"\u22d0","SubsetEqual;":"\u2286","Succeeds;":"\u227b","SucceedsEqual;":"\u2ab0","SucceedsSlantEqual;":"\u227d","SucceedsTilde;":"\u227f","SuchThat;":"\u220b","Sum;":"\u2211","Sup;":"\u22d1","Superset;":"\u2283","SupersetEqual;":"\u2287","Supset;":"\u22d1","THORN":"\u00de","THORN;":"\u00de","TRADE;":"\u2122","TSHcy;":"\u040b","TScy;":"\u0426","Tab;":"\t","Tau;":"\u03a4","Tcaron;":"\u0164","Tcedil;":"\u0162","Tcy;":"\u0422","Tfr;":"\ud835\udd17","Therefore;":"\u2234","Theta;":"\u0398","ThickSpace;":"\u205f\u200a","ThinSpace;":"\u2009","Tilde;":"\u223c","TildeEqual;":"\u2243","TildeFullEqual;":"\u2245","TildeTilde;":"\u2248","Topf;":"\ud835\udd4b","TripleDot;":"\u20db","Tscr;":"\ud835\udcaf","Tstrok;":"\u0166","Uacute":"\u00da","Uacute;":"\u00da","Uarr;":"\u219f","Uarrocir;":"\u2949","Ubrcy;":"\u040e","Ubreve;":"\u016c","Ucirc":"\u00db","Ucirc;":"\u00db","Ucy;":"\u0423","Udblac;":"\u0170","Ufr;":"\ud835\udd18","Ugrave":"\u00d9","Ugrave;":"\u00d9","Umacr;":"\u016a","UnderBar;":"_","UnderBrace;":"\u23df","UnderBracket;":"\u23b5","UnderParenthesis;":"\u23dd","Union;":"\u22c3","UnionPlus;":"\u228e","Uogon;":"\u0172","Uopf;":"\ud835\udd4c","UpArrow;":"\u2191","UpArrowBar;":"\u2912","UpArrowDownArrow;":"\u21c5","UpDownArrow;":"\u2195","UpEquilibrium;":"\u296e","UpTee;":"\u22a5","UpTeeArrow;":"\u21a5","Uparrow;":"\u21d1","Updownarrow;":"\u21d5","UpperLeftArrow;":"\u2196","UpperRightArrow;":"\u2197","Upsi;":"\u03d2","Upsilon;":"\u03a5","Uring;":"\u016e","Uscr;":"\ud835\udcb0","Utilde;":"\u0168","Uuml":"\u00dc","Uuml;":"\u00dc","VDash;":"\u22ab","Vbar;":"\u2aeb","Vcy;":"\u0412","Vdash;":"\u22a9","Vdashl;":"\u2ae6","Vee;":"\u22c1","Verbar;":"\u2016","Vert;":"\u2016","VerticalBar;":"\u2223","VerticalLine;":"|","VerticalSeparator;":"\u2758","VerticalTilde;":"\u2240","VeryThinSpace;":"\u200a","Vfr;":"\ud835\udd19","Vopf;":"\ud835\udd4d","Vscr;":"\ud835\udcb1","Vvdash;":"\u22aa","Wcirc;":"\u0174","Wedge;":"\u22c0","Wfr;":"\ud835\udd1a","Wopf;":"\ud835\udd4e","Wscr;":"\ud835\udcb2","Xfr;":"\ud835\udd1b","Xi;":"\u039e","Xopf;":"\ud835\udd4f","Xscr;":"\ud835\udcb3","YAcy;":"\u042f","YIcy;":"\u0407","YUcy;":"\u042e","Yacute":"\u00dd","Yacute;":"\u00dd","Ycirc;":"\u0176","Ycy;":"\u042b","Yfr;":"\ud835\udd1c","Yopf;":"\ud835\udd50","Yscr;":"\ud835\udcb4","Yuml;":"\u0178","ZHcy;":"\u0416","Zacute;":"\u0179","Zcaron;":"\u017d","Zcy;":"\u0417","Zdot;":"\u017b","ZeroWidthSpace;":"\u200b","Zeta;":"\u0396","Zfr;":"\u2128","Zopf;":"\u2124","Zscr;":"\ud835\udcb5","aacute":"\u00e1","aacute;":"\u00e1","abreve;":"\u0103","ac;":"\u223e","acE;":"\u223e\u0333","acd;":"\u223f","acirc":"\u00e2","acirc;":"\u00e2","acute":"\u00b4","acute;":"\u00b4","acy;":"\u0430","aelig":"\u00e6","aelig;":"\u00e6","af;":"\u2061","afr;":"\ud835\udd1e","agrave":"\u00e0","agrave;":"\u00e0","alefsym;":"\u2135","aleph;":"\u2135","alpha;":"\u03b1","amacr;":"\u0101","amalg;":"\u2a3f","amp":"&","amp;":"&","and;":"\u2227","andand;":"\u2a55","andd;":"\u2a5c","andslope;":"\u2a58","andv;":"\u2a5a","ang;":"\u2220","ange;":"\u29a4","angle;":"\u2220","angmsd;":"\u2221","angmsdaa;":"\u29a8","angmsdab;":"\u29a9","angmsdac;":"\u29aa","angmsdad;":"\u29ab","angmsdae;":"\u29ac","angmsdaf;":"\u29ad","angmsdag;":"\u29ae","angmsdah;":"\u29af","angrt;":"\u221f","angrtvb;":"\u22be","angrtvbd;":"\u299d","angsph;":"\u2222","angst;":"\u00c5","angzarr;":"\u237c","aogon;":"\u0105","aopf;":"\ud835\udd52","ap;":"\u2248","apE;":"\u2a70","apacir;":"\u2a6f","ape;":"\u224a","apid;":"\u224b","apos;":"'","approx;":"\u2248","approxeq;":"\u224a","aring":"\u00e5","aring;":"\u00e5","ascr;":"\ud835\udcb6","ast;":"*","asymp;":"\u2248","asympeq;":"\u224d","atilde":"\u00e3","atilde;":"\u00e3","auml":"\u00e4","auml;":"\u00e4","awconint;":"\u2233","awint;":"\u2a11","bNot;":"\u2aed","backcong;":"\u224c","backepsilon;":"\u03f6","backprime;":"\u2035","backsim;":"\u223d","backsimeq;":"\u22cd","barvee;":"\u22bd","barwed;":"\u2305","barwedge;":"\u2305","bbrk;":"\u23b5","bbrktbrk;":"\u23b6","bcong;":"\u224c","bcy;":"\u0431","bdquo;":"\u201e","becaus;":"\u2235","because;":"\u2235","bemptyv;":"\u29b0","bepsi;":"\u03f6","bernou;":"\u212c","beta;":"\u03b2","beth;":"\u2136","between;":"\u226c","bfr;":"\ud835\udd1f","bigcap;":"\u22c2","bigcirc;":"\u25ef","bigcup;":"\u22c3","bigodot;":"\u2a00","bigoplus;":"\u2a01","bigotimes;":"\u2a02","bigsqcup;":"\u2a06","bigstar;":"\u2605","bigtriangledown;":"\u25bd","bigtriangleup;":"\u25b3","biguplus;":"\u2a04","bigvee;":"\u22c1","bigwedge;":"\u22c0","bkarow;":"\u290d","blacklozenge;":"\u29eb","blacksquare;":"\u25aa","blacktriangle;":"\u25b4","blacktriangledown;":"\u25be","blacktriangleleft;":"\u25c2","blacktriangleright;":"\u25b8","blank;":"\u2423","blk12;":"\u2592","blk14;":"\u2591","blk34;":"\u2593","block;":"\u2588","bne;":"=\u20e5","bnequiv;":"\u2261\u20e5","bnot;":"\u2310","bopf;":"\ud835\udd53","bot;":"\u22a5","bottom;":"\u22a5","bowtie;":"\u22c8","boxDL;":"\u2557","boxDR;":"\u2554","boxDl;":"\u2556","boxDr;":"\u2553","boxH;":"\u2550","boxHD;":"\u2566","boxHU;":"\u2569","boxHd;":"\u2564","boxHu;":"\u2567","boxUL;":"\u255d","boxUR;":"\u255a","boxUl;":"\u255c","boxUr;":"\u2559","boxV;":"\u2551","boxVH;":"\u256c","boxVL;":"\u2563","boxVR;":"\u2560","boxVh;":"\u256b","boxVl;":"\u2562","boxVr;":"\u255f","boxbox;":"\u29c9","boxdL;":"\u2555","boxdR;":"\u2552","boxdl;":"\u2510","boxdr;":"\u250c","boxh;":"\u2500","boxhD;":"\u2565","boxhU;":"\u2568","boxhd;":"\u252c","boxhu;":"\u2534","boxminus;":"\u229f","boxplus;":"\u229e","boxtimes;":"\u22a0","boxuL;":"\u255b","boxuR;":"\u2558","boxul;":"\u2518","boxur;":"\u2514","boxv;":"\u2502","boxvH;":"\u256a","boxvL;":"\u2561","boxvR;":"\u255e","boxvh;":"\u253c","boxvl;":"\u2524","boxvr;":"\u251c","bprime;":"\u2035","breve;":"\u02d8","brvbar":"\u00a6","brvbar;":"\u00a6","bscr;":"\ud835\udcb7","bsemi;":"\u204f","bsim;":"\u223d","bsime;":"\u22cd","bsol;":"\\","bsolb;":"\u29c5","bsolhsub;":"\u27c8","bull;":"\u2022","bullet;":"\u2022","bump;":"\u224e","bumpE;":"\u2aae","bumpe;":"\u224f","bumpeq;":"\u224f","cacute;":"\u0107","cap;":"\u2229","capand;":"\u2a44","capbrcup;":"\u2a49","capcap;":"\u2a4b","capcup;":"\u2a47","capdot;":"\u2a40","caps;":"\u2229\ufe00","caret;":"\u2041","caron;":"\u02c7","ccaps;":"\u2a4d","ccaron;":"\u010d","ccedil":"\u00e7","ccedil;":"\u00e7","ccirc;":"\u0109","ccups;":"\u2a4c","ccupssm;":"\u2a50","cdot;":"\u010b","cedil":"\u00b8","cedil;":"\u00b8","cemptyv;":"\u29b2","cent":"\u00a2","cent;":"\u00a2","centerdot;":"\u00b7","cfr;":"\ud835\udd20","chcy;":"\u0447","check;":"\u2713","checkmark;":"\u2713","chi;":"\u03c7","cir;":"\u25cb","cirE;":"\u29c3","circ;":"\u02c6","circeq;":"\u2257","circlearrowleft;":"\u21ba","circlearrowright;":"\u21bb","circledR;":"\u00ae","circledS;":"\u24c8","circledast;":"\u229b","circledcirc;":"\u229a","circleddash;":"\u229d","cire;":"\u2257","cirfnint;":"\u2a10","cirmid;":"\u2aef","cirscir;":"\u29c2","clubs;":"\u2663","clubsuit;":"\u2663","colon;":":","colone;":"\u2254","coloneq;":"\u2254","comma;":",","commat;":"@","comp;":"\u2201","compfn;":"\u2218","complement;":"\u2201","complexes;":"\u2102","cong;":"\u2245","congdot;":"\u2a6d","conint;":"\u222e","copf;":"\ud835\udd54","coprod;":"\u2210","copy":"\u00a9","copy;":"\u00a9","copysr;":"\u2117","crarr;":"\u21b5","cross;":"\u2717","cscr;":"\ud835\udcb8","csub;":"\u2acf","csube;":"\u2ad1","csup;":"\u2ad0","csupe;":"\u2ad2","ctdot;":"\u22ef","cudarrl;":"\u2938","cudarrr;":"\u2935","cuepr;":"\u22de","cuesc;":"\u22df","cularr;":"\u21b6","cularrp;":"\u293d","cup;":"\u222a","cupbrcap;":"\u2a48","cupcap;":"\u2a46","cupcup;":"\u2a4a","cupdot;":"\u228d","cupor;":"\u2a45","cups;":"\u222a\ufe00","curarr;":"\u21b7","curarrm;":"\u293c","curlyeqprec;":"\u22de","curlyeqsucc;":"\u22df","curlyvee;":"\u22ce","curlywedge;":"\u22cf","curren":"\u00a4","curren;":"\u00a4","curvearrowleft;":"\u21b6","curvearrowright;":"\u21b7","cuvee;":"\u22ce","cuwed;":"\u22cf","cwconint;":"\u2232","cwint;":"\u2231","cylcty;":"\u232d","dArr;":"\u21d3","dHar;":"\u2965","dagger;":"\u2020","daleth;":"\u2138","darr;":"\u2193","dash;":"\u2010","dashv;":"\u22a3","dbkarow;":"\u290f","dblac;":"\u02dd","dcaron;":"\u010f","dcy;":"\u0434","dd;":"\u2146","ddagger;":"\u2021","ddarr;":"\u21ca","ddotseq;":"\u2a77","deg":"\u00b0","deg;":"\u00b0","delta;":"\u03b4","demptyv;":"\u29b1","dfisht;":"\u297f","dfr;":"\ud835\udd21","dharl;":"\u21c3","dharr;":"\u21c2","diam;":"\u22c4","diamond;":"\u22c4","diamondsuit;":"\u2666","diams;":"\u2666","die;":"\u00a8","digamma;":"\u03dd","disin;":"\u22f2","div;":"\u00f7","divide":"\u00f7","divide;":"\u00f7","divideontimes;":"\u22c7","divonx;":"\u22c7","djcy;":"\u0452","dlcorn;":"\u231e","dlcrop;":"\u230d","dollar;":"$","dopf;":"\ud835\udd55","dot;":"\u02d9","doteq;":"\u2250","doteqdot;":"\u2251","dotminus;":"\u2238","dotplus;":"\u2214","dotsquare;":"\u22a1","doublebarwedge;":"\u2306","downarrow;":"\u2193","downdownarrows;":"\u21ca","downharpoonleft;":"\u21c3","downharpoonright;":"\u21c2","drbkarow;":"\u2910","drcorn;":"\u231f","drcrop;":"\u230c","dscr;":"\ud835\udcb9","dscy;":"\u0455","dsol;":"\u29f6","dstrok;":"\u0111","dtdot;":"\u22f1","dtri;":"\u25bf","dtrif;":"\u25be","duarr;":"\u21f5","duhar;":"\u296f","dwangle;":"\u29a6","dzcy;":"\u045f","dzigrarr;":"\u27ff","eDDot;":"\u2a77","eDot;":"\u2251","eacute":"\u00e9","eacute;":"\u00e9","easter;":"\u2a6e","ecaron;":"\u011b","ecir;":"\u2256","ecirc":"\u00ea","ecirc;":"\u00ea","ecolon;":"\u2255","ecy;":"\u044d","edot;":"\u0117","ee;":"\u2147","efDot;":"\u2252","efr;":"\ud835\udd22","eg;":"\u2a9a","egrave":"\u00e8","egrave;":"\u00e8","egs;":"\u2a96","egsdot;":"\u2a98","el;":"\u2a99","elinters;":"\u23e7","ell;":"\u2113","els;":"\u2a95","elsdot;":"\u2a97","emacr;":"\u0113","empty;":"\u2205","emptyset;":"\u2205","emptyv;":"\u2205","emsp13;":"\u2004","emsp14;":"\u2005","emsp;":"\u2003","eng;":"\u014b","ensp;":"\u2002","eogon;":"\u0119","eopf;":"\ud835\udd56","epar;":"\u22d5","eparsl;":"\u29e3","eplus;":"\u2a71","epsi;":"\u03b5","epsilon;":"\u03b5","epsiv;":"\u03f5","eqcirc;":"\u2256","eqcolon;":"\u2255","eqsim;":"\u2242","eqslantgtr;":"\u2a96","eqslantless;":"\u2a95","equals;":"=","equest;":"\u225f","equiv;":"\u2261","equivDD;":"\u2a78","eqvparsl;":"\u29e5","erDot;":"\u2253","erarr;":"\u2971","escr;":"\u212f","esdot;":"\u2250","esim;":"\u2242","eta;":"\u03b7","eth":"\u00f0","eth;":"\u00f0","euml":"\u00eb","euml;":"\u00eb","euro;":"\u20ac","excl;":"!","exist;":"\u2203","expectation;":"\u2130","exponentiale;":"\u2147","fallingdotseq;":"\u2252","fcy;":"\u0444","female;":"\u2640","ffilig;":"\ufb03","fflig;":"\ufb00","ffllig;":"\ufb04","ffr;":"\ud835\udd23","filig;":"\ufb01","fjlig;":"fj","flat;":"\u266d","fllig;":"\ufb02","fltns;":"\u25b1","fnof;":"\u0192","fopf;":"\ud835\udd57","forall;":"\u2200","fork;":"\u22d4","forkv;":"\u2ad9","fpartint;":"\u2a0d","frac12":"\u00bd","frac12;":"\u00bd","frac13;":"\u2153","frac14":"\u00bc","frac14;":"\u00bc","frac15;":"\u2155","frac16;":"\u2159","frac18;":"\u215b","frac23;":"\u2154","frac25;":"\u2156","frac34":"\u00be","frac34;":"\u00be","frac35;":"\u2157","frac38;":"\u215c","frac45;":"\u2158","frac56;":"\u215a","frac58;":"\u215d","frac78;":"\u215e","frasl;":"\u2044","frown;":"\u2322","fscr;":"\ud835\udcbb","gE;":"\u2267","gEl;":"\u2a8c","gacute;":"\u01f5","gamma;":"\u03b3","gammad;":"\u03dd","gap;":"\u2a86","gbreve;":"\u011f","gcirc;":"\u011d","gcy;":"\u0433","gdot;":"\u0121","ge;":"\u2265","gel;":"\u22db","geq;":"\u2265","geqq;":"\u2267","geqslant;":"\u2a7e","ges;":"\u2a7e","gescc;":"\u2aa9","gesdot;":"\u2a80","gesdoto;":"\u2a82","gesdotol;":"\u2a84","gesl;":"\u22db\ufe00","gesles;":"\u2a94","gfr;":"\ud835\udd24","gg;":"\u226b","ggg;":"\u22d9","gimel;":"\u2137","gjcy;":"\u0453","gl;":"\u2277","glE;":"\u2a92","gla;":"\u2aa5","glj;":"\u2aa4","gnE;":"\u2269","gnap;":"\u2a8a","gnapprox;":"\u2a8a","gne;":"\u2a88","gneq;":"\u2a88","gneqq;":"\u2269","gnsim;":"\u22e7","gopf;":"\ud835\udd58","grave;":"`","gscr;":"\u210a","gsim;":"\u2273","gsime;":"\u2a8e","gsiml;":"\u2a90","gt":">","gt;":">","gtcc;":"\u2aa7","gtcir;":"\u2a7a","gtdot;":"\u22d7","gtlPar;":"\u2995","gtquest;":"\u2a7c","gtrapprox;":"\u2a86","gtrarr;":"\u2978","gtrdot;":"\u22d7","gtreqless;":"\u22db","gtreqqless;":"\u2a8c","gtrless;":"\u2277","gtrsim;":"\u2273","gvertneqq;":"\u2269\ufe00","gvnE;":"\u2269\ufe00","hArr;":"\u21d4","hairsp;":"\u200a","half;":"\u00bd","hamilt;":"\u210b","hardcy;":"\u044a","harr;":"\u2194","harrcir;":"\u2948","harrw;":"\u21ad","hbar;":"\u210f","hcirc;":"\u0125","hearts;":"\u2665","heartsuit;":"\u2665","hellip;":"\u2026","hercon;":"\u22b9","hfr;":"\ud835\udd25","hksearow;":"\u2925","hkswarow;":"\u2926","hoarr;":"\u21ff","homtht;":"\u223b","hookleftarrow;":"\u21a9","hookrightarrow;":"\u21aa","hopf;":"\ud835\udd59","horbar;":"\u2015","hscr;":"\ud835\udcbd","hslash;":"\u210f","hstrok;":"\u0127","hybull;":"\u2043","hyphen;":"\u2010","iacute":"\u00ed","iacute;":"\u00ed","ic;":"\u2063","icirc":"\u00ee","icirc;":"\u00ee","icy;":"\u0438","iecy;":"\u0435","iexcl":"\u00a1","iexcl;":"\u00a1","iff;":"\u21d4","ifr;":"\ud835\udd26","igrave":"\u00ec","igrave;":"\u00ec","ii;":"\u2148","iiiint;":"\u2a0c","iiint;":"\u222d","iinfin;":"\u29dc","iiota;":"\u2129","ijlig;":"\u0133","imacr;":"\u012b","image;":"\u2111","imagline;":"\u2110","imagpart;":"\u2111","imath;":"\u0131","imof;":"\u22b7","imped;":"\u01b5","in;":"\u2208","incare;":"\u2105","infin;":"\u221e","infintie;":"\u29dd","inodot;":"\u0131","int;":"\u222b","intcal;":"\u22ba","integers;":"\u2124","intercal;":"\u22ba","intlarhk;":"\u2a17","intprod;":"\u2a3c","iocy;":"\u0451","iogon;":"\u012f","iopf;":"\ud835\udd5a","iota;":"\u03b9","iprod;":"\u2a3c","iquest":"\u00bf","iquest;":"\u00bf","iscr;":"\ud835\udcbe","isin;":"\u2208","isinE;":"\u22f9","isindot;":"\u22f5","isins;":"\u22f4","isinsv;":"\u22f3","isinv;":"\u2208","it;":"\u2062","itilde;":"\u0129","iukcy;":"\u0456","iuml":"\u00ef","iuml;":"\u00ef","jcirc;":"\u0135","jcy;":"\u0439","jfr;":"\ud835\udd27","jmath;":"\u0237","jopf;":"\ud835\udd5b","jscr;":"\ud835\udcbf","jsercy;":"\u0458","jukcy;":"\u0454","kappa;":"\u03ba","kappav;":"\u03f0","kcedil;":"\u0137","kcy;":"\u043a","kfr;":"\ud835\udd28","kgreen;":"\u0138","khcy;":"\u0445","kjcy;":"\u045c","kopf;":"\ud835\udd5c","kscr;":"\ud835\udcc0","lAarr;":"\u21da","lArr;":"\u21d0","lAtail;":"\u291b","lBarr;":"\u290e","lE;":"\u2266","lEg;":"\u2a8b","lHar;":"\u2962","lacute;":"\u013a","laemptyv;":"\u29b4","lagran;":"\u2112","lambda;":"\u03bb","lang;":"\u27e8","langd;":"\u2991","langle;":"\u27e8","lap;":"\u2a85","laquo":"\u00ab","laquo;":"\u00ab","larr;":"\u2190","larrb;":"\u21e4","larrbfs;":"\u291f","larrfs;":"\u291d","larrhk;":"\u21a9","larrlp;":"\u21ab","larrpl;":"\u2939","larrsim;":"\u2973","larrtl;":"\u21a2","lat;":"\u2aab","latail;":"\u2919","late;":"\u2aad","lates;":"\u2aad\ufe00","lbarr;":"\u290c","lbbrk;":"\u2772","lbrace;":"{","lbrack;":"[","lbrke;":"\u298b","lbrksld;":"\u298f","lbrkslu;":"\u298d","lcaron;":"\u013e","lcedil;":"\u013c","lceil;":"\u2308","lcub;":"{","lcy;":"\u043b","ldca;":"\u2936","ldquo;":"\u201c","ldquor;":"\u201e","ldrdhar;":"\u2967","ldrushar;":"\u294b","ldsh;":"\u21b2","le;":"\u2264","leftarrow;":"\u2190","leftarrowtail;":"\u21a2","leftharpoondown;":"\u21bd","leftharpoonup;":"\u21bc","leftleftarrows;":"\u21c7","leftrightarrow;":"\u2194","leftrightarrows;":"\u21c6","leftrightharpoons;":"\u21cb","leftrightsquigarrow;":"\u21ad","leftthreetimes;":"\u22cb","leg;":"\u22da","leq;":"\u2264","leqq;":"\u2266","leqslant;":"\u2a7d","les;":"\u2a7d","lescc;":"\u2aa8","lesdot;":"\u2a7f","lesdoto;":"\u2a81","lesdotor;":"\u2a83","lesg;":"\u22da\ufe00","lesges;":"\u2a93","lessapprox;":"\u2a85","lessdot;":"\u22d6","lesseqgtr;":"\u22da","lesseqqgtr;":"\u2a8b","lessgtr;":"\u2276","lesssim;":"\u2272","lfisht;":"\u297c","lfloor;":"\u230a","lfr;":"\ud835\udd29","lg;":"\u2276","lgE;":"\u2a91","lhard;":"\u21bd","lharu;":"\u21bc","lharul;":"\u296a","lhblk;":"\u2584","ljcy;":"\u0459","ll;":"\u226a","llarr;":"\u21c7","llcorner;":"\u231e","llhard;":"\u296b","lltri;":"\u25fa","lmidot;":"\u0140","lmoust;":"\u23b0","lmoustache;":"\u23b0","lnE;":"\u2268","lnap;":"\u2a89","lnapprox;":"\u2a89","lne;":"\u2a87","lneq;":"\u2a87","lneqq;":"\u2268","lnsim;":"\u22e6","loang;":"\u27ec","loarr;":"\u21fd","lobrk;":"\u27e6","longleftarrow;":"\u27f5","longleftrightarrow;":"\u27f7","longmapsto;":"\u27fc","longrightarrow;":"\u27f6","looparrowleft;":"\u21ab","looparrowright;":"\u21ac","lopar;":"\u2985","lopf;":"\ud835\udd5d","loplus;":"\u2a2d","lotimes;":"\u2a34","lowast;":"\u2217","lowbar;":"_","loz;":"\u25ca","lozenge;":"\u25ca","lozf;":"\u29eb","lpar;":"(","lparlt;":"\u2993","lrarr;":"\u21c6","lrcorner;":"\u231f","lrhar;":"\u21cb","lrhard;":"\u296d","lrm;":"\u200e","lrtri;":"\u22bf","lsaquo;":"\u2039","lscr;":"\ud835\udcc1","lsh;":"\u21b0","lsim;":"\u2272","lsime;":"\u2a8d","lsimg;":"\u2a8f","lsqb;":"[","lsquo;":"\u2018","lsquor;":"\u201a","lstrok;":"\u0142","lt":"<","lt;":"<","ltcc;":"\u2aa6","ltcir;":"\u2a79","ltdot;":"\u22d6","lthree;":"\u22cb","ltimes;":"\u22c9","ltlarr;":"\u2976","ltquest;":"\u2a7b","ltrPar;":"\u2996","ltri;":"\u25c3","ltrie;":"\u22b4","ltrif;":"\u25c2","lurdshar;":"\u294a","luruhar;":"\u2966","lvertneqq;":"\u2268\ufe00","lvnE;":"\u2268\ufe00","mDDot;":"\u223a","macr":"\u00af","macr;":"\u00af","male;":"\u2642","malt;":"\u2720","maltese;":"\u2720","map;":"\u21a6","mapsto;":"\u21a6","mapstodown;":"\u21a7","mapstoleft;":"\u21a4","mapstoup;":"\u21a5","marker;":"\u25ae","mcomma;":"\u2a29","mcy;":"\u043c","mdash;":"\u2014","measuredangle;":"\u2221","mfr;":"\ud835\udd2a","mho;":"\u2127","micro":"\u00b5","micro;":"\u00b5","mid;":"\u2223","midast;":"*","midcir;":"\u2af0","middot":"\u00b7","middot;":"\u00b7","minus;":"\u2212","minusb;":"\u229f","minusd;":"\u2238","minusdu;":"\u2a2a","mlcp;":"\u2adb","mldr;":"\u2026","mnplus;":"\u2213","models;":"\u22a7","mopf;":"\ud835\udd5e","mp;":"\u2213","mscr;":"\ud835\udcc2","mstpos;":"\u223e","mu;":"\u03bc","multimap;":"\u22b8","mumap;":"\u22b8","nGg;":"\u22d9\u0338","nGt;":"\u226b\u20d2","nGtv;":"\u226b\u0338","nLeftarrow;":"\u21cd","nLeftrightarrow;":"\u21ce","nLl;":"\u22d8\u0338","nLt;":"\u226a\u20d2","nLtv;":"\u226a\u0338","nRightarrow;":"\u21cf","nVDash;":"\u22af","nVdash;":"\u22ae","nabla;":"\u2207","nacute;":"\u0144","nang;":"\u2220\u20d2","nap;":"\u2249","napE;":"\u2a70\u0338","napid;":"\u224b\u0338","napos;":"\u0149","napprox;":"\u2249","natur;":"\u266e","natural;":"\u266e","naturals;":"\u2115","nbsp":"\u00a0","nbsp;":"\u00a0","nbump;":"\u224e\u0338","nbumpe;":"\u224f\u0338","ncap;":"\u2a43","ncaron;":"\u0148","ncedil;":"\u0146","ncong;":"\u2247","ncongdot;":"\u2a6d\u0338","ncup;":"\u2a42","ncy;":"\u043d","ndash;":"\u2013","ne;":"\u2260","neArr;":"\u21d7","nearhk;":"\u2924","nearr;":"\u2197","nearrow;":"\u2197","nedot;":"\u2250\u0338","nequiv;":"\u2262","nesear;":"\u2928","nesim;":"\u2242\u0338","nexist;":"\u2204","nexists;":"\u2204","nfr;":"\ud835\udd2b","ngE;":"\u2267\u0338","nge;":"\u2271","ngeq;":"\u2271","ngeqq;":"\u2267\u0338","ngeqslant;":"\u2a7e\u0338","nges;":"\u2a7e\u0338","ngsim;":"\u2275","ngt;":"\u226f","ngtr;":"\u226f","nhArr;":"\u21ce","nharr;":"\u21ae","nhpar;":"\u2af2","ni;":"\u220b","nis;":"\u22fc","nisd;":"\u22fa","niv;":"\u220b","njcy;":"\u045a","nlArr;":"\u21cd","nlE;":"\u2266\u0338","nlarr;":"\u219a","nldr;":"\u2025","nle;":"\u2270","nleftarrow;":"\u219a","nleftrightarrow;":"\u21ae","nleq;":"\u2270","nleqq;":"\u2266\u0338","nleqslant;":"\u2a7d\u0338","nles;":"\u2a7d\u0338","nless;":"\u226e","nlsim;":"\u2274","nlt;":"\u226e","nltri;":"\u22ea","nltrie;":"\u22ec","nmid;":"\u2224","nopf;":"\ud835\udd5f","not":"\u00ac","not;":"\u00ac","notin;":"\u2209","notinE;":"\u22f9\u0338","notindot;":"\u22f5\u0338","notinva;":"\u2209","notinvb;":"\u22f7","notinvc;":"\u22f6","notni;":"\u220c","notniva;":"\u220c","notnivb;":"\u22fe","notnivc;":"\u22fd","npar;":"\u2226","nparallel;":"\u2226","nparsl;":"\u2afd\u20e5","npart;":"\u2202\u0338","npolint;":"\u2a14","npr;":"\u2280","nprcue;":"\u22e0","npre;":"\u2aaf\u0338","nprec;":"\u2280","npreceq;":"\u2aaf\u0338","nrArr;":"\u21cf","nrarr;":"\u219b","nrarrc;":"\u2933\u0338","nrarrw;":"\u219d\u0338","nrightarrow;":"\u219b","nrtri;":"\u22eb","nrtrie;":"\u22ed","nsc;":"\u2281","nsccue;":"\u22e1","nsce;":"\u2ab0\u0338","nscr;":"\ud835\udcc3","nshortmid;":"\u2224","nshortparallel;":"\u2226","nsim;":"\u2241","nsime;":"\u2244","nsimeq;":"\u2244","nsmid;":"\u2224","nspar;":"\u2226","nsqsube;":"\u22e2","nsqsupe;":"\u22e3","nsub;":"\u2284","nsubE;":"\u2ac5\u0338","nsube;":"\u2288","nsubset;":"\u2282\u20d2","nsubseteq;":"\u2288","nsubseteqq;":"\u2ac5\u0338","nsucc;":"\u2281","nsucceq;":"\u2ab0\u0338","nsup;":"\u2285","nsupE;":"\u2ac6\u0338","nsupe;":"\u2289","nsupset;":"\u2283\u20d2","nsupseteq;":"\u2289","nsupseteqq;":"\u2ac6\u0338","ntgl;":"\u2279","ntilde":"\u00f1","ntilde;":"\u00f1","ntlg;":"\u2278","ntriangleleft;":"\u22ea","ntrianglelefteq;":"\u22ec","ntriangleright;":"\u22eb","ntrianglerighteq;":"\u22ed","nu;":"\u03bd","num;":"#","numero;":"\u2116","numsp;":"\u2007","nvDash;":"\u22ad","nvHarr;":"\u2904","nvap;":"\u224d\u20d2","nvdash;":"\u22ac","nvge;":"\u2265\u20d2","nvgt;":">\u20d2","nvinfin;":"\u29de","nvlArr;":"\u2902","nvle;":"\u2264\u20d2","nvlt;":"<\u20d2","nvltrie;":"\u22b4\u20d2","nvrArr;":"\u2903","nvrtrie;":"\u22b5\u20d2","nvsim;":"\u223c\u20d2","nwArr;":"\u21d6","nwarhk;":"\u2923","nwarr;":"\u2196","nwarrow;":"\u2196","nwnear;":"\u2927","oS;":"\u24c8","oacute":"\u00f3","oacute;":"\u00f3","oast;":"\u229b","ocir;":"\u229a","ocirc":"\u00f4","ocirc;":"\u00f4","ocy;":"\u043e","odash;":"\u229d","odblac;":"\u0151","odiv;":"\u2a38","odot;":"\u2299","odsold;":"\u29bc","oelig;":"\u0153","ofcir;":"\u29bf","ofr;":"\ud835\udd2c","ogon;":"\u02db","ograve":"\u00f2","ograve;":"\u00f2","ogt;":"\u29c1","ohbar;":"\u29b5","ohm;":"\u03a9","oint;":"\u222e","olarr;":"\u21ba","olcir;":"\u29be","olcross;":"\u29bb","oline;":"\u203e","olt;":"\u29c0","omacr;":"\u014d","omega;":"\u03c9","omicron;":"\u03bf","omid;":"\u29b6","ominus;":"\u2296","oopf;":"\ud835\udd60","opar;":"\u29b7","operp;":"\u29b9","oplus;":"\u2295","or;":"\u2228","orarr;":"\u21bb","ord;":"\u2a5d","order;":"\u2134","orderof;":"\u2134","ordf":"\u00aa","ordf;":"\u00aa","ordm":"\u00ba","ordm;":"\u00ba","origof;":"\u22b6","oror;":"\u2a56","orslope;":"\u2a57","orv;":"\u2a5b","oscr;":"\u2134","oslash":"\u00f8","oslash;":"\u00f8","osol;":"\u2298","otilde":"\u00f5","otilde;":"\u00f5","otimes;":"\u2297","otimesas;":"\u2a36","ouml":"\u00f6","ouml;":"\u00f6","ovbar;":"\u233d","par;":"\u2225","para":"\u00b6","para;":"\u00b6","parallel;":"\u2225","parsim;":"\u2af3","parsl;":"\u2afd","part;":"\u2202","pcy;":"\u043f","percnt;":"%","period;":".","permil;":"\u2030","perp;":"\u22a5","pertenk;":"\u2031","pfr;":"\ud835\udd2d","phi;":"\u03c6","phiv;":"\u03d5","phmmat;":"\u2133","phone;":"\u260e","pi;":"\u03c0","pitchfork;":"\u22d4","piv;":"\u03d6","planck;":"\u210f","planckh;":"\u210e","plankv;":"\u210f","plus;":"+","plusacir;":"\u2a23","plusb;":"\u229e","pluscir;":"\u2a22","plusdo;":"\u2214","plusdu;":"\u2a25","pluse;":"\u2a72","plusmn":"\u00b1","plusmn;":"\u00b1","plussim;":"\u2a26","plustwo;":"\u2a27","pm;":"\u00b1","pointint;":"\u2a15","popf;":"\ud835\udd61","pound":"\u00a3","pound;":"\u00a3","pr;":"\u227a","prE;":"\u2ab3","prap;":"\u2ab7","prcue;":"\u227c","pre;":"\u2aaf","prec;":"\u227a","precapprox;":"\u2ab7","preccurlyeq;":"\u227c","preceq;":"\u2aaf","precnapprox;":"\u2ab9","precneqq;":"\u2ab5","precnsim;":"\u22e8","precsim;":"\u227e","prime;":"\u2032","primes;":"\u2119","prnE;":"\u2ab5","prnap;":"\u2ab9","prnsim;":"\u22e8","prod;":"\u220f","profalar;":"\u232e","profline;":"\u2312","profsurf;":"\u2313","prop;":"\u221d","propto;":"\u221d","prsim;":"\u227e","prurel;":"\u22b0","pscr;":"\ud835\udcc5","psi;":"\u03c8","puncsp;":"\u2008","qfr;":"\ud835\udd2e","qint;":"\u2a0c","qopf;":"\ud835\udd62","qprime;":"\u2057","qscr;":"\ud835\udcc6","quaternions;":"\u210d","quatint;":"\u2a16","quest;":"?","questeq;":"\u225f","quot":"\"","quot;":"\"","rAarr;":"\u21db","rArr;":"\u21d2","rAtail;":"\u291c","rBarr;":"\u290f","rHar;":"\u2964","race;":"\u223d\u0331","racute;":"\u0155","radic;":"\u221a","raemptyv;":"\u29b3","rang;":"\u27e9","rangd;":"\u2992","range;":"\u29a5","rangle;":"\u27e9","raquo":"\u00bb","raquo;":"\u00bb","rarr;":"\u2192","rarrap;":"\u2975","rarrb;":"\u21e5","rarrbfs;":"\u2920","rarrc;":"\u2933","rarrfs;":"\u291e","rarrhk;":"\u21aa","rarrlp;":"\u21ac","rarrpl;":"\u2945","rarrsim;":"\u2974","rarrtl;":"\u21a3","rarrw;":"\u219d","ratail;":"\u291a","ratio;":"\u2236","rationals;":"\u211a","rbarr;":"\u290d","rbbrk;":"\u2773","rbrace;":"}","rbrack;":"]","rbrke;":"\u298c","rbrksld;":"\u298e","rbrkslu;":"\u2990","rcaron;":"\u0159","rcedil;":"\u0157","rceil;":"\u2309","rcub;":"}","rcy;":"\u0440","rdca;":"\u2937","rdldhar;":"\u2969","rdquo;":"\u201d","rdquor;":"\u201d","rdsh;":"\u21b3","real;":"\u211c","realine;":"\u211b","realpart;":"\u211c","reals;":"\u211d","rect;":"\u25ad","reg":"\u00ae","reg;":"\u00ae","rfisht;":"\u297d","rfloor;":"\u230b","rfr;":"\ud835\udd2f","rhard;":"\u21c1","rharu;":"\u21c0","rharul;":"\u296c","rho;":"\u03c1","rhov;":"\u03f1","rightarrow;":"\u2192","rightarrowtail;":"\u21a3","rightharpoondown;":"\u21c1","rightharpoonup;":"\u21c0","rightleftarrows;":"\u21c4","rightleftharpoons;":"\u21cc","rightrightarrows;":"\u21c9","rightsquigarrow;":"\u219d","rightthreetimes;":"\u22cc","ring;":"\u02da","risingdotseq;":"\u2253","rlarr;":"\u21c4","rlhar;":"\u21cc","rlm;":"\u200f","rmoust;":"\u23b1","rmoustache;":"\u23b1","rnmid;":"\u2aee","roang;":"\u27ed","roarr;":"\u21fe","robrk;":"\u27e7","ropar;":"\u2986","ropf;":"\ud835\udd63","roplus;":"\u2a2e","rotimes;":"\u2a35","rpar;":")","rpargt;":"\u2994","rppolint;":"\u2a12","rrarr;":"\u21c9","rsaquo;":"\u203a","rscr;":"\ud835\udcc7","rsh;":"\u21b1","rsqb;":"]","rsquo;":"\u2019","rsquor;":"\u2019","rthree;":"\u22cc","rtimes;":"\u22ca","rtri;":"\u25b9","rtrie;":"\u22b5","rtrif;":"\u25b8","rtriltri;":"\u29ce","ruluhar;":"\u2968","rx;":"\u211e","sacute;":"\u015b","sbquo;":"\u201a","sc;":"\u227b","scE;":"\u2ab4","scap;":"\u2ab8","scaron;":"\u0161","sccue;":"\u227d","sce;":"\u2ab0","scedil;":"\u015f","scirc;":"\u015d","scnE;":"\u2ab6","scnap;":"\u2aba","scnsim;":"\u22e9","scpolint;":"\u2a13","scsim;":"\u227f","scy;":"\u0441","sdot;":"\u22c5","sdotb;":"\u22a1","sdote;":"\u2a66","seArr;":"\u21d8","searhk;":"\u2925","searr;":"\u2198","searrow;":"\u2198","sect":"\u00a7","sect;":"\u00a7","semi;":";","seswar;":"\u2929","setminus;":"\u2216","setmn;":"\u2216","sext;":"\u2736","sfr;":"\ud835\udd30","sfrown;":"\u2322","sharp;":"\u266f","shchcy;":"\u0449","shcy;":"\u0448","shortmid;":"\u2223","shortparallel;":"\u2225","shy":"\u00ad","shy;":"\u00ad","sigma;":"\u03c3","sigmaf;":"\u03c2","sigmav;":"\u03c2","sim;":"\u223c","simdot;":"\u2a6a","sime;":"\u2243","simeq;":"\u2243","simg;":"\u2a9e","simgE;":"\u2aa0","siml;":"\u2a9d","simlE;":"\u2a9f","simne;":"\u2246","simplus;":"\u2a24","simrarr;":"\u2972","slarr;":"\u2190","smallsetminus;":"\u2216","smashp;":"\u2a33","smeparsl;":"\u29e4","smid;":"\u2223","smile;":"\u2323","smt;":"\u2aaa","smte;":"\u2aac","smtes;":"\u2aac\ufe00","softcy;":"\u044c","sol;":"/","solb;":"\u29c4","solbar;":"\u233f","sopf;":"\ud835\udd64","spades;":"\u2660","spadesuit;":"\u2660","spar;":"\u2225","sqcap;":"\u2293","sqcaps;":"\u2293\ufe00","sqcup;":"\u2294","sqcups;":"\u2294\ufe00","sqsub;":"\u228f","sqsube;":"\u2291","sqsubset;":"\u228f","sqsubseteq;":"\u2291","sqsup;":"\u2290","sqsupe;":"\u2292","sqsupset;":"\u2290","sqsupseteq;":"\u2292","squ;":"\u25a1","square;":"\u25a1","squarf;":"\u25aa","squf;":"\u25aa","srarr;":"\u2192","sscr;":"\ud835\udcc8","ssetmn;":"\u2216","ssmile;":"\u2323","sstarf;":"\u22c6","star;":"\u2606","starf;":"\u2605","straightepsilon;":"\u03f5","straightphi;":"\u03d5","strns;":"\u00af","sub;":"\u2282","subE;":"\u2ac5","subdot;":"\u2abd","sube;":"\u2286","subedot;":"\u2ac3","submult;":"\u2ac1","subnE;":"\u2acb","subne;":"\u228a","subplus;":"\u2abf","subrarr;":"\u2979","subset;":"\u2282","subseteq;":"\u2286","subseteqq;":"\u2ac5","subsetneq;":"\u228a","subsetneqq;":"\u2acb","subsim;":"\u2ac7","subsub;":"\u2ad5","subsup;":"\u2ad3","succ;":"\u227b","succapprox;":"\u2ab8","succcurlyeq;":"\u227d","succeq;":"\u2ab0","succnapprox;":"\u2aba","succneqq;":"\u2ab6","succnsim;":"\u22e9","succsim;":"\u227f","sum;":"\u2211","sung;":"\u266a","sup1":"\u00b9","sup1;":"\u00b9","sup2":"\u00b2","sup2;":"\u00b2","sup3":"\u00b3","sup3;":"\u00b3","sup;":"\u2283","supE;":"\u2ac6","supdot;":"\u2abe","supdsub;":"\u2ad8","supe;":"\u2287","supedot;":"\u2ac4","suphsol;":"\u27c9","suphsub;":"\u2ad7","suplarr;":"\u297b","supmult;":"\u2ac2","supnE;":"\u2acc","supne;":"\u228b","supplus;":"\u2ac0","supset;":"\u2283","supseteq;":"\u2287","supseteqq;":"\u2ac6","supsetneq;":"\u228b","supsetneqq;":"\u2acc","supsim;":"\u2ac8","supsub;":"\u2ad4","supsup;":"\u2ad6","swArr;":"\u21d9","swarhk;":"\u2926","swarr;":"\u2199","swarrow;":"\u2199","swnwar;":"\u292a","szlig":"\u00df","szlig;":"\u00df","target;":"\u2316","tau;":"\u03c4","tbrk;":"\u23b4","tcaron;":"\u0165","tcedil;":"\u0163","tcy;":"\u0442","tdot;":"\u20db","telrec;":"\u2315","tfr;":"\ud835\udd31","there4;":"\u2234","therefore;":"\u2234","theta;":"\u03b8","thetasym;":"\u03d1","thetav;":"\u03d1","thickapprox;":"\u2248","thicksim;":"\u223c","thinsp;":"\u2009","thkap;":"\u2248","thksim;":"\u223c","thorn":"\u00fe","thorn;":"\u00fe","tilde;":"\u02dc","times":"\u00d7","times;":"\u00d7","timesb;":"\u22a0","timesbar;":"\u2a31","timesd;":"\u2a30","tint;":"\u222d","toea;":"\u2928","top;":"\u22a4","topbot;":"\u2336","topcir;":"\u2af1","topf;":"\ud835\udd65","topfork;":"\u2ada","tosa;":"\u2929","tprime;":"\u2034","trade;":"\u2122","triangle;":"\u25b5","triangledown;":"\u25bf","triangleleft;":"\u25c3","trianglelefteq;":"\u22b4","triangleq;":"\u225c","triangleright;":"\u25b9","trianglerighteq;":"\u22b5","tridot;":"\u25ec","trie;":"\u225c","triminus;":"\u2a3a","triplus;":"\u2a39","trisb;":"\u29cd","tritime;":"\u2a3b","trpezium;":"\u23e2","tscr;":"\ud835\udcc9","tscy;":"\u0446","tshcy;":"\u045b","tstrok;":"\u0167","twixt;":"\u226c","twoheadleftarrow;":"\u219e","twoheadrightarrow;":"\u21a0","uArr;":"\u21d1","uHar;":"\u2963","uacute":"\u00fa","uacute;":"\u00fa","uarr;":"\u2191","ubrcy;":"\u045e","ubreve;":"\u016d","ucirc":"\u00fb","ucirc;":"\u00fb","ucy;":"\u0443","udarr;":"\u21c5","udblac;":"\u0171","udhar;":"\u296e","ufisht;":"\u297e","ufr;":"\ud835\udd32","ugrave":"\u00f9","ugrave;":"\u00f9","uharl;":"\u21bf","uharr;":"\u21be","uhblk;":"\u2580","ulcorn;":"\u231c","ulcorner;":"\u231c","ulcrop;":"\u230f","ultri;":"\u25f8","umacr;":"\u016b","uml":"\u00a8","uml;":"\u00a8","uogon;":"\u0173","uopf;":"\ud835\udd66","uparrow;":"\u2191","updownarrow;":"\u2195","upharpoonleft;":"\u21bf","upharpoonright;":"\u21be","uplus;":"\u228e","upsi;":"\u03c5","upsih;":"\u03d2","upsilon;":"\u03c5","upuparrows;":"\u21c8","urcorn;":"\u231d","urcorner;":"\u231d","urcrop;":"\u230e","uring;":"\u016f","urtri;":"\u25f9","uscr;":"\ud835\udcca","utdot;":"\u22f0","utilde;":"\u0169","utri;":"\u25b5","utrif;":"\u25b4","uuarr;":"\u21c8","uuml":"\u00fc","uuml;":"\u00fc","uwangle;":"\u29a7","vArr;":"\u21d5","vBar;":"\u2ae8","vBarv;":"\u2ae9","vDash;":"\u22a8","vangrt;":"\u299c","varepsilon;":"\u03f5","varkappa;":"\u03f0","varnothing;":"\u2205","varphi;":"\u03d5","varpi;":"\u03d6","varpropto;":"\u221d","varr;":"\u2195","varrho;":"\u03f1","varsigma;":"\u03c2","varsubsetneq;":"\u228a\ufe00","varsubsetneqq;":"\u2acb\ufe00","varsupsetneq;":"\u228b\ufe00","varsupsetneqq;":"\u2acc\ufe00","vartheta;":"\u03d1","vartriangleleft;":"\u22b2","vartriangleright;":"\u22b3","vcy;":"\u0432","vdash;":"\u22a2","vee;":"\u2228","veebar;":"\u22bb","veeeq;":"\u225a","vellip;":"\u22ee","verbar;":"|","vert;":"|","vfr;":"\ud835\udd33","vltri;":"\u22b2","vnsub;":"\u2282\u20d2","vnsup;":"\u2283\u20d2","vopf;":"\ud835\udd67","vprop;":"\u221d","vrtri;":"\u22b3","vscr;":"\ud835\udccb","vsubnE;":"\u2acb\ufe00","vsubne;":"\u228a\ufe00","vsupnE;":"\u2acc\ufe00","vsupne;":"\u228b\ufe00","vzigzag;":"\u299a","wcirc;":"\u0175","wedbar;":"\u2a5f","wedge;":"\u2227","wedgeq;":"\u2259","weierp;":"\u2118","wfr;":"\ud835\udd34","wopf;":"\ud835\udd68","wp;":"\u2118","wr;":"\u2240","wreath;":"\u2240","wscr;":"\ud835\udccc","xcap;":"\u22c2","xcirc;":"\u25ef","xcup;":"\u22c3","xdtri;":"\u25bd","xfr;":"\ud835\udd35","xhArr;":"\u27fa","xharr;":"\u27f7","xi;":"\u03be","xlArr;":"\u27f8","xlarr;":"\u27f5","xmap;":"\u27fc","xnis;":"\u22fb","xodot;":"\u2a00","xopf;":"\ud835\udd69","xoplus;":"\u2a01","xotime;":"\u2a02","xrArr;":"\u27f9","xrarr;":"\u27f6","xscr;":"\ud835\udccd","xsqcup;":"\u2a06","xuplus;":"\u2a04","xutri;":"\u25b3","xvee;":"\u22c1","xwedge;":"\u22c0","yacute":"\u00fd","yacute;":"\u00fd","yacy;":"\u044f","ycirc;":"\u0177","ycy;":"\u044b","yen":"\u00a5","yen;":"\u00a5","yfr;":"\ud835\udd36","yicy;":"\u0457","yopf;":"\ud835\udd6a","yscr;":"\ud835\udcce","yucy;":"\u044e","yuml":"\u00ff","yuml;":"\u00ff","zacute;":"\u017a","zcaron;":"\u017e","zcy;":"\u0437","zdot;":"\u017c","zeetrf;":"\u2128","zeta;":"\u03b6","zfr;":"\ud835\udd37","zhcy;":"\u0436","zigrarr;":"\u21dd","zopf;":"\ud835\udd6b","zscr;":"\ud835\udccf","zwj;":"\u200d","zwnj;":"\u200c"}
@@ -0,0 +1,58 @@
1
+ import { readFile, stat } from 'node:fs/promises';
2
+ import { dirname, isAbsolute, resolve } from 'node:path';
3
+ import { cssReferences } from './site-markup.mjs';
4
+ import { memberName, stringValue, walkSyntax } from './site-syntax.mjs';
5
+
6
+ // CSS imports/assets and import.meta URL assets bypass Rollup's load hook in
7
+ // Vite. Inspect their syntax and recursively validate CSS before Vite reads it.
8
+ export function assetInputGuard(root, validate, deny, vite, compiled = false) {
9
+ const inspected = new Set();
10
+ return async function inspect(code, id) {
11
+ // Vite loads this helper after rewriting dynamic imports. Its URL receives
12
+ // emitted chunk names at runtime, not source assets; Vite's own asset URL
13
+ // transform excludes the same exact helper. Resolve/load validation still
14
+ // runs, and every other virtual module keeps the source-asset checks below.
15
+ if (id === '\0vite/preload-helper.js') return null;
16
+ const path = id.replace(/[?#].*$/, ''), css = /\.(?:css|scss|sass|less|styl|sss)$/.test(path), targets = [];
17
+ if (css) targets.push(...cssReferences(code));
18
+ else if (compiled || /\.[cm]?[jt]sx?$/.test(path) || id.startsWith('\0')) {
19
+ const extension = !compiled && /\.(tsx?|jsx)$/.exec(path)?.[1];
20
+ const source = extension ? (await vite.transformWithEsbuild(code, path, {loader:extension, tsconfigRaw:{}, sourcemap:false}, undefined, undefined, undefined, true)).code : code;
21
+ walkSyntax(vite.parseAst(source), node => {
22
+ if (node.type !== 'NewExpression' || node.callee.name !== 'URL') return;
23
+ const base = node.arguments[1];
24
+ if (memberName(base) !== 'url' || base.object.type !== 'MetaProperty' || base.object.meta.name !== 'import') return;
25
+ const url = stringValue(node.arguments[0]);
26
+ const template = node.arguments[0];
27
+ const prefix = template?.type === 'TemplateLiteral' ? template.quasis[0].value.cooked : null;
28
+ targets.push({url, dynamic:url === undefined, prefix});
29
+ });
30
+ }
31
+ for (const target of targets) {
32
+ if (target.dynamic) {
33
+ // Vite expands a relative template to glob imports. Validate the static
34
+ // directory now; resolve/load validate every glob result before loading.
35
+ if (!target.prefix?.startsWith('./') && !target.prefix?.startsWith('../')) { await deny('site_private_input'); continue; }
36
+ const directory = target.prefix.endsWith('/') ? target.prefix : dirname(target.prefix);
37
+ await validate(resolve(dirname(path), directory), id);
38
+ continue;
39
+ }
40
+ const url = target.url;
41
+ if (!url || /^(?:[a-z][a-z0-9+.-]*:|\/\/|#)/i.test(url)) continue;
42
+ // Match Vite's public-directory handling as well as package/alias resolution.
43
+ const publicFile = url.startsWith('/') ? resolve(root, 'public', url.slice(1)) : null;
44
+ const publicExists = publicFile && await readFileStatus(publicFile);
45
+ const result = publicExists ? {id:publicFile} : await this.resolve(url, id);
46
+ const file = result?.id ?? resolve(dirname(path), url);
47
+ await validate(file, id);
48
+ const resolved = file.replace(/[?#].*$/, '');
49
+ if (css && isAbsolute(resolved) && /\.(?:css|scss|sass|less|styl|sss)$/.test(resolved) && !inspected.has(resolved)) {
50
+ inspected.add(resolved);
51
+ const nested = await readFile(resolved, 'utf8');
52
+ await inspect.call(this, nested, resolved);
53
+ }
54
+ }
55
+ return null;
56
+ };
57
+ }
58
+ const readFileStatus = path => stat(path.replace(/[?#].*$/, '')).then(value => value.isFile(), () => false);
@@ -0,0 +1,79 @@
1
+ import { readFile, realpath } from 'node:fs/promises';
2
+ import { builtinModules } from 'node:module';
3
+ import { assetInputGuard } from './site-input-assets.mjs';
4
+ import { dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';
5
+
6
+ const within = (root, file) => file === root || file.startsWith(root + sep);
7
+ const builtins = new Set(builtinModules.flatMap(name => [name, `node:${name}`]));
8
+ const clean = id => id.replace(/[?#].*$/, '');
9
+ export function privateSitePaths(adapter) {
10
+ return [...new Set(['.seed', '.rer', '.wrangler', '.git', '.env', '.dev.vars', adapter.state, adapter.hooks?.secrets?.file, ...(adapter.settings ?? [])].filter(Boolean))];
11
+ }
12
+
13
+ // Build an allowlist from the installed dependency graph, not from the spelling
14
+ // "node_modules" in an arbitrary path. pnpm and linked dependency roots are real
15
+ // paths; files within a package must still remain inside that package.
16
+ export async function clientInputGuard(root, privatePaths, deny, vite) {
17
+ root = await realpath(root);
18
+ const packages = new Set(), seen = new Set(), edges = new Map();
19
+ async function dependencies(directory, isRoot = false) {
20
+ directory = await realpath(directory);
21
+ if (seen.has(directory)) return;
22
+ seen.add(directory);
23
+ const pkg = JSON.parse(await readFile(join(directory, 'package.json'), 'utf8'));
24
+ const allowed = new Set(); edges.set(directory, allowed);
25
+ const names = Object.keys({...pkg.dependencies, ...pkg.optionalDependencies, ...pkg.peerDependencies, ...(isRoot ? pkg.devDependencies : {})});
26
+ for (const name of names) {
27
+ if (!/^(?:@[a-z0-9._-]+\/)?[a-z0-9._-]+$/i.test(name)) continue;
28
+ let cursor = directory, target;
29
+ while (true) {
30
+ try { target = await realpath(join(cursor, 'node_modules', name)); break; } catch {}
31
+ const parent = dirname(cursor); if (parent === cursor) break; cursor = parent;
32
+ }
33
+ if (!target) continue; // Optional/peer packages may be absent.
34
+ allowed.add(target); packages.add(target);
35
+ await dependencies(target);
36
+ }
37
+ }
38
+ await dependencies(root, true);
39
+ const privateRoots = privatePaths.map(path => resolve(root, path));
40
+ const realPrivate = await Promise.all(privateRoots.map(path => realpath(path).catch(() => path)));
41
+ const packageFor = file => [...packages].filter(path => within(path, file)).sort((a,b) => b.length - a.length)[0];
42
+ const privateFile = file => [...privateRoots, ...realPrivate].some(path => within(path, file)) || relative(root, file).split(sep).some(part => /^(?:\.env(?:\.|$)|\.dev\.vars(?:\.|$)|\.(?:seed|rer|wrangler|git)$)/.test(part));
43
+ async function validate(id, importer) {
44
+ if (builtins.has(id) || id.startsWith('node:') || id.includes('__vite-browser-external')) return deny('site_client_server_import');
45
+ if (id.startsWith('\0') || !isAbsolute(clean(id))) return;
46
+ const file = clean(id), physical = await realpath(file).catch(() => null);
47
+ if (!physical) return;
48
+ if (privateFile(file) || privateFile(physical)) return deny('site_private_input');
49
+ const packageRoot = packageFor(physical);
50
+ if (packageRoot) {
51
+ // A symlink from an allowed package into an unrelated file is not a dependency.
52
+ const lexicalPackage = packageFor(file);
53
+ if (lexicalPackage && lexicalPackage !== packageRoot && !file.includes(`${sep}node_modules${sep}`)) return deny('site_private_input');
54
+ if (importer) {
55
+ const importingFile = isAbsolute(clean(importer)) ? await realpath(clean(importer)).catch(() => clean(importer)) : root;
56
+ const owner = packageFor(importingFile) ?? root;
57
+ if (owner !== packageRoot && !edges.get(owner)?.has(packageRoot)) return deny('site_private_input');
58
+ }
59
+ return;
60
+ }
61
+ if (!within(root, file) || !within(root, physical) || relative(root, file).split(sep).includes('node_modules') || relative(root, physical).split(sep).includes('node_modules')) return deny('site_private_input');
62
+ }
63
+ return [{
64
+ name: 'rer-site-client-inputs', enforce: 'pre',
65
+ resolveId: { order: 'pre', async handler(source, importer, options) {
66
+ await validate(source, importer ?? root);
67
+ const result = await this.resolve(source, importer, {...options, skipSelf:true});
68
+ if (result) { await validate(result.id, importer ?? root); if (result.external) await deny('site_client_server_import'); }
69
+ return result;
70
+ }},
71
+ load: { order: 'pre', async handler(id) { await validate(id); return null; }},
72
+ transform: { order: 'pre', handler: assetInputGuard(root, validate, deny, vite) },
73
+ }, {
74
+ // Normal user transforms (including TSX/framework plugins) run before Vite's
75
+ // asset URL rewrite. Check their generated JavaScript at that boundary too.
76
+ name: 'rer-site-transformed-assets',
77
+ transform: assetInputGuard(root, validate, deny, vite, true),
78
+ }];
79
+ }