diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..e61e3db --- /dev/null +++ b/.editorconfig @@ -0,0 +1,16 @@ +# http://editorconfig.org +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 4 +end_of_line = lf +trim_trailing_whitespace = false +insert_final_newline = false + +[*.json] +indent_size = 2 + +[*.md] +trim_trailing_whitespace = false diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..1d6f595 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,3 @@ +# Don't allow merging changes to the lock file, because the result +# may be invalid. Instead, conflicts should be resolved with "pnpm install". +pnpm-lock.yaml merge=binary diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1be51ed --- /dev/null +++ b/.gitignore @@ -0,0 +1,42 @@ +# Logs +logs +*.log +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# Dependency directories +node_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Build output +package/ +dist/ diff --git a/.node-version b/.node-version new file mode 100644 index 0000000..adb0705 --- /dev/null +++ b/.node-version @@ -0,0 +1 @@ +v22.4.1 diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..d6ad5d6 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,8 @@ +# Package manager files +pnpm-lock.yaml + +# Build outputs +dist/* + +# Prettier reformats code blocks inside Markdown, which affects rendered output +*.md diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..6440f11 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,13 @@ +# N.B.: whitespace rules are inferred from .editorconfig +printWidth: 100 # wrap at 100 chars +singleQuote: true # force single quotes for strings +arrowParens: 'always' # force (x) => x over x => x +trailingComma: 'all' # force trailing commas wherever possible on multiline expressions +bracketSpacing: true # force { foo: 123 } instead of {foo: 123} (single line literals) +bracketSameLine: false # force: + # + diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..9cff393 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,55 @@ +{ + "explorer.autoRevealExclude": { + "**/node_modules": true + }, + "explorer.fileNesting.enabled": true, + "explorer.fileNesting.expand": false, + "explorer.fileNesting.patterns": { + "*.ts": "${capture}.test.ts", + "*.d.ts": "${capture}.map", + "package.json": ".git*, .editorconfig, .eslint*, .node-version, .pnpm*, pnpm-*, .prettier*, .vscode*, eslint*, prettier*, tsconfig.json, *.log", + }, + "search.exclude": { + "**/node_modules": true, + "**/dist": true + }, + "typescript.tsdk": "node_modules/typescript/lib", + "prettier.prettierPath": "node_modules/prettier", + "nodejs-testing.include": [ + "./src" + ], + "nodejs-testing.extensions": [ + { + "extensions": [ + "mjs", + "cjs", + "js" + ], + "parameters": [] + }, + { + "extensions": [ + "mts", + "cts", + "ts" + ], + "parameters": [ + "--import", + "tsx" + ] + } + ], + "cSpell.words": [ + "arethetypeswrong", + "attw", + "decrementally", + "haragei", + "nonconstructor", + "pkgroll", + "postbuild", + "postpublish", + "ruleset", + "voxpelli" + ], + "references.preferredLocation": "peek" +} \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..305a125 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Aleksandar Ružičić + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..fced550 --- /dev/null +++ b/README.md @@ -0,0 +1,477 @@ +# @haragei/dag + +A TypeScript library implementing Directed Acyclic Graph (DAG) data structure with online cycle detection and topological ordering. + +A DAG is a finite graph that consists of nodes (a.k.a. vertices) and edges, with the edges directed from one node to another, ensuring that there are no cycles. This means you cannot start at any node and follow a consistently directed sequence of edges that eventually loops back to that node. + +## Features + +- **Online Cycle Detection**: The library dynamically checks for cycles as edges are added, ensuring the graph remains acyclic. + +- **Topological Ordering**: It provides O(1) getter to order the nodes of the graph linearly such that for every directed edge from node `u` to node `v`, `u` comes before `v` in the ordering. This is particularly useful in scenarios like task scheduling, where certain tasks must precede others. + +## Installation + +```bash +npm install @haragei/dag +``` +
+pnpm + +```bash +pnpm add @haragei/dag +``` +
+ +
+yarn + +```bash +yarn add @haragei/dag +``` +
+ +## Usage + +Creating a Graph: +```ts +import { DAG } from '@haragei/dag'; + +// Populate the graph with initial nodes +const graph = new DAG(['A', 'B', 'C']); +``` + +Adding nodes: +```ts +// Add few more nodes +graph + .add('D') + .add('E') + .add('F'); +``` + +Adding edges and detecting cycles: +```ts +// Add edge from 'A' to 'B' +graph.addEdge('A', 'B'); // No cycle + +// Add edge from 'B' to 'C' +graph.addEdge('B', 'C'); // No cycle + +// Attempt to add edge from 'C' to 'A' +try { + graph.addEdge('C', 'A'); // Cycle detected +} catch (error) { + console.error(error.message); // "Cycle detected" +} + +// Verify no edge with cycle was added: +console.log(graph.hasEdge('C', 'A')); // false + +// Add few more valid edges +graph.addEdge('B', 'D'); +graph.addEdge('D', 'E'); +graph.addEdge('E', 'C'); +graph.addEdge('C', 'F'); +``` + +Topological order: +```ts +console.log(graph.order); // ['A', 'B', 'D', 'E', 'C', 'F'] +``` + +## API Reference + + +### `DAG` + +A Directed Acyclic Graph structure with online cycle detection and topological ordering. + +Create / Copy: +- [`new DAG()`](#constructorinitialnodes-iterablet) +- [`.copy()`](#copy-dagt) + +Properties: +- [`.order`](#order-t) +- [`.size`](#size-number) + +Iteration: +- [`[Symbol.iterator]()`](#symboliterator-iterableiteratort) +- [`.keys()`](#keys-iterableiteratort) + +Nodes: +- [`.clear()`](#clear-this) +- [`.add()`](#addnode-t-this) +- [`.has()`](#hasnode-t-boolean) +- [`.delete()`](#deletenode-t-this) + +Edges: +- [`.addEdge()`](#addedgefrom-t-to-t-this) +- [`.tryAddEdge()`](#tryaddedgefrom-t-to-t-boolean) +- [`.hasEdge()`](#hasedgefrom-t-to-t-boolean) +- [`.hasPath()`](#haspathfrom-t-to-t-boolean) +- [`.deleteEdge()`](#deleteedgefrom-t-to-t-this) +- [`.deleteOutgoingEdgesOf()`](#deleteoutgoingedgesofnode-t-this) +- [`.deleteIncomingEdgesOf()`](#deleteincomingedgesofnode-t-this) + +Sorting / Ordering: +- [`.getNodeOrder()`](#getnodeordernodes-t-t) +- [`.sortNodes()`](#sortnodes-t-t) + +Predecessors / Successors: +- [`.getImmediatePredecessorsOf()`](#getimmediatepredecessorsofnodes-t-sett) +- [`.getOrderedImmediatePredecessorsOf()`](#getorderedimmediatepredecessorsofnodes-t-iterablet) +- [`.getPredecessorsOf()`](#getpredecessorsofnodes-t-sett) +- [`.getOrderedPredecessorsOf()`](#getorderedpredecessorsofnodes-t-iterablet) +- [`.getImmediateSuccessorsOf()`](#getimmediatesuccessorsofnodes-t-sett) +- [`.getOrderedImmediateSuccessorsOf()`](#getorderedimmediatesuccessorsofnodes-t-iterablet) +- [`.getSuccessorsOf()`](#getsuccessorsofnodes-t-sett) +- [`.getOrderedSuccessorsOf()`](#getorderedsuccessorsofnodes-t-iterablet) + +Merging: +- [`.mergeNodes()`](#mergenodesa-t-b-t-this) +- [`.tryMergeNodes()`](#trymergenodesa-t-b-t-boolean) + + +#### `constructor(initialNodes?: Iterable)` + +Creates a new DAG with optional initial nodes. + +**Parameters:** +- `initialNodes`: An optional iterable of nodes to populate the graph with. + +**Returns:** a new instance of `DAG`. + + +#### `copy(): DAG` + +Creates a new, independent copy of this DAG. + +**Returns:** Clone of this `DAG`. + + +#### `order: T[]` + +Returns a list of all nodes in the graph in a topological order. + +**Note:** for every `U -> V` directed edge, `U` will appear before `V` in a topological order. + +**Returns:** An array of all graph nodes in a topological order. + + +#### `size: number` + +Returns the number of nodes in the graph. + +**Returns:** Number of nodes in the graph. + + +#### `[Symbol.iterator](): IterableIterator` + +Returns an iterator that yields all nodes in the graph in a topological order. + +**Alias:** `keys()` +**Returns:** An iterator over all graph nodes in the graph. + + +#### `keys(): IterableIterator` + +Returns an iterator that yields all nodes in the graph in a topological order. + +**Returns:** An iterator over all graph nodes in the graph. + + +#### `clear(): this` + +Removes all nodes (and their edges) from the graph. + +**Returns:** This `DAG`. + + +#### `add(node: T): this` + +Adds a new node to the graph. +If the node already exists, this is a no-op. + +**Parameters:** +- `node`: The node to add. + +**Returns:** This `DAG`. + + +#### `has(node: T): boolean` + +Checks if a specific node exists in the graph. + +**Parameters:** +- `node`: The node to check. + +**Returns:** `true` if the node exists, `false` otherwise. + + +#### `delete(node: T): this` + +Removes a specified node from the graph. +If such node doesn't exist, this is a no-op. + +**Note:** This also removes all edges from or to the specified node. + +**Parameters:** +- `node`: The node to remove. + +**Returns:** This `DAG`. + + +#### `addEdge(from: T, to: T): this` + +Tries to add a directed edge to the graph. + +If any of the nodes doesn't already exist, it will be added. + +If inserting the given edge would introduce a cycle no changes are made to the graph and `CycleError` is thrown. + +Adding an edge from a node to that same node (i.e. `from` and `to` are the same) is considered a cycle and such edge cannot be added. + +**Parameters:** +- `from`: The "source" node. +- `to`: The "target" node. + +**Returns:** This `DAG`. + + +#### `tryAddEdge(from: T, to: T): boolean` + +Tries to add a directed edge to the graph. + +If any of the nodes doesn't already exist, it will be added. + +If inserting the given edge would introduce a cycle no changes are made to the graph and `false` is returned. + +Adding an edge from a node to that same node (i.e. `from` and `to` are the same) is considered a cycle and such edge cannot be added. + +**Parameters:** +- `from`: The "source" node. +- `to`: The "target" node. + +**Returns:** `true` if the edge was added, `false` otherwise. + + +#### `hasEdge(from: T, to: T): boolean` + +Checks if a specific (directed) edge exists in the graph. + +**Parameters:** +- `from`: The "source" node. +- `to`: The "target" node. + +**Returns:** `true` if the edge exists, `false` otherwise. + + +#### `hasPath(from: T, to: T): boolean` + +Checks whether a directed path between two nodes exists in the graph. + +If A is directly connected to B, `hasPath(A, B)` is exactly the same as `hasEdge(A, B)`. +On the other hand, if only the edges `A -> B` and `A -> C` exists in the graph, a `hasPath(A, C)` returns `true`, while `hasEdge(A, C)` returns `false`. + +**Parameters:** +- `from`: The "source" node. +- `to`: The "target" node. + +**Returns:** `true` if a directed path exists, `false` otherwise. + + +#### `deleteEdge(from: T, to: T): this` + +Removes a specified edge from the graph. +If such edge doesn't exist, this is a no-op. + +**Note:** this removes a directed edge. If an edge `A -> B` exists, it will not be removed with a `removeEdge(B, A)` call. + +**Parameters:** +- `from`: The "source" node. +- `to`: The "target" node. + +**Returns:** This `DAG`. + + +#### `deleteOutgoingEdgesOf(node: T): this` + +Removes all outgoing edges from a given node. +If such node doesn't exist, this is a no-op. + +**Parameters:** +- `node`: The node to remove outgoing edges from. + +**Returns:** This `DAG`. + + +#### `deleteIncomingEdgesOf(node: T): this` + +Removes all incoming edges to a given node. +If such node doesn't exist, this is a no-op. + +**Parameters:** +- `node`: The node to remove incoming edges to. + +**Returns:** This `DAG`. + + +#### `getNodeOrder(...nodes: T[]): T[]` + +Returns the given nodes in a topological order. + +In a case that a node does not exist in the graph, it is pushed to the end of the array. + +**Parameters:** +- `nodes`: The nodes to sort. + +**Returns:** An array of the given nodes in a topological order. + + +#### `sort(nodes: T[]): T[]` + +Sorts the given array of nodes, in place by their topological order. + +In a case that a node does not exist in the graph, it is pushed to the end of the array. + +**Parameters:** +- `nodes`: The nodes to sort. + +**Returns:** The input array of nodes, sorted in a topological order. + + +#### `getImmediatePredecessorsOf(...nodes: T[]): Set` + +Returns (an unordered) set of all immediate predecessors of the given nodes. + +**Parameters:** +- `nodes`: The nodes to get immediate predecessors of. + +**Returns:** An unordered set of all immediate predecessors of the given nodes. + + +#### `getOrderedImmediatePredecessorsOf(...nodes: T[]): Iterable` + +Returns an iterable of all immediate predecessors of the given nodes which iterates over them in a topological order. + +**Parameters:** +- `nodes`: The nodes to get immediate predecessors of. + +**Returns:** A topologically ordered iterable of all immediate predecessors of the given nodes. + + +#### `getPredecessorsOf(...nodes: T[]): Set` + +Returns (an unordered) set of all predecessors of the given nodes. + +**Parameters:** +- `nodes`: The nodes to get predecessors of. + +**Returns:** An unordered set of all predecessors of the given nodes. + + +#### `getOrderedPredecessorsOf(...nodes: T[]): Iterable` + +Returns an iterable of all predecessors of the given nodes which iterates over them in a topological order. + +**Parameters:** +- `nodes`: The nodes to get predecessors of. + +**Returns:** A topologically ordered iterable of all predecessors of the given nodes. + + +#### `getImmediateSuccessorsOf(...nodes: T[]): Set` + +Returns (an unordered) set of all immediate successors of the given nodes. + +**Parameters:** +- `nodes`: The nodes to get immediate successors of. + +**Returns:** An unordered set of all immediate successors of the given nodes. + + +#### `getOrderedImmediateSuccessorsOf(...nodes: T[]): Iterable` + +Returns an iterable of all immediate successors of the given nodes which iterates over them in a topological order. + +**Parameters:** +- `nodes`: The nodes to get immediate successors of. + +**Returns:** A topologically ordered iterable of all immediate successors of the given nodes. + + +#### `getSuccessorsOf(...nodes: T[]): Set` + +Returns (an unordered) set of all successors of the given nodes. + +**Parameters:** +- `nodes`: The nodes to get successors of. + +**Returns:** An unordered set of all successors of the given nodes. + + +#### `getOrderedSuccessorsOf(...nodes: T[]): Iterable` + +Returns an iterable of all successors of the given nodes which iterates over them in a topological order. + +**Parameters:** +- `nodes`: The nodes to get successors of. + +**Returns:** A topologically ordered iterable of all successors of the given nodes. + + +#### `mergeNodes(a: T, b: T): this` + +Merges two nodes if such action would not introduce a cycle. + +"Merging" of `A` and `B` is performed by making: + - all immediate predecessors of `B` be immediate predecessors of `A`, and + - all immediate successors of `B` be immediate successors of `A`. + + After that remapping, node `B` gets removed from the graph. + + **Note:** This method is a no-op if either `A` or `B` is absent in the graph. + + If there is a path between `A` and `B` (in either direction), a `CycleError` gets thrown, and the graph is not changed. + +**Parameters:** +- `a`: The first node to merge. +- `b`: The second node to merge. + +**Returns:** This `DAG`. + + +#### `tryMergeNodes(a: T, b: T): boolean` + +Merges two nodes if such action would not introduce a cycle. + +"Merging" of `A` and `B` is performed by making: + - all immediate predecessors of `B` be immediate predecessors of `A`, and + - all immediate successors of `B` be immediate successors of `A`. + + After that remapping, node `B` gets removed from the graph. + + **Note:** This method is a no-op if either `A` or `B` is absent in the graph. + + If there is a path between `A` and `B` (in either direction), the merging would introduce a cycle so this function returns `false`, and the graph is not changed. + +**Parameters:** +- `a`: The first node to merge. +- `b`: The second node to merge. + +**Returns:** This `DAG`. + +## References + +The core algorithm for cycle detection & dynamic topological ordering is an implementation of the following paper: + +> _PEARCE_, David J.; _KELLY_, Paul HJ. +> A dynamic algorithm for topologically sorting directed acyclic graphs. +> +> -- Lecture notes in computer science, 2004, 3059: 383-398. [[PDF]](https://citeseerx.ist.psu.edu/document?doi=388da0bed2a1658a34de39b28921de48f353b2ed) + + +## Contributing + +Contributions are welcome! For feature requests and bug reports, please [submit an issue]( \ No newline at end of file diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 0000000..f48ce79 --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,85 @@ +import js from '@eslint/js'; +import tsESLint from 'typescript-eslint'; + +export default [ + { + files: ['**/*.ts'], + plugins: { + '@typescript-eslint': tsESLint.plugin, + }, + languageOptions: { + sourceType: 'module', + parser: tsESLint.parser, + parserOptions: { + project: true, + tsconfigRootDir: import.meta.dirname, + }, + }, + }, + js.configs.recommended, + { + // This is a compatibility ruleset that: + // - disables rules from eslint:recommended which are already handled by TypeScript. + // - enables rules that make sense due to TS's typechecking / transpilation + rules: { + 'constructor-super': 'off', // ts(2335) & ts(2377) + 'getter-return': 'off', // ts(2378) + 'no-const-assign': 'off', // ts(2588) + 'no-dupe-args': 'off', // ts(2300) + 'no-dupe-class-members': 'off', // ts(2393) & ts(2300) + 'no-dupe-keys': 'off', // ts(1117) + 'no-func-assign': 'off', // ts(2630) + 'no-import-assign': 'off', // ts(2632) & ts(2540) + 'no-new-native-nonconstructor': 'off', // ts(7009) + 'no-obj-calls': 'off', // ts(2349) + 'no-redeclare': 'off', // ts(2451) + 'no-setter-return': 'off', // ts(2408) + 'no-this-before-super': 'off', // ts(2376) & ts(17009) + 'no-undef': 'off', // ts(2304) & ts(2552) + 'no-unreachable': 'off', // ts(7027) + 'no-unsafe-negation': 'off', // ts(2365) & ts(2322) & ts(2358) + 'no-var': 'error', // ts transpiles let/const to var, so no need for vars any more + 'prefer-const': 'error', // ts provides better types with const + 'prefer-rest-params': 'error', // ts provides better types with rest args over arguments + 'prefer-spread': 'error', // ts transpiles spread to apply, so no need for manual apply + }, + }, + { + // typescript-eslint/recommended-type-checked-only + rules: { + '@typescript-eslint/await-thenable': 'error', + '@typescript-eslint/no-array-delete': 'error', + '@typescript-eslint/no-base-to-string': 'error', + '@typescript-eslint/no-duplicate-type-constituents': 'error', + '@typescript-eslint/no-floating-promises': 'error', + '@typescript-eslint/no-for-in-array': 'error', + 'no-implied-eval': 'off', + '@typescript-eslint/no-implied-eval': 'error', + '@typescript-eslint/no-misused-promises': 'error', + '@typescript-eslint/no-redundant-type-constituents': 'error', + '@typescript-eslint/no-unnecessary-type-assertion': 'error', + '@typescript-eslint/no-unsafe-argument': 'error', + '@typescript-eslint/no-unsafe-assignment': 'error', + '@typescript-eslint/no-unsafe-call': 'error', + '@typescript-eslint/no-unsafe-enum-comparison': 'error', + '@typescript-eslint/no-unsafe-member-access': 'error', + '@typescript-eslint/no-unsafe-return': 'error', + '@typescript-eslint/no-unsafe-unary-minus': 'error', + 'no-throw-literal': 'off', + '@typescript-eslint/only-throw-error': 'error', + 'prefer-promise-reject-errors': 'off', + '@typescript-eslint/prefer-promise-reject-errors': 'error', + 'require-await': 'off', + '@typescript-eslint/require-await': 'error', + '@typescript-eslint/restrict-plus-operands': 'error', + '@typescript-eslint/restrict-template-expressions': 'error', + '@typescript-eslint/unbound-method': 'error', + }, + }, + { + files: ['**/*.test.ts'], + rules: { + '@typescript-eslint/no-floating-promises': 'off', + }, + } +]; diff --git a/fixtures/large-graph.json b/fixtures/large-graph.json new file mode 100644 index 0000000..27ac47d --- /dev/null +++ b/fixtures/large-graph.json @@ -0,0 +1,2311 @@ +{ + "nodes": [ + "A0", + "A1", + "A2", + "A3", + "A4", + "A5", + "A6", + "A7", + "A8", + "A9", + "B0", + "B1", + "B2", + "B3", + "B4", + "B5", + "B6", + "B7", + "B8", + "B9", + "C0", + "C1", + "C2", + "C3", + "C4", + "C5", + "C6", + "C7", + "C8", + "C9", + "D0", + "D1", + "D2", + "D3", + "D4", + "D5", + "D6", + "D7", + "D8", + "D9", + "E0", + "E1", + "E2", + "E3", + "E4", + "E5", + "E6", + "E7", + "E8", + "E9", + "F0", + "F1", + "F2", + "F3", + "F4", + "F5", + "F6", + "F7", + "F8", + "F9", + "G0", + "G1", + "G2", + "G3", + "G4", + "G5", + "G6", + "G7", + "G8", + "G9", + "H0", + "H1", + "H2", + "H3", + "H4", + "H5", + "H6", + "H7", + "H8", + "H9", + "I0", + "I1", + "I2", + "I3", + "I4", + "I5", + "I6", + "I7", + "I8", + "I9", + "J0", + "J1", + "J2", + "J3", + "J4", + "J5", + "J6", + "J7", + "J8", + "J9" + ], + "edges": [ + ["A0", "B4"], + ["A0", "B5"], + ["A0", "B6"], + ["A0", "B7"], + ["A0", "C2"], + ["A0", "C5"], + ["A0", "C6"], + ["A1", "B4"], + ["A1", "B6"], + ["A1", "B7"], + ["A1", "B8"], + ["A1", "C1"], + ["A1", "C2"], + ["A1", "C3"], + ["A2", "B6"], + ["A2", "B7"], + ["A2", "B8"], + ["A2", "B9"], + ["A2", "C0"], + ["A2", "C3"], + ["A2", "C4"], + ["A3", "B4"], + ["A3", "B7"], + ["A3", "B8"], + ["A3", "B9"], + ["A3", "C2"], + ["A3", "C3"], + ["A4", "B4"], + ["A4", "B6"], + ["A4", "B7"], + ["A4", "B9"], + ["A4", "C0"], + ["A4", "C1"], + ["A4", "C3"], + ["A4", "C4"], + ["A5", "B5"], + ["A5", "B7"], + ["A5", "B9"], + ["A5", "C0"], + ["A5", "C2"], + ["A5", "C3"], + ["A5", "C5"], + ["A5", "C6"], + ["A6", "B5"], + ["A6", "B7"], + ["A6", "C1"], + ["A6", "C5"], + ["A6", "C6"], + ["A7", "B4"], + ["A7", "B5"], + ["A7", "B8"], + ["A7", "C0"], + ["A7", "C5"], + ["A8", "B4"], + ["A8", "B6"], + ["A8", "B8"], + ["A8", "C0"], + ["A9", "B5"], + ["A9", "B8"], + ["A9", "B9"], + ["A9", "C2"], + ["A9", "C4"], + ["A9", "C5"], + ["A9", "C6"], + ["B0", "B4"], + ["B0", "B5"], + ["B0", "B6"], + ["B0", "B8"], + ["B0", "C0"], + ["B0", "C3"], + ["B0", "C4"], + ["B0", "C6"], + ["B1", "B7"], + ["B1", "B8"], + ["B1", "B9"], + ["B1", "C2"], + ["B2", "B4"], + ["B2", "B5"], + ["B2", "B7"], + ["B2", "B8"], + ["B2", "C1"], + ["B2", "C2"], + ["B2", "C3"], + ["B2", "C4"], + ["B3", "B8"], + ["B3", "B9"], + ["B3", "C0"], + ["B3", "C1"], + ["B3", "C2"], + ["B3", "C4"], + ["B3", "C5"], + ["B3", "C6"], + ["A0", "B6"], + ["A1", "B7"], + ["A2", "B6"], + ["A3", "B7"], + ["A4", "B6"], + ["A5", "B6"], + ["A8", "B6"], + ["B0", "B6"], + ["B1", "B7"], + ["B2", "B6"], + ["B3", "B6"], + ["B5", "B7"], + ["A0", "C0"], + ["A1", "C1"], + ["A2", "C0"], + ["A2", "C2"], + ["A3", "C1"], + ["A3", "C2"], + ["A4", "C1"], + ["A4", "C3"], + ["A5", "C1"], + ["A6", "C1"], + ["A6", "C3"], + ["A7", "C2"], + ["A8", "C0"], + ["A8", "C2"], + ["A8", "C3"], + ["A9", "C0"], + ["B0", "C0"], + ["B0", "C2"], + ["B0", "C3"], + ["B1", "C0"], + ["B1", "C1"], + ["B2", "C1"], + ["B3", "C1"], + ["B4", "C0"], + ["B6", "C0"], + ["B6", "C1"], + ["B6", "C3"], + ["B7", "C0"], + ["B8", "C0"], + ["B8", "C2"], + ["B8", "C3"], + ["B9", "C0"], + ["A0", "D6"], + ["A0", "E0"], + ["A0", "E4"], + ["A0", "E5"], + ["A0", "E6"], + ["A0", "E8"], + ["A0", "F1"], + ["A1", "D9"], + ["A1", "E0"], + ["A1", "E1"], + ["A1", "E2"], + ["A1", "E4"], + ["A1", "E8"], + ["A2", "D6"], + ["A2", "D8"], + ["A2", "E0"], + ["A2", "E2"], + ["A2", "E3"], + ["A2", "E4"], + ["A2", "F1"], + ["A3", "D7"], + ["A3", "D8"], + ["A3", "E1"], + ["A3", "E2"], + ["A3", "E6"], + ["A3", "E7"], + ["A3", "F0"], + ["A3", "F1"], + ["A4", "D7"], + ["A4", "D9"], + ["A4", "E2"], + ["A4", "E5"], + ["A4", "E6"], + ["A4", "F1"], + ["A5", "E0"], + ["A5", "E2"], + ["A5", "E5"], + ["A5", "E8"], + ["A5", "F1"], + ["A6", "D6"], + ["A6", "D8"], + ["A6", "D9"], + ["A6", "E0"], + ["A6", "E3"], + ["A6", "E6"], + ["A6", "E7"], + ["A6", "E9"], + ["A6", "F0"], + ["A6", "F1"], + ["A7", "D6"], + ["A7", "D8"], + ["A7", "D9"], + ["A7", "E0"], + ["A7", "E1"], + ["A7", "E2"], + ["A7", "E4"], + ["A7", "E6"], + ["A7", "E9"], + ["A7", "F0"], + ["A7", "F1"], + ["A8", "D6"], + ["A8", "D8"], + ["A8", "D9"], + ["A8", "E2"], + ["A8", "E4"], + ["A8", "E6"], + ["A8", "F0"], + ["A8", "F1"], + ["A9", "D7"], + ["A9", "E1"], + ["A9", "E3"], + ["A9", "E4"], + ["B0", "D6"], + ["B0", "D7"], + ["B0", "E2"], + ["B0", "E4"], + ["B0", "E7"], + ["B0", "E8"], + ["B0", "F0"], + ["B0", "F1"], + ["B1", "D6"], + ["B1", "D7"], + ["B1", "E0"], + ["B1", "E1"], + ["B1", "E3"], + ["B1", "E5"], + ["B1", "E6"], + ["B1", "F0"], + ["B1", "F1"], + ["B2", "D9"], + ["B2", "E1"], + ["B2", "E3"], + ["B2", "E5"], + ["B2", "E7"], + ["B2", "E9"], + ["B2", "F1"], + ["B3", "D6"], + ["B3", "D7"], + ["B3", "D8"], + ["B3", "E0"], + ["B3", "E1"], + ["B3", "E6"], + ["B3", "E8"], + ["B3", "E9"], + ["B3", "F0"], + ["B3", "F1"], + ["B4", "D6"], + ["B4", "D8"], + ["B4", "D9"], + ["B4", "E3"], + ["B4", "E4"], + ["B4", "E5"], + ["B5", "D6"], + ["B5", "D8"], + ["B5", "D9"], + ["B5", "E0"], + ["B5", "E2"], + ["B5", "E6"], + ["B5", "E8"], + ["B5", "E9"], + ["B5", "F0"], + ["B6", "D7"], + ["B6", "D9"], + ["B6", "E2"], + ["B6", "E3"], + ["B6", "E4"], + ["B6", "E5"], + ["B6", "E6"], + ["B6", "E8"], + ["B6", "E9"], + ["B6", "F1"], + ["B7", "D7"], + ["B7", "E3"], + ["B7", "E5"], + ["B7", "E6"], + ["B7", "E7"], + ["B7", "F0"], + ["B8", "D6"], + ["B8", "E1"], + ["B8", "E2"], + ["B8", "E3"], + ["B8", "E7"], + ["B8", "E9"], + ["B8", "F0"], + ["B8", "F1"], + ["B9", "D6"], + ["B9", "D7"], + ["B9", "D8"], + ["B9", "D9"], + ["B9", "E0"], + ["B9", "E2"], + ["B9", "E3"], + ["B9", "E4"], + ["B9", "E6"], + ["B9", "E7"], + ["B9", "E8"], + ["B9", "E9"], + ["C0", "D6"], + ["C0", "D8"], + ["C0", "D9"], + ["C0", "E0"], + ["C0", "E1"], + ["C0", "E4"], + ["C0", "E5"], + ["C0", "E6"], + ["C0", "E7"], + ["C0", "E8"], + ["C0", "E9"], + ["C0", "F1"], + ["C1", "D9"], + ["C1", "E0"], + ["C1", "E2"], + ["C1", "E7"], + ["C1", "F0"], + ["C1", "F1"], + ["C2", "D7"], + ["C2", "D8"], + ["C2", "E1"], + ["C2", "E3"], + ["C2", "E4"], + ["C2", "E5"], + ["C2", "E6"], + ["C2", "E9"], + ["C2", "F0"], + ["C3", "D6"], + ["C3", "D9"], + ["C3", "E4"], + ["C3", "E7"], + ["C3", "F1"], + ["C4", "D8"], + ["C4", "D9"], + ["C4", "E1"], + ["C4", "E3"], + ["C4", "E4"], + ["C4", "E5"], + ["C4", "E6"], + ["C5", "D6"], + ["C5", "D8"], + ["C5", "D9"], + ["C5", "E1"], + ["C5", "E6"], + ["C5", "F0"], + ["C6", "D6"], + ["C6", "D7"], + ["C6", "D8"], + ["C6", "E1"], + ["C6", "E4"], + ["C6", "E5"], + ["C6", "E8"], + ["C6", "E9"], + ["C6", "F0"], + ["C6", "F1"], + ["C7", "D6"], + ["C7", "D7"], + ["C7", "E0"], + ["C7", "E3"], + ["C7", "E6"], + ["C7", "E7"], + ["C8", "D6"], + ["C8", "D7"], + ["C8", "D8"], + ["C8", "E0"], + ["C8", "E1"], + ["C8", "E2"], + ["C8", "E6"], + ["C8", "E7"], + ["C8", "E8"], + ["C8", "F1"], + ["C9", "D9"], + ["C9", "E0"], + ["C9", "E2"], + ["C9", "E4"], + ["C9", "E6"], + ["C9", "E8"], + ["C9", "E9"], + ["D0", "D8"], + ["D0", "E0"], + ["D0", "E1"], + ["D0", "E4"], + ["D0", "E5"], + ["D0", "E6"], + ["D0", "E7"], + ["D0", "E9"], + ["D1", "D8"], + ["D1", "E0"], + ["D1", "E1"], + ["D1", "E3"], + ["D1", "E5"], + ["D1", "E6"], + ["D1", "F0"], + ["D2", "D7"], + ["D2", "D8"], + ["D2", "E2"], + ["D2", "E7"], + ["D2", "E8"], + ["D2", "F0"], + ["D3", "E3"], + ["D3", "E4"], + ["D3", "E5"], + ["D3", "E7"], + ["D3", "F0"], + ["D3", "F1"], + ["D4", "D6"], + ["D4", "E0"], + ["D4", "E1"], + ["D4", "E2"], + ["D4", "E4"], + ["D4", "E8"], + ["D4", "F0"], + ["D4", "F1"], + ["D5", "D8"], + ["D5", "E1"], + ["D5", "E2"], + ["D5", "E3"], + ["D5", "E4"], + ["D5", "E6"], + ["D5", "E7"], + ["D5", "E8"], + ["D5", "F1"], + ["A0", "F7"], + ["A0", "G1"], + ["A0", "G5"], + ["A0", "G6"], + ["A0", "G7"], + ["A0", "H1"], + ["A0", "H3"], + ["A1", "F9"], + ["A1", "G0"], + ["A1", "G1"], + ["A1", "G3"], + ["A1", "G4"], + ["A1", "G5"], + ["A1", "G7"], + ["A1", "G8"], + ["A1", "G9"], + ["A1", "H0"], + ["A1", "H1"], + ["A1", "H2"], + ["A1", "H3"], + ["A2", "F7"], + ["A2", "G1"], + ["A2", "G2"], + ["A2", "G3"], + ["A2", "G4"], + ["A2", "G5"], + ["A2", "G6"], + ["A2", "G7"], + ["A2", "G9"], + ["A2", "H0"], + ["A2", "H2"], + ["A2", "H3"], + ["A3", "F5"], + ["A3", "F6"], + ["A3", "F7"], + ["A3", "F8"], + ["A3", "G2"], + ["A3", "G3"], + ["A3", "G4"], + ["A3", "G5"], + ["A3", "G7"], + ["A3", "G8"], + ["A3", "G9"], + ["A3", "H0"], + ["A4", "F8"], + ["A4", "G0"], + ["A4", "G2"], + ["A4", "G3"], + ["A4", "G4"], + ["A4", "G7"], + ["A4", "G8"], + ["A4", "H3"], + ["A5", "F5"], + ["A5", "F6"], + ["A5", "F7"], + ["A5", "G0"], + ["A5", "G1"], + ["A5", "G4"], + ["A5", "G5"], + ["A5", "G6"], + ["A5", "G8"], + ["A5", "H0"], + ["A5", "H1"], + ["A6", "F5"], + ["A6", "F8"], + ["A6", "F9"], + ["A6", "G0"], + ["A6", "G1"], + ["A6", "G2"], + ["A6", "G4"], + ["A6", "G5"], + ["A6", "H1"], + ["A6", "H2"], + ["A7", "F5"], + ["A7", "F9"], + ["A7", "G1"], + ["A7", "G3"], + ["A7", "G4"], + ["A7", "G6"], + ["A7", "G8"], + ["A7", "H0"], + ["A7", "H2"], + ["A7", "H3"], + ["A8", "F6"], + ["A8", "F7"], + ["A8", "F8"], + ["A8", "G0"], + ["A8", "G1"], + ["A8", "G4"], + ["A8", "G5"], + ["A8", "G6"], + ["A8", "G7"], + ["A8", "G9"], + ["A8", "H0"], + ["A8", "H2"], + ["A8", "H3"], + ["A9", "F5"], + ["A9", "F8"], + ["A9", "F9"], + ["A9", "G0"], + ["A9", "G1"], + ["A9", "G7"], + ["A9", "G8"], + ["A9", "H1"], + ["A9", "H3"], + ["B0", "F5"], + ["B0", "F7"], + ["B0", "F9"], + ["B0", "G0"], + ["B0", "G1"], + ["B0", "G4"], + ["B0", "G7"], + ["B0", "G8"], + ["B0", "G9"], + ["B0", "H0"], + ["B0", "H1"], + ["B0", "H2"], + ["B0", "H3"], + ["B1", "F5"], + ["B1", "F8"], + ["B1", "G0"], + ["B1", "G2"], + ["B1", "G3"], + ["B1", "G4"], + ["B1", "G5"], + ["B1", "H0"], + ["B2", "F6"], + ["B2", "F7"], + ["B2", "G0"], + ["B2", "G1"], + ["B2", "G3"], + ["B2", "G6"], + ["B2", "G7"], + ["B2", "H3"], + ["B3", "F5"], + ["B3", "F7"], + ["B3", "F8"], + ["B3", "G3"], + ["B3", "G4"], + ["B3", "G5"], + ["B3", "G6"], + ["B3", "G7"], + ["B3", "G9"], + ["B3", "H0"], + ["B3", "H1"], + ["B4", "F5"], + ["B4", "F8"], + ["B4", "G0"], + ["B4", "G1"], + ["B4", "G3"], + ["B4", "G6"], + ["B4", "H0"], + ["B4", "H2"], + ["B5", "F5"], + ["B5", "F6"], + ["B5", "F7"], + ["B5", "G0"], + ["B5", "G1"], + ["B5", "G2"], + ["B5", "G3"], + ["B5", "G4"], + ["B5", "G5"], + ["B5", "G7"], + ["B5", "H0"], + ["B5", "H2"], + ["B6", "F8"], + ["B6", "F9"], + ["B6", "G3"], + ["B6", "G5"], + ["B6", "G6"], + ["B6", "G7"], + ["B6", "G8"], + ["B6", "H0"], + ["B6", "H3"], + ["B7", "F5"], + ["B7", "F6"], + ["B7", "G1"], + ["B7", "G2"], + ["B7", "G4"], + ["B7", "G6"], + ["B7", "G9"], + ["B7", "H3"], + ["B8", "F6"], + ["B8", "H1"], + ["B8", "H3"], + ["B9", "F6"], + ["B9", "G0"], + ["B9", "G5"], + ["B9", "G6"], + ["B9", "G7"], + ["B9", "G8"], + ["B9", "H0"], + ["B9", "H1"], + ["B9", "H3"], + ["C0", "F9"], + ["C0", "G1"], + ["C0", "G3"], + ["C0", "G4"], + ["C0", "G5"], + ["C0", "H1"], + ["C0", "H3"], + ["C1", "F5"], + ["C1", "F8"], + ["C1", "F9"], + ["C1", "G2"], + ["C1", "G6"], + ["C1", "G7"], + ["C1", "G8"], + ["C1", "G9"], + ["C1", "H1"], + ["C1", "H2"], + ["C2", "F5"], + ["C2", "F6"], + ["C2", "F8"], + ["C2", "F9"], + ["C2", "G2"], + ["C2", "G4"], + ["C2", "G5"], + ["C2", "G6"], + ["C2", "G7"], + ["C2", "G8"], + ["C2", "G9"], + ["C2", "H1"], + ["C3", "F5"], + ["C3", "F6"], + ["C3", "F8"], + ["C3", "F9"], + ["C3", "G0"], + ["C3", "G4"], + ["C3", "G7"], + ["C3", "H0"], + ["C3", "H1"], + ["C4", "F8"], + ["C4", "G0"], + ["C4", "G1"], + ["C4", "G3"], + ["C4", "G4"], + ["C4", "G6"], + ["C4", "G7"], + ["C4", "H0"], + ["C5", "F5"], + ["C5", "F6"], + ["C5", "F8"], + ["C5", "F9"], + ["C5", "G0"], + ["C5", "G3"], + ["C5", "G5"], + ["C5", "G6"], + ["C5", "G9"], + ["C5", "H0"], + ["C5", "H3"], + ["C6", "F5"], + ["C6", "F6"], + ["C6", "F9"], + ["C6", "G0"], + ["C6", "G2"], + ["C6", "G7"], + ["C6", "G8"], + ["C6", "H0"], + ["C7", "F5"], + ["C7", "F6"], + ["C7", "F9"], + ["C7", "G1"], + ["C7", "G2"], + ["C7", "G3"], + ["C7", "G6"], + ["C7", "G8"], + ["C7", "G9"], + ["C7", "H1"], + ["C7", "H3"], + ["C8", "F5"], + ["C8", "F6"], + ["C8", "G0"], + ["C8", "G2"], + ["C8", "G3"], + ["C8", "G5"], + ["C8", "H0"], + ["C9", "F5"], + ["C9", "G1"], + ["C9", "G2"], + ["C9", "G3"], + ["C9", "G4"], + ["C9", "H2"], + ["C9", "H3"], + ["D0", "F5"], + ["D0", "F6"], + ["D0", "G0"], + ["D0", "G1"], + ["D0", "G2"], + ["D0", "G3"], + ["D0", "G4"], + ["D0", "G6"], + ["D0", "G9"], + ["D0", "H1"], + ["D1", "F5"], + ["D1", "F8"], + ["D1", "G0"], + ["D1", "G1"], + ["D1", "G3"], + ["D1", "G5"], + ["D1", "G7"], + ["D1", "G9"], + ["D1", "H0"], + ["D1", "H2"], + ["D1", "H3"], + ["D2", "F5"], + ["D2", "F6"], + ["D2", "F7"], + ["D2", "F9"], + ["D2", "G3"], + ["D2", "G4"], + ["D2", "G7"], + ["D2", "H0"], + ["D2", "H2"], + ["D3", "G2"], + ["D3", "G4"], + ["D3", "G5"], + ["D3", "G6"], + ["D3", "G7"], + ["D3", "G8"], + ["D3", "H0"], + ["D3", "H1"], + ["D3", "H3"], + ["D4", "F9"], + ["D4", "G0"], + ["D4", "G1"], + ["D4", "G2"], + ["D4", "G4"], + ["D4", "G6"], + ["D4", "G8"], + ["D4", "G9"], + ["D4", "H1"], + ["D4", "H2"], + ["D4", "H3"], + ["D5", "F7"], + ["D5", "F9"], + ["D5", "G2"], + ["D5", "G4"], + ["D5", "G5"], + ["D5", "G6"], + ["D5", "G7"], + ["D5", "G9"], + ["D5", "H2"], + ["D5", "H3"], + ["D6", "F6"], + ["D6", "F7"], + ["D6", "F8"], + ["D6", "F9"], + ["D6", "G0"], + ["D6", "G5"], + ["D6", "G6"], + ["D6", "H0"], + ["D6", "H1"], + ["D6", "H2"], + ["D7", "F8"], + ["D7", "G0"], + ["D7", "G1"], + ["D7", "G2"], + ["D7", "G5"], + ["D7", "G6"], + ["D7", "G7"], + ["D7", "G8"], + ["D7", "H0"], + ["D7", "H3"], + ["D8", "F5"], + ["D8", "F6"], + ["D8", "F7"], + ["D8", "G3"], + ["D8", "H2"], + ["D8", "H3"], + ["D9", "F5"], + ["D9", "F7"], + ["D9", "F9"], + ["D9", "G0"], + ["D9", "G1"], + ["D9", "G2"], + ["D9", "G3"], + ["D9", "G4"], + ["D9", "G8"], + ["D9", "H0"], + ["D9", "H2"], + ["E0", "F6"], + ["E0", "F7"], + ["E0", "F8"], + ["E0", "F9"], + ["E0", "G0"], + ["E0", "G1"], + ["E0", "G4"], + ["E0", "G5"], + ["E0", "G8"], + ["E0", "G9"], + ["E0", "H3"], + ["E1", "F5"], + ["E1", "F7"], + ["E1", "F8"], + ["E1", "F9"], + ["E1", "G0"], + ["E1", "G3"], + ["E1", "G4"], + ["E1", "G9"], + ["E1", "H0"], + ["E1", "H1"], + ["E1", "H2"], + ["E1", "H3"], + ["E2", "F5"], + ["E2", "F6"], + ["E2", "F8"], + ["E2", "G1"], + ["E2", "G3"], + ["E2", "G4"], + ["E2", "G6"], + ["E2", "G7"], + ["E2", "G8"], + ["E2", "H2"], + ["E2", "H3"], + ["E3", "F5"], + ["E3", "F7"], + ["E3", "F8"], + ["E3", "F9"], + ["E3", "G1"], + ["E3", "G2"], + ["E3", "G3"], + ["E3", "G4"], + ["E3", "G6"], + ["E3", "G7"], + ["E3", "G9"], + ["E3", "H0"], + ["E3", "H3"], + ["E4", "F7"], + ["E4", "F9"], + ["E4", "G0"], + ["E4", "G5"], + ["E4", "G6"], + ["E4", "G8"], + ["E4", "H1"], + ["E4", "H2"], + ["E5", "F5"], + ["E5", "F6"], + ["E5", "F7"], + ["E5", "G0"], + ["E5", "G2"], + ["E5", "G3"], + ["E5", "G5"], + ["E5", "G6"], + ["E5", "G7"], + ["E5", "G8"], + ["E5", "H0"], + ["E5", "H1"], + ["E6", "F8"], + ["E6", "G0"], + ["E6", "G1"], + ["E6", "G2"], + ["E6", "G3"], + ["E6", "G6"], + ["E6", "G7"], + ["E6", "G8"], + ["E6", "G9"], + ["E6", "H0"], + ["E7", "F5"], + ["E7", "F8"], + ["E7", "F9"], + ["E7", "G1"], + ["E7", "G2"], + ["E7", "G4"], + ["E7", "G6"], + ["E7", "G8"], + ["E7", "H0"], + ["E7", "H3"], + ["E8", "F6"], + ["E8", "F9"], + ["E8", "G0"], + ["E8", "G1"], + ["E8", "G2"], + ["E8", "G4"], + ["E8", "G5"], + ["E8", "H1"], + ["E8", "H2"], + ["E9", "F5"], + ["E9", "F9"], + ["E9", "G1"], + ["E9", "G2"], + ["E9", "G3"], + ["E9", "G7"], + ["E9", "G9"], + ["E9", "H2"], + ["F0", "F5"], + ["F0", "F6"], + ["F0", "F9"], + ["F0", "G2"], + ["F0", "G4"], + ["F0", "G6"], + ["F0", "G9"], + ["F0", "H0"], + ["F0", "H1"], + ["F0", "H3"], + ["F1", "F7"], + ["F1", "F8"], + ["F1", "F9"], + ["F1", "G0"], + ["F1", "G2"], + ["F1", "G4"], + ["F1", "G7"], + ["F1", "G8"], + ["F1", "H1"], + ["F1", "H2"], + ["F1", "H3"], + ["F2", "F5"], + ["F2", "F7"], + ["F2", "G0"], + ["F2", "G2"], + ["F2", "G4"], + ["F2", "G5"], + ["F2", "G6"], + ["F2", "G7"], + ["F2", "H0"], + ["F3", "F6"], + ["F3", "F7"], + ["F3", "F8"], + ["F3", "G0"], + ["F3", "G1"], + ["F3", "G5"], + ["F3", "G7"], + ["F3", "G8"], + ["F3", "G9"], + ["F3", "H0"], + ["F3", "H1"], + ["F3", "H2"], + ["F3", "H3"], + ["F4", "F8"], + ["F4", "F9"], + ["F4", "G1"], + ["F4", "G3"], + ["F4", "G5"], + ["F4", "G6"], + ["F4", "G7"], + ["F4", "G8"], + ["F4", "G9"], + ["F4", "H2"], + ["F4", "H3"], + ["A0", "H0"], + ["A0", "H2"], + ["A0", "H5"], + ["A0", "H7"], + ["A1", "G7"], + ["A1", "G8"], + ["A1", "H1"], + ["A1", "H3"], + ["A1", "H6"], + ["A1", "H8"], + ["A2", "G7"], + ["A2", "H0"], + ["A2", "H1"], + ["A2", "H4"], + ["A2", "H6"], + ["A3", "G7"], + ["A3", "G9"], + ["A3", "H0"], + ["A3", "H1"], + ["A3", "H3"], + ["A3", "H4"], + ["A3", "H6"], + ["A3", "H8"], + ["A4", "G7"], + ["A4", "H1"], + ["A4", "H2"], + ["A4", "H4"], + ["A4", "H5"], + ["A4", "H8"], + ["A5", "H1"], + ["A5", "H2"], + ["A5", "H3"], + ["A6", "G7"], + ["A6", "H2"], + ["A6", "H4"], + ["A6", "H5"], + ["A6", "H8"], + ["A7", "G7"], + ["A7", "G8"], + ["A7", "H0"], + ["A7", "H2"], + ["A7", "H3"], + ["A7", "H5"], + ["A7", "H7"], + ["A7", "H8"], + ["A8", "G7"], + ["A8", "G9"], + ["A8", "H3"], + ["A8", "H4"], + ["A8", "H5"], + ["A8", "H8"], + ["A9", "G7"], + ["A9", "G8"], + ["A9", "G9"], + ["A9", "H3"], + ["A9", "H4"], + ["A9", "H7"], + ["A9", "H8"], + ["B0", "G8"], + ["B0", "H2"], + ["B0", "H3"], + ["B0", "H4"], + ["B1", "G7"], + ["B1", "H5"], + ["B1", "H7"], + ["B1", "H8"], + ["B2", "G7"], + ["B2", "G8"], + ["B2", "G9"], + ["B2", "H0"], + ["B2", "H1"], + ["B2", "H3"], + ["B2", "H4"], + ["B2", "H5"], + ["B2", "H7"], + ["B3", "G8"], + ["B3", "H0"], + ["B3", "H1"], + ["B3", "H7"], + ["B3", "H8"], + ["B4", "G8"], + ["B4", "G9"], + ["B4", "H0"], + ["B4", "H3"], + ["B4", "H4"], + ["B4", "H8"], + ["B5", "G8"], + ["B5", "G9"], + ["B5", "H0"], + ["B5", "H5"], + ["B5", "H6"], + ["B6", "H1"], + ["B6", "H2"], + ["B6", "H3"], + ["B6", "H6"], + ["B7", "H1"], + ["B7", "H2"], + ["B7", "H5"], + ["B7", "H6"], + ["B8", "G8"], + ["B8", "H1"], + ["B8", "H4"], + ["B8", "H5"], + ["B8", "H7"], + ["B8", "H8"], + ["B9", "G7"], + ["B9", "G8"], + ["B9", "G9"], + ["B9", "H0"], + ["B9", "H1"], + ["B9", "H3"], + ["B9", "H5"], + ["B9", "H6"], + ["C0", "G7"], + ["C0", "H0"], + ["C0", "H1"], + ["C0", "H3"], + ["C0", "H5"], + ["C0", "H7"], + ["C1", "G8"], + ["C1", "G9"], + ["C1", "H3"], + ["C1", "H4"], + ["C1", "H7"], + ["C2", "G8"], + ["C2", "G9"], + ["C2", "H3"], + ["C2", "H5"], + ["C2", "H7"], + ["C2", "H8"], + ["C3", "G7"], + ["C3", "G8"], + ["C3", "H0"], + ["C3", "H1"], + ["C3", "H4"], + ["C3", "H5"], + ["C3", "H6"], + ["C3", "H8"], + ["C4", "G7"], + ["C4", "G8"], + ["C4", "H1"], + ["C4", "H2"], + ["C4", "H6"], + ["C5", "G7"], + ["C5", "H1"], + ["C5", "H4"], + ["C5", "H6"], + ["C5", "H8"], + ["C6", "H0"], + ["C6", "H2"], + ["C6", "H3"], + ["C6", "H6"], + ["C7", "H0"], + ["C7", "H1"], + ["C7", "H2"], + ["C7", "H3"], + ["C7", "H5"], + ["C7", "H6"], + ["C7", "H7"], + ["C8", "G7"], + ["C8", "G8"], + ["C8", "G9"], + ["C8", "H0"], + ["C8", "H1"], + ["C8", "H2"], + ["C8", "H8"], + ["C9", "G8"], + ["C9", "G9"], + ["C9", "H0"], + ["C9", "H2"], + ["C9", "H8"], + ["D0", "G9"], + ["D0", "H0"], + ["D0", "H4"], + ["D0", "H6"], + ["D0", "H7"], + ["D0", "H8"], + ["D1", "H2"], + ["D1", "H3"], + ["D1", "H4"], + ["D1", "H5"], + ["D1", "H7"], + ["D1", "H8"], + ["D2", "G8"], + ["D2", "H0"], + ["D2", "H2"], + ["D2", "H3"], + ["D2", "H5"], + ["D2", "H6"], + ["D2", "H7"], + ["D3", "G7"], + ["D3", "G9"], + ["D3", "H0"], + ["D3", "H2"], + ["D3", "H3"], + ["D3", "H4"], + ["D3", "H5"], + ["D3", "H6"], + ["D4", "G7"], + ["D4", "G8"], + ["D4", "G9"], + ["D4", "H0"], + ["D4", "H1"], + ["D4", "H4"], + ["D4", "H6"], + ["D5", "G7"], + ["D5", "G8"], + ["D5", "H3"], + ["D5", "H4"], + ["D5", "H7"], + ["D6", "H0"], + ["D6", "H5"], + ["D6", "H6"], + ["D6", "H7"], + ["D7", "G7"], + ["D7", "G8"], + ["D7", "H0"], + ["D7", "H3"], + ["D7", "H5"], + ["D7", "H8"], + ["D8", "G7"], + ["D8", "G9"], + ["D8", "H0"], + ["D8", "H1"], + ["D8", "H2"], + ["D8", "H3"], + ["D8", "H4"], + ["D8", "H5"], + ["D8", "H7"], + ["D9", "G9"], + ["D9", "H0"], + ["D9", "H1"], + ["D9", "H2"], + ["D9", "H7"], + ["E0", "G8"], + ["E0", "G9"], + ["E0", "H2"], + ["E0", "H5"], + ["E1", "G8"], + ["E1", "H2"], + ["E1", "H5"], + ["E1", "H6"], + ["E1", "H7"], + ["E1", "H8"], + ["E2", "G7"], + ["E2", "H2"], + ["E2", "H3"], + ["E2", "H4"], + ["E2", "H6"], + ["E3", "G7"], + ["E3", "H0"], + ["E3", "H1"], + ["E3", "H4"], + ["E3", "H8"], + ["E4", "G7"], + ["E4", "G9"], + ["E4", "H0"], + ["E4", "H2"], + ["E4", "H3"], + ["E4", "H7"], + ["E4", "H8"], + ["E5", "G8"], + ["E5", "G9"], + ["E5", "H0"], + ["E5", "H1"], + ["E5", "H6"], + ["E6", "G8"], + ["E6", "H3"], + ["E6", "H4"], + ["E6", "H5"], + ["E6", "H6"], + ["E6", "H7"], + ["E6", "H8"], + ["E7", "G7"], + ["E7", "G9"], + ["E7", "H1"], + ["E7", "H2"], + ["E7", "H3"], + ["E7", "H5"], + ["E7", "H8"], + ["E8", "G7"], + ["E8", "H0"], + ["E8", "H2"], + ["E8", "H3"], + ["E8", "H5"], + ["E8", "H6"], + ["E8", "H7"], + ["E9", "G8"], + ["E9", "G9"], + ["E9", "H0"], + ["E9", "H1"], + ["E9", "H4"], + ["E9", "H6"], + ["E9", "H7"], + ["F0", "G7"], + ["F0", "G9"], + ["F0", "H0"], + ["F0", "H1"], + ["F0", "H2"], + ["F0", "H4"], + ["F0", "H5"], + ["F0", "H6"], + ["F0", "H8"], + ["F1", "G7"], + ["F1", "H0"], + ["F1", "H1"], + ["F1", "H2"], + ["F1", "H4"], + ["F1", "H5"], + ["F1", "H6"], + ["F1", "H7"], + ["F1", "H8"], + ["F2", "G8"], + ["F2", "H1"], + ["F2", "H6"], + ["F2", "H7"], + ["F2", "H8"], + ["F3", "G7"], + ["F3", "G8"], + ["F3", "G9"], + ["F3", "H5"], + ["F3", "H7"], + ["F4", "G7"], + ["F4", "G8"], + ["F4", "H0"], + ["F4", "H1"], + ["F4", "H7"], + ["F5", "G8"], + ["F5", "G9"], + ["F5", "H2"], + ["F5", "H3"], + ["F5", "H4"], + ["F5", "H8"], + ["F6", "G7"], + ["F6", "G8"], + ["F6", "H0"], + ["F6", "H1"], + ["F6", "H3"], + ["F6", "H4"], + ["F6", "H5"], + ["F6", "H6"], + ["F6", "H7"], + ["F6", "H8"], + ["F7", "G7"], + ["F7", "H1"], + ["F7", "H3"], + ["F8", "G8"], + ["F8", "G9"], + ["F8", "H0"], + ["F8", "H1"], + ["F8", "H2"], + ["F8", "H3"], + ["F8", "H5"], + ["F9", "G8"], + ["F9", "H1"], + ["F9", "H4"], + ["F9", "H7"], + ["F9", "H8"], + ["G0", "G7"], + ["G0", "G8"], + ["G0", "H1"], + ["G0", "H2"], + ["G0", "H3"], + ["G0", "H6"], + ["G0", "H8"], + ["G1", "G9"], + ["G1", "H2"], + ["G1", "H3"], + ["G1", "H4"], + ["G1", "H5"], + ["G1", "H6"], + ["G1", "H8"], + ["G2", "G7"], + ["G2", "G8"], + ["G2", "G9"], + ["G2", "H1"], + ["G2", "H5"], + ["G2", "H7"], + ["G3", "G7"], + ["G3", "G8"], + ["G3", "H0"], + ["G3", "H2"], + ["G3", "H3"], + ["G3", "H4"], + ["G3", "H5"], + ["G3", "H6"], + ["G3", "H7"], + ["G3", "H8"], + ["G4", "G7"], + ["G4", "G8"], + ["G4", "H0"], + ["G4", "H5"], + ["G4", "H6"], + ["G5", "G9"], + ["G5", "H0"], + ["G5", "H5"], + ["G5", "H7"], + ["G6", "G7"], + ["G6", "G8"], + ["G6", "G9"], + ["G6", "H0"], + ["G6", "H3"], + ["G6", "H4"], + ["G6", "H6"], + ["G6", "H7"], + ["A0", "H8"], + ["A0", "I1"], + ["A0", "I2"], + ["A0", "I6"], + ["A0", "I7"], + ["A1", "I1"], + ["A1", "I3"], + ["A1", "I4"], + ["A1", "I5"], + ["A1", "I6"], + ["A1", "I7"], + ["A2", "H8"], + ["A2", "I0"], + ["A2", "I2"], + ["A2", "I7"], + ["A2", "I8"], + ["A3", "H8"], + ["A3", "I1"], + ["A3", "I5"], + ["A3", "I6"], + ["A3", "I7"], + ["A3", "I8"], + ["A4", "I0"], + ["A4", "I1"], + ["A4", "I4"], + ["A4", "I6"], + ["A5", "H9"], + ["A5", "I0"], + ["A5", "I1"], + ["A5", "I2"], + ["A5", "I3"], + ["A5", "I4"], + ["A5", "I8"], + ["A6", "H9"], + ["A6", "I1"], + ["A6", "I2"], + ["A6", "I3"], + ["A7", "H8"], + ["A7", "H9"], + ["A7", "I0"], + ["A7", "I1"], + ["A7", "I2"], + ["A7", "I3"], + ["A7", "I4"], + ["A7", "I6"], + ["A8", "H8"], + ["A8", "H9"], + ["A8", "I1"], + ["A8", "I3"], + ["A8", "I5"], + ["A8", "I8"], + ["A9", "H8"], + ["A9", "H9"], + ["A9", "I1"], + ["A9", "I3"], + ["A9", "I5"], + ["A9", "I6"], + ["A9", "I8"], + ["B0", "H9"], + ["B0", "I1"], + ["B0", "I5"], + ["B0", "I8"], + ["B1", "I1"], + ["B1", "I4"], + ["B1", "I7"], + ["B2", "H9"], + ["B2", "I0"], + ["B2", "I1"], + ["B2", "I2"], + ["B2", "I3"], + ["B2", "I4"], + ["B2", "I5"], + ["B2", "I6"], + ["B2", "I7"], + ["B2", "I8"], + ["B3", "H9"], + ["B3", "I0"], + ["B3", "I2"], + ["B3", "I7"], + ["B4", "H8"], + ["B4", "I2"], + ["B4", "I6"], + ["B5", "H9"], + ["B5", "I4"], + ["B5", "I7"], + ["B5", "I8"], + ["B6", "I6"], + ["B6", "I8"], + ["B7", "H9"], + ["B7", "I3"], + ["B7", "I4"], + ["B7", "I6"], + ["B7", "I8"], + ["B8", "I0"], + ["B8", "I3"], + ["B8", "I6"], + ["B9", "I0"], + ["B9", "I2"], + ["B9", "I3"], + ["B9", "I5"], + ["B9", "I6"], + ["B9", "I8"], + ["C0", "H8"], + ["C0", "H9"], + ["C0", "I0"], + ["C0", "I1"], + ["C0", "I2"], + ["C0", "I3"], + ["C0", "I4"], + ["C0", "I5"], + ["C0", "I6"], + ["C0", "I7"], + ["C0", "I8"], + ["C1", "H8"], + ["C1", "I7"], + ["C2", "I0"], + ["C2", "I4"], + ["C2", "I5"], + ["C2", "I6"], + ["C3", "H8"], + ["C3", "I2"], + ["C3", "I4"], + ["C3", "I5"], + ["C3", "I6"], + ["C3", "I8"], + ["C4", "H8"], + ["C4", "I1"], + ["C4", "I2"], + ["C4", "I5"], + ["C5", "I1"], + ["C5", "I4"], + ["C5", "I6"], + ["C6", "H8"], + ["C6", "H9"], + ["C6", "I2"], + ["C6", "I4"], + ["C6", "I5"], + ["C6", "I8"], + ["C7", "H8"], + ["C7", "H9"], + ["C7", "I1"], + ["C7", "I2"], + ["C7", "I5"], + ["C7", "I7"], + ["C8", "H9"], + ["C8", "I0"], + ["C8", "I2"], + ["C8", "I4"], + ["C8", "I5"], + ["C8", "I6"], + ["C8", "I7"], + ["C8", "I8"], + ["C9", "H8"], + ["C9", "H9"], + ["C9", "I1"], + ["C9", "I3"], + ["C9", "I4"], + ["C9", "I6"], + ["C9", "I7"], + ["D0", "H8"], + ["D0", "H9"], + ["D0", "I1"], + ["D0", "I2"], + ["D0", "I4"], + ["D0", "I7"], + ["D0", "I8"], + ["D1", "H8"], + ["D1", "I0"], + ["D1", "I1"], + ["D1", "I2"], + ["D1", "I4"], + ["D1", "I6"], + ["D1", "I7"], + ["D1", "I8"], + ["D2", "H8"], + ["D2", "H9"], + ["D2", "I1"], + ["D2", "I2"], + ["D2", "I3"], + ["D2", "I4"], + ["D2", "I5"], + ["D2", "I6"], + ["D2", "I7"], + ["D2", "I8"], + ["D3", "H9"], + ["D3", "I0"], + ["D3", "I3"], + ["D3", "I4"], + ["D3", "I6"], + ["D3", "I7"], + ["D4", "I0"], + ["D4", "I1"], + ["D4", "I2"], + ["D4", "I3"], + ["D4", "I4"], + ["D4", "I5"], + ["D4", "I7"], + ["D5", "H8"], + ["D5", "I0"], + ["D5", "I2"], + ["D5", "I3"], + ["D5", "I5"], + ["D5", "I6"], + ["D6", "H8"], + ["D6", "H9"], + ["D6", "I1"], + ["D6", "I5"], + ["D6", "I6"], + ["D6", "I7"], + ["D6", "I8"], + ["D7", "H8"], + ["D7", "I2"], + ["D7", "I3"], + ["D7", "I4"], + ["D7", "I5"], + ["D7", "I7"], + ["D8", "H8"], + ["D8", "I3"], + ["D8", "I5"], + ["D8", "I7"], + ["D9", "H8"], + ["D9", "H9"], + ["D9", "I1"], + ["D9", "I2"], + ["D9", "I5"], + ["D9", "I6"], + ["D9", "I8"], + ["E1", "I0"], + ["E1", "I1"], + ["E1", "I2"], + ["E1", "I5"], + ["E1", "I7"], + ["E1", "I8"], + ["E2", "H9"], + ["E2", "I2"], + ["E2", "I3"], + ["E2", "I4"], + ["E2", "I5"], + ["E2", "I6"], + ["E2", "I8"], + ["E3", "H9"], + ["E3", "I1"], + ["E3", "I2"], + ["E3", "I4"], + ["E3", "I8"], + ["E4", "H8"], + ["E4", "H9"], + ["E4", "I0"], + ["E4", "I2"], + ["E4", "I3"], + ["E4", "I5"], + ["E4", "I6"], + ["E4", "I7"], + ["E4", "I8"], + ["E5", "H8"], + ["E5", "H9"], + ["E5", "I1"], + ["E5", "I2"], + ["E5", "I8"], + ["E6", "H9"], + ["E6", "I0"], + ["E6", "I1"], + ["E6", "I2"], + ["E6", "I3"], + ["E6", "I5"], + ["E6", "I7"], + ["E6", "I8"], + ["E7", "H8"], + ["E7", "I0"], + ["E7", "I3"], + ["E7", "I7"], + ["E7", "I8"], + ["E8", "I0"], + ["E8", "I3"], + ["E8", "I5"], + ["E8", "I7"], + ["E9", "H8"], + ["E9", "H9"], + ["E9", "I0"], + ["E9", "I8"], + ["F0", "I1"], + ["F0", "I2"], + ["F0", "I4"], + ["F0", "I5"], + ["F0", "I7"], + ["F1", "H9"], + ["F1", "I0"], + ["F1", "I1"], + ["F1", "I4"], + ["F1", "I5"], + ["F1", "I6"], + ["F1", "I7"], + ["F2", "I0"], + ["F2", "I2"], + ["F2", "I3"], + ["F2", "I4"], + ["F3", "I0"], + ["F3", "I2"], + ["F3", "I3"], + ["F3", "I6"], + ["F3", "I8"], + ["F4", "I0"], + ["F4", "I1"], + ["F4", "I4"], + ["F4", "I5"], + ["F4", "I7"], + ["F5", "H9"], + ["F5", "I1"], + ["F5", "I2"], + ["F5", "I3"], + ["F5", "I5"], + ["F5", "I6"], + ["F5", "I8"], + ["F6", "H8"], + ["F6", "H9"], + ["F6", "I3"], + ["F6", "I4"], + ["F6", "I5"], + ["F6", "I7"], + ["F7", "H9"], + ["F7", "I0"], + ["F7", "I3"], + ["F7", "I5"], + ["F7", "I6"], + ["F7", "I7"], + ["F7", "I8"], + ["F8", "I0"], + ["F8", "I1"], + ["F8", "I2"], + ["F8", "I3"], + ["F8", "I5"], + ["F8", "I6"], + ["F9", "I0"], + ["F9", "I4"], + ["F9", "I5"], + ["F9", "I6"], + ["F9", "I8"], + ["G0", "H8"], + ["G0", "I0"], + ["G0", "I1"], + ["G0", "I2"], + ["G0", "I3"], + ["G0", "I4"], + ["G0", "I5"], + ["G0", "I7"], + ["G0", "I8"], + ["G1", "H9"], + ["G1", "I0"], + ["G1", "I2"], + ["G1", "I7"], + ["G1", "I8"], + ["G2", "I2"], + ["G2", "I3"], + ["G2", "I4"], + ["G2", "I7"], + ["G3", "H8"], + ["G3", "I0"], + ["G3", "I1"], + ["G3", "I2"], + ["G3", "I4"], + ["G3", "I5"], + ["G3", "I6"], + ["G3", "I7"], + ["G3", "I8"], + ["G4", "I1"], + ["G4", "I3"], + ["G4", "I5"], + ["G4", "I8"], + ["G5", "H8"], + ["G5", "H9"], + ["G5", "I0"], + ["G5", "I3"], + ["G5", "I5"], + ["G5", "I6"], + ["G5", "I8"], + ["G6", "H9"], + ["G6", "I2"], + ["G6", "I3"], + ["G6", "I5"], + ["G6", "I6"], + ["G6", "I8"], + ["G7", "I2"], + ["G7", "I5"], + ["G7", "I6"], + ["G8", "H8"], + ["G8", "I1"], + ["G8", "I2"], + ["G8", "I4"], + ["G8", "I8"], + ["G9", "H8"], + ["G9", "I0"], + ["G9", "I1"], + ["G9", "I2"], + ["G9", "I4"], + ["G9", "I8"], + ["H0", "H9"], + ["H0", "I0"], + ["H0", "I2"], + ["H0", "I3"], + ["H0", "I4"], + ["H0", "I5"], + ["H0", "I6"], + ["H0", "I7"], + ["H1", "H9"], + ["H1", "I0"], + ["H1", "I1"], + ["H1", "I3"], + ["H1", "I5"], + ["H1", "I6"], + ["H1", "I7"], + ["H2", "H9"], + ["H2", "I4"], + ["H2", "I5"], + ["H2", "I7"], + ["H3", "H8"], + ["H3", "I4"], + ["H3", "I5"], + ["H3", "I7"], + ["H3", "I8"], + ["H4", "H8"], + ["H4", "I0"], + ["H4", "I2"], + ["H4", "I8"], + ["H5", "I2"], + ["H5", "I3"], + ["H5", "I4"], + ["H5", "I5"], + ["H6", "I0"], + ["H6", "I6"], + ["H7", "H8"], + ["H7", "H9"], + ["H7", "I0"], + ["H7", "I1"], + ["H7", "I4"], + ["H7", "I5"], + ["H7", "I8"], + ["A0", "J1"], + ["A0", "J2"], + ["A0", "J4"], + ["A0", "J5"], + ["A1", "I7"], + ["A1", "I8"], + ["A1", "I9"], + ["A1", "J1"], + ["A1", "J2"], + ["A1", "J3"], + ["A1", "J5"], + ["A2", "I9"], + ["A2", "J0"], + ["A2", "J1"], + ["A2", "J5"], + ["A3", "J0"], + ["A3", "J1"], + ["A3", "J3"], + ["A3", "J5"], + ["A4", "J2"], + ["A5", "J0"], + ["A5", "J1"], + ["A5", "J2"], + ["A5", "J3"], + ["A5", "J4"], + ["A6", "I9"], + ["A6", "J0"], + ["A6", "J1"], + ["A6", "J3"], + ["A6", "J4"], + ["A7", "I8"], + ["A7", "J0"], + ["A7", "J3"], + ["A7", "J4"], + ["A7", "J5"], + ["A8", "I7"], + ["A8", "J0"], + ["A8", "J1"], + ["A8", "J2"], + ["A8", "J4"], + ["A9", "I9"], + ["A9", "J0"], + ["A9", "J2"], + ["A9", "J3"], + ["B0", "I7"], + ["B0", "J1"], + ["B0", "J2"], + ["B0", "J3"], + ["B0", "J5"], + ["B1", "J1"], + ["B1", "J2"], + ["B1", "J4"], + ["B1", "J5"], + ["B2", "I7"], + ["B2", "J1"], + ["B2", "J2"], + ["B2", "J4"], + ["B3", "I8"], + ["B3", "J1"], + ["B3", "J2"], + ["B3", "J4"], + ["B3", "J5"], + ["B4", "I7"], + ["B4", "I8"], + ["B4", "I9"], + ["B4", "J0"], + ["B4", "J4"], + ["B4", "J5"], + ["B5", "I7"], + ["B5", "I8"], + ["B5", "J2"], + ["B5", "J3"], + ["B5", "J4"], + ["B6", "I7"], + ["B6", "J1"], + ["B6", "J2"], + ["B6", "J3"], + ["B6", "J5"], + ["B7", "J1"], + ["B7", "J2"], + ["B8", "J0"], + ["B8", "J4"], + ["B9", "I8"], + ["B9", "J1"], + ["B9", "J2"], + ["B9", "J4"], + ["C0", "I9"], + ["C0", "J0"], + ["C0", "J3"], + ["C0", "J4"], + ["C1", "I8"], + ["C1", "J1"], + ["C1", "J3"], + ["C1", "J4"], + ["C1", "J5"], + ["C2", "I7"], + ["C2", "I8"], + ["C2", "J1"], + ["C2", "J2"], + ["C2", "J4"], + ["C3", "I8"], + ["C3", "J1"], + ["C3", "J5"], + ["C4", "I7"], + ["C4", "J0"], + ["C4", "J2"], + ["C4", "J3"], + ["C4", "J4"], + ["C4", "J5"], + ["C5", "I7"], + ["C5", "I9"], + ["C5", "J1"], + ["C5", "J2"], + ["C5", "J3"], + ["C6", "I8"], + ["C6", "I9"], + ["C6", "J1"], + ["C6", "J2"], + ["C6", "J3"], + ["C7", "I7"], + ["C7", "I8"], + ["C7", "J0"], + ["C7", "J3"], + ["C7", "J4"], + ["C8", "I7"], + ["C8", "I9"], + ["C8", "J0"], + ["C8", "J1"], + ["C8", "J2"], + ["C8", "J3"], + ["C9", "I7"], + ["C9", "I9"], + ["C9", "J0"], + ["C9", "J1"], + ["C9", "J2"], + ["C9", "J4"], + ["D0", "I8"], + ["D0", "I9"], + ["D0", "J1"], + ["D0", "J2"], + ["D0", "J3"], + ["D0", "J4"], + ["D0", "J5"], + ["D1", "I9"], + ["D1", "J2"], + ["D1", "J5"], + ["D2", "I7"], + ["D2", "I8"], + ["D2", "J0"], + ["D2", "J3"], + ["D2", "J4"], + ["D2", "J5"], + ["D3", "I7"], + ["D3", "I8"], + ["D3", "I9"], + ["D3", "J2"], + ["D3", "J5"], + ["D4", "I7"], + ["D4", "I9"], + ["D4", "J0"], + ["D4", "J2"], + ["D4", "J4"], + ["D4", "J5"], + ["D5", "I7"], + ["D5", "J3"], + ["D5", "J5"], + ["D6", "J3"], + ["D6", "J5"], + ["D7", "I7"], + ["D7", "J1"], + ["D7", "J3"], + ["D8", "I8"], + ["D8", "J0"], + ["D8", "J1"], + ["D8", "J4"], + ["D9", "I7"], + ["D9", "I9"], + ["D9", "J1"], + ["D9", "J3"], + ["D9", "J4"], + ["E0", "I8"], + ["E0", "J0"], + ["E1", "I9"], + ["E1", "J2"], + ["E2", "I9"], + ["E2", "J1"], + ["E2", "J2"], + ["E2", "J3"], + ["E3", "I9"], + ["E3", "J1"], + ["E3", "J2"], + ["E3", "J3"], + ["E3", "J5"], + ["E4", "I7"], + ["E4", "I9"], + ["E4", "J1"], + ["E4", "J3"], + ["E5", "I8"], + ["E5", "I9"], + ["E5", "J0"], + ["E5", "J3"], + ["E5", "J4"], + ["E5", "J5"], + ["E6", "I7"], + ["E6", "I8"], + ["E6", "J2"], + ["E6", "J3"], + ["E7", "I7"], + ["E7", "I8"], + ["E7", "I9"], + ["E7", "J3"], + ["E8", "I9"], + ["E8", "J3"], + ["E8", "J4"], + ["E8", "J5"], + ["E9", "I7"], + ["E9", "I8"], + ["E9", "I9"], + ["E9", "J4"], + ["F0", "I8"], + ["F0", "I9"], + ["F0", "J1"], + ["F0", "J2"], + ["F0", "J4"], + ["F0", "J5"], + ["F1", "I8"], + ["F1", "I9"], + ["F1", "J0"], + ["F1", "J1"], + ["F1", "J2"], + ["F1", "J3"], + ["F1", "J5"], + ["F2", "J3"], + ["F2", "J4"], + ["F3", "I7"], + ["F3", "I8"], + ["F3", "I9"], + ["F3", "J2"], + ["F3", "J3"], + ["F4", "J0"], + ["F4", "J1"], + ["F4", "J3"], + ["F4", "J5"], + ["F5", "I7"], + ["F5", "J2"], + ["F6", "I7"], + ["F6", "J0"], + ["F6", "J3"], + ["F6", "J4"], + ["F6", "J5"], + ["F7", "I8"], + ["F7", "I9"], + ["F7", "J2"], + ["F7", "J3"], + ["F7", "J4"], + ["F8", "I7"], + ["F8", "I8"], + ["F8", "J1"], + ["F8", "J2"], + ["F8", "J4"], + ["F8", "J5"], + ["F9", "I7"], + ["F9", "J1"], + ["F9", "J2"], + ["G0", "J0"], + ["G0", "J2"], + ["G1", "I8"], + ["G1", "J0"], + ["G1", "J2"], + ["G1", "J5"], + ["G2", "I9"], + ["G2", "J0"], + ["G2", "J1"], + ["G2", "J3"], + ["G2", "J4"], + ["G3", "I7"], + ["G3", "I8"], + ["G3", "I9"], + ["G3", "J0"], + ["G3", "J4"], + ["G4", "I7"], + ["G4", "I8"], + ["G4", "J0"], + ["G4", "J1"], + ["G4", "J2"], + ["G4", "J4"], + ["G5", "I8"], + ["G5", "J0"], + ["G5", "J2"], + ["G5", "J3"], + ["G6", "I8"], + ["G6", "J4"], + ["G6", "J5"], + ["G7", "I7"], + ["G7", "I8"], + ["G7", "J2"], + ["G7", "J3"], + ["G7", "J4"], + ["G8", "I8"], + ["G8", "J0"], + ["G8", "J3"], + ["G9", "J4"], + ["G9", "J5"], + ["H0", "I7"], + ["H0", "I9"], + ["H0", "J2"], + ["H0", "J4"], + ["H1", "I7"], + ["H1", "I8"], + ["H1", "J0"], + ["H1", "J3"], + ["H1", "J5"], + ["H2", "J1"], + ["H3", "I8"], + ["H3", "J1"], + ["H4", "I7"], + ["H4", "J1"], + ["H4", "J2"], + ["H4", "J5"], + ["H5", "I8"], + ["H5", "J1"], + ["H5", "J4"], + ["H6", "I7"], + ["H6", "I8"], + ["H6", "I9"], + ["H6", "J0"], + ["H6", "J2"], + ["H6", "J3"], + ["H7", "I7"], + ["H7", "I8"], + ["H7", "J1"], + ["H7", "J2"], + ["H7", "J4"], + ["H7", "J5"], + ["H8", "I8"], + ["H8", "I9"], + ["H8", "J2"], + ["H8", "J3"], + ["H8", "J4"], + ["H9", "J4"], + ["H9", "J5"], + ["I0", "J1"], + ["I0", "J4"], + ["I0", "J5"], + ["I1", "I7"], + ["I1", "J2"], + ["I1", "J3"], + ["I2", "I8"], + ["I2", "I9"], + ["I2", "J4"], + ["I3", "I7"], + ["I3", "J1"], + ["I3", "J2"], + ["I3", "J3"], + ["I3", "J5"], + ["I4", "I7"], + ["I4", "I8"], + ["I4", "I9"], + ["I4", "J0"], + ["I4", "J3"], + ["I4", "J4"], + ["I4", "J5"], + ["I5", "I7"], + ["I5", "J2"], + ["I5", "J3"], + ["I5", "J4"], + ["I5", "J5"], + ["I6", "I7"], + ["I6", "I8"], + ["I6", "J0"], + ["I6", "J1"], + ["I6", "J2"], + ["I6", "J4"], + ["I6", "J5"], + ["A2", "I8"], + ["A7", "I8"], + ["A8", "I8"], + ["B0", "I8"], + ["B4", "I8"], + ["B6", "I8"], + ["B8", "I8"], + ["C1", "I8"], + ["C7", "I8"], + ["C9", "I8"], + ["D0", "I8"], + ["D2", "I8"], + ["D3", "I8"], + ["D4", "I8"], + ["D5", "I8"], + ["D9", "I8"], + ["E0", "I8"], + ["E6", "I8"], + ["E8", "I8"], + ["E9", "I8"], + ["F3", "I8"], + ["F4", "I8"], + ["F7", "I8"], + ["F8", "I8"], + ["G1", "I8"], + ["G2", "I8"], + ["G3", "I8"], + ["G4", "I8"], + ["G7", "I8"], + ["H3", "I8"], + ["H9", "I8"], + ["I0", "I8"], + ["I1", "I8"], + ["I4", "I8"], + ["A0", "C4"], + ["I7", "I8"] + ] +} diff --git a/fixtures/medium-graph.json b/fixtures/medium-graph.json new file mode 100644 index 0000000..3467cdb --- /dev/null +++ b/fixtures/medium-graph.json @@ -0,0 +1,178 @@ +{ + "nodes": [ + "A0", + "B0", + "C0", + "D0", + "E0", + "F0", + "G0", + "H0", + "I0", + "J0", + "A1", + "B1", + "C1", + "D1", + "E1", + "F1", + "G1", + "H1", + "I1", + "J1", + "A2", + "B2", + "C2", + "D2", + "E2", + "F2", + "G2", + "H2", + "I2", + "J2", + "A3", + "B3", + "C3", + "D3", + "E3", + "F3", + "G3", + "H3", + "I3", + "J3", + "A4", + "B4", + "C4", + "D4", + "E4", + "F4", + "G4", + "H4", + "I4", + "J4" + ], + "edges": [ + ["A0", "H0"], + ["A0", "E3"], + ["B0", "E1"], + ["B0", "F4"], + ["B0", "B2"], + ["C0", "D3"], + ["D0", "E0"], + ["D0", "H0"], + ["D0", "H2"], + ["D0", "G3"], + ["D0", "C4"], + ["A1", "I2"], + ["A1", "I2"], + ["E0", "H0"], + ["E0", "H2"], + ["G0", "D1"], + ["G0", "D1"], + ["G0", "I2"], + ["G0", "I2"], + ["E0", "H0"], + ["H0", "B4"], + ["H0", "E4"], + ["I0", "J1"], + ["I0", "I4"], + ["H3", "H4"], + ["B0", "C2"], + ["B0", "C2"], + ["B0", "J4"], + ["C0", "J1"], + ["C0", "F2"], + ["J0", "A3"], + ["J0", "G4"], + ["A1", "A0"], + ["A1", "H0"], + ["A1", "I2"], + ["A1", "J2"], + ["A1", "J2"], + ["A1", "E3"], + ["A1", "B4"], + ["F0", "D4"], + ["B1", "B2"], + ["B1", "A3"], + ["C1", "J0"], + ["C1", "B1"], + ["C1", "B2"], + ["C1", "B2"], + ["C1", "G2"], + ["D1", "C2"], + ["D1", "D2"], + ["D1", "H4"], + ["E1", "I0"], + ["E1", "B2"], + ["H2", "F0"], + ["H2", "E2"], + ["H2", "C3"], + ["E1", "I4"], + ["F1", "E3"], + ["F1", "J4"], + ["G1", "J0"], + ["H0", "A2"], + ["H0", "E2"], + ["H0", "I3"], + ["I1", "G0"], + ["E2", "D4"], + ["F2", "E3"], + ["G2", "J0"], + ["G2", "G1"], + ["J1", "A4"], + ["A2", "F3"], + ["A2", "I3"], + ["D2", "B1"], + ["D2", "B2"], + ["D2", "C2"], + ["E2", "F0"], + ["E2", "I3"], + ["H2", "B3"], + ["H2", "C4"], + ["I2", "C2"], + ["I2", "J2"], + ["A2", "G4"], + ["I1", "I2"], + ["I1", "C3"], + ["C3", "G0"], + ["C3", "D1"], + ["J2", "J4"], + ["C3", "H3"], + ["C3", "H4"], + ["D3", "J1"], + ["E3", "A4"], + ["F3", "J0"], + ["I1", "C4"], + ["J1", "F1"], + ["I2", "J3"], + ["I2", "E4"], + ["J2", "C2"], + ["A3", "H3"], + ["B3", "I1"], + ["B3", "C3"], + ["C3", "F0"], + ["D3", "I0"], + ["F3", "H3"], + ["F3", "G4"], + ["G3", "A2"], + ["G3", "C4"], + ["H3", "F0"], + ["I4", "C1"], + ["I4", "B2"], + ["J4", "E3"], + ["J4", "C2"], + ["H3", "H4"], + ["I3", "H3"], + ["J3", "C4"], + ["B4", "I2"], + ["B4", "E4"], + ["E4", "J3"], + ["F4", "I0"], + ["F4", "E1"], + ["F4", "E1"], + ["F4", "F1"], + ["F4", "J4"], + ["I3", "F3"], + ["J0", "B1"] + ] +} diff --git a/fixtures/small-graph.json b/fixtures/small-graph.json new file mode 100644 index 0000000..6d55a10 --- /dev/null +++ b/fixtures/small-graph.json @@ -0,0 +1,21 @@ +{ + "nodes": ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M"], + "edges": [ + ["E", "C"], + ["C", "D"], + ["G", "A"], + ["A", "B"], + ["L", "M"], + ["M", "J"], + ["C", "A"], + ["J", "K"], + ["H", "J"], + ["L", "E"], + ["E", "D"], + ["D", "F"], + ["G", "I"], + ["G", "E"], + ["G", "J"], + ["H", "G"] + ] +} diff --git a/fixtures/tiny-graph.json b/fixtures/tiny-graph.json new file mode 100644 index 0000000..8fdfb4a --- /dev/null +++ b/fixtures/tiny-graph.json @@ -0,0 +1,9 @@ +{ + "nodes": ["A", "B", "C", "D"], + "edges": [ + ["A", "B"], + ["B", "C"], + ["B", "D"], + ["D", "C"] + ] +} diff --git a/fixtures/wikipedia.json b/fixtures/wikipedia.json new file mode 100644 index 0000000..3c9b729 --- /dev/null +++ b/fixtures/wikipedia.json @@ -0,0 +1,14 @@ +{ + "nodes": ["2", "3", "5", "7", "8", "9", "10", "11"], + "edges": [ + ["5", "11"], + ["7", "11"], + ["7", "8"], + ["3", "8"], + ["3", "10"], + ["11", "2"], + ["11", "9"], + ["11", "10"], + ["8", "9"] + ] +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..5c79414 --- /dev/null +++ b/package.json @@ -0,0 +1,82 @@ +{ + "name": "@haragei/dag", + "version": "1.0.0", + "author": "Aleksandar Ružičić", + "license": "MIT", + "description": "A Directed Acyclic Graph (DAG) library with online cycle detection and topological ordering.", + "keywords": [ + "dag", + "graph", + "cycle detection" + ], + "homepage": "https://github.com/haragei-dev/dag", + "repository": "github:haragei-dev/dag", + "bugs": { + "url": "https://github.com/haragei-dev/dag/issues" + }, + "type": "module", + "main": "./dist/index.cjs", + "module": "./dist/index.mjs", + "types": "./dist/index.d.cts", + "exports": { + "require": { + "types": "./dist/index.d.cts", + "default": "./dist/index.cjs" + }, + "import": { + "types": "./dist/index.d.mts", + "default": "./dist/index.mjs" + } + }, + "files": [ + "dist" + ], + "publishConfig": { + "directory": "package" + }, + "clean-publish": { + "withoutPublish": true, + "tempDir": "package", + "fields": [ + "packageManager", + "pnpm", + "publishConfig", + "scripts" + ] + }, + "scripts": { + "prepublishOnly": "pnpm lint && pnpm typecheck && pnpm test && pnpm build && rm -rf ./package && clean-publish && attw --pack ./package", + "postpublish": "rm -rf ./package", + "build": "pkgroll --target=node20 --minify --sourcemap", + "lint": "eslint ./src", + "test": "NODE_V8_COVERAGE=coverage glob -c \"node --import tsx --experimental-test-coverage --test-reporter=lcov --test-reporter-destination=coverage/lcov.info --no-warnings --test-reporter @voxpelli/node-test-pretty-reporter --test-reporter-destination stdout $NODE_TEST_ARGS --test\" \"./src/**/*.test.ts\"", + "test:watch": "NODE_TEST_ARGS='--watch' pnpm test", + "test:ci": "NODE_TEST_ARGS='--test-reporter node-test-github-reporter --test-reporter-destination stdout' pnpm test", + "coverage": "pnpx lcov-cli-report-viewer coverage/lcov.info", + "coverage:html": "pnpx @lcov-viewer/cli lcov -o coverage/report coverage/lcov.info && pnpx serve coverage/report", + "typecheck": "tsc --noEmit" + }, + "devDependencies": { + "@arethetypeswrong/cli": "0.15.3", + "@eslint/js": "9.6.0", + "@types/eslint__js": "8.42.3", + "@types/node": "20.14.10", + "@voxpelli/node-test-pretty-reporter": "1.1.2", + "clean-publish": "5.0.0", + "eslint": "9.6.0", + "glob": "11.0.0", + "node-test-github-reporter": "1.2.0", + "pkgroll": "2.1.1", + "prettier": "3.3.2", + "tsx": "4.16.2", + "typescript": "5.5.3", + "typescript-eslint": "8.0.0-alpha.41", + "typescript-eslint-language-service": "5.0.5" + }, + "pnpm": { + "overrides": { + "@rollup/plugin-commonjs": "^26.0.1" + } + }, + "packageManager": "pnpm@9.5.0+sha256.dbdf5961c32909fb030595a9daa1dae720162e658609a8f92f2fa99835510ca5" +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..260a695 --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,3140 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +overrides: + '@rollup/plugin-commonjs': ^26.0.1 + +importers: + + .: + devDependencies: + '@arethetypeswrong/cli': + specifier: 0.15.3 + version: 0.15.3 + '@eslint/js': + specifier: 9.6.0 + version: 9.6.0 + '@types/eslint__js': + specifier: 8.42.3 + version: 8.42.3 + '@types/node': + specifier: 20.14.10 + version: 20.14.10 + '@voxpelli/node-test-pretty-reporter': + specifier: 1.1.2 + version: 1.1.2 + clean-publish: + specifier: 5.0.0 + version: 5.0.0 + eslint: + specifier: 9.6.0 + version: 9.6.0 + glob: + specifier: 11.0.0 + version: 11.0.0 + node-test-github-reporter: + specifier: 1.2.0 + version: 1.2.0 + pkgroll: + specifier: 2.1.1 + version: 2.1.1(typescript@5.5.3) + prettier: + specifier: 3.3.2 + version: 3.3.2 + tsx: + specifier: 4.16.2 + version: 4.16.2 + typescript: + specifier: 5.5.3 + version: 5.5.3 + typescript-eslint: + specifier: 8.0.0-alpha.41 + version: 8.0.0-alpha.41(eslint@9.6.0)(typescript@5.5.3) + typescript-eslint-language-service: + specifier: 5.0.5 + version: 5.0.5(@typescript-eslint/parser@8.0.0-alpha.41(eslint@9.6.0)(typescript@5.5.3))(eslint@9.6.0)(typescript@5.5.3) + publishDirectory: package + +packages: + + '@actions/core@1.10.1': + resolution: {integrity: sha512-3lBR9EDAY+iYIpTnTIXmWcNbX3T2kCkAEQGIQx4NVQ0575nk2k3GRZDTPQG+vVtS2izSLmINlxXf0uLtnrTP+g==} + + '@actions/http-client@2.2.1': + resolution: {integrity: sha512-KhC/cZsq7f8I4LfZSJKgCvEwfkE8o1538VoBeoGzokVLLnbFDEAdFD3UhoMklxo2un9NJVBdANOresx7vTHlHw==} + + '@andrewbranch/untar.js@1.0.3': + resolution: {integrity: sha512-Jh15/qVmrLGhkKJBdXlK1+9tY4lZruYjsgkDFj08ZmDiWVBLJcqkok7Z0/R0In+i1rScBpJlSvrTS2Lm41Pbnw==} + + '@arethetypeswrong/cli@0.15.3': + resolution: {integrity: sha512-sIMA9ZJBWDEg1+xt5RkAEflZuf8+PO8SdKj17x6PtETuUho+qlZJg4DgmKc3q+QwQ9zOB5VLK6jVRbFdNLdUIA==} + engines: {node: '>=18'} + hasBin: true + + '@arethetypeswrong/core@0.15.1': + resolution: {integrity: sha512-FYp6GBAgsNz81BkfItRz8RLZO03w5+BaeiPma1uCfmxTnxbtuMrI/dbzGiOk8VghO108uFI0oJo0OkewdSHw7g==} + engines: {node: '>=18'} + + '@colors/colors@1.5.0': + resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} + engines: {node: '>=0.1.90'} + + '@esbuild/aix-ppc64@0.20.2': + resolution: {integrity: sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [aix] + + '@esbuild/aix-ppc64@0.21.5': + resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.20.2': + resolution: {integrity: sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm64@0.21.5': + resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.20.2': + resolution: {integrity: sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + + '@esbuild/android-arm@0.21.5': + resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.20.2': + resolution: {integrity: sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + + '@esbuild/android-x64@0.21.5': + resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.20.2': + resolution: {integrity: sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-arm64@0.21.5': + resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.20.2': + resolution: {integrity: sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + + '@esbuild/darwin-x64@0.21.5': + resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.20.2': + resolution: {integrity: sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-arm64@0.21.5': + resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.20.2': + resolution: {integrity: sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.21.5': + resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.20.2': + resolution: {integrity: sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm64@0.21.5': + resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.20.2': + resolution: {integrity: sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-arm@0.21.5': + resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.20.2': + resolution: {integrity: sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-ia32@0.21.5': + resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.20.2': + resolution: {integrity: sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-loong64@0.21.5': + resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.20.2': + resolution: {integrity: sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-mips64el@0.21.5': + resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.20.2': + resolution: {integrity: sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-ppc64@0.21.5': + resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.20.2': + resolution: {integrity: sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-riscv64@0.21.5': + resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.20.2': + resolution: {integrity: sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-s390x@0.21.5': + resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.20.2': + resolution: {integrity: sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + + '@esbuild/linux-x64@0.21.5': + resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-x64@0.20.2': + resolution: {integrity: sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.21.5': + resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-x64@0.20.2': + resolution: {integrity: sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.21.5': + resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + + '@esbuild/sunos-x64@0.20.2': + resolution: {integrity: sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + + '@esbuild/sunos-x64@0.21.5': + resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.20.2': + resolution: {integrity: sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-arm64@0.21.5': + resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.20.2': + resolution: {integrity: sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-ia32@0.21.5': + resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.20.2': + resolution: {integrity: sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + + '@esbuild/win32-x64@0.21.5': + resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + + '@eslint-community/eslint-utils@4.4.0': + resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + + '@eslint-community/regexpp@4.11.0': + resolution: {integrity: sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + '@eslint/config-array@0.17.0': + resolution: {integrity: sha512-A68TBu6/1mHHuc5YJL0U0VVeGNiklLAL6rRmhTCP2B5XjWLMnrX+HkO+IAXyHvks5cyyY1jjK5ITPQ1HGS2EVA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/eslintrc@3.1.0': + resolution: {integrity: sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/js@9.6.0': + resolution: {integrity: sha512-D9B0/3vNg44ZeWbYMpBoXqNP4j6eQD5vNwIlGAuFRRzK/WtT/jvDQW3Bi9kkf3PMDMlM7Yi+73VLUsn5bJcl8A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/object-schema@2.1.4': + resolution: {integrity: sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@fastify/busboy@2.1.1': + resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==} + engines: {node: '>=14'} + + '@humanwhocodes/module-importer@1.0.1': + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + + '@humanwhocodes/retry@0.3.0': + resolution: {integrity: sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==} + engines: {node: '>=18.18'} + + '@isaacs/cliui@8.0.2': + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + + '@jest/schemas@29.6.3': + resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jridgewell/sourcemap-codec@1.5.0': + resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + + '@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'} + + '@pkgjs/parseargs@0.11.0': + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + + '@rollup/plugin-alias@5.1.0': + resolution: {integrity: sha512-lpA3RZ9PdIG7qqhEfv79tBffNaoDuukFDrmhLqg9ifv99u/ehn+lOg30x2zmhf8AQqQUZaMk/B9fZraQ6/acDQ==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/plugin-commonjs@26.0.1': + resolution: {integrity: sha512-UnsKoZK6/aGIH6AdkptXhNvhaqftcjq3zZdT+LY5Ftms6JR06nADcDsYp5hTU9E2lbJUEOhdlY5J4DNTneM+jQ==} + engines: {node: '>=16.0.0 || 14 >= 14.17'} + peerDependencies: + rollup: ^2.68.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/plugin-inject@5.0.5': + resolution: {integrity: sha512-2+DEJbNBoPROPkgTDNe8/1YXWcqxbN5DTjASVIOx8HS+pITXushyNiBV56RB08zuptzz8gT3YfkqriTBVycepg==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/plugin-json@6.1.0': + resolution: {integrity: sha512-EGI2te5ENk1coGeADSIwZ7G2Q8CJS2sF120T7jLw4xFw9n7wIOXHo+kIYRAoVpJAN+kmqZSoO3Fp4JtoNF4ReA==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/plugin-node-resolve@15.2.3': + resolution: {integrity: sha512-j/lym8nf5E21LwBT4Df1VD6hRO2L2iwUeUmP7litikRsVp1H6NWx20NEp0Y7su+7XGc476GnXXc4kFeZNGmaSQ==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^2.78.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/plugin-replace@5.0.7': + resolution: {integrity: sha512-PqxSfuorkHz/SPpyngLyg5GCEkOcee9M1bkxiVDr41Pd61mqP1PLOoDPbpl44SB2mQGKwV/In74gqQmGITOhEQ==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/pluginutils@5.1.0': + resolution: {integrity: sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/rollup-android-arm-eabi@4.18.1': + resolution: {integrity: sha512-lncuC4aHicncmbORnx+dUaAgzee9cm/PbIqgWz1PpXuwc+sa1Ct83tnqUDy/GFKleLiN7ZIeytM6KJ4cAn1SxA==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.18.1': + resolution: {integrity: sha512-F/tkdw0WSs4ojqz5Ovrw5r9odqzFjb5LIgHdHZG65dFI1lWTWRVy32KDJLKRISHgJvqUeUhdIvy43fX41znyDg==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.18.1': + resolution: {integrity: sha512-vk+ma8iC1ebje/ahpxpnrfVQJibTMyHdWpOGZ3JpQ7Mgn/3QNHmPq7YwjZbIE7km73dH5M1e6MRRsnEBW7v5CQ==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.18.1': + resolution: {integrity: sha512-IgpzXKauRe1Tafcej9STjSSuG0Ghu/xGYH+qG6JwsAUxXrnkvNHcq/NL6nz1+jzvWAnQkuAJ4uIwGB48K9OCGA==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-linux-arm-gnueabihf@4.18.1': + resolution: {integrity: sha512-P9bSiAUnSSM7EmyRK+e5wgpqai86QOSv8BwvkGjLwYuOpaeomiZWifEos517CwbG+aZl1T4clSE1YqqH2JRs+g==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.18.1': + resolution: {integrity: sha512-5RnjpACoxtS+aWOI1dURKno11d7krfpGDEn19jI8BuWmSBbUC4ytIADfROM1FZrFhQPSoP+KEa3NlEScznBTyQ==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.18.1': + resolution: {integrity: sha512-8mwmGD668m8WaGbthrEYZ9CBmPug2QPGWxhJxh/vCgBjro5o96gL04WLlg5BA233OCWLqERy4YUzX3bJGXaJgQ==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-musl@4.18.1': + resolution: {integrity: sha512-dJX9u4r4bqInMGOAQoGYdwDP8lQiisWb9et+T84l2WXk41yEej8v2iGKodmdKimT8cTAYt0jFb+UEBxnPkbXEQ==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-powerpc64le-gnu@4.18.1': + resolution: {integrity: sha512-V72cXdTl4EI0x6FNmho4D502sy7ed+LuVW6Ym8aI6DRQ9hQZdp5sj0a2usYOlqvFBNKQnLQGwmYnujo2HvjCxQ==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.18.1': + resolution: {integrity: sha512-f+pJih7sxoKmbjghrM2RkWo2WHUW8UbfxIQiWo5yeCaCM0TveMEuAzKJte4QskBp1TIinpnRcxkquY+4WuY/tg==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.18.1': + resolution: {integrity: sha512-qb1hMMT3Fr/Qz1OKovCuUM11MUNLUuHeBC2DPPAWUYYUAOFWaxInaTwTQmc7Fl5La7DShTEpmYwgdt2hG+4TEg==} + cpu: [s390x] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.18.1': + resolution: {integrity: sha512-7O5u/p6oKUFYjRbZkL2FLbwsyoJAjyeXHCU3O4ndvzg2OFO2GinFPSJFGbiwFDaCFc+k7gs9CF243PwdPQFh5g==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-linux-x64-musl@4.18.1': + resolution: {integrity: sha512-pDLkYITdYrH/9Cv/Vlj8HppDuLMDUBmgsM0+N+xLtFd18aXgM9Nyqupb/Uw+HeidhfYg2lD6CXvz6CjoVOaKjQ==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-win32-arm64-msvc@4.18.1': + resolution: {integrity: sha512-W2ZNI323O/8pJdBGil1oCauuCzmVd9lDmWBBqxYZcOqWD6aWqJtVBQ1dFrF4dYpZPks6F+xCZHfzG5hYlSHZ6g==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.18.1': + resolution: {integrity: sha512-ELfEX1/+eGZYMaCIbK4jqLxO1gyTSOIlZr6pbC4SRYFaSIDVKOnZNMdoZ+ON0mrFDp4+H5MhwNC1H/AhE3zQLg==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.18.1': + resolution: {integrity: sha512-yjk2MAkQmoaPYCSu35RLJ62+dz358nE83VfTePJRp8CG7aMg25mEJYpXFiD+NcevhX8LxD5OP5tktPXnXN7GDw==} + cpu: [x64] + os: [win32] + + '@sinclair/typebox@0.27.8': + resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} + + '@sindresorhus/is@4.6.0': + resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==} + engines: {node: '>=10'} + + '@types/debug@4.1.12': + resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} + + '@types/eslint@8.56.10': + resolution: {integrity: sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ==} + + '@types/eslint__js@8.42.3': + resolution: {integrity: sha512-alfG737uhmPdnvkrLdZLcEKJ/B8s9Y4hrZ+YAdzUeoArBlSUERA2E87ROfOaS4jd/C45fzOoZzidLc1IPwLqOw==} + + '@types/estree@1.0.5': + resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} + + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + + '@types/mdast@4.0.4': + resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} + + '@types/ms@0.7.34': + resolution: {integrity: sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==} + + '@types/node@20.14.10': + resolution: {integrity: sha512-MdiXf+nDuMvY0gJKxyfZ7/6UFsETO7mGKF54MVD/ekJS6HdFtpZFBgrh6Pseu64XTb2MLyFPlbW6hj8HYRQNOQ==} + + '@types/resolve@1.20.2': + resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==} + + '@types/unist@3.0.2': + resolution: {integrity: sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==} + + '@typescript-eslint/eslint-plugin@8.0.0-alpha.41': + resolution: {integrity: sha512-WePtbzWMaQO4qtGAXp3zzEN8yYZCEuAHVCERCUXgoSUTQ80F5UB7T5lYyA9ySpFDB7rqJ2ev98DtnbS4U3Ms+w==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0 + eslint: ^8.57.0 || ^9.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/parser@8.0.0-alpha.41': + resolution: {integrity: sha512-7HMXwy/q/59ZASBXz2FtdIsR7LgABrR8j2dTKq9GMR8OkjjdO4klxWSY/uOBozVt4UxlMRYsBdBDhEq4/tHRiw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/scope-manager@8.0.0-alpha.41': + resolution: {integrity: sha512-iNxuQ0TMVfFiMJ2al4bGd/mY9+aLtBxnHfo7B2xoVzR6cRFgUdBLlMa//MSIjSmVRpCEqNLQnkxpJb96tFG+xw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/type-utils@8.0.0-alpha.41': + resolution: {integrity: sha512-+QIA1z/jrox6bbvqlyqBQjotpevieLTycfiuoKuqGcKoskFZV5Rma51BV8LCJacnOafwJtSi+7b8zDo8OsXUvA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/types@8.0.0-alpha.41': + resolution: {integrity: sha512-n0P2FP3YC3pD3yoiCf4lHqbUP45xlnOk8HkjB+LtKSUZZWLLJ8k1ZXZtQj7MEX22tytCMj//Bmq403xFuCwfIg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/typescript-estree@8.0.0-alpha.41': + resolution: {integrity: sha512-adCr+vbLYTFhwhIwjIjjMxTdUYiPA2Jlyuhnbj092IzgLHtT79bvuwcgPWeTyLbFb/13SMKmOEka00xHiqLpig==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/utils@8.0.0-alpha.41': + resolution: {integrity: sha512-DTxc9VdERS6iloiw1P5tgRDqRArmp/sIuvgdHBvGh2SiltEFc3VjLGnHHGSTr6GfH7tjFWvcCnCtxx+pjWfp5Q==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + + '@typescript-eslint/visitor-keys@8.0.0-alpha.41': + resolution: {integrity: sha512-uetCAUBVC+YarBdZnWzDDgX11PpAEGV8Cw31I3d1xNrhx6/bJGThKX+holEmd3amMdnr4w/XUKH/4YuQOgtjDA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@voxpelli/node-test-pretty-reporter@1.1.2': + resolution: {integrity: sha512-8CgypuCjjTOH7psFDbYTpEyBHAYPhaXsVxbuUSziJ401YLAsHBR6U31LEREOKs4GpCTLNwr5G30ztG/NdrE8cg==} + engines: {node: '>=18.0.0'} + + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn@8.12.1: + resolution: {integrity: sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==} + engines: {node: '>=0.4.0'} + hasBin: true + + ajv@6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + + ansi-escapes@5.0.0: + resolution: {integrity: sha512-5GFMVX8HqE/TB+FuBJGuO5XG0WrsA6ptUqoODaT/n9mmUaZFkqnBueB4leqGBCmrUHnCnC4PCZTCd0E7QQ83bA==} + engines: {node: '>=12'} + + ansi-escapes@6.2.1: + resolution: {integrity: sha512-4nJ3yixlEthEJ9Rk4vPcdBRkZvQZlYyu8j4/Mqz5sgIkddmEnH2Yj2ZrnP9S3tQOvSNRUIgVNF/1yPpRAGNRig==} + engines: {node: '>=14.16'} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-regex@6.0.1: + resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} + engines: {node: '>=12'} + + 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'} + + ansi-styles@6.2.1: + resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} + engines: {node: '>=12'} + + ansicolors@0.3.2: + resolution: {integrity: sha512-QXu7BPrP29VllRxH8GwB7x5iX5qWKAAMLqKQGWTeLWVlNHNOpVMJ91dsxQAIWXpjuW5wqvxu3Jd/nRjrJ+0pqg==} + + any-promise@1.3.0: + resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + array-union@2.1.0: + resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} + engines: {node: '>=8'} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + + brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + builtin-modules@3.3.0: + resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==} + engines: {node: '>=6'} + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + cardinal@2.1.1: + resolution: {integrity: sha512-JSr5eOgoEymtYHBjNWyjrMqet9Am2miJhlfKNdqLp6zoeAh0KN5dRAcxlecj5mAJrmQomgiOBj35xHLrFjqBpw==} + hasBin: true + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + chalk@5.3.0: + resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + + char-regex@1.0.2: + resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} + engines: {node: '>=10'} + + character-entities@2.0.2: + resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} + + clean-publish@5.0.0: + resolution: {integrity: sha512-1qjtqP3piZL4t8SqGojOyA12bg8AtbFPIQstNvxmss1fhwfma3CqMJ/Y/kbRvAllLX2/c4ZKjcCCKDqEtpcymA==} + engines: {node: '>= 18.0.0'} + hasBin: true + + clean-stack@5.2.0: + resolution: {integrity: sha512-TyUIUJgdFnCISzG5zu3291TAsE77ddchd0bepon1VVQrKLGKFED4iXFEDQ24mIPdPBbyE16PK3F8MYE1CmcBEQ==} + engines: {node: '>=14.16'} + + cli-highlight@2.1.11: + resolution: {integrity: sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg==} + engines: {node: '>=8.0.0', npm: '>=5.0.0'} + hasBin: true + + cli-table3@0.6.5: + resolution: {integrity: sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==} + engines: {node: 10.* || >= 12.*} + + cliui@7.0.4: + resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} + + 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@10.0.1: + resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} + engines: {node: '>=14'} + + commondir@1.0.1: + resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + cross-spawn@7.0.3: + resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} + engines: {node: '>= 8'} + + debug@4.3.5: + resolution: {integrity: sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + decode-named-character-reference@1.0.2: + resolution: {integrity: sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==} + + deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + + deepmerge@4.3.1: + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} + engines: {node: '>=0.10.0'} + + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + + devlop@1.1.0: + resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + + diff-sequences@29.6.3: + resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + dir-glob@3.0.1: + resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} + engines: {node: '>=8'} + + eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + + emojilib@2.4.0: + resolution: {integrity: sha512-5U0rVMU5Y2n2+ykNLQqMoqklN9ICBT/KsvC1Gz6vqHbz2AXXGkG+Pm5rMWk/8Vjrr/mY9985Hi8DYzn1F09Nyw==} + + error-stack-parser@2.1.4: + resolution: {integrity: sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==} + + esbuild@0.20.2: + resolution: {integrity: sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==} + engines: {node: '>=12'} + hasBin: true + + esbuild@0.21.5: + resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} + engines: {node: '>=12'} + hasBin: true + + escalade@3.1.2: + resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==} + engines: {node: '>=6'} + + escape-string-regexp@2.0.0: + resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} + engines: {node: '>=8'} + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + escape-string-regexp@5.0.0: + resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} + engines: {node: '>=12'} + + eslint-scope@8.0.1: + resolution: {integrity: sha512-pL8XjgP4ZOmmwfFE8mEhSxA7ZY4C+LWyqjQ3o4yWkkmD0qcMT9kkW3zWHOczhWcjTSgqycYAgwSlXvZltv65og==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-visitor-keys@4.0.0: + resolution: {integrity: sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint@9.6.0: + resolution: {integrity: sha512-ElQkdLMEEqQNM9Njff+2Y4q2afHk7JpkPvrd7Xh7xefwgQynqPxwf55J7di9+MEibWUGdNjFF9ITG9Pck5M84w==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + hasBin: true + + espree@10.1.0: + resolution: {integrity: sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + + esquery@1.6.0: + resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} + engines: {node: '>=0.10'} + + esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + + estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-glob@3.3.2: + resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} + engines: {node: '>=8.6.0'} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + + fastq@1.17.1: + resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} + + fflate@0.8.2: + resolution: {integrity: sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==} + + file-entry-cache@8.0.0: + resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} + engines: {node: '>=16.0.0'} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + + flat-cache@4.0.1: + resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} + engines: {node: '>=16'} + + flatted@3.3.1: + resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} + + foreground-child@3.2.1: + resolution: {integrity: sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA==} + engines: {node: '>=14'} + + 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==} + + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + + get-tsconfig@4.7.5: + resolution: {integrity: sha512-ZCuZCnlqNzjb4QprAzXKdpp/gh6KTxSJuw3IBsPnV/7fV4NxC9ckB+vPTt8w7fJA0TaSD7c55BR47JD6MEDyDw==} + + 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@10.4.5: + resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} + hasBin: true + + glob@11.0.0: + resolution: {integrity: sha512-9UiX/Bl6J2yaBbxKoEBRm4Cipxgok8kQYcOPEhScPwebu2I0HoQOuYdIO6S3hLuWoZgpDpwQZMzTFxgpkyT76g==} + engines: {node: 20 || >=22} + hasBin: true + + globals@14.0.0: + resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} + engines: {node: '>=18'} + + globby@11.1.0: + resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} + engines: {node: '>=10'} + + graphemer@1.4.0: + resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + highlight.js@10.7.3: + resolution: {integrity: sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==} + + ignore@5.3.1: + resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==} + engines: {node: '>= 4'} + + import-fresh@3.3.0: + resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} + engines: {node: '>=6'} + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + is-builtin-module@3.2.1: + resolution: {integrity: sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==} + engines: {node: '>=6'} + + is-core-module@2.14.0: + resolution: {integrity: sha512-a5dFJih5ZLYlRtDc0dZWP7RiKr6xIKzmn/oAYCDvdLThadVgyJwlaoQPmRtMSpz+rk0OGAgIu+TcM9HUF0fk1A==} + 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-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-module@1.0.0: + resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-path-inside@3.0.3: + resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} + engines: {node: '>=8'} + + is-reference@1.2.1: + resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==} + + is-unicode-supported@2.0.0: + resolution: {integrity: sha512-FRdAyx5lusK1iHG0TWpVtk9+1i+GjrzRffhDg4ovQ7mcidMQ6mj+MhKPmvh7Xwyv5gIS06ns49CA7Sqg7lC22Q==} + engines: {node: '>=18'} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + jackspeak@3.4.3: + resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + + jackspeak@4.0.1: + resolution: {integrity: sha512-cub8rahkh0Q/bw1+GxP7aeSe29hHHn2V4m29nnDlvCdlgU+3UGxkZp7Z53jLUdpX3jdTO0nJZUDl3xvbWc2Xog==} + engines: {node: 20 || >=22} + + jest-diff@29.7.0: + resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==} + 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} + + js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + + json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + + keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + + levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + + lilconfig@3.1.2: + resolution: {integrity: sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==} + engines: {node: '>=14'} + + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + longest-streak@3.1.0: + resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} + + lru-cache@10.4.3: + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + + lru-cache@11.0.0: + resolution: {integrity: sha512-Qv32eSV1RSCfhY3fpPE2GNZ8jgM9X7rdAfemLWqTUxwiyIC4jJ6Sy0fZ8H+oLWevO6i4/bizg7c8d8i6bxrzbA==} + engines: {node: 20 || >=22} + + magic-string@0.30.10: + resolution: {integrity: sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==} + + markdown-or-chalk@0.2.1: + resolution: {integrity: sha512-s/ca1OQ8RalBGxHo2qP/Hc0Sg2Jw88Tz83kcfPETrDjsoO6O4+30WzqYGDijyVx37ratWe2IW9AjqbKo/VRx+Q==} + engines: {node: '>=18.0.0'} + + markdown-table@3.0.3: + resolution: {integrity: sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw==} + + marked-terminal@6.2.0: + resolution: {integrity: sha512-ubWhwcBFHnXsjYNsu+Wndpg0zhY4CahSpPlA70PlO0rR9r2sZpkyU+rkCsOWH+KMEkx847UpALON+HWgxowFtw==} + engines: {node: '>=16.0.0'} + peerDependencies: + marked: '>=1 <12' + + marked@9.1.6: + resolution: {integrity: sha512-jcByLnIFkd5gSXZmjNvS1TlmRhCXZjIzHYlaGkPlLIekG55JDR2Z4va9tZwCiP+/RDERiNhMOFu01xd6O5ct1Q==} + engines: {node: '>= 16'} + hasBin: true + + mdast-util-from-markdown@2.0.1: + resolution: {integrity: sha512-aJEUyzZ6TzlsX2s5B4Of7lN7EQtAxvtradMMglCQDyaTFgse6CmtmdJ15ElnVRlCg1vpNyVtbem0PWzlNieZsA==} + + mdast-util-gfm-table@2.0.0: + resolution: {integrity: sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==} + + mdast-util-phrasing@4.1.0: + resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==} + + mdast-util-to-markdown@2.1.0: + resolution: {integrity: sha512-SR2VnIEdVNCJbP6y7kVTJgPLifdr8WEU440fQec7qHoHOUz/oJ2jmNRqdDQ3rbiStOXb2mCDGTuwsK5OPUgYlQ==} + + mdast-util-to-string@4.0.0: + resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==} + + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + micromark-core-commonmark@2.0.1: + resolution: {integrity: sha512-CUQyKr1e///ZODyD1U3xit6zXwy1a8q2a1S1HKtIlmgvurrEpaw/Y9y6KSIbF8P59cn/NjzHyO+Q2fAyYLQrAA==} + + micromark-factory-destination@2.0.0: + resolution: {integrity: sha512-j9DGrQLm/Uhl2tCzcbLhy5kXsgkHUrjJHg4fFAeoMRwJmJerT9aw4FEhIbZStWN8A3qMwOp1uzHr4UL8AInxtA==} + + micromark-factory-label@2.0.0: + resolution: {integrity: sha512-RR3i96ohZGde//4WSe/dJsxOX6vxIg9TimLAS3i4EhBAFx8Sm5SmqVfR8E87DPSR31nEAjZfbt91OMZWcNgdZw==} + + micromark-factory-space@2.0.0: + resolution: {integrity: sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==} + + micromark-factory-title@2.0.0: + resolution: {integrity: sha512-jY8CSxmpWLOxS+t8W+FG3Xigc0RDQA9bKMY/EwILvsesiRniiVMejYTE4wumNc2f4UbAa4WsHqe3J1QS1sli+A==} + + micromark-factory-whitespace@2.0.0: + resolution: {integrity: sha512-28kbwaBjc5yAI1XadbdPYHX/eDnqaUFVikLwrO7FDnKG7lpgxnvk/XGRhX/PN0mOZ+dBSZ+LgunHS+6tYQAzhA==} + + micromark-util-character@2.1.0: + resolution: {integrity: sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==} + + micromark-util-chunked@2.0.0: + resolution: {integrity: sha512-anK8SWmNphkXdaKgz5hJvGa7l00qmcaUQoMYsBwDlSKFKjc6gjGXPDw3FNL3Nbwq5L8gE+RCbGqTw49FK5Qyvg==} + + micromark-util-classify-character@2.0.0: + resolution: {integrity: sha512-S0ze2R9GH+fu41FA7pbSqNWObo/kzwf8rN/+IGlW/4tC6oACOs8B++bh+i9bVyNnwCcuksbFwsBme5OCKXCwIw==} + + micromark-util-combine-extensions@2.0.0: + resolution: {integrity: sha512-vZZio48k7ON0fVS3CUgFatWHoKbbLTK/rT7pzpJ4Bjp5JjkZeasRfrS9wsBdDJK2cJLHMckXZdzPSSr1B8a4oQ==} + + micromark-util-decode-numeric-character-reference@2.0.1: + resolution: {integrity: sha512-bmkNc7z8Wn6kgjZmVHOX3SowGmVdhYS7yBpMnuMnPzDq/6xwVA604DuOXMZTO1lvq01g+Adfa0pE2UKGlxL1XQ==} + + micromark-util-decode-string@2.0.0: + resolution: {integrity: sha512-r4Sc6leeUTn3P6gk20aFMj2ntPwn6qpDZqWvYmAG6NgvFTIlj4WtrAudLi65qYoaGdXYViXYw2pkmn7QnIFasA==} + + micromark-util-encode@2.0.0: + resolution: {integrity: sha512-pS+ROfCXAGLWCOc8egcBvT0kf27GoWMqtdarNfDcjb6YLuV5cM3ioG45Ys2qOVqeqSbjaKg72vU+Wby3eddPsA==} + + micromark-util-html-tag-name@2.0.0: + resolution: {integrity: sha512-xNn4Pqkj2puRhKdKTm8t1YHC/BAjx6CEwRFXntTaRf/x16aqka6ouVoutm+QdkISTlT7e2zU7U4ZdlDLJd2Mcw==} + + micromark-util-normalize-identifier@2.0.0: + resolution: {integrity: sha512-2xhYT0sfo85FMrUPtHcPo2rrp1lwbDEEzpx7jiH2xXJLqBuy4H0GgXk5ToU8IEwoROtXuL8ND0ttVa4rNqYK3w==} + + micromark-util-resolve-all@2.0.0: + resolution: {integrity: sha512-6KU6qO7DZ7GJkaCgwBNtplXCvGkJToU86ybBAUdavvgsCiG8lSSvYxr9MhwmQ+udpzywHsl4RpGJsYWG1pDOcA==} + + micromark-util-sanitize-uri@2.0.0: + resolution: {integrity: sha512-WhYv5UEcZrbAtlsnPuChHUAsu/iBPOVaEVsntLBIdpibO0ddy8OzavZz3iL2xVvBZOpolujSliP65Kq0/7KIYw==} + + micromark-util-subtokenize@2.0.1: + resolution: {integrity: sha512-jZNtiFl/1aY73yS3UGQkutD0UbhTt68qnRpw2Pifmz5wV9h8gOVsN70v+Lq/f1rKaU/W8pxRe8y8Q9FX1AOe1Q==} + + micromark-util-symbol@2.0.0: + resolution: {integrity: sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==} + + micromark-util-types@2.0.0: + resolution: {integrity: sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w==} + + micromark@4.0.0: + resolution: {integrity: sha512-o/sd0nMof8kYff+TqcDx3VSrgBTcZpSvYcAHIfHhv5VAuNmisCxjhx6YmxS8PFEpb9z5WKWKPdzf0jM23ro3RQ==} + + micromatch@4.0.7: + resolution: {integrity: sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==} + engines: {node: '>=8.6'} + + minimatch@10.0.1: + resolution: {integrity: sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==} + engines: {node: 20 || >=22} + + minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + + minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + + minipass@7.1.2: + resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} + engines: {node: '>=16 || 14 >=14.17'} + + ms@2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + + mz@2.7.0: + resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + node-emoji@2.1.3: + resolution: {integrity: sha512-E2WEOVsgs7O16zsURJ/eH8BqhF029wGpEOnv7Urwdo2wmQanOACwJQh0devF9D9RhoZru0+9JXIS0dBXIAz+lA==} + engines: {node: '>=18'} + + node-test-github-reporter@1.2.0: + resolution: {integrity: sha512-rnCQctMTPAqJrOhaHaj60IMS5qB5B2rusCGv7RIbY6FsTKjaRmS4OBKCVQb3kYdMNqj0Fw9btDOZkCi3OFHx/g==} + + node-test-parser@2.2.2: + resolution: {integrity: sha512-Cbe0pabtJaZOrjvCguHe9kZLDrHZpRr+4+JO29hNf143qFUhGn6Xn5HxwQmh4vmyyLFlF2YmnJGIwfEX+aQ7mw==} + + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + engines: {node: '>= 0.8.0'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + + package-json-from-dist@1.0.0: + resolution: {integrity: sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==} + + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + + parse5-htmlparser2-tree-adapter@6.0.1: + resolution: {integrity: sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==} + + parse5@5.1.1: + resolution: {integrity: sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==} + + parse5@6.0.1: + resolution: {integrity: sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + 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@1.11.1: + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} + + path-scurry@2.0.0: + resolution: {integrity: sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==} + engines: {node: 20 || >=22} + + path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + pkgroll@2.1.1: + resolution: {integrity: sha512-ZQjWkcfY+RvzQhavoOvXZ6UvYZL8qwJjGoJvU2yrTwfUybL9QG4SblhYXV+uRwh0GRRvo1JtEg0htzD0RGr9CA==} + engines: {node: '>=18'} + hasBin: true + peerDependencies: + typescript: ^4.1 || ^5.0 + peerDependenciesMeta: + typescript: + optional: true + + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + + prettier@3.3.2: + resolution: {integrity: sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==} + engines: {node: '>=14'} + hasBin: true + + pretty-format@29.7.0: + resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + react-is@18.3.1: + resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} + + redeyed@2.1.1: + resolution: {integrity: sha512-FNpGGo1DycYAdnrKFxCMmKYgo/mILAqtRYbkdQD8Ep/Hk2PQ5+aEAEx+IU713RTDmuBaH0c8P5ZozurNu5ObRQ==} + + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + + resolve@1.22.8: + resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} + hasBin: true + + reusify@1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + rollup@4.18.1: + resolution: {integrity: sha512-Elx2UT8lzxxOXMpy5HWQGZqkrQOtrVDDa/bm9l10+U4rQnVzbL/LgZ4NOM1MPIDyHk69W4InuYDF5dzRh4Kw1A==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + semver@7.6.2: + resolution: {integrity: sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==} + engines: {node: '>=10'} + hasBin: true + + 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@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + + skin-tone@2.0.0: + resolution: {integrity: sha512-kUMbT1oBJCpgrnKoSr0o6wPtvRWT9W9UKvGLwfJYO2WuahZRHOpEyL1ckyMGgMWh0UdpmaoFqKKD29WTomNEGA==} + engines: {node: '>=8'} + + slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + + slash@4.0.0: + resolution: {integrity: sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==} + engines: {node: '>=12'} + + stack-utils@2.0.6: + resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} + engines: {node: '>=10'} + + stackframe@1.3.4: + resolution: {integrity: sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-ansi@7.1.0: + resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} + engines: {node: '>=12'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + supports-hyperlinks@2.3.0: + resolution: {integrity: sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==} + engines: {node: '>=8'} + + supports-hyperlinks@3.0.0: + resolution: {integrity: sha512-QBDPHyPQDRTy9ku4URNGY5Lah8PAaXs6tAAwp55sL5WCsSW7GIfdf6W5ixfziW+t7wh3GVvHyHHyQ1ESsoRvaA==} + engines: {node: '>=14.18'} + + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + terminal-link@3.0.0: + resolution: {integrity: sha512-flFL3m4wuixmf6IfhFJd1YPiLiMuxEc8uHRM1buzIeZPm22Au2pDqBJQgdo7n1WfPU1ONFGv7YDwpFBmHGF6lg==} + engines: {node: '>=12'} + + text-table@0.2.0: + resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + + 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==} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + ts-api-utils@1.3.0: + resolution: {integrity: sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==} + engines: {node: '>=16'} + peerDependencies: + typescript: '>=4.2.0' + + ts-expose-internals-conditionally@1.0.0-empty.0: + resolution: {integrity: sha512-F8m9NOF6ZhdOClDVdlM8gj3fDCav4ZIFSs/EI3ksQbAAXVSCN/Jh5OCJDDZWBuBy9psFc6jULGDlPwjMYMhJDw==} + + tsx@4.16.2: + resolution: {integrity: sha512-C1uWweJDgdtX2x600HjaFaucXTilT7tgUZHbOE4+ypskZ1OP8CRCSDkCxG6Vya9EwaFIVagWwpaVAn5wzypaqQ==} + engines: {node: '>=18.0.0'} + hasBin: true + + tunnel@0.0.6: + resolution: {integrity: sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==} + engines: {node: '>=0.6.11 <=0.7.0 || >=0.7.3'} + + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + + type-fest@1.4.0: + resolution: {integrity: sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==} + engines: {node: '>=10'} + + typescript-eslint-language-service@5.0.5: + resolution: {integrity: sha512-b7gWXpwSTqMVKpPX3WttNZEyVAMKs/2jsHKF79H+qaD6mjzCyU5jboJe/lOZgLJD+QRsXCr0GjIVxvl5kI1NMw==} + peerDependencies: + '@typescript-eslint/parser': '>= 5.0.0' + eslint: '>= 8.0.0' + typescript: '>= 4.0.0' + + typescript-eslint@8.0.0-alpha.41: + resolution: {integrity: sha512-+e7D2XDZeHLe9D3bP7S0Va8YdLHzn3YcesoxMS9SjMWhtaSb5ylxk2txqT84sUS0WIDQetZlvDg2/UmY5B/ycg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + typescript@5.3.3: + resolution: {integrity: sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==} + engines: {node: '>=14.17'} + hasBin: true + + typescript@5.5.3: + resolution: {integrity: sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==} + engines: {node: '>=14.17'} + hasBin: true + + undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + + undici@5.28.4: + resolution: {integrity: sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==} + engines: {node: '>=14.0'} + + unicode-emoji-modifier-base@1.0.0: + resolution: {integrity: sha512-yLSH4py7oFH3oG/9K+XWrz1pSi3dfUrWEnInbxMfArOfc1+33BlGPQtLsOYwvdMy11AwUBetYuaRxSPqgkq+8g==} + engines: {node: '>=4'} + + unist-util-is@6.0.0: + resolution: {integrity: sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==} + + unist-util-stringify-position@4.0.0: + resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} + + unist-util-visit-parents@6.0.1: + resolution: {integrity: sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==} + + unist-util-visit@5.0.0: + resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==} + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + uuid@8.3.2: + resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} + hasBin: true + + validate-npm-package-name@5.0.1: + resolution: {integrity: sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + + yargs-parser@20.2.9: + resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} + engines: {node: '>=10'} + + yargs@16.2.0: + resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} + engines: {node: '>=10'} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + + zwitch@2.0.4: + resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} + +snapshots: + + '@actions/core@1.10.1': + dependencies: + '@actions/http-client': 2.2.1 + uuid: 8.3.2 + + '@actions/http-client@2.2.1': + dependencies: + tunnel: 0.0.6 + undici: 5.28.4 + + '@andrewbranch/untar.js@1.0.3': {} + + '@arethetypeswrong/cli@0.15.3': + dependencies: + '@arethetypeswrong/core': 0.15.1 + chalk: 4.1.2 + cli-table3: 0.6.5 + commander: 10.0.1 + marked: 9.1.6 + marked-terminal: 6.2.0(marked@9.1.6) + semver: 7.6.2 + + '@arethetypeswrong/core@0.15.1': + dependencies: + '@andrewbranch/untar.js': 1.0.3 + fflate: 0.8.2 + semver: 7.6.2 + ts-expose-internals-conditionally: 1.0.0-empty.0 + typescript: 5.3.3 + validate-npm-package-name: 5.0.1 + + '@colors/colors@1.5.0': + optional: true + + '@esbuild/aix-ppc64@0.20.2': + optional: true + + '@esbuild/aix-ppc64@0.21.5': + optional: true + + '@esbuild/android-arm64@0.20.2': + optional: true + + '@esbuild/android-arm64@0.21.5': + optional: true + + '@esbuild/android-arm@0.20.2': + optional: true + + '@esbuild/android-arm@0.21.5': + optional: true + + '@esbuild/android-x64@0.20.2': + optional: true + + '@esbuild/android-x64@0.21.5': + optional: true + + '@esbuild/darwin-arm64@0.20.2': + optional: true + + '@esbuild/darwin-arm64@0.21.5': + optional: true + + '@esbuild/darwin-x64@0.20.2': + optional: true + + '@esbuild/darwin-x64@0.21.5': + optional: true + + '@esbuild/freebsd-arm64@0.20.2': + optional: true + + '@esbuild/freebsd-arm64@0.21.5': + optional: true + + '@esbuild/freebsd-x64@0.20.2': + optional: true + + '@esbuild/freebsd-x64@0.21.5': + optional: true + + '@esbuild/linux-arm64@0.20.2': + optional: true + + '@esbuild/linux-arm64@0.21.5': + optional: true + + '@esbuild/linux-arm@0.20.2': + optional: true + + '@esbuild/linux-arm@0.21.5': + optional: true + + '@esbuild/linux-ia32@0.20.2': + optional: true + + '@esbuild/linux-ia32@0.21.5': + optional: true + + '@esbuild/linux-loong64@0.20.2': + optional: true + + '@esbuild/linux-loong64@0.21.5': + optional: true + + '@esbuild/linux-mips64el@0.20.2': + optional: true + + '@esbuild/linux-mips64el@0.21.5': + optional: true + + '@esbuild/linux-ppc64@0.20.2': + optional: true + + '@esbuild/linux-ppc64@0.21.5': + optional: true + + '@esbuild/linux-riscv64@0.20.2': + optional: true + + '@esbuild/linux-riscv64@0.21.5': + optional: true + + '@esbuild/linux-s390x@0.20.2': + optional: true + + '@esbuild/linux-s390x@0.21.5': + optional: true + + '@esbuild/linux-x64@0.20.2': + optional: true + + '@esbuild/linux-x64@0.21.5': + optional: true + + '@esbuild/netbsd-x64@0.20.2': + optional: true + + '@esbuild/netbsd-x64@0.21.5': + optional: true + + '@esbuild/openbsd-x64@0.20.2': + optional: true + + '@esbuild/openbsd-x64@0.21.5': + optional: true + + '@esbuild/sunos-x64@0.20.2': + optional: true + + '@esbuild/sunos-x64@0.21.5': + optional: true + + '@esbuild/win32-arm64@0.20.2': + optional: true + + '@esbuild/win32-arm64@0.21.5': + optional: true + + '@esbuild/win32-ia32@0.20.2': + optional: true + + '@esbuild/win32-ia32@0.21.5': + optional: true + + '@esbuild/win32-x64@0.20.2': + optional: true + + '@esbuild/win32-x64@0.21.5': + optional: true + + '@eslint-community/eslint-utils@4.4.0(eslint@9.6.0)': + dependencies: + eslint: 9.6.0 + eslint-visitor-keys: 3.4.3 + + '@eslint-community/regexpp@4.11.0': {} + + '@eslint/config-array@0.17.0': + dependencies: + '@eslint/object-schema': 2.1.4 + debug: 4.3.5 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + + '@eslint/eslintrc@3.1.0': + dependencies: + ajv: 6.12.6 + debug: 4.3.5 + espree: 10.1.0 + globals: 14.0.0 + ignore: 5.3.1 + import-fresh: 3.3.0 + js-yaml: 4.1.0 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + '@eslint/js@9.6.0': {} + + '@eslint/object-schema@2.1.4': {} + + '@fastify/busboy@2.1.1': {} + + '@humanwhocodes/module-importer@1.0.1': {} + + '@humanwhocodes/retry@0.3.0': {} + + '@isaacs/cliui@8.0.2': + dependencies: + string-width: 5.1.2 + string-width-cjs: string-width@4.2.3 + strip-ansi: 7.1.0 + strip-ansi-cjs: strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: wrap-ansi@7.0.0 + + '@jest/schemas@29.6.3': + dependencies: + '@sinclair/typebox': 0.27.8 + + '@jridgewell/sourcemap-codec@1.5.0': {} + + '@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.17.1 + + '@pkgjs/parseargs@0.11.0': + optional: true + + '@rollup/plugin-alias@5.1.0(rollup@4.18.1)': + dependencies: + slash: 4.0.0 + optionalDependencies: + rollup: 4.18.1 + + '@rollup/plugin-commonjs@26.0.1(rollup@4.18.1)': + dependencies: + '@rollup/pluginutils': 5.1.0(rollup@4.18.1) + commondir: 1.0.1 + estree-walker: 2.0.2 + glob: 10.4.5 + is-reference: 1.2.1 + magic-string: 0.30.10 + optionalDependencies: + rollup: 4.18.1 + + '@rollup/plugin-inject@5.0.5(rollup@4.18.1)': + dependencies: + '@rollup/pluginutils': 5.1.0(rollup@4.18.1) + estree-walker: 2.0.2 + magic-string: 0.30.10 + optionalDependencies: + rollup: 4.18.1 + + '@rollup/plugin-json@6.1.0(rollup@4.18.1)': + dependencies: + '@rollup/pluginutils': 5.1.0(rollup@4.18.1) + optionalDependencies: + rollup: 4.18.1 + + '@rollup/plugin-node-resolve@15.2.3(rollup@4.18.1)': + dependencies: + '@rollup/pluginutils': 5.1.0(rollup@4.18.1) + '@types/resolve': 1.20.2 + deepmerge: 4.3.1 + is-builtin-module: 3.2.1 + is-module: 1.0.0 + resolve: 1.22.8 + optionalDependencies: + rollup: 4.18.1 + + '@rollup/plugin-replace@5.0.7(rollup@4.18.1)': + dependencies: + '@rollup/pluginutils': 5.1.0(rollup@4.18.1) + magic-string: 0.30.10 + optionalDependencies: + rollup: 4.18.1 + + '@rollup/pluginutils@5.1.0(rollup@4.18.1)': + dependencies: + '@types/estree': 1.0.5 + estree-walker: 2.0.2 + picomatch: 2.3.1 + optionalDependencies: + rollup: 4.18.1 + + '@rollup/rollup-android-arm-eabi@4.18.1': + optional: true + + '@rollup/rollup-android-arm64@4.18.1': + optional: true + + '@rollup/rollup-darwin-arm64@4.18.1': + optional: true + + '@rollup/rollup-darwin-x64@4.18.1': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.18.1': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.18.1': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.18.1': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.18.1': + optional: true + + '@rollup/rollup-linux-powerpc64le-gnu@4.18.1': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.18.1': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.18.1': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.18.1': + optional: true + + '@rollup/rollup-linux-x64-musl@4.18.1': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.18.1': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.18.1': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.18.1': + optional: true + + '@sinclair/typebox@0.27.8': {} + + '@sindresorhus/is@4.6.0': {} + + '@types/debug@4.1.12': + dependencies: + '@types/ms': 0.7.34 + + '@types/eslint@8.56.10': + dependencies: + '@types/estree': 1.0.5 + '@types/json-schema': 7.0.15 + + '@types/eslint__js@8.42.3': + dependencies: + '@types/eslint': 8.56.10 + + '@types/estree@1.0.5': {} + + '@types/json-schema@7.0.15': {} + + '@types/mdast@4.0.4': + dependencies: + '@types/unist': 3.0.2 + + '@types/ms@0.7.34': {} + + '@types/node@20.14.10': + dependencies: + undici-types: 5.26.5 + + '@types/resolve@1.20.2': {} + + '@types/unist@3.0.2': {} + + '@typescript-eslint/eslint-plugin@8.0.0-alpha.41(@typescript-eslint/parser@8.0.0-alpha.41(eslint@9.6.0)(typescript@5.5.3))(eslint@9.6.0)(typescript@5.5.3)': + dependencies: + '@eslint-community/regexpp': 4.11.0 + '@typescript-eslint/parser': 8.0.0-alpha.41(eslint@9.6.0)(typescript@5.5.3) + '@typescript-eslint/scope-manager': 8.0.0-alpha.41 + '@typescript-eslint/type-utils': 8.0.0-alpha.41(eslint@9.6.0)(typescript@5.5.3) + '@typescript-eslint/utils': 8.0.0-alpha.41(eslint@9.6.0)(typescript@5.5.3) + '@typescript-eslint/visitor-keys': 8.0.0-alpha.41 + eslint: 9.6.0 + graphemer: 1.4.0 + ignore: 5.3.1 + natural-compare: 1.4.0 + ts-api-utils: 1.3.0(typescript@5.5.3) + optionalDependencies: + typescript: 5.5.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@8.0.0-alpha.41(eslint@9.6.0)(typescript@5.5.3)': + dependencies: + '@typescript-eslint/scope-manager': 8.0.0-alpha.41 + '@typescript-eslint/types': 8.0.0-alpha.41 + '@typescript-eslint/typescript-estree': 8.0.0-alpha.41(typescript@5.5.3) + '@typescript-eslint/visitor-keys': 8.0.0-alpha.41 + debug: 4.3.5 + eslint: 9.6.0 + optionalDependencies: + typescript: 5.5.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/scope-manager@8.0.0-alpha.41': + dependencies: + '@typescript-eslint/types': 8.0.0-alpha.41 + '@typescript-eslint/visitor-keys': 8.0.0-alpha.41 + + '@typescript-eslint/type-utils@8.0.0-alpha.41(eslint@9.6.0)(typescript@5.5.3)': + dependencies: + '@typescript-eslint/typescript-estree': 8.0.0-alpha.41(typescript@5.5.3) + '@typescript-eslint/utils': 8.0.0-alpha.41(eslint@9.6.0)(typescript@5.5.3) + debug: 4.3.5 + ts-api-utils: 1.3.0(typescript@5.5.3) + optionalDependencies: + typescript: 5.5.3 + transitivePeerDependencies: + - eslint + - supports-color + + '@typescript-eslint/types@8.0.0-alpha.41': {} + + '@typescript-eslint/typescript-estree@8.0.0-alpha.41(typescript@5.5.3)': + dependencies: + '@typescript-eslint/types': 8.0.0-alpha.41 + '@typescript-eslint/visitor-keys': 8.0.0-alpha.41 + debug: 4.3.5 + globby: 11.1.0 + is-glob: 4.0.3 + minimatch: 9.0.5 + semver: 7.6.2 + ts-api-utils: 1.3.0(typescript@5.5.3) + optionalDependencies: + typescript: 5.5.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@8.0.0-alpha.41(eslint@9.6.0)(typescript@5.5.3)': + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@9.6.0) + '@typescript-eslint/scope-manager': 8.0.0-alpha.41 + '@typescript-eslint/types': 8.0.0-alpha.41 + '@typescript-eslint/typescript-estree': 8.0.0-alpha.41(typescript@5.5.3) + eslint: 9.6.0 + transitivePeerDependencies: + - supports-color + - typescript + + '@typescript-eslint/visitor-keys@8.0.0-alpha.41': + dependencies: + '@typescript-eslint/types': 8.0.0-alpha.41 + eslint-visitor-keys: 3.4.3 + + '@voxpelli/node-test-pretty-reporter@1.1.2': + dependencies: + clean-stack: 5.2.0 + jest-diff: 29.7.0 + markdown-or-chalk: 0.2.1 + transitivePeerDependencies: + - supports-color + + acorn-jsx@5.3.2(acorn@8.12.1): + dependencies: + acorn: 8.12.1 + + acorn@8.12.1: {} + + ajv@6.12.6: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + + ansi-escapes@5.0.0: + dependencies: + type-fest: 1.4.0 + + ansi-escapes@6.2.1: {} + + ansi-regex@5.0.1: {} + + ansi-regex@6.0.1: {} + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + ansi-styles@5.2.0: {} + + ansi-styles@6.2.1: {} + + ansicolors@0.3.2: {} + + any-promise@1.3.0: {} + + argparse@2.0.1: {} + + array-union@2.1.0: {} + + balanced-match@1.0.2: {} + + brace-expansion@1.1.11: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@2.0.1: + dependencies: + balanced-match: 1.0.2 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + builtin-modules@3.3.0: {} + + callsites@3.1.0: {} + + cardinal@2.1.1: + dependencies: + ansicolors: 0.3.2 + redeyed: 2.1.1 + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + chalk@5.3.0: {} + + char-regex@1.0.2: {} + + character-entities@2.0.2: {} + + clean-publish@5.0.0: + dependencies: + cross-spawn: 7.0.3 + fast-glob: 3.3.2 + lilconfig: 3.1.2 + micromatch: 4.0.7 + + clean-stack@5.2.0: + dependencies: + escape-string-regexp: 5.0.0 + + cli-highlight@2.1.11: + dependencies: + chalk: 4.1.2 + highlight.js: 10.7.3 + mz: 2.7.0 + parse5: 5.1.1 + parse5-htmlparser2-tree-adapter: 6.0.1 + yargs: 16.2.0 + + cli-table3@0.6.5: + dependencies: + string-width: 4.2.3 + optionalDependencies: + '@colors/colors': 1.5.0 + + cliui@7.0.4: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + commander@10.0.1: {} + + commondir@1.0.1: {} + + concat-map@0.0.1: {} + + cross-spawn@7.0.3: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + debug@4.3.5: + dependencies: + ms: 2.1.2 + + decode-named-character-reference@1.0.2: + dependencies: + character-entities: 2.0.2 + + deep-is@0.1.4: {} + + deepmerge@4.3.1: {} + + dequal@2.0.3: {} + + devlop@1.1.0: + dependencies: + dequal: 2.0.3 + + diff-sequences@29.6.3: {} + + dir-glob@3.0.1: + dependencies: + path-type: 4.0.0 + + eastasianwidth@0.2.0: {} + + emoji-regex@8.0.0: {} + + emoji-regex@9.2.2: {} + + emojilib@2.4.0: {} + + error-stack-parser@2.1.4: + dependencies: + stackframe: 1.3.4 + + esbuild@0.20.2: + optionalDependencies: + '@esbuild/aix-ppc64': 0.20.2 + '@esbuild/android-arm': 0.20.2 + '@esbuild/android-arm64': 0.20.2 + '@esbuild/android-x64': 0.20.2 + '@esbuild/darwin-arm64': 0.20.2 + '@esbuild/darwin-x64': 0.20.2 + '@esbuild/freebsd-arm64': 0.20.2 + '@esbuild/freebsd-x64': 0.20.2 + '@esbuild/linux-arm': 0.20.2 + '@esbuild/linux-arm64': 0.20.2 + '@esbuild/linux-ia32': 0.20.2 + '@esbuild/linux-loong64': 0.20.2 + '@esbuild/linux-mips64el': 0.20.2 + '@esbuild/linux-ppc64': 0.20.2 + '@esbuild/linux-riscv64': 0.20.2 + '@esbuild/linux-s390x': 0.20.2 + '@esbuild/linux-x64': 0.20.2 + '@esbuild/netbsd-x64': 0.20.2 + '@esbuild/openbsd-x64': 0.20.2 + '@esbuild/sunos-x64': 0.20.2 + '@esbuild/win32-arm64': 0.20.2 + '@esbuild/win32-ia32': 0.20.2 + '@esbuild/win32-x64': 0.20.2 + + esbuild@0.21.5: + optionalDependencies: + '@esbuild/aix-ppc64': 0.21.5 + '@esbuild/android-arm': 0.21.5 + '@esbuild/android-arm64': 0.21.5 + '@esbuild/android-x64': 0.21.5 + '@esbuild/darwin-arm64': 0.21.5 + '@esbuild/darwin-x64': 0.21.5 + '@esbuild/freebsd-arm64': 0.21.5 + '@esbuild/freebsd-x64': 0.21.5 + '@esbuild/linux-arm': 0.21.5 + '@esbuild/linux-arm64': 0.21.5 + '@esbuild/linux-ia32': 0.21.5 + '@esbuild/linux-loong64': 0.21.5 + '@esbuild/linux-mips64el': 0.21.5 + '@esbuild/linux-ppc64': 0.21.5 + '@esbuild/linux-riscv64': 0.21.5 + '@esbuild/linux-s390x': 0.21.5 + '@esbuild/linux-x64': 0.21.5 + '@esbuild/netbsd-x64': 0.21.5 + '@esbuild/openbsd-x64': 0.21.5 + '@esbuild/sunos-x64': 0.21.5 + '@esbuild/win32-arm64': 0.21.5 + '@esbuild/win32-ia32': 0.21.5 + '@esbuild/win32-x64': 0.21.5 + + escalade@3.1.2: {} + + escape-string-regexp@2.0.0: {} + + escape-string-regexp@4.0.0: {} + + escape-string-regexp@5.0.0: {} + + eslint-scope@8.0.1: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-visitor-keys@3.4.3: {} + + eslint-visitor-keys@4.0.0: {} + + eslint@9.6.0: + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@9.6.0) + '@eslint-community/regexpp': 4.11.0 + '@eslint/config-array': 0.17.0 + '@eslint/eslintrc': 3.1.0 + '@eslint/js': 9.6.0 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.3.0 + '@nodelib/fs.walk': 1.2.8 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.3 + debug: 4.3.5 + escape-string-regexp: 4.0.0 + eslint-scope: 8.0.1 + eslint-visitor-keys: 4.0.0 + espree: 10.1.0 + esquery: 1.6.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 8.0.0 + find-up: 5.0.0 + glob-parent: 6.0.2 + ignore: 5.3.1 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + is-path-inside: 3.0.3 + json-stable-stringify-without-jsonify: 1.0.1 + levn: 0.4.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.4 + strip-ansi: 6.0.1 + text-table: 0.2.0 + transitivePeerDependencies: + - supports-color + + espree@10.1.0: + dependencies: + acorn: 8.12.1 + acorn-jsx: 5.3.2(acorn@8.12.1) + eslint-visitor-keys: 4.0.0 + + esprima@4.0.1: {} + + esquery@1.6.0: + dependencies: + estraverse: 5.3.0 + + esrecurse@4.3.0: + dependencies: + estraverse: 5.3.0 + + estraverse@5.3.0: {} + + estree-walker@2.0.2: {} + + esutils@2.0.3: {} + + fast-deep-equal@3.1.3: {} + + fast-glob@3.3.2: + 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.7 + + fast-json-stable-stringify@2.1.0: {} + + fast-levenshtein@2.0.6: {} + + fastq@1.17.1: + dependencies: + reusify: 1.0.4 + + fflate@0.8.2: {} + + file-entry-cache@8.0.0: + dependencies: + flat-cache: 4.0.1 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + flat-cache@4.0.1: + dependencies: + flatted: 3.3.1 + keyv: 4.5.4 + + flatted@3.3.1: {} + + foreground-child@3.2.1: + dependencies: + cross-spawn: 7.0.3 + signal-exit: 4.1.0 + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + get-caller-file@2.0.5: {} + + get-tsconfig@4.7.5: + dependencies: + resolve-pkg-maps: 1.0.0 + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + glob@10.4.5: + dependencies: + foreground-child: 3.2.1 + jackspeak: 3.4.3 + minimatch: 9.0.5 + minipass: 7.1.2 + package-json-from-dist: 1.0.0 + path-scurry: 1.11.1 + + glob@11.0.0: + dependencies: + foreground-child: 3.2.1 + jackspeak: 4.0.1 + minimatch: 10.0.1 + minipass: 7.1.2 + package-json-from-dist: 1.0.0 + path-scurry: 2.0.0 + + globals@14.0.0: {} + + globby@11.1.0: + dependencies: + array-union: 2.1.0 + dir-glob: 3.0.1 + fast-glob: 3.3.2 + ignore: 5.3.1 + merge2: 1.4.1 + slash: 3.0.0 + + graphemer@1.4.0: {} + + has-flag@4.0.0: {} + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + highlight.js@10.7.3: {} + + ignore@5.3.1: {} + + import-fresh@3.3.0: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + imurmurhash@0.1.4: {} + + is-builtin-module@3.2.1: + dependencies: + builtin-modules: 3.3.0 + + is-core-module@2.14.0: + dependencies: + hasown: 2.0.2 + + is-extglob@2.1.1: {} + + is-fullwidth-code-point@3.0.0: {} + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-module@1.0.0: {} + + is-number@7.0.0: {} + + is-path-inside@3.0.3: {} + + is-reference@1.2.1: + dependencies: + '@types/estree': 1.0.5 + + is-unicode-supported@2.0.0: {} + + isexe@2.0.0: {} + + jackspeak@3.4.3: + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + + jackspeak@4.0.1: + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + + 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-get-type@29.6.3: {} + + js-yaml@4.1.0: + dependencies: + argparse: 2.0.1 + + json-buffer@3.0.1: {} + + json-schema-traverse@0.4.1: {} + + json-stable-stringify-without-jsonify@1.0.1: {} + + keyv@4.5.4: + dependencies: + json-buffer: 3.0.1 + + levn@0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + + lilconfig@3.1.2: {} + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + + lodash.merge@4.6.2: {} + + longest-streak@3.1.0: {} + + lru-cache@10.4.3: {} + + lru-cache@11.0.0: {} + + magic-string@0.30.10: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.0 + + markdown-or-chalk@0.2.1: + dependencies: + '@types/mdast': 4.0.4 + chalk: 5.3.0 + cli-highlight: 2.1.11 + is-unicode-supported: 2.0.0 + mdast-util-gfm-table: 2.0.0 + mdast-util-to-markdown: 2.1.0 + mdast-util-to-string: 4.0.0 + strip-ansi: 7.1.0 + terminal-link: 3.0.0 + transitivePeerDependencies: + - supports-color + + markdown-table@3.0.3: {} + + marked-terminal@6.2.0(marked@9.1.6): + dependencies: + ansi-escapes: 6.2.1 + cardinal: 2.1.1 + chalk: 5.3.0 + cli-table3: 0.6.5 + marked: 9.1.6 + node-emoji: 2.1.3 + supports-hyperlinks: 3.0.0 + + marked@9.1.6: {} + + mdast-util-from-markdown@2.0.1: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.2 + decode-named-character-reference: 1.0.2 + devlop: 1.1.0 + mdast-util-to-string: 4.0.0 + micromark: 4.0.0 + micromark-util-decode-numeric-character-reference: 2.0.1 + micromark-util-decode-string: 2.0.0 + micromark-util-normalize-identifier: 2.0.0 + micromark-util-symbol: 2.0.0 + micromark-util-types: 2.0.0 + unist-util-stringify-position: 4.0.0 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-table@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + markdown-table: 3.0.3 + mdast-util-from-markdown: 2.0.1 + mdast-util-to-markdown: 2.1.0 + transitivePeerDependencies: + - supports-color + + mdast-util-phrasing@4.1.0: + dependencies: + '@types/mdast': 4.0.4 + unist-util-is: 6.0.0 + + mdast-util-to-markdown@2.1.0: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.2 + longest-streak: 3.1.0 + mdast-util-phrasing: 4.1.0 + mdast-util-to-string: 4.0.0 + micromark-util-decode-string: 2.0.0 + unist-util-visit: 5.0.0 + zwitch: 2.0.4 + + mdast-util-to-string@4.0.0: + dependencies: + '@types/mdast': 4.0.4 + + merge2@1.4.1: {} + + micromark-core-commonmark@2.0.1: + dependencies: + decode-named-character-reference: 1.0.2 + devlop: 1.1.0 + micromark-factory-destination: 2.0.0 + micromark-factory-label: 2.0.0 + micromark-factory-space: 2.0.0 + micromark-factory-title: 2.0.0 + micromark-factory-whitespace: 2.0.0 + micromark-util-character: 2.1.0 + micromark-util-chunked: 2.0.0 + micromark-util-classify-character: 2.0.0 + micromark-util-html-tag-name: 2.0.0 + micromark-util-normalize-identifier: 2.0.0 + micromark-util-resolve-all: 2.0.0 + micromark-util-subtokenize: 2.0.1 + micromark-util-symbol: 2.0.0 + micromark-util-types: 2.0.0 + + micromark-factory-destination@2.0.0: + dependencies: + micromark-util-character: 2.1.0 + micromark-util-symbol: 2.0.0 + micromark-util-types: 2.0.0 + + micromark-factory-label@2.0.0: + dependencies: + devlop: 1.1.0 + micromark-util-character: 2.1.0 + micromark-util-symbol: 2.0.0 + micromark-util-types: 2.0.0 + + micromark-factory-space@2.0.0: + dependencies: + micromark-util-character: 2.1.0 + micromark-util-types: 2.0.0 + + micromark-factory-title@2.0.0: + dependencies: + micromark-factory-space: 2.0.0 + micromark-util-character: 2.1.0 + micromark-util-symbol: 2.0.0 + micromark-util-types: 2.0.0 + + micromark-factory-whitespace@2.0.0: + dependencies: + micromark-factory-space: 2.0.0 + micromark-util-character: 2.1.0 + micromark-util-symbol: 2.0.0 + micromark-util-types: 2.0.0 + + micromark-util-character@2.1.0: + dependencies: + micromark-util-symbol: 2.0.0 + micromark-util-types: 2.0.0 + + micromark-util-chunked@2.0.0: + dependencies: + micromark-util-symbol: 2.0.0 + + micromark-util-classify-character@2.0.0: + dependencies: + micromark-util-character: 2.1.0 + micromark-util-symbol: 2.0.0 + micromark-util-types: 2.0.0 + + micromark-util-combine-extensions@2.0.0: + dependencies: + micromark-util-chunked: 2.0.0 + micromark-util-types: 2.0.0 + + micromark-util-decode-numeric-character-reference@2.0.1: + dependencies: + micromark-util-symbol: 2.0.0 + + micromark-util-decode-string@2.0.0: + dependencies: + decode-named-character-reference: 1.0.2 + micromark-util-character: 2.1.0 + micromark-util-decode-numeric-character-reference: 2.0.1 + micromark-util-symbol: 2.0.0 + + micromark-util-encode@2.0.0: {} + + micromark-util-html-tag-name@2.0.0: {} + + micromark-util-normalize-identifier@2.0.0: + dependencies: + micromark-util-symbol: 2.0.0 + + micromark-util-resolve-all@2.0.0: + dependencies: + micromark-util-types: 2.0.0 + + micromark-util-sanitize-uri@2.0.0: + dependencies: + micromark-util-character: 2.1.0 + micromark-util-encode: 2.0.0 + micromark-util-symbol: 2.0.0 + + micromark-util-subtokenize@2.0.1: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.0 + micromark-util-symbol: 2.0.0 + micromark-util-types: 2.0.0 + + micromark-util-symbol@2.0.0: {} + + micromark-util-types@2.0.0: {} + + micromark@4.0.0: + dependencies: + '@types/debug': 4.1.12 + debug: 4.3.5 + decode-named-character-reference: 1.0.2 + devlop: 1.1.0 + micromark-core-commonmark: 2.0.1 + micromark-factory-space: 2.0.0 + micromark-util-character: 2.1.0 + micromark-util-chunked: 2.0.0 + micromark-util-combine-extensions: 2.0.0 + micromark-util-decode-numeric-character-reference: 2.0.1 + micromark-util-encode: 2.0.0 + micromark-util-normalize-identifier: 2.0.0 + micromark-util-resolve-all: 2.0.0 + micromark-util-sanitize-uri: 2.0.0 + micromark-util-subtokenize: 2.0.1 + micromark-util-symbol: 2.0.0 + micromark-util-types: 2.0.0 + transitivePeerDependencies: + - supports-color + + micromatch@4.0.7: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + + minimatch@10.0.1: + dependencies: + brace-expansion: 2.0.1 + + minimatch@3.1.2: + dependencies: + brace-expansion: 1.1.11 + + minimatch@9.0.5: + dependencies: + brace-expansion: 2.0.1 + + minipass@7.1.2: {} + + ms@2.1.2: {} + + mz@2.7.0: + dependencies: + any-promise: 1.3.0 + object-assign: 4.1.1 + thenify-all: 1.6.0 + + natural-compare@1.4.0: {} + + node-emoji@2.1.3: + dependencies: + '@sindresorhus/is': 4.6.0 + char-regex: 1.0.2 + emojilib: 2.4.0 + skin-tone: 2.0.0 + + node-test-github-reporter@1.2.0: + dependencies: + '@actions/core': 1.10.1 + error-stack-parser: 2.1.4 + node-test-parser: 2.2.2 + stack-utils: 2.0.6 + + node-test-parser@2.2.2: {} + + object-assign@4.1.1: {} + + optionator@0.9.4: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.5 + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + + package-json-from-dist@1.0.0: {} + + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + + parse5-htmlparser2-tree-adapter@6.0.1: + dependencies: + parse5: 6.0.1 + + parse5@5.1.1: {} + + parse5@6.0.1: {} + + path-exists@4.0.0: {} + + path-key@3.1.1: {} + + path-parse@1.0.7: {} + + path-scurry@1.11.1: + dependencies: + lru-cache: 10.4.3 + minipass: 7.1.2 + + path-scurry@2.0.0: + dependencies: + lru-cache: 11.0.0 + minipass: 7.1.2 + + path-type@4.0.0: {} + + picomatch@2.3.1: {} + + pkgroll@2.1.1(typescript@5.5.3): + dependencies: + '@rollup/plugin-alias': 5.1.0(rollup@4.18.1) + '@rollup/plugin-commonjs': 26.0.1(rollup@4.18.1) + '@rollup/plugin-inject': 5.0.5(rollup@4.18.1) + '@rollup/plugin-json': 6.1.0(rollup@4.18.1) + '@rollup/plugin-node-resolve': 15.2.3(rollup@4.18.1) + '@rollup/plugin-replace': 5.0.7(rollup@4.18.1) + '@rollup/pluginutils': 5.1.0(rollup@4.18.1) + esbuild: 0.20.2 + magic-string: 0.30.10 + rollup: 4.18.1 + optionalDependencies: + typescript: 5.5.3 + + prelude-ls@1.2.1: {} + + prettier@3.3.2: {} + + pretty-format@29.7.0: + dependencies: + '@jest/schemas': 29.6.3 + ansi-styles: 5.2.0 + react-is: 18.3.1 + + punycode@2.3.1: {} + + queue-microtask@1.2.3: {} + + react-is@18.3.1: {} + + redeyed@2.1.1: + dependencies: + esprima: 4.0.1 + + require-directory@2.1.1: {} + + resolve-from@4.0.0: {} + + resolve-pkg-maps@1.0.0: {} + + resolve@1.22.8: + dependencies: + is-core-module: 2.14.0 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + reusify@1.0.4: {} + + rollup@4.18.1: + dependencies: + '@types/estree': 1.0.5 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.18.1 + '@rollup/rollup-android-arm64': 4.18.1 + '@rollup/rollup-darwin-arm64': 4.18.1 + '@rollup/rollup-darwin-x64': 4.18.1 + '@rollup/rollup-linux-arm-gnueabihf': 4.18.1 + '@rollup/rollup-linux-arm-musleabihf': 4.18.1 + '@rollup/rollup-linux-arm64-gnu': 4.18.1 + '@rollup/rollup-linux-arm64-musl': 4.18.1 + '@rollup/rollup-linux-powerpc64le-gnu': 4.18.1 + '@rollup/rollup-linux-riscv64-gnu': 4.18.1 + '@rollup/rollup-linux-s390x-gnu': 4.18.1 + '@rollup/rollup-linux-x64-gnu': 4.18.1 + '@rollup/rollup-linux-x64-musl': 4.18.1 + '@rollup/rollup-win32-arm64-msvc': 4.18.1 + '@rollup/rollup-win32-ia32-msvc': 4.18.1 + '@rollup/rollup-win32-x64-msvc': 4.18.1 + fsevents: 2.3.3 + + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + + semver@7.6.2: {} + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + signal-exit@4.1.0: {} + + skin-tone@2.0.0: + dependencies: + unicode-emoji-modifier-base: 1.0.0 + + slash@3.0.0: {} + + slash@4.0.0: {} + + stack-utils@2.0.6: + dependencies: + escape-string-regexp: 2.0.0 + + stackframe@1.3.4: {} + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + string-width@5.1.2: + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.1.0 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-ansi@7.1.0: + dependencies: + ansi-regex: 6.0.1 + + strip-json-comments@3.1.1: {} + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + supports-hyperlinks@2.3.0: + dependencies: + has-flag: 4.0.0 + supports-color: 7.2.0 + + supports-hyperlinks@3.0.0: + dependencies: + has-flag: 4.0.0 + supports-color: 7.2.0 + + supports-preserve-symlinks-flag@1.0.0: {} + + terminal-link@3.0.0: + dependencies: + ansi-escapes: 5.0.0 + supports-hyperlinks: 2.3.0 + + text-table@0.2.0: {} + + thenify-all@1.6.0: + dependencies: + thenify: 3.3.1 + + thenify@3.3.1: + dependencies: + any-promise: 1.3.0 + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + ts-api-utils@1.3.0(typescript@5.5.3): + dependencies: + typescript: 5.5.3 + + ts-expose-internals-conditionally@1.0.0-empty.0: {} + + tsx@4.16.2: + dependencies: + esbuild: 0.21.5 + get-tsconfig: 4.7.5 + optionalDependencies: + fsevents: 2.3.3 + + tunnel@0.0.6: {} + + type-check@0.4.0: + dependencies: + prelude-ls: 1.2.1 + + type-fest@1.4.0: {} + + typescript-eslint-language-service@5.0.5(@typescript-eslint/parser@8.0.0-alpha.41(eslint@9.6.0)(typescript@5.5.3))(eslint@9.6.0)(typescript@5.5.3): + dependencies: + '@typescript-eslint/parser': 8.0.0-alpha.41(eslint@9.6.0)(typescript@5.5.3) + eslint: 9.6.0 + typescript: 5.5.3 + + typescript-eslint@8.0.0-alpha.41(eslint@9.6.0)(typescript@5.5.3): + dependencies: + '@typescript-eslint/eslint-plugin': 8.0.0-alpha.41(@typescript-eslint/parser@8.0.0-alpha.41(eslint@9.6.0)(typescript@5.5.3))(eslint@9.6.0)(typescript@5.5.3) + '@typescript-eslint/parser': 8.0.0-alpha.41(eslint@9.6.0)(typescript@5.5.3) + '@typescript-eslint/utils': 8.0.0-alpha.41(eslint@9.6.0)(typescript@5.5.3) + optionalDependencies: + typescript: 5.5.3 + transitivePeerDependencies: + - eslint + - supports-color + + typescript@5.3.3: {} + + typescript@5.5.3: {} + + undici-types@5.26.5: {} + + undici@5.28.4: + dependencies: + '@fastify/busboy': 2.1.1 + + unicode-emoji-modifier-base@1.0.0: {} + + unist-util-is@6.0.0: + dependencies: + '@types/unist': 3.0.2 + + unist-util-stringify-position@4.0.0: + dependencies: + '@types/unist': 3.0.2 + + unist-util-visit-parents@6.0.1: + dependencies: + '@types/unist': 3.0.2 + unist-util-is: 6.0.0 + + unist-util-visit@5.0.0: + dependencies: + '@types/unist': 3.0.2 + unist-util-is: 6.0.0 + unist-util-visit-parents: 6.0.1 + + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + + uuid@8.3.2: {} + + validate-npm-package-name@5.0.1: {} + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + word-wrap@1.2.5: {} + + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrap-ansi@8.1.0: + dependencies: + ansi-styles: 6.2.1 + string-width: 5.1.2 + strip-ansi: 7.1.0 + + y18n@5.0.8: {} + + yargs-parser@20.2.9: {} + + yargs@16.2.0: + dependencies: + cliui: 7.0.4 + escalade: 3.1.2 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 20.2.9 + + yocto-queue@0.1.0: {} + + zwitch@2.0.4: {} diff --git a/src/dag.test.ts b/src/dag.test.ts new file mode 100644 index 0000000..8c8111d --- /dev/null +++ b/src/dag.test.ts @@ -0,0 +1,476 @@ +import assert, { AssertionError } from 'node:assert'; +import { readdir, readFile } from 'node:fs/promises'; +import { join } from 'node:path'; +import { describe, it } from 'node:test'; +import { DAG } from './dag'; + +describe('DAG', () => { + it('should create a new DAG', () => { + const dag = new DAG(); + + assert(dag instanceof DAG); + }); + + it('should create a new DAG with initial nodes', () => { + const dag = new DAG(['A', 'B', 'C']); + + assert.equal(dag.has('A'), true); + assert.equal(dag.has('B'), true); + assert.equal(dag.has('C'), true); + }); + + it('should add a node to the DAG', () => { + const dag = new DAG(); + dag.add('A'); + + assert.equal(dag.has('A'), true); + assert.equal(dag.has('B'), false); + assert.equal(dag.has('C'), false); + + dag.add('B'); + dag.add('C'); + + assert.equal(dag.has('A'), true); + assert.equal(dag.has('B'), true); + assert.equal(dag.has('C'), true); + assert.equal(dag.has('D'), false); + + assert.equal(dag.size, 3); + }); + + it('should remove a node from the DAG', () => { + const dag = new DAG(['A', 'B', 'C']); + + assert.equal(dag.has('A'), true); + assert.equal(dag.has('B'), true); + assert.equal(dag.has('C'), true); + assert.equal(dag.size, 3); + + dag.delete('B'); + + assert.equal(dag.has('A'), true); + assert.equal(dag.has('B'), false); + assert.equal(dag.has('C'), true); + assert.equal(dag.size, 2); + }); + + it('should add an edge to the DAG', () => { + const dag = new DAG(['A', 'B', 'C']); + + dag.addEdge('A', 'B'); + + assert.equal(dag.hasEdge('A', 'B'), true); + assert.equal(dag.hasEdge('B', 'A'), false); + assert.equal(dag.hasEdge('A', 'C'), false); + assert.equal(dag.hasEdge('C', 'A'), false); + + dag.addEdge('B', 'C'); + + assert.equal(dag.hasEdge('A', 'B'), true); + assert.equal(dag.hasEdge('B', 'C'), true); + assert.equal(dag.hasEdge('A', 'C'), false); + assert.equal(dag.hasEdge('C', 'A'), false); + }); + + it('should remove an edge from the DAG', () => { + const dag = new DAG(['A', 'B', 'C']); + + dag.addEdge('A', 'B'); + dag.addEdge('B', 'C'); + + assert.equal(dag.hasEdge('A', 'B'), true); + assert.equal(dag.hasEdge('B', 'C'), true); + + dag.deleteEdge('A', 'B'); + + assert.equal(dag.hasEdge('A', 'B'), false); + assert.equal(dag.hasEdge('B', 'C'), true); + }); + + it('should prevent adding a cycle', () => { + const dag = new DAG(['A', 'B', 'C']); + + dag.addEdge('A', 'B'); + dag.addEdge('B', 'C'); + + assert.throws( + () => { + dag.addEdge('C', 'A'); + }, + { + name: 'CycleError', + message: 'Cycle detected', + }, + ); + + assert.equal(dag.hasEdge('C', 'A'), false); + }); + + it('should return a topological order of the DAG', () => { + const dag = new DAG(['A', 'B', 'C', 'D', 'E']); + + const edges: [string, string][] = [ + ['A', 'B'], + ['A', 'C'], + ['B', 'D'], + ['C', 'D'], + ['D', 'E'], + ]; + + for (const [from, to] of edges) { + dag.addEdge(from, to); + } + + assertTopologicalOrder(edges, dag.order); + }); + + it('should return list of predecessors', () => { + const dag = new DAG(['A', 'B', 'C', 'D', 'E']); + + const edges: [string, string][] = [ + ['A', 'C'], + ['B', 'C'], + ['C', 'D'], + ['A', 'D'], + ['D', 'E'], + ['E', 'F'], + ['B', 'F'], + ['G', 'H'], + ['H', 'I'], + ['C', 'I'], + ]; + + for (const [from, to] of edges) { + dag.addEdge(from, to); + assert.equal(dag.hasEdge(from, to), true); + } + + assertEqualElements(dag.getImmediatePredecessorsOf('D'), ['A', 'C']); + assertEqualElements(dag.getImmediatePredecessorsOf('I'), ['C', 'H']); + + let ordered = Array.from(dag.getOrderedImmediatePredecessorsOf('D', 'I')); + + assertEqualElements(ordered, ['A', 'C', 'H']); + assertTopologicalOrder(edges, ordered); + + assertEqualElements(dag.getPredecessorsOf('D'), ['A', 'B', 'C']); + + ordered = Array.from(dag.getOrderedPredecessorsOf('D', 'I')); + + assertEqualElements(ordered, ['A', 'B', 'C', 'H', 'G']); + assertTopologicalOrder(edges, ordered); + }); + + it('should return list of successors', () => { + const dag = new DAG(['A', 'B', 'C', 'D', 'E']); + + const edges: [string, string][] = [ + ['A', 'C'], + ['B', 'C'], + ['C', 'D'], + ['A', 'D'], + ['D', 'E'], + ['E', 'F'], + ['B', 'F'], + ['G', 'H'], + ['H', 'I'], + ['C', 'I'], + ]; + + for (const [from, to] of edges) { + dag.addEdge(from, to); + assert.equal(dag.hasEdge(from, to), true); + } + + assertEqualElements(dag.getImmediateSuccessorsOf('B'), ['C', 'F']); + assertEqualElements(dag.getImmediateSuccessorsOf('C'), ['D', 'I']); + + let ordered = Array.from(dag.getOrderedImmediateSuccessorsOf('B', 'C')); + + assertEqualElements(ordered, ['D', 'F', 'I']); + assertTopologicalOrder(edges, ordered); + + assertEqualElements(dag.getSuccessorsOf('C'), ['D', 'E', 'F', 'I']); + + ordered = Array.from(dag.getOrderedSuccessorsOf('H', 'A')); + + assertEqualElements(ordered, ['D', 'C', 'I', 'F', 'E']); + assertTopologicalOrder(edges, ordered); + }); + + it('should incrementally update the topological order', async (t) => { + const fixtures = await loadFixtures<{ + nodes: string[]; + edges: [string, string][]; + }>(); + + await Promise.all( + Array.from(fixtures.keys()).map((name) => { + const { nodes, edges } = fixtures.get(name)!; + + return t.test(`${name} (${nodes.length} nodes, ${edges.length} edges)`, () => { + const graph = new DAG(); + + for (const node of nodes) { + graph.add(node); + assert.equal(graph.has(node), true); + } + + const addedEdges: [string, string][] = []; + + for (const [from, to] of edges) { + graph.addEdge(from, to); + assert.equal(graph.hasEdge(from, to), true); + + addedEdges.push([from, to]); + + assertTopologicalOrder( + addedEdges, + graph.order, + `(inserting edge ${from} -> ${to})`, + ); + } + + const { order } = graph; + + assert.equal(order.length, nodes.length); + }); + }), + ); + }); + + it('should decrementally update the topological order', () => { + const graph = new DAG(); + + graph.addEdge('A', 'B'); + graph.addEdge('A', 'D'); + graph.addEdge('B', 'C'); + graph.addEdge('A', 'E'); + graph.addEdge('E', 'F'); + graph.addEdge('D', 'C'); + graph.addEdge('D', 'F'); + graph.addEdge('C', 'F'); + + assertTopologicalOrder( + [ + ['A', 'B'], + ['A', 'D'], + ['B', 'C'], + ['A', 'E'], + ['E', 'F'], + ['D', 'C'], + ['D', 'F'], + ['C', 'F'], + ], + graph.order, + ); + + graph.deleteEdge('D', 'C'); + graph.deleteEdge('A', 'F'); + + assertTopologicalOrder( + [ + ['A', 'B'], + ['A', 'D'], + ['B', 'C'], + ['A', 'E'], + ['D', 'F'], + ['C', 'F'], + ['E', 'F'], + ], + graph.order, + ); + + graph.delete('D'); + + assertTopologicalOrder( + [ + ['A', 'B'], + ['B', 'C'], + ['A', 'E'], + ['C', 'F'], + ], + graph.order, + ); + + assertTopologicalOrder( + [ + ['A', 'C'], + ['B', 'C'], + ['A', 'E'], + ['C', 'F'], + ], + Array.from(graph.getOrderedPredecessorsOf('C', 'E', 'A', 'X', 'Y')), + ); + }); + + it('should merge nodes', () => { + // + // A -> B -> C + // D -> E -> F + // + // "merge" E into B: + // + // A >-+ +-> C + // \ / + // B + // / \ + // D >-+ +-> F + // + const graph = new DAG(); + + graph.addEdge('A', 'B'); + graph.addEdge('B', 'C'); + graph.addEdge('D', 'E'); + graph.addEdge('E', 'F'); + + assertEqualElements(graph.order, ['A', 'B', 'C', 'D', 'E', 'F']); + assertTopologicalOrder( + [ + ['A', 'B'], + ['B', 'C'], + ['D', 'E'], + ['E', 'F'], + ], + graph.order, + ); + + graph.mergeNodes('B', 'E'); + + assertEqualElements(graph.order, ['A', 'B', 'C', 'D', 'F']); + assertTopologicalOrder( + [ + ['A', 'B'], + ['B', 'C'], + ['D', 'B'], + ['B', 'F'], + ], + graph.order, + ); + + graph.mergeNodes('X', 'B'); // no node X + + // nothing changed: + assertEqualElements(graph.order, ['A', 'B', 'C', 'D', 'F']); + assertTopologicalOrder( + [ + ['A', 'B'], + ['B', 'C'], + ['D', 'B'], + ['B', 'F'], + ], + graph.order, + ); + + graph.addEdge('G', 'H'); + graph.addEdge('H', 'B'); + + assertEqualElements(graph.order, ['A', 'B', 'C', 'D', 'F', 'G', 'H']); + assertTopologicalOrder( + [ + ['A', 'B'], + ['B', 'C'], + ['D', 'B'], + ['B', 'F'], + ['G', 'H'], + ['H', 'B'], + ], + graph.order, + ); + + // + // merging F and G should fail (would cycle through B) + // + // A >-+ +-> C + // \ / + // B <- H <- G + // / \ + // D >-+ +-> F + // + + assert.throws( + () => { + graph.mergeNodes('F', 'G'); + }, + { + name: 'CycleError', + message: 'Cycle detected', + }, + ); + + // nothing changed: + assertEqualElements(graph.order, ['A', 'B', 'C', 'D', 'F', 'G', 'H']); + assertTopologicalOrder( + [ + ['A', 'B'], + ['B', 'C'], + ['D', 'B'], + ['B', 'F'], + ['G', 'H'], + ['H', 'B'], + ], + graph.order, + ); + }); +}); + +function assertTopologicalOrder(edges: Iterable<[T, T]>, order: T[], message = ''): void { + const indices = new Map(); + + for (let i = 0; i < order.length; i++) { + indices.set(order[i]!, i); + } + + for (const [from, to] of edges) { + const fromOrder = indices.get(from); + const toOrder = indices.get(to); + + if (fromOrder === undefined || toOrder === undefined) { + continue; + } + + if (fromOrder >= toOrder) { + throw new AssertionError({ + message: `Expected ${String(from)} to come before ${String(to)} in a topological order. ${message}`, + actual: [ + { from, order: fromOrder }, + { to, order: toOrder }, + ], + expected: [ + { from, order: fromOrder }, + { to, order: `>= ${fromOrder + 1}` }, + ], + }); + } + } +} + +function assertEqualElements(a: Iterable, b: Iterable): void { + const actual = new Set(a); + const expected = new Set(b); + + if (actual.size !== expected.size || actual.union(expected).size !== actual.size) { + throw new AssertionError({ + message: 'Expected the same elements', + actual, + expected, + }); + } +} + +async function loadFixtures( + dirname = join(import.meta.dirname, '../fixtures'), +): Promise> { + const result = new Map(); + + for (const entry of await readdir(dirname, { withFileTypes: true })) { + if (!entry.isFile() || !entry.name.endsWith('.json')) { + continue; + } + + const data = await readFile(join(dirname, entry.name), 'utf8'); + result.set(entry.name, JSON.parse(data) as T); + } + + return result; +} diff --git a/src/dag.ts b/src/dag.ts new file mode 100644 index 0000000..79fca56 --- /dev/null +++ b/src/dag.ts @@ -0,0 +1,781 @@ +import { CycleError } from './errors'; +import type { Node } from './internal/node'; +import { byOrder, byValue } from './internal/order'; +import { PriorityQueue } from './internal/priority-queue'; +import { union } from './internal/union'; + +/** + * A Directed Acyclic Graph structure with online cycle detection and topological ordering. + */ +export class DAG { + /** + * The internal state of the graph. + */ + #nodes: Map>; + + /** + * a topological order of the nodes in the graph. + */ + #order: T[]; + + /** + * Creates a new DAG with optional initial nodes. + * + * @param initialNodes - An optional iterable of initial nodes to populate the graph with. + */ + public constructor(initialNodes?: Iterable) { + this.#nodes = new Map(); + this.#order = []; + + if (initialNodes) { + for (const node of initialNodes) { + this.#ensureNodeExists(node); + } + } + } + + /** + * Returns a list of all nodes in the graph in a topological order. + * + * **Note:** for every `U -> V` directed edge, `U` will appear + * before `V` in a topological order. + * + * @return An array of all graph nodes in a topological order. + */ + public get order(): T[] { + return this.#order.slice(0); + } + + /** + * Returns the number of nodes in the graph. + * + * @return Number of nodes in the graph + */ + public get size(): number { + return this.#nodes.size; + } + + /** + * Iterates over all nodes in the graph in a topological order. + * + * @alias keys + * @return An iterator over all nodes in the graph. + */ + [Symbol.iterator](): IterableIterator { + return this.#order[Symbol.iterator](); + } + + /** + * Iterates over all nodes in the graph in a topological order. + * + * @return An iterator over all nodes in the graph. + */ + keys(): IterableIterator { + return this.#order[Symbol.iterator](); + } + + /** + * Creates a new, independent copy of this DAG. + * + * @return Clone of this DAG. + */ + public copy(): DAG { + const clone = new DAG(); + + clone.#order = this.#order.slice(0); + clone.#nodes = new Map(); + + for (const [id, node] of this.#nodes) { + clone.#nodes.set(id, { + id, + order: node.order, + incoming: new Set(node.incoming), + outgoing: new Set(node.outgoing), + }); + } + + return clone; + } + + /** + * Removes all nodes (and their edges) from the graph. + * + * @return This DAG. + */ + public clear(): this { + this.#nodes.clear(); + this.#order.splice(0, this.#order.length); + return this; + } + + /** + * Adds a node to the graph. + * If the node already exists, this is a no-op. + * + * @param node - The node to add. + * @return This DAG. + */ + public add(node: T): this { + this.#ensureNodeExists(node); + return this; + } + + /** + * Checks if a specific node exists in the graph. + * + * @param node - The node to check. + * @return `true` if the node exists, `false` otherwise. + */ + public has(node: T): boolean { + return this.#nodes.has(node); + } + + /** + * Removes a specified node from the graph. + * If such node doesn't exist, this is a no-op. + * + * **Note:** This also removes all edges from or to the specified node. + * + * @param node - The node to remove. + * @return This DAG. + */ + public delete(node: T): this { + const state = this.#nodes.get(node); + + if (state) { + const index = state.order; + const last = this.#order.length - 1; + + for (let i = index; i < last; i++) { + this.#order[i] = this.#order[i + 1]!; + this.#nodes.get(this.#order[i]!)!.order = i; + } + + this.#order.pop(); + + for (const id of state.incoming) { + this.#nodes.get(id)!.outgoing.delete(node); + } + for (const id of state.outgoing) { + this.#nodes.get(id)!.incoming.delete(node); + } + + this.#nodes.delete(node); + } + + return this; + } + + /** + * Tries to add a directed edge to the graph. + * + * If any of the nodes doesn't already exist, it will be added. + * + * If inserting the given edge would introduce a cycle no changes + * are made to the graph and CycleError is thrown. + * + * Adding an edge from a node to that same node (i.e. `from` and `to` are + * the same) is considered a cycle and such edge cannot be added. + * + * @param from - The "source" node. + * @param to - The "target" node. + * @return This DAG. + */ + public addEdge(from: T, to: T): this { + if (from == to) { + throw new CycleError(); + } + + this.#addEdge(from, to); + + return this; + } + + /** + * Tries to add a directed edge to the graph. + * + * If any of the nodes doesn't already exist, it will be added. + * + * If inserting the given edge would introduce a cycle no changes + * are made to the graph and `false` is returned. + * + * Adding an edge from a node to that same node (i.e. `from` and `to` are + * the same) is considered a cycle and such edge cannot be added. + * + * @param from - The "source" node. + * @param to - The "target" node. + * @return `true` if the edge was added, `false` otherwise. + */ + public tryAddEdge(from: T, to: T): boolean { + try { + this.addEdge(from, to); + return true; + } catch { + return false; + } + } + + /** + * Checks if a specific (directed) edge exists in the graph. + * + * @param from - The "source" node. + * @param to - The "target" node. + * @return `true` if the edge exists, `false` otherwise. + */ + public hasEdge(from: T, to: T): boolean { + const node = this.#nodes.get(from); + return node !== undefined && node.outgoing.has(to); + } + + /** + * Removes a specified edge from the graph. + * If such edge doesn't exist, this is a no-op. + * + * **Note:** this removes a directed edge. If an edge A -> B exists, + * it will not be removed with a removeEdge(B, A) call. + * + * @param from - The "source" node. + * @param to - The "target" node. + * @return This DAG. + */ + public deleteEdge(from: T, to: T): this { + if (this.hasEdge(from, to)) { + this.#nodes.get(from)!.outgoing.delete(to); + this.#nodes.get(to)!.incoming.delete(from); + } + + return this; + } + + /** + * Removes all outgoing edges from a given node. + * If such node doesn't exist, this is a no-op. + * + * @param node - The node to remove outgoing edges from. + * @return This DAG. + */ + public deleteOutgoingEdgesOf(node: T): this { + return this.#deleteAllEdges('outgoing', node); + } + + /** + * Removes all incoming edges to a given node. + * If such node doesn't exist, this is a no-op. + * + * @param node - The node to remove incoming edges to. + * @return This DAG. + */ + public deleteIncomingEdgesOf(node: T): this { + return this.#deleteAllEdges('incoming', node); + } + + /** + * Returns the given nodes in a topological order. + * + * In a case that a node does not exist in the graph, it is pushed to the end of the array. + * + * @param nodes - The nodes to sort. + * @return An array of the given nodes in a topological order. + */ + public getNodeOrder(...nodes: T[]): T[] { + return this.sortNodes(nodes); + } + + /** + * Sorts the given array of nodes, in place by their topological order. + * + * In a case that a node does not exist in the graph, it is pushed to the end of the array. + * + * @param nodes - The nodes to sort. + * @return The input array of nodes, sorted in a topological order. + */ + public sortNodes(nodes: T[]): T[] { + return nodes.sort((lhsId, rhsId) => { + const lhs = this.#nodes.get(lhsId); + if (!lhs) { + return +1; + } + + const rhs = this.#nodes.get(rhsId); + if (!rhs) { + return -1; + } + + return byValue(lhs.order, rhs.order); + }); + } + + /** + * Returns (an unordered) set of all immediate predecessors of the given nodes. + * + * @param nodes - The nodes to get immediate predecessors of. + * @return An unordered set of all immediate predecessors of the given nodes. + */ + public getImmediatePredecessorsOf(...nodes: T[]): Set { + return this.#getImmediate('incoming', ...nodes); + } + + /** + * Returns an iterable of all immediate predecessors of the given nodes which + * iterates over them in a topological order. + * + * @param nodes - The nodes to get immediate predecessors of. + * @return A topologically ordered iterable of all immediate predecessors of the given nodes. + */ + public getOrderedImmediatePredecessorsOf(...nodes: T[]): Iterable { + return this.#toOrderedIterable(this.getImmediatePredecessorsOf(...nodes)); + } + + /** + * Returns (an unordered) set of all predecessors of the given nodes. + * + * @param nodes - The nodes to get predecessors of. + * @return An unordered set of all predecessors of the given nodes. + */ + public getPredecessorsOf(...nodes: T[]): Set { + return this.#getReachable('incoming', ...nodes); + } + + /** + * Returns an iterable of all predecessors of the given nodes which + * iterates over them in a topological order. + * + * @param nodes - The nodes to get predecessors of. + * @return A topologically ordered iterable of all predecessors of the given nodes. + */ + public getOrderedPredecessorsOf(...nodes: T[]): Iterable { + return this.#toOrderedIterable(this.getPredecessorsOf(...nodes)); + } + + /** + * Returns (an unordered) set of all immediate successors of the given nodes. + * + * @param nodes - The nodes to get immediate successors of. + * @return An unordered set of all immediate successors of the given nodes. + */ + public getImmediateSuccessorsOf(...nodes: T[]): Set { + return this.#getImmediate('outgoing', ...nodes); + } + + /** + * Returns an iterable of all immediate successors of the given nodes which + * iterates over them in a topological order. + * + * @param nodes - The nodes to get immediate successors of. + * @return A topologically ordered iterable of all immediate successors of the given nodes. + */ + public getOrderedImmediateSuccessorsOf(...nodes: T[]): Iterable { + return this.#toOrderedIterable(this.getImmediateSuccessorsOf(...nodes)); + } + + /** + * Returns (an unordered) set of all successors of the given nodes. + * + * @param nodes - The nodes to get successors of. + * @return An unordered set of all successors of the given nodes. + */ + public getSuccessorsOf(...nodes: T[]): Set { + return this.#getReachable('outgoing', ...nodes); + } + + /** + * Returns an iterable of all successors of the given nodes which + * iterates over them in a topological order. + * + * @param nodes - The nodes to get successors of. + * @return A topologically ordered iterable of all successors of the given nodes. + */ + public getOrderedSuccessorsOf(...nodes: T[]): Iterable { + return this.#toOrderedIterable(this.getSuccessorsOf(...nodes)); + } + + /** + * Checks whether a directed path between two nodes exists in the graph. + * + * If A is directly connected to B, `hasPath(A, B)` is exactly the same as `hasEdge(A, B)`. + * On the other hand, if only the edges `A -> B` and `A -> C` exists in the + * graph, a `hasPath(A, C)` returns `true`, while `hasEdge(A, C)` returns `false`. + * + * + * @param from - The "source" node. + * @param to - The "target" node. + * @return `true` if a directed path exists, `false` otherwise. + */ + public hasPath(from: T, to: T): boolean { + if (from == to) { + return false; + } + + const fromNode = this.#nodes.get(from); + const toNode = this.#nodes.get(to); + + if (!fromNode || !toNode || fromNode.order > toNode.order) { + return false; + } + + if (fromNode.outgoing.has(to)) { + return true; + } + + const queue = [from]; + const visited = new Set(queue); + + while (queue.length > 0) { + for (const successor of this.#nodes.get(queue.shift()!)!.outgoing) { + if (successor == to) { + return true; + } + + if (!visited.has(successor)) { + visited.add(successor); + queue.push(successor); + } + } + } + + return false; + } + + /** + * Merges two nodes if such action would not introduce a cycle. + * + * "Merging" of A and B is performed by making: + * - all immediate predecessors of B be immediate predecessors of A, and + * - all immediate successors of B be immediate successors of A. + * + * After that remapping, node B gets removed from the graph. + * + * **Note:** This method is a no-op if either A or B is absent in the graph. + * + * If there is a path between A and B (in either direction), a CycleError + * gets thrown, and the graph is not changed. + * + * @param a - The first node to merge. + * @param b - The second node to merge. + * @return This DAG. + */ + public mergeNodes(a: T, b: T): this { + if (a == b) { + return this; + } + + const nodeA = this.#nodes.get(a); + const nodeB = this.#nodes.get(b); + + if (nodeA && nodeB) { + if (this.hasPath(a, b) || this.hasPath(b, a)) { + throw new CycleError(); + } + + for (const predecessor of nodeB.incoming) { + this.addEdge(predecessor, a); + } + + for (const successor of nodeB.outgoing) { + this.addEdge(a, successor); + } + + this.delete(b); + } + + return this; + } + + /** + * Tries to merge two nodes if such action would not introduce a cycle. + * + * "Merging" of A and B is performed by making: + * - all immediate predecessors of B be immediate predecessors of A, and + * - all immediate successors of B be immediate successors of A. + * + * After that remapping, node B gets removed from the graph. + * + * **Note:** This method is a no-op if either A or B is absent in the graph. + * + * If there is a path between A and B (in either direction), the merging would + * introduce a cycle so this function returns `false`, and the graph is not changed. + * + * @param a - The first node to merge. + * @param b - The second node to merge. + * @return True if the nodes were successfully merged, or if + * at least one of the given nodes is not present in the graph. + */ + tryMergeNodes(a: T, b: T): boolean { + try { + this.mergeNodes(a, b); + return true; + } catch { + return false; + } + } + + /** + * Adds a node to the graph and returns it. + * If the node already exists, it is returned unchanged. + * + * @param id - The node to add. + * @returns The Node state object. + */ + #ensureNodeExists(id: T): Node { + let node = this.#nodes.get(id); + if (node) { + return node; + } + + node = { + id, + order: this.#order.length, + incoming: new Set(), + outgoing: new Set(), + }; + + this.#nodes.set(id, node); + this.#order.push(id); + + return node; + } + + /** + * Tries to add a directed edge to the graph. + * + * If any of the nodes doesn't already exist, it will be added. + * + * If inserting the given edge would introduce a cycle no changes + * are made to the graph and CycleError is thrown. + * + * @param from - The "source" node. + * @param to - The "target" node. + */ + #addEdge(from: T, to: T): void { + if (this.hasEdge(from, to)) { + return; + } + + // + // This function implements the PK algorithm for incremental + // topological ordering as presented in the paper: + // + // PEARCE, David J.; KELLY, Paul HJ. A dynamic algorithm for + // topologically sorting directed acyclic graphs. + // Lecture notes in computer science, 2004, 3059: 383-398. + // + // https://citeseerx.ist.psu.edu/document?doi=388da0bed2a1658a34de39b28921de48f353b2ed + // + + // N.B. intentionally reversing direction + const u = this.#ensureNodeExists(to); + const v = this.#ensureNodeExists(from); + + if (u.order < v.order) { + const successors = this.#findSuccessors(u, v.order); + const predecessors = this.#findPredecessors(v, u.order); + + successors.sort(byOrder); + predecessors.sort(byOrder); + + const totalPredecessors = predecessors.length; + const totalAffected = totalPredecessors + successors.length; + + const topology = new Array(totalAffected); + + let i = 0; + for (const { order } of successors) { + topology[i++] = order; + } + for (const { order } of predecessors) { + topology[i++] = order; + } + + topology.sort(byValue); + + for (i = 0; i < totalPredecessors; i++) { + const index = topology[i]!; + const predecessor = predecessors[i]!; + this.#order[index] = predecessor.id; + predecessor.order = index; + } + for (i = totalPredecessors; i < totalAffected; i++) { + const index = topology[i]!; + const successor = successors[i - totalPredecessors]!; + this.#order[index] = successor.id; + successor.order = index; + } + } + + u.incoming.add(from); + v.outgoing.add(to); + } + + /** + * Removes all edges from a given node in the given direction (i.e. incoming or outgoing). + * If such node doesn't exist, this is a no-op. + * + * @param direction - The direction of the edges to remove. + * @param node - The node whose incoming edges to remove. + * @return This DAG. + */ + #deleteAllEdges(direction: 'incoming' | 'outgoing', node: T): this { + const state = this.#nodes.get(node); + + if (state) { + const reversed = direction == 'incoming' ? 'outgoing' : 'incoming'; + + for (const from of state[direction]) { + this.#nodes.get(from)![reversed].delete(node); + } + + state[direction].clear(); + } + + return this; + } + + /** + * Returns all successors of the given node, such that their current topological + * order is less than the given one. These nodes will need to be reordered. + * + * @param startNode - The node whose successors to return. + * @param order - The order to constrain the successor set with. + * @return The unordered list of successors nodes. + */ + #findSuccessors(startNode: Node, order: number): Node[] { + const result: Node[] = []; + const visited = new Set(); + const stack = [startNode]; + + while (stack.length > 0) { + const node = stack.pop()!; + + if (visited.has(node.id)) { + continue; + } + + visited.add(node.id); + result.push(node); + + for (const id of node.outgoing) { + const successor = this.#nodes.get(id)!; + + if (successor.order == order) { + throw new CycleError(); + } + if (!visited.has(id) && successor.order < order) { + stack.push(successor); + } + } + } + + return result; + } + + /** + * Returns all predecessors of the given node, such that their current topological + * order is greater than the given one. These nodes will need to be reordered. + * + * @param startNode - The node whose predecessors to return. + * @param order - The order to constrain the predecessor set with. + * @return The unordered list of predecessors nodes. + */ + #findPredecessors(startNode: Node, order: number): Node[] { + const result: Node[] = []; + const visited = new Set(); + const stack = [startNode]; + + while (stack.length > 0) { + const node = stack.pop()!; + + if (visited.has(node.id)) { + continue; + } + + visited.add(node.id); + result.push(node); + + for (const id of node.incoming) { + const predecessor = this.#nodes.get(id)!; + + if (!visited.has(id) && predecessor.order >= order) { + stack.push(predecessor); + } + } + } + + return result; + } + + /** + * Returns (an unordered) set of all immediate neighbors of the given nodes. + * + * @param direction - The direction of the edges to traverse. + * @param nodes - Nodes whose immediate neighbors to return. + * @return An unordered set of all immediate neighbors of the given nodes. + */ + #getImmediate(direction: 'incoming' | 'outgoing', ...nodes: T[]): Set { + let results = new Set(); + + for (const id of nodes) { + const node = this.#nodes.get(id); + if (node) { + results = union(results, node[direction]); + } + } + + for (const id of nodes) { + results.delete(id); + } + + return results; + } + + /** + * Returns (an unordered) set of all nodes reachable from the given nodes. + * + * @param direction - The direction of the edges to traverse. + * @param nodes - Nodes whose reachable nodes to return. + * @return An unordered set of all reachable nodes of the given nodes.. + */ + #getReachable(direction: 'incoming' | 'outgoing', ...nodes: T[]): Set { + const results = new Set(nodes); + const queue = nodes.slice(0); + + while (queue.length > 0) { + const node = this.#nodes.get(queue.shift()!); + if (!node) { + continue; + } + + for (const id of node[direction]) { + if (!results.has(id)) { + results.add(id); + queue.push(id); + } + } + } + + for (const id of nodes) { + results.delete(id); + } + + return results; + } + + /** + * Returns a new iterable which iterates over the nodes + * in the given iterable in topological order. + * + * **Note:** This function assumes that all nodes + * in the given iterable are present in the graph. + * + * @param ids - An iterable of node ids. + * @returns Iterable over the given nodes in topological order. + */ + #toOrderedIterable(ids: Iterable): Iterable { + const queue = new PriorityQueue(); + + for (const id of ids) { + queue.enqueue(id, this.#nodes.get(id)!.order); + } + + return queue; + } +} diff --git a/src/errors.test.ts b/src/errors.test.ts new file mode 100644 index 0000000..76055e0 --- /dev/null +++ b/src/errors.test.ts @@ -0,0 +1,16 @@ +import assert from 'node:assert'; +import { describe, it } from 'node:test'; +import { CycleError } from './errors'; + +describe('CycleError', () => { + it('has "Cycle detected" message', () => { + const error = new CycleError(); + + assert.equal(error.message, 'Cycle detected'); + }); + it('has "CycleError" name', () => { + const error = new CycleError(); + + assert.equal(error.name, 'CycleError'); + }); +}); diff --git a/src/errors.ts b/src/errors.ts new file mode 100644 index 0000000..d2bfa7f --- /dev/null +++ b/src/errors.ts @@ -0,0 +1,9 @@ +/** + * Error thrown when a cycle would be introduced in a DAG. + */ +export class CycleError extends Error { + public constructor() { + super('Cycle detected'); + this.name = 'CycleError'; + } +} diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..8349859 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,2 @@ +export * from './dag'; +export * from './errors'; diff --git a/src/internal/node.ts b/src/internal/node.ts new file mode 100644 index 0000000..93f237a --- /dev/null +++ b/src/internal/node.ts @@ -0,0 +1,21 @@ +/** + * Represents the state of a node added to the graph. + */ +export interface Node { + /** + * The "id" of this node (i.e., this is a node, as far as public API is concerned). + */ + readonly id: T; + /** + * The current index of this node in the topological order of the graph. + */ + order: number; + /** + * The set of immediate predecessors of this node (i.e., all nodes that point to this node). + */ + incoming: Set; + /** + * The set of immediate successors od this node (i.e., all nodes that this node points to). + */ + outgoing: Set; +} diff --git a/src/internal/order.test.ts b/src/internal/order.test.ts new file mode 100644 index 0000000..92417d8 --- /dev/null +++ b/src/internal/order.test.ts @@ -0,0 +1,43 @@ +import assert from 'node:assert'; +import { describe, it } from 'node:test'; +import { byValue, byOrder } from './order'; +import type { Node } from './node'; + +describe('byValue()', () => { + it('returns negative number if first number is less than the second', () => { + assert.equal(byValue(1, 2), -1); + assert.equal(byValue(0, 1), -1); + assert.equal(byValue(-1, 0), -1); + assert.equal(byValue(-Infinity, Infinity), -1); + }); + it('returns positive number if first number is greater than the second', () => { + assert.equal(byValue(2, 1), 1); + assert.equal(byValue(1, 0), 1); + assert.equal(byValue(0, -1), 1); + assert.equal(byValue(Infinity, -Infinity), 1); + }); + it('returns zero if numbers are equal', () => { + assert.equal(byValue(0, 0), 0); + assert.equal(byValue(1, 1), 0); + assert.equal(byValue(-1, -1), 0); + assert.equal(byValue(Infinity, Infinity), 0); + }); +}); + +describe('byOrder()', () => { + it('returns negative number if the first node should be ordered before the second', () => { + const lhs = { order: 1 } as Node; + const rhs = { order: 2 } as Node; + assert.equal(byOrder(lhs, rhs), -1); + }); + it('returns positive number if the first node should be ordered after the second', () => { + const lhs = { order: 2 } as Node; + const rhs = { order: 1 } as Node; + assert.equal(byOrder(lhs, rhs), 1); + }); + it('returns zero if nodes have the same order', () => { + const lhs = { order: 0 } as Node; + const rhs = { order: 0 } as Node; + assert.equal(byOrder(lhs, rhs), 0); + }); +}); diff --git a/src/internal/order.ts b/src/internal/order.ts new file mode 100644 index 0000000..7cda630 --- /dev/null +++ b/src/internal/order.ts @@ -0,0 +1,25 @@ +import type { Node } from './node'; + +/** + * Compares two Node objects by order. + * + * @param lhs - The left hand-side operand. + * @param rhs - The right hand-side operand. + * @return Negative number if 'lhs' is less than 'rhs', positive number if + * `lhs` is greater than `rhs`, or 0 if they have equal order. + */ +export function byOrder(lhs: Node, rhs: Node): -1 | 0 | 1 { + return byValue(lhs.order, rhs.order); +} + +/** + * Compares two numbers by value. + * + * @param lhs - The left hand-side operand. + * @param rhs - The right hand-side operand. + * @return Negative number if 'lhs' is less than 'rhs', positive number if + * `lhs` is greater than `rhs`, or 0 if they are equal. + */ +export function byValue(lhs: number, rhs: number): -1 | 0 | 1 { + return lhs < rhs ? -1 : lhs == rhs ? 0 : +1; +} diff --git a/src/internal/priority-queue.test.ts b/src/internal/priority-queue.test.ts new file mode 100644 index 0000000..467d0a9 --- /dev/null +++ b/src/internal/priority-queue.test.ts @@ -0,0 +1,17 @@ +import assert from 'node:assert'; +import { describe, it } from 'node:test'; +import { PriorityQueue } from './priority-queue'; + +describe('PriorityQueue', () => { + it('enqueues items maintaining the priority order', () => { + const queue = new PriorityQueue(); + + queue.enqueue('B', 2); + queue.enqueue('C', 3); + queue.enqueue('E', 5); + queue.enqueue('A', 1); + queue.enqueue('D', 4); + + assert.deepStrictEqual([...queue], ['A', 'B', 'C', 'D', 'E']); + }); +}); diff --git a/src/internal/priority-queue.ts b/src/internal/priority-queue.ts new file mode 100644 index 0000000..dbf553d --- /dev/null +++ b/src/internal/priority-queue.ts @@ -0,0 +1,61 @@ +/** + * A simple priority queue based on a sorted array. + */ +export class PriorityQueue { + #data: T[]; + #priorities: number[]; + + /** + * Creates a new, empty priority queue. + */ + public constructor() { + this.#data = []; + this.#priorities = []; + } + + /** + * Enqueues an item with the given priority. + * + * The priority is in ascending order, where lower values have higher priority. + * + * @param item - Item to insert to the queue. + * @param priority - Item priority to use to re-prioritize the queue. + */ + public enqueue(item: T, priority: number): void { + const { length } = this.#data; + + this.#data.push(item); + this.#priorities.push(priority); + + if (length > 0 && this.#priorities[length - 1]! > priority) { + let lo = 0, + hi = length; + + while (lo < hi) { + const mid = lo + Math.trunc((hi - lo) / 2); + if (this.#priorities[mid]! < priority) { + lo = mid + 1; + } else { + hi = mid; + } + } + + if (lo < length) { + this.#data.copyWithin(lo + 1, lo, length); + this.#data[lo] = item; + + this.#priorities.copyWithin(lo + 1, lo, length); + this.#priorities[lo] = priority; + } + } + } + + /** + * Returns iterator over all queue items in priority order. + * + * @returns Queue item iterator in priority order. + */ + [Symbol.iterator](): Iterator { + return this.#data[Symbol.iterator](); + } +} diff --git a/src/internal/union.test.ts b/src/internal/union.test.ts new file mode 100644 index 0000000..2431b4e --- /dev/null +++ b/src/internal/union.test.ts @@ -0,0 +1,20 @@ +import assert from 'node:assert'; +import { describe, it } from 'node:test'; +import { union } from './union'; + +describe('union()', () => { + it('should combine two sets into a new set', () => { + const a = new Set([1, 2, 3]); + const b = new Set([3, 4, 5]); + + const result = union(a, b); + + assert(result instanceof Set); + assert.equal(result.size, 5); + assert(result.has(1)); + assert(result.has(2)); + assert(result.has(3)); + assert(result.has(4)); + assert(result.has(5)); + }); +}); diff --git a/src/internal/union.ts b/src/internal/union.ts new file mode 100644 index 0000000..146dc07 --- /dev/null +++ b/src/internal/union.ts @@ -0,0 +1,19 @@ +/** + * Combines two sets into a new set. + * + * @param a - The first set. + * @param b - The second set. + * @return A new set that contains all elements from both input sets. + */ +export function union(a: Set, b: Set): Set { + if ('union' in a) { + return a.union(b); + } + + const result = new Set(a); + for (const item of b) { + result.add(item); + } + + return result; +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..3bac512 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,33 @@ +{ + "include": [ + "src/**/*.ts" + ], + "compilerOptions": { + "target": "ESNext", + "lib": [ + "ESNext" + ], + "module": "ESNext", + "moduleResolution": "Bundler", + "composite": true, + "rootDir": "./src", + "noEmit": true, + "isolatedModules": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitAny": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "exactOptionalPropertyTypes": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedIndexedAccess": true, + "skipLibCheck": true, + "plugins": [ + { + "name": "typescript-eslint-language-service" + } + ] + } +} \ No newline at end of file