Initial commit: New MoreminiMore website with fresh design

This commit is contained in:
MoreminiMore
2026-04-22 01:59:05 +07:00
commit 76409638cc
14010 changed files with 2052041 additions and 0 deletions

7
node_modules/devalue/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,7 @@
Copyright (c) 2018-19 [these people](https://github.com/rich-harris/devalue/graphs/contributors)
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.

228
node_modules/devalue/README.md generated vendored Normal file
View File

@@ -0,0 +1,228 @@
# devalue
Like `JSON.stringify`, but handles
- cyclical references (`obj.self = obj`)
- repeated references (`[value, value]`)
- `undefined`, `Infinity`, `NaN`, `-0`
- regular expressions
- dates
- `Map` and `Set`
- `BigInt`
- `ArrayBuffer` and Typed Arrays
- `URL` and `URLSearchParams`
- `Temporal`
- custom types via replacers, reducers and revivers
Try it out [here](https://svelte.dev/repl/138d70def7a748ce9eda736ef1c71239?version=3.49.0).
## Goals:
- Performance
- Security (see [XSS mitigation](#xss-mitigation))
- Compact output
## Non-goals:
- Human-readable output
- Stringifying functions
## Usage
There are two ways to use `devalue`:
### `uneval`
This function takes a JavaScript value and returns the JavaScript code to create an equivalent value — sort of like `eval` in reverse:
```js
import * as devalue from 'devalue';
let obj = { message: 'hello' };
devalue.uneval(obj); // '{message:"hello"}'
obj.self = obj;
devalue.uneval(obj); // '(function(a){a.message="hello";a.self=a;return a}({}))'
```
Use `uneval` when you want the most compact possible output and don't want to include any code for parsing the serialized value.
### `stringify` and `parse`
These two functions are analogous to `JSON.stringify` and `JSON.parse`:
```js
import * as devalue from 'devalue';
let obj = { message: 'hello' };
let stringified = devalue.stringify(obj); // '[{"message":1},"hello"]'
devalue.parse(stringified); // { message: 'hello' }
obj.self = obj;
stringified = devalue.stringify(obj); // '[{"message":1,"self":0},"hello"]'
devalue.parse(stringified); // { message: 'hello', self: [Circular] }
```
Use `stringify` and `parse` when evaluating JavaScript isn't an option.
### `unflatten`
In the case where devalued data is one part of a larger JSON string, `unflatten` allows you to revive just the bit you need:
```js
import * as devalue from 'devalue';
const json = `{
"type": "data",
"data": ${devalue.stringify(data)}
}`;
const data = devalue.unflatten(JSON.parse(json).data);
```
## Custom types
You can serialize and deserialize custom types by passing a second argument to `stringify` containing an object of types and their _reducers_, and a second argument to `parse` or `unflatten` containing an object of types and their _revivers_:
```js
class Vector {
constructor(x, y) {
this.x = x;
this.y = y;
}
magnitude() {
return Math.sqrt(this.x * this.x + this.y * this.y);
}
}
const stringified = devalue.stringify(new Vector(30, 40), {
Vector: (value) => value instanceof Vector && [value.x, value.y]
});
console.log(stringified); // [["Vector",1],[2,3],30,40]
const vector = devalue.parse(stringified, {
Vector: ([x, y]) => new Vector(x, y)
});
console.log(vector.magnitude()); // 50
```
If a function passed to `stringify` returns a truthy value, it's treated as a match.
You can also use custom types with `uneval` by specifying a custom replacer:
```js
devalue.uneval(vector, (value, uneval) => {
if (value instanceof Vector) {
return `new Vector(${value.x},${value.y})`;
}
}); // `new Vector(30,40)`
```
Note that any variables referenced in the resulting JavaScript (like `Vector` in the example above) must be in scope when it runs.
## Error handling
If `uneval` or `stringify` encounters a function or a non-POJO that isn't handled by a custom replacer/reducer, it will throw an error. You can find where in the input data the offending value lives by inspecting `error.path`:
```js
try {
const map = new Map();
map.set('key', function invalid() {});
uneval({
object: {
array: [map]
}
});
} catch (e) {
console.log(e.path); // '.object.array[0].get("key")'
}
```
## XSS mitigation
Say you're server-rendering a page and want to serialize some state, which could include user input. `JSON.stringify` doesn't protect against XSS attacks:
```js
const state = {
userinput: `</script><script src='https://evil.com/mwahaha.js'>`
};
const template = `
<script>
// NEVER DO THIS
var preloaded = ${JSON.stringify(state)};
</script>`;
```
Which would result in this:
```html
<script>
// NEVER DO THIS
var preloaded = {"userinput":"
</script>
<script src="https://evil.com/mwahaha.js">
"};
</script>
```
Using `uneval` or `stringify`, we're protected against that attack:
```js
const template = `
<script>
var preloaded = ${uneval(state)};
</script>`;
```
```html
<script>
var preloaded = {
userinput:
"\\u003C\\u002Fscript\\u003E\\u003Cscript src='https:\\u002F\\u002Fevil.com\\u002Fmwahaha.js'\\u003E"
};
</script>
```
This, along with the fact that `uneval` and `stringify` bail on functions and non-POJOs, stops attackers from executing arbitrary code. Strings generated by `uneval` can be safely deserialized with `eval` or `new Function`:
```js
const value = (0, eval)('(' + str + ')');
```
## Other security considerations
While `uneval` prevents the XSS vulnerability shown above, meaning you can use it to send data from server to client, **you should not send user data from client to server** using the same method. Since it has to be evaluated, an attacker that successfully submitted data that bypassed `uneval` would have access to your system.
When using `eval`, ensure that you call it _indirectly_ so that the evaluated code doesn't have access to the surrounding scope:
```js
{
const sensitiveData = 'Setec Astronomy';
eval('sendToEvilServer(sensitiveData)'); // pwned :(
(0, eval)('sendToEvilServer(sensitiveData)'); // nice try, evildoer!
}
```
Using `new Function(code)` is akin to using indirect eval.
## See also
- [lave](https://github.com/jed/lave) by Jed Schmidt
- [arson](https://github.com/benjamn/arson) by Ben Newman. The `stringify`/`parse` approach in `devalue` was inspired by `arson`
- [oson](https://github.com/KnorpelSenf/oson) by Steffen Trog
- [tosource](https://github.com/marcello3d/node-tosource) by Marcello Bastéa-Forte
- [serialize-javascript](https://github.com/yahoo/serialize-javascript) by Eric Ferraiuolo
- [jsesc](https://github.com/mathiasbynens/jsesc) by Mathias Bynens
- [superjson](https://github.com/blitz-js/superjson) by Blitz
- [next-json](https://github.com/iccicci/next-json) by Daniele Ricci
## License
[MIT](LICENSE)

4
node_modules/devalue/index.js generated vendored Normal file
View File

@@ -0,0 +1,4 @@
export { uneval } from './src/uneval.js';
export { parse, unflatten } from './src/parse.js';
export { stringify } from './src/stringify.js';
export { DevalueError } from './src/utils.js';

40
node_modules/devalue/package.json generated vendored Normal file
View File

@@ -0,0 +1,40 @@
{
"name": "devalue",
"description": "Gets the job done when JSON.stringify can't",
"version": "5.7.1",
"repository": "sveltejs/devalue",
"sideEffects": false,
"exports": {
".": {
"types": "./types/index.d.ts",
"import": "./index.js",
"default": "./index.js"
}
},
"files": [
"index.js",
"src",
"types"
],
"types": "./types/index.d.ts",
"devDependencies": {
"@changesets/cli": "^2.29.6",
"@js-temporal/polyfill": "^0.5.1",
"@types/node": "^24.12.0",
"dts-buddy": "^0.6.2",
"publint": "^0.3.12",
"typescript": "^5.9.2",
"uvu": "^0.5.6"
},
"license": "MIT",
"type": "module",
"packageManager": "pnpm@8.15.9",
"scripts": {
"changeset:version": "changeset version",
"changeset:publish": "changeset publish",
"build": "dts-buddy",
"test": "uvu",
"bench": "node --allow-natives-syntax ./benchmarking/run.js",
"bench:compare": "node --allow-natives-syntax ./benchmarking/compare/index.js"
}
}

60
node_modules/devalue/src/base64.js generated vendored Normal file
View File

@@ -0,0 +1,60 @@
/* Baseline 2025 runtimes */
/** @type {(array_buffer: ArrayBuffer) => string} */
export function encode_native(array_buffer) {
return new Uint8Array(array_buffer).toBase64();
}
/** @type {(base64: string) => ArrayBuffer} */
export function decode_native(base64) {
return Uint8Array.fromBase64(base64).buffer;
}
/* Node-compatible runtimes */
/** @type {(array_buffer: ArrayBuffer) => string} */
export function encode_buffer(array_buffer) {
return Buffer.from(array_buffer).toString('base64');
}
/** @type {(base64: string) => ArrayBuffer} */
export function decode_buffer(base64) {
return Uint8Array.from(Buffer.from(base64, 'base64')).buffer;
}
/* Legacy runtimes */
/** @type {(array_buffer: ArrayBuffer) => string} */
export function encode_legacy(array_buffer) {
const array = new Uint8Array(array_buffer);
let binary = '';
// the maximum number of arguments to String.fromCharCode.apply
// should be around 0xFFFF in modern engines
const chunk_size = 0x8000;
for (let i = 0; i < array.length; i += chunk_size) {
const chunk = array.subarray(i, i + chunk_size);
binary += String.fromCharCode.apply(null, chunk);
}
return btoa(binary);
}
/** @type {(base64: string) => ArrayBuffer} */
export function decode_legacy(base64) {
const binary_string = atob(base64);
const len = binary_string.length;
const array = new Uint8Array(len);
for (let i = 0; i < len; i++) {
array[i] = binary_string.charCodeAt(i);
}
return array.buffer;
}
const native = typeof Uint8Array.fromBase64 === 'function';
const buffer = typeof process === 'object' && process.versions?.node !== undefined;
export const encode64 = native ? encode_native : buffer ? encode_buffer : encode_legacy;
export const decode64 = native ? decode_native : buffer ? decode_buffer : decode_legacy;

44
node_modules/devalue/src/base64.test.js generated vendored Normal file
View File

@@ -0,0 +1,44 @@
import * as assert from 'uvu/assert';
import { suite } from 'uvu';
import * as base64 from './base64.js';
const strings = [
'',
'a',
'ab',
'abc',
'a\r\nb',
'\xFF\xFE',
'\x00',
'\x00\x00\x00',
'the quick brown fox etc',
'é',
'中文',
'+/',
'😎'
];
const test = suite('base64_encode_decode');
const encoder = new TextEncoder();
const decoder = new TextDecoder();
for (const string of strings) {
test(string, () => {
const data = encoder.encode(string);
const with_buffer = base64.encode_buffer(data);
const with_legacy = base64.encode_legacy(data);
assert.equal(with_buffer, with_legacy);
assert.equal(decoder.decode(base64.decode_buffer(with_buffer)), string);
assert.equal(decoder.decode(base64.decode_legacy(with_legacy)), string);
if (typeof Uint8Array.fromBase64 === 'function') {
const with_native = base64.encode_native(data);
assert.equal(decoder.decode(base64.decode_native(with_native)), string);
}
});
}
test.run();

7
node_modules/devalue/src/constants.js generated vendored Normal file
View File

@@ -0,0 +1,7 @@
export const UNDEFINED = -1;
export const HOLE = -2;
export const NAN = -3;
export const POSITIVE_INFINITY = -4;
export const NEGATIVE_INFINITY = -5;
export const NEGATIVE_ZERO = -6;
export const SPARSE = -7;

268
node_modules/devalue/src/parse.js generated vendored Normal file
View File

@@ -0,0 +1,268 @@
import { decode64 } from './base64.js';
import {
HOLE,
NAN,
NEGATIVE_INFINITY,
NEGATIVE_ZERO,
POSITIVE_INFINITY,
SPARSE,
UNDEFINED
} from './constants.js';
/**
* Revive a value serialized with `devalue.stringify`
* @param {string} serialized
* @param {Record<string, (value: any) => any>} [revivers]
*/
export function parse(serialized, revivers) {
return unflatten(JSON.parse(serialized), revivers);
}
/**
* Revive a value flattened with `devalue.stringify`
* @param {number | any[]} parsed
* @param {Record<string, (value: any) => any>} [revivers]
*/
export function unflatten(parsed, revivers) {
if (typeof parsed === 'number') return hydrate(parsed, true);
if (!Array.isArray(parsed) || parsed.length === 0) {
throw new Error('Invalid input');
}
const values = /** @type {any[]} */ (parsed);
const hydrated = Array(values.length);
/**
* A set of values currently being hydrated with custom revivers,
* used to detect invalid cyclical dependencies
* @type {Set<number> | null}
*/
let hydrating = null;
/**
* @param {number} index
* @returns {any}
*/
function hydrate(index, standalone = false) {
if (index === UNDEFINED) return undefined;
if (index === NAN) return NaN;
if (index === POSITIVE_INFINITY) return Infinity;
if (index === NEGATIVE_INFINITY) return -Infinity;
if (index === NEGATIVE_ZERO) return -0;
if (standalone || typeof index !== 'number') {
throw new Error(`Invalid input`);
}
if (index in hydrated) return hydrated[index];
const value = values[index];
if (!value || typeof value !== 'object') {
hydrated[index] = value;
} else if (Array.isArray(value)) {
if (typeof value[0] === 'string') {
const type = value[0];
const reviver = revivers && Object.hasOwn(revivers, type) ? revivers[type] : undefined;
if (reviver) {
let i = value[1];
if (typeof i !== 'number') {
// if it's not a number, it was serialized by a builtin reviver
// so we need to munge it into the format expected by a custom reviver
i = values.push(value[1]) - 1;
}
hydrating ??= new Set();
if (hydrating.has(i)) {
throw new Error('Invalid circular reference');
}
hydrating.add(i);
hydrated[index] = reviver(hydrate(i));
hydrating.delete(i);
return hydrated[index];
}
switch (type) {
case 'Date':
hydrated[index] = new Date(value[1]);
break;
case 'Set':
const set = new Set();
hydrated[index] = set;
for (let i = 1; i < value.length; i += 1) {
set.add(hydrate(value[i]));
}
break;
case 'Map':
const map = new Map();
hydrated[index] = map;
for (let i = 1; i < value.length; i += 2) {
map.set(hydrate(value[i]), hydrate(value[i + 1]));
}
break;
case 'RegExp':
hydrated[index] = new RegExp(value[1], value[2]);
break;
case 'Object': {
const wrapped_index = value[1];
if (
typeof values[wrapped_index] === 'object' &&
values[wrapped_index][0] !== 'BigInt'
) {
// avoid infinite recusion in case of malformed input
throw new Error('Invalid input');
}
hydrated[index] = Object(hydrate(wrapped_index));
break;
}
case 'BigInt':
hydrated[index] = BigInt(value[1]);
break;
case 'null':
const obj = Object.create(null);
hydrated[index] = obj;
for (let i = 1; i < value.length; i += 2) {
if (value[i] === '__proto__') {
throw new Error('Cannot parse an object with a `__proto__` property');
}
obj[value[i]] = hydrate(value[i + 1]);
}
break;
case 'Int8Array':
case 'Uint8Array':
case 'Uint8ClampedArray':
case 'Int16Array':
case 'Uint16Array':
case 'Float16Array':
case 'Int32Array':
case 'Uint32Array':
case 'Float32Array':
case 'Float64Array':
case 'BigInt64Array':
case 'BigUint64Array':
case 'DataView': {
if (values[value[1]][0] !== 'ArrayBuffer') {
// without this, if we receive malformed input we could
// end up trying to hydrate in a circle or allocate
// huge amounts of memory when we call `new TypedArrayConstructor(buffer)`
throw new Error('Invalid data');
}
const TypedArrayConstructor = globalThis[type];
const buffer = hydrate(value[1]);
hydrated[index] =
value[2] !== undefined
? new TypedArrayConstructor(buffer, value[2], value[3])
: new TypedArrayConstructor(buffer);
break;
}
case 'ArrayBuffer': {
const base64 = value[1];
if (typeof base64 !== 'string') {
throw new Error('Invalid ArrayBuffer encoding');
}
const arraybuffer = decode64(base64);
hydrated[index] = arraybuffer;
break;
}
case 'Temporal.Duration':
case 'Temporal.Instant':
case 'Temporal.PlainDate':
case 'Temporal.PlainTime':
case 'Temporal.PlainDateTime':
case 'Temporal.PlainMonthDay':
case 'Temporal.PlainYearMonth':
case 'Temporal.ZonedDateTime': {
const temporalName = type.slice(9);
// @ts-expect-error TS doesn't know about Temporal yet
hydrated[index] = Temporal[temporalName].from(value[1]);
break;
}
case 'URL': {
const url = new URL(value[1]);
hydrated[index] = url;
break;
}
case 'URLSearchParams': {
const url = new URLSearchParams(value[1]);
hydrated[index] = url;
break;
}
default:
throw new Error(`Unknown type ${type}`);
}
} else if (value[0] === SPARSE) {
// Sparse array encoding: [SPARSE, length, idx, val, idx, val, ...]
const len = value[1];
if (!Number.isInteger(len) || len < 0) {
throw new Error('Invalid input');
}
const array = new Array(len);
hydrated[index] = array;
for (let i = 2; i < value.length; i += 2) {
const idx = value[i];
if (!Number.isInteger(idx) || idx < 0 || idx >= len) {
throw new Error('Invalid input');
}
array[idx] = hydrate(value[i + 1]);
}
} else {
const array = new Array(value.length);
hydrated[index] = array;
for (let i = 0; i < value.length; i += 1) {
const n = value[i];
if (n === HOLE) continue;
array[i] = hydrate(n);
}
}
} else {
/** @type {Record<string, any>} */
const object = {};
hydrated[index] = object;
for (const key of Object.keys(value)) {
if (key === '__proto__') {
throw new Error('Cannot parse an object with a `__proto__` property');
}
const n = value[key];
object[key] = hydrate(n);
}
}
return hydrated[index];
}
return hydrate(0);
}

335
node_modules/devalue/src/stringify.js generated vendored Normal file
View File

@@ -0,0 +1,335 @@
import {
DevalueError,
enumerable_symbols,
get_type,
is_plain_object,
is_primitive,
stringify_key,
stringify_string,
valid_array_indices
} from './utils.js';
import {
HOLE,
NAN,
NEGATIVE_INFINITY,
NEGATIVE_ZERO,
POSITIVE_INFINITY,
SPARSE,
UNDEFINED
} from './constants.js';
import { encode64 } from './base64.js';
/**
* Turn a value into a JSON string that can be parsed with `devalue.parse`
* @param {any} value
* @param {Record<string, (value: any) => any>} [reducers]
*/
export function stringify(value, reducers) {
/** @type {any[]} */
const stringified = [];
/** @type {Map<any, number>} */
const indexes = new Map();
/** @type {Array<{ key: string, fn: (value: any) => any }>} */
const custom = [];
if (reducers) {
for (const key of Object.getOwnPropertyNames(reducers)) {
custom.push({ key, fn: reducers[key] });
}
}
/** @type {string[]} */
const keys = [];
let p = 0;
/** @param {any} thing */
function flatten(thing) {
if (thing === undefined) return UNDEFINED;
if (Number.isNaN(thing)) return NAN;
if (thing === Infinity) return POSITIVE_INFINITY;
if (thing === -Infinity) return NEGATIVE_INFINITY;
if (thing === 0 && 1 / thing < 0) return NEGATIVE_ZERO;
if (indexes.has(thing)) return /** @type {number} */ (indexes.get(thing));
const index = p++;
indexes.set(thing, index);
for (const { key, fn } of custom) {
const value = fn(thing);
if (value) {
stringified[index] = `["${key}",${flatten(value)}]`;
return index;
}
}
if (typeof thing === 'function') {
throw new DevalueError(`Cannot stringify a function`, keys, thing, value);
} else if (typeof thing === 'symbol') {
throw new DevalueError(`Cannot stringify a Symbol primitive`, keys, thing, value);
}
let str = '';
if (is_primitive(thing)) {
str = stringify_primitive(thing);
} else {
const type = get_type(thing);
switch (type) {
case 'Number':
case 'String':
case 'Boolean':
case 'BigInt':
str = `["Object",${flatten(thing.valueOf())}]`;
break;
case 'Date':
const valid = !isNaN(thing.getDate());
str = `["Date","${valid ? thing.toISOString() : ''}"]`;
break;
case 'URL':
str = `["URL",${stringify_string(thing.toString())}]`;
break;
case 'URLSearchParams':
str = `["URLSearchParams",${stringify_string(thing.toString())}]`;
break;
case 'RegExp':
const { source, flags } = thing;
str = flags
? `["RegExp",${stringify_string(source)},"${flags}"]`
: `["RegExp",${stringify_string(source)}]`;
break;
case 'Array': {
// For dense arrays (no holes), we iterate normally.
// When we encounter the first hole, we call Object.keys
// to determine the sparseness, then decide between:
// - HOLE encoding: [-2, val, -2, ...] (default)
// - Sparse encoding: [-7, length, idx, val, ...] (for very sparse arrays)
// Only the sparse path avoids iterating every slot, which
// is what protects against the DoS of e.g. `arr[1000000] = 1`.
let mostly_dense = false;
str = '[';
for (let i = 0; i < thing.length; i += 1) {
if (i > 0) str += ',';
if (Object.hasOwn(thing, i)) {
keys.push(`[${i}]`);
str += flatten(thing[i]);
keys.pop();
} else if (mostly_dense) {
// Use dense encoding. The heuristic guarantees the
// array is only mildly sparse, so iterating over every
// slot is fine.
str += HOLE;
} else {
// Decide between HOLE encoding and sparse encoding.
//
// HOLE encoding: each hole is serialized as the HOLE
// sentinel (-2). For example, [, "a", ,] becomes
// [-2, 0, -2]. Each hole costs 3 chars ("-2" + comma).
//
// Sparse encoding: lists only populated indices.
// For example, [, "a", ,] becomes [-7, 3, 1, 0] — the
// -7 sentinel, the array length (3), then index-value
// pairs. This avoids paying per-hole, but each element
// costs extra chars to write its index.
//
// The values are the same size either way, so the
// choice comes down to structural overhead:
//
// HOLE overhead:
// 3 chars per hole ("-2" + comma)
// = (L - P) * 3
//
// Sparse overhead:
// "-7," — 3 chars (sparse sentinel + comma)
// + length + "," — (d + 1) chars (array length + comma)
// + per element: index + "," — (d + 1) chars
// = (4 + d) + P * (d + 1)
//
// where L is the array length, P is the number of
// populated elements, and d is the number of digits
// in L (an upper bound on the digits in any index).
//
// Sparse encoding is cheaper when:
// (4 + d) + P * (d + 1) < (L - P) * 3
const populated_keys = valid_array_indices(/** @type {any[]} */ (thing));
const population = populated_keys.length;
const d = String(thing.length).length;
const hole_cost = (thing.length - population) * 3;
const sparse_cost = 4 + d + population * (d + 1);
if (hole_cost > sparse_cost) {
str = '[' + SPARSE + ',' + thing.length;
for (let j = 0; j < populated_keys.length; j++) {
const key = populated_keys[j];
keys.push(`[${key}]`);
str += ',' + key + ',' + flatten(thing[key]);
keys.pop();
}
break;
} else {
mostly_dense = true;
str += HOLE;
}
}
}
str += ']';
break;
}
case 'Set':
str = '["Set"';
for (const value of thing) {
str += `,${flatten(value)}`;
}
str += ']';
break;
case 'Map':
str = '["Map"';
for (const [key, value] of thing) {
keys.push(`.get(${is_primitive(key) ? stringify_primitive(key) : '...'})`);
str += `,${flatten(key)},${flatten(value)}`;
keys.pop();
}
str += ']';
break;
case 'Int8Array':
case 'Uint8Array':
case 'Uint8ClampedArray':
case 'Int16Array':
case 'Uint16Array':
case 'Float16Array':
case 'Int32Array':
case 'Uint32Array':
case 'Float32Array':
case 'Float64Array':
case 'BigInt64Array':
case 'BigUint64Array':
case 'DataView': {
/** @type {import("./types.js").TypedArray} */
const typedArray = thing;
str = '["' + type + '",' + flatten(typedArray.buffer);
// handle subarrays
if (typedArray.byteLength !== typedArray.buffer.byteLength) {
// to be used with `new TypedArray(buffer, byteOffset, length)`
str += `,${typedArray.byteOffset},${typedArray.length}`;
}
str += ']';
break;
}
case 'ArrayBuffer': {
/** @type {ArrayBuffer} */
const arraybuffer = thing;
const base64 = encode64(arraybuffer);
str = `["ArrayBuffer","${base64}"]`;
break;
}
case 'Temporal.Duration':
case 'Temporal.Instant':
case 'Temporal.PlainDate':
case 'Temporal.PlainTime':
case 'Temporal.PlainDateTime':
case 'Temporal.PlainMonthDay':
case 'Temporal.PlainYearMonth':
case 'Temporal.ZonedDateTime':
str = `["${type}",${stringify_string(thing.toString())}]`;
break;
default:
if (!is_plain_object(thing)) {
throw new DevalueError(`Cannot stringify arbitrary non-POJOs`, keys, thing, value);
}
if (enumerable_symbols(thing).length > 0) {
throw new DevalueError(`Cannot stringify POJOs with symbolic keys`, keys, thing, value);
}
if (Object.getPrototypeOf(thing) === null) {
str = '["null"';
for (const key of Object.keys(thing)) {
if (key === '__proto__') {
throw new DevalueError(
`Cannot stringify objects with __proto__ keys`,
keys,
thing,
value
);
}
keys.push(stringify_key(key));
str += `,${stringify_string(key)},${flatten(thing[key])}`;
keys.pop();
}
str += ']';
} else {
str = '{';
let started = false;
for (const key of Object.keys(thing)) {
if (key === '__proto__') {
throw new DevalueError(
`Cannot stringify objects with __proto__ keys`,
keys,
thing,
value
);
}
if (started) str += ',';
started = true;
keys.push(stringify_key(key));
str += `${stringify_string(key)}:${flatten(thing[key])}`;
keys.pop();
}
str += '}';
}
}
}
stringified[index] = str;
return index;
}
const index = flatten(value);
// special case — value is represented as a negative index
if (index < 0) return `${index}`;
return `[${stringified.join(',')}]`;
}
/**
* @param {any} thing
* @returns {string}
*/
function stringify_primitive(thing) {
const type = typeof thing;
if (type === 'string') return stringify_string(thing);
if (thing === void 0) return UNDEFINED.toString();
if (thing === 0 && 1 / thing < 0) return NEGATIVE_ZERO.toString();
if (type === 'bigint') return `["BigInt","${thing}"]`;
return String(thing);
}

13
node_modules/devalue/src/types.d.ts generated vendored Normal file
View File

@@ -0,0 +1,13 @@
export type TypedArray =
| Int8Array
| Uint8Array
| Uint8ClampedArray
| Int16Array
| Uint16Array
| Float16Array
| Int32Array
| Uint32Array
| Float32Array
| Float64Array
| BigInt64Array
| BigUint64Array;

552
node_modules/devalue/src/uneval.js generated vendored Normal file
View File

@@ -0,0 +1,552 @@
import {
DevalueError,
enumerable_symbols,
escaped,
get_type,
is_plain_object,
is_primitive,
stringify_key,
stringify_string,
valid_array_indices
} from './utils.js';
const chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_$';
const unsafe_chars = /[<\b\f\n\r\t\0\u2028\u2029]/g;
const reserved =
/^(?:do|if|in|for|int|let|new|try|var|byte|case|char|else|enum|goto|long|this|void|with|await|break|catch|class|const|final|float|short|super|throw|while|yield|delete|double|export|import|native|return|switch|throws|typeof|boolean|default|extends|finally|package|private|abstract|continue|debugger|function|volatile|interface|protected|transient|implements|instanceof|synchronized)$/;
/**
* Turn a value into the JavaScript that creates an equivalent value
* @param {any} value
* @param {(value: any, uneval: (value: any) => string) => string | void} [replacer]
*/
export function uneval(value, replacer) {
const counts = new Map();
/** @type {string[]} */
const keys = [];
const custom = new Map();
/** @param {any} thing */
function walk(thing) {
if (!is_primitive(thing)) {
if (counts.has(thing)) {
counts.set(thing, counts.get(thing) + 1);
return;
}
counts.set(thing, 1);
if (replacer) {
const str = replacer(thing, (value) => uneval(value, replacer));
if (typeof str === 'string') {
custom.set(thing, str);
return;
}
}
if (typeof thing === 'function') {
throw new DevalueError(`Cannot stringify a function`, keys, thing, value);
}
const type = get_type(thing);
switch (type) {
case 'Number':
case 'BigInt':
case 'String':
case 'Boolean':
case 'Date':
case 'RegExp':
case 'URL':
case 'URLSearchParams':
return;
case 'Array':
/** @type {any[]} */ (thing).forEach((value, i) => {
keys.push(`[${i}]`);
walk(value);
keys.pop();
});
break;
case 'Set':
Array.from(thing).forEach(walk);
break;
case 'Map':
for (const [key, value] of thing) {
keys.push(`.get(${is_primitive(key) ? stringify_primitive(key) : '...'})`);
walk(value);
keys.pop();
}
break;
case 'Int8Array':
case 'Uint8Array':
case 'Uint8ClampedArray':
case 'Int16Array':
case 'Uint16Array':
case 'Float16Array':
case 'Int32Array':
case 'Uint32Array':
case 'Float32Array':
case 'Float64Array':
case 'BigInt64Array':
case 'BigUint64Array':
case 'DataView':
walk(thing.buffer);
return;
case 'ArrayBuffer':
return;
case 'Temporal.Duration':
case 'Temporal.Instant':
case 'Temporal.PlainDate':
case 'Temporal.PlainTime':
case 'Temporal.PlainDateTime':
case 'Temporal.PlainMonthDay':
case 'Temporal.PlainYearMonth':
case 'Temporal.ZonedDateTime':
return;
default:
if (!is_plain_object(thing)) {
throw new DevalueError(`Cannot stringify arbitrary non-POJOs`, keys, thing, value);
}
if (enumerable_symbols(thing).length > 0) {
throw new DevalueError(`Cannot stringify POJOs with symbolic keys`, keys, thing, value);
}
for (const key of Object.keys(thing)) {
if (key === '__proto__') {
throw new DevalueError(
`Cannot stringify objects with __proto__ keys`,
keys,
thing,
value
);
}
keys.push(stringify_key(key));
walk(thing[key]);
keys.pop();
}
}
} else if (typeof thing === 'symbol') {
throw new DevalueError(`Cannot stringify a Symbol primitive`, keys, thing, value);
}
}
walk(value);
const names = new Map();
Array.from(counts)
.filter((entry) => entry[1] > 1)
.sort((a, b) => b[1] - a[1])
.forEach((entry, i) => {
names.set(entry[0], get_name(i));
});
/**
* @param {any} thing
* @returns {string}
*/
function stringify(thing) {
if (names.has(thing)) {
return names.get(thing);
}
if (is_primitive(thing)) {
return stringify_primitive(thing);
}
if (custom.has(thing)) {
return custom.get(thing);
}
const type = get_type(thing);
switch (type) {
case 'Number':
case 'String':
case 'Boolean':
case 'BigInt':
return `Object(${stringify(thing.valueOf())})`;
case 'RegExp':
const { source, flags } = thing;
return flags
? `new RegExp(${stringify_string(source)},"${flags}")`
: `new RegExp(${stringify_string(source)})`;
case 'Date':
return `new Date(${thing.getTime()})`;
case 'URL':
return `new URL(${stringify_string(thing.toString())})`;
case 'URLSearchParams':
return `new URLSearchParams(${stringify_string(thing.toString())})`;
case 'Array': {
// For dense arrays (no holes), we iterate normally.
// When we encounter the first hole, we call Object.keys
// to determine the sparseness, then decide between:
// - Array literal with holes: [,"a",,] (default)
// - Object.assign: Object.assign(Array(n),{...}) (for very sparse arrays)
// Only the Object.assign path avoids iterating every slot, which
// is what protects against the DoS of e.g. `arr[1000000] = 1`.
let has_holes = false;
let result = '[';
for (let i = 0; i < thing.length; i += 1) {
if (i > 0) result += ',';
if (Object.hasOwn(thing, i)) {
result += stringify(thing[i]);
} else if (!has_holes) {
// Decide between array literal and Object.assign.
//
// Array literal: holes are consecutive commas.
// For example, [, "a", ,] is written as [,"a",,].
// Each hole costs 1 char (a comma).
//
// Object.assign: populated indices are listed explicitly.
// For example, [, "a", ,] would be written as
// Object.assign(Array(3),{1:"a"}). This avoids paying
// per-hole, but has a large fixed overhead for the
// "Object.assign(Array(n),{...})" wrapper, and each
// element costs extra chars for its index and colon.
//
// The serialized values are the same size either way, so
// the choice comes down to the structural overhead:
//
// Array literal overhead:
// 1 char per element or hole (comma separators)
// + 2 chars for "[" and "]"
// = L + 2
//
// Object.assign overhead:
// "Object.assign(Array(" — 20 chars
// + length — d chars
// + "),{" — 3 chars
// + for each populated element:
// index + ":" + "," — (d + 2) chars
// + "})" — 2 chars
// = (25 + d) + P * (d + 2)
//
// where L is the array length, P is the number of
// populated elements, and d is the number of digits
// in L (an upper bound on the digits in any index).
//
// Object.assign is cheaper when:
// (25 + d) + P * (d + 2) < L + 2
const populated_keys = valid_array_indices(/** @type {any[]} */ (thing));
const population = populated_keys.length;
const d = String(thing.length).length;
const hole_cost = thing.length + 2;
const sparse_cost = 25 + d + population * (d + 2);
if (hole_cost > sparse_cost) {
const entries = populated_keys.map((k) => `${k}:${stringify(thing[k])}`).join(',');
return `Object.assign(Array(${thing.length}),{${entries}})`;
}
// Re-process this index as a hole in the array literal
has_holes = true;
i -= 1;
}
// else: already decided on array literal, hole is just an empty slot
// (the comma separator is all we need — no content for this position)
}
const tail = thing.length === 0 || thing.length - 1 in thing ? '' : ',';
return result + tail + ']';
}
case 'Set':
case 'Map':
return `new ${type}([${Array.from(thing).map(stringify).join(',')}])`;
case 'Int8Array':
case 'Uint8Array':
case 'Uint8ClampedArray':
case 'Int16Array':
case 'Uint16Array':
case 'Float16Array':
case 'Int32Array':
case 'Uint32Array':
case 'Float32Array':
case 'Float64Array':
case 'BigInt64Array':
case 'BigUint64Array': {
let str = `new ${type}`;
if (!names.has(thing.buffer)) {
const array = new thing.constructor(thing.buffer);
str += `([${array}])`;
} else {
str += `(${stringify(thing.buffer)})`;
}
// handle subarrays
if (thing.byteLength !== thing.buffer.byteLength) {
const start = thing.byteOffset / thing.BYTES_PER_ELEMENT;
const end = start + thing.length;
str += `.subarray(${start},${end})`;
}
return str;
}
case 'DataView': {
let str = `new DataView`;
if (!names.has(thing.buffer)) {
str += `(new Uint8Array([${new Uint8Array(thing.buffer)}]).buffer`;
} else {
str += `(${stringify(thing.buffer)}`;
}
// handle subviews
if (thing.byteLength !== thing.buffer.byteLength) {
str += `,${thing.startOffset},${thing.byteLength}`;
}
return str + ')';
}
case 'ArrayBuffer': {
const ui8 = new Uint8Array(thing);
return `new Uint8Array([${ui8.toString()}]).buffer`;
}
case 'Temporal.Duration':
case 'Temporal.Instant':
case 'Temporal.PlainDate':
case 'Temporal.PlainTime':
case 'Temporal.PlainDateTime':
case 'Temporal.PlainMonthDay':
case 'Temporal.PlainYearMonth':
case 'Temporal.ZonedDateTime':
return `${type}.from(${stringify_string(thing.toString())})`;
default:
const keys = Object.keys(thing);
const obj = keys.map((key) => `${safe_key(key)}:${stringify(thing[key])}`).join(',');
const proto = Object.getPrototypeOf(thing);
if (proto === null) {
return keys.length > 0 ? `{${obj},__proto__:null}` : `{__proto__:null}`;
}
return `{${obj}}`;
}
}
const str = stringify(value);
if (names.size) {
/** @type {string[]} */
const params = [];
/** @type {string[]} */
const statements = [];
/** @type {string[]} */
const values = [];
names.forEach((name, thing) => {
params.push(name);
if (custom.has(thing)) {
values.push(/** @type {string} */ (custom.get(thing)));
return;
}
if (is_primitive(thing)) {
values.push(stringify_primitive(thing));
return;
}
const type = get_type(thing);
switch (type) {
case 'Number':
case 'String':
case 'Boolean':
case 'BigInt':
values.push(`Object(${stringify(thing.valueOf())})`);
break;
case 'RegExp':
const { source, flags } = thing;
const regexp = flags
? `new RegExp(${stringify_string(source)},"${flags}")`
: `new RegExp(${stringify_string(source)})`
values.push(regexp);
break;
case 'Date':
values.push(`new Date(${thing.getTime()})`);
break;
case 'URL':
values.push(`new URL(${stringify_string(thing.toString())})`);
break;
case 'URLSearchParams':
values.push(`new URLSearchParams(${stringify_string(thing.toString())})`);
break;
case 'Array':
values.push(`Array(${thing.length})`);
/** @type {any[]} */ (thing).forEach((v, i) => {
statements.push(`${name}[${i}]=${stringify(v)}`);
});
break;
case 'Set':
values.push(`new Set`);
statements.push(
`${name}.${Array.from(thing)
.map((v) => `add(${stringify(v)})`)
.join('.')}`
);
break;
case 'Map':
values.push(`new Map`);
statements.push(
`${name}.${Array.from(thing)
.map(([k, v]) => `set(${stringify(k)}, ${stringify(v)})`)
.join('.')}`
);
break;
case 'Int8Array':
case 'Uint8Array':
case 'Uint8ClampedArray':
case 'Int16Array':
case 'Uint16Array':
case 'Float16Array':
case 'Int32Array':
case 'Uint32Array':
case 'Float32Array':
case 'Float64Array':
case 'BigInt64Array':
case 'BigUint64Array': {
let str = `new ${type}`;
if (!names.has(thing.buffer)) {
const array = new thing.constructor(thing.buffer);
str += `([${array}])`;
} else {
str += `(${stringify(thing.buffer)})`;
}
// handle subarrays
if (thing.byteLength !== thing.buffer.byteLength) {
const start = thing.byteOffset / thing.BYTES_PER_ELEMENT;
const end = start + thing.length;
str += `.subarray(${start},${end})`;
}
values.push(`{}`);
statements.push(`${name}=${str}`);
break;
}
case 'DataView': {
let str = `new DataView`;
if (!names.has(thing.buffer)) {
str += `(new Uint8Array([${new Uint8Array(thing.buffer)}]).buffer`;
} else {
str += `(${stringify(thing.buffer)}`;
}
// handle subviews
if (thing.byteLength !== thing.buffer.byteLength) {
str += `,${thing.byteOffset},${thing.byteLength}`;
}
str += ')';
values.push(`{}`);
statements.push(`${name}=${str}`);
break;
}
case 'ArrayBuffer':
values.push(`new Uint8Array([${new Uint8Array(thing)}]).buffer`);
break;
default:
values.push(Object.getPrototypeOf(thing) === null ? 'Object.create(null)' : '{}');
Object.keys(thing).forEach((key) => {
statements.push(`${name}${safe_prop(key)}=${stringify(thing[key])}`);
});
}
});
statements.push(`return ${str}`);
return `(function(${params.join(',')}){${statements.join(';')}}(${values.join(',')}))`;
} else {
return str;
}
}
/** @param {number} num */
function get_name(num) {
let name = '';
do {
name = chars[num % chars.length] + name;
num = ~~(num / chars.length) - 1;
} while (num >= 0);
return reserved.test(name) ? `${name}0` : name;
}
/** @param {string} c */
function escape_unsafe_char(c) {
return escaped[c] || c;
}
/** @param {string} str */
function escape_unsafe_chars(str) {
return str.replace(unsafe_chars, escape_unsafe_char);
}
/** @param {string} key */
function safe_key(key) {
return /^[_$a-zA-Z][_$a-zA-Z0-9]*$/.test(key) ? key : escape_unsafe_chars(JSON.stringify(key));
}
/** @param {string} key */
function safe_prop(key) {
return /^[_$a-zA-Z][_$a-zA-Z0-9]*$/.test(key)
? `.${key}`
: `[${escape_unsafe_chars(JSON.stringify(key))}]`;
}
/** @param {any} thing */
function stringify_primitive(thing) {
const type = typeof thing;
if (type === 'string') return stringify_string(thing);
if (thing === void 0) return 'void 0';
if (thing === 0 && 1 / thing < 0) return '-0';
const str = String(thing);
if (type === 'number') return str.replace(/^(-)?0\./, '$1.');
if (type === 'bigint') return thing + 'n';
return str;
}

144
node_modules/devalue/src/utils.js generated vendored Normal file
View File

@@ -0,0 +1,144 @@
/** @type {Record<string, string>} */
export const escaped = {
'<': '\\u003C',
'\\': '\\\\',
'\b': '\\b',
'\f': '\\f',
'\n': '\\n',
'\r': '\\r',
'\t': '\\t',
'\u2028': '\\u2028',
'\u2029': '\\u2029'
};
export class DevalueError extends Error {
/**
* @param {string} message
* @param {string[]} keys
* @param {any} [value] - The value that failed to be serialized
* @param {any} [root] - The root value being serialized
*/
constructor(message, keys, value, root) {
super(message);
this.name = 'DevalueError';
this.path = keys.join('');
this.value = value;
this.root = root;
}
}
/** @param {any} thing */
export function is_primitive(thing) {
return thing === null || (typeof thing !== 'object' && typeof thing !== 'function');
}
const object_proto_names = /* @__PURE__ */ Object.getOwnPropertyNames(Object.prototype)
.sort()
.join('\0');
/** @param {any} thing */
export function is_plain_object(thing) {
const proto = Object.getPrototypeOf(thing);
return (
proto === Object.prototype ||
proto === null ||
Object.getPrototypeOf(proto) === null ||
Object.getOwnPropertyNames(proto).sort().join('\0') === object_proto_names
);
}
/** @param {any} thing */
export function get_type(thing) {
return Object.prototype.toString.call(thing).slice(8, -1);
}
/** @param {string} char */
function get_escaped_char(char) {
switch (char) {
case '"':
return '\\"';
case '<':
return '\\u003C';
case '\\':
return '\\\\';
case '\n':
return '\\n';
case '\r':
return '\\r';
case '\t':
return '\\t';
case '\b':
return '\\b';
case '\f':
return '\\f';
case '\u2028':
return '\\u2028';
case '\u2029':
return '\\u2029';
default:
return char < ' ' ? `\\u${char.charCodeAt(0).toString(16).padStart(4, '0')}` : '';
}
}
/** @param {string} str */
export function stringify_string(str) {
let result = '';
let last_pos = 0;
const len = str.length;
for (let i = 0; i < len; i += 1) {
const char = str[i];
const replacement = get_escaped_char(char);
if (replacement) {
result += str.slice(last_pos, i) + replacement;
last_pos = i + 1;
}
}
return `"${last_pos === 0 ? str : result + str.slice(last_pos)}"`;
}
/** @param {Record<string | symbol, any>} object */
export function enumerable_symbols(object) {
return Object.getOwnPropertySymbols(object).filter(
(symbol) => Object.getOwnPropertyDescriptor(object, symbol).enumerable
);
}
const is_identifier = /^[a-zA-Z_$][a-zA-Z_$0-9]*$/;
/** @param {string} key */
export function stringify_key(key) {
return is_identifier.test(key) ? '.' + key : '[' + JSON.stringify(key) + ']';
}
/** @param {string} s */
function is_valid_array_index(s) {
if (s.length === 0) return false;
if (s.length > 1 && s.charCodeAt(0) === 48) return false; // leading zero
for (let i = 0; i < s.length; i++) {
const c = s.charCodeAt(i);
if (c < 48 || c > 57) return false;
}
// by this point we know it's a string of digits, but it has to be within the range of valid array indices
const n = +s;
if (n >= 2 ** 32 - 1) return false;
if (n < 0) return false;
return true;
}
/**
* Finds the populated indices of an array.
* @param {unknown[]} array
*/
export function valid_array_indices(array) {
const keys = Object.keys(array);
for (var i = keys.length - 1; i >= 0; i--) {
if (is_valid_array_index(keys[i])) {
break;
}
}
keys.length = i + 1;
return keys;
}

63
node_modules/devalue/src/utils.test.js generated vendored Normal file
View File

@@ -0,0 +1,63 @@
import * as assert from 'uvu/assert';
import { suite } from 'uvu';
import { valid_array_indices } from './utils.js';
const test = suite('valid_array_indices');
test('returns all indices for a normal dense array', () => {
const arr = ['a', 'b', 'c'];
assert.equal(valid_array_indices(arr), ['0', '1', '2']);
});
test('returns empty array for an empty array', () => {
assert.equal(valid_array_indices([]), []);
});
test('returns populated indices for a sparse array', () => {
const arr = [, 'b', ,];
assert.equal(valid_array_indices(arr), ['1']);
});
test('strips non-numeric properties from a dense array', () => {
const arr = ['a', 'b'];
arr.foo = 'x';
arr.bar = 42;
assert.equal(valid_array_indices(arr), ['0', '1']);
});
test('strips non-numeric properties from a very sparse array', () => {
const arr = [];
arr[1_000_000] = 'x';
arr.foo = 'should be ignored';
assert.equal(valid_array_indices(arr), ['1000000']);
});
test('returns empty array when only non-numeric properties exist', () => {
const arr = [];
arr.foo = 'x';
arr.bar = 42;
assert.equal(valid_array_indices(arr), []);
});
test('handles multiple non-numeric properties after indices', () => {
const arr = [1, 2, 3];
arr.a = 'x';
arr.b = 'y';
arr.c = 'z';
assert.equal(valid_array_indices(arr), ['0', '1', '2']);
});
test('handles a single-element array with non-numeric property', () => {
const arr = ['only'];
arr.extra = true;
assert.equal(valid_array_indices(arr), ['0']);
});
test('handles array properties pretending to be indices', () => {
const arr = ['a', 'b'];
arr[-1] = 'negative index';
arr[2 ** 32 - 1] = 'too large index';
assert.equal(valid_array_indices(arr), ['0', '1']);
});
test.run();

36
node_modules/devalue/types/index.d.ts generated vendored Normal file
View File

@@ -0,0 +1,36 @@
declare module 'devalue' {
/**
* Turn a value into the JavaScript that creates an equivalent value
*
*/
export function uneval(value: any, replacer?: (value: any, uneval: (value: any) => string) => string | void): string;
/**
* Turn a value into a JSON string that can be parsed with `devalue.parse`
*
*/
export function stringify(value: any, reducers?: Record<string, (value: any) => any>): string;
export class DevalueError extends Error {
/**
* @param value - The value that failed to be serialized
* @param root - The root value being serialized
*/
constructor(message: string, keys: string[], value?: any, root?: any);
path: string;
value: any;
root: any;
}
/**
* Revive a value serialized with `devalue.stringify`
*
*/
export function parse(serialized: string, revivers?: Record<string, (value: any) => any>): any;
/**
* Revive a value flattened with `devalue.stringify`
*
*/
export function unflatten(parsed: number | any[], revivers?: Record<string, (value: any) => any>): any;
export {};
}
//# sourceMappingURL=index.d.ts.map

25
node_modules/devalue/types/index.d.ts.map generated vendored Normal file
View File

@@ -0,0 +1,25 @@
{
"version": 3,
"file": "index.d.ts",
"names": [
"uneval",
"stringify",
"DevalueError",
"parse",
"unflatten"
],
"sources": [
"../src/uneval.js",
"../src/stringify.js",
"../src/utils.js",
"../src/parse.js"
],
"sourcesContent": [
null,
null,
null,
null
],
"mappings": ";;;;;iBAsBgBA,MAAMA;;;;;iBCINC,SAASA;cCbZC,YAAYA;;;;;;;;;;;;;;iBCGTC,KAAKA;;;;;iBASLC,SAASA",
"ignoreList": []
}