diff --git a/.gitignore b/.gitignore index ecdef5b..066147b 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,6 @@ -static \ No newline at end of file +node_modules/ +.next/ +out/ +next-env.d.ts +tsconfig.tsbuildinfo +.DS_Store diff --git a/README.md b/README.md new file mode 100644 index 0000000..4e9f378 --- /dev/null +++ b/README.md @@ -0,0 +1,26 @@ +# latex2js.com + +The website for [LaTeX2JS](https://github.com/Mathapedia/LaTeX2JS) — author interactive math equations and diagrams online using LaTeX and PSTricks. + +Built with Next.js (static export) on the same architecture as [constructive.io](https://constructive.io) and [danlynch.com](https://danlynch.com): + +- **JSON-LD knowledge graph** — `src/data/jsonld/` holds a flat graph of schema.org entities with namespaced `@id`s (`software:latex2js`, `org:constructive`, `person:danlynch`, …) shared across the site family. Pages slice per-page subgraphs via `jsonldjs` and the `` component injects them as `application/ld+json`. +- **SEO registry** — `src/seo.ts` holds per-route titles/descriptions; canonicals are derived from typed routes. +- **Sitemap + robots.txt** — generated post-build from the exported HTML by `src/seo/seo.ts`. +- **llms.txt + markdown twins** — `scripts/generate-llm-markdown.ts` emits `out/llms.txt` and a `.md` twin for every example and installation page. +- **Content as data** — the interactive PSTricks examples live as `.tex` files in `content/examples/`, registered in `src/data/examples.ts`, and rendered client-side by [`@latex2js/react`](https://www.npmjs.com/package/@latex2js/react). + +## Develop + +```bash +pnpm install +pnpm dev # http://localhost:5007 +pnpm test # JSON-LD graph validation + registry tests +``` + +## Build & deploy + +```bash +pnpm build # next build + llms.txt/md twins + sitemap/robots into out/ +pnpm deploy:all # build, sync to s3://latex2js.com, extensionless copies, CloudFront invalidation +``` diff --git a/__tests__/helpers/jsonld-test-utils.ts b/__tests__/helpers/jsonld-test-utils.ts new file mode 100644 index 0000000..cee5100 --- /dev/null +++ b/__tests__/helpers/jsonld-test-utils.ts @@ -0,0 +1,97 @@ +/** + * JSON-LD Test Utilities + * + * Helper functions for testing JSON-LD output. + * Snapshots are kept lean by extracting only @id and @type properties. + */ + +import { type JsonLdGraph, type JsonLdEntity } from 'jsonldjs'; + +/** + * Extract only @id properties from entities for lean snapshots + */ +export function extractIds(entities: JsonLdEntity[]): string[] { + return entities + .map((e) => e['@id']) + .filter((id): id is string => typeof id === 'string') + .sort(); +} + +/** + * Extract @id and @type for more detailed snapshots + */ +export function extractIdsAndTypes(entities: JsonLdEntity[]): { id: string; type: string | string[] }[] { + return entities + .map((e) => ({ + id: e['@id'], + type: e['@type'] as string | string[], + })) + .filter((e): e is { id: string; type: string | string[] } => typeof e.id === 'string') + .sort((a, b) => a.id.localeCompare(b.id)); +} + +/** + * Group entities by @type + */ +export function groupByType(entities: JsonLdEntity[]): Record { + const grouped: Record = {}; + + for (const entity of entities) { + const type = entity['@type']; + const id = entity['@id']; + + if (!id) continue; + + const types = Array.isArray(type) ? type : [type]; + for (const t of types) { + if (t) { + if (!grouped[t]) grouped[t] = []; + grouped[t].push(id); + } + } + } + + // Sort IDs within each type + for (const type of Object.keys(grouped)) { + grouped[type].sort(); + } + + return grouped; +} + +/** + * Create a summary of the JSON-LD graph + */ +export interface JsonLdSummary { + totalEntities: number; + entityIds: string[]; + byType: Record; +} + +export function createJsonLdSummary(entities: JsonLdEntity[]): JsonLdSummary { + return { + totalEntities: entities.length, + entityIds: extractIds(entities), + byType: groupByType(entities), + }; +} + +/** + * Filter entities that have usesSoftware referencing a specific software ID + */ +export function findOrganizationsUsingSoftware(entities: JsonLdEntity[], softwareId: string): string[] { + return entities + .filter((entity) => { + if (entity['@type'] !== 'Organization') return false; + const usesSoftware = entity.usesSoftware; + if (!usesSoftware) return false; + + const refs = Array.isArray(usesSoftware) ? usesSoftware : [usesSoftware]; + return refs.some((ref) => { + const refId = typeof ref === 'string' ? ref : ref?.['@id']; + return refId === softwareId; + }); + }) + .map((e) => e['@id'] as string) + .sort(); +} diff --git a/__tests__/jsonld/__snapshots__/graph-validation.test.ts.snap b/__tests__/jsonld/__snapshots__/graph-validation.test.ts.snap new file mode 100644 index 0000000..7ab2f7a --- /dev/null +++ b/__tests__/jsonld/__snapshots__/graph-validation.test.ts.snap @@ -0,0 +1,33 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`JSON-LD Graph Validation Graph Integrity should have consistent entity count 1`] = ` +{ + "totalEntities": 25, +} +`; + +exports[`JSON-LD Graph Validation findMissingReferences should find missing references in the graph 1`] = `[]`; + +exports[`JSON-LD Graph Validation findNestedEntities should find nested entities in the graph 1`] = `[]`; + +exports[`JSON-LD Graph Validation findOrphans should find orphaned entities in the graph 1`] = ` +[ + "software:latex2js-react", + "software:latex2js-vue", + "webpage:latex2js-example-block-diagram", + "webpage:latex2js-example-complex-plane", + "webpage:latex2js-example-custom-path", + "webpage:latex2js-example-derivative-story", + "webpage:latex2js-example-draggable-vector", + "webpage:latex2js-example-feedback-system", + "webpage:latex2js-example-function-plot", + "webpage:latex2js-example-geometric-series", + "webpage:latex2js-example-interactive-plot", + "webpage:latex2js-example-sampling-system", + "webpage:latex2js-example-shaded-integral", + "webpage:latex2js-example-two-variables", + "webpage:latex2js-example-unit-circle", + "webpage:latex2js-example-vector-functions", + "webpage:latex2js-sandbox", +] +`; diff --git a/__tests__/jsonld/examples-registry.test.ts b/__tests__/jsonld/examples-registry.test.ts new file mode 100644 index 0000000..6799108 --- /dev/null +++ b/__tests__/jsonld/examples-registry.test.ts @@ -0,0 +1,32 @@ +/** + * Examples registry tests + * + * The examples registry drives routes, JSON-LD entities, and llms.txt — + * every entry must point at a real .tex file and have a unique slug. + */ + +import fs from 'fs'; +import path from 'path'; + +import { examples } from '@/data/examples'; + +const CONTENT_DIR = path.resolve(__dirname, '../../content/examples'); + +describe('Examples registry', () => { + it('every example points to an existing .tex file', () => { + examples.forEach((example) => { + expect(fs.existsSync(path.join(CONTENT_DIR, example.file))).toBe(true); + }); + }); + + it('every .tex file is registered exactly once', () => { + const texFiles = fs.readdirSync(CONTENT_DIR).filter((f) => f.endsWith('.tex')); + const registered = examples.map((e) => e.file).sort(); + expect(registered).toEqual(texFiles.sort()); + }); + + it('slugs are unique', () => { + const slugs = examples.map((e) => e.slug); + expect(new Set(slugs).size).toBe(slugs.length); + }); +}); diff --git a/__tests__/jsonld/graph-validation.test.ts b/__tests__/jsonld/graph-validation.test.ts new file mode 100644 index 0000000..04dd6a3 --- /dev/null +++ b/__tests__/jsonld/graph-validation.test.ts @@ -0,0 +1,85 @@ +/** + * JSON-LD Graph Validation Tests + * + * Tests for graph integrity - checking for missing references, + * nested entities, orphans, and duplicates. + */ + +import { findMissingReferences, findNestedEntities, findOrphans } from 'jsonldjs'; + +import { jsonldGraph } from '@/data/jsonld'; + +describe('JSON-LD Graph Validation', () => { + describe('findMissingReferences', () => { + it('should find missing references in the graph', () => { + const missingRefs = findMissingReferences(jsonldGraph); + + if (missingRefs.length > 0) { + console.log('Missing references found:', missingRefs.length); + console.log('First 10 missing references:', missingRefs.slice(0, 10)); + } + + expect(missingRefs.sort()).toMatchSnapshot(); + }); + }); + + describe('findNestedEntities', () => { + it('should find nested entities in the graph', () => { + const nestedEntities = findNestedEntities(jsonldGraph); + + const summary = nestedEntities.map((n) => ({ + parentId: n.parentId, + property: n.property, + hasId: n.hasId, + type: n.nestedEntity['@type'], + })); + + expect(summary).toMatchSnapshot(); + }); + }); + + describe('findOrphans', () => { + it('should find orphaned entities in the graph', () => { + const orphans = findOrphans(jsonldGraph); + + if (orphans.length > 0) { + console.log('Orphaned entities found:', orphans.length); + console.log('First 10 orphaned entities:', orphans.slice(0, 10)); + } + + expect(orphans.sort()).toMatchSnapshot(); + }); + }); + + describe('Graph Integrity', () => { + it('should track duplicate IDs in the graph', () => { + const ids = jsonldGraph.map((e) => e['@id']).filter(Boolean); + const duplicates = ids.filter((id, index) => ids.indexOf(id) !== index); + const uniqueDuplicates = [...new Set(duplicates)].sort(); + + expect(uniqueDuplicates).toEqual([]); + }); + + it('should have software:latex2js in the graph', () => { + const latex2js = jsonldGraph.find((e) => e['@id'] === 'software:latex2js'); + expect(latex2js).toBeDefined(); + expect(latex2js?.['@type']).toBe('SoftwareApplication'); + }); + + it('should have website:latex2js.com in the graph', () => { + const website = jsonldGraph.find((e) => e['@id'] === 'website:latex2js.com'); + expect(website).toBeDefined(); + expect(website?.['@type']).toBe('WebSite'); + }); + + it('should have no missing references', () => { + expect(findMissingReferences(jsonldGraph)).toEqual([]); + }); + + it('should have consistent entity count', () => { + expect({ + totalEntities: jsonldGraph.length, + }).toMatchSnapshot(); + }); + }); +}); diff --git a/assets/css/latex2js.css b/assets/css/latex2js.css deleted file mode 100644 index dc0d4f1..0000000 --- a/assets/css/latex2js.css +++ /dev/null @@ -1,75 +0,0 @@ -/* LaTeX2JS */ - -html, -body, -div, -svg { - -webkit-tap-highlight-color: rgba(0, 0, 0, 0); -} - -.pspicture { - position: relative; - margin: auto; -} - -.enumerate { - list-style: circle; - padding: 12px; -} - -span.tt { - font-family: courier; -} - -p.quotation { - padding: 0 0 0 15px; - margin: 0 0 20px; - font-size: 10pt; -} - -.nicebox { - margin-top: 20px; - min-height: 20px; - padding: 19px; - margin-bottom: 20px; - background-color: #f5f5f5; - border: 1px solid #e3e3e3; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); - -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); -} - -.latex-container { - max-width: 870px; - margin-right: auto; - margin-left: auto; -} - -@media (min-width: 768px) and (max-width: 979px) { - .latex-container { - width: 724px; - } -} - -@media (max-width: 767px) { - body { - padding-right: 20px; - padding-left: 20px; - } - .latex-container { - width: auto; - } -} - -@media (max-width: 979px) { - body { - padding-top: 0; - } -} - -pre { - overflow: auto; -} diff --git a/assets/css/website.css b/assets/css/website.css deleted file mode 100644 index 3d2326b..0000000 --- a/assets/css/website.css +++ /dev/null @@ -1,26 +0,0 @@ -body { - font-family: 'Arbutus Slab', 'Helvetica Neue', Helvetica, Arial, sans-serif; - color: #333333; -} -h2 { - font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; -} - -.centered { - max-width: 100%; - text-align: center; -} - -@media (min-width: 768px) { - .centered > img { - max-width: 600px; - } -} - -img { - height: auto; - max-width: 100%; - vertical-align: middle; - border: 0; - -ms-interpolation-mode: bicubic; -} diff --git a/assets/js/latex2html5.bundle.js b/assets/js/latex2html5.bundle.js deleted file mode 100644 index 8e1791b..0000000 --- a/assets/js/latex2html5.bundle.js +++ /dev/null @@ -1,2460 +0,0 @@ -(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.LaTeX2HTML5 = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i { - var m = line.match(/\\item (.*)/); - if (m) { - return '
  • ' + m[1] + '
  • '; - } - else { - return line; - } - }) - .join('\n'); - const ul = document.createElement('ul'); - ul.className = 'math'; - ul.innerHTML = lines; - return ul; -} - -},{}],2:[function(require,module,exports){ -"use strict"; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.default = render; -const macros_1 = __importDefault(require("@latex2js/macros")); -function render(_that) { - var div = document.createElement('div'); - div.id = 'latex-macros'; - div.style.display = 'none'; - div.className = 'verbatim'; - div.innerHTML = macros_1.default; - return div; -} - -},{"@latex2js/macros":14}],3:[function(require,module,exports){ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.default = render; -function render(that) { - const span = document.createElement('span'); - span.className = 'math'; - span.innerHTML = that.lines.join('\n'); - return span; -} - -},{}],4:[function(require,module,exports){ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.default = render; -function render(that) { - const span = document.createElement('span'); - span.className = 'math nicebox'; - span.innerHTML = that.lines.join('\n'); - return span; -} - -},{}],5:[function(require,module,exports){ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.default = render; -const pstricks_1 = require("@latex2js/pstricks"); -const utils_1 = require("@latex2js/utils"); -function render(that) { - const size = pstricks_1.psgraph.getSize.call(that); - const width = `${size.width}px`; - const height = `${size.height}px`; - const div = document.createElement('div'); - div.className = 'pspicture'; - div.style.width = width; - div.style.height = height; - const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); - svg.setAttribute('width', width); - svg.setAttribute('height', height); - var svgEl = (0, utils_1.select)(svg); - that.$el = div; - pstricks_1.psgraph.pspicture.call(that, svgEl); - div.appendChild(svg); - const { env, plot } = that; - const { sliders } = env; - if (sliders && sliders.length) { - sliders.forEach((slider) => { - const { latex, scalar, variable, value, min, max } = slider; - const onChange = (event) => { - const target = event.target; - var val = Number(target.value) / scalar; - if (!env.variables) - env.variables = {}; - env.variables[variable] = val; - svgEl.selectAll('.psplot').remove(); - Object.entries(plot).forEach(([k, plotData]) => { - if (k.match(/psplot/)) { - plotData.forEach((data) => { - const d = data.fn.call(data.env, data.match); - if (pstricks_1.psgraph[k] && d && svgEl) { - pstricks_1.psgraph[k].call(d, svgEl); - } - }); - } - }); - }; - const label = document.createElement('label'); - const text = document.createTextNode(latex); - const input = document.createElement('input'); - input.setAttribute('min', String(min * scalar)); - input.setAttribute('max', String(max * scalar)); - input.setAttribute('type', 'range'); - input.setAttribute('value', value); - label.appendChild(text); - label.appendChild(input); - div.appendChild(label); - input.addEventListener('input', (event) => { - onChange(event); - }); - }); - } - return div; -} - -},{"@latex2js/pstricks":16,"@latex2js/utils":20}],6:[function(require,module,exports){ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.default = render; -function render(that) { - var pre = document.createElement('pre'); - pre.className = 'verbatim'; - pre.innerHTML = that.lines.join('\n'); - return pre; -} - -},{}],7:[function(require,module,exports){ -"use strict"; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.init = exports.macros = exports.math = exports.verbatim = exports.enumerate = exports.nicebox = exports.pspicture = void 0; -exports.default = render; -const latex2js_1 = __importDefault(require("latex2js")); -const mathjaxjs_1 = require("mathjaxjs"); -const pspicture_js_1 = __importDefault(require("./components/pspicture.js")); -exports.pspicture = pspicture_js_1.default; -const nicebox_js_1 = __importDefault(require("./components/nicebox.js")); -exports.nicebox = nicebox_js_1.default; -const enumerate_js_1 = __importDefault(require("./components/enumerate.js")); -exports.enumerate = enumerate_js_1.default; -const verbatim_js_1 = __importDefault(require("./components/verbatim.js")); -exports.verbatim = verbatim_js_1.default; -const math_js_1 = __importDefault(require("./components/math.js")); -exports.math = math_js_1.default; -const macros_1 = __importDefault(require("./components/macros")); -exports.macros = macros_1.default; -const ELEMENTS = { pspicture: pspicture_js_1.default, nicebox: nicebox_js_1.default, enumerate: enumerate_js_1.default, verbatim: verbatim_js_1.default, math: math_js_1.default, macros: macros_1.default }; -function render(tex, resolve) { - const done = () => { - const latex = new latex2js_1.default(); - const parsed = latex.parse(tex); - const div = document.createElement('div'); - div.className = 'latex-container'; - parsed && - parsed.forEach && - parsed.forEach((el) => { - if (ELEMENTS.hasOwnProperty(el.type)) { - const elementType = el.type; - div.appendChild(ELEMENTS[elementType](el)); - } - }); - resolve(div); - }; - if ((0, mathjaxjs_1.getMathJax)()) { - return done(); - } - (0, mathjaxjs_1.loadMathJax)(done); -} -const init = () => { - (0, mathjaxjs_1.loadMathJax)(); - document.querySelectorAll('script[type="text/latex"]').forEach((el) => { - render(el.innerHTML, (div) => { - if (el.parentNode) { - el.parentNode.insertBefore(div, el.nextSibling); - } - }); - }); -}; -exports.init = init; - -},{"./components/enumerate.js":1,"./components/macros":2,"./components/math.js":3,"./components/nicebox.js":4,"./components/pspicture.js":5,"./components/verbatim.js":6,"latex2js":8,"mathjaxjs":15}],8:[function(require,module,exports){ -"use strict"; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -const text_1 = __importDefault(require("./lib/text")); -const headers_1 = __importDefault(require("./lib/headers")); -const pstricks_1 = require("@latex2js/pstricks"); -const environments_1 = __importDefault(require("./lib/environments")); -const ignore_1 = __importDefault(require("./lib/ignore")); -const parser_1 = __importDefault(require("./lib/parser")); -class LaTeX2HTML5 { - constructor(Text = text_1.default, Headers = headers_1.default, Environments = environments_1.default, Ignore = ignore_1.default, PSTricks = pstricks_1.pstricks, Views = {}) { - this.Text = Text; - this.Headers = Headers; - this.Environments = Environments; - this.Ignore = Ignore; - this.PSTricks = PSTricks; - this.Views = Views; - this.Delimiters = {}; - Environments.forEach((name) => { - this.addEnvironment(name); - }); - } - addEnvironment(name) { - var delim = { - begin: new RegExp('\\\\begin\\{' + name + '\\}'), - end: new RegExp('\\\\end\\{' + name + '\\}') - }; - this.Delimiters[name] = delim; - } - addView(name, _options) { - this.addEnvironment(name); - // var view = {}; - // this.Views[name] = this.BaseEnvView.extend(options); - } - addText(name, exp, func) { - this.Text.Expressions[name] = exp; - this.Text.Functions[name] = func; - } - addHeaders(name, begin, end) { - var exp = {}; - var beginHash = name + 'begin'; - var endHash = name + 'end'; - exp[beginHash] = new RegExp('\\\\begin\\{' + name + '\\}'); - exp[endHash] = new RegExp('\\\\end\\{' + name + '\\}'); - Object.assign(this.Headers.Expressions, exp); - var fns = {}; - fns[beginHash] = function () { - return begin || ''; - }; - fns[endHash] = function () { - return end || ''; - }; - Object.assign(this.Headers.Functions, fns); - } - getParser() { - return new parser_1.default(this); - } - parse(text) { - const parser = new parser_1.default(this); - const parsed = parser.parse(text); - parsed.forEach((element) => { - if (!element.hasOwnProperty('type')) { - throw new Error('no type!'); - } - // TODO implement rendering - }); - return parsed; - } -} -exports.default = LaTeX2HTML5; - -},{"./lib/environments":9,"./lib/headers":10,"./lib/ignore":11,"./lib/parser":12,"./lib/text":13,"@latex2js/pstricks":16}],9:[function(require,module,exports){ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const environments = ['pspicture', 'verbatim', 'enumerate', 'print', 'nicebox']; -exports.default = environments; - -},{}],10:[function(require,module,exports){ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.Functions = exports.Expressions = void 0; -exports.Expressions = { - bq: /\\begin\{quotation\}/, - claim: /\\begin\{claim\}/, - corollary: /\\begin\{corollary\}/, - definition: /\\begin\{definition\}/, - endclaim: /\\end\{claim\}/, - endcorallary: /\\end\{corallary\}/, - enddefinition: /\\end\{definition\}/, - endexample: /\\end\{example\}/, - endproblem: /\\end\{problem\}/, - endsolution: /\\end\{solution\}/, - endtheorem: /\\end\{theorem\}/, - eq: /\\end\{quotation\}/, - example: /\\begin\{example\}/, - problem: /\\begin\{problem\}/, - proof: /\\begin\{proof\}/, - qed: /\\end\{proof\}/, - solution: /\\begin\{solution\}/, - theorem: /\\begin\{theorem\}/ -}; -exports.Functions = { - bq: () => '

    ', - claim: () => '

    Claim

    ', - corollary: () => '

    Corollary

    ', - definition: () => '

    Definition

    ', - endclaim: () => '', - endcorollary: () => '', - enddefinition: () => '', - endexample: () => '', - endproblem: () => '', - endsolution: () => '', - endtheorem: () => '', - eq: () => '

    ', - example: () => '

    Example

    ', - problem: () => '

    Problem

    ', - proof: () => '

    Proof

    ', - qed: () => '$\\qed$', - solution: () => '

    Solution

    ', - theorem: () => '

    Theorem

    ' -}; -exports.default = { - Expressions: exports.Expressions, - Functions: exports.Functions -}; - -},{}],11:[function(require,module,exports){ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const ignore = [ - /^\%/, - /\\begin\{document\}/, - /\\end\{document\}/, - /\\begin\{interactive\}/, - /\\end\{interactive\}/, - /\\usepackage/, - /\\documentclass/, - /\\tableofcontents/, - /\\author/, - /\\date/, - /\\maketitle/, - /\\title/, - /\\pagestyle/, - /\\smallskip/, - /\\medskip/, - /\\bigskip/, - /\\nobreak/, - /\\begin\{center\}/, - /\\end\{center\}/ -]; -exports.default = ignore; - -},{}],12:[function(require,module,exports){ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class Parser { - constructor(LaTeX2JS) { - this.Ignore = LaTeX2JS.Ignore; - this.Delimiters = LaTeX2JS.Delimiters; - this.Text = LaTeX2JS.Text; - this.PSTricks = LaTeX2JS.PSTricks; - this.Headers = LaTeX2JS.Headers; - this.objects = []; - this.environment = null; - this.settings = this.PSTricks.Functions.psset.call(this, [ - '', - 'units=1cm,linecolor=black,linestyle=solid,fillstyle=none' - ]); - } - parse(text) { - if (!text) - return []; - var lines = text.split('\n'); - this.parseEnvText(lines); - this.parseEnv(lines); - this.objects.forEach((obj) => { - if (obj.type.match(/pspicture/)) { - obj.plot = this.parsePSTricks(obj.lines, obj.env); - } - }); - return this.objects; - } - newEnvironment(type) { - if (this.environment && this.environment.lines.length) { - this.environment.settings = { ...this.settings }; - this.objects.push(this.environment); - } - this.environment = { - type: type, - lines: [] - }; - } - pushLine(line) { - var add = true; - this.Ignore.forEach((exp) => { - if (exp.test(line)) { - add = false; - } - }); - if (add) { - if (typeof line === 'string' && line.trim().length) { - if (this.PSTricks.Expressions.psset.test(line)) { - this.parseUnits(line); - } - else { - this.environment.lines.push(line); - } - } - } - } - parseUnits(line) { - var m = line.match(this.PSTricks.Expressions.psset); - Object.assign(this.settings, this.PSTricks.Functions.psset.call(this, m)); - } - metaData(environment, line) { - if (this.PSTricks.Expressions.hasOwnProperty(environment)) { - this.environment.match = line.match(this.PSTricks.Expressions[environment]); - this.environment.env = this.PSTricks.Functions[environment].call(this.settings, this.environment.match); - if (environment.match(/pspicture/)) { - if (typeof this.environment.env.xunit === 'undefined') { - this.environment.env.xunit = this.settings.xunit; - } - if (typeof this.environment.env.yunit === 'undefined') { - this.environment.env.yunit = this.settings.yunit; - } - } - } - } - parseEnv(lines) { - this.objects = []; - this.environment = { - type: 'math', - lines: [] - }; - const Delimiters = this.Delimiters; - lines.forEach((line) => { - var isDelim = false; - Object.entries(Delimiters).forEach(([env, type]) => { - Object.entries(type).forEach(([k, delim]) => { - if (line.match(delim)) { - isDelim = true; - if (k.match(/begin/)) { - if (this.environment.type.match(/verbatim/)) { - isDelim = false; - } - else if (this.environment.type.match(/print/)) { - isDelim = false; - } - else { - this.newEnvironment(env); - this.metaData(env, line); - } - } - else if (k.match(/end/)) { - if (this.environment.type.match(/verbatim/)) { - if (env.match(/verbatim/)) { - this.newEnvironment('math'); - } - else { - isDelim = false; - } - } - else if (this.environment.type.match(/print/)) { - if (env.match(/print/)) { - this.newEnvironment('math'); - } - else { - isDelim = false; - } - } - else { - this.newEnvironment('math'); - } - } - } - }); - }); - if (!isDelim) - this.pushLine(line); // } - }); - // push last! - this.newEnvironment('math'); - } - parseEnvText(lines) { - var _env = 'math'; - const Delimiters = this.Delimiters; - lines.forEach((line, i) => { - var isDelim = false; - Object.entries(Delimiters).forEach(([env, type]) => { - Object.entries(type).forEach(([k, delim]) => { - if (line.match(delim)) { - isDelim = true; - if (k.match(/begin/)) { - if (!_env.match(/verbatim/)) { - _env = env; - } - else { - isDelim = false; - } - } - else if (k.match(/end/)) { - if (!_env.match(/verbatim/)) { - _env = 'math'; - } - else { - if (!env.match(/verbatim/)) { - isDelim = false; - } - else { - _env = 'math'; - } - } - } - } - }); - }); - if (!isDelim) { - if (!_env.match(/verbatim/)) { - lines[i] = this.parseText(line); - } - if (!line.trim().length) { - lines[i] = '
    '; - } - } - }); - } - parsePSExpression(line, exp, plot, k, env) { - var match = line.match(exp); - if (match) { - plot[k].push({ - data: this.PSTricks.Functions[k].call(env, match), - env: env, - match: match, - fn: this.PSTricks.Functions[k] - }); - return true; - } - return false; - } - parsePSVariables(line, exp, _plot, k, env) { - var match = line.match(exp); - if (match) { - if (k.match(/uservariable/)) { - var dd = this.PSTricks.Functions[k].call(env, match); - env.variables = env.variables || {}; - env.variables[dd.name] = dd.value; - } - } - } - parsePSTricks(lines, env) { - var plot = {}; - const entries = Object.entries(this.PSTricks.Expressions); - entries.forEach(([k, _exp]) => { - plot[k] = []; - }); - lines.forEach((line) => { - entries.forEach(([k, exp]) => { - this.parsePSVariables(line, exp, plot, k, env); - const result = this.parsePSExpression(line, exp, plot, k, env); - if (result && k === 'psaxes' && plot[k].length > 0) { - const axesData = plot[k][plot[k].length - 1].data; - if (axesData && axesData.dx !== undefined) { - env.dx = axesData.dx; - env.dy = axesData.dy; - env.origin = axesData.origin; - } - } - }); - }); - return plot; - } - parseTextExpression(line, exp, k, contents) { - var match = line.match(exp); - if (match) { - return this.Text.Functions[k].call(this, match, contents); - } - return contents; - } - parseHeadersExpression(line, exp, k, contents) { - var match = line.match(exp); - if (match) { - return this.Headers.Functions[k].call(this); - } - return contents; - } - parseText(line) { - var contents = line; - // TEXT - Object.entries(this.Text.Expressions).forEach(([k, exp]) => { - contents = this.parseTextExpression(line, exp, k, contents); - }); - // HEADERS - Object.entries(this.Headers.Expressions).forEach(([k, exp]) => { - contents = this.parseHeadersExpression(line, exp, k, contents); - }); - return contents; - } -} -exports.default = Parser; - -},{}],13:[function(require,module,exports){ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.Functions = exports.Expressions = void 0; -const utils_1 = require("@latex2js/utils"); -exports.Expressions = { - emph: /\\emph\{[^}]*\}/g, - bf: /\{*\\bf [^}]*\}/g, - rm: /\{*\\rm [^}]*\}/g, - sl: /\{*\\sl [^}]*\}/g, - it: /\{*\\it [^}]*\}/g, - tt: /\{*\\tt [^}]*\}/g, - mdash: /---/g, - ndash: /--/g, - openq: /``/g, - closeq: /''/g, - TeX: /\\TeX\\|\\TeX/g, - LaTeX: /\\LaTeX\\|\\LaTeX/g, - vspace: /\\vspace/g, - cite: /\\cite\[\d+\]\{[^}]*\}/g, - href: /\\href\{[^}]*\}\{[^}]*\}/g, - img: /\\img\{[^}]*\}/g, - set: /\\set\{[^}]*\}/g, - youtube: /\\youtube\{[^}]*\}/g, - euler: /Euler\^/g, -}; -exports.Functions = { - cite: function (m, contents) { - m.forEach((match) => { - var m2 = match.match(/\\cite\[(\d+)\]\{([^}]*)\}/); - var m = location.pathname.match(/\/books\/(\d+)\//); - var book_id = 0; - if (m) { - book_id = parseInt(m[1], 10); - } - contents = contents.replace(m2.input, '[p' + - m2[1] + - ']'); - }); - return contents; - }, - img: (0, utils_1.matchrepl)(/\\img\{([^}]*)\}/, function (m) { - return ('
    '); - }), - youtube: (0, utils_1.matchrepl)(/\\youtube\{([^}]*)\}/, function (m) { - return ('
    '); - }), - href: (0, utils_1.matchrepl)(/\\href\{([^}]*)\}\{([^}]*)\}/, function (m) { - return '' + m[2] + ''; - }), - set: (0, utils_1.matchrepl)(/\\set\{([^}]*)\}/, function (m) { - return '' + m[1] + ''; - }), - euler: (0, utils_1.simplerepl)(/Euler\^/, 'exp'), - emph: (0, utils_1.matchrepl)(/\{([^}]*)\}/, function (m) { - return '' + m[1] + ''; - }), - bf: (0, utils_1.matchrepl)(/\{*\\bf ([^}]*)\}/, function (m) { - return '' + m[1] + ''; - }), - rm: (0, utils_1.matchrepl)(/\{*\\rm ([^}]*)\}/, function (m) { - return '' + m[1] + ''; - }), - sl: (0, utils_1.matchrepl)(/\{*\\sl ([^}]*)\}/, function (m) { - return '' + m[1] + ''; - }), - it: (0, utils_1.matchrepl)(/\{*\\it ([^}]*)\}/, function (m) { - return '' + m[1] + ''; - }), - tt: (0, utils_1.matchrepl)(/\{*\\tt ([^}]*)\}/, function (m) { - return '' + m[1] + ''; - }), - ndash: (0, utils_1.simplerepl)(/--/g, '–'), - mdash: (0, utils_1.simplerepl)(/---/g, '—'), - openq: (0, utils_1.simplerepl)(/``/g, '“'), - closeq: (0, utils_1.simplerepl)(/''/g, '”'), - vspace: (0, utils_1.simplerepl)(/\\vspace/g, '
    '), - TeX: (0, utils_1.simplerepl)(/\\TeX\\|\\TeX/g, '$\\TeX$'), - LaTeX: (0, utils_1.simplerepl)(/\\LaTeX\\|\\LaTeX/g, '$\\LaTeX$'), -}; -exports.default = { - Expressions: exports.Expressions, - Functions: exports.Functions, -}; - -},{"@latex2js/utils":20}],14:[function(require,module,exports){ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.default = String.raw ` - $$ - % create the definition symbol - \def\bydef{\stackrel{\Delta}{=}} - %\def\circconv{\otimes} - \def\circconv{\circledast} - - \newcommand{\qed}{\mbox{ } \Box} - - - \newcommand{\infint}{\int_{-\infty}^{\infty}} - - % z transform - \newcommand{\ztp}{ ~~ \mathop{\mathcal{Z}}\limits_{\longleftrightarrow} ~~ } - \newcommand{\iztp}{ ~~ \mathop{\mathcal{Z}^{-1}}\limits_{\longleftrightarrow} ~~ } - % fourier transform pair - \newcommand{\ftp}{ ~~ \mathop{\mathcal{F}}\limits_{\longleftrightarrow} ~~ } - \newcommand{\iftp}{ ~~ \mathop{\mathcal{F}^{-1}}\limits_{\longleftrightarrow} ~~ } - % laplace transform - \newcommand{\ltp}{ ~~ \mathop{\mathcal{L}}\limits_{\longleftrightarrow} ~~ } - \newcommand{\iltp}{ ~~ \mathop{\mathcal{L}^{-1}}\limits_{\longleftrightarrow} ~~ } - - \newcommand{\ftrans}[1]{ \mathcal{F} \left\{#1\right\} } - \newcommand{\iftrans}[1]{ \mathcal{F}^{-1} \left\{#1\right\} } - \newcommand{\ztrans}[1]{ \mathcal{Z} \left\{#1\right\} } - \newcommand{\iztrans}[1]{ \mathcal{Z}^{-1} \left\{#1\right\} } - \newcommand{\ltrans}[1]{ \mathcal{L} \left\{#1\right\} } - \newcommand{\iltrans}[1]{ \mathcal{L}^{-1} \left\{#1\right\} } - - - % coordinate vector relative to a basis (linear algebra) - \newcommand{\cvrb}[2]{\left[ \vec{#1} \right]_{#2} } - % change of coordinate matrix (linear algebra) - \newcommand{\cocm}[2]{ \mathop{P}\limits_{#2 \leftarrow #1} } - % Transformed vector set - \newcommand{\tset}[3]{\{#1\lr{\vec{#2}_1}, #1\lr{\vec{#2}_2}, \dots, #1\lr{\vec{#2}_{#3}}\}} - % sum transformed vector set - \newcommand{\tsetcsum}[4]{{#1}_1#2(\vec{#3}_1) + {#1}_2#2(\vec{#3}_2) + \cdots + {#1}_{#4}#2(\vec{#3}_{#4})} - \newcommand{\tsetcsumall}[4]{#2\lr{{#1}_1\vec{#3}_1 + {#1}_2\vec{#3}_2 + \cdots + {#1}_{#4}\vec{#3}_{#4}}} - \newcommand{\cvecsum}[3]{{#1}_1\vec{#2}_1 + {#1}_2\vec{#2}_2 + \cdots + {#1}_{#3}\vec{#2}_{#3}} - - - % function def - \newcommand{\fndef}[3]{#1:#2 \to #3} - % vector set - \newcommand{\vset}[2]{\{\vec{#1}_1, \vec{#1}_2, \dots, \vec{#1}_{#2}\}} - % absolute value - \newcommand{\abs}[1]{\left| #1 \right|} - % vector norm - \newcommand{\norm}[1]{\left|\left| #1 \right|\right|} - % trans - \newcommand{\trans}{\mapsto} - % evaluate integral - \newcommand{\evalint}[3]{\left. #1 \right|_{#2}^{#3}} - % slist - \newcommand{\slist}[2]{{#1}_{1},{#1}_{2},\dots,{#1}_{#2}} - - % vectors - \newcommand{\vc}[1]{\textbf{#1}} - - % real - \newcommand{\Real}[1]{{\Re \mit{e}\left\{{#1}\right\}}} - % imaginary - \newcommand{\Imag}[1]{{\Im \mit{m}\left\{{#1}\right\}}} - - \newcommand{\mcal}[1]{\mathcal{#1}} - \newcommand{\bb}[1]{\mathbb{#1}} - \newcommand{\N}{\mathbb{N}} - \newcommand{\Z}{\mathbb{Z}} - \newcommand{\Q}{\mathbb{Q}} - \newcommand{\R}{\mathbb{R}} - \newcommand{\C}{\mathbb{C}} - \newcommand{\I}{\mathbb{I}} - \newcommand{\Th}[1]{\mathop\mathrm{Th(#1)}} - \newcommand{\intersect}{\cap} - \newcommand{\\union}{\cup} - \newcommand{\intersectop}{\bigcap} - \newcommand{\\unionop}{\bigcup} - \newcommand{\setdiff}{\backslash} - \newcommand{\iso}{\cong} - \newcommand{\aut}[1]{\mathop{\mathrm{Aut(#1)}}} - \newcommand{\inn}[1]{\mathop{\mathrm{Inn(#1)}}} - \newcommand{\Ann}[1]{\mathop{\mathrm{Ann(#1)}}} - \newcommand{\dom}[1]{\mathop{\mathrm{dom} #1}} - \newcommand{\cod}[1]{\mathop{\mathrm{cod} #1}} - \newcommand{\id}{\mathrm{id}} - \newcommand{\st}{\ |\ } - \newcommand{\mbf}[1]{\mathbf{#1}} - \newcommand{\enclose}[1]{\left\langle #1\right\rangle} - \newcommand{\lr}[1]{\left( #1\right)} - \newcommand{\lrsq}[1]{\left[ #1\right]} - \newcommand{\op}{\mathrm{op}} - \newcommand{\dotarr}{\dot{\rightarrow}} - %Category Names: - \newcommand{\Grp}{\mathbf{Grp}} - \newcommand{\Ab}{\mathbf{Ab}} - \newcommand{\Set}{\mathbf{Set}} - \newcommand{\Matr}{\mathbf{Matr}} - \newcommand{\IntDom}{\mathbf{IntDom}} - \newcommand{\Field}{\mathbf{Field}} - \newcommand{\Vect}{\mathbf{Vect}} - - \newcommand{\thm}[1]{\begin{theorem} #1 \end{theorem}} - \newcommand{\clm}[1]{\begin{claim} #1 \end{claim}} - \newcommand{\cor}[1]{\begin{corollary} #1 \end{corollary}} - \newcommand{\ex}[1]{\begin{example} #1 \end{example}} - \newcommand{\prf}[1]{\begin{proof} #1 \end{proof}} - \newcommand{\prbm}[1]{\begin{problem} #1 \end{problem}} - \newcommand{\soln}[1]{\begin{solution} #1 \end{solution}} - \newcommand{\rmk}[1]{\begin{remark} #1 \end{remark}} - \newcommand{\defn}[1]{\begin{definition} #1 \end{definition}} - - \newcommand{\ifff}{\LeftRightArrow} - - - \newcommand{\rr}{\R} - \newcommand{\reals}{\R} - \newcommand{\ii}{\Z} - \newcommand{\cc}{\C} - \newcommand{\nn}{\N} - \newcommand{\nats}{\N} - - - - - \newcommand{\strong}[1]{\textbf{#1}} - - - \newcommand{\set}[1]{\textit{#1}} - - $$ - `; - -},{}],15:[function(require,module,exports){ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.loadMathJax = exports.getMathJax = exports.DEFAULT_CONFIG = void 0; -exports.DEFAULT_CONFIG = { - tex: { - inlineMath: [['$', '$'], ['\\(', '\\)']], - displayMath: [['$$', '$$'], ['\\[', '\\]']], - processEscapes: true, - processEnvironments: true, - packages: ['base', 'ams', 'newcommand', 'configmacros'] - }, - chtml: { - linebreaks: { automatic: true, width: 'container' } - }, - startup: { - ready: () => { - console.log('MathJax v3 startup ready'); - } - } -}; -let mathJaxInstance = null; -const getMathJax = () => mathJaxInstance || globalThis.MathJax; -exports.getMathJax = getMathJax; -const loadMathJax = async (callback = () => { }, config = exports.DEFAULT_CONFIG) => { - if (typeof window === 'undefined') { - callback(); - return; - } - if (globalThis.MathJax) { - mathJaxInstance = globalThis.MathJax; - callback(); - return; - } - try { - globalThis.MathJax = { - ...config, - startup: { - ...config.startup, - ready: () => { - globalThis.MathJax.startup.defaultReady(); - mathJaxInstance = globalThis.MathJax; - if (config.startup?.ready) { - config.startup.ready(); - } - callback(); - } - } - }; - const script = document.createElement('script'); - script.src = 'https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js'; - script.async = true; - script.id = 'MathJax-script'; - script.onload = () => { - console.log('MathJax v3 script loaded from CDN'); - }; - script.onerror = () => { - console.error('Failed to load MathJax v3 from CDN'); - callback(); - }; - document.head.appendChild(script); - } - catch (error) { - console.error('Failed to load MathJax v3:', error); - callback(); - } -}; -exports.loadMathJax = loadMathJax; - -},{}],16:[function(require,module,exports){ -"use strict"; -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - var desc = Object.getOwnPropertyDescriptor(m, k); - if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { - desc = { enumerable: true, get: function() { return m[k]; } }; - } - Object.defineProperty(o, k2, desc); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -var __importStar = (this && this.__importStar) || (function () { - var ownKeys = function(o) { - ownKeys = Object.getOwnPropertyNames || function (o) { - var ar = []; - for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; - return ar; - }; - return ownKeys(o); - }; - return function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); - __setModuleDefault(result, mod); - return result; - }; -})(); -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.arrow = exports.psgraph = exports.pstricks = void 0; -const pstricks_1 = __importDefault(require("./lib/pstricks")); -exports.pstricks = pstricks_1.default; -const psgraph_1 = __importStar(require("./lib/psgraph")); -exports.psgraph = psgraph_1.default; -Object.defineProperty(exports, "arrow", { enumerable: true, get: function () { return psgraph_1.arrow; } }); -exports.default = { - pstricks: pstricks_1.default, - psgraph: psgraph_1.default, - arrow: psgraph_1.arrow, -}; - -},{"./lib/psgraph":17,"./lib/pstricks":18}],17:[function(require,module,exports){ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.arrow = arrow; -const utils_1 = require("@latex2js/utils"); -function arrow(x1, y1, x2, y2) { - var t = Math.PI / 6; - var d = 8; - var dx = x2 - x1, dy = y2 - y1; - var l = Math.sqrt(dx * dx + dy * dy); - var cost = Math.cos(t); - var sint = Math.sin(t); - var dl = d / l; - var x = x2 - (dx * cost - dy * sint) * dl; - var y = y2 - (dy * cost + dx * sint) * dl; - var context = []; - context.push('M'); - context.push(x2); - context.push(y2); - context.push('L'); - context.push(x); - context.push(y); - cost = Math.cos(-t); - sint = Math.sin(-t); - x = x2 - (dx * cost - dy * sint) * dl; - y = y2 - (dy * cost + dx * sint) * dl; - context.push(x); - context.push(y); - context.push('Z'); - return context.join(' '); -} -const psgraph = { - env: null, - getSize() { - const padding = 20; - this.env.scale = 1; - const goalWidth = Math.max(document.documentElement.clientWidth, window.innerWidth || 0) - - padding; - if (goalWidth <= this.env.w * this.env.xunit) { - this.env.scale = goalWidth / this.env.w / this.env.xunit; - } - const width = this.env.w * this.env.xunit; - const height = this.env.h * this.env.yunit; - return { - width, - height - }; - }, - psframe(svg) { - svg - .append('svg:line') - .attr('x1', this.x1) - .attr('y1', this.y1) - .attr('x2', this.x2) - .attr('y2', this.y1) - .style('stroke-width', 2) - .style('stroke', 'rgb(0,0,0)') - .style('stroke-opacity', 1); - svg - .append('svg:line') - .attr('x1', this.x2) - .attr('y1', this.y1) - .attr('x2', this.x2) - .attr('y2', this.y2) - .style('stroke-width', 2) - .style('stroke', 'rgb(0,0,0)') - .style('stroke-opacity', 1); - svg - .append('svg:line') - .attr('x1', this.x2) - .attr('y1', this.y2) - .attr('x2', this.x1) - .attr('y2', this.y2) - .style('stroke-width', 2) - .style('stroke', 'rgb(0,0,0)') - .style('stroke-opacity', 1); - svg - .append('svg:line') - .attr('x1', this.x1) - .attr('y1', this.y2) - .attr('x2', this.x1) - .attr('y2', this.y1) - .style('stroke-width', 2) - .style('stroke', 'rgb(0,0,0)') - .style('stroke-opacity', 1); - }, - pscircle: function (svg) { - svg - .append('svg:circle') - .attr('cx', this.cx) - .attr('cy', this.cy) - .attr('r', this.r) - .style('stroke', 'black') - .style('fill', 'none') - .style('stroke-width', 2) - .style('stroke-opacity', 1); - }, - psplot(svg) { - var context = []; - context.push('M'); - if (this.fillstyle === 'solid') { - context.push(this.data[0]); - context.push(utils_1.Y.call(this.global, 0)); - } - else { - context.push(this.data[0]); - context.push(this.data[1]); - } - context.push('L'); - this.data.forEach((data) => { - context.push(data); - }); - if (this.fillstyle === 'solid') { - context.push(this.data[this.data.length - 2]); - context.push(utils_1.Y.call(this.global, 0)); - context.push('Z'); - } - svg - .append('svg:path') - .attr('d', context.join(' ')) - .attr('class', 'psplot') - .style('stroke-width', this.linewidth) - .style('stroke-opacity', 1) - .style('fill', this.fillstyle === 'none' ? 'none' : this.fillcolor) - .style('stroke', this.linecolor); - }, - pspolygon(svg) { - var context = []; - context.push('M'); - context.push(this.data[0]); - context.push(this.data[1]); - context.push('L'); - this.data.forEach((data) => { - context.push(data); - }); - context.push('Z'); - svg - .append('svg:path') - .attr('d', context.join(' ')) - .style('stroke-width', this.linewidth) - .style('stroke-opacity', 1) - .style('fill', this.fillstyle === 'none' ? 'none' : this.fillcolor) - .style('stroke', 'black'); - }, - psarc(svg) { - var context = []; - context.push('M'); - context.push(this.cx); - context.push(this.cy); - context.push('L'); - context.push(this.A.x); - context.push(this.A.y); - context.push('A'); - context.push(this.A.x); - context.push(this.A.y); - context.push(0); - context.push(0); - context.push(0); - context.push(this.B.x); - context.push(this.B.y); - svg - .append('svg:path') - .attr('d', context.join(' ')) - .style('stroke-width', 2) - .style('stroke-opacity', 1) - .style('fill', 'blue') - .style('stroke', 'black'); - }, - psaxes(svg) { - var xaxis = [this.bottomLeft[0], this.topRight[0]]; - var yaxis = [this.bottomLeft[1], this.topRight[1]]; - var origin = this.origin; - function line(x1, y1, x2, y2) { - svg - .append('svg:path') - .attr('d', 'M ' + x1 + ' ' + y1 + ' L ' + x2 + ' ' + y2) - .style('stroke-width', 2) - .style('stroke', 'rgb(0,0,0)') - .style('stroke-opacity', 1); - } - var xticks = () => { - for (var x = xaxis[0]; x <= xaxis[1]; x += this.dx) { - line(x, origin[1] - 5, x, origin[1] + 5); - } - }; - var yticks = () => { - for (var y = yaxis[0]; y <= yaxis[1]; y += this.dy) { - line(origin[0] - 5, y, origin[0] + 5, y); - } - }; - line(xaxis[0], origin[1], xaxis[1], origin[1]); - line(origin[0], yaxis[0], origin[0], yaxis[1]); - if (this.ticks.match(/all/)) { - xticks(); - yticks(); - } - else if (this.ticks.match(/x/)) { - xticks(); - } - else if (this.ticks.match(/y/)) { - yticks(); - } - if (this.arrows[0]) { - svg - .append('path') - .attr('d', arrow(xaxis[1], origin[1], xaxis[0], origin[1])) - .style('fill', 'black') - .style('stroke', 'black'); - svg - .append('path') - .attr('d', arrow(origin[0], yaxis[1], origin[0], yaxis[0])) - .style('fill', 'black') - .style('stroke', 'black'); - } - if (this.arrows[1]) { - svg - .append('path') - .attr('d', arrow(xaxis[0], origin[1], xaxis[1], origin[1])) - .style('fill', 'black') - .style('stroke', 'black'); - svg - .append('path') - .attr('d', arrow(origin[0], yaxis[0], origin[0], yaxis[1])) - .style('fill', 'black') - .style('stroke', 'black'); - } - }, - psline(svg) { - var linewidth = this.linewidth, linecolor = this.linecolor; - function solid(x1, y1, x2, y2) { - svg - .append('svg:path') - .attr('d', 'M ' + x1 + ' ' + y1 + ' L ' + x2 + ' ' + y2) - .style('stroke-width', linewidth) - .style('stroke', linecolor) - .style('stroke-opacity', 1); - } - function dashed(x1, y1, x2, y2) { - svg - .append('svg:path') - .attr('d', 'M ' + x1 + ' ' + y1 + ' L ' + x2 + ' ' + y2) - .style('stroke-width', linewidth) - .style('stroke', linecolor) - .style('stroke-dasharray', '9,5') - .style('stroke-opacity', 1); - } - function dotted(x1, y1, x2, y2) { - svg - .append('svg:path') - .attr('d', 'M ' + x1 + ' ' + y1 + ' L ' + x2 + ' ' + y2) - .style('stroke-width', linewidth) - .style('stroke', linecolor) - .style('stroke-dasharray', '9,5') - .style('stroke-opacity', 1); - } - if (this.linestyle.match(/dotted/)) { - dotted(this.x1, this.y1, this.x2, this.y2); - } - else if (this.linestyle.match(/dashed/)) { - dashed(this.x1, this.y1, this.x2, this.y2); - } - else { - solid(this.x1, this.y1, this.x2, this.y2); - } - if (this.dots[0]) { - svg - .append('svg:circle') - .attr('cx', this.x1) - .attr('cy', this.y1) - .attr('r', 3) - .style('stroke', this.linecolor) - .style('fill', this.linecolor) - .style('stroke-width', 1) - .style('stroke-opacity', 1); - } - if (this.dots[1]) { - svg - .append('svg:circle') - .attr('cx', this.x2) - .attr('cy', this.y2) - .attr('r', 3) - .style('stroke', this.linecolor) - .style('fill', this.linecolor) - .style('stroke-width', 1) - .style('stroke-opacity', 1); - } - var x1 = this.x1, y1 = this.y1, x2 = this.x2, y2 = this.y2; - if (this.arrows[0]) { - svg - .append('path') - .attr('d', arrow(x2, y2, x1, y1)) - .style('fill', this.linecolor) - .style('stroke', this.linecolor); - } - if (this.arrows[1]) { - svg - .append('path') - .attr('d', arrow(x1, y1, x2, y2)) - .style('fill', this.linecolor) - .style('stroke', this.linecolor); - } - }, - userline(svg) { - var linewidth = this.linewidth, linecolor = this.linecolor; - function solid(x1, y1, x2, y2) { - svg - .append('svg:path') - .attr('class', 'userline') - .attr('d', 'M ' + x1 + ' ' + y1 + ' L ' + x2 + ' ' + y2) - .style('stroke-width', linewidth) - .style('stroke', linecolor) - .style('stroke-opacity', 1); - } - function dashed(x1, y1, x2, y2) { - svg - .append('svg:path') - .attr('d', 'M ' + x1 + ' ' + y1 + ' L ' + x2 + ' ' + y2) - .attr('class', 'userline') - .style('stroke-width', linewidth) - .style('stroke', linecolor) - .style('stroke-dasharray', '9,5') - .style('stroke-opacity', 1); - } - function dotted(x1, y1, x2, y2) { - svg - .append('svg:path') - .attr('d', 'M ' + x1 + ' ' + y1 + ' L ' + x2 + ' ' + y2) - .attr('class', 'userline') - .style('stroke-width', linewidth) - .style('stroke', linecolor) - .style('stroke-dasharray', '9,5') - .style('stroke-opacity', 1); - } - if (this.linestyle.match(/dotted/)) { - dotted(this.x1, this.y1, this.x2, this.y2); - } - else if (this.linestyle.match(/dashed/)) { - dashed(this.x1, this.y1, this.x2, this.y2); - } - else { - solid(this.x1, this.y1, this.x2, this.y2); - } - if (this.dots[0]) { - svg - .append('svg:circle') - .attr('cx', this.x1) - .attr('cy', this.y1) - .attr('r', 3) - .attr('class', 'userline') - .style('stroke', this.linecolor) - .style('fill', this.linecolor) - .style('stroke-width', 1) - .style('stroke-opacity', 1); - } - if (this.dots[1]) { - svg - .append('svg:circle') - .attr('cx', this.x2) - .attr('cy', this.y2) - .attr('r', 3) - .attr('class', 'userline') - .style('stroke', this.linecolor) - .style('fill', this.linecolor) - .style('stroke-width', 1) - .style('stroke-opacity', 1); - } - var x1 = this.x1, y1 = this.y1, x2 = this.x2, y2 = this.y2; - if (this.arrows[0]) { - svg - .append('path') - .attr('d', arrow(x2, y2, x1, y1)) - .attr('class', 'userline') - .style('fill', this.linecolor) - .style('stroke', this.linecolor); - } - if (this.arrows[1]) { - svg - .append('path') - .attr('d', arrow(x1, y1, x2, y2)) - .attr('class', 'userline') - .style('fill', this.linecolor) - .style('stroke', this.linecolor); - } - }, - rput(el) { - // Import debug utilities - const startTime = Date.now(); - // Validate coordinates - const x = this.x; - const y = this.y; - if (typeof x !== 'number' || typeof y !== 'number' || isNaN(x) || isNaN(y)) { - console.warn('RPUT: Invalid coordinates detected', { x, y, text: this.text }); - return; - } - // Validate parent container - if (!el || !el.appendChild) { - console.warn('RPUT: Invalid parent container provided'); - return; - } - // Validate content - if (!this.text || typeof this.text !== 'string') { - console.warn('RPUT: Invalid text content', { text: this.text }); - return; - } - const div = document.createElement('div'); - // Set up element with improved styling for better measurement - div.className = 'math'; - div.style.position = 'absolute'; - div.style.visibility = 'hidden'; - div.style.whiteSpace = 'nowrap'; // Prevent text wrapping during measurement - div.style.top = `${y}px`; - div.style.left = `${x}px`; - div.style.pointerEvents = 'none'; // Prevent interference during positioning - // Add data attributes for debugging - div.setAttribute('data-rput-x', x.toString()); - div.setAttribute('data-rput-y', y.toString()); - div.setAttribute('data-rput-text', this.text); - // Enhanced positioning function with better measurement - const positionElement = () => { - return new Promise((resolve) => { - // Use requestAnimationFrame to ensure DOM has been updated - requestAnimationFrame(() => { - try { - // Get accurate bounding box - const rect = div.getBoundingClientRect(); - // Validate measurements - if (rect.width === 0 || rect.height === 0) { - console.warn('RPUT: Element has zero dimensions, retrying...', { - text: this.text, - rect: { width: rect.width, height: rect.height } - }); - // Retry measurement after a short delay - setTimeout(() => { - const retryRect = div.getBoundingClientRect(); - const w = retryRect.width / 2; - const h = retryRect.height / 2; - // Apply centering with fallback for zero dimensions - div.style.top = `${y - (h || 10)}px`; - div.style.left = `${x - (w || 20)}px`; - div.style.visibility = 'visible'; - div.style.pointerEvents = 'auto'; - resolve(); - }, 10); - return; - } - // Calculate center offsets - const centerX = rect.width / 2; - const centerY = rect.height / 2; - // Apply precise centering - div.style.top = `${y - centerY}px`; - div.style.left = `${x - centerX}px`; - div.style.visibility = 'visible'; - div.style.pointerEvents = 'auto'; - resolve(); - } - catch (error) { - console.error('RPUT: Error during positioning', error); - // Fallback positioning - div.style.top = `${y}px`; - div.style.left = `${x}px`; - div.style.visibility = 'visible'; - div.style.pointerEvents = 'auto'; - resolve(); - } - }); - }); - }; - // Enhanced MathJax processing with better async handling - const processContent = async () => { - const mathJax = window.MathJax; - if (mathJax && mathJax.typesetPromise) { - try { - // Set content before MathJax processing - div.innerHTML = this.text; - // Process with MathJax - await mathJax.typesetPromise([div]); - // Wait for MathJax to complete rendering - await new Promise(resolve => setTimeout(resolve, 0)); - // Position element after MathJax is complete - await positionElement(); - } - catch (error) { - console.error('MathJax typesetting failed:', error); - // Fallback to plain HTML - div.innerHTML = this.text; - await positionElement(); - } - } - else { - // No MathJax available, use plain HTML - div.innerHTML = this.text; - await positionElement(); - } - }; - // Ensure parent is ready before appending - if (el.isConnected === false) { - console.warn('RPUT: Parent container not connected to DOM'); - } - // Append to DOM - el.appendChild(div); - // Process content asynchronously - processContent().catch((error) => { - console.error('RPUT: Failed to process content', error); - // Emergency fallback - div.style.visibility = 'visible'; - div.style.pointerEvents = 'auto'; - }); - }, - pspicture(svg) { - var env = this.env; - var el = this.$el; - Object.keys(this.plot).forEach((key) => { - const plot = this.plot[key]; - if (key.match(/rput/)) - return; - if (psgraph.hasOwnProperty(key)) { - plot.forEach((data) => { - data.data.global = env; - psgraph[key].call(data.data, svg); - }); - } - }); - svg.on('touchmove', function (event) { - event.preventDefault(); - var touch = event.touches ? event.touches[0] : null; - var rect = event.target.getBoundingClientRect(); - var touchcoords = touch ? [touch.clientX - rect.left, touch.clientY - rect.top] : [0, 0]; - userEvent(touchcoords); - }); - svg.on('mousemove', function (event) { - var coords = [event.offsetX || 0, event.offsetY || 0]; - userEvent(coords); - }); - const plots = this.plot; - function userEvent(coords) { - svg.selectAll('.userline').remove(); - svg.selectAll('.psplot').remove(); - var currentEnvironment = {}; - Object.entries(plots || {}) - .forEach(([k, plot]) => { - if (k.match(/uservariable/)) { - plot.forEach((data) => { - data.env.userx = coords[0]; - data.env.usery = coords[1]; - var dd = data.fn.call(data.env, data.match); - currentEnvironment[data.data.name] = dd.value; - }); - } - }); - Object.entries(plots || {}) - .forEach(([k, plot]) => { - if (k.match(/psplot/)) { - plot.forEach((data) => { - Object.entries(currentEnvironment || {}) - .forEach(([name, variable]) => { - data.env.variables[name] = variable; - }); - var d = data.fn.call(data.env, data.match); - d.global = {}; - Object.assign(d.global, env); - psgraph[k].call(d, svg); - }); - } - if (k.match(/userline/)) { - plot.forEach((data) => { - var d = data.fn.call(data.env, data.match); - data.env.x2 = coords[0]; - data.env.y2 = coords[1]; - data.data.x2 = data.env.x2; - data.data.y2 = data.env.y2; - if (data.data.xExp2) { - data.data.x2 = d.userx2(coords); - data.data.x1 = d.userx(coords); - } - else if (data.data.xExp) { - data.data.x2 = d.userx(coords); - } - if (data.data.yExp2) { - data.data.y2 = d.usery2(coords); - data.data.y1 = d.usery(coords); - } - else if (data.data.yExp) { - data.data.y2 = d.usery(coords); - } - d.global = {}; - Object.assign(d.global, env); - Object.assign(d, data.data); - psgraph[k].call(d, svg); - }); - } - }); - } - // Enhanced cleanup and RPUT processing - psgraph.processRputElements.call(this, el); - }, - processRputElements(el) { - // Validate container - if (!el || typeof el.querySelectorAll !== 'function') { - console.warn('RPUT: Invalid container for RPUT processing'); - return; - } - // Validate RPUT data - if (!this.plot || !Array.isArray(this.plot.rput)) { - console.warn('RPUT: No RPUT data to process'); - return; - } - // Enhanced cleanup with better error handling - try { - // Remove existing RPUT elements - const existingElements = el.querySelectorAll('.math[data-rput-x]'); - let cleanupCount = 0; - existingElements.forEach((element) => { - try { - // Clean up any pending async operations - element.style.visibility = 'hidden'; - element.remove(); - cleanupCount++; - } - catch (error) { - console.warn('RPUT: Error removing existing element', error); - } - }); - if (cleanupCount > 0) { - console.log(`RPUT: Cleaned up ${cleanupCount} existing elements`); - } - // Wait for DOM to settle after cleanup - requestAnimationFrame(() => { - psgraph.renderRputElements.call(this, el); - }); - } - catch (error) { - console.error('RPUT: Error during cleanup', error); - // Fallback to immediate rendering - psgraph.renderRputElements.call(this, el); - } - }, - renderRputElements(el) { - if (!this.plot?.rput || this.plot.rput.length === 0) { - return; - } - // Track rendering for debugging - console.log(`RPUT: Rendering ${this.plot.rput.length} elements`); - // Process RPUT elements with better error isolation - const renderPromises = []; - this.plot.rput.forEach((rput, index) => { - try { - // Validate RPUT data - if (!rput || !rput.data) { - console.warn(`RPUT: Invalid RPUT data at index ${index}`, rput); - return; - } - // Add global context - rput.data.global = this.env; - // Create a promise for this RPUT element - const renderPromise = new Promise((resolve) => { - try { - // Use setTimeout to prevent blocking the main thread - setTimeout(() => { - psgraph.rput.call(rput.data, el); - resolve(); - }, index * 10); // Stagger rendering slightly - } - catch (error) { - console.error(`RPUT: Error rendering element ${index}`, error); - resolve(); - } - }); - renderPromises.push(renderPromise); - } - catch (error) { - console.error(`RPUT: Error processing element ${index}`, error); - } - }); - // Wait for all RPUT elements to be processed - Promise.all(renderPromises) - .then(() => { - console.log('RPUT: All elements rendered successfully'); - }) - .catch((error) => { - console.error('RPUT: Error in batch rendering', error); - }); - } -}; -exports.default = psgraph; - -},{"@latex2js/utils":20}],18:[function(require,module,exports){ -"use strict"; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.Functions = exports.Expressions = void 0; -const utils_1 = require("@latex2js/utils"); -const settings_1 = __importDefault(require("@latex2js/settings")); -exports.Expressions = { - pspicture: /\\begin\{pspicture\}\(\s*(.*),(.*)\s*\)\(\s*(.*),(.*)\s*\)/, - psframe: /\\psframe\(\s*(.*),(.*)\s*\)\(\s*(.*),(.*)\s*\)/, - psplot: /\\psplot(\[[^\]]*\])?\{([^\}]*)\}\{([^\}]*)\}\{([^\}]*)\}/, - psarc: new RegExp('\\\\psarc' + - utils_1.RE.options + - utils_1.RE.type + - utils_1.RE.coords + - utils_1.RE.squiggle + - utils_1.RE.squiggle + - utils_1.RE.squiggle), - pscircle: /\\pscircle.*\(\s*(.*),(.*)\s*\)\{(.*)\}/, - pspolygon: new RegExp('\\\\pspolygon' + utils_1.RE.options + '(.*)'), - psaxes: new RegExp('\\\\psaxes' + - utils_1.RE.options + - utils_1.RE.type + - utils_1.RE.coords + - utils_1.RE.coordsOpt + - utils_1.RE.coordsOpt), - slider: new RegExp('\\\\slider' + - utils_1.RE.options + - utils_1.RE.squiggle + - utils_1.RE.squiggle + - utils_1.RE.squiggle + - utils_1.RE.squiggle + - utils_1.RE.squiggle), - psline: new RegExp('\\\\psline' + utils_1.RE.options + utils_1.RE.type + utils_1.RE.coords + utils_1.RE.coordsOpt), - userline: new RegExp('\\\\userline' + - utils_1.RE.options + - utils_1.RE.type + - utils_1.RE.coords + - utils_1.RE.coords + - utils_1.RE.squiggleOpt + - utils_1.RE.squiggleOpt + - utils_1.RE.squiggleOpt + - utils_1.RE.squiggleOpt), - uservariable: new RegExp('\\\\uservariable' + utils_1.RE.options + utils_1.RE.squiggle + utils_1.RE.coords + utils_1.RE.squiggle), - rput: /\\rput\((.*),(.*)\)\{(.*)\}/, - psset: /\\psset\{(.*)\}/ -}; -exports.Functions = { - slider(m) { - var obj = { - scalar: 1, - min: Number(m[2]), - max: Number(m[3]), - variable: m[4], - latex: m[5], - value: Number(m[6]) - }; - this.variables = this.variables || {}; - this.variables[obj.variable] = obj.value; - this.sliders = this.sliders || []; - this.sliders.push(obj); - if (m[1]) { - Object.assign(obj, (0, utils_1.parseOptions)(m[1])); - } - return obj; - }, - pspicture(m) { - var p = { - x0: Number(m[1]), - y0: Number(m[2]), - x1: Number(m[3]), - y1: Number(m[4]) - }; - var s = { - w: p.x1 - p.x0, - h: p.y1 - p.y0 - }; - Object.assign(this, p, s); - return Object.assign(p, s); - }, - psframe(m) { - var obj = { - x1: utils_1.X.call(this, m[1]), - y1: utils_1.Y.call(this, m[2]), - x2: utils_1.X.call(this, m[3]), - y2: utils_1.Y.call(this, m[4]) - }; - return obj; - }, - pscircle(m) { - var obj = { - cx: utils_1.X.call(this, m[1]), - cy: utils_1.Y.call(this, m[2]), - r: this.xunit * m[3] - }; - return obj; - }, - psaxes(m) { - var obj = { - dx: 1 * this.xunit, - dy: 1 * this.yunit, - arrows: [0, 0], - dots: [0, 0], - ticks: 'all' - }; - if (m[1]) { - var options = (0, utils_1.parseOptions)(m[1]); - if (options.Dx) { - obj.dx = Number(options.Dx) * this.xunit; - } - if (options.Dy) { - obj.dy = Number(options.Dy) * this.yunit; - } - } - // arrows? - var l = (0, utils_1.parseArrows)(m[2]); - obj.arrows = l.arrows; - obj.dots = l.dots; - // \psaxes*[par]{arrows}(x0,y0)(x1,y1)(x2,y2) - // m[1] [options] - // m[2] {<->} - // origin - // m[3] x0 - // m[4] y0 - // bottom left corner - // m[6] x1 - // m[7] y1 - // top right corner - // m[9] x2 - // m[10] y2 - if (m[5] && !m[8]) { - // If (x0,y0) is omitted, then the origin is (x1,y1). - obj.origin = [utils_1.X.call(this, m[3]), utils_1.Y.call(this, m[4])]; - obj.bottomLeft = [utils_1.X.call(this, m[3]), utils_1.Y.call(this, m[4])]; - obj.topRight = [utils_1.X.call(this, m[6]), utils_1.Y.call(this, m[7])]; - } - else if (!m[5] && !m[8]) { - // If both (x0,y0) and (x1,y1) are omitted, (0,0) is used as the default. - obj.origin = [utils_1.X.call(this, 0), utils_1.Y.call(this, 0)]; - obj.bottomLeft = [utils_1.X.call(this, 0), utils_1.Y.call(this, 0)]; - obj.topRight = [utils_1.X.call(this, m[3]), utils_1.Y.call(this, m[6])]; - } - else { - // all three are specified - obj.origin = [utils_1.X.call(this, m[3]), utils_1.Y.call(this, m[4])]; - obj.bottomLeft = [utils_1.X.call(this, m[6]), utils_1.Y.call(this, m[7])]; - obj.topRight = [utils_1.X.call(this, m[9]), utils_1.Y.call(this, m[10])]; - } - return obj; - }, - psplot(m) { - var startX = utils_1.evaluate.call(this, m[2]); - var endX = utils_1.evaluate.call(this, m[3]); - var data = []; - var x; - // get env - var expression = ''; - Object.entries(this.variables || {}).forEach(([name, val]) => { - expression += 'var ' + name + ' = ' + val + ';'; - }); - const mathFunctions = 'var cos=Math.cos,sin=Math.sin,tan=Math.tan,atan=Math.atan,atan2=Math.atan2,exp=Math.exp,log=Math.log,sqrt=Math.sqrt,abs=Math.abs,floor=Math.floor,ceil=Math.ceil,round=Math.round,pow=Math.pow,PI=Math.PI,E=Math.E;'; - expression += mathFunctions + 'return ' + m[4] + ';'; - for (x = startX; x <= endX; x += 0.005) { - data.push(utils_1.X.call(this, x)); - try { - const evalFunc = new Function('x', expression); - const yValue = evalFunc(x); - if (yValue !== undefined && !isNaN(yValue)) { - data.push(utils_1.Y.call(this, yValue)); - } - else { - data.push(utils_1.Y.call(this, 0)); - } - } - catch (err) { - data.push(utils_1.Y.call(this, 0)); // fallback value - } - } - var obj = { - linecolor: 'black', - linestyle: 'solid', - fillstyle: 'none', - fillcolor: 'none', - linewidth: 2 - }; - if (m[1]) - Object.assign(obj, (0, utils_1.parseOptions)(m[1])); - obj.data = data; - return obj; - }, - pspolygon(m) { - var coords = m[2]; - if (!coords) - return; - var manyCoords = new RegExp(utils_1.RE.coords, 'g'); - var matches = coords.match(manyCoords); - var singleCoord = new RegExp(utils_1.RE.coords); - var data = []; - matches.forEach((coord) => { - var d = singleCoord.exec(coord); - if (d) { - data.push(utils_1.X.call(this, d[1])); - data.push(utils_1.Y.call(this, d[2])); - } - }); - var obj = { - linecolor: 'black', - linestyle: 'solid', - fillstyle: 'none', - fillcolor: 'black', - linewidth: 2, - data: data - }; - if (m[1]) - Object.assign(obj, (0, utils_1.parseOptions)(m[1])); - return obj; - }, - psarc(m) { - var l = (0, utils_1.parseArrows)(m[2]); - var arrows = l.arrows; - var dots = l.dots; - var obj = { - linecolor: 'black', - linestyle: 'solid', - fillstyle: 'solid', - fillcolor: 'black', - linewidth: 2, - arrows: arrows, - dots: dots, - cx: utils_1.X.call(this, 0), - cy: utils_1.Y.call(this, 0) - }; - if (m[1]) { - Object.assign(obj, (0, utils_1.parseOptions)(m[1])); - } - // m[1] options - // m[2] arrows - // m[3] x1 - // m[4] y1 - // m[5] radius - // m[6] angleA - // m[7] angleB - if (m[3]) { - obj.cx = utils_1.X.call(this, m[3]); - } - if (m[4]) { - obj.cy = utils_1.Y.call(this, m[4]); - } - // choose x units over y, no reason... - obj.r = Number(m[5]) * this.xunit; - obj.angleA = (Number(m[6]) * Math.PI) / 180; - obj.angleB = (Number(m[7]) * Math.PI) / 180; - obj.A = { - x: utils_1.X.call(this, Number(m[5]) * Math.cos(obj.angleA)), - y: utils_1.Y.call(this, Number(m[5]) * Math.sin(obj.angleA)) - }; - obj.B = { - x: utils_1.X.call(this, Number(m[5]) * Math.cos(obj.angleB)), - y: utils_1.Y.call(this, Number(m[5]) * Math.sin(obj.angleB)) - }; - return obj; - }, - psline(m) { - var options = m[1]; - var lineType = m[2]; - var l = (0, utils_1.parseArrows)(lineType); - var arrows = l.arrows; - var dots = l.dots; - var obj = { - linecolor: 'black', - linestyle: 'solid', - fillstyle: 'solid', - fillcolor: 'black', - linewidth: 2, - arrows: arrows, - dots: dots - }; - if (m[5]) { - obj.x1 = utils_1.X.call(this, m[3]); - obj.y1 = utils_1.Y.call(this, m[4]); - obj.x2 = utils_1.X.call(this, m[6]); - obj.y2 = utils_1.Y.call(this, m[7]); - } - else { - obj.x1 = utils_1.X.call(this, 0); - obj.y1 = utils_1.Y.call(this, 0); - obj.x2 = utils_1.X.call(this, m[3]); - obj.y2 = utils_1.Y.call(this, m[4]); - } - if (options) { - Object.assign(obj, (0, utils_1.parseOptions)(options)); - } - // TODO: add regex - if (typeof obj.linewidth === 'string') { - obj.linewidth = 2; - } - return obj; - }, - uservariable(m) { - var coords = []; - if (this.userx && this.usery) { - // coords.push( Xinv.call(this, this.userx) ); - // coords.push( Yinv.call(this, this.usery) ); - coords.push(Number(this.userx)); - coords.push(Number(this.usery)); - } - else { - coords.push(utils_1.X.call(this, m[3])); - coords.push(utils_1.Y.call(this, m[4])); - } - var nx1 = utils_1.Xinv.call(this, coords[0]); - var ny1 = utils_1.Yinv.call(this, coords[1]); - var expx1 = 'var x = ' + nx1 + ';'; - var expy1 = 'var y = ' + ny1 + ';'; - // return X.call(this, eval(expy1 + expx1 + xExp)); - var obj = { - name: m[2], - x: utils_1.X.call(this, m[3]), - y: utils_1.Y.call(this, m[4]), - func: m[5], - value: (() => { - try { - const mathFunctions = 'var cos=Math.cos,sin=Math.sin,tan=Math.tan,atan=Math.atan,atan2=Math.atan2,exp=Math.exp,log=Math.log,sqrt=Math.sqrt,abs=Math.abs,floor=Math.floor,ceil=Math.ceil,round=Math.round,pow=Math.pow,PI=Math.PI,E=Math.E;'; - const evalFunc = new Function('', mathFunctions + expx1 + expy1 + 'return ' + m[5]); - return evalFunc(); - } - catch (err) { - console.warn('Error evaluating uservariable expression:', err); - return 0; - } - })() - }; - return obj; - }, - userline(m) { - var options = m[1]; - // WE ARENT USING THIS YET!!!! e.g., [linecolor=green] - var lineType = m[2]; - var l = (0, utils_1.parseArrows)(lineType); - var arrows = l.arrows; - var dots = l.dots; - var xExp = m[7]; - var yExp = m[8]; - const mathFunctions = 'var cos=Math.cos,sin=Math.sin,tan=Math.tan,atan=Math.atan,atan2=Math.atan2,exp=Math.exp,log=Math.log,sqrt=Math.sqrt,abs=Math.abs,floor=Math.floor,ceil=Math.ceil,round=Math.round,pow=Math.pow,PI=Math.PI,E=Math.E;'; - if (xExp) - xExp = mathFunctions + xExp.replace(/^\{/, '').replace(/\}$/, ''); - if (yExp) - yExp = mathFunctions + yExp.replace(/^\{/, '').replace(/\}$/, ''); - var xExp2 = m[9]; - var yExp2 = m[10]; - if (xExp2) - xExp2 = mathFunctions + xExp2.replace(/^\{/, '').replace(/\}$/, ''); - if (yExp2) - yExp2 = mathFunctions + yExp2.replace(/^\{/, '').replace(/\}$/, ''); - var expression = ''; - Object.entries(this.variables || {}).forEach(([name, val]) => { - expression += 'var ' + name + ' = ' + val + ';'; - }); - var obj = { - x1: utils_1.X.call(this, m[3]), - y1: utils_1.Y.call(this, m[4]), - x2: utils_1.X.call(this, m[5]), - y2: utils_1.Y.call(this, m[6]), - xExp: xExp, - yExp: yExp, - xExp2: xExp2, - yExp2: yExp2, - userx: (coords) => { - var nx1 = utils_1.Xinv.call(this, coords[0]); - var ny1 = utils_1.Yinv.call(this, coords[1]); - var expx1 = 'var x = ' + nx1 + ';'; - var expy1 = 'var y = ' + ny1 + ';'; - try { - const cleanExp = xExp ? xExp.replace(/^var cos=Math\.cos[^;]*;/, '') : '0'; - const evalFunc = new Function('', mathFunctions + expression + expy1 + expx1 + 'return (' + cleanExp + ')'); - return utils_1.X.call(this, evalFunc()); - } - catch (err) { - console.warn('Error evaluating userx expression:', err); - return utils_1.X.call(this, 0); - } - }, - usery: (coords) => { - var nx2 = utils_1.Xinv.call(this, coords[0]); - var ny2 = utils_1.Yinv.call(this, coords[1]); - var expx2 = 'var x = ' + nx2 + ';'; - var expy2 = 'var y = ' + ny2 + ';'; - try { - const cleanExp = yExp ? yExp.replace(/^var cos=Math\.cos[^;]*;/, '') : '0'; - const evalFunc = new Function('', mathFunctions + expression + expy2 + expx2 + 'return (' + cleanExp + ')'); - return utils_1.Y.call(this, evalFunc()); - } - catch (err) { - console.warn('Error evaluating usery expression:', err); - return utils_1.Y.call(this, 0); - } - }, - userx2: (coords) => { - var nx3 = utils_1.Xinv.call(this, coords[0]); - var ny3 = utils_1.Yinv.call(this, coords[1]); - var expx3 = 'var x = ' + nx3 + ';'; - var expy3 = 'var y = ' + ny3 + ';'; - try { - const cleanExp = xExp2 ? xExp2.replace(/^var cos=Math\.cos[^;]*;/, '') : '0'; - const evalFunc = new Function('', mathFunctions + expression + expy3 + expx3 + 'return (' + cleanExp + ')'); - return utils_1.X.call(this, evalFunc()); - } - catch (err) { - console.warn('Error evaluating userx2 expression:', err); - return utils_1.X.call(this, 0); - } - }, - usery2: (coords) => { - var nx4 = utils_1.Xinv.call(this, coords[0]); - var ny4 = utils_1.Yinv.call(this, coords[1]); - var expx4 = 'var x = ' + nx4 + ';'; - var expy4 = 'var y = ' + ny4 + ';'; - try { - const cleanExp = yExp2 ? yExp2.replace(/^var cos=Math\.cos[^;]*;/, '') : '0'; - const evalFunc = new Function('', mathFunctions + expression + expy4 + expx4 + 'return (' + cleanExp + ')'); - return utils_1.Y.call(this, evalFunc()); - } - catch (err) { - console.warn('Error evaluating usery2 expression:', err); - return utils_1.Y.call(this, 0); - } - }, - linecolor: 'black', - linestyle: 'solid', - fillstyle: 'solid', - fillcolor: 'black', - linewidth: 2, - arrows: arrows, - dots: dots - }; - if (options) { - Object.assign(obj, (0, utils_1.parseOptions)(options)); - } - // TODO: add regex - if (typeof obj.linewidth === 'string') { - obj.linewidth = 2; - } - return obj; - }, - rput(m) { - return { - x: utils_1.X.call(this, m[1]), - y: utils_1.Y.call(this, m[2]), - text: m[3] - }; - }, - psset(m) { - const pairs = m[1].split(',').map((pair) => pair.split('=')); - const obj = {}; - pairs.forEach((pair) => { - const key = pair[0]; - const value = pair[1]; - Object.keys(settings_1.default.Expressions).forEach((setting) => { - const exp = settings_1.default.Expressions[setting]; - if (key.match(exp)) { - settings_1.default.Functions[setting](obj, value); - } - }); - }); - return obj; - } -}; -exports.default = { - Expressions: exports.Expressions, - Functions: exports.Functions -}; - -},{"@latex2js/settings":19,"@latex2js/utils":20}],19:[function(require,module,exports){ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.Functions = exports.Expressions = void 0; -const utils_1 = require("@latex2js/utils"); -exports.Expressions = { - fillcolor: /^fillcolor$/, - fillstyle: /^fillstyle$/, - linecolor: /^linecolor$/, - linestyle: /^linestyle$/, - unit: /^unit/, - runit: /^runit/, - xunit: /^xunit/, - yunit: /^yunit/ -}; -exports.Functions = { - fillcolor(o, v) { - o.fillcolor = v; - }, - fillstyle(o, v) { - o.fillstyle = v; - }, - linecolor(o, v) { - o.linecolor = v; - }, - linestyle(o, v) { - o.linestyle = v; - }, - unit(o, v) { - const converted = (0, utils_1.convertUnits)(v); - o.unit = converted; - o.runit = converted; - o.xunit = converted; - o.yunit = converted; - }, - runit(o, v) { - const converted = (0, utils_1.convertUnits)(v); - o.runit = converted; - }, - xunit(o, v) { - const converted = (0, utils_1.convertUnits)(v); - o.xunit = converted; - }, - yunit(o, v) { - const converted = (0, utils_1.convertUnits)(v); - o.yunit = converted; - } -}; -exports.default = { - Expressions: exports.Expressions, - Functions: exports.Functions -}; - -},{"@latex2js/utils":20}],20:[function(require,module,exports){ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.select = exports.SVGSelection = exports.dotType = exports.arrowType = exports.Yinv = exports.Y = exports.Xinv = exports.X = exports.evaluate = exports.parseArrows = exports.parseOptions = exports.RE = exports.convertUnits = exports.matchrepl = exports.simplerepl = void 0; -const simplerepl = function (regex, replace) { - return function (_m, contents) { - return contents.replace(regex, replace); - }; -}; -exports.simplerepl = simplerepl; -const matchrepl = function (regex, callback) { - return function (m, contents) { - if (Array.isArray(m)) { - m.forEach((match) => { - var m2 = match.match(regex); - contents = contents.replace(m2.input, callback(m2)); - }); - } - return contents; - }; -}; -exports.matchrepl = matchrepl; -const convertUnits = function (value) { - var m = null; - if ((m = value.match(/([^c]+)\s*cm/))) { - var num1 = Number(m[1]); - return num1 * 50; //118; - } - else if ((m = value.match(/([^i]+)\s*in/))) { - var num2 = Number(m[1]); - return num2 * 20; //46; - } - else if ((m = value.match(/(.*)/))) { - var num3 = Number(m[1]); - return num3 * 50; - } - else { - var num4 = Number(value); - return num4; - } -}; -exports.convertUnits = convertUnits; -exports.RE = { - options: '(\\[[^\\]]*\\])?', - type: '(\\{[^\\}]*\\})?', - squiggle: '\\{([^\\}]*)\\}', - squiggleOpt: '(\\{[^\\}]*\\})?', - coordsOpt: '(\\(\\s*([^\\)]*),([^\\)]*)\\s*\\))?', - coords: '\\(\\s*([^\\)]*),([^\\)]*)\\s*\\)' -}; -// OPTIONS -// converts [showorigin=false,labels=none, Dx=3.14] to {showorigin: 'false', labels: 'none', Dx: '3.14'} -const parseOptions = function (opts) { - var options = opts.replace(/[\]\[]/g, ''); - var all = options.split(','); - var obj = {}; - all.forEach((option) => { - var kv = option.split('='); - if (kv.length == 2) { - obj[kv[0].trim()] = kv[1].trim(); - } - }); - return obj; -}; -exports.parseOptions = parseOptions; -const parseArrows = function (m) { - var lineType = m; - var arrows = [0, 0]; - var dots = [0, 0]; - if (lineType) { - var type = lineType.match(/\{([^\-]*)?\-([^\-]*)?\}/); - if (type) { - if (type[1]) { - // check starting point - if (type[1].match(/\*/)) { - dots[0] = 1; - } - else if (type[1].match(//)) { - arrows[1] = 1; - } - } - } - } - return { - arrows: arrows, - dots: dots - }; -}; -exports.parseArrows = parseArrows; -// export const evaluate = function (this: any, exp: string) { -// var num = Number(exp); -// if (isNaN(num)) { -// var expression = ''; -// this.variables = this.variables || {}; -// Object.keys(this.variables).map((name: string) => { -// const val = this.variables[name]; -// expression += 'var ' + name + ' = ' + val + ';'; -// }) -// expression += 'with (Math){' + exp + '}'; -// return eval(expression); -// } else { -// return num; -// } -// }; -const evaluate = function (exp) { - const num = Number(exp); - if (!isNaN(num)) - return num; - this.variables = this.variables || {}; - const mathKeys = Object.keys(Math); - const varKeys = Object.keys(this.variables); - const allKeys = [...mathKeys, ...varKeys]; - const allValues = [ - ...mathKeys.map(k => Math[k]), - ...varKeys.map(k => this.variables[k]) - ]; - try { - // @ts-ignore - const fn = new Function(...allKeys, `return (${exp});`); - return fn(...allValues); - } - catch (e) { - console.warn('Evaluation error:', e); - return NaN; - } -}; -exports.evaluate = evaluate; -const X = function (v) { - // Enhanced validation for coordinate transformation - const numV = typeof v === 'string' ? parseFloat(v) : v; - if (isNaN(numV)) { - console.warn('X function: Invalid input value', { input: v, parsed: numV }); - return 0; - } - if (isNaN(this.w) || isNaN(this.x1) || isNaN(this.xunit)) { - console.warn('X function: NaN detected in context properties', { w: this.w, x1: this.x1, xunit: this.xunit }); - return 0; - } - // Validate context properties are reasonable - if (this.xunit <= 0) { - console.warn('X function: Invalid xunit value', { xunit: this.xunit }); - return 0; - } - // Use more precise calculation with proper parentheses - const result = (this.w - (this.x1 - numV)) * this.xunit; - // Validate result is finite - if (!isFinite(result)) { - console.warn('X function: Non-finite result', { - input: numV, - w: this.w, - x1: this.x1, - xunit: this.xunit, - result - }); - return 0; - } - return Math.round(result * 100) / 100; // Round to 2 decimal places for pixel precision -}; -exports.X = X; -const Xinv = function (v) { - return Number(v) / this.xunit - this.w + this.x1; -}; -exports.Xinv = Xinv; -const Y = function (v) { - // Enhanced validation for coordinate transformation - const numV = typeof v === 'string' ? parseFloat(v) : v; - if (isNaN(numV)) { - console.warn('Y function: Invalid input value', { input: v, parsed: numV }); - return 0; - } - if (isNaN(this.y1) || isNaN(this.yunit)) { - console.warn('Y function: NaN detected in context properties', { y1: this.y1, yunit: this.yunit }); - return 0; - } - // Validate context properties are reasonable - if (this.yunit <= 0) { - console.warn('Y function: Invalid yunit value', { yunit: this.yunit }); - return 0; - } - // Use more precise calculation for Y coordinate inversion - const result = (this.y1 - numV) * this.yunit; - // Validate result is finite - if (!isFinite(result)) { - console.warn('Y function: Non-finite result', { - input: numV, - y1: this.y1, - yunit: this.yunit, - result - }); - return 0; - } - return Math.round(result * 100) / 100; // Round to 2 decimal places for pixel precision -}; -exports.Y = Y; -const Yinv = function (v) { - return this.y1 - Number(v) / this.yunit; -}; -exports.Yinv = Yinv; -exports.arrowType = exports.parseArrows; -exports.dotType = exports.parseArrows; -var svg_utils_1 = require("./svg-utils"); -Object.defineProperty(exports, "SVGSelection", { enumerable: true, get: function () { return svg_utils_1.SVGSelection; } }); -Object.defineProperty(exports, "select", { enumerable: true, get: function () { return svg_utils_1.select; } }); - -},{"./svg-utils":21}],21:[function(require,module,exports){ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.SVGSelection = void 0; -exports.select = select; -class SVGSelection { - constructor(elements) { - if (elements instanceof Element) { - this.elements = [elements]; - } - else if (elements instanceof NodeList) { - this.elements = Array.from(elements).filter((node) => node.nodeType === Node.ELEMENT_NODE); - } - else { - this.elements = Array.isArray(elements) ? elements : []; - } - } - append(tagName) { - const newElements = []; - this.elements.forEach(parent => { - const elementName = tagName.startsWith('svg:') ? tagName.substring(4) : tagName; - const element = document.createElementNS('http://www.w3.org/2000/svg', elementName); - parent.appendChild(element); - newElements.push(element); - }); - return new SVGSelection(newElements); - } - attr(name, value) { - this.elements.forEach(el => { - el.setAttribute(name, String(value)); - }); - return this; - } - style(name, value) { - this.elements.forEach(el => { - if (el instanceof SVGElement || el instanceof HTMLElement) { - el.style[name] = String(value); - } - }); - return this; - } - selectAll(selector) { - const selected = []; - this.elements.forEach(parent => { - const found = parent.querySelectorAll(selector); - selected.push(...Array.from(found)); - }); - return new SVGSelection(selected); - } - remove() { - this.elements.forEach(el => { - if (el.parentNode) { - el.parentNode.removeChild(el); - } - }); - return this; - } - on(event, handler) { - this.elements.forEach(el => { - el.addEventListener(event, handler); - }); - return this; - } - node() { - return this.elements[0] || null; - } - text(content) { - this.elements.forEach(el => { - if (el instanceof SVGTextElement || el instanceof HTMLElement) { - el.textContent = content; - } - }); - return this; - } -} -exports.SVGSelection = SVGSelection; -function select(selector) { - if (typeof selector === 'string') { - const element = document.querySelector(selector); - return new SVGSelection(element ? [element] : []); - } - return new SVGSelection(selector); -} - -},{}]},{},[7])(7) -}); diff --git a/bin/examples.ts b/bin/examples.ts deleted file mode 100644 index f61b036..0000000 --- a/bin/examples.ts +++ /dev/null @@ -1,100 +0,0 @@ -import { sync as glob } from 'glob'; -import * as fs from 'fs'; - -const t = []; -glob(__dirname + '/../examples/tex/*.tex').forEach(tex => { - const text = fs.readFileSync(tex).toString(); - - t.push('
    '); - t.push('
    '); - t.push(text); - t.push('
    '); - t.push('source:'); - t.push('
    '); - t.push('\\begin{verbatim}'); - t.push(text); - t.push('\\end{verbatim}'); - t.push('
    '); - t.push('
    '); -}); - -const HEADER = ` - - - - - - - - - - - LaTeX2JS Examples - - - - - - - - - - - - - - - - - - - - - - - - -Home -Examples -Installation - -
    -

    LaTeX2JS Examples

    -

    Be sure to checkout the example apps on Github here!

    -
    - - - - - -
    -

    Dan Lynch © LaTeX2JS 2020

    -
    - - - - - -`; - -const content = HEADER + t.join('\n') + FOOTER; - -fs.writeFileSync(__dirname + '/../examples/index.html', content); - -glob(__dirname + '/../examples/community/*.tex').forEach(tex => { - const text = fs.readFileSync(tex).toString(); - const content = HEADER + text + FOOTER; - fs.writeFileSync(tex.replace(/\.tex$/, '.html'), content); -}); diff --git a/examples/tex/01.tex b/content/examples/01.tex similarity index 100% rename from examples/tex/01.tex rename to content/examples/01.tex diff --git a/examples/tex/02.tex b/content/examples/02.tex similarity index 100% rename from examples/tex/02.tex rename to content/examples/02.tex diff --git a/examples/tex/03.tex b/content/examples/03.tex similarity index 71% rename from examples/tex/03.tex rename to content/examples/03.tex index b0b736d..64c814d 100644 --- a/examples/tex/03.tex +++ b/content/examples/03.tex @@ -1,7 +1,8 @@ +\definecolor{lightblue}{RGB}{173,216,230} \begin{pspicture}(-2,-2)(2,2) \psframe(-2,-2)(2,2) \userline[linewidth=2pt,linecolor=green]{->}(0,0)(2,2){-x}{-y} \userline[linewidth=2pt,linecolor=red]{->}(0,0)(2,2){0}{y} -\userline[linewidth=2pt,linecolor=purple]{->}(0,0)(2,2){-x}{cos(y)} +\userline[linewidth=2pt,linecolor=violet]{->}(0,0)(2,2){-x}{cos(y)} \userline[linewidth=2pt,linecolor=lightblue]{->}(0,0)(2,2)(sin(x)}{-y} \end{pspicture} diff --git a/examples/tex/04.tex b/content/examples/04.tex similarity index 100% rename from examples/tex/04.tex rename to content/examples/04.tex diff --git a/examples/tex/05.tex b/content/examples/05.tex similarity index 100% rename from examples/tex/05.tex rename to content/examples/05.tex diff --git a/examples/tex/06.tex b/content/examples/06.tex similarity index 100% rename from examples/tex/06.tex rename to content/examples/06.tex diff --git a/examples/tex/07.tex b/content/examples/07.tex similarity index 100% rename from examples/tex/07.tex rename to content/examples/07.tex diff --git a/examples/tex/08.tex b/content/examples/08.tex similarity index 100% rename from examples/tex/08.tex rename to content/examples/08.tex diff --git a/examples/tex/09.tex b/content/examples/09.tex similarity index 100% rename from examples/tex/09.tex rename to content/examples/09.tex diff --git a/examples/tex/10.tex b/content/examples/10.tex similarity index 100% rename from examples/tex/10.tex rename to content/examples/10.tex diff --git a/examples/tex/11.tex b/content/examples/11.tex similarity index 100% rename from examples/tex/11.tex rename to content/examples/11.tex diff --git a/examples/tex/12.tex b/content/examples/12.tex similarity index 100% rename from examples/tex/12.tex rename to content/examples/12.tex diff --git a/examples/tex/13.tex b/content/examples/13.tex similarity index 100% rename from examples/tex/13.tex rename to content/examples/13.tex diff --git a/examples/community/graph.tex b/content/examples/14.tex similarity index 100% rename from examples/community/graph.tex rename to content/examples/14.tex diff --git a/examples/community/graph.html b/examples/community/graph.html deleted file mode 100644 index d612ca4..0000000 --- a/examples/community/graph.html +++ /dev/null @@ -1,152 +0,0 @@ - - - - - - - - - - - - LaTeX2JS Examples - - - - - - - - - - - - - - - - - - - - - - - - - - Home - Examples - Installation - -
    -

    LaTeX2JS Examples

    -

    Be sure to checkout the example apps on Github here!

    -
    - - - -
    - - Powered by MathJax - -
    - -
    -

    Dan Lynch © LaTeX2JS 2020

    -
    - - - - - - \ No newline at end of file diff --git a/examples/index.html b/examples/index.html deleted file mode 100644 index 45b080d..0000000 --- a/examples/index.html +++ /dev/null @@ -1,749 +0,0 @@ - - - - - - - - - - - - LaTeX2JS Examples - - - - - - - - - - - - - - - - - - - - - - - - - - Home - Examples - Installation - -
    -

    LaTeX2JS Examples

    -

    Be sure to checkout the example apps on Github here!

    -
    - - - -
    - - Powered by MathJax - -
    - -
    -

    Dan Lynch © LaTeX2JS 2020

    -
    - - - - - - \ No newline at end of file diff --git a/index.html b/index.html deleted file mode 100644 index b4b2df9..0000000 --- a/index.html +++ /dev/null @@ -1,326 +0,0 @@ - - - - - - - - - - - - LaTeX2JS | Interactive Math Equations and Diagrams - - - - - - - - - - - - - - - - - - - - - - - - - -
    - -

    LaTeX2JS

    -

    Author interactive math equations and diagrams online using $\LaTeX$ and PSTricks

    - -
    - -
    - -
    - -
    - -

    This project is the frontend only version of the code that originated from Mathapedia to enable real-time, dynamic authorship of mathematical ebooks

    - - - $$\frac{\delta}{\delta u} \int_{birth}^{death} f(life) du = \mbox{your life}$$ - -
    - -
    -

    Proud to support the best

    - - - - - - - - - -
    - -
    - - -
    -

    Installation

    - -

    You will also find installation instructions here.

    - -

    Examples

    - -

    - Get inspired, and make sure you see the PSTricks examples here! -

    - -

    Get Started

    - -

    - To get started, check out the example apps - on Github, or view source. Play in the sandbox here. -

    - -

    Documentation

    - -

    There's also quite a bit of documentation here

    - -

    Help spread the word!

    -

    - If you've built anything cool with LaTeX2JS, please share! -

    - -
    - -
    - -
    - - - -
    -

    Installation

    - -

    You will also find installation instructions here.

    - -

    Examples

    - -

    - Get inspired, and make sure you see the PSTricks examples here! -

    - -

    Get Started

    - -

    - To get started, check out the example apps - on Github, or view source. Play in the sandbox here. -

    - -

    Documentation

    - -

    There's also quite a bit of documentation here

    - -

    Help spread the word!

    -

    - If you've built anything cool with LaTeX2JS, please share! -

    - -
    - - - - -
    - - Powered by MathJax - -
    - -
    -

    Dan Lynch © LaTeX2JS 2020

    -
    - - - - - - \ No newline at end of file diff --git a/installation/html5.html b/installation/html5.html deleted file mode 100644 index 6030358..0000000 --- a/installation/html5.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - - - - LaTeX2HTML5 Installation - - - - - - - - - - - - - - - - - - - - - - - - - Home - Examples - Installation - -
    - -
    -

    LaTeX2HTML5 Installation

    -
    - -
    -

    HTML5

    - -
    - - - - -
    - - Powered by MathJax - -
    - -
    -

    Dan Lynch © LaTeX2JS 2020

    -
    - - - - - - \ No newline at end of file diff --git a/installation/index.html b/installation/index.html deleted file mode 100644 index d37de74..0000000 --- a/installation/index.html +++ /dev/null @@ -1,103 +0,0 @@ - - - - - - - - - - - - LaTeX2JS Installation - - - - - - - - - - - - - - - - - - - - - - - - - Home - Examples - Installation - -
    - -
    -

    LaTeX2JS Installation

    - -

    Proud to support the best! Click below to find the installation for your favorite library/framework:

    - -
    - - - Vue Installation - -
    - - - React Installation - -
    - - - HTML5 Installation - -
    - -
    - - If you want to add another adapter, please let us know by making an issue on our github! - - - - - - -
    - - Powered by MathJax - -
    - -
    -

    Dan Lynch © LaTeX2JS 2020

    -
    - - - - - - \ No newline at end of file diff --git a/installation/react.html b/installation/react.html deleted file mode 100644 index 9c8decd..0000000 --- a/installation/react.html +++ /dev/null @@ -1,108 +0,0 @@ - - - - - - - - - - - - LaTeX2React Installation - - - - - - - - - - - - - - - - - - - - - - - - - Home - Examples - Installation - -
    - -
    -

    LaTeX2React Installation

    -
    - - -
    -

    React

    - -
    - - - -
    - - Powered by MathJax - -
    - -
    -

    Dan Lynch © LaTeX2JS 2020

    -
    - - - - - - \ No newline at end of file diff --git a/installation/vue.html b/installation/vue.html deleted file mode 100644 index 200645c..0000000 --- a/installation/vue.html +++ /dev/null @@ -1,104 +0,0 @@ - - - - - - - - - - - - LaTeX2Vue Installation - - - - - - - - - - - - - - - - - - - - - - - - - Home - Examples - Installation - -
    - -
    -

    LaTeX2Vue Installation

    -
    - - - -
    - - Powered by MathJax - -
    - -
    -

    Dan Lynch © LaTeX2JS 2020

    -
    - - - - - - \ No newline at end of file diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 0000000..524d487 --- /dev/null +++ b/jest.config.js @@ -0,0 +1,15 @@ +/** @type {import('jest').Config} */ +module.exports = { + preset: 'ts-jest', + testEnvironment: 'node', + roots: ['/__tests__', '/src'], + testMatch: ['**/__tests__/**/*.test.(ts|js)', '**/?(*.)+(spec|test).(ts|js)'], + transform: { + '^.+\\.(ts|tsx)$': 'ts-jest', + }, + moduleNameMapper: { + '^@/(.*)$': '/src/$1', + }, + testTimeout: 30000, + verbose: true, +}; diff --git a/next.config.mjs b/next.config.mjs new file mode 100644 index 0000000..5832784 --- /dev/null +++ b/next.config.mjs @@ -0,0 +1,11 @@ +/** @type {import('next').NextConfig} */ +const nextConfig = { + output: 'export', + reactStrictMode: true, + images: { + unoptimized: true, + deviceSizes: [640, 960, 1280, 1600, 1920], + }, +}; + +export default nextConfig; diff --git a/node_modules/glob b/node_modules/glob index e7b14cf..cd44a7b 120000 --- a/node_modules/glob +++ b/node_modules/glob @@ -1 +1 @@ -../../../node_modules/.pnpm/glob@7.2.3/node_modules/glob \ No newline at end of file +.pnpm/glob@11.1.0/node_modules/glob \ No newline at end of file diff --git a/package.json b/package.json index adbdd35..9939d8f 100644 --- a/package.json +++ b/package.json @@ -1,15 +1,53 @@ { - "name": "latex2js.com", - "version": "2.1.2", - "private": true, - "scripts": { - "copy": "rm -rf static && mkdir -p static && cp -r assets static/ && cp -r examples static/ && cp -r installation static/ && cp -r index.html static/", - "examples": "node bin/examples", - "upload": "AWS_PROFILE=pyramation aws s3 sync static/ s3://latex2js.com", - "deploy": "npm run copy && npm run upload", - "invalidate": "AWS_PROFILE=pyramation aws cloudfront create-invalidation --distribution-id E2IV32FSPB7S79 --paths \"/*\"" - }, - "devDependencies": { - "glob": "^7.1.2" - } + "name": "latex2js.com", + "version": "1.0.0", + "private": true, + "scripts": { + "dev": "next dev --port 5007", + "build": "next build && pnpm run generate:llm-md && pnpm run seo", + "start": "next start", + "test": "jest", + "test:watch": "jest --watch", + "test:update": "jest --updateSnapshot", + "seo": "tsx src/seo/seo.ts", + "generate:llm-md": "tsx scripts/generate-llm-markdown.ts", + "deploy": "AWS_PROFILE=pyramation aws s3 sync out/ s3://latex2js.com --exclude \"*.md\" --exclude \"llms.txt\" && pnpm run deploy:md", + "deploy:md": "AWS_PROFILE=pyramation aws s3 cp out/ s3://latex2js.com --recursive --exclude \"*\" --include \"*.md\" --include \"llms.txt\" --content-type \"text/plain; charset=utf-8\"", + "deploy:all": "pnpm run build && pnpm run deploy && ./src/seo/prepare.sh && pnpm run invalidate", + "invalidate": "AWS_PROFILE=pyramation aws cloudfront create-invalidation --distribution-id E2IV32FSPB7S79 --paths \"/*\"" + }, + "engines": { + "node": ">=22", + "pnpm": ">=10" + }, + "dependencies": { + "@codemirror/language": "6.12.4", + "@codemirror/lint": "6.9.7", + "@codemirror/legacy-modes": "6.5.3", + "@uiw/react-codemirror": "4.25.11", + "jsonldjs": "^0.1.2", + "latex2js": "4.5.0", + "latex2react": "4.4.2", + "next": "16.1.6", + "next-seo": "^6.8.0", + "react": "19.2.4", + "react-dom": "19.2.4" + }, + "devDependencies": { + "@types/glob": "^8.1.0", + "@types/jest": "^29.5.14", + "@types/node": "^22.19.7", + "@types/react": "19.2.10", + "@types/react-dom": "19.2.3", + "autoprefixer": "^10.4.24", + "glob": "^11.1.0", + "jest": "^29.7.0", + "mkdirp": "^3.0.1", + "postcss": "^8.5.6", + "schema-dts": "^1.1.5", + "tailwindcss": "^3.4.19", + "ts-jest": "^29.4.6", + "tsx": "^4.21.0", + "typescript": "^5.9.3" + } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..d24d2bb --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,4284 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +overrides: + '@types/react': 19.2.10 + '@types/react-dom': 19.2.3 + +importers: + + .: + dependencies: + '@codemirror/language': + specifier: 6.12.4 + version: 6.12.4 + '@codemirror/legacy-modes': + specifier: 6.5.3 + version: 6.5.3 + '@codemirror/lint': + specifier: 6.9.7 + version: 6.9.7 + '@uiw/react-codemirror': + specifier: 4.25.11 + version: 4.25.11(@babel/runtime@8.0.0)(@codemirror/autocomplete@6.20.3)(@codemirror/language@6.12.4)(@codemirror/lint@6.9.7)(@codemirror/search@6.7.1)(@codemirror/state@6.7.1)(@codemirror/theme-one-dark@6.1.3)(@codemirror/view@6.43.9)(codemirror@6.0.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + jsonldjs: + specifier: ^0.1.2 + version: 0.1.2 + latex2js: + specifier: 4.5.0 + version: 4.5.0 + latex2react: + specifier: 4.4.2 + version: 4.4.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + next: + specifier: 16.1.6 + version: 16.1.6(@babel/core@7.29.7(supports-color@8.1.1))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + next-seo: + specifier: ^6.8.0 + version: 6.8.0(next@16.1.6(@babel/core@7.29.7(supports-color@8.1.1))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + react: + specifier: 19.2.4 + version: 19.2.4 + react-dom: + specifier: 19.2.4 + version: 19.2.4(react@19.2.4) + devDependencies: + '@types/glob': + specifier: ^8.1.0 + version: 8.1.0 + '@types/jest': + specifier: ^29.5.14 + version: 29.5.14 + '@types/node': + specifier: ^22.19.7 + version: 22.20.1 + '@types/react': + specifier: 19.2.10 + version: 19.2.10 + '@types/react-dom': + specifier: 19.2.3 + version: 19.2.3(@types/react@19.2.10) + autoprefixer: + specifier: ^10.4.24 + version: 10.5.4(postcss@8.5.26) + glob: + specifier: ^11.1.0 + version: 11.1.0 + jest: + specifier: ^29.7.0 + version: 29.7.0(@types/node@22.20.1)(supports-color@8.1.1) + mkdirp: + specifier: ^3.0.1 + version: 3.0.1 + postcss: + specifier: ^8.5.6 + version: 8.5.26 + schema-dts: + specifier: ^1.1.5 + version: 1.1.5 + tailwindcss: + specifier: ^3.4.19 + version: 3.4.19(tsx@4.23.12) + ts-jest: + specifier: ^29.4.6 + version: 29.4.12(@babel/core@7.29.7(supports-color@8.1.1))(@jest/transform@29.7.0(supports-color@8.1.1))(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1))(esbuild@0.28.2)(jest-util@29.7.0)(jest@29.7.0(@types/node@22.20.1)(supports-color@8.1.1))(typescript@5.9.3) + tsx: + specifier: ^4.21.0 + version: 4.23.12 + typescript: + specifier: ^5.9.3 + version: 5.9.3 + +packages: + + '@alloc/quick-lru@5.2.0': + resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} + engines: {node: '>=10'} + + '@babel/code-frame@7.29.7': + resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.29.7': + resolution: {integrity: sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.29.7': + resolution: {integrity: sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.29.8': + resolution: {integrity: sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.29.7': + resolution: {integrity: sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==} + engines: {node: '>=6.9.0'} + + '@babel/helper-globals@7.29.7': + resolution: {integrity: sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.29.7': + resolution: {integrity: sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.29.7': + resolution: {integrity: sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-plugin-utils@7.29.7': + resolution: {integrity: sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.29.7': + resolution: {integrity: sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.29.7': + resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.29.7': + resolution: {integrity: sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.29.7': + resolution: {integrity: sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.29.8': + resolution: {integrity: sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/plugin-syntax-async-generators@7.8.4': + resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-bigint@7.8.3': + resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-class-properties@7.12.13': + resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-class-static-block@7.14.5': + resolution: {integrity: sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-import-attributes@7.29.7': + resolution: {integrity: sha512-zGYcYfq/WmZ4V+kBIXQon9dSSc8ircGZqw9ZaNhhGj9nZkeBu1jHLBDQqYYi5WA9uawvA2sIMbry2nCFhf5Djg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-import-meta@7.10.4': + resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-json-strings@7.8.3': + resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-jsx@7.29.7': + resolution: {integrity: sha512-TSu8+mHCoEaaCDEZ0I3+6mvTBYR4PCxQwf2z9/r5Tbztv6NaLR3B9thGTTxX2WGuGHJqRiAbKPeGTJ5XWXVg6A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-logical-assignment-operators@7.10.4': + resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3': + resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-numeric-separator@7.10.4': + resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-object-rest-spread@7.8.3': + resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-optional-catch-binding@7.8.3': + resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-optional-chaining@7.8.3': + resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-private-property-in-object@7.14.5': + resolution: {integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-top-level-await@7.14.5': + resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-typescript@7.29.7': + resolution: {integrity: sha512-ngr+82Sh0xMz25TPCZi+nC2iTzjfCdWS2ONXTp/PtSCHCgaCNBpdMqgvJ2ccdLlClVZ7sisIgB914j/JFe+RZA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/runtime@8.0.0': + resolution: {integrity: sha512-sL6cvO2IfkSu/iU+zs2S/w01B7A8V7suXSIKEN4hPFFdZoiPGxrj5pAG0lCaqLWiEIrjKzdznIWuaLcxPR53qw==} + + '@babel/template@7.29.7': + resolution: {integrity: sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.29.8': + resolution: {integrity: sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.29.8': + resolution: {integrity: sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==} + engines: {node: '>=6.9.0'} + + '@bcoe/v8-coverage@0.2.3': + resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} + + '@codemirror/autocomplete@6.20.3': + resolution: {integrity: sha512-tlosUqb+3BbxCxZdu4tKeRghPFC+QM7q4X5YhKV2eCmPG+1r2F3f4AaSz5sCrFqUtX4Jh20VFTKecl16MgiV9g==} + + '@codemirror/commands@6.11.0': + resolution: {integrity: sha512-/K4Rl5BN0OtTiPWmJCdqODu38XnDMsDxKY5rgrPnCkutPTJf2wVbkoixLfealF5Kwse/s8P8M5jAiURiwSwnFA==} + + '@codemirror/language@6.12.4': + resolution: {integrity: sha512-1q4PaT+o6PbgpkJt4Q8Fv5XJxTy4FUZ4MWETtyiDw3J0Pyr9E2vqcKL+k9wcvjNTIsauxvE7OfmWj3FRPHQ76A==} + + '@codemirror/legacy-modes@6.5.3': + resolution: {integrity: sha512-xCsmIzH78MyWkib9jlPaaun57XNkfbMIhagfaZVd0iLTqlpw3jXaIcbZm72MTmmn64eTZpBVNjbyYh+QXnxRsg==} + + '@codemirror/lint@6.9.7': + resolution: {integrity: sha512-28/+iWLYxKxsvGYhSYL7zaCZqLz5+FFFDq9tVsvGv9kv8RY4fFAchJ5WX9M3YrrRlTIsECjsXPqeNgnSmNP2dg==} + + '@codemirror/search@6.7.1': + resolution: {integrity: sha512-uMe5UO6PamJtSHrXhhHOzSX3ReWtiJrva6GnPMwSOrZtiExb5X5eExhr2OUZQVvdxPsKpY3Ro2mFbQadpPWmHA==} + + '@codemirror/state@6.7.1': + resolution: {integrity: sha512-9QzNDgE4EYDnAHfrTlR2lwiPciiOymLtwKK+8yHQzCc7GXhAP9xdEbEJFy2IWB1j9UGUl9BsgMmTo/ImA02T7A==} + + '@codemirror/theme-one-dark@6.1.3': + resolution: {integrity: sha512-NzBdIvEJmx6fjeremiGp3t/okrLPYT0d9orIc7AFun8oZcRk58aejkqhv6spnz4MLAevrKNPMQYXEWMg4s+sKA==} + + '@codemirror/view@6.43.9': + resolution: {integrity: sha512-sTuUzTpPMFebRhg6dawChoKKgndIwfjmJgKVxBefPElcU2NwQ6AFroupk0SFqEerQyZOGRfDNnSN8Dw/lMAsXw==} + + '@emnapi/runtime@1.11.3': + resolution: {integrity: sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==} + + '@esbuild/aix-ppc64@0.28.2': + resolution: {integrity: sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.28.2': + resolution: {integrity: sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.28.2': + resolution: {integrity: sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.28.2': + resolution: {integrity: sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.28.2': + resolution: {integrity: sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.28.2': + resolution: {integrity: sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.28.2': + resolution: {integrity: sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.28.2': + resolution: {integrity: sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.28.2': + resolution: {integrity: sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.28.2': + resolution: {integrity: sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.28.2': + resolution: {integrity: sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.28.2': + resolution: {integrity: sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.28.2': + resolution: {integrity: sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.28.2': + resolution: {integrity: sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.28.2': + resolution: {integrity: sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.28.2': + resolution: {integrity: sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.28.2': + resolution: {integrity: sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.28.2': + resolution: {integrity: sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.28.2': + resolution: {integrity: sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.28.2': + resolution: {integrity: sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.28.2': + resolution: {integrity: sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.28.2': + resolution: {integrity: sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.28.2': + resolution: {integrity: sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.28.2': + resolution: {integrity: sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.28.2': + resolution: {integrity: sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.28.2': + resolution: {integrity: sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@img/colour@1.1.0': + resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} + engines: {node: '>=18'} + + '@img/sharp-darwin-arm64@0.34.5': + resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [darwin] + + '@img/sharp-darwin-x64@0.34.5': + resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-darwin-arm64@1.2.4': + resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} + cpu: [arm64] + os: [darwin] + + '@img/sharp-libvips-darwin-x64@1.2.4': + resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-linux-arm64@1.2.4': + resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-arm@1.2.4': + resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-ppc64@1.2.4': + resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-riscv64@1.2.4': + resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-s390x@1.2.4': + resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-x64@1.2.4': + resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@img/sharp-linux-arm64@0.34.5': + resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-arm@0.34.5': + resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-ppc64@0.34.5': + resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-riscv64@0.34.5': + resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-s390x@0.34.5': + resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-x64@0.34.5': + resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@img/sharp-linuxmusl-arm64@0.34.5': + resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@img/sharp-linuxmusl-x64@0.34.5': + resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@img/sharp-wasm32@0.34.5': + resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [wasm32] + + '@img/sharp-win32-arm64@0.34.5': + resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [win32] + + '@img/sharp-win32-ia32@0.34.5': + resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ia32] + os: [win32] + + '@img/sharp-win32-x64@0.34.5': + resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [win32] + + '@isaacs/cliui@9.0.0': + resolution: {integrity: sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg==} + engines: {node: '>=18'} + + '@istanbuljs/load-nyc-config@1.1.0': + resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} + engines: {node: '>=8'} + + '@istanbuljs/schema@0.1.6': + resolution: {integrity: sha512-+Sg6GCR/wy1oSmQDFq4LQDAhm3ETKnorxN+y5nbLULOR3P0c14f2Wurzj3/xqPXtasLFfHd5iRFQ7AJt4KH2cw==} + engines: {node: '>=8'} + + '@jest/console@29.7.0': + resolution: {integrity: sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/core@29.7.0': + resolution: {integrity: sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + '@jest/environment@29.7.0': + resolution: {integrity: sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/expect-utils@29.7.0': + resolution: {integrity: sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/expect@29.7.0': + resolution: {integrity: sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/fake-timers@29.7.0': + resolution: {integrity: sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/globals@29.7.0': + resolution: {integrity: sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/reporters@29.7.0': + resolution: {integrity: sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + '@jest/schemas@29.6.3': + resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/source-map@29.6.3': + resolution: {integrity: sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/test-result@29.7.0': + resolution: {integrity: sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/test-sequencer@29.7.0': + resolution: {integrity: sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/transform@29.7.0': + resolution: {integrity: sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/types@29.6.3': + resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@latex2js/macros@3.2.0': + resolution: {integrity: sha512-c+wxIDpiW/W5roOBHY3f15GVTKcoemWbE0sOl+1vQj5tDlmXlqhNwCdzNRKSGHBA27MSb3/kHBTxwfhVMJA8Fg==} + + '@latex2js/pstricks@4.2.0': + resolution: {integrity: sha512-W9VtYJrqOYdosHV2FOFga3xS38YkTLjqns19Bu3zJ9WK86YdD4WooZrIDCoFnmOsXB3n5ibPua2LHXuNhEVAtg==} + + '@latex2js/settings@4.2.0': + resolution: {integrity: sha512-8oAeVuspWZyLxrhg02a+pAijE1jGUjTiEhJGJvLPJAft5Im18WrLeIMy9AYk3oknPjwJJZkkX0ubAB6MykZVww==} + + '@latex2js/utils@4.2.0': + resolution: {integrity: sha512-Rlniv0qwnF7e15MnQMnAN0jeOQCmIwwJxgZ57V3bOqZePGkCnIw4VG2TviRlrA76QsggPAe+G2xPNbe4U1xrDg==} + + '@lezer/common@1.5.2': + resolution: {integrity: sha512-sxQE460fPZyU3sdc8lafxiPwJHBzZRy/udNFynGQky1SePYBdhkBl1kOagA9uT3pxR8K09bOrmTUqA9wb/PjSQ==} + + '@lezer/highlight@1.2.3': + resolution: {integrity: sha512-qXdH7UqTvGfdVBINrgKhDsVTJTxactNNxLk7+UMwZhU13lMHaOBlJe9Vqp907ya56Y3+ed2tlqzys7jDkTmW0g==} + + '@lezer/lr@1.4.10': + resolution: {integrity: sha512-rnCpTIBafOx4mRp43xOxDJbFipJm/c0cia/V5TiGlhmMa+wsSdoGmUN3w5Bqrks/09Q/D4tNAmWaT8p6NRi77A==} + + '@marijn/find-cluster-break@1.0.4': + resolution: {integrity: sha512-Wy0V7+SGUjnF9/TkiM1hKVDPj7jKXduPNboMVtHTA8dySMURWqfg/JZ9E2Sq8JgSJmkl7k7Qe9FLeMSrSraWmQ==} + + '@next/env@16.1.6': + resolution: {integrity: sha512-N1ySLuZjnAtN3kFnwhAwPvZah8RJxKasD7x1f8shFqhncnWZn4JMfg37diLNuoHsLAlrDfM3g4mawVdtAG8XLQ==} + + '@next/swc-darwin-arm64@16.1.6': + resolution: {integrity: sha512-wTzYulosJr/6nFnqGW7FrG3jfUUlEf8UjGA0/pyypJl42ExdVgC6xJgcXQ+V8QFn6niSG2Pb8+MIG1mZr2vczw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@next/swc-darwin-x64@16.1.6': + resolution: {integrity: sha512-BLFPYPDO+MNJsiDWbeVzqvYd4NyuRrEYVB5k2N3JfWncuHAy2IVwMAOlVQDFjj+krkWzhY2apvmekMkfQR0CUQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@next/swc-linux-arm64-gnu@16.1.6': + resolution: {integrity: sha512-OJYkCd5pj/QloBvoEcJ2XiMnlJkRv9idWA/j0ugSuA34gMT6f5b7vOiCQHVRpvStoZUknhl6/UxOXL4OwtdaBw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@next/swc-linux-arm64-musl@16.1.6': + resolution: {integrity: sha512-S4J2v+8tT3NIO9u2q+S0G5KdvNDjXfAv06OhfOzNDaBn5rw84DGXWndOEB7d5/x852A20sW1M56vhC/tRVbccQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@next/swc-linux-x64-gnu@16.1.6': + resolution: {integrity: sha512-2eEBDkFlMMNQnkTyPBhQOAyn2qMxyG2eE7GPH2WIDGEpEILcBPI/jdSv4t6xupSP+ot/jkfrCShLAa7+ZUPcJQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@next/swc-linux-x64-musl@16.1.6': + resolution: {integrity: sha512-oicJwRlyOoZXVlxmIMaTq7f8pN9QNbdes0q2FXfRsPhfCi8n8JmOZJm5oo1pwDaFbnnD421rVU409M3evFbIqg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@next/swc-win32-arm64-msvc@16.1.6': + resolution: {integrity: sha512-gQmm8izDTPgs+DCWH22kcDmuUp7NyiJgEl18bcr8irXA5N2m2O+JQIr6f3ct42GOs9c0h8QF3L5SzIxcYAAXXw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@next/swc-win32-x64-msvc@16.1.6': + resolution: {integrity: sha512-NRfO39AIrzBnixKbjuo2YiYhB6o9d8v/ymU9m/Xk8cyVk+k7XylniXkHwjs4s70wedVffc6bQNbufk5v0xEm0A==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + + '@sinclair/typebox@0.27.12': + resolution: {integrity: sha512-hhyNJ+nbR6ZR7pToHvllEFun9TL0sbL+tk/ON75lo+Xas054uez98qRbsuNt7MBCyZKK4+8Yli/OAGZhmfBZ/g==} + + '@sinonjs/commons@3.0.1': + resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==} + + '@sinonjs/fake-timers@10.3.0': + resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==} + + '@swc/helpers@0.5.15': + resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} + + '@types/babel__core@7.20.5': + resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + + '@types/babel__generator@7.27.0': + resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==} + + '@types/babel__template@7.4.4': + resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} + + '@types/babel__traverse@7.28.0': + resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} + + '@types/glob@8.1.0': + resolution: {integrity: sha512-IO+MJPVhoqz+28h1qLAcBEH2+xHMK6MTyHJc7MTnnYb6wsoLR29POVGJ7LycmVXIqyy/4/2ShP5sUwTXuOwb/w==} + + '@types/graceful-fs@4.1.9': + resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==} + + '@types/istanbul-lib-coverage@2.0.6': + resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} + + '@types/istanbul-lib-report@3.0.3': + resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==} + + '@types/istanbul-reports@3.0.4': + resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} + + '@types/jest@29.5.14': + resolution: {integrity: sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==} + + '@types/minimatch@5.1.2': + resolution: {integrity: sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==} + + '@types/node@22.20.1': + resolution: {integrity: sha512-EANqOCF9QFyra+4pfxUcX9STKJpCLjMbObVzljIJomAWSnuSIEAvyzEU53GaajbXJEgdh0iEcPL+DGvpUd4k1Q==} + + '@types/react-dom@19.2.3': + resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} + peerDependencies: + '@types/react': 19.2.10 + + '@types/react@19.2.10': + resolution: {integrity: sha512-WPigyYuGhgZ/cTPRXB2EwUw+XvsRA3GqHlsP4qteqrnnjDrApbS7MxcGr/hke5iUoeB7E/gQtrs9I37zAJ0Vjw==} + + '@types/stack-utils@2.0.3': + resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} + + '@types/yargs-parser@21.0.3': + resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} + + '@types/yargs@17.0.35': + resolution: {integrity: sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==} + + '@uiw/codemirror-extensions-basic-setup@4.25.11': + resolution: {integrity: sha512-otyFa+n9IOYtEjaKOxPedHkj15fTPUF21wdR9pv0GpZPfuGl27cvmcv6+tognbRu9VvEcsHKE+ESoszeo3KfTw==} + peerDependencies: + '@codemirror/autocomplete': '>=6.0.0' + '@codemirror/commands': '>=6.0.0' + '@codemirror/language': '>=6.0.0' + '@codemirror/lint': '>=6.0.0' + '@codemirror/search': '>=6.0.0' + '@codemirror/state': '>=6.0.0' + '@codemirror/view': '>=6.0.0' + + '@uiw/react-codemirror@4.25.11': + resolution: {integrity: sha512-DYVFAKLX+F/4JS9N/7xexh+TICrlncwkX9HKKInrP1bwO0tSfc3k0GB6oawTYhelVKh20cX3TuRx+NJSkVXuMw==} + peerDependencies: + '@babel/runtime': '>=7.11.0' + '@codemirror/state': '>=6.0.0' + '@codemirror/theme-one-dark': '>=6.0.0' + '@codemirror/view': '>=6.0.0' + codemirror: '>=6.0.0' + react: '>=17.0.0' + react-dom: '>=17.0.0' + + ansi-escapes@4.3.2: + resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} + engines: {node: '>=8'} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + ansi-styles@5.2.0: + resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} + engines: {node: '>=10'} + + any-promise@1.3.0: + resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} + + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + + arg@5.0.2: + resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} + + argparse@1.0.10: + resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + + autoprefixer@10.5.4: + resolution: {integrity: sha512-MaU0U/za7N3r6brxD4YB/l4NSrFzLPlANv6wEuQVaIPlD3L4W9rFcQPbL/EilY9BHhHvhfcz3gInDLrEtWT4EA==} + engines: {node: ^10 || ^12 || >=14} + hasBin: true + peerDependencies: + postcss: ^8.1.0 + + babel-jest@29.7.0: + resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@babel/core': ^7.8.0 + + babel-plugin-istanbul@6.1.1: + resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==} + engines: {node: '>=8'} + + babel-plugin-jest-hoist@29.6.3: + resolution: {integrity: sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + babel-preset-current-node-syntax@1.2.0: + resolution: {integrity: sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==} + peerDependencies: + '@babel/core': ^7.0.0 || ^8.0.0-0 + + babel-preset-jest@29.6.3: + resolution: {integrity: sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@babel/core': ^7.0.0 + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + balanced-match@4.0.4: + resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} + engines: {node: 18 || 20 || >=22} + + baseline-browser-mapping@2.11.18: + resolution: {integrity: sha512-1iEmLEYSiE1SeBoAfPo/Mnx3PzfzHUkDK61ASkCpuk3YXugYLH5DYK1SzqV55F8FMI6s0F+/tCP7Polz1QRjxw==} + engines: {node: '>=6.0.0'} + hasBin: true + + binary-extensions@2.3.0: + resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} + engines: {node: '>=8'} + + brace-expansion@1.1.18: + resolution: {integrity: sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==} + + brace-expansion@5.0.9: + resolution: {integrity: sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==} + engines: {node: 20 || >=22} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + browserslist@4.28.8: + resolution: {integrity: sha512-V2NpofLblG64mfOtSgDhOJESZEGogzDMBv/q+W6oc4LXWP/q75eOXoOaaOu1EOadB9U4Bwx/e0yzbvwKH8zalA==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + bs-logger@0.2.6: + resolution: {integrity: sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==} + engines: {node: '>= 6'} + + bser@2.1.1: + resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} + + buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + camelcase-css@2.0.1: + resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} + engines: {node: '>= 6'} + + camelcase@5.3.1: + resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} + engines: {node: '>=6'} + + camelcase@6.3.0: + resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} + engines: {node: '>=10'} + + caniuse-lite@1.0.30001809: + resolution: {integrity: sha512-xxWVywk6a6Arlk+hymeycyn/VgqEfLDxupvhH/xiY5SJ/18kmi9o6MiO320DCUzypORHLtvh0I4i04tUhCNHNQ==} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + char-regex@1.0.2: + resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} + engines: {node: '>=10'} + + chokidar@3.6.0: + resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} + engines: {node: '>= 8.10.0'} + + ci-info@3.9.0: + resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} + engines: {node: '>=8'} + + cjs-module-lexer@1.4.3: + resolution: {integrity: sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==} + + client-only@0.0.1: + resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} + + cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + + co@4.6.0: + resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} + engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} + + codemirror@6.0.2: + resolution: {integrity: sha512-VhydHotNW5w1UGK0Qj96BwSk/Zqbp9WbnyK2W/eVMv4QyF41INRGpjUhFJY7/uDNuudSc33a/PKr4iDqRduvHw==} + + collect-v8-coverage@1.0.3: + resolution: {integrity: sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + commander@4.1.1: + resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} + engines: {node: '>= 6'} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + create-jest@29.7.0: + resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + hasBin: true + + crelt@1.0.7: + resolution: {integrity: sha512-aK6BbWfhf4U/wCcLHKPJl/xa6VkVstRaPywWtMKGwuOLc/wZTyQYuoxgvZnNsBvv7Kg3YTBQYYBCggcviQczuA==} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + dedent@1.7.2: + resolution: {integrity: sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==} + peerDependencies: + babel-plugin-macros: ^3.1.0 + peerDependenciesMeta: + babel-plugin-macros: + optional: true + + deepmerge@4.3.1: + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} + engines: {node: '>=0.10.0'} + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + detect-newline@3.1.0: + resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} + engines: {node: '>=8'} + + didyoumean@1.2.2: + resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} + + diff-sequences@29.6.3: + resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + dlv@1.1.3: + resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} + + electron-to-chromium@1.5.412: + resolution: {integrity: sha512-z4rMe3esBzlzovKHj4gxJnsCGZRK5l4baUvm+gCGJBPE+gsyUMKsuU9tnEUtI1dOebXz1ytAPGjvXhmQ7rIPwA==} + + emittery@0.13.1: + resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==} + engines: {node: '>=12'} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + error-ex@1.3.4: + resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + esbuild@0.28.2: + resolution: {integrity: sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==} + engines: {node: '>=18'} + hasBin: true + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + escape-string-regexp@2.0.0: + resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} + engines: {node: '>=8'} + + esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + + execa@5.1.1: + resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} + engines: {node: '>=10'} + + exit@0.1.2: + resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==} + engines: {node: '>= 0.8.0'} + + expect@29.7.0: + resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + fast-glob@3.3.3: + resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} + engines: {node: '>=8.6.0'} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fastq@1.20.1: + resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} + + fb-watchman@2.0.2: + resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + find-up@4.1.0: + resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} + engines: {node: '>=8'} + + foreground-child@3.3.1: + resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} + engines: {node: '>=14'} + + fraction.js@5.3.4: + resolution: {integrity: sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==} + + fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + + get-package-type@0.1.0: + resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} + engines: {node: '>=8.0.0'} + + get-stream@6.0.1: + resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} + engines: {node: '>=10'} + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + + glob@11.1.0: + resolution: {integrity: sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw==} + engines: {node: 20 || >=22} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me + hasBin: true + + glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + handlebars@4.7.9: + resolution: {integrity: sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==} + engines: {node: '>=0.4.7'} + hasBin: true + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + hasown@2.0.4: + resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==} + engines: {node: '>= 0.4'} + + html-escaper@2.0.2: + resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + + human-signals@2.1.0: + resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} + engines: {node: '>=10.17.0'} + + import-local@3.2.0: + resolution: {integrity: sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==} + engines: {node: '>=8'} + hasBin: true + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + + is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + + is-core-module@2.16.2: + resolution: {integrity: sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==} + engines: {node: '>= 0.4'} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + is-generator-fn@2.1.0: + resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==} + engines: {node: '>=6'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + istanbul-lib-coverage@3.2.2: + resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} + engines: {node: '>=8'} + + istanbul-lib-instrument@5.2.1: + resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==} + engines: {node: '>=8'} + + istanbul-lib-instrument@6.0.3: + resolution: {integrity: sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==} + engines: {node: '>=10'} + + istanbul-lib-report@3.0.1: + resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} + engines: {node: '>=10'} + + istanbul-lib-source-maps@4.0.1: + resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} + engines: {node: '>=10'} + + istanbul-reports@3.2.0: + resolution: {integrity: sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==} + engines: {node: '>=8'} + + jackspeak@4.2.3: + resolution: {integrity: sha512-ykkVRwrYvFm1nb2AJfKKYPr0emF6IiXDYUaFx4Zn9ZuIH7MrzEZ3sD5RlqGXNRpHtvUHJyOnCEFxOlNDtGo7wg==} + engines: {node: 20 || >=22} + + jest-changed-files@29.7.0: + resolution: {integrity: sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-circus@29.7.0: + resolution: {integrity: sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-cli@29.7.0: + resolution: {integrity: sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + hasBin: true + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + jest-config@29.7.0: + resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@types/node': '*' + ts-node: '>=9.0.0' + peerDependenciesMeta: + '@types/node': + optional: true + ts-node: + optional: true + + jest-diff@29.7.0: + resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-docblock@29.7.0: + resolution: {integrity: sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-each@29.7.0: + resolution: {integrity: sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-environment-node@29.7.0: + resolution: {integrity: sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-get-type@29.6.3: + resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-haste-map@29.7.0: + resolution: {integrity: sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-leak-detector@29.7.0: + resolution: {integrity: sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-matcher-utils@29.7.0: + resolution: {integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-message-util@29.7.0: + resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-mock@29.7.0: + resolution: {integrity: sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-pnp-resolver@1.2.3: + resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==} + engines: {node: '>=6'} + peerDependencies: + jest-resolve: '*' + peerDependenciesMeta: + jest-resolve: + optional: true + + jest-regex-util@29.6.3: + resolution: {integrity: sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-resolve-dependencies@29.7.0: + resolution: {integrity: sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-resolve@29.7.0: + resolution: {integrity: sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-runner@29.7.0: + resolution: {integrity: sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-runtime@29.7.0: + resolution: {integrity: sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-snapshot@29.7.0: + resolution: {integrity: sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-util@29.7.0: + resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-validate@29.7.0: + resolution: {integrity: sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-watcher@29.7.0: + resolution: {integrity: sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-worker@29.7.0: + resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest@29.7.0: + resolution: {integrity: sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + hasBin: true + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + jiti@1.21.7: + resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==} + hasBin: true + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-yaml@3.15.1: + resolution: {integrity: sha512-S99WuO3HlhO3XN41EtYUNl9zzXjoJx7QvmipxsJVxtCBT0YHEFy+iOJhjSvrmV12nYhWpZaM8lPHkJm0yUMbag==} + hasBin: true + + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + + json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + jsonldjs@0.1.2: + resolution: {integrity: sha512-OsJYDgcm/H2u1/r2h1Buic9ouMzitYc5cC/ESqJmtmp150x8h6rLWpQHrTaFnju+vu3nxPcg2HEwnaeUeqTNHw==} + + kleur@3.0.3: + resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} + engines: {node: '>=6'} + + latex2js@4.5.0: + resolution: {integrity: sha512-nhgpnbL3R+Zx6cL8i3dRZqGZz/LfDsIXCcjnzavsAOd6yfB2BXJyZgE5E/f75D+8RHigRDU7n5Ctew4TaRn1kw==} + + latex2react@4.4.2: + resolution: {integrity: sha512-3kusYgkJk2n/iX4T7r9AvDg2IPQtzk2PkbvdNH4N6MYSjQUuwHnb/UCcyrauQkEzejNwNJ0tgqBjICCSsnpnVw==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + leven@3.1.0: + resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} + engines: {node: '>=6'} + + lilconfig@3.1.3: + resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} + engines: {node: '>=14'} + + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + + locate-path@5.0.0: + resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} + engines: {node: '>=8'} + + lodash.memoize@4.1.2: + resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} + + lru-cache@11.5.2: + resolution: {integrity: sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==} + engines: {node: 20 || >=22} + + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + + make-dir@4.0.0: + resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} + engines: {node: '>=10'} + + make-error@1.3.6: + resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + + makeerror@1.0.12: + resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} + + mathjaxjs-react@4.2.0: + resolution: {integrity: sha512-pWDpuD/F4jqlRk7vu6e86kQuLSV8AgtKh7eUv+7BU+mYqwVHrbDR00n9s798hJU8MLqJ3MVHl6/Ra+DamQR9Ow==} + peerDependencies: + react: ^18.0.0 || ^19.0.0 + + mathjaxjs@4.2.0: + resolution: {integrity: sha512-FvAjuYxJREp3Ars33ShNC9iFd752V/BmAjVMkfTQJVomJbSvNyOFSPPfjSIwabtTuniE4/Kee9xar5+e75SG+A==} + + merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + + mimic-fn@2.1.0: + resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} + engines: {node: '>=6'} + + minimatch@10.2.6: + resolution: {integrity: sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==} + engines: {node: 18 || 20 || >=22} + + minimatch@3.1.5: + resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} + + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + minipass@7.1.3: + resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} + engines: {node: '>=16 || 14 >=14.17'} + + mkdirp@3.0.1: + resolution: {integrity: sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==} + engines: {node: '>=10'} + hasBin: true + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + mz@2.7.0: + resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + + nanoid@3.3.18: + resolution: {integrity: sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + neo-async@2.6.2: + resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} + + next-seo@6.8.0: + resolution: {integrity: sha512-zcxaV67PFXCSf8e6SXxbxPaOTgc8St/esxfsYXfQXMM24UESUVSXFm7f2A9HMkAwa0Gqn4s64HxYZAGfdF4Vhg==} + peerDependencies: + next: ^8.1.1-canary.54 || >=9.0.0 + react: '>=16.0.0' + react-dom: '>=16.0.0' + + next@16.1.6: + resolution: {integrity: sha512-hkyRkcu5x/41KoqnROkfTm2pZVbKxvbZRuNvKXLRXxs3VfyO0WhY50TQS40EuKO9SW3rBj/sF3WbVwDACeMZyw==} + engines: {node: '>=20.9.0'} + hasBin: true + peerDependencies: + '@opentelemetry/api': ^1.1.0 + '@playwright/test': ^1.51.1 + babel-plugin-react-compiler: '*' + react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 + react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 + sass: ^1.3.0 + peerDependenciesMeta: + '@opentelemetry/api': + optional: true + '@playwright/test': + optional: true + babel-plugin-react-compiler: + optional: true + sass: + optional: true + + node-int64@0.4.0: + resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} + + node-releases@2.0.53: + resolution: {integrity: sha512-D9UOmYG3UH1V+ENW56t5QXBwJw1YEY18ruVeus89Rw+SyIgjPkCO84bRzO3uNIYosJbNwiabWVn48o3uJLjxFQ==} + engines: {node: '>=18'} + + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + npm-run-path@4.0.1: + resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} + engines: {node: '>=8'} + + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + object-hash@3.0.0: + resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} + engines: {node: '>= 6'} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + onetime@5.1.2: + resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} + engines: {node: '>=6'} + + p-limit@2.3.0: + resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} + engines: {node: '>=6'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-locate@4.1.0: + resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} + engines: {node: '>=8'} + + p-try@2.2.0: + resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} + engines: {node: '>=6'} + + package-json-from-dist@1.0.1: + resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + + parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + path-scurry@2.0.2: + resolution: {integrity: sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==} + engines: {node: 18 || 20 || >=22} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.2: + resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==} + engines: {node: '>=8.6'} + + picomatch@4.0.5: + resolution: {integrity: sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==} + engines: {node: '>=12'} + + pirates@4.0.7: + resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} + engines: {node: '>= 6'} + + pkg-dir@4.2.0: + resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} + engines: {node: '>=8'} + + postcss-import@15.1.0: + resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} + engines: {node: '>=14.0.0'} + peerDependencies: + postcss: ^8.0.0 + + postcss-js@4.1.0: + resolution: {integrity: sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==} + engines: {node: ^12 || ^14 || >= 16} + peerDependencies: + postcss: ^8.4.21 + + postcss-load-config@6.0.1: + resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==} + engines: {node: '>= 18'} + peerDependencies: + jiti: '>=1.21.0' + postcss: '>=8.0.9' + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + jiti: + optional: true + postcss: + optional: true + tsx: + optional: true + yaml: + optional: true + + postcss-nested@6.2.0: + resolution: {integrity: sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==} + engines: {node: '>=12.0'} + peerDependencies: + postcss: ^8.2.14 + + postcss-selector-parser@6.1.4: + resolution: {integrity: sha512-bIoJLOmjCO1S9XdY/DcnR5hJxvrDir1PbGChrzXG3vw0/FOliy/fA3dmdhQ441kah4gKv+TwckGzex6wNS5cnQ==} + engines: {node: '>=4'} + + postcss-value-parser@4.2.0: + resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + + postcss@8.4.31: + resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} + engines: {node: ^10 || ^12 || >=14} + + postcss@8.5.26: + resolution: {integrity: sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ==} + engines: {node: ^10 || ^12 || >=14} + + pretty-format@29.7.0: + resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + prompts@2.4.2: + resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} + engines: {node: '>= 6'} + + pure-rand@6.1.0: + resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + react-dom@19.2.4: + resolution: {integrity: sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==} + peerDependencies: + react: ^19.2.4 + + react-is@18.3.1: + resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} + + react@19.2.4: + resolution: {integrity: sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==} + engines: {node: '>=0.10.0'} + + read-cache@1.0.2: + resolution: {integrity: sha512-/peqiBB/n07gQGLsWaHho3WfvUyRscw0gYTsEFMhrIe/nWLkYaf5SbKYjGYqtRV3aPwykJgF2VEMo1ac4bnsGA==} + + readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + + resolve-cwd@3.0.0: + resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} + engines: {node: '>=8'} + + resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + + resolve.exports@2.0.3: + resolution: {integrity: sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==} + engines: {node: '>=10'} + + resolve@1.22.12: + resolution: {integrity: sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==} + engines: {node: '>= 0.4'} + hasBin: true + + reusify@1.1.0: + resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + scheduler@0.27.0: + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} + + schema-dts@1.1.5: + resolution: {integrity: sha512-RJr9EaCmsLzBX2NDiO5Z3ux2BVosNZN5jo0gWgsyKvxKIUL5R3swNvoorulAeL9kLB0iTSX7V6aokhla2m7xbg==} + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + semver@7.8.5: + resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} + engines: {node: '>=10'} + hasBin: true + + sharp@0.34.5: + resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + + sisteransi@1.0.5: + resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + + slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + source-map-support@0.5.13: + resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==} + + source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + + sprintf-js@1.0.3: + resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + + stack-utils@2.0.6: + resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} + engines: {node: '>=10'} + + string-length@4.0.2: + resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==} + engines: {node: '>=10'} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-bom@4.0.0: + resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==} + engines: {node: '>=8'} + + strip-final-newline@2.0.0: + resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} + engines: {node: '>=6'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + style-mod@4.1.3: + resolution: {integrity: sha512-i/n8VsZydrugj3Iuzll8+x/00GH2vnYsk1eomD8QiRrSAeW6ItbCQDtfXCeJHd0iwiNagqjQkvpvREEPtW3IoQ==} + + styled-jsx@5.1.6: + resolution: {integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==} + engines: {node: '>= 12.0.0'} + peerDependencies: + '@babel/core': '*' + babel-plugin-macros: '*' + react: '>= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0' + peerDependenciesMeta: + '@babel/core': + optional: true + babel-plugin-macros: + optional: true + + sucrase@3.35.1: + resolution: {integrity: sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==} + engines: {node: '>=16 || 14 >=14.17'} + hasBin: true + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + tailwindcss@3.4.19: + resolution: {integrity: sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==} + engines: {node: '>=14.0.0'} + hasBin: true + + test-exclude@6.0.0: + resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} + engines: {node: '>=8'} + + thenify-all@1.6.0: + resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} + engines: {node: '>=0.8'} + + thenify@3.3.1: + resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + + tinyglobby@0.2.17: + resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} + engines: {node: '>=12.0.0'} + + tmpl@1.0.5: + resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + ts-interface-checker@0.1.13: + resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + + ts-jest@29.4.12: + resolution: {integrity: sha512-Ov6ClY53Fflh6BGAnY2DlTq1hYDrTycz2PVTXBWFW2CU+9zrEqAp9fWdGXl42EXO5RLSFAcAZ2JFKbP+zBTFfw==} + engines: {node: ^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@babel/core': '>=7.0.0-beta.0 <8' + '@jest/transform': ^29.0.0 || ^30.0.0 + '@jest/types': ^29.0.0 || ^30.0.0 + babel-jest: ^29.0.0 || ^30.0.0 + esbuild: '*' + jest: ^29.0.0 || ^30.0.0 + jest-util: ^29.0.0 || ^30.0.0 + typescript: '>=4.3 <7' + peerDependenciesMeta: + '@babel/core': + optional: true + '@jest/transform': + optional: true + '@jest/types': + optional: true + babel-jest: + optional: true + esbuild: + optional: true + jest-util: + optional: true + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + tsx@4.23.12: + resolution: {integrity: sha512-FDf4L4sYzKtzWYhU/Xm0AQFdTjdIxNo9ElTf2mxXM6k8YMHXzYUe4yODVaXP4V9uMFbVg8c0qyBccK2OOxb45Q==} + engines: {node: '>=18.0.0'} + hasBin: true + + type-detect@4.0.8: + resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} + engines: {node: '>=4'} + + type-fest@0.21.3: + resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} + engines: {node: '>=10'} + + type-fest@4.41.0: + resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} + engines: {node: '>=16'} + + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + + uglify-js@3.19.3: + resolution: {integrity: sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==} + engines: {node: '>=0.8.0'} + hasBin: true + + undici-types@6.21.0: + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + + update-browserslist-db@1.3.1: + resolution: {integrity: sha512-ZZ61DsRsOnakl74HAmp3oSN4aXUmEWXf+i/yv0h7tIBfICc3VdrFErQKUUKPgu3AMsTUMbcongALEN4l6GSUrQ==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + v8-to-istanbul@9.3.0: + resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==} + engines: {node: '>=10.12.0'} + + w3c-keyname@2.2.8: + resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==} + + walker@1.0.8: + resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + wordwrap@1.0.0: + resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + write-file-atomic@4.0.2: + resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + + yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + + yargs@17.7.3: + resolution: {integrity: sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g==} + engines: {node: '>=12'} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + +snapshots: + + '@alloc/quick-lru@5.2.0': {} + + '@babel/code-frame@7.29.7': + dependencies: + '@babel/helper-validator-identifier': 7.29.7 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/compat-data@7.29.7': {} + + '@babel/core@7.29.7(supports-color@8.1.1)': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/generator': 7.29.8 + '@babel/helper-compilation-targets': 7.29.7 + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) + '@babel/helpers': 7.29.7 + '@babel/parser': 7.29.8 + '@babel/template': 7.29.7 + '@babel/traverse': 7.29.8(supports-color@8.1.1) + '@babel/types': 7.29.8 + '@jridgewell/remapping': 2.3.5 + convert-source-map: 2.0.0 + debug: 4.4.3(supports-color@8.1.1) + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.29.8': + dependencies: + '@babel/parser': 7.29.8 + '@babel/types': 7.29.8 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + + '@babel/helper-compilation-targets@7.29.7': + dependencies: + '@babel/compat-data': 7.29.7 + '@babel/helper-validator-option': 7.29.7 + browserslist: 4.28.8 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-globals@7.29.7': {} + + '@babel/helper-module-imports@7.29.7(supports-color@8.1.1)': + dependencies: + '@babel/traverse': 7.29.8(supports-color@8.1.1) + '@babel/types': 7.29.8 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1)': + dependencies: + '@babel/core': 7.29.7(supports-color@8.1.1) + '@babel/helper-module-imports': 7.29.7(supports-color@8.1.1) + '@babel/helper-validator-identifier': 7.29.7 + '@babel/traverse': 7.29.8(supports-color@8.1.1) + transitivePeerDependencies: + - supports-color + + '@babel/helper-plugin-utils@7.29.7': {} + + '@babel/helper-string-parser@7.29.7': {} + + '@babel/helper-validator-identifier@7.29.7': {} + + '@babel/helper-validator-option@7.29.7': {} + + '@babel/helpers@7.29.7': + dependencies: + '@babel/template': 7.29.7 + '@babel/types': 7.29.8 + + '@babel/parser@7.29.8': + dependencies: + '@babel/types': 7.29.8 + + '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.29.7(supports-color@8.1.1))': + dependencies: + '@babel/core': 7.29.7(supports-color@8.1.1) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.29.7(supports-color@8.1.1))': + dependencies: + '@babel/core': 7.29.7(supports-color@8.1.1) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.29.7(supports-color@8.1.1))': + dependencies: + '@babel/core': 7.29.7(supports-color@8.1.1) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.29.7(supports-color@8.1.1))': + dependencies: + '@babel/core': 7.29.7(supports-color@8.1.1) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-syntax-import-attributes@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))': + dependencies: + '@babel/core': 7.29.7(supports-color@8.1.1) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.29.7(supports-color@8.1.1))': + dependencies: + '@babel/core': 7.29.7(supports-color@8.1.1) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.29.7(supports-color@8.1.1))': + dependencies: + '@babel/core': 7.29.7(supports-color@8.1.1) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-syntax-jsx@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))': + dependencies: + '@babel/core': 7.29.7(supports-color@8.1.1) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.29.7(supports-color@8.1.1))': + dependencies: + '@babel/core': 7.29.7(supports-color@8.1.1) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.29.7(supports-color@8.1.1))': + dependencies: + '@babel/core': 7.29.7(supports-color@8.1.1) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.29.7(supports-color@8.1.1))': + dependencies: + '@babel/core': 7.29.7(supports-color@8.1.1) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.29.7(supports-color@8.1.1))': + dependencies: + '@babel/core': 7.29.7(supports-color@8.1.1) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.29.7(supports-color@8.1.1))': + dependencies: + '@babel/core': 7.29.7(supports-color@8.1.1) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.29.7(supports-color@8.1.1))': + dependencies: + '@babel/core': 7.29.7(supports-color@8.1.1) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.29.7(supports-color@8.1.1))': + dependencies: + '@babel/core': 7.29.7(supports-color@8.1.1) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.29.7(supports-color@8.1.1))': + dependencies: + '@babel/core': 7.29.7(supports-color@8.1.1) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-syntax-typescript@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))': + dependencies: + '@babel/core': 7.29.7(supports-color@8.1.1) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/runtime@8.0.0': {} + + '@babel/template@7.29.7': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/parser': 7.29.8 + '@babel/types': 7.29.8 + + '@babel/traverse@7.29.8(supports-color@8.1.1)': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/generator': 7.29.8 + '@babel/helper-globals': 7.29.7 + '@babel/parser': 7.29.8 + '@babel/template': 7.29.7 + '@babel/types': 7.29.8 + debug: 4.4.3(supports-color@8.1.1) + transitivePeerDependencies: + - supports-color + + '@babel/types@7.29.8': + dependencies: + '@babel/helper-string-parser': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + + '@bcoe/v8-coverage@0.2.3': {} + + '@codemirror/autocomplete@6.20.3': + dependencies: + '@codemirror/language': 6.12.4 + '@codemirror/state': 6.7.1 + '@codemirror/view': 6.43.9 + '@lezer/common': 1.5.2 + + '@codemirror/commands@6.11.0': + dependencies: + '@codemirror/language': 6.12.4 + '@codemirror/state': 6.7.1 + '@codemirror/view': 6.43.9 + '@lezer/common': 1.5.2 + + '@codemirror/language@6.12.4': + dependencies: + '@codemirror/state': 6.7.1 + '@codemirror/view': 6.43.9 + '@lezer/common': 1.5.2 + '@lezer/highlight': 1.2.3 + '@lezer/lr': 1.4.10 + style-mod: 4.1.3 + + '@codemirror/legacy-modes@6.5.3': + dependencies: + '@codemirror/language': 6.12.4 + + '@codemirror/lint@6.9.7': + dependencies: + '@codemirror/state': 6.7.1 + '@codemirror/view': 6.43.9 + crelt: 1.0.7 + + '@codemirror/search@6.7.1': + dependencies: + '@codemirror/state': 6.7.1 + '@codemirror/view': 6.43.9 + crelt: 1.0.7 + + '@codemirror/state@6.7.1': + dependencies: + '@marijn/find-cluster-break': 1.0.4 + + '@codemirror/theme-one-dark@6.1.3': + dependencies: + '@codemirror/language': 6.12.4 + '@codemirror/state': 6.7.1 + '@codemirror/view': 6.43.9 + '@lezer/highlight': 1.2.3 + + '@codemirror/view@6.43.9': + dependencies: + '@codemirror/state': 6.7.1 + crelt: 1.0.7 + style-mod: 4.1.3 + w3c-keyname: 2.2.8 + + '@emnapi/runtime@1.11.3': + dependencies: + tslib: 2.8.1 + optional: true + + '@esbuild/aix-ppc64@0.28.2': + optional: true + + '@esbuild/android-arm64@0.28.2': + optional: true + + '@esbuild/android-arm@0.28.2': + optional: true + + '@esbuild/android-x64@0.28.2': + optional: true + + '@esbuild/darwin-arm64@0.28.2': + optional: true + + '@esbuild/darwin-x64@0.28.2': + optional: true + + '@esbuild/freebsd-arm64@0.28.2': + optional: true + + '@esbuild/freebsd-x64@0.28.2': + optional: true + + '@esbuild/linux-arm64@0.28.2': + optional: true + + '@esbuild/linux-arm@0.28.2': + optional: true + + '@esbuild/linux-ia32@0.28.2': + optional: true + + '@esbuild/linux-loong64@0.28.2': + optional: true + + '@esbuild/linux-mips64el@0.28.2': + optional: true + + '@esbuild/linux-ppc64@0.28.2': + optional: true + + '@esbuild/linux-riscv64@0.28.2': + optional: true + + '@esbuild/linux-s390x@0.28.2': + optional: true + + '@esbuild/linux-x64@0.28.2': + optional: true + + '@esbuild/netbsd-arm64@0.28.2': + optional: true + + '@esbuild/netbsd-x64@0.28.2': + optional: true + + '@esbuild/openbsd-arm64@0.28.2': + optional: true + + '@esbuild/openbsd-x64@0.28.2': + optional: true + + '@esbuild/openharmony-arm64@0.28.2': + optional: true + + '@esbuild/sunos-x64@0.28.2': + optional: true + + '@esbuild/win32-arm64@0.28.2': + optional: true + + '@esbuild/win32-ia32@0.28.2': + optional: true + + '@esbuild/win32-x64@0.28.2': + optional: true + + '@img/colour@1.1.0': + optional: true + + '@img/sharp-darwin-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-arm64': 1.2.4 + optional: true + + '@img/sharp-darwin-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-x64': 1.2.4 + optional: true + + '@img/sharp-libvips-darwin-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-darwin-x64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm@1.2.4': + optional: true + + '@img/sharp-libvips-linux-ppc64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-riscv64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-s390x@1.2.4': + optional: true + + '@img/sharp-libvips-linux-x64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + optional: true + + '@img/sharp-linux-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.2.4 + optional: true + + '@img/sharp-linux-arm@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.2.4 + optional: true + + '@img/sharp-linux-ppc64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-ppc64': 1.2.4 + optional: true + + '@img/sharp-linux-riscv64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-riscv64': 1.2.4 + optional: true + + '@img/sharp-linux-s390x@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-s390x': 1.2.4 + optional: true + + '@img/sharp-linux-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-x64': 1.2.4 + optional: true + + '@img/sharp-linuxmusl-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + optional: true + + '@img/sharp-linuxmusl-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + optional: true + + '@img/sharp-wasm32@0.34.5': + dependencies: + '@emnapi/runtime': 1.11.3 + optional: true + + '@img/sharp-win32-arm64@0.34.5': + optional: true + + '@img/sharp-win32-ia32@0.34.5': + optional: true + + '@img/sharp-win32-x64@0.34.5': + optional: true + + '@isaacs/cliui@9.0.0': {} + + '@istanbuljs/load-nyc-config@1.1.0': + dependencies: + camelcase: 5.3.1 + find-up: 4.1.0 + get-package-type: 0.1.0 + js-yaml: 3.15.1 + resolve-from: 5.0.0 + + '@istanbuljs/schema@0.1.6': {} + + '@jest/console@29.7.0': + dependencies: + '@jest/types': 29.6.3 + '@types/node': 22.20.1 + chalk: 4.1.2 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + slash: 3.0.0 + + '@jest/core@29.7.0(supports-color@8.1.1)': + dependencies: + '@jest/console': 29.7.0 + '@jest/reporters': 29.7.0(supports-color@8.1.1) + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0(supports-color@8.1.1) + '@jest/types': 29.6.3 + '@types/node': 22.20.1 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + ci-info: 3.9.0 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-changed-files: 29.7.0 + jest-config: 29.7.0(@types/node@22.20.1)(supports-color@8.1.1) + jest-haste-map: 29.7.0 + jest-message-util: 29.7.0 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-resolve-dependencies: 29.7.0(supports-color@8.1.1) + jest-runner: 29.7.0(supports-color@8.1.1) + jest-runtime: 29.7.0(supports-color@8.1.1) + jest-snapshot: 29.7.0(supports-color@8.1.1) + jest-util: 29.7.0 + jest-validate: 29.7.0 + jest-watcher: 29.7.0 + micromatch: 4.0.8 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-ansi: 6.0.1 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + - ts-node + + '@jest/environment@29.7.0': + dependencies: + '@jest/fake-timers': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 22.20.1 + jest-mock: 29.7.0 + + '@jest/expect-utils@29.7.0': + dependencies: + jest-get-type: 29.6.3 + + '@jest/expect@29.7.0(supports-color@8.1.1)': + dependencies: + expect: 29.7.0 + jest-snapshot: 29.7.0(supports-color@8.1.1) + transitivePeerDependencies: + - supports-color + + '@jest/fake-timers@29.7.0': + dependencies: + '@jest/types': 29.6.3 + '@sinonjs/fake-timers': 10.3.0 + '@types/node': 22.20.1 + jest-message-util: 29.7.0 + jest-mock: 29.7.0 + jest-util: 29.7.0 + + '@jest/globals@29.7.0(supports-color@8.1.1)': + dependencies: + '@jest/environment': 29.7.0 + '@jest/expect': 29.7.0(supports-color@8.1.1) + '@jest/types': 29.6.3 + jest-mock: 29.7.0 + transitivePeerDependencies: + - supports-color + + '@jest/reporters@29.7.0(supports-color@8.1.1)': + dependencies: + '@bcoe/v8-coverage': 0.2.3 + '@jest/console': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0(supports-color@8.1.1) + '@jest/types': 29.6.3 + '@jridgewell/trace-mapping': 0.3.31 + '@types/node': 22.20.1 + chalk: 4.1.2 + collect-v8-coverage: 1.0.3 + exit: 0.1.2 + glob: 7.2.3 + graceful-fs: 4.2.11 + istanbul-lib-coverage: 3.2.2 + istanbul-lib-instrument: 6.0.3(supports-color@8.1.1) + istanbul-lib-report: 3.0.1 + istanbul-lib-source-maps: 4.0.1(supports-color@8.1.1) + istanbul-reports: 3.2.0 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + jest-worker: 29.7.0 + slash: 3.0.0 + string-length: 4.0.2 + strip-ansi: 6.0.1 + v8-to-istanbul: 9.3.0 + transitivePeerDependencies: + - supports-color + + '@jest/schemas@29.6.3': + dependencies: + '@sinclair/typebox': 0.27.12 + + '@jest/source-map@29.6.3': + dependencies: + '@jridgewell/trace-mapping': 0.3.31 + callsites: 3.1.0 + graceful-fs: 4.2.11 + + '@jest/test-result@29.7.0': + dependencies: + '@jest/console': 29.7.0 + '@jest/types': 29.6.3 + '@types/istanbul-lib-coverage': 2.0.6 + collect-v8-coverage: 1.0.3 + + '@jest/test-sequencer@29.7.0': + dependencies: + '@jest/test-result': 29.7.0 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + slash: 3.0.0 + + '@jest/transform@29.7.0(supports-color@8.1.1)': + dependencies: + '@babel/core': 7.29.7(supports-color@8.1.1) + '@jest/types': 29.6.3 + '@jridgewell/trace-mapping': 0.3.31 + babel-plugin-istanbul: 6.1.1(supports-color@8.1.1) + chalk: 4.1.2 + convert-source-map: 2.0.0 + fast-json-stable-stringify: 2.1.0 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + jest-regex-util: 29.6.3 + jest-util: 29.7.0 + micromatch: 4.0.8 + pirates: 4.0.7 + slash: 3.0.0 + write-file-atomic: 4.0.2 + transitivePeerDependencies: + - supports-color + + '@jest/types@29.6.3': + dependencies: + '@jest/schemas': 29.6.3 + '@types/istanbul-lib-coverage': 2.0.6 + '@types/istanbul-reports': 3.0.4 + '@types/node': 22.20.1 + '@types/yargs': 17.0.35 + chalk: 4.1.2 + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@latex2js/macros@3.2.0': {} + + '@latex2js/pstricks@4.2.0': + dependencies: + '@latex2js/settings': 4.2.0 + '@latex2js/utils': 4.2.0 + + '@latex2js/settings@4.2.0': + dependencies: + '@latex2js/utils': 4.2.0 + + '@latex2js/utils@4.2.0': {} + + '@lezer/common@1.5.2': {} + + '@lezer/highlight@1.2.3': + dependencies: + '@lezer/common': 1.5.2 + + '@lezer/lr@1.4.10': + dependencies: + '@lezer/common': 1.5.2 + + '@marijn/find-cluster-break@1.0.4': {} + + '@next/env@16.1.6': {} + + '@next/swc-darwin-arm64@16.1.6': + optional: true + + '@next/swc-darwin-x64@16.1.6': + optional: true + + '@next/swc-linux-arm64-gnu@16.1.6': + optional: true + + '@next/swc-linux-arm64-musl@16.1.6': + optional: true + + '@next/swc-linux-x64-gnu@16.1.6': + optional: true + + '@next/swc-linux-x64-musl@16.1.6': + optional: true + + '@next/swc-win32-arm64-msvc@16.1.6': + optional: true + + '@next/swc-win32-x64-msvc@16.1.6': + optional: true + + '@nodelib/fs.scandir@2.1.5': + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + '@nodelib/fs.stat@2.0.5': {} + + '@nodelib/fs.walk@1.2.8': + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.20.1 + + '@sinclair/typebox@0.27.12': {} + + '@sinonjs/commons@3.0.1': + dependencies: + type-detect: 4.0.8 + + '@sinonjs/fake-timers@10.3.0': + dependencies: + '@sinonjs/commons': 3.0.1 + + '@swc/helpers@0.5.15': + dependencies: + tslib: 2.8.1 + + '@types/babel__core@7.20.5': + dependencies: + '@babel/parser': 7.29.8 + '@babel/types': 7.29.8 + '@types/babel__generator': 7.27.0 + '@types/babel__template': 7.4.4 + '@types/babel__traverse': 7.28.0 + + '@types/babel__generator@7.27.0': + dependencies: + '@babel/types': 7.29.8 + + '@types/babel__template@7.4.4': + dependencies: + '@babel/parser': 7.29.8 + '@babel/types': 7.29.8 + + '@types/babel__traverse@7.28.0': + dependencies: + '@babel/types': 7.29.8 + + '@types/glob@8.1.0': + dependencies: + '@types/minimatch': 5.1.2 + '@types/node': 22.20.1 + + '@types/graceful-fs@4.1.9': + dependencies: + '@types/node': 22.20.1 + + '@types/istanbul-lib-coverage@2.0.6': {} + + '@types/istanbul-lib-report@3.0.3': + dependencies: + '@types/istanbul-lib-coverage': 2.0.6 + + '@types/istanbul-reports@3.0.4': + dependencies: + '@types/istanbul-lib-report': 3.0.3 + + '@types/jest@29.5.14': + dependencies: + expect: 29.7.0 + pretty-format: 29.7.0 + + '@types/minimatch@5.1.2': {} + + '@types/node@22.20.1': + dependencies: + undici-types: 6.21.0 + + '@types/react-dom@19.2.3(@types/react@19.2.10)': + dependencies: + '@types/react': 19.2.10 + + '@types/react@19.2.10': + dependencies: + csstype: 3.2.3 + + '@types/stack-utils@2.0.3': {} + + '@types/yargs-parser@21.0.3': {} + + '@types/yargs@17.0.35': + dependencies: + '@types/yargs-parser': 21.0.3 + + '@uiw/codemirror-extensions-basic-setup@4.25.11(@codemirror/autocomplete@6.20.3)(@codemirror/commands@6.11.0)(@codemirror/language@6.12.4)(@codemirror/lint@6.9.7)(@codemirror/search@6.7.1)(@codemirror/state@6.7.1)(@codemirror/view@6.43.9)': + dependencies: + '@codemirror/autocomplete': 6.20.3 + '@codemirror/commands': 6.11.0 + '@codemirror/language': 6.12.4 + '@codemirror/lint': 6.9.7 + '@codemirror/search': 6.7.1 + '@codemirror/state': 6.7.1 + '@codemirror/view': 6.43.9 + + '@uiw/react-codemirror@4.25.11(@babel/runtime@8.0.0)(@codemirror/autocomplete@6.20.3)(@codemirror/language@6.12.4)(@codemirror/lint@6.9.7)(@codemirror/search@6.7.1)(@codemirror/state@6.7.1)(@codemirror/theme-one-dark@6.1.3)(@codemirror/view@6.43.9)(codemirror@6.0.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@babel/runtime': 8.0.0 + '@codemirror/commands': 6.11.0 + '@codemirror/state': 6.7.1 + '@codemirror/theme-one-dark': 6.1.3 + '@codemirror/view': 6.43.9 + '@uiw/codemirror-extensions-basic-setup': 4.25.11(@codemirror/autocomplete@6.20.3)(@codemirror/commands@6.11.0)(@codemirror/language@6.12.4)(@codemirror/lint@6.9.7)(@codemirror/search@6.7.1)(@codemirror/state@6.7.1)(@codemirror/view@6.43.9) + codemirror: 6.0.2 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + transitivePeerDependencies: + - '@codemirror/autocomplete' + - '@codemirror/language' + - '@codemirror/lint' + - '@codemirror/search' + + ansi-escapes@4.3.2: + dependencies: + type-fest: 0.21.3 + + ansi-regex@5.0.1: {} + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + ansi-styles@5.2.0: {} + + any-promise@1.3.0: {} + + anymatch@3.1.3: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.2 + + arg@5.0.2: {} + + argparse@1.0.10: + dependencies: + sprintf-js: 1.0.3 + + autoprefixer@10.5.4(postcss@8.5.26): + dependencies: + browserslist: 4.28.8 + caniuse-lite: 1.0.30001809 + fraction.js: 5.3.4 + picocolors: 1.1.1 + postcss: 8.5.26 + postcss-value-parser: 4.2.0 + + babel-jest@29.7.0(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1): + dependencies: + '@babel/core': 7.29.7(supports-color@8.1.1) + '@jest/transform': 29.7.0(supports-color@8.1.1) + '@types/babel__core': 7.20.5 + babel-plugin-istanbul: 6.1.1(supports-color@8.1.1) + babel-preset-jest: 29.6.3(@babel/core@7.29.7(supports-color@8.1.1)) + chalk: 4.1.2 + graceful-fs: 4.2.11 + slash: 3.0.0 + transitivePeerDependencies: + - supports-color + + babel-plugin-istanbul@6.1.1(supports-color@8.1.1): + dependencies: + '@babel/helper-plugin-utils': 7.29.7 + '@istanbuljs/load-nyc-config': 1.1.0 + '@istanbuljs/schema': 0.1.6 + istanbul-lib-instrument: 5.2.1(supports-color@8.1.1) + test-exclude: 6.0.0 + transitivePeerDependencies: + - supports-color + + babel-plugin-jest-hoist@29.6.3: + dependencies: + '@babel/template': 7.29.7 + '@babel/types': 7.29.8 + '@types/babel__core': 7.20.5 + '@types/babel__traverse': 7.28.0 + + babel-preset-current-node-syntax@1.2.0(@babel/core@7.29.7(supports-color@8.1.1)): + dependencies: + '@babel/core': 7.29.7(supports-color@8.1.1) + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-syntax-import-attributes': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.29.7(supports-color@8.1.1)) + + babel-preset-jest@29.6.3(@babel/core@7.29.7(supports-color@8.1.1)): + dependencies: + '@babel/core': 7.29.7(supports-color@8.1.1) + babel-plugin-jest-hoist: 29.6.3 + babel-preset-current-node-syntax: 1.2.0(@babel/core@7.29.7(supports-color@8.1.1)) + + balanced-match@1.0.2: {} + + balanced-match@4.0.4: {} + + baseline-browser-mapping@2.11.18: {} + + binary-extensions@2.3.0: {} + + brace-expansion@1.1.18: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@5.0.9: + dependencies: + balanced-match: 4.0.4 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + browserslist@4.28.8: + dependencies: + baseline-browser-mapping: 2.11.18 + caniuse-lite: 1.0.30001809 + electron-to-chromium: 1.5.412 + node-releases: 2.0.53 + update-browserslist-db: 1.3.1(browserslist@4.28.8) + + bs-logger@0.2.6: + dependencies: + fast-json-stable-stringify: 2.1.0 + + bser@2.1.1: + dependencies: + node-int64: 0.4.0 + + buffer-from@1.1.2: {} + + callsites@3.1.0: {} + + camelcase-css@2.0.1: {} + + camelcase@5.3.1: {} + + camelcase@6.3.0: {} + + caniuse-lite@1.0.30001809: {} + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + char-regex@1.0.2: {} + + chokidar@3.6.0: + dependencies: + anymatch: 3.1.3 + braces: 3.0.3 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + + ci-info@3.9.0: {} + + cjs-module-lexer@1.4.3: {} + + client-only@0.0.1: {} + + cliui@8.0.1: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + + co@4.6.0: {} + + codemirror@6.0.2: + dependencies: + '@codemirror/autocomplete': 6.20.3 + '@codemirror/commands': 6.11.0 + '@codemirror/language': 6.12.4 + '@codemirror/lint': 6.9.7 + '@codemirror/search': 6.7.1 + '@codemirror/state': 6.7.1 + '@codemirror/view': 6.43.9 + + collect-v8-coverage@1.0.3: {} + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + commander@4.1.1: {} + + concat-map@0.0.1: {} + + convert-source-map@2.0.0: {} + + create-jest@29.7.0(@types/node@22.20.1)(supports-color@8.1.1): + dependencies: + '@jest/types': 29.6.3 + chalk: 4.1.2 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-config: 29.7.0(@types/node@22.20.1)(supports-color@8.1.1) + jest-util: 29.7.0 + prompts: 2.4.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + + crelt@1.0.7: {} + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + cssesc@3.0.0: {} + + csstype@3.2.3: {} + + debug@4.4.3(supports-color@8.1.1): + dependencies: + ms: 2.1.3 + optionalDependencies: + supports-color: 8.1.1 + + dedent@1.7.2: {} + + deepmerge@4.3.1: {} + + detect-libc@2.1.2: + optional: true + + detect-newline@3.1.0: {} + + didyoumean@1.2.2: {} + + diff-sequences@29.6.3: {} + + dlv@1.1.3: {} + + electron-to-chromium@1.5.412: {} + + emittery@0.13.1: {} + + emoji-regex@8.0.0: {} + + error-ex@1.3.4: + dependencies: + is-arrayish: 0.2.1 + + es-errors@1.3.0: {} + + esbuild@0.28.2: + optionalDependencies: + '@esbuild/aix-ppc64': 0.28.2 + '@esbuild/android-arm': 0.28.2 + '@esbuild/android-arm64': 0.28.2 + '@esbuild/android-x64': 0.28.2 + '@esbuild/darwin-arm64': 0.28.2 + '@esbuild/darwin-x64': 0.28.2 + '@esbuild/freebsd-arm64': 0.28.2 + '@esbuild/freebsd-x64': 0.28.2 + '@esbuild/linux-arm': 0.28.2 + '@esbuild/linux-arm64': 0.28.2 + '@esbuild/linux-ia32': 0.28.2 + '@esbuild/linux-loong64': 0.28.2 + '@esbuild/linux-mips64el': 0.28.2 + '@esbuild/linux-ppc64': 0.28.2 + '@esbuild/linux-riscv64': 0.28.2 + '@esbuild/linux-s390x': 0.28.2 + '@esbuild/linux-x64': 0.28.2 + '@esbuild/netbsd-arm64': 0.28.2 + '@esbuild/netbsd-x64': 0.28.2 + '@esbuild/openbsd-arm64': 0.28.2 + '@esbuild/openbsd-x64': 0.28.2 + '@esbuild/openharmony-arm64': 0.28.2 + '@esbuild/sunos-x64': 0.28.2 + '@esbuild/win32-arm64': 0.28.2 + '@esbuild/win32-ia32': 0.28.2 + '@esbuild/win32-x64': 0.28.2 + + escalade@3.2.0: {} + + escape-string-regexp@2.0.0: {} + + esprima@4.0.1: {} + + execa@5.1.1: + dependencies: + cross-spawn: 7.0.6 + get-stream: 6.0.1 + human-signals: 2.1.0 + is-stream: 2.0.1 + merge-stream: 2.0.0 + npm-run-path: 4.0.1 + onetime: 5.1.2 + signal-exit: 3.0.7 + strip-final-newline: 2.0.0 + + exit@0.1.2: {} + + expect@29.7.0: + dependencies: + '@jest/expect-utils': 29.7.0 + jest-get-type: 29.6.3 + jest-matcher-utils: 29.7.0 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + + fast-glob@3.3.3: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + + fast-json-stable-stringify@2.1.0: {} + + fastq@1.20.1: + dependencies: + reusify: 1.1.0 + + fb-watchman@2.0.2: + dependencies: + bser: 2.1.1 + + fdir@6.5.0(picomatch@4.0.5): + optionalDependencies: + picomatch: 4.0.5 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + find-up@4.1.0: + dependencies: + locate-path: 5.0.0 + path-exists: 4.0.0 + + foreground-child@3.3.1: + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 + + fraction.js@5.3.4: {} + + fs.realpath@1.0.0: {} + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + gensync@1.0.0-beta.2: {} + + get-caller-file@2.0.5: {} + + get-package-type@0.1.0: {} + + get-stream@6.0.1: {} + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + glob@11.1.0: + dependencies: + foreground-child: 3.3.1 + jackspeak: 4.2.3 + minimatch: 10.2.6 + minipass: 7.1.3 + package-json-from-dist: 1.0.1 + path-scurry: 2.0.2 + + glob@7.2.3: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.5 + once: 1.4.0 + path-is-absolute: 1.0.1 + + graceful-fs@4.2.11: {} + + handlebars@4.7.9: + dependencies: + minimist: 1.2.8 + neo-async: 2.6.2 + source-map: 0.6.1 + wordwrap: 1.0.0 + optionalDependencies: + uglify-js: 3.19.3 + + has-flag@4.0.0: {} + + hasown@2.0.4: + dependencies: + function-bind: 1.1.2 + + html-escaper@2.0.2: {} + + human-signals@2.1.0: {} + + import-local@3.2.0: + dependencies: + pkg-dir: 4.2.0 + resolve-cwd: 3.0.0 + + imurmurhash@0.1.4: {} + + inflight@1.0.6: + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + + inherits@2.0.4: {} + + is-arrayish@0.2.1: {} + + is-binary-path@2.1.0: + dependencies: + binary-extensions: 2.3.0 + + is-core-module@2.16.2: + dependencies: + hasown: 2.0.4 + + is-extglob@2.1.1: {} + + is-fullwidth-code-point@3.0.0: {} + + is-generator-fn@2.1.0: {} + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-number@7.0.0: {} + + is-stream@2.0.1: {} + + isexe@2.0.0: {} + + istanbul-lib-coverage@3.2.2: {} + + istanbul-lib-instrument@5.2.1(supports-color@8.1.1): + dependencies: + '@babel/core': 7.29.7(supports-color@8.1.1) + '@babel/parser': 7.29.8 + '@istanbuljs/schema': 0.1.6 + istanbul-lib-coverage: 3.2.2 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + istanbul-lib-instrument@6.0.3(supports-color@8.1.1): + dependencies: + '@babel/core': 7.29.7(supports-color@8.1.1) + '@babel/parser': 7.29.8 + '@istanbuljs/schema': 0.1.6 + istanbul-lib-coverage: 3.2.2 + semver: 7.8.5 + transitivePeerDependencies: + - supports-color + + istanbul-lib-report@3.0.1: + dependencies: + istanbul-lib-coverage: 3.2.2 + make-dir: 4.0.0 + supports-color: 7.2.0 + + istanbul-lib-source-maps@4.0.1(supports-color@8.1.1): + dependencies: + debug: 4.4.3(supports-color@8.1.1) + istanbul-lib-coverage: 3.2.2 + source-map: 0.6.1 + transitivePeerDependencies: + - supports-color + + istanbul-reports@3.2.0: + dependencies: + html-escaper: 2.0.2 + istanbul-lib-report: 3.0.1 + + jackspeak@4.2.3: + dependencies: + '@isaacs/cliui': 9.0.0 + + jest-changed-files@29.7.0: + dependencies: + execa: 5.1.1 + jest-util: 29.7.0 + p-limit: 3.1.0 + + jest-circus@29.7.0(supports-color@8.1.1): + dependencies: + '@jest/environment': 29.7.0 + '@jest/expect': 29.7.0(supports-color@8.1.1) + '@jest/test-result': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 22.20.1 + chalk: 4.1.2 + co: 4.6.0 + dedent: 1.7.2 + is-generator-fn: 2.1.0 + jest-each: 29.7.0 + jest-matcher-utils: 29.7.0 + jest-message-util: 29.7.0 + jest-runtime: 29.7.0(supports-color@8.1.1) + jest-snapshot: 29.7.0(supports-color@8.1.1) + jest-util: 29.7.0 + p-limit: 3.1.0 + pretty-format: 29.7.0 + pure-rand: 6.1.0 + slash: 3.0.0 + stack-utils: 2.0.6 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + + jest-cli@29.7.0(@types/node@22.20.1)(supports-color@8.1.1): + dependencies: + '@jest/core': 29.7.0(supports-color@8.1.1) + '@jest/test-result': 29.7.0 + '@jest/types': 29.6.3 + chalk: 4.1.2 + create-jest: 29.7.0(@types/node@22.20.1)(supports-color@8.1.1) + exit: 0.1.2 + import-local: 3.2.0 + jest-config: 29.7.0(@types/node@22.20.1)(supports-color@8.1.1) + jest-util: 29.7.0 + jest-validate: 29.7.0 + yargs: 17.7.3 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + + jest-config@29.7.0(@types/node@22.20.1)(supports-color@8.1.1): + dependencies: + '@babel/core': 7.29.7(supports-color@8.1.1) + '@jest/test-sequencer': 29.7.0 + '@jest/types': 29.6.3 + babel-jest: 29.7.0(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) + chalk: 4.1.2 + ci-info: 3.9.0 + deepmerge: 4.3.1 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-circus: 29.7.0(supports-color@8.1.1) + jest-environment-node: 29.7.0 + jest-get-type: 29.6.3 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-runner: 29.7.0(supports-color@8.1.1) + jest-util: 29.7.0 + jest-validate: 29.7.0 + micromatch: 4.0.8 + parse-json: 5.2.0 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-json-comments: 3.1.1 + optionalDependencies: + '@types/node': 22.20.1 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + + jest-diff@29.7.0: + dependencies: + chalk: 4.1.2 + diff-sequences: 29.6.3 + jest-get-type: 29.6.3 + pretty-format: 29.7.0 + + jest-docblock@29.7.0: + dependencies: + detect-newline: 3.1.0 + + jest-each@29.7.0: + dependencies: + '@jest/types': 29.6.3 + chalk: 4.1.2 + jest-get-type: 29.6.3 + jest-util: 29.7.0 + pretty-format: 29.7.0 + + jest-environment-node@29.7.0: + dependencies: + '@jest/environment': 29.7.0 + '@jest/fake-timers': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 22.20.1 + jest-mock: 29.7.0 + jest-util: 29.7.0 + + jest-get-type@29.6.3: {} + + jest-haste-map@29.7.0: + dependencies: + '@jest/types': 29.6.3 + '@types/graceful-fs': 4.1.9 + '@types/node': 22.20.1 + anymatch: 3.1.3 + fb-watchman: 2.0.2 + graceful-fs: 4.2.11 + jest-regex-util: 29.6.3 + jest-util: 29.7.0 + jest-worker: 29.7.0 + micromatch: 4.0.8 + walker: 1.0.8 + optionalDependencies: + fsevents: 2.3.3 + + jest-leak-detector@29.7.0: + dependencies: + jest-get-type: 29.6.3 + pretty-format: 29.7.0 + + jest-matcher-utils@29.7.0: + dependencies: + chalk: 4.1.2 + jest-diff: 29.7.0 + jest-get-type: 29.6.3 + pretty-format: 29.7.0 + + jest-message-util@29.7.0: + dependencies: + '@babel/code-frame': 7.29.7 + '@jest/types': 29.6.3 + '@types/stack-utils': 2.0.3 + chalk: 4.1.2 + graceful-fs: 4.2.11 + micromatch: 4.0.8 + pretty-format: 29.7.0 + slash: 3.0.0 + stack-utils: 2.0.6 + + jest-mock@29.7.0: + dependencies: + '@jest/types': 29.6.3 + '@types/node': 22.20.1 + jest-util: 29.7.0 + + jest-pnp-resolver@1.2.3(jest-resolve@29.7.0): + optionalDependencies: + jest-resolve: 29.7.0 + + jest-regex-util@29.6.3: {} + + jest-resolve-dependencies@29.7.0(supports-color@8.1.1): + dependencies: + jest-regex-util: 29.6.3 + jest-snapshot: 29.7.0(supports-color@8.1.1) + transitivePeerDependencies: + - supports-color + + jest-resolve@29.7.0: + dependencies: + chalk: 4.1.2 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + jest-pnp-resolver: 1.2.3(jest-resolve@29.7.0) + jest-util: 29.7.0 + jest-validate: 29.7.0 + resolve: 1.22.12 + resolve.exports: 2.0.3 + slash: 3.0.0 + + jest-runner@29.7.0(supports-color@8.1.1): + dependencies: + '@jest/console': 29.7.0 + '@jest/environment': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0(supports-color@8.1.1) + '@jest/types': 29.6.3 + '@types/node': 22.20.1 + chalk: 4.1.2 + emittery: 0.13.1 + graceful-fs: 4.2.11 + jest-docblock: 29.7.0 + jest-environment-node: 29.7.0 + jest-haste-map: 29.7.0 + jest-leak-detector: 29.7.0 + jest-message-util: 29.7.0 + jest-resolve: 29.7.0 + jest-runtime: 29.7.0(supports-color@8.1.1) + jest-util: 29.7.0 + jest-watcher: 29.7.0 + jest-worker: 29.7.0 + p-limit: 3.1.0 + source-map-support: 0.5.13 + transitivePeerDependencies: + - supports-color + + jest-runtime@29.7.0(supports-color@8.1.1): + dependencies: + '@jest/environment': 29.7.0 + '@jest/fake-timers': 29.7.0 + '@jest/globals': 29.7.0(supports-color@8.1.1) + '@jest/source-map': 29.6.3 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0(supports-color@8.1.1) + '@jest/types': 29.6.3 + '@types/node': 22.20.1 + chalk: 4.1.2 + cjs-module-lexer: 1.4.3 + collect-v8-coverage: 1.0.3 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + jest-message-util: 29.7.0 + jest-mock: 29.7.0 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-snapshot: 29.7.0(supports-color@8.1.1) + jest-util: 29.7.0 + slash: 3.0.0 + strip-bom: 4.0.0 + transitivePeerDependencies: + - supports-color + + jest-snapshot@29.7.0(supports-color@8.1.1): + dependencies: + '@babel/core': 7.29.7(supports-color@8.1.1) + '@babel/generator': 7.29.8 + '@babel/plugin-syntax-jsx': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-syntax-typescript': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/types': 7.29.8 + '@jest/expect-utils': 29.7.0 + '@jest/transform': 29.7.0(supports-color@8.1.1) + '@jest/types': 29.6.3 + babel-preset-current-node-syntax: 1.2.0(@babel/core@7.29.7(supports-color@8.1.1)) + chalk: 4.1.2 + expect: 29.7.0 + graceful-fs: 4.2.11 + jest-diff: 29.7.0 + jest-get-type: 29.6.3 + jest-matcher-utils: 29.7.0 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + natural-compare: 1.4.0 + pretty-format: 29.7.0 + semver: 7.8.5 + transitivePeerDependencies: + - supports-color + + jest-util@29.7.0: + dependencies: + '@jest/types': 29.6.3 + '@types/node': 22.20.1 + chalk: 4.1.2 + ci-info: 3.9.0 + graceful-fs: 4.2.11 + picomatch: 2.3.2 + + jest-validate@29.7.0: + dependencies: + '@jest/types': 29.6.3 + camelcase: 6.3.0 + chalk: 4.1.2 + jest-get-type: 29.6.3 + leven: 3.1.0 + pretty-format: 29.7.0 + + jest-watcher@29.7.0: + dependencies: + '@jest/test-result': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 22.20.1 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + emittery: 0.13.1 + jest-util: 29.7.0 + string-length: 4.0.2 + + jest-worker@29.7.0: + dependencies: + '@types/node': 22.20.1 + jest-util: 29.7.0 + merge-stream: 2.0.0 + supports-color: 8.1.1 + + jest@29.7.0(@types/node@22.20.1)(supports-color@8.1.1): + dependencies: + '@jest/core': 29.7.0(supports-color@8.1.1) + '@jest/types': 29.6.3 + import-local: 3.2.0 + jest-cli: 29.7.0(@types/node@22.20.1)(supports-color@8.1.1) + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + + jiti@1.21.7: {} + + js-tokens@4.0.0: {} + + js-yaml@3.15.1: + dependencies: + argparse: 1.0.10 + esprima: 4.0.1 + + jsesc@3.1.0: {} + + json-parse-even-better-errors@2.3.1: {} + + json5@2.2.3: {} + + jsonldjs@0.1.2: {} + + kleur@3.0.3: {} + + latex2js@4.5.0: + dependencies: + '@latex2js/pstricks': 4.2.0 + '@latex2js/settings': 4.2.0 + '@latex2js/utils': 4.2.0 + + latex2react@4.4.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + dependencies: + '@latex2js/macros': 3.2.0 + '@latex2js/pstricks': 4.2.0 + '@latex2js/utils': 4.2.0 + latex2js: 4.5.0 + mathjaxjs: 4.2.0 + mathjaxjs-react: 4.2.0(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + leven@3.1.0: {} + + lilconfig@3.1.3: {} + + lines-and-columns@1.2.4: {} + + locate-path@5.0.0: + dependencies: + p-locate: 4.1.0 + + lodash.memoize@4.1.2: {} + + lru-cache@11.5.2: {} + + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + + make-dir@4.0.0: + dependencies: + semver: 7.8.5 + + make-error@1.3.6: {} + + makeerror@1.0.12: + dependencies: + tmpl: 1.0.5 + + mathjaxjs-react@4.2.0(react@19.2.4): + dependencies: + mathjaxjs: 4.2.0 + react: 19.2.4 + + mathjaxjs@4.2.0: {} + + merge-stream@2.0.0: {} + + merge2@1.4.1: {} + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.2 + + mimic-fn@2.1.0: {} + + minimatch@10.2.6: + dependencies: + brace-expansion: 5.0.9 + + minimatch@3.1.5: + dependencies: + brace-expansion: 1.1.18 + + minimist@1.2.8: {} + + minipass@7.1.3: {} + + mkdirp@3.0.1: {} + + ms@2.1.3: {} + + mz@2.7.0: + dependencies: + any-promise: 1.3.0 + object-assign: 4.1.1 + thenify-all: 1.6.0 + + nanoid@3.3.18: {} + + natural-compare@1.4.0: {} + + neo-async@2.6.2: {} + + next-seo@6.8.0(next@16.1.6(@babel/core@7.29.7(supports-color@8.1.1))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + dependencies: + next: 16.1.6(@babel/core@7.29.7(supports-color@8.1.1))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + next@16.1.6(@babel/core@7.29.7(supports-color@8.1.1))(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + dependencies: + '@next/env': 16.1.6 + '@swc/helpers': 0.5.15 + baseline-browser-mapping: 2.11.18 + caniuse-lite: 1.0.30001809 + postcss: 8.4.31 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + styled-jsx: 5.1.6(@babel/core@7.29.7(supports-color@8.1.1))(react@19.2.4) + optionalDependencies: + '@next/swc-darwin-arm64': 16.1.6 + '@next/swc-darwin-x64': 16.1.6 + '@next/swc-linux-arm64-gnu': 16.1.6 + '@next/swc-linux-arm64-musl': 16.1.6 + '@next/swc-linux-x64-gnu': 16.1.6 + '@next/swc-linux-x64-musl': 16.1.6 + '@next/swc-win32-arm64-msvc': 16.1.6 + '@next/swc-win32-x64-msvc': 16.1.6 + sharp: 0.34.5 + transitivePeerDependencies: + - '@babel/core' + - babel-plugin-macros + + node-int64@0.4.0: {} + + node-releases@2.0.53: {} + + normalize-path@3.0.0: {} + + npm-run-path@4.0.1: + dependencies: + path-key: 3.1.1 + + object-assign@4.1.1: {} + + object-hash@3.0.0: {} + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + onetime@5.1.2: + dependencies: + mimic-fn: 2.1.0 + + p-limit@2.3.0: + dependencies: + p-try: 2.2.0 + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-locate@4.1.0: + dependencies: + p-limit: 2.3.0 + + p-try@2.2.0: {} + + package-json-from-dist@1.0.1: {} + + parse-json@5.2.0: + dependencies: + '@babel/code-frame': 7.29.7 + error-ex: 1.3.4 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + + path-exists@4.0.0: {} + + path-is-absolute@1.0.1: {} + + path-key@3.1.1: {} + + path-parse@1.0.7: {} + + path-scurry@2.0.2: + dependencies: + lru-cache: 11.5.2 + minipass: 7.1.3 + + picocolors@1.1.1: {} + + picomatch@2.3.2: {} + + picomatch@4.0.5: {} + + pirates@4.0.7: {} + + pkg-dir@4.2.0: + dependencies: + find-up: 4.1.0 + + postcss-import@15.1.0(postcss@8.5.26): + dependencies: + postcss: 8.5.26 + postcss-value-parser: 4.2.0 + read-cache: 1.0.2 + resolve: 1.22.12 + + postcss-js@4.1.0(postcss@8.5.26): + dependencies: + camelcase-css: 2.0.1 + postcss: 8.5.26 + + postcss-load-config@6.0.1(jiti@1.21.7)(postcss@8.5.26)(tsx@4.23.12): + dependencies: + lilconfig: 3.1.3 + optionalDependencies: + jiti: 1.21.7 + postcss: 8.5.26 + tsx: 4.23.12 + + postcss-nested@6.2.0(postcss@8.5.26): + dependencies: + postcss: 8.5.26 + postcss-selector-parser: 6.1.4 + + postcss-selector-parser@6.1.4: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + + postcss-value-parser@4.2.0: {} + + postcss@8.4.31: + dependencies: + nanoid: 3.3.18 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + postcss@8.5.26: + dependencies: + nanoid: 3.3.18 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + pretty-format@29.7.0: + dependencies: + '@jest/schemas': 29.6.3 + ansi-styles: 5.2.0 + react-is: 18.3.1 + + prompts@2.4.2: + dependencies: + kleur: 3.0.3 + sisteransi: 1.0.5 + + pure-rand@6.1.0: {} + + queue-microtask@1.2.3: {} + + react-dom@19.2.4(react@19.2.4): + dependencies: + react: 19.2.4 + scheduler: 0.27.0 + + react-is@18.3.1: {} + + react@19.2.4: {} + + read-cache@1.0.2: {} + + readdirp@3.6.0: + dependencies: + picomatch: 2.3.2 + + require-directory@2.1.1: {} + + resolve-cwd@3.0.0: + dependencies: + resolve-from: 5.0.0 + + resolve-from@5.0.0: {} + + resolve.exports@2.0.3: {} + + resolve@1.22.12: + dependencies: + es-errors: 1.3.0 + is-core-module: 2.16.2 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + reusify@1.1.0: {} + + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + + scheduler@0.27.0: {} + + schema-dts@1.1.5: {} + + semver@6.3.1: {} + + semver@7.8.5: {} + + sharp@0.34.5: + dependencies: + '@img/colour': 1.1.0 + detect-libc: 2.1.2 + semver: 7.8.5 + optionalDependencies: + '@img/sharp-darwin-arm64': 0.34.5 + '@img/sharp-darwin-x64': 0.34.5 + '@img/sharp-libvips-darwin-arm64': 1.2.4 + '@img/sharp-libvips-darwin-x64': 1.2.4 + '@img/sharp-libvips-linux-arm': 1.2.4 + '@img/sharp-libvips-linux-arm64': 1.2.4 + '@img/sharp-libvips-linux-ppc64': 1.2.4 + '@img/sharp-libvips-linux-riscv64': 1.2.4 + '@img/sharp-libvips-linux-s390x': 1.2.4 + '@img/sharp-libvips-linux-x64': 1.2.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + '@img/sharp-linux-arm': 0.34.5 + '@img/sharp-linux-arm64': 0.34.5 + '@img/sharp-linux-ppc64': 0.34.5 + '@img/sharp-linux-riscv64': 0.34.5 + '@img/sharp-linux-s390x': 0.34.5 + '@img/sharp-linux-x64': 0.34.5 + '@img/sharp-linuxmusl-arm64': 0.34.5 + '@img/sharp-linuxmusl-x64': 0.34.5 + '@img/sharp-wasm32': 0.34.5 + '@img/sharp-win32-arm64': 0.34.5 + '@img/sharp-win32-ia32': 0.34.5 + '@img/sharp-win32-x64': 0.34.5 + optional: true + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + signal-exit@3.0.7: {} + + signal-exit@4.1.0: {} + + sisteransi@1.0.5: {} + + slash@3.0.0: {} + + source-map-js@1.2.1: {} + + source-map-support@0.5.13: + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + + source-map@0.6.1: {} + + sprintf-js@1.0.3: {} + + stack-utils@2.0.6: + dependencies: + escape-string-regexp: 2.0.0 + + string-length@4.0.2: + dependencies: + char-regex: 1.0.2 + strip-ansi: 6.0.1 + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-bom@4.0.0: {} + + strip-final-newline@2.0.0: {} + + strip-json-comments@3.1.1: {} + + style-mod@4.1.3: {} + + styled-jsx@5.1.6(@babel/core@7.29.7(supports-color@8.1.1))(react@19.2.4): + dependencies: + client-only: 0.0.1 + react: 19.2.4 + optionalDependencies: + '@babel/core': 7.29.7(supports-color@8.1.1) + + sucrase@3.35.1: + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + commander: 4.1.1 + lines-and-columns: 1.2.4 + mz: 2.7.0 + pirates: 4.0.7 + tinyglobby: 0.2.17 + ts-interface-checker: 0.1.13 + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + supports-color@8.1.1: + dependencies: + has-flag: 4.0.0 + + supports-preserve-symlinks-flag@1.0.0: {} + + tailwindcss@3.4.19(tsx@4.23.12): + dependencies: + '@alloc/quick-lru': 5.2.0 + arg: 5.0.2 + chokidar: 3.6.0 + didyoumean: 1.2.2 + dlv: 1.1.3 + fast-glob: 3.3.3 + glob-parent: 6.0.2 + is-glob: 4.0.3 + jiti: 1.21.7 + lilconfig: 3.1.3 + micromatch: 4.0.8 + normalize-path: 3.0.0 + object-hash: 3.0.0 + picocolors: 1.1.1 + postcss: 8.5.26 + postcss-import: 15.1.0(postcss@8.5.26) + postcss-js: 4.1.0(postcss@8.5.26) + postcss-load-config: 6.0.1(jiti@1.21.7)(postcss@8.5.26)(tsx@4.23.12) + postcss-nested: 6.2.0(postcss@8.5.26) + postcss-selector-parser: 6.1.4 + resolve: 1.22.12 + sucrase: 3.35.1 + transitivePeerDependencies: + - tsx + - yaml + + test-exclude@6.0.0: + dependencies: + '@istanbuljs/schema': 0.1.6 + glob: 7.2.3 + minimatch: 3.1.5 + + thenify-all@1.6.0: + dependencies: + thenify: 3.3.1 + + thenify@3.3.1: + dependencies: + any-promise: 1.3.0 + + tinyglobby@0.2.17: + dependencies: + fdir: 6.5.0(picomatch@4.0.5) + picomatch: 4.0.5 + + tmpl@1.0.5: {} + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + ts-interface-checker@0.1.13: {} + + ts-jest@29.4.12(@babel/core@7.29.7(supports-color@8.1.1))(@jest/transform@29.7.0(supports-color@8.1.1))(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1))(esbuild@0.28.2)(jest-util@29.7.0)(jest@29.7.0(@types/node@22.20.1)(supports-color@8.1.1))(typescript@5.9.3): + dependencies: + bs-logger: 0.2.6 + fast-json-stable-stringify: 2.1.0 + handlebars: 4.7.9 + jest: 29.7.0(@types/node@22.20.1)(supports-color@8.1.1) + json5: 2.2.3 + lodash.memoize: 4.1.2 + make-error: 1.3.6 + semver: 7.8.5 + type-fest: 4.41.0 + typescript: 5.9.3 + yargs-parser: 21.1.1 + optionalDependencies: + '@babel/core': 7.29.7(supports-color@8.1.1) + '@jest/transform': 29.7.0(supports-color@8.1.1) + '@jest/types': 29.6.3 + babel-jest: 29.7.0(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) + esbuild: 0.28.2 + jest-util: 29.7.0 + + tslib@2.8.1: {} + + tsx@4.23.12: + dependencies: + esbuild: 0.28.2 + optionalDependencies: + fsevents: 2.3.3 + + type-detect@4.0.8: {} + + type-fest@0.21.3: {} + + type-fest@4.41.0: {} + + typescript@5.9.3: {} + + uglify-js@3.19.3: + optional: true + + undici-types@6.21.0: {} + + update-browserslist-db@1.3.1(browserslist@4.28.8): + dependencies: + browserslist: 4.28.8 + escalade: 3.2.0 + picocolors: 1.1.1 + + util-deprecate@1.0.2: {} + + v8-to-istanbul@9.3.0: + dependencies: + '@jridgewell/trace-mapping': 0.3.31 + '@types/istanbul-lib-coverage': 2.0.6 + convert-source-map: 2.0.0 + + w3c-keyname@2.2.8: {} + + walker@1.0.8: + dependencies: + makeerror: 1.0.12 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + wordwrap@1.0.0: {} + + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrappy@1.0.2: {} + + write-file-atomic@4.0.2: + dependencies: + imurmurhash: 0.1.4 + signal-exit: 3.0.7 + + y18n@5.0.8: {} + + yallist@3.1.1: {} + + yargs-parser@21.1.1: {} + + yargs@17.7.3: + dependencies: + cliui: 8.0.1 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + + yocto-queue@0.1.0: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml new file mode 100644 index 0000000..c0c7e3a --- /dev/null +++ b/pnpm-workspace.yaml @@ -0,0 +1,17 @@ +packages: + - '.' +allowBuilds: + esbuild: true + sharp: true +minimumReleaseAgeExclude: + - '@latex2js/macros@3.2.0' + - '@latex2js/pstricks@4.2.0' + - '@latex2js/settings@4.2.0' + - '@latex2js/utils@4.2.0' + - latex2js@4.5.0 + - latex2react@4.4.2 + - mathjaxjs-react@4.2.0 + - mathjaxjs@4.2.0 +overrides: + '@types/react': 19.2.10 + '@types/react-dom': 19.2.3 diff --git a/postcss.config.js b/postcss.config.js new file mode 100644 index 0000000..e873f1a --- /dev/null +++ b/postcss.config.js @@ -0,0 +1,6 @@ +module.exports = { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +}; diff --git a/public/favicon.png b/public/favicon.png new file mode 100644 index 0000000..0fb5067 Binary files /dev/null and b/public/favicon.png differ diff --git a/assets/images/html5.png b/public/images/html5.png similarity index 100% rename from assets/images/html5.png rename to public/images/html5.png diff --git a/assets/images/photo.png b/public/images/photo.png similarity index 100% rename from assets/images/photo.png rename to public/images/photo.png diff --git a/assets/images/react.png b/public/images/react.png similarity index 100% rename from assets/images/react.png rename to public/images/react.png diff --git a/assets/images/share.jpg b/public/images/share.jpg similarity index 100% rename from assets/images/share.jpg rename to public/images/share.jpg diff --git a/assets/images/vue.png b/public/images/vue.png similarity index 100% rename from assets/images/vue.png rename to public/images/vue.png diff --git a/scripts/generate-llm-markdown.ts b/scripts/generate-llm-markdown.ts new file mode 100644 index 0000000..27ab8c2 --- /dev/null +++ b/scripts/generate-llm-markdown.ts @@ -0,0 +1,103 @@ +// ============================================================================= +// llms.txt + markdown twins +// ============================================================================= +// Generates agent-facing content into out/ after `next build`: +// - out/llms.txt index of the site for LLMs +// - out/examples/.md markdown twin of each example page +// - out/installation/.md markdown twin of each installation guide +// Deployed with text/plain content-type via the deploy:md script. +// ============================================================================= + +import fs from 'fs'; +import path from 'path'; +import { mkdirp } from 'mkdirp'; + +import { examples } from '../src/data/examples'; +import { installGuides } from '../src/data/installs'; +import { canonical, pages, site } from '../src/seo'; + +const OUT_DIR = path.resolve(__dirname, '../out'); +const CONTENT_DIR = path.resolve(__dirname, '../content/examples'); + +// --------------------------------------------------------------------------- +// llms.txt +// --------------------------------------------------------------------------- + +const llmsTxt = `# ${site.name} + +> ${pages['/'].description} + +LaTeX2JS renders LaTeX and PSTricks in the browser: pspicture environments, draggable vectors (userline), draggable variables (uservariable), sliders, and live plots (psplot), with equations typeset by MathJax. Source: https://github.com/Mathapedia/LaTeX2JS + +## Sandbox + +- [LaTeX Sandbox](${canonical}/sandbox): Edit and render LaTeX and PSTricks in the browser, or start from one of the interactive examples. + +## Installation + +${installGuides + .map((guide) => `- [${guide.title}](${canonical}/installation/${guide.slug}.md): ${pages[`/installation/${guide.slug}`].description}`) + .join('\n')} + +## Examples + +${examples + .map((example) => `- [${example.title}](${canonical}/examples/${example.slug}.md): ${example.description}`) + .join('\n')} +`; + +// --------------------------------------------------------------------------- +// Markdown twins +// --------------------------------------------------------------------------- + +function exampleMarkdown(slug: string): string { + const example = examples.find((e) => e.slug === slug)!; + const source = fs.readFileSync(path.join(CONTENT_DIR, example.file), 'utf-8').trim(); + + return `# ${example.title} + +> ${example.description} + +Rendered live at ${canonical}/examples/${example.slug} +${example.interactive ? '\nThis diagram is interactive in the browser (mouse/touch).\n' : ''} +## LaTeX source + +\`\`\`latex +${source} +\`\`\` +`; +} + +function installMarkdown(slug: string): string { + const guide = installGuides.find((g) => g.slug === slug)!; + + return `# ${guide.title} + +> ${pages[`/installation/${guide.slug}`].description} + +${guide.steps + .map((step, index) => { + const code = step.code ? `\n\n\`\`\`${step.language ?? ''}\n${step.code}\n\`\`\`` : ''; + return `${index + 1}. ${step.text}${code}`; + }) + .join('\n\n')} +`; +} + +// --------------------------------------------------------------------------- +// Write +// --------------------------------------------------------------------------- + +fs.writeFileSync(path.join(OUT_DIR, 'llms.txt'), llmsTxt); + +mkdirp.sync(path.join(OUT_DIR, 'examples')); +examples.forEach((example) => { + fs.writeFileSync(path.join(OUT_DIR, 'examples', `${example.slug}.md`), exampleMarkdown(example.slug)); +}); + +mkdirp.sync(path.join(OUT_DIR, 'installation')); +installGuides.forEach((guide) => { + fs.writeFileSync(path.join(OUT_DIR, 'installation', `${guide.slug}.md`), installMarkdown(guide.slug)); +}); + +console.log(`llms.txt + ${examples.length + installGuides.length} markdown twins written to out/`); diff --git a/src/components/code-block.tsx b/src/components/code-block.tsx new file mode 100644 index 0000000..807f792 --- /dev/null +++ b/src/components/code-block.tsx @@ -0,0 +1,7 @@ +export function CodeBlock({ code }: { code: string }) { + return ( +
    +			{code}
    +		
    + ); +} diff --git a/src/components/common/head.tsx b/src/components/common/head.tsx new file mode 100644 index 0000000..e4e30d2 --- /dev/null +++ b/src/components/common/head.tsx @@ -0,0 +1,64 @@ +import NextHead from 'next/head'; +import { createJsonLdBuilder, type JsonLdConfig } from 'jsonldjs'; +import { NextSeo } from 'next-seo'; + +import { seoConfig } from '@/seo'; +import { siteConfig } from '@/config'; + +interface HeadProps { + title: string; + description: string; + route: `/${string}`; + images?: { + url: string; + alt: string; + width?: number; + height?: number; + }[]; + noindex?: boolean; + nofollow?: boolean; + canonicalUrl?: string; + jsonLdConfig?: JsonLdConfig; +} + +export function Head({ + title, + description, + route, + images, + nofollow = false, + noindex = false, + canonicalUrl = '', + jsonLdConfig, +}: HeadProps) { + const defaultCanonical = `${siteConfig.site.canonical}${route}`; + + const graph = { + ...seoConfig.openGraph, + images: images || seoConfig.openGraph.images, + url: defaultCanonical, + title, + description, + }; + + const jsonLdContent = jsonLdConfig ? createJsonLdBuilder().mergeConfig(jsonLdConfig).build() : null; + + return ( + <> + + {jsonLdContent && ( + + + `, + language: 'html', + }, + { + text: 'Write your LaTeX inside script tags with type set to "text/latex":', + code: ` + `, + language: 'html', + }, + { + text: 'Towards the end of your HTML page, call the init method:', + code: ` + +`, + language: 'html', + }, + ], + }, +]; + +export function getInstallGuide(slug: string): InstallGuide | undefined { + return installGuides.find((g) => g.slug === slug); +} diff --git a/src/data/jsonld/examples.ts b/src/data/jsonld/examples.ts new file mode 100644 index 0000000..9c6b6b8 --- /dev/null +++ b/src/data/jsonld/examples.ts @@ -0,0 +1,19 @@ +import { examples } from '@/data/examples'; +import { canonical } from '@/seo'; + +// One CreativeWork per interactive example page, generated from the examples +// registry so the graph stays in lockstep with the routes. +export default examples.map((example) => ({ + '@type': 'CreativeWork' as const, + '@id': `webpage:latex2js-example-${example.slug}`, + name: example.title, + description: example.description, + url: `${canonical}/examples/${example.slug}`, + genre: 'Interactive PSTricks example', + exampleOfWork: { + '@id': 'software:latex2js', + }, + creator: { + '@id': 'person:danlynch', + }, +})); diff --git a/src/data/jsonld/index.ts b/src/data/jsonld/index.ts new file mode 100644 index 0000000..8ade8f9 --- /dev/null +++ b/src/data/jsonld/index.ts @@ -0,0 +1,19 @@ +import { JsonLdGraph } from 'jsonldjs'; + +import examples from './examples'; +import sandbox from './sandbox'; +import people from './people'; +import publications from './publications'; +import software from './software'; +import videos from './videos'; +import website from './website'; + +export const jsonldGraph: JsonLdGraph = [ + ...software, + ...people, + ...website, + ...publications, + ...videos, + ...examples, + ...sandbox, +]; diff --git a/src/data/jsonld/organizations.ts b/src/data/jsonld/organizations.ts new file mode 100644 index 0000000..3a7aa76 --- /dev/null +++ b/src/data/jsonld/organizations.ts @@ -0,0 +1,3 @@ +// These sites are personal (Dan Lynch) rather than Constructive products; +// the person entity is the publisher, so no organisation is emitted here. +export default []; diff --git a/src/data/jsonld/people.ts b/src/data/jsonld/people.ts new file mode 100644 index 0000000..4d303ce --- /dev/null +++ b/src/data/jsonld/people.ts @@ -0,0 +1,26 @@ +export default [ + { + '@type': 'Person', + '@id': 'person:danlynch', + name: 'Dan Lynch', + url: 'https://danlynch.com', + sameAs: [ + 'https://github.com/pyramation', + 'https://www.linkedin.com/in/dan-p-lynch/', + 'https://x.com/danlynch', + 'https://scholar.google.com/citations?user=1U4vfEUAAAAJ&hl=en', + ], + }, + { + '@type': 'Person', + '@id': 'person:babak-ayazifar', + name: 'Babak Ayazifar', + url: 'https://www2.eecs.berkeley.edu/Faculty/Homepages/ayazifar.html', + sameAs: [ + 'https://www2.eecs.berkeley.edu/Faculty/Homepages/ayazifar.html', + 'https://www2.eecs.berkeley.edu/Pubs/Theses/Faculty/ayazifar.html', + ], + description: + 'Lecturer in EECS at UC Berkeley and advisor to Dan Lynch on the Art of Digital Publishing thesis.', + }, +]; diff --git a/src/data/jsonld/publications.ts b/src/data/jsonld/publications.ts new file mode 100644 index 0000000..9c0002e --- /dev/null +++ b/src/data/jsonld/publications.ts @@ -0,0 +1,24 @@ +export default [ + { + '@type': 'Thesis', + '@id': 'thesis:danlynch-digital-publishing', + name: 'The Art of Digital Publishing: A foundation of combined standards to support the future of publishing', + description: + `Dan Lynch's UC Berkeley EECS master's thesis proposing a synthesis of TeX and HTML5 standards to support the future of digital publishing.`, + author: { '@id': 'person:danlynch' }, + contributor: [{ '@id': 'person:babak-ayazifar' }], + datePublished: '2012-12-18', + identifier: 'UCB/EECS-2012-268', + publisher: 'EECS Department, University of California, Berkeley', + url: 'https://www2.eecs.berkeley.edu/Pubs/TechRpts/2012/EECS-2012-268.html', + sameAs: [ + 'https://www2.eecs.berkeley.edu/Pubs/TechRpts/2012/EECS-2012-268.html', + 'https://www2.eecs.berkeley.edu/Pubs/TechRpts/2012/Archive/EECS-2012-268.pdf', + 'https://scholar.google.com/citations?view_op=view_citation&hl=en&user=1U4vfEUAAAAJ&citation_for_view=1U4vfEUAAAAJ:u5HHmVD_uO8C', + 'https://www.academia.edu/download/31197157/EECS-2012-268.pdf', + ], + abstract: + `Scientific content increasingly relies on the presentation and authoring of complex multimedia diagrams and figures, sometimes interactive, to convey information in a non-textual way. Wikis and user-generated hyper-linked content have both been very successful in the case for text—this is what we aim to do for mathematical diagrams. Many professors in higher education who write textbooks know TeX, however, they don't often know how to program the Web. The future of building interactive user interfaces should lie not in the hands of programmers, but in the hands of the expert of a given field—the goal of this project is to supply math, physics, and engineering professors with a platform to express mathematical concepts to students to provide immersive learning environments. Ideally, this projects serves twofold: First, in closing the gap for non-web-technical authors to express ideas and concepts through Web technology without the knowledge of coding or user interface design, by mapping a typesetting language to interactive programming. Second, in providing deep, educational experiences for our youth to engage more in the sciences, and begin to use exploration and creativity in learning through interactive textbooks. The loose structure and nature of user interface design poses a problem for documenting science and related interfaces in a consistent manner. TeX provides us with some "laws" to obey in order to design the output of a text and graphical language around. Hence, we can attempt to create a synthesis of a structured user interface specification (TeX) and a structured functional specification (HTML5) to provide a publishing platform for the current and next generation. The Art is where we can blend these two standards bodies; higher levels of abstraction allow people to express their ideas without having to worry about the mechanisms by which the technology is rendering their works. It is in these environments when people can express themselves freely.`, + keywords: ['latex', 'html5', 'digital publishing', 'tex', 'interactive textbooks', 'education'], + }, +]; diff --git a/src/data/jsonld/sandbox.ts b/src/data/jsonld/sandbox.ts new file mode 100644 index 0000000..6c02945 --- /dev/null +++ b/src/data/jsonld/sandbox.ts @@ -0,0 +1,18 @@ +import { WebPage } from 'schema-dts'; + +export default [ + { + '@type': 'WebPage', + '@id': 'webpage:latex2js-sandbox', + name: 'LaTeX Sandbox', + description: + 'Edit and render LaTeX and PSTricks in the browser with LaTeX2JS, or start from one of the interactive examples.', + url: 'https://latex2js.com/sandbox', + isPartOf: { + '@id': 'website:latex2js.com', + }, + about: { + '@id': 'software:latex2js', + }, + } satisfies WebPage, +]; diff --git a/src/data/jsonld/software.ts b/src/data/jsonld/software.ts new file mode 100644 index 0000000..0b74c0c --- /dev/null +++ b/src/data/jsonld/software.ts @@ -0,0 +1,73 @@ +export default [ + { + '@type': 'SoftwareApplication', + '@id': 'software:latex2js', + name: 'LaTeX2JS', + alternateName: ['LaTeX2HTML5'], + url: 'https://latex2js.com', + startDate: '2013-10', + applicationCategory: ['math', 'latex'], + operatingSystem: 'Web', + description: + 'A JavaScript LaTeX rendering engine that brings LaTeX and PSTricks to the browser: pspicture environments, draggable vectors, sliders, and live plots, with equations typeset by MathJax. Originally launched as LaTeX2HTML5 and reached #3 trending on GitHub.', + creator: { + '@id': 'person:danlynch', + }, + isPartOf: { + '@id': 'software:mathapedia', + }, + isBasedOn: [{ '@id': 'thesis:danlynch-digital-publishing' }], + softwareRequirements: [{ '@id': 'software:mathjax' }], + video: [{ '@id': 'video:latex2html5-proposal' }], + sameAs: [ + 'https://github.com/Mathapedia/LaTeX2JS', + 'https://www.npmjs.com/package/latex2js', + ], + }, + { + '@type': 'SoftwareSourceCode', + '@id': 'software:latex2js-react', + name: 'latex2react', + description: 'React bindings for LaTeX2JS: render interactive LaTeX and PSTricks diagrams with the component.', + url: 'https://latex2js.com/installation/react', + codeRepository: 'https://github.com/Mathapedia/LaTeX2JS', + programmingLanguage: 'TypeScript', + runtimePlatform: 'React', + isPartOf: { + '@id': 'software:latex2js', + }, + sameAs: ['https://www.npmjs.com/package/latex2react'], + }, + { + '@type': 'SoftwareSourceCode', + '@id': 'software:latex2js-vue', + name: 'latex2vue', + description: 'Vue bindings for LaTeX2JS: render interactive LaTeX and PSTricks diagrams with the component.', + url: 'https://latex2js.com/installation/vue', + codeRepository: 'https://github.com/Mathapedia/LaTeX2JS', + programmingLanguage: 'TypeScript', + runtimePlatform: 'Vue', + isPartOf: { + '@id': 'software:latex2js', + }, + sameAs: ['https://www.npmjs.com/package/latex2vue'], + }, + { + '@type': 'WebApplication', + '@id': 'software:mathapedia', + name: 'Mathapedia', + url: 'https://mathapedia.com', + description: + 'An educational platform enabling non-technical authors to express scientific ideas via TeX & HTML5.', + creator: { + '@id': 'person:danlynch', + }, + }, + { + '@type': 'SoftwareApplication', + '@id': 'software:mathjax', + name: 'MathJax', + url: 'https://www.mathjax.org', + description: 'A JavaScript display engine for mathematics that works in all browsers.', + }, +]; diff --git a/src/data/jsonld/types.ts b/src/data/jsonld/types.ts new file mode 100644 index 0000000..be26ccb --- /dev/null +++ b/src/data/jsonld/types.ts @@ -0,0 +1,144 @@ +import type { UrlObject } from 'url'; + +type Url = string | UrlObject; + +interface Person { + '@type': 'Person'; + name: string; + [key: string]: any; +} + +interface Organization { + '@type': 'Organization'; + name: string; + [key: string]: any; +} + +interface Place { + '@type': 'Place'; + name?: string; + address?: PostalAddress | string; +} + +interface Role { + '@type': 'Role'; + roleName?: string; + startDate?: string; + endDate?: string; + member?: Ref; +} + +interface PostalAddress { + '@type': 'PostalAddress'; + streetAddress?: string; + addressLocality?: string; + addressRegion?: string; + postalCode?: string; + addressCountry?: string; +} + +interface QuantitativeValue { + '@type': 'QuantitativeValue'; + value: number; + unitText?: string; +} + +interface EducationalOccupationalCredential { + '@type': 'EducationalOccupationalCredential'; + credentialCategory?: string; + recognizedBy?: Organization; +} + +interface CreativeWork { + '@type': 'CreativeWork'; + name?: string; + url?: Url; +} + +export interface Event { + '@type': 'Event'; + '@id': string; + name: string; + startDate: string; // ISO 8601 + endDate?: string; + url?: string; + description?: string; + speaker?: Ref | Ref[] | Person | Person[]; + organizer?: Ref | Ref[] | Person | Person[] | EnrichedOrganization | EnrichedOrganization[]; + host?: Ref | Ref[] | Person | Person[] | EnrichedOrganization | EnrichedOrganization[]; + performer?: Ref | Ref[] | Person | Person[] | EnrichedOrganization | EnrichedOrganization[]; + contributor?: Ref | Ref[] | Person | Person[] | EnrichedOrganization | EnrichedOrganization[]; + location?: { + '@type': 'Place'; + name: string; + address?: { + '@type': 'PostalAddress'; + streetAddress?: string; + addressLocality?: string; + postalCode?: string; + addressRegion?: string; + addressCountry?: string; + }; + }; + keywords?: string[]; + 'x-image'?: string; +} + +interface EducationalOccupationalProgram { + '@type': 'EducationalOccupationalProgram'; + name?: string; + educationalCredentialAwarded?: string | string[]; +} + +interface Ref { + '@id': string; +} + +export interface EnrichedOrganization { + // Core JSON-LD required + '@context'?: string; + '@type': 'Organization' | 'CollegeOrUniversity'; + '@id': string; + + // Common schema.org fields for Organization + name: string; + alternateName?: string | string[]; + url?: Url; + logo?: string; + image?: string; + description?: string; + disambiguatingDescription?: string; + email?: string; + telephone?: string; + foundingDate?: string; + dissolutionDate?: string; + founder?: Ref[] | Person | Person[]; + funder?: Ref[] | Person | Person[]; + foundingLocation?: Place | string; + location?: Place | string; + address?: PostalAddress | string; + memberOf?: Ref | Organization | string; + member?: Ref[] | Role[]; + parentOrganization?: Ref | Organization | string; + subOrganization?: Ref | Organization | string; + alumni?: Ref | Person | string; + employee?: Ref | Person | string; + numberOfEmployees?: QuantitativeValue; + department?: Ref | EnrichedOrganization | EducationalOccupationalProgram; + + // Legal / commercial + legalName?: string; + + // Geo/social extensions + sameAs?: string[]; + hasCredential?: Ref | EducationalOccupationalCredential | string; + + // Web metadata (you may add these manually) + mainEntityOfPage?: string; + subjectOf?: Ref[]; + + // Custom extensions + 'x-tags'?: string[]; + 'x-logo'?: string; + 'x-priority'?: number; +} diff --git a/src/data/jsonld/videos.ts b/src/data/jsonld/videos.ts new file mode 100644 index 0000000..fcc87b7 --- /dev/null +++ b/src/data/jsonld/videos.ts @@ -0,0 +1,15 @@ +export default [ + { + '@type': 'VideoObject', + '@id': 'video:latex2html5-proposal', + name: 'LaTeX2HTML5 - a proposal for the future of digital publishing', + description: + 'A new platform that utilizes existing standards for the future of digital publishing in the realm of mathematics and science. Works on all devices, including paper! Diagrams can be interactive with touch/mouse interactions.', + uploadDate: '2012-12-15', + embedUrl: 'https://www.youtube.com/embed/QYMLMUKJyFc', + url: 'https://www.youtube.com/watch?v=QYMLMUKJyFc', + creator: { '@id': 'person:danlynch' }, + associatedProject: { '@id': 'software:mathapedia' }, + keywords: ['latex', 'html5', 'digital publishing', 'mathapedia', 'interactive textbooks', 'education', 'tex'], + }, +]; diff --git a/src/data/jsonld/website.ts b/src/data/jsonld/website.ts new file mode 100644 index 0000000..fc0c270 --- /dev/null +++ b/src/data/jsonld/website.ts @@ -0,0 +1,17 @@ +import { WebSite } from 'schema-dts'; + +export default [ + { + '@type': 'WebSite', + '@id': 'website:latex2js.com', + url: 'https://latex2js.com', + name: 'LaTeX2JS', + description: 'Author interactive math equations and diagrams online using LaTeX and PSTricks.', + mainEntity: { + '@id': 'software:latex2js', + }, + publisher: { + '@id': 'person:danlynch', + }, + }, +] satisfies WebSite[]; diff --git a/src/lib/jsonld/filters.ts b/src/lib/jsonld/filters.ts new file mode 100644 index 0000000..3b6c9d6 --- /dev/null +++ b/src/lib/jsonld/filters.ts @@ -0,0 +1,157 @@ +import { JsonLdFilterOptions } from 'jsonldjs'; + +/** + * Create a filter for entities created by a specific organization + */ +export function createOrgCreatorFilter(orgId: string): JsonLdFilterOptions { + return { + customFilter: (entity) => { + // Include the org itself + if (entity['@id'] === orgId) return true; + + // Include entities created by this org + const creator = entity.creator; + if (creator) { + if (Array.isArray(creator)) { + return creator.some((c) => (typeof c === 'object' ? c['@id'] : c) === orgId); + } + const creatorId = typeof creator === 'object' ? creator['@id'] : creator; + return creatorId === orgId; + } + + return false; + }, + }; +} + +/** + * Create a filter for an organization and their associated entities + */ +export function createOrgWithRelatedFilter( + orgId: string, + options?: { + includeSoftware?: boolean; + includeCreativeWorks?: boolean; + includePeople?: boolean; + softwareIds?: string[]; + }, +): JsonLdFilterOptions { + const opts = { + includeSoftware: true, + includeCreativeWorks: false, + includePeople: false, + ...options, + }; + + return { + customFilter: (entity) => { + // Always include the organization + if (entity['@id'] === orgId) return true; + + // Include specified software + if ( + opts.includeSoftware && + (entity['@type'] === 'SoftwareApplication' || entity['@type'] === 'SoftwareSourceCode') + ) { + if (opts.softwareIds) { + return !!entity['@id'] && opts.softwareIds.includes(entity['@id']); + } + // Check if created by this org + const creator = entity.creator; + if (creator) { + if (Array.isArray(creator)) { + return creator.some((c) => (typeof c === 'object' ? c['@id'] : c) === orgId); + } + const creatorId = typeof creator === 'object' ? creator['@id'] : creator; + return creatorId === orgId; + } + } + + // Include creative works by this org + if ( + opts.includeCreativeWorks && + (entity['@type'] === 'CreativeWork' || + entity['@type'] === 'Article' || + entity['@type'] === 'VideoObject') + ) { + const author = entity.author || entity.creator || entity.publisher; + if (author) { + const authorId = typeof author === 'object' ? author['@id'] : author; + return authorId === orgId; + } + } + + // Include people associated with this org + if (opts.includePeople && entity['@type'] === 'Person') { + const worksFor = entity.worksFor || entity.memberOf; + if (worksFor) { + if (Array.isArray(worksFor)) { + return worksFor.some((w) => (typeof w === 'object' ? w['@id'] : w) === orgId); + } + const workId = typeof worksFor === 'object' ? worksFor['@id'] : worksFor; + return workId === orgId; + } + } + + return false; + }, + }; +} + +/** + * Common filter presets for Constructive + */ +export const FilterPresets = { + /** Include only the main organization entity (Constructive) */ + organizationOnly: { + includeIds: ['org:constructive'], + } satisfies JsonLdFilterOptions, + + /** Include organization and website */ + organizationAndWebsite: { + includeIds: ['org:constructive', 'website:constructive.io'], + } satisfies JsonLdFilterOptions, + + /** Include only software entities */ + softwareOnly: { + includeTypes: ['SoftwareApplication', 'SoftwareSourceCode'], + } satisfies JsonLdFilterOptions, + + /** Include only articles */ + articlesOnly: { + includeTypes: ['Article', 'BlogPosting'], + } satisfies JsonLdFilterOptions, + + /** Include only creative works (articles, videos, etc.) */ + creativeWorksOnly: { + includeTypes: ['CreativeWork', 'Article', 'VideoObject', 'BlogPosting'], + } satisfies JsonLdFilterOptions, + + /** Include only educational content */ + educationOnly: { + includeTypes: ['Course', 'LearningResource'], + } satisfies JsonLdFilterOptions, + + /** Exclude images */ + noImages: { + excludeTypes: ['ImageObject'], + } satisfies JsonLdFilterOptions, + + /** Include only entities with URLs */ + withUrlsOnly: { + requiredProperties: ['url'], + } satisfies JsonLdFilterOptions, + + /** Minimal graph - org and website only */ + minimal: { + customFilter: (entity) => { + if (entity['@type'] === 'Organization') { + return entity['@id'] === 'org:constructive'; + } + if (entity['@type'] === 'WebSite') { + return entity['@id'] === 'website:constructive.io'; + } + return false; + }, + } satisfies JsonLdFilterOptions, +} satisfies Record; diff --git a/src/lib/jsonld/index.ts b/src/lib/jsonld/index.ts new file mode 100644 index 0000000..8e7dafb --- /dev/null +++ b/src/lib/jsonld/index.ts @@ -0,0 +1,2 @@ +export * from './filters'; +export * from './subgraph'; diff --git a/src/lib/jsonld/subgraph.ts b/src/lib/jsonld/subgraph.ts new file mode 100644 index 0000000..c40272b --- /dev/null +++ b/src/lib/jsonld/subgraph.ts @@ -0,0 +1,125 @@ +import { extractSubgraphs, findReferencingEntities, type JsonLdGraph, type JsonLdEntity } from 'jsonldjs'; + +/** + * Pipe function type for JSON-LD graph transformations + */ +type PipeFunction = (graph: JsonLdGraph) => JsonLdGraph; + +export interface BidirectionalSubgraphOptions { + /** + * Whether to include entities that reference the root entities (reverse traversal) + * @default true + */ + includeReferencingEntities?: boolean; + + /** + * Filter referencing entities by @type. If specified, only entities with + * these types will be included in reverse traversal. + * @example ['Organization'] - only include organizations that reference the root + */ + referencingEntityTypes?: string[]; + + /** + * Whether to also extract the full subgraph (forward traversal) for + * referencing entities found during reverse traversal. + * @default false + */ + expandReferencingEntities?: boolean; +} + +/** + * Extract a bidirectional subgraph - both forward and reverse references + * + * Forward: Starting from root IDs, find all entities they reference + * Reverse: Find all entities that reference the root IDs + * + * @param graph - The full JSON-LD graph + * @param rootIds - Starting entity IDs + * @param options - Configuration options + * @returns Combined subgraph with both directions + */ +export function extractBidirectionalSubgraph( + graph: JsonLdGraph, + rootIds: string[], + options: BidirectionalSubgraphOptions = {}, +): JsonLdGraph { + const { + includeReferencingEntities = true, + referencingEntityTypes, + expandReferencingEntities = false, + } = options; + + // Start with forward traversal + const forwardEntities = extractSubgraphs(graph, rootIds); + const resultMap = new Map(); + + forwardEntities.forEach((entity) => { + resultMap.set(entity['@id'], entity); + }); + + // Reverse traversal - find entities that reference any of our root IDs + if (includeReferencingEntities) { + const referencingIds = new Set(); + + for (const rootId of rootIds) { + const referencing = findReferencingEntities(graph, rootId); + + for (const entity of referencing) { + // Apply type filter if specified + if (referencingEntityTypes && referencingEntityTypes.length > 0) { + const entityType = entity['@type']; + const types = Array.isArray(entityType) ? entityType : [entityType]; + if (!types.some((t) => referencingEntityTypes.includes(t as string))) { + continue; + } + } + + resultMap.set(entity['@id'], entity); + referencingIds.add(entity['@id']); + } + } + + // Optionally expand referencing entities (get their full subgraphs) + if (expandReferencingEntities && referencingIds.size > 0) { + const expandedEntities = extractSubgraphs(graph, Array.from(referencingIds)); + expandedEntities.forEach((entity) => { + if (!resultMap.has(entity['@id'])) { + resultMap.set(entity['@id'], entity); + } + }); + } + } + + return Array.from(resultMap.values()); +} + +/** + * Create a pipe function for bidirectional subgraph extraction + * + * Since pipe() receives the already-filtered graph, this function requires + * the original full graph to be passed in for reverse lookups. + * + * @param fullGraph - The complete JSON-LD graph (needed for reverse lookups) + * @param rootIds - Starting entity IDs for subgraph extraction + * @param options - Bidirectional subgraph options + * @returns A pipe function compatible with jsonldjs config builder + * + * @example + * ```typescript + * import { jsonldGraph } from '@/data/jsonld'; + * + * const config = defaultJsonLdConfig + * .clearSubgraph() + * .pipe(createBidirectionalSubgraphPipe(jsonldGraph, ['software:pgsql-parser'], { + * referencingEntityTypes: ['Organization'] + * })) + * .getConfig(); + * ``` + */ +export function createBidirectionalSubgraphPipe( + fullGraph: JsonLdGraph, + rootIds: string[], + options: BidirectionalSubgraphOptions = {}, +): PipeFunction { + return (_filteredGraph) => extractBidirectionalSubgraph(fullGraph, rootIds, options); +} diff --git a/src/pages/404.tsx b/src/pages/404.tsx new file mode 100644 index 0000000..1db1a9e --- /dev/null +++ b/src/pages/404.tsx @@ -0,0 +1,21 @@ +import Link from 'next/link'; + +import { Head } from '@/components/common/head'; +import { routes } from '@/routes'; + +export default function NotFound() { + return ( + <> + +
    +

    404

    +

    This page could not be found.

    +

    + + Back to LaTeX2JS + +

    +
    + + ); +} diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx new file mode 100644 index 0000000..f1877ba --- /dev/null +++ b/src/pages/_app.tsx @@ -0,0 +1,30 @@ +import '@/styles/globals.css'; +import 'latex2js/latex2js.css'; + +import type { AppProps } from 'next/app'; +import { Arbutus_Slab } from 'next/font/google'; +import NextHead from 'next/head'; +import { DefaultSeo } from 'next-seo'; + +import { Layout } from '@/components/common/layout'; +import { seoConfig } from '@/seo'; + +const arbutusSlab = Arbutus_Slab({ + weight: '400', + subsets: ['latin'], + variable: '--font-arbutus-slab', +}); + +export default function App({ Component, pageProps }: AppProps) { + return ( +
    + + + + + + + +
    + ); +} diff --git a/src/pages/examples/[exampleId].tsx b/src/pages/examples/[exampleId].tsx new file mode 100644 index 0000000..aef7dd1 --- /dev/null +++ b/src/pages/examples/[exampleId].tsx @@ -0,0 +1,134 @@ +import fs from 'fs'; +import path from 'path'; +import { useState } from 'react'; + +import type { GetStaticPaths, GetStaticProps } from 'next'; +import Link from 'next/link'; + +import { CodeBlock } from '@/components/code-block'; +import { Head } from '@/components/common/head'; +import { Latex } from '@/components/latex'; +import { TexEditor } from '@/components/tex-editor'; +import { useAutoRender } from '@/components/use-auto-render'; +import { defaultJsonLdConfig } from '@/config'; +import { examples, getExample, type ExampleMeta } from '@/data/examples'; +import { routes } from '@/routes'; + +interface ExamplePageProps { + example: ExampleMeta; + source: string; +} + +export default function ExamplePage({ example, source }: ExamplePageProps) { + const route = `/examples/${example.slug}` as const; + const [isEditing, setIsEditing] = useState(false); + const [editedSource, setEditedSource] = useState(source); + const { rendered, diagnostics, renderNow } = useAutoRender(editedSource, source); + + const jsonLdConfig = defaultJsonLdConfig + .clearSubgraph() + .subgraph(['website:latex2js.com', 'software:latex2js', `webpage:latex2js-example-${example.slug}`]) + .getConfig(); + + return ( + <> + + +

    + + ← All examples + +

    +

    {example.title}

    +

    {example.description}

    + {example.interactive && ( +

    + This diagram is interactive — use your mouse or touch to play with it. +

    + )} + +
    + +
    + +

    Source

    +
    + {isEditing ? ( +
    + renderNow()} + diagnostics={diagnostics} + /> +
    + ) : ( + + )} +
    +
    + {isEditing ? ( + <> + + + + ) : ( + + )} + + Open in sandbox + +
    + + ); +} + +export const getStaticPaths: GetStaticPaths = () => { + return { + paths: examples.map((example) => ({ params: { exampleId: example.slug } })), + fallback: false, + }; +}; + +export const getStaticProps: GetStaticProps = ({ params }) => { + const example = getExample(params?.exampleId as string); + if (!example) { + return { notFound: true }; + } + + const source = fs.readFileSync(path.join(process.cwd(), 'content/examples', example.file), 'utf-8'); + + return { + props: { + example, + source, + }, + }; +}; diff --git a/src/pages/examples/index.tsx b/src/pages/examples/index.tsx new file mode 100644 index 0000000..7cee227 --- /dev/null +++ b/src/pages/examples/index.tsx @@ -0,0 +1,50 @@ +import Link from 'next/link'; + +import { Head } from '@/components/common/head'; +import { defaultJsonLdConfig } from '@/config'; +import { examples } from '@/data/examples'; +import { routes } from '@/routes'; +import { getPageSeo } from '@/seo'; + +export default function ExamplesIndex() { + const seo = getPageSeo('/examples'); + + const jsonLdConfig = defaultJsonLdConfig + .clearSubgraph() + .subgraph([ + 'website:latex2js.com', + 'software:latex2js', + ...examples.map((example) => `webpage:latex2js-example-${example.slug}`), + ]) + .getConfig(); + + return ( + <> + + +

    Examples

    +

    + Interactive PSTricks diagrams rendered live in the browser by LaTeX2JS — each with its LaTeX source. Be sure to + check out the{' '} + + example apps on GitHub + + ! +

    + +
      + {examples.map((example) => ( +
    • + +

      {example.title}

      +

      {example.description}

      + {example.interactive && ( +

      Interactive

      + )} + +
    • + ))} +
    + + ); +} diff --git a/src/pages/index.tsx b/src/pages/index.tsx new file mode 100644 index 0000000..269376c --- /dev/null +++ b/src/pages/index.tsx @@ -0,0 +1,258 @@ +import Image from 'next/image'; +import Link from 'next/link'; + +import { Head } from '@/components/common/head'; +import { Latex } from '@/components/latex'; +import { defaultJsonLdConfig } from '@/config'; +import { routes } from '@/routes'; +import { getPageSeo } from '@/seo'; + +import photo from '../../public/images/photo.png'; + +const lifeEquation = String.raw` +$$\frac{\delta}{\delta u} \int_{birth}^{death} f(life) du = \mbox{your life}$$ +`; + +const essay = String.raw` +\definecolor{lightblue}{RGB}{173,216,230} +\begin{pspicture}(0,-3)(8,3) +\rput(0,0){$x(t)$} +\rput(4,1.5){$f(t)$} +\rput(4,-1.5){$g(t)$} +\rput(8.2,0){$y(t)$} +\rput(1.5,-2){$h(t)$} +\psframe(1,-2.5)(7,2.5) +\psframe(3,1)(5,2) +\psframe(3,-1)(5,-2) +\rput(4,0){$X_k = \frac{1}{p} \sum \limits_{n=\langle p\rangle}x(n)e^{-ik\omega_0n}$} +\psline{->}(0.5,0)(1.5,0) +\psline{->}(1.5,1.5)(3,1.5) +\psline{->}(1.5,-1.5)(3,-1.5) +\psline{->}(6.5,1.5)(6.5,0.25) +\psline{->}(6.5,-1.5)(6.5,-0.25) +\psline{->}(6.75,0)(7.75,0) +\psline(1.5,-1.5)(1.5,1.5) +\psline(5,1.5)(6.5,1.5) +\psline(5,-1.5)(6.5,-1.5) +\psline(6,-1.5)(6.5,-1.5) +\pscircle(6.5,0){0.25} +\psline(6.25,0)(6.75,0) +\psline(6.5,0.5)(6.5,-0.5) +\end{pspicture} + +Many of us think our thoughts using a language of some sort---there is usually some voice in our minds. Language in some ways, makes us who we are. Some even argue in the world of cognitive science that language is the foundation of our consciousness. + + +An author who has in their minds representations of intelligent concepts should be able to freely express herself through language with free association---digital expressions of these ideas in some cases requires total control of the computer and all of its processes. + + +The vision behind the personal computer was that any person could have full command of the functions of their device. I think this vision has come true to some degree, but not fully when it comes to creating graphics, especially mathematical diagrams online. + + +Does the common mathematician or professor have the ability to express concepts through web technology? The Web has its own language, and the goal of this project is to help blur the lines between what authoring the mathematical Web should be like and typesetting beautiful Math. + + +If you know \LaTeX, then get ready to author interactive diagrams in real-time (try using mouse or touch to interact with diagrams). + + +What matters most is minimizing the distance between our expression of an idea and the execution of that idea. For example, I can describe a vector at $(0,0)$ and initial value of the head at $(2,2)$ that will follow a user touch or mouse event. This will produce the following interaction: + + +\begin{center} +\begin{pspicture}(-2,-2)(2,2) +\psframe(-2,-2)(2,2) +\userline[linewidth=1.5 pt]{->}(0,0)(2,2) +\end{pspicture} +\end{center} + + +This was as easy as using this \TeX, which many math professors could understand. + +\begin{verbatim} +\begin{pspicture}(-2,-2)(2,2) +\psframe(-2,-2)(2,2) +\userline[linewidth=1.5 pt]{->}(0,0)(2,2) +\end{pspicture} +\end{verbatim} + +If you specify more arguments, you can create functions for the head and and tail of the vector, which each takes the current $x$ and $y$ position of the users finger or cursor as they move and produces the following interaction: + +\begin{center} +\begin{pspicture}(-2,-2)(2,2) +\psframe(-2,-2)(2,2) +\userline[linewidth=2pt,linecolor=green]{->}(0,0)(2,2){-x}{-y} +\userline[linewidth=2pt,linecolor=red]{->}(0,0)(2,2){0}{y} +\userline[linewidth=2pt,linecolor=violet]{->}(0,0)(2,2){-x}{cos(y)} +\userline[linewidth=2pt,linecolor=lightblue]{->}(0,0)(2,2)(sin(x)}{-y} +\end{pspicture} +\end{center} + +2 extra arguments provide functions for the head, 4 extra arguments allows you to control both and tail + +\begin{verbatim} +\userline[linewidth=2pt,linecolor=green]{->}(0,0)(2,2){-x}{-y} +\userline[linewidth=2pt,linecolor=red]{->}(0,0)(2,2){0}{y} +\userline[linewidth=2pt,linecolor=violet]{->}(0,0)(2,2){-x}{cos(y)} +\userline[linewidth=2pt,linecolor=lightblue]{->}(0,0)(2,2)(sin(x)}{-y} +\end{verbatim} + +I can also draw a more complex version, and start to make more useful diagrams to describe vectors: + +\begin{center} +\begin{pspicture}(-5,-5)(5,5) + +% y-axis +\rput(0.3,3.75){ $Im$ } +\psline{->}(0,-3.75)(0,3.75) + +% x-axis +\rput(3.75,0.3){ $Re$ } +\psline{->}(-3.75,0)(3.75,0) + +% the circle +\pscircle(0,0){ 3 } + + + % new vector +\rput(2.3,1){$e^{i\omega}-\alpha$} +\userline[linewidth=1.5 pt]{->}(1.500,0.000)(2.121,2.121) +\userline[linewidth=1.5 pt,linecolor=blue]{->}(0,0.000)(2.121,2.121){(x>0) ? 3 * cos( atan(-y/x) ) : -3 * cos( atan(-y/x) ) }{ (x>0) ? -3 * sin( atan(-y/x) ) : 3 * sin( atan(-y/x) )} + +\userline[linewidth=1.5 pt,linestyle=dashed](-1.500,0.000)(2.121,2.121){x}{0}{x}{y} +\userline[linewidth=1.5 pt,linestyle=dashed](-1.500,0.000)(2.121,2.121){0}{y}{x}{y} + +\rput(-0.75,-4.25){$1+\alpha$} +\rput(2.25,-4.25){$1-\alpha$} +\psline{<->}(-3,-4)(1.5,-4) +\psline{<->}(1.5,-4)(3,-4) +\psline[linestyle=dashed](3,-4.5)(3,0) +\psline[linestyle=dashed](-3,-4.5)(-3,0) +\psline[linestyle=dashed](1.5,-4.5)(1.5,0) + + +\end{pspicture} +\end{center} +`; + +const frameworks = [ + { label: 'Vue', href: routes.installation.vue, image: '/images/vue.png' }, + { label: 'React', href: routes.installation.react, image: '/images/react.png' }, + { label: 'HTML5', href: routes.installation.html5, image: '/images/html5.png' }, +]; + +export default function Home() { + const seo = getPageSeo('/'); + + return ( + <> + + +
    +

    LaTeX2JS

    +

    + Author interactive math equations and diagrams online using LaTeX and PSTricks +

    +
    + +
    + +
    + Interactive LaTeX2JS diagrams rendered on multiple devices +
    + +
    + +
    +

    + This project is the frontend-only version of the code that originated from{' '} + + Mathapedia + {' '} + to enable real-time, dynamic authorship of mathematical ebooks. +

    + +
    + +
    + +
    +

    Proud to support the best

    +
    + {frameworks.map((framework) => ( + + {framework.label} + + ))} +
    +
    + +
    + +
    +
    +

    Installation

    +

    + Install LaTeX2JS for{' '} + + React + + ,{' '} + + Vue + + , or{' '} + + plain HTML5 + + . +

    +
    +
    +

    Examples

    +

    + Get inspired, and make sure you see{' '} + + the PSTricks examples here + + ! +

    +
    +
    +

    Get Started

    +

    + Check out the{' '} + + example apps on GitHub + + , or play in the{' '} + + sandbox + + . +

    +
    +
    +

    Documentation

    +

    + There is also quite a bit of documentation{' '} + + here + + . +

    +
    +
    + +
    + +
    + +
    + + ); +} diff --git a/src/pages/installation/[framework].tsx b/src/pages/installation/[framework].tsx new file mode 100644 index 0000000..ef6f20e --- /dev/null +++ b/src/pages/installation/[framework].tsx @@ -0,0 +1,76 @@ +import type { GetStaticPaths, GetStaticProps } from 'next'; +import Link from 'next/link'; + +import { CodeBlock } from '@/components/code-block'; +import { Head } from '@/components/common/head'; +import { defaultJsonLdConfig } from '@/config'; +import { getInstallGuide, installGuides, type InstallGuide } from '@/data/installs'; +import { routes } from '@/routes'; +import { getPageSeo } from '@/seo'; + +interface InstallPageProps { + guide: InstallGuide; +} + +export default function InstallPage({ guide }: InstallPageProps) { + const route = `/installation/${guide.slug}` as const; + const seo = getPageSeo(route); + + const subgraphIds = ['website:latex2js.com', 'software:latex2js']; + if (guide.pkg) { + subgraphIds.push(`software:latex2js-${guide.slug}`); + } + const jsonLdConfig = defaultJsonLdConfig.clearSubgraph().subgraph(subgraphIds).getConfig(); + + return ( + <> + + +

    + + ← All installation guides + +

    + +
    + {guide.name} +

    {guide.title}

    +
    + +
      + {guide.steps.map((step, index) => ( +
    1. +

      + {index + 1}. {step.text} +

      + {step.code && ( +
      + +
      + )} +
    2. + ))} +
    + + ); +} + +export const getStaticPaths: GetStaticPaths = () => { + return { + paths: installGuides.map((guide) => ({ params: { framework: guide.slug } })), + fallback: false, + }; +}; + +export const getStaticProps: GetStaticProps = ({ params }) => { + const guide = getInstallGuide(params?.framework as string); + if (!guide) { + return { notFound: true }; + } + + return { + props: { + guide, + }, + }; +}; diff --git a/src/pages/installation/index.tsx b/src/pages/installation/index.tsx new file mode 100644 index 0000000..c0ba7d2 --- /dev/null +++ b/src/pages/installation/index.tsx @@ -0,0 +1,38 @@ +import Link from 'next/link'; + +import { Head } from '@/components/common/head'; +import { defaultJsonLdConfig } from '@/config'; +import { installGuides } from '@/data/installs'; +import { routes } from '@/routes'; +import { getPageSeo } from '@/seo'; + +export default function InstallationIndex() { + const seo = getPageSeo('/installation'); + + const jsonLdConfig = defaultJsonLdConfig + .clearSubgraph() + .subgraph(['website:latex2js.com', 'software:latex2js', 'software:latex2js-react', 'software:latex2js-vue']) + .getConfig(); + + return ( + <> + + +

    Installation

    +

    + LaTeX2JS ships adapters for the frameworks you already use. Pick yours: +

    + +
      + {installGuides.map((guide) => ( +
    • + + {guide.name} +

      {guide.name}

      + +
    • + ))} +
    + + ); +} diff --git a/src/pages/sandbox.tsx b/src/pages/sandbox.tsx new file mode 100644 index 0000000..f647134 --- /dev/null +++ b/src/pages/sandbox.tsx @@ -0,0 +1,163 @@ +import fs from 'fs'; +import path from 'path'; +import { useEffect, useState } from 'react'; + +import type { GetStaticProps } from 'next'; +import Link from 'next/link'; + +import { Head } from '@/components/common/head'; +import { Latex } from '@/components/latex'; +import { TexEditor } from '@/components/tex-editor'; +import { useAutoRender } from '@/components/use-auto-render'; +import { defaultJsonLdConfig } from '@/config'; +import { examples } from '@/data/examples'; +import { routes } from '@/routes'; +import { getPageSeo } from '@/seo'; + +interface SandboxExample { + slug: string; + title: string; + source: string; +} + +interface SandboxPageProps { + exampleSources: SandboxExample[]; +} + +const placeholder = [ + '\\begin{pspicture}(-2,-2)(2,2)', + '\\psframe(-2,-2)(2,2)', + '\\userline[linewidth=1.5 pt]{->}(0,0)(2,2)', + '\\end{pspicture}', +].join('\n'); + +export default function Sandbox({ exampleSources }: SandboxPageProps) { + const seo = getPageSeo(routes.sandbox); + const [tex, setTex] = useState(''); + const [editorOpen, setEditorOpen] = useState(true); + const { rendered, diagnostics, renderNow } = useAutoRender(tex); + + useEffect(() => { + const prefix = '#tex='; + if (!window.location.hash.startsWith(prefix)) return; + + try { + const source = decodeURIComponent(window.location.hash.slice(prefix.length)); + setTex(source); + renderNow(source); + } catch { + // Ignore malformed deep-link hashes and leave the editor empty. + } + }, []); + + const loadExample = (slug: string) => { + const example = exampleSources.find((item) => item.slug === slug); + if (!example) return; + setTex(example.source); + renderNow(example.source); + }; + + return ( + <> + + +
    +

    LaTeX Sandbox

    +
    + + +
    +
    + +

    + Write LaTeX and PSTricks, then render it live. Powered by LaTeX2JS and MathJax. +

    + + + + +
    + {editorOpen && ( +
    + renderNow()} + placeholder={placeholder} + diagnostics={diagnostics} + /> +
    + )} +
    + {diagnostics.some((diagnostic) => diagnostic.severity === 'error') && ( +

    + The source has a syntax error; showing the last valid render. +

    + )} + {rendered ? ( + /* Remount on each render so LaTeX2JS reprocesses the new source. */ + + ) : ( +

    + The preview appears here and updates as you type — start from an{' '} + + example + {' '} + if you'd like something to take apart. +

    + )} +
    +
    + + ); +} + +export const getStaticProps: GetStaticProps = () => { + return { + props: { + exampleSources: examples.map((example) => ({ + slug: example.slug, + title: example.title, + source: fs.readFileSync(path.join(process.cwd(), 'content/examples', example.file), 'utf-8'), + })), + }, + }; +}; diff --git a/src/routes.ts b/src/routes.ts new file mode 100644 index 0000000..e12ba26 --- /dev/null +++ b/src/routes.ts @@ -0,0 +1,24 @@ +// ==== App routes ==== +export const routes = { + home: '/', + sandbox: '/sandbox', + sandboxWithSource: (tex: string) => `/sandbox#tex=${encodeURIComponent(tex)}` as const, + examples: { + index: '/examples', + example: (exampleId: string) => `/examples/${exampleId}` as const, + }, + installation: { + index: '/installation', + react: '/installation/react', + vue: '/installation/vue', + html5: '/installation/html5', + }, + external: { + github: 'https://github.com/Mathapedia/LaTeX2JS', + exampleApps: 'https://github.com/Mathapedia/LaTeX2JS/tree/main/examples', + npm: 'https://www.npmjs.com/package/latex2js', + docs: 'https://mathapedia.com/books/31/sections/176', + mathapedia: 'https://mathapedia.com', + mathjax: 'https://www.mathjax.org', + }, +} as const; diff --git a/src/seo.ts b/src/seo.ts new file mode 100644 index 0000000..b9a31e4 --- /dev/null +++ b/src/seo.ts @@ -0,0 +1,111 @@ +// ============================================================================= +// SEO Configuration +// ============================================================================= +// Central place for all SEO-related content and metadata. +// Edit page-specific SEO in the `pages` object below. +// ============================================================================= + +export const site = { + url: 'https://latex2js.com', + name: 'LaTeX2JS', + twitterHandle: '@mathapedia', +}; + +export const canonical = site.url; + +// ----------------------------------------------------------------------------- +// Page SEO Interface +// ----------------------------------------------------------------------------- + +export interface PageSeo { + title: string; + description: string; + ogImage?: string; +} + +// ----------------------------------------------------------------------------- +// Page-Specific SEO +// ----------------------------------------------------------------------------- +// Add new pages here. The key should match the route path. +// ----------------------------------------------------------------------------- + +export const pages: Record = { + '/': { + title: 'LaTeX2JS - Interactive Math Equations and Diagrams', + description: + 'Author interactive math equations and diagrams online using LaTeX and PSTricks. LaTeX2JS renders pspicture environments, draggable vectors, sliders, and live plots directly in the browser.', + }, + '/examples': { + title: 'Examples - LaTeX2JS', + description: + 'Interactive PSTricks examples rendered live by LaTeX2JS: block diagrams, draggable vectors, slider-driven plots, and more — each with its LaTeX source.', + }, + '/sandbox': { + title: 'LaTeX Sandbox - LaTeX2JS', + description: + 'Edit and render LaTeX and PSTricks in the browser with LaTeX2JS, or start from one of the interactive examples.', + }, + '/installation': { + title: 'Installation - LaTeX2JS', + description: + 'Install LaTeX2JS for React, Vue, or plain HTML5. Render interactive LaTeX and PSTricks diagrams in your own app in minutes.', + }, + '/installation/react': { + title: 'React Installation - LaTeX2JS', + description: + 'Use the latex2react package to render interactive LaTeX and PSTricks diagrams in React applications.', + }, + '/installation/vue': { + title: 'Vue Installation - LaTeX2JS', + description: + 'Use the latex2vue plugin to render interactive LaTeX and PSTricks diagrams in Vue and Nuxt applications.', + }, + '/installation/html5': { + title: 'HTML5 Installation - LaTeX2JS', + description: + 'Drop the LaTeX2HTML5 bundle into any HTML page and render interactive LaTeX and PSTricks diagrams with a single script tag.', + }, +}; + +// ----------------------------------------------------------------------------- +// Default OG Image +// ----------------------------------------------------------------------------- + +export const defaultOgImage = { + url: `${canonical}/images/share.jpg`, + width: 1024, + height: 768, + alt: 'LaTeX2JS', +}; + +// ----------------------------------------------------------------------------- +// Computed SEO Config (used by next-seo) +// ----------------------------------------------------------------------------- + +export const seoConfig = { + siteUrl: site.url, + title: pages['/'].title, + canonical, + description: pages['/'].description, + openGraph: { + type: 'website', + url: site.url, + title: pages['/'].title, + description: pages['/'].description, + site_name: site.name, + images: [defaultOgImage], + }, + twitter: { + handle: site.twitterHandle, + site: site.twitterHandle, + cardType: 'summary_large_image', + }, +}; + +// ----------------------------------------------------------------------------- +// Helper to get SEO for a route (with fallback to home) +// ----------------------------------------------------------------------------- + +export function getPageSeo(route: string): PageSeo { + return pages[route] ?? pages['/']; +} diff --git a/src/seo/prepare.sh b/src/seo/prepare.sh new file mode 100755 index 0000000..b6e8ad3 --- /dev/null +++ b/src/seo/prepare.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +export S3_BUCKET=latex2js.com +export AWS_PROFILE=pyramation + +(cd out && + find . -type f -name '*.html' | while read HTMLFILE; do + HTMLFILESHORT=${HTMLFILE:2} + + HTMLFILE_WITHOUT_INDEX=${HTMLFILESHORT//index.html/} + HTMLFILE_WITHOUT_HTML=${HTMLFILE_WITHOUT_INDEX//.html/} + + # cp /examples/index.html to /examples so extensionless URLs work on S3 + aws s3 cp s3://$S3_BUCKET/${HTMLFILESHORT} s3://$S3_BUCKET/$HTMLFILE_WITHOUT_HTML + echo aws s3 cp s3://$S3_BUCKET/${HTMLFILESHORT} s3://$S3_BUCKET/$HTMLFILE_WITHOUT_HTML + + if [ $? -ne 0 ]; then + echo "***** Failed renaming build to $S3_BUCKET (html)" + exit 1 + fi + done) diff --git a/src/seo/seo.ts b/src/seo/seo.ts new file mode 100644 index 0000000..210aafd --- /dev/null +++ b/src/seo/seo.ts @@ -0,0 +1,170 @@ +import fs from 'fs'; +import path from 'path'; +import { globSync } from 'glob'; +import { mkdirp } from 'mkdirp'; + +import { siteConfig } from '../config'; +import { seoConfig } from '../seo'; + +const canonical: string = seoConfig.canonical; +const pageObjects: Record = {}; + +const OUT_DIR: string = path.resolve(__dirname, '../../out'); +const IGNORE: string[] = ['404', '_document', '_app']; + +interface PageObject { + page: string; + lastModified: Date; +} + +const walkSync = (dir: string): void => { + // Get all html files of the current directory + const htmlFiles: string[] = globSync(`${dir}/**/*.html`); + + htmlFiles.forEach((htmlFile: string) => { + // Retrieve file's stats + const fileStat = fs.statSync(htmlFile); + + // Construct this file's pathname excluding the outer folder & its extension + let cleanFileName: string = htmlFile.replace(`${dir}/`, '').replace('.html', ''); + + // Any index.js pages will be renamed to / + if (cleanFileName.match(/\/index$/) || cleanFileName === 'index') { + cleanFileName = cleanFileName.replace(/\/?index$/, ''); + } + + // The filename only without path + const exactFileName: string | undefined = cleanFileName.split('/').pop(); + + if (exactFileName !== undefined && !IGNORE.includes(exactFileName)) { + pageObjects[`/${cleanFileName}`] = { + page: `/${cleanFileName}`, + lastModified: fileStat.mtime, + }; + } + }); +}; + +// Fill `pageObjects` +walkSync(OUT_DIR); + +function formatDate(date: Date): string { + const d = new Date(date); + let month: string = '' + (d.getMonth() + 1); + let day: string = '' + d.getDate(); + const year: number = d.getFullYear(); + + if (month.length < 2) month = '0' + month; + if (day.length < 2) day = '0' + day; + + return [year, month, day].join('-'); +} + +const pageSitemapXml: string = ` + + ${Object.keys(pageObjects) + .map( + (pagePath) => ` + ${canonical}${pagePath} + ${formatDate(new Date(pageObjects[pagePath].lastModified))} + `, + ) + .join('\n')} +`; + +const sitemapXml: string = ` + + +${canonical}/sitemaps/pages.xml + + +`; + +interface BadAgent { + text: string; + bots: string[]; +} + +const BAD_AGENTS: BadAgent[] = [ + { + text: 'Search engines only please :) Thanks for obeying robots.txt', + bots: ['UbiCrawler', 'DOC', 'Zao', 'discobot', 'dotbot', 'yacybot'], + }, + { + text: "Dear bots, we don't appreciate you copying site content and providing very little additional value.", + bots: [ + 'sitecheck.internetseer.com', + 'Zealbot', + 'MJ12bot', + 'MSIECrawler', + 'SiteSnagger', + 'WebStripper', + 'WebCopier', + 'Fetch', + 'Offline Explorer', + 'Teleport', + 'TeleportPro', + 'WebZIP', + 'linko', + 'HTTrack', + 'Microsoft.URL.Control', + 'Xenu', + 'larbin', + 'libwww', + 'ZyBORG', + 'Download Ninja', + ], + }, + { + text: 'Recursive mode wget is not friendly', + bots: ['wget', 'grub-client'], + }, + { + text: "I realize you don't follow robots.txt, but FYI", + bots: ['k2spider'], + }, + { + text: 'Abusive bots', + bots: ['NPBot'], + }, +]; + +const robotsTxt: string = ` +# +# Dear bot, crawler or kind technical person who wishes to crawl ${siteConfig.site.host}, +# please email ${siteConfig.emails.support}. We require whitelisting to access our sitemap. +# +# Thanks in advance! Your friendly Ops Team @ ${siteConfig.company.name}. + +${BAD_AGENTS.map(({ text, bots }) => { + return ` +# +# ${text} +# + + ${bots + .map((bot) => { + return ` +User-agent: ${bot} +Disallow: /`; + }) + .join('\n')} + `; +}).join('')} + +User-agent: * + +${Object.keys(pageObjects) + .map((pagePath) => `Allow: ${pagePath}$`) + .join('\n')} + +Sitemap: ${canonical}/sitemaps/pages.xml + +Host: ${siteConfig.site.host} + +`; + +fs.writeFileSync('out/sitemap.xml', sitemapXml); +mkdirp.sync('out/sitemaps'); +fs.writeFileSync('out/sitemaps/pages.xml', pageSitemapXml); +fs.writeFileSync('out/robots.txt', robotsTxt); diff --git a/src/styles/globals.css b/src/styles/globals.css new file mode 100644 index 0000000..db3538e --- /dev/null +++ b/src/styles/globals.css @@ -0,0 +1,51 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +@layer base { + /* Match the original site: Arbutus Slab (the Knuth-esque slab serif the old + CSS applied to body and rendered LaTeX content), equations via MathJax. + The family itself is applied on the _app wrapper, where the next/font + variable is in scope. */ + body { + @apply bg-white text-neutral-800 antialiased; + } + + /* Original-site headings: Arbutus Slab, bold (browser-synthesized — the + face ships 400 only), rgb(51,51,51). */ + h1, + h2, + h3, + h4 { + @apply font-bold text-[#333]; + } +} + +/* The latex2js stylesheet references the Google Fonts family name; point those + selectors at the next/font self-hosted face so they actually resolve. */ +.math, +span.rm { + font-family: var(--font-arbutus-slab), Georgia, serif; +} + +/* The old site used the browser's default paragraph margin (16px top/bottom); + Tailwind preflight zeroes it, which cramped paragraphs and the pspicture + figures between them. */ +.math p { + margin: 16px 0; +} + +/* latex2react ships verbatim as a gray code block; the old site rendered it as + plain white text. Override the inline style to match. */ +pre.verbatim { + background-color: transparent !important; + padding: 0 !important; + border-radius: 0 !important; + margin: 13px 0; +} + +/* Give rendered LaTeX blocks breathing room; the latex2js stylesheet handles + the pspicture internals. */ +.latex2js-content { + @apply mx-auto max-w-3xl; +} diff --git a/tailwind.config.ts b/tailwind.config.ts new file mode 100644 index 0000000..3c0494e --- /dev/null +++ b/tailwind.config.ts @@ -0,0 +1,15 @@ +import type { Config } from 'tailwindcss'; + +const config: Config = { + content: ['./src/**/*.{ts,tsx}'], + theme: { + extend: { + fontFamily: { + serif: ['var(--font-arbutus-slab)', 'Georgia', 'serif'], + }, + }, + }, + plugins: [], +}; + +export default config; diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..e338f33 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "react-jsx", + "incremental": true, + "paths": { + "@/*": ["./src/*"] + }, + "target": "ES2020", + "plugins": [ + { + "name": "next" + } + ] + }, + "include": ["**/*.ts", "**/*.tsx", "next-env.d.ts", ".next/types/**/*.ts"], + "exclude": ["node_modules", "out"] +} diff --git a/yarn.lock b/yarn.lock deleted file mode 100644 index c008302..0000000 --- a/yarn.lock +++ /dev/null @@ -1,64 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -balanced-match@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" - -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - -glob@^7.1.2: - version "7.1.2" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" - -minimatch@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - dependencies: - brace-expansion "^1.1.7" - -once@^1.3.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - dependencies: - wrappy "1" - -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"