@vielzeug/arsenal 1.1.1 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +31 -75
- package/dist/_dev.cjs +1 -1
- package/dist/_dev.cjs.map +1 -1
- package/dist/_dev.js +2 -5
- package/dist/_dev.js.map +1 -1
- package/dist/array/chunk.cjs +1 -1
- package/dist/array/chunk.cjs.map +1 -1
- package/dist/array/chunk.d.ts +2 -1
- package/dist/array/chunk.d.ts.map +1 -1
- package/dist/array/chunk.js +5 -7
- package/dist/array/chunk.js.map +1 -1
- package/dist/array/compare.cjs +1 -1
- package/dist/array/compare.cjs.map +1 -1
- package/dist/array/compare.d.ts.map +1 -1
- package/dist/array/compare.js +13 -14
- package/dist/array/compare.js.map +1 -1
- package/dist/array/index.cjs +1 -0
- package/dist/array/index.js +29 -0
- package/dist/array/search.cjs +1 -1
- package/dist/array/search.cjs.map +1 -1
- package/dist/array/search.d.ts +8 -77
- package/dist/array/search.d.ts.map +1 -1
- package/dist/array/search.js +21 -38
- package/dist/array/search.js.map +1 -1
- package/dist/array/sort.cjs +1 -1
- package/dist/array/sort.cjs.map +1 -1
- package/dist/array/sort.d.ts +1 -1
- package/dist/array/sort.d.ts.map +1 -1
- package/dist/array/sort.js +9 -10
- package/dist/array/sort.js.map +1 -1
- package/dist/arsenal.cjs +1 -1
- package/dist/arsenal.cjs.map +1 -1
- package/dist/arsenal.iife.js +1 -1
- package/dist/arsenal.iife.js.map +1 -1
- package/dist/arsenal.js +1 -1
- package/dist/arsenal.js.map +1 -1
- package/dist/async/attempt.cjs +1 -1
- package/dist/async/attempt.cjs.map +1 -1
- package/dist/async/attempt.d.ts +3 -8
- package/dist/async/attempt.d.ts.map +1 -1
- package/dist/async/attempt.js +3 -10
- package/dist/async/attempt.js.map +1 -1
- package/dist/async/index.cjs +1 -0
- package/dist/async/index.d.ts +1 -1
- package/dist/async/index.d.ts.map +1 -1
- package/dist/async/index.js +9 -0
- package/dist/async/parallel.cjs +1 -1
- package/dist/async/parallel.cjs.map +1 -1
- package/dist/async/parallel.d.ts +1 -1
- package/dist/async/parallel.d.ts.map +1 -1
- package/dist/async/parallel.js +15 -16
- package/dist/async/parallel.js.map +1 -1
- package/dist/async/retry.cjs +1 -1
- package/dist/async/retry.cjs.map +1 -1
- package/dist/async/retry.d.ts +1 -1
- package/dist/async/retry.d.ts.map +1 -1
- package/dist/async/retry.js +14 -15
- package/dist/async/retry.js.map +1 -1
- package/dist/async/taskPool.cjs +2 -0
- package/dist/async/taskPool.cjs.map +1 -0
- package/dist/async/taskPool.d.ts +14 -0
- package/dist/async/taskPool.d.ts.map +1 -0
- package/dist/async/taskPool.js +51 -0
- package/dist/async/taskPool.js.map +1 -0
- package/dist/cache/cache.cjs +2 -0
- package/dist/cache/cache.cjs.map +1 -0
- package/dist/cache/cache.d.ts +17 -0
- package/dist/cache/cache.d.ts.map +1 -0
- package/dist/cache/cache.js +59 -0
- package/dist/cache/cache.js.map +1 -0
- package/dist/cache/index.cjs +1 -0
- package/dist/cache/index.d.ts +1 -1
- package/dist/cache/index.d.ts.map +1 -1
- package/dist/cache/index.js +3 -0
- package/dist/cache/memo.cjs +1 -1
- package/dist/cache/memo.cjs.map +1 -1
- package/dist/cache/memo.d.ts +2 -2
- package/dist/cache/memo.js +24 -23
- package/dist/cache/memo.js.map +1 -1
- package/dist/errors.cjs +1 -1
- package/dist/errors.cjs.map +1 -1
- package/dist/errors.d.ts +0 -7
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +2 -2
- package/dist/errors.js.map +1 -1
- package/dist/function/debounce.cjs +1 -1
- package/dist/function/debounce.cjs.map +1 -1
- package/dist/function/debounce.js +15 -17
- package/dist/function/debounce.js.map +1 -1
- package/dist/function/index.cjs +1 -0
- package/dist/function/index.d.ts +0 -2
- package/dist/function/index.d.ts.map +1 -1
- package/dist/function/index.js +8 -0
- package/dist/function/pipe.cjs +1 -1
- package/dist/function/pipe.cjs.map +1 -1
- package/dist/function/pipe.js +1 -1
- package/dist/function/pipe.js.map +1 -1
- package/dist/guards/index.cjs +1 -0
- package/dist/guards/index.d.ts +0 -3
- package/dist/guards/index.d.ts.map +1 -1
- package/dist/guards/index.js +17 -0
- package/dist/guards/isEqual.cjs.map +1 -1
- package/dist/guards/isEqual.js.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +2 -91
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +30 -118
- package/dist/math/allocate.cjs +1 -1
- package/dist/math/allocate.cjs.map +1 -1
- package/dist/math/allocate.d.ts +1 -1
- package/dist/math/allocate.d.ts.map +1 -1
- package/dist/math/allocate.js +13 -14
- package/dist/math/allocate.js.map +1 -1
- package/dist/math/index.cjs +1 -0
- package/dist/math/index.d.ts +0 -3
- package/dist/math/index.d.ts.map +1 -1
- package/dist/math/index.js +17 -0
- package/dist/math/mod.cjs +1 -1
- package/dist/math/mod.cjs.map +1 -1
- package/dist/math/mod.d.ts +1 -1
- package/dist/math/mod.d.ts.map +1 -1
- package/dist/math/mod.js +4 -5
- package/dist/math/mod.js.map +1 -1
- package/dist/math/range.cjs +1 -1
- package/dist/math/range.cjs.map +1 -1
- package/dist/math/range.d.ts +1 -1
- package/dist/math/range.d.ts.map +1 -1
- package/dist/math/range.js +14 -15
- package/dist/math/range.js.map +1 -1
- package/dist/math/sum.cjs +1 -1
- package/dist/math/sum.cjs.map +1 -1
- package/dist/math/sum.d.ts +2 -2
- package/dist/math/sum.d.ts.map +1 -1
- package/dist/math/sum.js +6 -7
- package/dist/math/sum.js.map +1 -1
- package/dist/object/getPath.cjs +1 -1
- package/dist/object/getPath.cjs.map +1 -1
- package/dist/object/getPath.d.ts +12 -42
- package/dist/object/getPath.d.ts.map +1 -1
- package/dist/object/getPath.js +21 -22
- package/dist/object/getPath.js.map +1 -1
- package/dist/object/index.cjs +1 -0
- package/dist/object/index.d.ts +1 -1
- package/dist/object/index.d.ts.map +1 -1
- package/dist/object/index.js +15 -0
- package/dist/object/merge.cjs +1 -1
- package/dist/object/merge.cjs.map +1 -1
- package/dist/object/merge.d.ts +1 -1
- package/dist/object/merge.d.ts.map +1 -1
- package/dist/object/merge.js +2 -3
- package/dist/object/merge.js.map +1 -1
- package/dist/object/prune.cjs +1 -1
- package/dist/object/prune.cjs.map +1 -1
- package/dist/object/prune.d.ts.map +1 -1
- package/dist/object/prune.js +22 -23
- package/dist/object/prune.js.map +1 -1
- package/dist/object/tryParseJson.cjs +2 -0
- package/dist/object/tryParseJson.cjs.map +1 -0
- package/dist/object/tryParseJson.d.ts +9 -0
- package/dist/object/tryParseJson.d.ts.map +1 -0
- package/dist/object/tryParseJson.js +18 -0
- package/dist/object/tryParseJson.js.map +1 -0
- package/dist/random/_index.cjs +2 -0
- package/dist/random/_index.cjs.map +1 -0
- package/dist/random/_index.d.ts +3 -0
- package/dist/random/_index.d.ts.map +1 -0
- package/dist/random/_index.js +10 -0
- package/dist/random/_index.js.map +1 -0
- package/dist/random/draw.cjs +1 -1
- package/dist/random/draw.cjs.map +1 -1
- package/dist/random/draw.d.ts +3 -2
- package/dist/random/draw.d.ts.map +1 -1
- package/dist/random/draw.js +12 -12
- package/dist/random/draw.js.map +1 -1
- package/dist/random/index.cjs +1 -0
- package/dist/random/index.d.ts +1 -0
- package/dist/random/index.d.ts.map +1 -1
- package/dist/random/index.js +5 -0
- package/dist/random/random.cjs +1 -1
- package/dist/random/random.cjs.map +1 -1
- package/dist/random/random.d.ts +2 -1
- package/dist/random/random.d.ts.map +1 -1
- package/dist/random/random.js +5 -6
- package/dist/random/random.js.map +1 -1
- package/dist/random/shuffle.cjs +1 -1
- package/dist/random/shuffle.cjs.map +1 -1
- package/dist/random/shuffle.d.ts +2 -1
- package/dist/random/shuffle.d.ts.map +1 -1
- package/dist/random/shuffle.js +7 -7
- package/dist/random/shuffle.js.map +1 -1
- package/dist/random/source.d.ts +4 -0
- package/dist/random/source.d.ts.map +1 -0
- package/dist/string/index.cjs +1 -0
- package/dist/string/index.d.ts +0 -2
- package/dist/string/index.d.ts.map +1 -1
- package/dist/string/index.js +12 -0
- package/dist/string/similarity.cjs +1 -1
- package/dist/string/similarity.cjs.map +1 -1
- package/dist/string/similarity.d.ts.map +1 -1
- package/dist/string/similarity.js +16 -17
- package/dist/string/similarity.js.map +1 -1
- package/dist/string/truncate.cjs +1 -1
- package/dist/string/truncate.cjs.map +1 -1
- package/dist/string/truncate.d.ts +2 -1
- package/dist/string/truncate.d.ts.map +1 -1
- package/dist/string/truncate.js +10 -11
- package/dist/string/truncate.js.map +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +14 -19
- package/dist/_common/_secureRandomIndex.cjs +0 -2
- package/dist/_common/_secureRandomIndex.cjs.map +0 -1
- package/dist/_common/_secureRandomIndex.d.ts +0 -2
- package/dist/_common/_secureRandomIndex.d.ts.map +0 -1
- package/dist/_common/_secureRandomIndex.js +0 -9
- package/dist/_common/_secureRandomIndex.js.map +0 -1
- package/dist/async/queue.cjs +0 -2
- package/dist/async/queue.cjs.map +0 -1
- package/dist/async/queue.d.ts +0 -42
- package/dist/async/queue.d.ts.map +0 -1
- package/dist/async/queue.js +0 -72
- package/dist/async/queue.js.map +0 -1
- package/dist/cache/stash.cjs +0 -2
- package/dist/cache/stash.cjs.map +0 -1
- package/dist/cache/stash.d.ts +0 -111
- package/dist/cache/stash.d.ts.map +0 -1
- package/dist/cache/stash.js +0 -92
- package/dist/cache/stash.js.map +0 -1
- package/dist/function/constant.cjs +0 -2
- package/dist/function/constant.cjs.map +0 -1
- package/dist/function/constant.d.ts +0 -5
- package/dist/function/constant.d.ts.map +0 -1
- package/dist/function/constant.js +0 -8
- package/dist/function/constant.js.map +0 -1
- package/dist/function/identity.cjs +0 -2
- package/dist/function/identity.cjs.map +0 -1
- package/dist/function/identity.d.ts +0 -5
- package/dist/function/identity.d.ts.map +0 -1
- package/dist/function/identity.js +0 -8
- package/dist/function/identity.js.map +0 -1
- package/dist/guards/isArray.cjs +0 -2
- package/dist/guards/isArray.cjs.map +0 -1
- package/dist/guards/isArray.d.ts +0 -16
- package/dist/guards/isArray.d.ts.map +0 -1
- package/dist/guards/isArray.js +0 -8
- package/dist/guards/isArray.js.map +0 -1
- package/dist/guards/isBoolean.cjs +0 -2
- package/dist/guards/isBoolean.cjs.map +0 -1
- package/dist/guards/isBoolean.d.ts +0 -23
- package/dist/guards/isBoolean.d.ts.map +0 -1
- package/dist/guards/isBoolean.js +0 -8
- package/dist/guards/isBoolean.js.map +0 -1
- package/dist/guards/isString.cjs +0 -2
- package/dist/guards/isString.cjs.map +0 -1
- package/dist/guards/isString.d.ts +0 -15
- package/dist/guards/isString.d.ts.map +0 -1
- package/dist/guards/isString.js +0 -8
- package/dist/guards/isString.js.map +0 -1
- package/dist/math/abs.cjs +0 -2
- package/dist/math/abs.cjs.map +0 -1
- package/dist/math/abs.d.ts +0 -17
- package/dist/math/abs.d.ts.map +0 -1
- package/dist/math/abs.js +0 -8
- package/dist/math/abs.js.map +0 -1
- package/dist/math/max.cjs +0 -2
- package/dist/math/max.cjs.map +0 -1
- package/dist/math/max.d.ts +0 -21
- package/dist/math/max.d.ts.map +0 -1
- package/dist/math/max.js +0 -12
- package/dist/math/max.js.map +0 -1
- package/dist/math/min.cjs +0 -2
- package/dist/math/min.cjs.map +0 -1
- package/dist/math/min.d.ts +0 -21
- package/dist/math/min.d.ts.map +0 -1
- package/dist/math/min.js +0 -12
- package/dist/math/min.js.map +0 -1
- package/dist/object/parseJSON.cjs +0 -2
- package/dist/object/parseJSON.cjs.map +0 -1
- package/dist/object/parseJSON.d.ts +0 -32
- package/dist/object/parseJSON.d.ts.map +0 -1
- package/dist/object/parseJSON.js +0 -16
- package/dist/object/parseJSON.js.map +0 -1
- package/dist/string/endsWith.cjs +0 -2
- package/dist/string/endsWith.cjs.map +0 -1
- package/dist/string/endsWith.d.ts +0 -5
- package/dist/string/endsWith.d.ts.map +0 -1
- package/dist/string/endsWith.js +0 -8
- package/dist/string/endsWith.js.map +0 -1
- package/dist/string/startsWith.cjs +0 -2
- package/dist/string/startsWith.cjs.map +0 -1
- package/dist/string/startsWith.d.ts +0 -5
- package/dist/string/startsWith.d.ts.map +0 -1
- package/dist/string/startsWith.js +0 -8
- package/dist/string/startsWith.js.map +0 -1
package/dist/arsenal.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"arsenal.cjs","names":[],"sources":["../src/errors.ts","../src/guards/isString.ts","../src/array/chunk.ts","../src/array/compact.ts","../src/array/compare.ts","../src/array/compareBy.ts","../src/guards/isEqual.ts","../src/array/contains.ts","../src/_common/unsafePaths.ts","../src/array/countBy.ts","../src/_common/_selectorSet.ts","../src/array/difference.ts","../src/array/drop.ts","../src/array/dropLast.ts","../src/array/filterMap.ts","../src/array/first.ts","../src/array/flatten.ts","../src/array/groupBy.ts","../src/array/indexBy.ts","../src/array/intersection.ts","../src/array/last.ts","../src/array/partition.ts","../src/array/replace.ts","../src/array/rotate.ts","../src/guards/isNil.ts","../src/guards/isNumber.ts","../src/string/similarity.ts","../src/array/search.ts","../src/array/sort.ts","../src/array/take.ts","../src/array/takeLast.ts","../src/array/toggle.ts","../src/array/union.ts","../src/array/uniq.ts","../src/array/unzip.ts","../src/array/zip.ts","../src/async/abortError.ts","../src/async/attempt.ts","../src/async/backoff.ts","../src/async/parallel.ts","../src/async/queue.ts","../src/async/sleep.ts","../src/async/retry.ts","../src/async/waitFor.ts","../src/_common/_lruMap.ts","../src/cache/memo.ts","../src/guards/isPromise.ts","../src/cache/stash.ts","../src/function/assert.ts","../src/function/constant.ts","../src/_dev.ts","../src/function/debounce.ts","../src/function/identity.ts","../src/function/once.ts","../src/function/pipe.ts","../src/function/runAll.ts","../src/function/tap.ts","../src/function/throttle.ts","../src/guards/combinators.ts","../src/guards/isAbortError.ts","../src/guards/isArray.ts","../src/guards/isBoolean.ts","../src/guards/isDate.ts","../src/guards/isDefined.ts","../src/guards/isPlainObject.ts","../src/guards/isEmpty.ts","../src/guards/isError.ts","../src/guards/isFunction.ts","../src/guards/isMatch.ts","../src/guards/isPrimitive.ts","../src/guards/isRegex.ts","../src/guards/shallowEqual.ts","../src/math/abs.ts","../src/math/allocate.ts","../src/math/sum.ts","../src/math/average.ts","../src/math/clamp.ts","../src/math/gcd.ts","../src/math/lcm.ts","../src/math/lerp.ts","../src/math/linspace.ts","../src/math/max.ts","../src/math/median.ts","../src/math/min.ts","../src/math/mod.ts","../src/math/normalize.ts","../src/math/percent.ts","../src/math/range.ts","../src/math/round.ts","../src/math/variance.ts","../src/math/standardDeviation.ts","../src/object/defaults.ts","../src/object/diff.ts","../src/object/filterValues.ts","../src/object/flattenPaths.ts","../src/object/getPath.ts","../src/object/invert.ts","../src/object/mapKeys.ts","../src/object/mapValues.ts","../src/object/merge.ts","../src/object/omit.ts","../src/object/parseJSON.ts","../src/object/pick.ts","../src/object/prune.ts","../src/object/hash.ts","../src/_common/_secureRandomIndex.ts","../src/random/random.ts","../src/random/draw.ts","../src/random/shuffle.ts","../src/random/uuid.ts","../src/string/_caseUtils.ts","../src/string/camelCase.ts","../src/string/endsWith.ts","../src/string/escape.ts","../src/string/kebabCase.ts","../src/string/pad.ts","../src/string/pascalCase.ts","../src/string/snakeCase.ts","../src/string/startsWith.ts","../src/string/words.ts","../src/string/titleCase.ts","../src/string/truncate.ts","../src/string/unescape.ts"],"sourcesContent":["/** Base class for all arsenal errors. Use `instanceof ArsenalError` to catch any arsenal-originated error. */\nexport class ArsenalError extends Error {\n constructor(message: string, opts?: ErrorOptions) {\n super(message, opts);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n\n static is(err: unknown): err is ArsenalError {\n return err instanceof ArsenalError;\n }\n}\n\n/**\n * Thrown when a function argument or option is invalid — wrong type, out of range, or an\n * otherwise-unusable value (e.g. a negative `concurrency`, a non-finite `range` bound, an\n * oversized `similarity` input).\n */\nexport class ArsenalValidationError extends ArsenalError {}\n\n/**\n * Thrown when converting a value to or from its serialized form fails — e.g. `memo`'s default\n * cache key (`JSON.stringify`) encountering a circular reference, or `hash` encountering an\n * unsupported class instance with `{ onClassInstance: 'throw' }`.\n */\nexport class ArsenalSerializationError extends ArsenalError {}\n","/**\n * Determines if the passed value is a String.\n *\n * @example\n * ```ts\n * isString('Hello World'); // true\n * isString(42); // false\n * ```\n *\n * @param arg - The argument to be checked.\n *\n * @returns `true` if the value is a String, else `false`.\n */\nexport function isString(arg: unknown): arg is string {\n return typeof arg === 'string';\n}\n","import { ArsenalValidationError } from '../errors';\nimport { isString } from '../guards/isString';\n\n/**\n * Splits an array or string into chunks of a specified size.\n *\n * @example\n * ```ts\n * chunk([1, 2, 3, 4, 5], 2) // [[1, 2], [3, 4], [5]]\n * chunk('hello', 2) // ['he', 'll', 'o']\n * ```\n *\n * @param input - The input array or string to be chunked.\n * @param size - The size of each chunk (default 2).\n *\n * @returns An array of chunks.\n *\n * @throws {ArsenalValidationError} If the input is not an array or string, or if the chunk size is less than 1.\n */\nexport function chunk(input: string, size?: number): string[];\nexport function chunk<T>(input: T[], size?: number): T[][];\nexport function chunk<T>(input: T[] | string, size = 2): string[] | T[][] {\n if (!Array.isArray(input) && !isString(input))\n throw new ArsenalValidationError('chunk: argument must be an array or string');\n\n if (size < 1) throw new ArsenalValidationError('chunk: size must be at least 1');\n\n return Array.from({ length: Math.ceil(input.length / size) }, (_, i) => input.slice(i * size, i * size + size)) as\n string[] | T[][];\n}\n","type Falsy = false | '' | 0 | 0n | null | undefined;\n\n/**\n * Creates a new array with all falsy values removed.\n */\nexport function compact<T>(array: T[]): Array<Exclude<T, Falsy>> {\n return array.filter(Boolean) as Array<Exclude<T, Falsy>>;\n}\n","import { ArsenalValidationError } from '../errors';\n\n/**\n * Compares two values and returns a number suitable for use as a sort comparator.\n *\n * - Numbers and Dates: returns `0`, `1`, or `-1`.\n * - Strings: delegates to `String.prototype.localeCompare`, which may return any integer\n * (not just `0`, `1`, `-1`) depending on locale and engine.\n * - `null` sorts before all non-null values; `undefined` sorts last.\n *\n * @example\n * ```ts\n * compare('a', 'b'); // negative (locale-dependent)\n * compare(1, 2); // -1\n * compare(new Date('2023-01-01'), new Date('2023-01-02')); // -1\n * compare('a', 'a'); // 0\n * compare(1, 1); // 0\n * compare(new Date('2023-01-01'), new Date('2023-01-01')); // 0\n * ```\n *\n * @param a - The first value to compare.\n * @param b - The second value to compare.\n *\n * @returns A negative number, zero, or a positive number.\n *\n * Pass directly as an `Array.sort` comparator:\n * ```ts\n * [3, 1, 2].sort(compare); // [1, 2, 3]\n * ['banana', 'apple', 'cherry'].sort(compare); // ['apple', 'banana', 'cherry']\n * ```\n */\nexport const compare = (a: unknown, b: unknown): number => {\n if (a === b) return 0;\n\n if (a === undefined) return 1;\n\n if (b === undefined) return -1;\n\n if (a === null) return b === null ? 0 : -1;\n\n if (b === null) return 1;\n\n if (typeof a === 'string' && typeof b === 'string') {\n return a.localeCompare(b);\n }\n\n if (typeof a === 'number' && typeof b === 'number') {\n return a === b ? 0 : a > b ? 1 : -1;\n }\n\n if (a instanceof Date && b instanceof Date) {\n const at = a.getTime();\n const bt = b.getTime();\n\n return at === bt ? 0 : at > bt ? 1 : -1;\n }\n\n throw new ArsenalValidationError(\n `compare: unsupported types \"${typeof a}\" and \"${typeof b}\". Supported: number, string, Date, null, undefined.`,\n );\n};\n","import { compare } from './compare';\n\n/**\n * Compares two objects based on multiple selectors.\n * The comparison is done in the order of the selectors provided.\n * Each selector can be 'asc' for ascending or 'desc' for descending order.\n *\n * @example\n * ```ts\n * const compareByNameAndAge = compareBy<{ name: string; age: number }>({\n * name: 'asc',\n * age: 'desc',\n * });\n *\n * const a = { name: 'Alice', age: 30 };\n * const b = { name: 'Bob', age: 25 };\n *\n * console.log(compareByNameAndAge(a, b)); // -1 (Alice < Bob)\n * ```\n *\n * @param selectors - An object where keys are properties to compare and values are 'asc' or 'desc'.\n *\n * @returns A comparator for use with `Array.sort` or `sort()`.\n */\nexport const compareBy = <T>(selectors: Partial<Record<keyof T, 'asc' | 'desc'>>) => {\n const entries = Object.entries(selectors) as [keyof T, 'asc' | 'desc'][];\n\n return (a: T, b: T) => {\n for (const [key, direction] of entries) {\n const v1 = a[key];\n const v2 = b[key];\n const dir = direction === 'desc' ? -1 : 1;\n\n const cmp = compare(v1, v2);\n\n if (cmp !== 0) return cmp * dir;\n }\n\n return 0;\n };\n};\n","/**\n * Recursively compares two values for deep equality.\n * Supports plain objects, arrays, `Date`, `Map`, `Set`, `RegExp`, and circular references.\n *\n * Uses `===` for the primitive comparison, so `isEqual(NaN, NaN)` is `false` and\n * `isEqual(0, -0)` is `true` — the opposite of `shallowEqual`, which uses `Object.is` and\n * treats `NaN` as equal to itself and `-0` as distinct from `0`.\n *\n * For one-level-deep reference equality, use `shallowEqual` instead.\n *\n * @example\n * ```ts\n * isEqual([1, 2, 3], [1, 2, 3]); // true\n * isEqual({ a: { b: 2 } }, { a: { b: 2 } }); // true\n * isEqual(new Date('2023-01-01'), new Date('2023-01-01')); // true\n * isEqual(new Map([['k', 1]]), new Map([['k', 1]])); // true\n * ```\n *\n * @param a - First value to compare.\n * @param b - Second value to compare.\n * @returns `true` if the values are deeply equal.\n */\nexport function isEqual(a: unknown, b: unknown): boolean {\n return safeIsEqual(a, b, new WeakMap());\n}\n\nfunction safeIsEqual(a: unknown, b: unknown, visited: WeakMap<object, object>): boolean {\n // Check for strict equality (handles primitives and references)\n if (a === b) return true;\n\n // If either is null or not an object, they're not equal\n if (a == null || b == null || typeof a !== typeof b || typeof a !== 'object' || typeof b !== 'object') return false;\n\n // Check for circular references\n // We only track 'a' because if 'a' is cyclical, 'b' must also be cyclic to be equal\n if (visited.has(a as object)) {\n return visited.get(a as object) === b;\n }\n\n visited.set(a as object, b as object);\n\n // Array comparison\n if (Array.isArray(a) || Array.isArray(b)) {\n if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length) return false;\n\n return a.every((item, idx) => safeIsEqual(item, b[idx], visited));\n }\n\n // Date comparison\n if (a instanceof Date && b instanceof Date) {\n return a.getTime() === b.getTime();\n }\n\n // Map comparison\n if (a instanceof Map && b instanceof Map) {\n if (a.size !== b.size) return false;\n\n for (const [k, v] of a) {\n if (!b.has(k) || !safeIsEqual(v, b.get(k), visited)) return false;\n }\n\n return true;\n }\n\n // Set comparison — fast path for primitive values, deep for objects\n if (a instanceof Set && b instanceof Set) {\n if (a.size !== b.size) return false;\n\n const bItems = [...b];\n\n for (const v of a) {\n // O(1) path for primitives — avoid the O(n) .some() scan\n if (typeof v === 'string' || typeof v === 'number' || typeof v === 'boolean' || v === null || v === undefined) {\n if (!b.has(v)) return false;\n } else if (!bItems.some((bv) => safeIsEqual(v, bv, visited))) {\n return false;\n }\n }\n\n return true;\n }\n\n // RegExp comparison\n if (a instanceof RegExp || b instanceof RegExp) {\n return a instanceof RegExp && b instanceof RegExp && a.source === b.source && a.flags === b.flags;\n }\n\n // Cross-type guards: Map/Set vs plain objects are never equal\n if (a instanceof Map || b instanceof Map) return false;\n\n if (a instanceof Set || b instanceof Set) return false;\n\n // Object comparison\n const keysA = Object.keys(a);\n const keysB = Object.keys(b);\n\n if (keysA.length !== keysB.length) return false;\n\n for (const key of keysA) {\n if (\n !Object.hasOwn(b, key) ||\n !safeIsEqual((a as Record<string, unknown>)[key], (b as Record<string, unknown>)[key], visited)\n )\n return false;\n }\n\n return true;\n}\n","import { isEqual } from '../guards/isEqual';\n\n/**\n * Checks if a value is present in an array.\n *\n * @example\n * ```ts\n * const arr = [1, 2, 3, { a: 1 }, 'hello'];\n * const value = { a: 1 };\n * contains(arr, value) // true;\n * ```\n *\n * @param array - The array to check.\n * @param value - The value to search for.\n *\n * @returns true if the value is present in the array, else false.\n */\n\nexport function contains<T>(array: T[], value: unknown): boolean {\n // Fast path: reference / primitive equality via Array.includes — avoids\n // deep-equal traversal for the common case of searching for a scalar.\n if (value === null || value === undefined || typeof value !== 'object') {\n return array.includes(value as T);\n }\n\n return array.some((val) => isEqual(val, value));\n}\n","/**\n * Path segments that must be rejected in any dot-notation traversal or mutation\n * to prevent prototype pollution reads and writes.\n * @internal\n */\nexport const UNSAFE_PATH_SEGMENTS = new Set(['__proto__', 'constructor', 'prototype']);\n\n/**\n * Returns `true` if every dot-notation segment in `key` is safe to use as a\n * plain-object property.\n *\n * @example\n * ```ts\n * isSafePath('user.name') // true\n * isSafePath('__proto__.polluted') // false\n * ```\n */\nexport function isSafePath(key: string): boolean {\n return key.split('.').every((s) => !UNSAFE_PATH_SEGMENTS.has(s));\n}\n\n/**\n * Returns `true` if `key` is one of the dangerous own-property names that can be used to\n * pollute `Object.prototype` (`__proto__`, `constructor`, `prototype`). Use this for plain\n * (non-dotted) property keys — e.g. object keys being copied or reassigned. For dotted paths,\n * use `isSafePath` instead.\n *\n * @example\n * ```ts\n * isUnsafeKey('name') // false\n * isUnsafeKey('__proto__') // true\n * ```\n */\nexport function isUnsafeKey(key: PropertyKey): boolean {\n return typeof key === 'string' && UNSAFE_PATH_SEGMENTS.has(key);\n}\n","import type { Primitive } from '../types';\n\nimport { isUnsafeKey } from '../_common/unsafePaths';\n\n/**\n * Counts elements in an array by selector output. Selector results of `null`/`undefined` are\n * bucketed under the key `'_'`, matching `groupBy`'s convention. Dangerous keys (`__proto__`,\n * `constructor`, `prototype`) are skipped.\n */\nexport function countBy<T>(array: T[], selector: (item: T) => Primitive): Record<string, number> {\n const out: Record<string, number> = {};\n\n for (let index = 0; index < array.length; index++) {\n const rawKey = selector(array[index]);\n const key = rawKey === undefined || rawKey === null ? '_' : String(rawKey);\n\n if (isUnsafeKey(key)) continue;\n\n out[key] = (out[key] ?? 0) + 1;\n }\n\n return out;\n}\n","import type { Primitive } from '../types';\n\n/**\n * Builds a `Set` of `selector(item)` results for O(1) membership checks — shared by\n * `intersection()` and `difference()`.\n *\n * Module-private: underscore-prefixed file is excluded from barrel exports.\n * @internal\n */\nexport function toSelectorSet<T>(items: readonly T[], selector: (item: T) => Primitive): Set<Primitive> {\n return new Set(items.map((item) => selector(item)));\n}\n\n/**\n * Returns `items` with duplicate `selector(item)` results removed, preserving the first\n * occurrence of each key — shared by `union()` and `uniq()`.\n *\n * Module-private: underscore-prefixed file is excluded from barrel exports.\n * @internal\n */\nexport function dedupeBySelector<T>(items: readonly T[], selector: (item: T) => Primitive): T[] {\n const seen = new Set<Primitive>();\n const out: T[] = [];\n\n for (const item of items) {\n const key = selector(item);\n\n if (seen.has(key)) continue;\n\n seen.add(key);\n out.push(item);\n }\n\n return out;\n}\n","import type { Primitive } from '../types';\n\nimport { toSelectorSet } from '../_common/_selectorSet';\n\n/**\n * Returns elements that are in source but not in other.\n */\nexport function difference<T>(source: T[], other: T[], selector?: (item: T) => Primitive): T[] {\n if (!selector) {\n const deny = new Set(other);\n\n return source.filter((item) => !deny.has(item));\n }\n\n const deny = toSelectorSet(other, selector);\n\n return source.filter((item) => !deny.has(selector(item)));\n}\n","/**\n * Drops the first n elements from an array.\n */\nexport function drop<T>(array: T[], n = 1): T[] {\n const count = Math.max(0, Math.floor(n));\n\n return array.slice(count);\n}\n","/**\n * Drops the last n elements from an array.\n */\nexport function dropLast<T>(array: T[], n = 1): T[] {\n const count = Math.max(0, Math.floor(n));\n\n if (count === 0) return [...array];\n\n return array.slice(0, Math.max(0, array.length - count));\n}\n","/**\n * Maps and filters in one pass. Returning `undefined` drops an item.\n */\nexport function filterMap<T, R>(array: T[], callback: (item: T, index: number, array: T[]) => R | undefined): R[] {\n const result: R[] = [];\n\n for (let index = 0; index < array.length; index++) {\n const value = callback(array[index], index, array);\n\n if (value !== undefined) {\n result.push(value);\n }\n }\n\n return result;\n}\n","/**\n * Returns the first element or fallback when array is empty.\n */\nexport function first<T>(array: T[], fallback?: T): T | undefined {\n return array.length > 0 ? array[0] : fallback;\n}\n","/**\n * Flattens nested arrays up to the provided depth.\n */\nexport function flatten<T>(array: unknown[], depth = 1): T[] {\n if (depth < 1) return [...array] as T[];\n\n const out: unknown[] = [];\n\n for (const item of array) {\n if (Array.isArray(item)) {\n out.push(...flatten(item, depth - 1));\n } else {\n out.push(item);\n }\n }\n\n return out as T[];\n}\n","import type { Primitive } from '../types';\n\nimport { isUnsafeKey } from '../_common/unsafePaths';\n\n/**\n * Groups elements by a selector function. Dangerous keys (`__proto__`, `constructor`,\n * `prototype`) are skipped.\n */\nexport function groupBy<T>(array: T[], selector: (item: T) => Primitive): Record<string, T[]> {\n const result: Record<string, T[]> = {};\n\n for (const item of array) {\n const rawKey = selector(item);\n const key = rawKey === undefined || rawKey === null ? '_' : String(rawKey);\n\n if (isUnsafeKey(key)) continue;\n\n if (!result[key]) {\n result[key] = [];\n }\n\n result[key].push(item);\n }\n\n return result;\n}\n","import type { Primitive } from '../types';\n\nimport { isUnsafeKey } from '../_common/unsafePaths';\n\n/**\n * Creates an object keyed by selector result. Last item wins on collisions. Dangerous keys\n * (`__proto__`, `constructor`, `prototype`) are skipped.\n */\nexport function indexBy<T>(array: T[], selector: (item: T) => Primitive): Record<string, T> {\n const result: Record<string, T> = {};\n\n for (const item of array) {\n const key = String(selector(item));\n\n if (isUnsafeKey(key)) continue;\n\n result[key] = item;\n }\n\n return result;\n}\n","import type { Primitive } from '../types';\n\nimport { toSelectorSet } from '../_common/_selectorSet';\n\n/**\n * Returns elements that are present in both arrays.\n */\nexport function intersection<T>(source: T[], other: T[], selector?: (item: T) => Primitive): T[] {\n if (!selector) {\n const allow = new Set(other);\n\n return source.filter((item) => allow.has(item));\n }\n\n const allow = toSelectorSet(other, selector);\n\n return source.filter((item) => allow.has(selector(item)));\n}\n","/**\n * Returns the last element or fallback when array is empty.\n */\nexport function last<T>(array: T[], fallback?: T): T | undefined {\n return array.length > 0 ? array[array.length - 1] : fallback;\n}\n","/**\n * Splits an array into values that match and do not match the predicate.\n */\nexport function partition<T>(array: T[], predicate: (item: T, index: number, array: T[]) => boolean): [T[], T[]] {\n const accepted: T[] = [];\n const rejected: T[] = [];\n\n for (let index = 0; index < array.length; index++) {\n if (predicate(array[index], index, array)) {\n accepted.push(array[index]);\n } else {\n rejected.push(array[index]);\n }\n }\n\n return [accepted, rejected];\n}\n","import type { Predicate } from '../types';\n\n/**\n * Replaces the first element in an array that satisfies the provided predicate\n * function with a new value.\n *\n * @example\n * ```ts\n * replace([1, 2, 3], (n) => n === 2, 4) // [1, 4, 3]\n * ```\n *\n * @param array - The array to search.\n * @param predicate - A function to test each element of the array.\n * @param value - The new value to replace the found element.\n *\n * @return A new array with the replaced value.\n */\nexport function replace<T>(array: T[], predicate: Predicate<T>, value: T): T[] {\n const index = array.findIndex(predicate);\n\n if (index === -1) return array;\n\n return [...array.slice(0, index), value, ...array.slice(index + 1)];\n}\n","/**\n * Rotates the elements of an array by a specified number of positions.\n *\n * @example\n * ```ts\n * const arr = [1, 2, 3, 4, 5];\n * rotate(arr, 2); // [3, 4, 5]\n * rotate(arr, 2, { wrap: true }); // [3, 4, 5, 1, 2]\n * ```\n * @param array - The array to rotate.\n * @param positions - The number of positions to rotate the array.\n * @param [options] - Options for the rotate operation.\n * @param [options.wrap] - If `true`, the rotated-out elements are appended to the end.\n *\n * @returns A new array with the elements rotated.\n */\nexport function rotate<T>(array: T[], positions: number, { wrap = false }: { wrap?: boolean } = {}): T[] {\n if (array.length === 0) return array;\n\n const normalizedPos = ((positions % array.length) + array.length) % array.length;\n const rotated = array.slice(normalizedPos);\n\n return wrap ? [...rotated, ...array.slice(0, normalizedPos)] : rotated;\n}\n","/**\n * Determines if the passed value is null or undefined.\n *\n * @example\n * ```ts\n * isNil(null); // true\n * isNil(undefined); // true\n * isNil(''); // false\n * isNil(0); // false\n * ```\n *\n * @param arg - The argument to be checked.\n *\n * @returns `true` if the value is null or undefined, else `false`.\n */\nexport function isNil(arg: unknown): arg is null | undefined {\n return arg === undefined || arg === null;\n}\n","/**\n * Determines if the passed value is a number.\n *\n * @example\n * ```ts\n * isNumber(123); // true\n * isNumber('hello world'); // false\n * ```\n *\n * @param arg - The argument to be checked.\n *\n * @returns `true` if the value is a number, else `false`.\n */\nexport function isNumber(arg: unknown): arg is number {\n return typeof arg === 'number' && !Number.isNaN(arg);\n}\n","import { ArsenalValidationError } from '../errors';\n\n/**\n * Calculate the similarity between two strings using the Levenshtein distance algorithm.\n *\n * @example\n * ```ts\n * similarity('abc', 'abc') // 1\n * similarity('a', 'b') // 0\n * similarity('ab', 'ac') // 0.5\n * similarity('doe', 'John Doe') // 0.25\n * similarity('abc', 'axc') // 0.6666666666666667\n * similarity('kitten', 'sitting') // 0.5714285714285714\n * ```\n *\n * @param str1 - The first string.\n * @param str2 - The second string.\n *\n * @returns A number between 0 and 1 representing the similarity between the two strings.\n *\n * @throws {ArsenalValidationError} If either input string exceeds 10 000 characters.\n */\nconst MAX_SIMILARITY_LENGTH = 10_000;\n\nexport function similarity(str1: string, str2: string): number {\n if (str1.length > MAX_SIMILARITY_LENGTH || str2.length > MAX_SIMILARITY_LENGTH) {\n throw new ArsenalValidationError(\n `similarity: input strings must not exceed ${MAX_SIMILARITY_LENGTH} characters to prevent excessive memory usage`,\n );\n }\n\n const a = str1.toLowerCase();\n const b = str2.toLowerCase();\n\n if (a === b) return 1;\n\n if (a.length === 0) return b.length === 0 ? 1 : 0;\n\n if (b.length === 0) return 0;\n\n // Swap to ensure we use the smaller string for columns (O(min(A,B)) space)\n const [shorter, longer] = a.length < b.length ? [a, b] : [b, a];\n const shorterLength = shorter.length;\n const longerLength = longer.length;\n\n let prevRow = Array.from({ length: shorterLength + 1 }, (_, i) => i);\n let currRow = new Array(shorterLength + 1);\n\n for (let i = 1; i <= longerLength; i++) {\n currRow[0] = i;\n for (let j = 1; j <= shorterLength; j++) {\n const cost = longer[i - 1] === shorter[j - 1] ? 0 : 1;\n\n currRow[j] = Math.min(\n currRow[j - 1] + 1, // insertion\n prevRow[j] + 1, // deletion\n prevRow[j - 1] + cost, // substitution\n );\n }\n // Swap rows for the next iteration (avoid allocation)\n [prevRow, currRow] = [currRow, prevRow];\n }\n\n // After the loop, a result is in prevRow because of the swap\n const distance = prevRow[shorterLength];\n\n return 1 - distance / Math.max(a.length, b.length);\n}\n","import { ArsenalValidationError } from '../errors';\nimport { isNil } from '../guards/isNil';\nimport { isNumber } from '../guards/isNumber';\nimport { isString } from '../guards/isString';\nimport { similarity } from '../string/similarity';\n\nexport type ScoredResult<T> = { item: T; score: number };\n\nexport type FuzzyOptions<T> = {\n fields?: ReadonlyArray<keyof T & string>;\n /**\n * Maximum recursive depth for full-tree scanning when `fields` is omitted. Values beyond\n * this depth are not searched. Must be a non-negative integer; silently clamped to\n * `HARD_MAX_SEEK_DEPTH` to bound worst-case recursion on untrusted, deeply-nested input.\n * Default: `10`.\n */\n maxDepth?: number;\n /** When `true`, applies Unicode NFKD normalization before comparison so accented characters match their base form (é ≈ e). Default: `false`. */\n normalize?: boolean;\n threshold?: number;\n};\n\n/** Default maximum recursive depth for full-tree scanning when `fields` is omitted and `maxDepth` isn't set. */\nconst DEFAULT_MAX_SEEK_DEPTH = 10;\n\n/**\n * Hard ceiling for `maxDepth`, regardless of caller input — bounds worst-case recursion depth\n * (and therefore call-stack usage) even when `maxDepth` is attacker-influenced.\n */\nconst HARD_MAX_SEEK_DEPTH = 1000;\n\n/** @security `maxDepth` may originate from untrusted input reaching a public API — validate and clamp. */\nfunction resolveMaxDepth(maxDepth: number | undefined): number {\n if (maxDepth === undefined) return DEFAULT_MAX_SEEK_DEPTH;\n\n if (!Number.isInteger(maxDepth) || maxDepth < 0) {\n throw new ArsenalValidationError(`fuzzy: maxDepth must be a non-negative integer, got ${maxDepth}`);\n }\n\n return Math.min(maxDepth, HARD_MAX_SEEK_DEPTH);\n}\n\nconst normalizeStr = (s: string): string => s.normalize('NFKD').replace(/\\p{M}/gu, '');\n\nfunction seekScore(item: unknown, query: string, normalize: boolean, maxDepth: number, depth = 0): number {\n if (depth > maxDepth) return 0;\n\n if (isNil(item)) return 0;\n\n if (isString(item) || isNumber(item)) {\n const a = normalize ? normalizeStr(String(item)) : String(item);\n\n return similarity(a, query);\n }\n\n if (Array.isArray(item))\n return (item as unknown[]).reduce<number>(\n (max, v) => Math.max(max, seekScore(v, query, normalize, maxDepth, depth + 1)),\n 0,\n );\n\n if (typeof item === 'object')\n return Object.values(item as Record<string, unknown>).reduce<number>(\n (max, v) => Math.max(max, seekScore(v, query, normalize, maxDepth, depth + 1)),\n 0,\n );\n\n return 0;\n}\n\nfunction seekValue(item: unknown, query: string, threshold: number, normalize: boolean, maxDepth: number): boolean {\n return seekScore(item, query, normalize, maxDepth) >= threshold;\n}\n\n/**\n * Performs a fuzzy filter on an array of items using string similarity.\n * Returns items whose similarity to `query` meets `threshold`.\n * When `fields` is provided, only those keys are searched; otherwise all values are scanned.\n *\n * For results sorted by relevance score, use `fuzzyScore`.\n *\n * @example\n * ```ts\n * const data = [{ name: 'John Doe', age: 25 }, { name: 'Jane Doe', age: 30 }];\n *\n * fuzzyFilter(data, 'doe'); // [{ name: 'John Doe' }, { name: 'Jane Doe' }]\n * fuzzyFilter(data, 'john', { fields: ['name'] });\n * ```\n *\n * @param array - The array of items to filter.\n * @param query - The string to search for.\n * @param [options.threshold=0.25] - Similarity threshold between 0 and 1. Higher = stricter.\n * @param [options.fields] - Limit search to these object keys. Searches all values when omitted.\n * @param [options.normalize=false] - NFKD normalization so accented chars match base form (é ≈ e).\n * @param [options.maxDepth=10] - Maximum recursive depth when scanning nested values (ignored when `fields` is set).\n * @throws {ArsenalValidationError} If `maxDepth` is provided and is not a non-negative integer.\n */\nexport function fuzzyFilter<T>(array: T[], query: string, options: FuzzyOptions<T> = {}): T[] {\n const { fields, normalize = false, threshold = 0.25 } = options;\n const maxDepth = resolveMaxDepth(options.maxDepth);\n\n if (!query) return [...array];\n\n const raw = query.trim().toLowerCase();\n\n if (!raw) return [...array];\n\n const searchTerm = normalize ? normalizeStr(raw) : raw;\n\n return array.filter((item) => {\n if (fields && fields.length > 0 && typeof item === 'object' && item !== null) {\n return fields.some((field) =>\n seekValue((item as Record<string, unknown>)[field], searchTerm, threshold, normalize, maxDepth),\n );\n }\n\n return seekValue(item, searchTerm, threshold, normalize, maxDepth);\n });\n}\n\n/**\n * Performs a fuzzy score on an array of items using string similarity.\n * Returns all items with their similarity score, filtered by `threshold`, sorted by score descending.\n * When `query` is empty, all items are returned with score `1`.\n *\n * For a simple filtered list without scores, use `fuzzyFilter`.\n *\n * @example\n * ```ts\n * const data = [{ name: 'John Doe', age: 25 }, { name: 'Jane Doe', age: 30 }];\n *\n * fuzzyScore(data, 'john', { fields: ['name'] });\n * // [{ item: { name: 'John Doe', age: 25 }, score: 0.8 }, ...]\n * ```\n *\n * @param array - The array of items to score.\n * @param query - The string to search for.\n * @param [options.threshold=0.25] - Minimum score to include in results.\n * @param [options.fields] - Limit scoring to these object keys. Scores all values when omitted.\n * @param [options.normalize=false] - NFKD normalization so accented chars match base form (é ≈ e).\n * @param [options.maxDepth=10] - Maximum recursive depth when scanning nested values (ignored when `fields` is set).\n * @throws {ArsenalValidationError} If `maxDepth` is provided and is not a non-negative integer.\n */\nexport function fuzzyScore<T>(array: T[], query: string, options: FuzzyOptions<T> = {}): ScoredResult<T>[] {\n const { fields, normalize = false, threshold = 0.25 } = options;\n const maxDepth = resolveMaxDepth(options.maxDepth);\n\n if (!query || !query.trim()) {\n return array.map((item) => ({ item, score: 1 }));\n }\n\n const raw = query.trim().toLowerCase();\n const searchTerm = normalize ? normalizeStr(raw) : raw;\n\n const scored = array.map((item) => {\n const score =\n fields && fields.length > 0 && typeof item === 'object' && item !== null\n ? fields.reduce<number>(\n (max, field) =>\n Math.max(max, seekScore((item as Record<string, unknown>)[field], searchTerm, normalize, maxDepth)),\n 0,\n )\n : seekScore(item, searchTerm, normalize, maxDepth);\n\n return { item, score };\n });\n\n return scored.filter(({ score }) => score >= threshold).sort((a, b) => b.score - a.score);\n}\n\n/**\n * Fuzzy-searches an array. In filter mode (default) returns `T[]`.\n * Pass `{ scored: true }` to return `ScoredResult<T>[]` sorted by relevance descending.\n *\n * @example\n * ```ts\n * const users = [{ name: 'Alice' }, { name: 'Bob' }];\n *\n * fuzzy(users, 'ali'); // [{ name: 'Alice' }]\n * fuzzy(users, 'ali', { scored: true }); // [{ item: { name: 'Alice' }, score: 0.9 }]\n * fuzzy(users, 'ali', { fields: ['name'] }); // field-restricted\n * ```\n */\nexport function fuzzy<T>(array: T[], query: string, options: FuzzyOptions<T> & { scored: true }): ScoredResult<T>[];\nexport function fuzzy<T>(array: T[], query: string, options?: FuzzyOptions<T> & { scored?: false }): T[];\nexport function fuzzy<T>(\n array: T[],\n query: string,\n options: FuzzyOptions<T> & { scored?: boolean } = {},\n): T[] | ScoredResult<T>[] {\n const { scored, ...rest } = options;\n\n return scored ? fuzzyScore(array, query, rest) : fuzzyFilter(array, query, rest);\n}\n","import { ArsenalValidationError } from '../errors';\nimport { compare } from './compare';\nimport { compareBy } from './compareBy';\n\nexport type SortDirection = 'asc' | 'desc';\nexport type SortSelectors<T> = Partial<Record<keyof T, SortDirection>>;\n\n/**\n * Sorts an array by a selector function (single-field) or by a multi-field\n * object of `{ key: 'asc' | 'desc' }` entries.\n *\n * @example\n * ```ts\n * // Single field\n * sort([{ a: 2 }, { a: 1 }], item => item.a); // [{ a:1 }, { a:2 }]\n * sort([{ a: 2 }, { a: 1 }], item => item.a, 'desc'); // [{ a:2 }, { a:1 }]\n *\n * // Multi-field\n * sort(users, { name: 'asc', age: 'desc' });\n * ```\n *\n * @param array - The array to sort.\n * @param selector - A function extracting the sort key, or a multi-field object.\n * @param direction - `'asc'` (default) or `'desc'` — only applies to single-field mode.\n * @returns A new sorted array.\n *\n * @throws {ArsenalValidationError} If the first argument is not an array.\n */\nexport function sort<T>(array: T[], selector: (item: T) => unknown, direction?: SortDirection): T[];\nexport function sort<T>(array: T[], selectors: SortSelectors<T>): T[];\nexport function sort<T>(\n array: T[],\n selectorOrSelectors: ((item: T) => unknown) | SortSelectors<T>,\n direction: SortDirection = 'asc',\n): T[] {\n if (!Array.isArray(array)) throw new ArsenalValidationError('sort: first argument must be an array');\n\n if (typeof selectorOrSelectors === 'function') {\n const multiplier = direction === 'desc' ? -1 : 1;\n\n return [...array].sort((a, b) => compare(selectorOrSelectors(a), selectorOrSelectors(b)) * multiplier);\n }\n\n return [...array].sort(compareBy(selectorOrSelectors));\n}\n","/**\n * Takes the first n elements from an array.\n */\nexport function take<T>(array: T[], n = 1): T[] {\n const count = Math.max(0, Math.floor(n));\n\n return array.slice(0, count);\n}\n","/**\n * Takes the last n elements from an array.\n */\nexport function takeLast<T>(array: T[], n = 1): T[] {\n const count = Math.max(0, Math.floor(n));\n\n if (count === 0) return [];\n\n return array.slice(Math.max(0, array.length - count));\n}\n","import type { Primitive } from '../types';\n\n/**\n * Either adds or removes an item from an array, based on whether it already\n * exists in the array (toggle behaviour).\n *\n * @example\n * ```ts\n * toggle([1, 2, 3], 4) // [1, 2, 3, 4]\n * toggle([1, 2, 3], 2) // [1, 3]\n *\n * toggle(\n * [{ id: 1 }, { id: 2 }],\n * { id: 3 },\n * (obj) => obj.id,\n * { strategy: 'prepend' }\n * ) // [{ id: 3 }, { id: 1 }, { id: 2 }]\n * ```\n *\n * @param array - The array to modify.\n * @param item - The item to add or remove.\n * @param selector - A function to determine item identity.\n * @param [options] - Options for the toggle operation.\n * @param [options.strategy] - Where to insert when adding: 'prepend' or 'append' (default).\n * @returns A new array with the item toggled.\n */\nexport function toggle<T>(\n array: T[],\n item: T,\n selector?: (item: T) => Primitive,\n options: { strategy?: 'prepend' | 'append' } = {},\n): T[] {\n const { strategy = 'append' } = options;\n const compareFn = selector ? (el: T) => selector(el) === selector(item) : (el: T) => el === item;\n\n const index = array.findIndex(compareFn);\n\n if (index !== -1) {\n return [...array.slice(0, index), ...array.slice(index + 1)];\n }\n\n return strategy === 'prepend' ? [item, ...array] : [...array, item];\n}\n","import type { Primitive } from '../types';\n\nimport { dedupeBySelector } from '../_common/_selectorSet';\n\n/**\n * Returns a deduplicated union of both arrays.\n */\nexport function union<T>(source: T[], other: T[], selector?: (item: T) => Primitive): T[] {\n if (!selector) {\n return [...new Set([...source, ...other])];\n }\n\n return dedupeBySelector([...source, ...other], selector);\n}\n","import type { Primitive } from '../types';\n\nimport { dedupeBySelector } from '../_common/_selectorSet';\n\n/**\n * Creates a new array with duplicate values removed.\n *\n * @example\n * ```ts\n * uniq([1, 2, 2, 3, 3, 3]); // [1, 2, 3]\n * const arrObj = [{ id: 1 }, { id: 2 }, { id: 2 }, { id: 3 }, { id: 3 }, { id: 3 }];\n * uniq(arrObj, item => item.id); // [{ id: 1 }, { id: 2 }, { id: 3 }]\n * ```\n *\n * @param array - The array to process.\n * @param [selector] - Function used to generate comparison values for each item.\n\n * @returns A new duplicate-free array.\n */\nexport function uniq<T>(array: T[], selector?: (item: T) => Primitive): T[] {\n if (array.length <= 1) {\n return [...array];\n }\n\n if (!selector) {\n return [...new Set(array)];\n }\n\n return dedupeBySelector(array, selector);\n}\n","/**\n * Transposes an array of tuples into tuple arrays.\n */\nexport function unzip<T extends readonly unknown[]>(rows: readonly T[]): { [K in keyof T]: Array<T[K]> } {\n if (rows.length === 0) return [] as unknown as { [K in keyof T]: Array<T[K]> };\n\n const width = rows[0].length;\n const out = Array.from({ length: width }, () => [] as unknown[]);\n\n for (const row of rows) {\n for (let index = 0; index < width; index++) {\n out[index].push(row[index]);\n }\n }\n\n return out as { [K in keyof T]: Array<T[K]> };\n}\n","/**\n * Zips multiple arrays by index.\n */\nexport function zip<T extends readonly unknown[][]>(\n ...arrays: T\n): Array<{ [K in keyof T]: T[K] extends readonly (infer U)[] ? U | undefined : never }> {\n if (arrays.length === 0) return [];\n\n const length = Math.max(...arrays.map((arr) => arr.length));\n const out = new Array(length);\n\n for (let index = 0; index < length; index++) {\n out[index] = arrays.map((array) => array[index]);\n }\n\n return out as Array<{ [K in keyof T]: T[K] extends readonly (infer U)[] ? U | undefined : never }>;\n}\n","/**\n * Returns the abort error for the given signal.\n *\n * If the signal has a `reason`, that is returned directly (preserving the\n * original error thrown by `AbortController.abort(reason)`).\n * Otherwise, returns a `DOMException` with `name === 'AbortError'`.\n *\n * @example\n * ```ts\n * const ac = new AbortController();\n * ac.abort();\n * throw abortError(ac.signal); // DOMException { name: 'AbortError' }\n *\n * const ac2 = new AbortController();\n * ac2.abort(new TypeError('custom'));\n * throw abortError(ac2.signal); // TypeError('custom')\n * ```\n *\n * @param signal - The aborted signal to extract the error from.\n * @returns The abort reason, or a new `DOMException('Aborted', 'AbortError')`.\n */\nexport function abortError(signal?: AbortSignal): unknown {\n return signal?.reason ?? new DOMException('Aborted', 'AbortError');\n}\n","export type AttemptResult<T> =\n | { ok: true; value: T }\n // eslint-disable-next-line perfectionist/sort-object-types\n | { ok: false; error: unknown };\n\n/**\n * Narrows an `AttemptResult` to the success branch.\n * @example\n * ```ts\n * const result = await attempt(() => fetch('/api').then(r => r.json()));\n * if (isOk(result)) console.log(result.value);\n * ```\n */\n\nexport function isOk<T>(result: AttemptResult<T>): result is { ok: true; value: T } {\n return result.ok === true;\n}\n\n/**\n * Narrows an `AttemptResult` to the failure branch.\n * @example\n * ```ts\n * const result = await attempt(() => fetch('/api').then(r => r.json()));\n * if (isFail(result)) console.error(result.error);\n * ```\n */\n// eslint-disable-next-line perfectionist/sort-object-types\nexport function isFail<T>(result: AttemptResult<T>): result is { ok: false; error: unknown } {\n return result.ok === false;\n}\n\n/**\n * Executes a function — sync or async — and returns an `AttemptResult` (or\n * `Promise<AttemptResult>` for async factories). Never throws.\n *\n * TypeScript infers the return type from the factory:\n * - sync factory → `AttemptResult<T>`\n * - async factory → `Promise<AttemptResult<T>>`\n *\n * @example\n * ```ts\n * // Sync\n * const parsed = attempt(() => JSON.parse(rawJson));\n * if (parsed.ok) console.log(parsed.value);\n * else console.error(parsed.error);\n *\n * // Async\n * const result = await attempt(() => fetch('/api').then(r => r.json()));\n * if (result.ok) console.log(result.value);\n * else console.error(result.error);\n *\n * // Combined with retry()\n * const result = await attempt(() => retry(fn, { times: 3 }));\n * ```\n */\nexport function attempt<T>(fn: () => Promise<T>): Promise<AttemptResult<T>>;\nexport function attempt<T>(fn: () => T): AttemptResult<T>;\nexport function attempt<T>(fn: () => T | Promise<T>): AttemptResult<T> | Promise<AttemptResult<T>> {\n try {\n const result = fn();\n\n if (typeof (result as PromiseLike<T>)?.then === 'function') {\n return (result as Promise<T>).then(\n (value) => ({ ok: true as const, value }),\n (error) => ({ error, ok: false as const }),\n );\n }\n\n return { ok: true, value: result as T };\n } catch (error) {\n return { error, ok: false };\n }\n}\n","/**\n * Computes an exponential backoff delay cap for a given zero-based attempt number.\n * Returns `min(1000 × 2ⁿ, maxMs)` — the cap before optional jitter is applied.\n *\n * Multiply the result by `Math.random()` for full-jitter backoff.\n *\n * @example\n * ```ts\n * // Deterministic (sourcerer-style):\n * const delay = backoff(attempt); // 1s, 2s, 4s, … capped at 30s\n *\n * // Full-jitter (courier-style):\n * const delay = Math.random() * backoff(attempt);\n * ```\n *\n * @param attempt - Zero-based attempt index (0 = first retry wait).\n * @param maxMs - Maximum cap in milliseconds. Defaults to 30 000.\n */\nexport function backoff(attempt: number, maxMs = 30_000): number {\n const n = Math.max(0, Number.isNaN(attempt) ? 0 : Math.floor(attempt));\n\n return Math.min(1000 * (n <= 30 ? 1 << n : Math.pow(2, n)), maxMs);\n}\n","import { ArsenalValidationError } from '../errors';\nimport { abortError } from './abortError';\n\n/**\n * Processes an array with an async callback with controlled parallelism.\n * Similar to Promise.all, but limits how many items are processed concurrently.\n * Returns an ordered array of results.\n *\n * @example\n * ```ts\n * // Process 3 items at a time\n * const results = await parallel([1, 2, 3, 4, 5], async (n) => {\n * await delay(100);\n * return n * 2;\n * }, { limit: 3 });\n * // [2, 4, 6, 8, 10]\n *\n * // With abort signal\n * const controller = new AbortController();\n * const results = await parallel(items, async (item) => {\n * return processItem(item);\n * }, { limit: 2, signal: controller.signal });\n *\n * // Stop other workers as soon as one item fails\n * await parallel(items, riskyOperation, { abortOnError: true, limit: 3 });\n * ```\n *\n * @param array - Array of items to process\n * @param callback - Async function to process each item\n * @param options - Optional options for concurrency and cancellation\n * @param [options.limit=Infinity] - Maximum number of concurrent operations. Defaults to unbounded.\n * @param [options.signal] - Optional AbortSignal to cancel processing\n * @param [options.abortOnError=false] - When `true`, stops other in-flight workers as soon as any\n * callback throws, instead of letting them keep running to completion unobserved. Default\n * preserves the existing best-effort-completion behavior.\n * @returns Promise resolving to an ordered array of results\n * @throws {ArsenalValidationError} If limit is less than 1\n * @throws {DOMException} If aborted via signal\n */\nexport async function parallel<T, R>(\n array: readonly T[],\n callback: (item: T, index: number, array: readonly T[]) => Promise<R> | R,\n options: { abortOnError?: boolean; limit?: number; signal?: AbortSignal } = {},\n): Promise<R[]> {\n const { abortOnError = false, limit = Infinity, signal } = options;\n\n if (limit < 1) {\n throw new ArsenalValidationError(`parallel: limit must be at least 1, got ${limit}`);\n }\n\n if (signal?.aborted) {\n throw abortError(signal);\n }\n\n if (array.length === 0) {\n return [];\n }\n\n const results: R[] = new Array(array.length);\n let currentIndex = 0;\n const failFastController = abortOnError ? new AbortController() : undefined;\n\n const worker = async (): Promise<void> => {\n while (true) {\n if (signal?.aborted) {\n throw abortError(signal);\n }\n\n if (failFastController?.signal.aborted) {\n return;\n }\n\n if (currentIndex >= array.length) {\n return;\n }\n\n const index = currentIndex++;\n\n try {\n results[index] = await callback(array[index]!, index, array);\n } catch (err) {\n failFastController?.abort();\n throw err;\n }\n }\n };\n\n const workerCount = Math.min(limit, array.length);\n const workers = Array.from({ length: workerCount }, () => worker());\n\n await Promise.all(workers);\n\n return results;\n}\n","import type { AttemptResult } from './attempt';\n\nimport { ArsenalValidationError } from '../errors';\n\n/**\n * Creates a promise queue that processes promises sequentially with optional concurrency limit.\n *\n * @example\n * ```ts\n * const requestQueue = queue({ concurrency: 2 });\n *\n * requestQueue.add(() => fetch('/api/1'));\n * requestQueue.add(() => fetch('/api/2'));\n * requestQueue.add(() => fetch('/api/3'));\n *\n * await requestQueue.onIdle(); // Wait for all tasks to complete\n * ```\n *\n * @param options - Queue configuration\n * @param options.concurrency - Maximum number of concurrent promises (default: 1)\n * @returns Queue instance with add, onIdle, clear, and onSettled methods\n */\nexport type QueueSettledCallback<T = unknown> = (result: AttemptResult<T>) => void;\n\nexport interface Queue {\n /** Adds a task to the queue. Returns a promise that resolves/rejects with the task result. */\n add<T>(fn: () => Promise<T>, options?: { priority?: number }): Promise<T>;\n /** Clears all pending tasks, rejecting them with the given reason. Running tasks are unaffected. */\n clear(reason?: unknown): void;\n /** Returns a promise that resolves when the queue becomes idle (no active or pending tasks). */\n onIdle(): Promise<void>;\n /** Subscribes to settled results (both resolved and rejected). Returns an unsubscribe function. */\n onSettled<T>(cb: QueueSettledCallback<T>): () => void;\n /** Number of currently running tasks. */\n readonly active: number;\n /** Number of tasks waiting to run. */\n readonly pending: number;\n /** Total tasks (active + pending). */\n readonly size: number;\n}\n\nexport function queue(options: { concurrency?: number } = {}): Queue {\n const { concurrency = 1 } = options;\n\n if (concurrency < 1) throw new ArsenalValidationError('Concurrency must be at least 1');\n\n let activeCount = 0;\n let isDraining = false;\n let idlePromise: Promise<void> | null = null;\n let idleResolve: (() => void) | null = null;\n\n const tasks: Array<{\n fn: () => Promise<unknown>;\n priority: number;\n reject: (error: unknown) => void;\n resolve: (value: unknown) => void;\n }> = [];\n\n const settledListeners = new Set<QueueSettledCallback>();\n\n const resolveIdle = (): void => {\n if (activeCount === 0 && tasks.length === 0 && idleResolve) {\n idleResolve();\n idlePromise = null;\n idleResolve = null;\n }\n };\n\n const notifySettled = (result: AttemptResult<unknown>): void => {\n for (const cb of settledListeners) {\n cb(result);\n }\n };\n\n const drain = (): void => {\n if (isDraining) {\n return;\n }\n\n isDraining = true;\n\n while (activeCount < concurrency && tasks.length > 0) {\n const task = tasks.shift()!;\n\n activeCount++;\n\n void Promise.resolve()\n .then(() => task.fn())\n .then((v) => {\n notifySettled({ ok: true, value: v });\n task.resolve(v);\n })\n .catch((e: unknown) => {\n notifySettled({ error: e, ok: false });\n task.reject(e);\n })\n .finally(() => {\n activeCount--;\n drain();\n resolveIdle();\n });\n }\n\n isDraining = false;\n resolveIdle();\n };\n\n return {\n /**\n * Returns the number of currently running tasks.\n */\n get active(): number {\n return activeCount;\n },\n\n /**\n * Adds a promise-returning function to the queue.\n * Tasks with a higher `priority` number run before lower-priority tasks.\n * Tasks with equal priority run in insertion order (FIFO).\n *\n * @param fn - The async function to queue.\n * @param options.priority - Task priority. Higher numbers run first. Default: 0.\n */\n add: <T>(fn: () => Promise<T>, options?: { priority?: number }): Promise<T> => {\n const { promise, reject, resolve } = Promise.withResolvers<T>();\n const priority = options?.priority ?? 0;\n\n const task = {\n fn: fn as () => Promise<unknown>,\n priority,\n reject,\n resolve: resolve as (value: unknown) => void,\n };\n\n let i = tasks.length;\n\n while (i > 0 && tasks[i - 1]!.priority < priority) {\n i--;\n }\n\n tasks.splice(i, 0, task);\n drain();\n\n return promise;\n },\n\n /**\n * Clears all pending tasks from the queue and rejects them.\n * Running tasks are not affected.\n * @param reason - The error reason for the rejection (defaults to 'Queue cleared')\n */\n clear: (reason?: unknown): void => {\n const clearReason = reason ?? new Error('Queue cleared');\n\n for (const task of tasks.splice(0)) {\n task.reject(clearReason);\n }\n\n resolveIdle();\n },\n\n /**\n * Returns a promise that resolves when the queue becomes idle.\n */\n onIdle: (): Promise<void> => {\n if (activeCount === 0 && tasks.length === 0) {\n return Promise.resolve();\n }\n\n if (!idlePromise) {\n const deferred = Promise.withResolvers<void>();\n\n idlePromise = deferred.promise;\n idleResolve = deferred.resolve;\n }\n\n return idlePromise;\n },\n\n /**\n * Subscribes to settled task results (both resolved and rejected).\n * The callback fires once per task, in completion order.\n * Returns an unsubscribe function.\n *\n * Unlike a `for await` loop, multiple subscribers are supported and\n * no results are accumulated in memory.\n *\n * @example\n * ```ts\n * const q = queue({ concurrency: 2 });\n * const unsub = q.onSettled((result) => {\n * if (result.ok) console.log(result.value);\n * else console.error(result.error);\n * });\n *\n * q.add(() => fetchUser(1));\n * q.add(() => fetchUser(2));\n *\n * await q.onIdle();\n * unsub(); // stop listening\n * ```\n */\n onSettled: <T = unknown>(cb: QueueSettledCallback<T>): (() => void) => {\n settledListeners.add(cb as QueueSettledCallback);\n\n return () => {\n settledListeners.delete(cb as QueueSettledCallback);\n };\n },\n\n /**\n * Returns the number of tasks waiting to run (queued but not yet started).\n */\n get pending(): number {\n return tasks.length;\n },\n\n /**\n * Returns the total number of tasks (active + pending).\n */\n get size(): number {\n return activeCount + tasks.length;\n },\n };\n}\n","import { abortError } from './abortError';\n\n/**\n * Creates a Promise that resolves after a specified amount of time.\n * If an `AbortSignal` is provided and fires before the delay elapses, the promise rejects with\n * the signal's reason (or a generic `DOMException('Aborted', 'AbortError')`).\n *\n * @example\n * ```ts\n * sleep(1000).then(() => console.log('Hello, world!')); // logs after 1 second\n *\n * // With abort support\n * const controller = new AbortController();\n * await sleep(5000, controller.signal); // rejects immediately when aborted\n * ```\n *\n * @param timeout - The number of milliseconds to wait before resolving the Promise.\n * @param signal - Optional AbortSignal to cancel the sleep early.\n *\n * @returns A Promise that resolves after the specified time.\n */\nexport async function sleep(timeout: number, signal?: AbortSignal): Promise<void> {\n if (!signal) {\n return new Promise((resolve) => setTimeout(resolve, timeout));\n }\n\n if (signal.aborted) {\n return Promise.reject(abortError(signal));\n }\n\n return new Promise<void>((resolve, reject) => {\n const id = setTimeout(() => {\n signal.removeEventListener('abort', onAbort);\n resolve();\n }, timeout);\n\n const onAbort = () => {\n clearTimeout(id);\n signal.removeEventListener('abort', onAbort);\n reject(abortError(signal));\n };\n\n signal.addEventListener('abort', onAbort);\n });\n}\n","import { ArsenalValidationError } from '../errors';\nimport { abortError } from './abortError';\nimport { sleep } from './sleep';\n\nexport type RetryOptions = {\n delay?: number | ((attempt: number) => number);\n onError?: (error: unknown) => void;\n shouldRetry?: (error: unknown, attempt: number) => boolean;\n signal?: AbortSignal;\n timeout?: number;\n times?: number;\n};\n\nfunction buildSignal(timeout: number | undefined, signal: AbortSignal | undefined): AbortSignal | undefined {\n const parts = [timeout !== undefined ? AbortSignal.timeout(timeout) : undefined, signal].filter(\n (s): s is AbortSignal => s != null,\n );\n\n if (parts.length === 0) return undefined;\n\n if (parts.length === 1) return parts[0];\n\n return AbortSignal.any(parts);\n}\n\n/**\n * Retries an async function with optional per-attempt timeout, delay strategy, and abort support.\n * The function receives a merged AbortSignal from the per-attempt timeout and any external signal.\n * On total failure, throws the last error (use `attempt()` to get an `AttemptResult` without throwing).\n *\n * @example\n * ```ts\n * // Basic retry\n * const data = await retry(() => fetch('/api').then(r => r.json()), { times: 3 });\n *\n * // With per-attempt timeout and cancellation\n * const data = await retry(\n * async (signal) => fetch('/api', { signal }).then(r => r.json()),\n * { times: 3, timeout: 5000 },\n * );\n *\n * // As AttemptResult (never throws) — combine with attempt()\n * const result = await attempt(() => retry(fn, { times: 3 }));\n * ```\n *\n * @param fn - Async function to retry. Receives a merged AbortSignal when timeout or signal is set.\n * @param options - Retry configuration.\n * @param [options.times=3] - Total attempts including the first.\n * @param [options.delay=250] - Delay between retries in ms, or a function of (attemptIndex).\n * @param [options.timeout] - Per-attempt timeout in milliseconds.\n * @param [options.signal] - External AbortSignal to cancel all retries.\n * @param [options.shouldRetry] - Predicate called after each non-final failure.\n * Receives the error and the number of failures so far (0-indexed: `0` on the first failure,\n * `1` on the second, etc.). Return `false` to abort immediately. **Not called on the final attempt**\n * (use `onError` to observe the final error unconditionally).\n * @param [options.onError] - Called with the last error before rethrowing — both on final attempt exhaustion\n * and when `shouldRetry` returns `false` to abort early.\n * @returns The resolved value.\n * @throws {ArsenalValidationError} If `times` is not a positive integer.\n * @throws The last error if all attempts fail.\n */\nexport async function retry<T>(\n fn: (signal?: AbortSignal) => Promise<T>,\n { delay = 250, onError, shouldRetry, signal, timeout, times = 3 }: RetryOptions = {},\n): Promise<T> {\n if (!Number.isInteger(times) || times < 1) {\n throw new ArsenalValidationError(`retry: times must be a positive integer, got ${times}`);\n }\n\n for (let tryCount = 1; tryCount <= times; tryCount++) {\n if (signal?.aborted) throw abortError(signal);\n\n const callSignal = buildSignal(timeout, signal);\n\n try {\n return await fn(callSignal);\n } catch (err) {\n if (tryCount === times) {\n onError?.(err);\n throw err;\n }\n\n if (shouldRetry && !shouldRetry(err, tryCount - 1)) {\n onError?.(err);\n throw err;\n }\n\n const ms = typeof delay === 'function' ? delay(tryCount - 1) : delay;\n\n if (ms > 0) await sleep(ms, signal);\n }\n }\n\n /* unreachable — the loop always returns or throws before exhausting all attempts */\n return undefined as never;\n}\n","import { sleep } from './sleep';\n\nexport type WaitForOptions = {\n interval?: number;\n signal?: AbortSignal;\n timeout?: number;\n};\n\n/**\n * Waits for a condition to become true by polling.\n * Useful for waiting for DOM elements, API states, or other conditions.\n *\n * @example\n * ```ts\n * // Wait for an element to appear\n * await waitFor(() => document.querySelector('#myElement') !== null);\n *\n * // Wait for API to be ready with cancellation support\n * await waitFor(\n * async (signal) => {\n * const res = await fetch('/api/health', { signal });\n * return res.ok;\n * },\n * { timeout: 30000, interval: 1000 },\n * );\n * ```\n *\n * @param condition - Polling function that receives the merged AbortSignal and returns true when the condition is met\n * @param options - Configuration options\n * @param [options.timeout=5000] - Maximum time to wait in ms\n * @param [options.interval=100] - Polling interval in ms\n * @param [options.signal] - AbortSignal to cancel waiting\n * @returns Promise that resolves when condition becomes true\n * @throws Rejects with the abort reason when timed out or cancelled\n */\nexport async function waitFor(\n condition: (signal: AbortSignal) => boolean | Promise<boolean>,\n { interval = 100, signal, timeout: ms = 5000 }: WaitForOptions = {},\n): Promise<void> {\n const deadline = AbortSignal.timeout(ms);\n const merged = signal ? AbortSignal.any([signal, deadline]) : deadline;\n\n merged.throwIfAborted();\n\n while (true) {\n merged.throwIfAborted();\n\n if (await condition(merged)) return;\n\n await sleep(interval, merged);\n }\n}\n","/**\n * A Map subclass that evicts the oldest non-excluded entry when the map exceeds\n * `maxSize`. Iteration order (insertion order) determines LRU — the first key\n * returned by `keys()` is the oldest.\n *\n * Calling `set` on an existing key refreshes its position (move-to-end).\n *\n * Module-private: underscore-prefixed file is excluded from barrel exports.\n */\nexport class LruMap<K, V> extends Map<K, V> {\n readonly maxSize: number;\n\n constructor(maxSize: number) {\n super();\n this.maxSize = maxSize;\n }\n\n override set(key: K, value: V): this {\n // Move existing entry to the end (most-recently-used position)\n if (this.has(key)) this.delete(key);\n\n super.set(key, value);\n\n // Evict oldest entry if we've exceeded maxSize\n if (this.size > this.maxSize) this.evictOldest();\n\n return this;\n }\n\n /**\n * Evicts the oldest entry for which `canEvict` returns true.\n * Returns `true` if an entry was evicted, `false` if all entries are guarded.\n */\n evictOldest(canEvict: (key: K, value: V) => boolean = () => true): boolean {\n for (const [k, v] of this) {\n if (canEvict(k, v)) {\n this.delete(k);\n\n return true;\n }\n }\n\n return false;\n }\n}\n","import type { Fn } from '../types';\n\nimport { LruMap } from '../_common/_lruMap';\nimport { ArsenalSerializationError, ArsenalValidationError } from '../errors';\n\nexport type MemoOptions<T extends Fn> = {\n key?: (...args: Parameters<T>) => PropertyKey;\n maxSize?: number;\n};\n\nexport type Memoized<T extends Fn> = ((...args: Parameters<T>) => ReturnType<T>) & {\n clear(): void;\n invalidate(...args: Parameters<T>): void;\n readonly size: number;\n};\n\nconst UNDEFINED_SENTINEL = '\\x00undefined\\x00';\nconst NAN_SENTINEL = '\\x00NaN\\x00';\nconst POSITIVE_INFINITY_SENTINEL = '\\x00+Infinity\\x00';\nconst NEGATIVE_INFINITY_SENTINEL = '\\x00-Infinity\\x00';\nconst FUNCTION_SENTINEL = '\\x00function\\x00';\n\nlet functionIdCounter = 0;\nconst functionIds = new WeakMap<Fn, number>();\n\n/** Returns a stable per-identity id for a function so distinct functions never collide as cache keys. */\nfunction idForFunction(fn: Fn): number {\n let id = functionIds.get(fn);\n\n if (id === undefined) {\n id = functionIdCounter++;\n functionIds.set(fn, id);\n }\n\n return id;\n}\n\nconst defaultKey = (args: unknown[]): string => {\n try {\n return JSON.stringify(args, (_, value) => {\n if (value === undefined) return UNDEFINED_SENTINEL;\n\n if (typeof value === 'number' && Number.isNaN(value)) return NAN_SENTINEL;\n\n if (value === Number.POSITIVE_INFINITY) return POSITIVE_INFINITY_SENTINEL;\n\n if (value === Number.NEGATIVE_INFINITY) return NEGATIVE_INFINITY_SENTINEL;\n\n if (typeof value === 'function') return `${FUNCTION_SENTINEL}${idForFunction(value as Fn)}`;\n\n return value;\n });\n } catch (error) {\n const reason = error instanceof Error && error.message ? ` Reason: ${error.message}` : '';\n\n throw new ArsenalSerializationError(\n `[arsenal/memo] Failed to serialize memo arguments. Provide options.key for non-serializable arguments.${reason}`,\n { cause: error },\n );\n }\n};\n\n/** Excludes async functions at the type level so callers cannot accidentally memoize a Promise. */\ntype SyncFn<T extends Fn> = ReturnType<T> extends Promise<unknown> ? never : T;\n\n/**\n * Memoizes a **sync** function with optional LRU eviction by cache size.\n * The returned function exposes `.clear()` and `.invalidate(...args)` methods.\n *\n * **Do not pass async functions.** `memo` caches the raw `Promise` object, not\n * the resolved value — subsequent calls return the same stale Promise. Use\n * `stash.getOrSet` for async caching with TTL and stampede prevention.\n *\n * @example\n * ```ts\n * const add = (x: number, y: number) => x + y;\n * const memoAdd = memo(add, { maxSize: 100 });\n *\n * memoAdd(1, 2); // 3 (computed)\n * memoAdd(1, 2); // 3 (from cache)\n * memoAdd.invalidate(1, 2); // remove specific entry\n * memoAdd.clear(); // wipe entire cache\n * ```\n *\n * @param fn - The sync function to memoize. Must not return a Promise.\n * @param [options.maxSize] - Maximum cache size. Oldest entries evicted when exceeded (LRU). Default: `Infinity`.\n * @param [options.key] - Custom cache key function. Defaults to `JSON.stringify(args)`.\n *\n * @throws {ArsenalValidationError} If `maxSize` is not a positive integer or `Infinity`.\n */\nexport function memo<T extends Fn>(fn: SyncFn<T>, { key, maxSize = Infinity }: MemoOptions<T> = {}): Memoized<T> {\n if (maxSize !== Infinity && (!Number.isInteger(maxSize) || maxSize < 1)) {\n throw new ArsenalValidationError(`memo: maxSize must be a positive integer or Infinity, got ${maxSize}`);\n }\n\n const cache = new LruMap<PropertyKey, ReturnType<T>>(maxSize);\n\n const resolveKey = (...args: Parameters<T>): PropertyKey => (key ? key(...args) : defaultKey(args));\n\n const memoized = (...args: Parameters<T>): ReturnType<T> => {\n const cacheKey = resolveKey(...args);\n\n if (cache.has(cacheKey)) {\n const cached = cache.get(cacheKey)!;\n\n cache.set(cacheKey, cached);\n\n return cached;\n }\n\n const value = fn(...args) as ReturnType<T>;\n\n cache.set(cacheKey, value);\n\n return value;\n };\n\n const result = Object.assign(memoized, {\n clear: () => cache.clear(),\n invalidate: (...args: Parameters<T>): void => {\n cache.delete(resolveKey(...args));\n },\n });\n\n Object.defineProperty(result, 'size', { get: () => cache.size });\n\n return result as Memoized<T>;\n}\n","/**\n * Determines if the passed value is a Promise (or any thenable).\n *\n * @example\n * ```ts\n * isPromise(new Promise((resolve) => resolve(1))); // true\n * isPromise(asyncFn()); // true (calling it returns a Promise)\n * isPromise(async () => {}); // false (the function itself is not a Promise)\n * isPromise(() => {}); // false\n * ```\n *\n * @param arg - The argument to be checked.\n *\n * @returns `true` if the value is a thenable, else `false`.\n */\nexport function isPromise(arg: unknown): arg is Promise<unknown> {\n return typeof arg === 'object' && arg !== null && typeof (arg as { then?: unknown }).then === 'function';\n}\n","import { ArsenalValidationError } from '../errors';\nimport { isPromise } from '../guards/isPromise';\n\ntype CacheRecord<K, T> = {\n key: K;\n value: T;\n};\n\nexport type CachePersistence<T> = {\n /** Deserializes a stored string back into a value of type `T`. */\n deserialize: (raw: string) => T;\n /** Serializes a value to a string for internal storage. */\n serialize: (value: T) => string;\n};\n\nexport type CacheOptions<K = string, T = unknown> = {\n /**\n * Converts a key to its canonical string representation for internal storage.\n * Defaults to `String(key)` — suitable for all string, number, and symbol keys.\n * Provide a custom function for object keys or composite keys.\n */\n hash?: (key: K) => string;\n /**\n * Maximum number of entries to hold. When the store reaches capacity, the oldest\n * entry is evicted (FIFO) before inserting the new one. `onEvict` is called on\n * capacity evictions just like TTL evictions.\n *\n * Default: `Infinity` (unbounded).\n */\n maxSize?: number;\n onEvict?: (key: K, value: T) => void;\n /**\n * Optional serialization pair for persistent caches (e.g. localStorage, cross-process IPC).\n * Both `serialize` and `deserialize` must be provided together.\n *\n * @example\n * ```ts\n * const cache = stash<User>({\n * persistence: {\n * serialize: (u) => JSON.stringify(u),\n * deserialize: (raw) => JSON.parse(raw) as User,\n * },\n * });\n * ```\n */\n persistence?: CachePersistence<T>;\n /**\n * Default time-to-live for all entries in milliseconds.\n * Applied automatically to every `set()` and `getOrSet()` call unless\n * overridden per-entry via `CacheSetOptions.ttlMs`.\n *\n * Default: `undefined` (entries do not expire).\n */\n ttlMs?: number;\n};\n\nexport type CacheSetOptions = {\n /**\n * When `true`, bypasses both the cache and any in-flight promise for this key,\n * and always calls the factory. The new value replaces the old cache entry.\n * **Note:** if a prior in-flight is still pending when `forceRefresh` resolves,\n * whichever `.then` runs last will write the cache slot — ensure prior in-flight\n * tasks have settled if ordering matters.\n */\n forceRefresh?: boolean;\n ttlMs?: number;\n};\n\nexport type Stash<T, K = string> = {\n clear: () => void;\n delete: (key: K) => boolean;\n entries: () => IterableIterator<[K, T]>;\n get: (key: K) => T | undefined;\n /**\n * Returns the cached value for `key`, or invokes `factory` to produce and cache it.\n * Pass `{ forceRefresh: true }` to skip the cache and always call `factory`.\n */\n getOrSet(key: K, factory: () => T, options?: CacheSetOptions): T;\n getOrSet(key: K, factory: () => Promise<T>, options?: CacheSetOptions): Promise<T>;\n set: (key: K, value: T, options?: CacheSetOptions) => void;\n readonly size: number;\n};\n\n/**\n * Creates a generic key-value cache with TTL-based garbage collection, optional capacity\n * limit (FIFO eviction), async stampede prevention, and optional eviction callback.\n *\n * This is the single caching primitive in arsenal — use it for simple bounded caches,\n * TTL caches, or async deduplication/stampede prevention.\n *\n * @example\n * ```ts\n * // Simple string cache — no options needed for string keys\n * const myCache = stash<string>();\n * myCache.set('user:1', 'John Doe');\n * const value = myCache.get('user:1'); // 'John Doe'\n *\n * // Global TTL — all entries expire after 60 seconds unless overridden\n * const apiCache = stash<Response>({ ttlMs: 60_000 });\n * apiCache.set('data', response); // expires in 60s\n * apiCache.set('data', response, { ttlMs: 5_000 }); // override: expires in 5s\n *\n * // Async getOrSet prevents stampedes — concurrent callers share one in-flight promise\n * const user = await myCache.getOrSet('user:1', () => fetchUser(1));\n *\n * // Bounded FIFO cache\n * const fmtCache = stash<Intl.NumberFormat>({ maxSize: 64 });\n * const fmt = fmtCache.getOrSet('en-US', () => new Intl.NumberFormat('en-US'));\n *\n * // Custom key type — provide a hash function\n * const objCache = stash<Result, { id: number }>({ hash: (k) => String(k.id) });\n *\n * // Note: `undefined` is a valid cached value — if a key is set to `undefined`,\n * // `getOrSet` returns it without invoking the factory again.\n * ```\n *\n * @template T - The type of values stored in the cache.\n * @template K - The key type. Defaults to `string`.\n *\n * @throws {ArsenalValidationError} If `options.maxSize` is provided and is not a positive integer or `Infinity`.\n */\nexport function stash<T, K = string>(options: CacheOptions<K, T> = {}): Stash<T, K> {\n const maxSize = options.maxSize ?? Infinity;\n\n if (maxSize !== Infinity && (!Number.isInteger(maxSize) || maxSize < 1)) {\n throw new ArsenalValidationError(`stash: maxSize must be a positive integer or Infinity, got ${maxSize}`);\n }\n\n const store = new Map<string, CacheRecord<K, T>>();\n const gcTimers = new Map<string, ReturnType<typeof setTimeout>>();\n const inFlight = new Map<string, Promise<T>>();\n const hash = options.hash ?? ((key: K) => String(key));\n const onEvict = options.onEvict;\n const defaultTtlMs = options.ttlMs;\n const persistence = options.persistence;\n let generation = 0;\n const deletedWhileInFlight = new Set<string>();\n\n function evictOldestIfOverCapacity(): void {\n if (store.size > maxSize) {\n const [firstHash] = store.keys();\n\n if (firstHash !== undefined) {\n deleteByHash(firstHash);\n }\n }\n }\n\n function cancelGcByHash(keyHash: string): void {\n const id = gcTimers.get(keyHash);\n\n if (id !== undefined) {\n clearTimeout(id);\n gcTimers.delete(keyHash);\n }\n }\n\n function deleteByHash(keyHash: string): boolean {\n const record = store.get(keyHash);\n\n cancelGcByHash(keyHash);\n\n if (record) {\n onEvict?.(record.key, record.value);\n store.delete(keyHash);\n }\n\n if (inFlight.has(keyHash)) deletedWhileInFlight.add(keyHash);\n\n return record !== undefined;\n }\n\n function scheduleGcByHash(keyHash: string, delayMs: number): void {\n cancelGcByHash(keyHash);\n\n if (delayMs === Number.POSITIVE_INFINITY) return;\n\n if (!Number.isFinite(delayMs)) {\n throw new ArsenalValidationError('stash: ttlMs must be a finite number or Infinity');\n }\n\n if (delayMs <= 0) {\n deleteByHash(keyHash);\n\n return;\n }\n\n if (!store.has(keyHash)) return;\n\n const id = setTimeout(() => {\n gcTimers.delete(keyHash);\n deleteByHash(keyHash);\n }, delayMs);\n\n gcTimers.set(keyHash, id);\n }\n\n function deserializeValue(raw: T): T {\n if (persistence && typeof raw === 'string') return persistence.deserialize(raw);\n\n return raw;\n }\n\n function get(key: K): T | undefined {\n const record = store.get(hash(key));\n\n return record ? deserializeValue(record.value) : undefined;\n }\n\n function set(key: K, value: T, opts?: CacheSetOptions): void {\n const keyHash = hash(key);\n const stored = persistence ? (persistence.serialize(value) as unknown as T) : value;\n\n cancelGcByHash(keyHash);\n store.set(keyHash, { key, value: stored });\n evictOldestIfOverCapacity();\n\n const ttl = opts?.ttlMs ?? defaultTtlMs;\n\n if (ttl !== undefined) {\n scheduleGcByHash(keyHash, ttl);\n }\n }\n\n function getOrSet(key: K, factory: () => T | Promise<T>, opts?: CacheSetOptions): T | Promise<T> {\n const keyHash = hash(key);\n\n if (store.has(keyHash) && !opts?.forceRefresh) return get(key) as T;\n\n const pending = inFlight.get(keyHash);\n\n if (pending && !opts?.forceRefresh) return pending;\n\n const value = factory();\n\n if (isPromise(value)) {\n const capturedGeneration = generation;\n const promise: Promise<T> = value\n .then((resolved) => {\n // Only clear the in-flight slot if it's still *this* promise — an overlapping\n // `forceRefresh` call may have already replaced it with a newer in-flight promise.\n if (inFlight.get(keyHash) === promise) inFlight.delete(keyHash);\n\n if (generation === capturedGeneration && !deletedWhileInFlight.has(keyHash)) {\n set(key, resolved, opts);\n }\n\n deletedWhileInFlight.delete(keyHash);\n\n return resolved;\n })\n .catch((err: unknown) => {\n if (inFlight.get(keyHash) === promise) inFlight.delete(keyHash);\n\n deletedWhileInFlight.delete(keyHash);\n throw err;\n });\n\n inFlight.set(keyHash, promise);\n\n return promise;\n }\n\n set(key, value, opts);\n\n return value;\n }\n\n function del(key: K): boolean {\n return deleteByHash(hash(key));\n }\n\n function clear(): void {\n generation++;\n for (const id of gcTimers.values()) clearTimeout(id);\n\n if (onEvict) {\n for (const record of store.values()) {\n onEvict(record.key, record.value);\n }\n }\n\n store.clear();\n gcTimers.clear();\n inFlight.clear();\n deletedWhileInFlight.clear();\n }\n\n function* entries(): IterableIterator<[K, T]> {\n for (const record of store.values()) {\n yield [record.key, deserializeValue(record.value)];\n }\n }\n\n return {\n clear,\n delete: del,\n entries,\n get,\n getOrSet: getOrSet as Stash<T, K>['getOrSet'],\n set,\n get size() {\n return store.size;\n },\n };\n}\n","/**\n * Asserts that a condition is true. Throws with `message` if false.\n *\n * @example\n * ```ts\n * assert(Array.isArray(x));\n * assert(x > 0, 'x must be positive');\n * assert(n >= 1, 'must be at least 1', { type: RangeError });\n * ```\n *\n * @param condition - The boolean condition to assert.\n * @param [message] - Error message (default: `'Assertion failed'`).\n * @param [options.type] - Error class to throw (default: `Error`).\n * @throws {Error} If `condition` is false.\n */\nexport function assert(condition: boolean, message?: string, options?: { type?: ErrorConstructor }): asserts condition {\n if (!condition) throw new (options?.type ?? Error)(message ?? 'Assertion failed');\n}\n","/**\n * Returns a function that always returns the same value.\n */\nexport function constant<T>(value: T): () => T {\n return () => value;\n}\n","const isDev = !(globalThis as { __ARSENAL_PROD__?: boolean }).__ARSENAL_PROD__;\n\n/** @internal @security Messages may include user data. */\nexport function warn(msg: string): void {\n if (isDev) console.warn(`[@vielzeug/arsenal] ${msg}`);\n}\n","import type { Fn } from '../types';\n\nimport { warn } from '../_dev';\n\nexport type DebounceOptions = {\n /** Invoke on the leading edge of the delay window. Default: `false`. */\n leading?: boolean;\n /** Invoke on the trailing edge of the delay window. Default: `true`. */\n trailing?: boolean;\n};\n\nexport type Debounced<T extends Fn> = ((...args: Parameters<T>) => ReturnType<T> | undefined) & {\n cancel(): void;\n flush(): ReturnType<T> | undefined;\n pending(): boolean;\n};\n\n/**\n * Debounces a function. By default only the trailing edge fires (after input settles).\n * Pass `{ leading: true }` to fire immediately on the first call instead.\n * Pass `{ leading: true, trailing: true }` to fire on both edges.\n *\n * Use `flush()` to invoke immediately, `cancel()` to clear, and `pending()` to check\n * whether an invocation is scheduled.\n *\n * @example\n * ```ts\n * // Trailing (default) — fires after input settles\n * const save = debounce(persist, 500);\n *\n * // Leading — fires on the first keystroke, then silences during the window\n * const submit = debounce(sendRequest, 500, { leading: true, trailing: false });\n * ```\n */\nexport function debounce<T extends Fn>(\n fn: T,\n delay = 300,\n options: DebounceOptions = { leading: false, trailing: true },\n): Debounced<T> {\n const leading = options.leading ?? false;\n const trailing = options.trailing ?? true;\n\n if (!leading && !trailing) {\n warn('debounce: both `leading` and `trailing` are false — the wrapped function will never be invoked.');\n }\n\n let timerId: ReturnType<typeof setTimeout> | undefined;\n let lastArgs: Parameters<T> | undefined;\n let lastResult: ReturnType<T> | undefined;\n let leadingFired = false;\n\n const clearTimer = () => {\n if (timerId !== undefined) {\n clearTimeout(timerId);\n timerId = undefined;\n }\n };\n\n const invokeTrailing = () => {\n clearTimer();\n leadingFired = false;\n\n if (!lastArgs) return undefined;\n\n const args = lastArgs;\n\n lastArgs = undefined;\n lastResult = fn(...args) as ReturnType<T>;\n\n return lastResult;\n };\n\n return Object.assign(\n (...args: Parameters<T>): ReturnType<T> | undefined => {\n lastArgs = args;\n\n if (leading && !leadingFired) {\n leadingFired = true;\n lastResult = fn(...args) as ReturnType<T>;\n // Clear args regardless of `trailing` — the leading call already consumed this\n // invocation. The trailing timer below only re-invokes `fn` if a *further* call\n // arrives during the cooldown window and repopulates `lastArgs`.\n lastArgs = undefined;\n\n if (!trailing) {\n // Leading-only: start cooldown — no trailing call needed\n timerId = setTimeout(() => {\n timerId = undefined;\n leadingFired = false;\n }, delay);\n\n return lastResult;\n }\n }\n\n // When leading-only, ignore calls within the cooldown window\n if (leading && !trailing && leadingFired) return lastResult;\n\n clearTimer();\n timerId = setTimeout(invokeTrailing, delay);\n\n return lastResult;\n },\n {\n cancel: () => {\n clearTimer();\n lastArgs = undefined;\n leadingFired = false;\n },\n flush: (): ReturnType<T> | undefined => invokeTrailing(),\n pending: () => timerId !== undefined,\n },\n );\n}\n","/**\n * Returns the same input value.\n */\nexport function identity<T>(value: T): T {\n return value;\n}\n","import type { Fn } from '../types';\n\n/**\n * A wrapped function that executes `fn` at most once and exposes a `.reset()` method\n * to allow re-invocation.\n */\nexport type Once<T extends Fn> = T & { reset: () => void };\n\n/**\n * Create a function that runs once and returns the first result.\n *\n * If the first call throws, it does not count as \"called\" — the thrown error propagates to\n * that caller, and the next call will invoke `fn` again (rather than caching the failure).\n *\n * @example\n * ```ts\n * const onceRandom = once(() => Math.random())\n * onceRandom() // 0.3\n * onceRandom() // 0.3\n *\n * onceRandom.reset() // clears the cached result — allows one more invocation\n *\n * onceRandom() // 0.2\n * onceRandom() // 0.2\n * ```\n *\n * @param fn - The function to wrap.\n *\n * @returns A `Once<T>` — the wrapped function with a `.reset()` method to clear the cached result.\n */\nexport const once = <T extends Fn>(fn: T): Once<T> => {\n let result: ReturnType<T> | undefined;\n let called = false;\n\n const wrappedFn = ((...args: Parameters<T>): ReturnType<T> => {\n if (!called) {\n result = fn(...args) as ReturnType<T>;\n called = true;\n }\n\n return result as ReturnType<T>;\n }) as Once<T>;\n\n wrappedFn.reset = () => {\n result = undefined;\n called = false;\n };\n\n return wrappedFn;\n};\n","import type { Fn } from '../types';\n\ntype FirstParameters<T extends readonly Fn[]> = T extends [infer First extends Fn, ...unknown[]]\n ? Parameters<First>\n : never;\ntype LastReturnType<T extends readonly Fn[]> = T extends [...unknown[], infer Last extends Fn]\n ? ReturnType<Last>\n : never;\n\n/**\n * Pipes multiple functions into a single function. It starts from the leftmost function and proceeds to the right.\n *\n * The TypeScript overload captures the input type from the first function and the output type from the last.\n * Intermediate steps are typed as `unknown` at the call site — TypeScript cannot infer a safe chain across\n * heterogeneous function signatures without explicit overloads for every arity.\n *\n * `pipe()` with no arguments returns an identity function `<T>(x: T) => T`.\n *\n * @example\n * ```ts\n * const add = (x: number) => x + 2;\n * const multiply = (x: number) => x * 3;\n * const subtract = (x: number) => x - 4;\n * const pipedFn = pipe(subtract, multiply, add);\n *\n * pipedFn(5); // ((5-4) * 3) + 2 = 5\n *\n * // Zero-arg identity\n * pipe()(42); // 42\n * ```\n *\n * @param fns - List of functions to be piped.\n * @returns A new function that is the pipe of the input functions.\n */\nexport function pipe(): <T>(x: T) => T;\nexport function pipe<T extends readonly [Fn, ...Fn[]]>(...fns: T): (...args: FirstParameters<T>) => LastReturnType<T>;\nexport function pipe(...fns: Fn[]): Fn {\n if (fns.length === 0) return <T>(x: T): T => x;\n\n const [firstFn, ...restFns] = fns;\n\n return (...args: unknown[]) => restFns.reduce((prev: unknown, fn) => fn(prev), firstFn!(...args));\n}\n","/**\n * Runs all functions in `fns`, collecting any thrown errors.\n * - With `reverse: true`, iterates in LIFO order (useful for cleanup/teardown stacks).\n * - Throws an `AggregateError` containing all failures if any function throws.\n *\n * @example\n * ```ts\n * const cleanups = [() => a.dispose(), () => b.dispose()];\n * runAll(cleanups, { reverse: true });\n * ```\n */\nexport function runAll(fns: readonly (() => void)[], opts?: { reverse?: boolean }): void {\n const errors: unknown[] = [];\n const len = fns.length;\n\n if (opts?.reverse) {\n for (let i = len - 1; i >= 0; i--) {\n try {\n fns[i]!();\n } catch (err) {\n errors.push(err);\n }\n }\n } else {\n for (const fn of fns) {\n try {\n fn();\n } catch (err) {\n errors.push(err);\n }\n }\n }\n\n if (errors.length > 0) {\n throw new AggregateError(errors, 'One or more callbacks failed');\n }\n}\n","/**\n * Executes a side-effect callback and returns the original value.\n */\nexport function tap<T>(value: T, callback: (value: T) => void): T {\n callback(value);\n\n return value;\n}\n","import type { Fn } from '../types';\n\nexport type ThrottleOptions = {\n leading?: boolean; // invoke at the start of the window\n trailing?: boolean; // invoke at the end with the last args\n};\n\nexport type Throttled<T extends Fn> = ((...args: Parameters<T>) => ReturnType<T> | undefined) & {\n cancel(): void;\n flush(): ReturnType<T> | undefined;\n pending(): boolean; // whether there's a pending call that flush() would execute\n};\n\n/**\n * Throttles a function. By default, only the leading edge fires.\n * Pass `{ trailing: true }` to also invoke at the end of the throttle window.\n *\n * @example\n * ```ts\n * const fn = () => { ... };\n * const t = throttle(fn, 700);\n * const withTrailing = throttle(fn, 700, { trailing: true });\n * ```\n */\nexport function throttle<T extends Fn>(\n fn: T,\n delay = 700,\n options: ThrottleOptions = { leading: true, trailing: false },\n): Throttled<T> {\n const leading = options.leading ?? true;\n const trailing = options.trailing ?? false;\n\n let timerId: ReturnType<typeof setTimeout> | undefined;\n let lastInvokeTime = -Infinity;\n let lastArgs: Parameters<T> | undefined;\n let lastResult: ReturnType<T> | undefined;\n\n const clearTimer = () => {\n if (timerId !== undefined) {\n clearTimeout(timerId);\n timerId = undefined;\n }\n };\n\n const scheduleTimer = (delayMs: number) => {\n timerId = setTimeout(timerExpired, delayMs);\n };\n\n const invoke = (now: number) => {\n lastInvokeTime = now;\n clearTimer();\n\n if (!lastArgs) return undefined;\n\n const args = lastArgs;\n\n lastArgs = undefined;\n lastResult = fn(...args) as ReturnType<T>;\n\n return lastResult;\n };\n\n const remaining = (now: number) => delay - (now - lastInvokeTime);\n\n const timerExpired = () => {\n const now = Date.now();\n\n if (lastArgs && remaining(now) <= 0) {\n // trailing edge invoke\n invoke(now);\n } else if (lastArgs) {\n // reschedule until a window elapses\n scheduleTimer(remaining(now));\n } else {\n clearTimer();\n }\n };\n\n return Object.assign(\n (...args: Parameters<T>): ReturnType<T> | undefined => {\n const now = Date.now();\n\n if (lastInvokeTime === -Infinity && !leading) {\n // If leading is false, start the window now but don't invoke immediately\n lastInvokeTime = now;\n }\n\n lastArgs = args;\n\n const rem = remaining(now);\n\n if (rem <= 0) {\n // Window elapsed: invoke now\n return invoke(now);\n } else if (trailing && !timerId) {\n // Schedule trailing call if not already scheduled\n scheduleTimer(rem);\n }\n\n return lastResult;\n },\n {\n cancel: () => {\n clearTimer();\n lastArgs = undefined;\n lastInvokeTime = -Infinity;\n },\n flush: (): ReturnType<T> | undefined => {\n if (!lastArgs) return undefined;\n\n return invoke(Date.now());\n },\n // Pending if a trailing call is scheduled OR there are queued args.\n pending: () => lastArgs !== undefined || timerId !== undefined,\n },\n );\n}\n","import type { Predicate } from '../types';\n\n/**\n * Returns a predicate that is `true` only when every provided predicate is `true`.\n *\n * With zero predicates, returns `true` for all values (vacuous truth).\n *\n * @example\n * ```ts\n * const isPositiveEven = allOf(\n * (n) => n > 0,\n * (n) => n % 2 === 0,\n * );\n * [1, 2, 3, 4].filter(isPositiveEven); // [2, 4]\n * ```\n */\nexport function allOf<T>(...predicates: Predicate<T>[]): Predicate<T> {\n return (value) => predicates.every((predicate) => predicate(value));\n}\n\n/**\n * Returns a predicate that is `true` when at least one provided predicate is `true`.\n *\n * With zero predicates, returns `false` for all values (vacuous falsity).\n *\n * @example\n * ```ts\n * [1, 2, 3, 4].filter(anyOf((n) => n === 1, (n) => n === 3)); // [1, 3]\n * ```\n */\nexport function anyOf<T>(...predicates: Predicate<T>[]): Predicate<T> {\n return (value) => predicates.some((predicate) => predicate(value));\n}\n\n/**\n * Returns a predicate that is `true` when none of the provided predicates match.\n * With a single predicate this is equivalent to logical NOT.\n *\n * With zero predicates, returns `true` for all values (nothing fails — vacuous truth).\n *\n * @example\n * ```ts\n * [1, 2, 3, 4].filter(noneOf((n) => n % 2 === 0)); // [1, 3]\n * ```\n */\nexport function noneOf<T>(...predicates: Predicate<T>[]): Predicate<T> {\n return (value) => predicates.every((predicate) => !predicate(value));\n}\n\n/**\n * Returns a predicate that negates the given predicate.\n *\n * @example\n * ```ts\n * [1, 2, 3, 4].filter(not((n) => n % 2 === 0)); // [1, 3]\n * ```\n */\nexport function not<T>(predicate: Predicate<T>): Predicate<T> {\n return (value) => !predicate(value);\n}\n","/**\n * Returns `true` if the given value is an `AbortError` — i.e. an `Error` whose\n * `name` is `'AbortError'`, as thrown by `AbortController` / `AbortSignal`.\n *\n * @example\n * ```ts\n * try {\n * await fetch(url, { signal });\n * } catch (err) {\n * if (isAbortError(err)) return; // request was cancelled — ignore\n * throw err;\n * }\n * ```\n *\n * @param value - The value to test.\n * @returns `true` when `value` is an `Error` with `name === 'AbortError'`.\n */\nexport function isAbortError(value: unknown): value is Error {\n return value instanceof Error && value.name === 'AbortError';\n}\n","/**\n * Returns `true` if `value` is an `Array`, with an optional item-type guard.\n *\n * @example\n * ```ts\n * isArray([1, 2, 3]) // true\n * isArray('hello') // false\n * isArray([1, 2, 3], isNumber) // true — all items pass isNumber\n * isArray([1, 'x'], isNumber) // false — 'x' fails isNumber\n * ```\n *\n * @param value - The value to check.\n * @param itemGuard - Optional type guard applied to every element.\n */\nexport function isArray<T = unknown>(value: unknown, itemGuard?: (item: unknown) => item is T): value is T[] {\n if (!Array.isArray(value)) return false;\n\n if (itemGuard) return value.every(itemGuard);\n\n return true;\n}\n","/**\n * Checks if the value is a boolean.\n *\n * @example\n * ```ts\n * isBoolean(true); // true\n * isBoolean(false); // true\n * isBoolean(123); // false\n * isBoolean('hello world'); // false\n * isBoolean({}); // false\n * isBoolean([]); // false\n * isBoolean(new Date()); // false\n * isBoolean(null); // false\n * isBoolean(undefined); // false\n * isBoolean(NaN); // false\n * ```\n *\n * @param arg - The argument to be checked.\n *\n * @returns `true` if the value is a boolean, else `false`.\n */\nexport function isBoolean(arg: unknown): arg is boolean {\n return typeof arg === 'boolean';\n}\n","/**\n * Determines if the passed value is a valid Date Object.\n *\n * @example\n * ```ts\n * isDate(new Date()); // true\n * isDate(123); // false\n * ```\n *\n * @param arg - The argument to be checked.\n *\n * @returns `true` if the value is a valid Date object, else `false`.\n */\nexport function isDate(arg: unknown): arg is Date {\n return arg instanceof Date && !Number.isNaN(arg.getTime());\n}\n","/**\n * Checks if a value is defined (not `undefined`).\n *\n * @example\n * ```ts\n * isDefined(123); // true\n * isDefined(undefined); // false\n * isDefined('hello world'); // true\n * isDefined({}); // true\n * isDefined([]); // true\n * isDefined(null); // true\n * ```\n *\n * @param arg - The value to check.\n *\n * @returns `true` if the value is defined, else `false`.\n */\nexport function isDefined<T>(arg: T | undefined): arg is T {\n return arg !== undefined;\n}\n","/**\n * Returns `true` if `value` is a plain object — one with `Object.prototype` or `null` as its\n * prototype. Class instances, `Map`, `Set`, `Array` and other built-ins all return `false`.\n *\n * @example\n * ```ts\n * isPlainObject({}) // true\n * isPlainObject({ a: 1 }) // true\n * isPlainObject(Object.create(null)) // true\n * isPlainObject(new Map()) // false\n * isPlainObject([]) // false\n * isPlainObject(null) // false\n * ```\n */\nexport function isPlainObject(value: unknown): value is Record<string, unknown> {\n if (value == null || typeof value !== 'object') return false;\n\n const prototype = Object.getPrototypeOf(value);\n\n return prototype === Object.prototype || prototype === null;\n}\n","import { isNil } from './isNil';\nimport { isPlainObject } from './isPlainObject';\n\n/**\n * Checks if the given argument is empty.\n *\n * @example\n * ```ts\n * isEmpty(null); // true\n * isEmpty(undefined); // true\n * isEmpty([]); // true\n * isEmpty({}); // true\n * isEmpty(''); // true\n * isEmpty(0); // false\n * isEmpty(123); // false\n * isEmpty('abc'); // false\n * isEmpty([1, 2, 3]); // false\n * isEmpty({ a: 1, b: 2 }); // false\n * ```\n *\n * @param arg - The argument to be checked.\n *\n * @returns `true` if all arguments are `null`, `undefined`, `{}`, `[]`, or empty strings. Otherwise, it returns `false`.\n */\nexport function isEmpty(arg: unknown): boolean {\n if (isNil(arg) || arg === '') return true;\n\n if (Array.isArray(arg)) return arg.length === 0;\n\n if (arg instanceof Map || arg instanceof Set) return arg.size === 0;\n\n if (isPlainObject(arg)) return Object.keys(arg).length === 0;\n\n return false;\n}\n","/**\n * Determines if the passed value is an `Error` instance.\n *\n * @example\n * ```ts\n * isError(new Error('oops')); // true\n * isError('oops'); // false\n * isError(null); // false\n * ```\n *\n * @param value - The value to test.\n * @returns `true` if the value is an `Error` instance.\n */\nexport function isError(value: unknown): value is Error {\n return value instanceof Error;\n}\n","/**\n * Determines if the passed value is a function.\n *\n * @example\n * ```ts\n * isFunction(function() {}) // true\n * isFunction(() => {}) // true\n * isFunction('hello world') // false\n * ```\n *\n * @param arg - The argument to be checked.\n *\n * @returns `true` if the value is a function, else `false`.\n */\nexport function isFunction(arg: unknown): arg is (...args: any[]) => any {\n return typeof arg === 'function';\n}\n","/**\n * Performs a partial deep comparison between object and source to determine if object contains equivalent property values.\n *\n * @example\n * ```ts\n * const object = { a: 1, b: 2, c: { d: 3 } };\n *\n * isMatch(object, { a: 1, c: { d: 3 } }); // true\n * isMatch(object, { a: 1, b: 2 }); // true\n * isMatch(object, { a: 1, c: { d: 4 } }); // false\n *\n * isMatch([1, 2, 3], [1, 2]); // true\n * isMatch([1, 2, 3], [1, 2, 3]); // true\n * isMatch([1, 2, 3], [1, 2, 4]); // false\n * ```\n *\n * @param object - The object to inspect.\n * @param source - The object of property values to match.\n *\n * @returns `true` if the object is a match, else `false`.\n */\nexport function isMatch(object: unknown, source: unknown): boolean {\n if (object === source) return true;\n\n if (object == null || source == null) return false;\n\n const isObjArray = Array.isArray(object);\n const isSrcArray = Array.isArray(source);\n\n if (isObjArray !== isSrcArray) return false;\n\n if (isObjArray && isSrcArray) {\n const objArr = object as unknown[];\n const srcArr = source as unknown[];\n\n if (srcArr.length > objArr.length) return false;\n\n return srcArr.every((item, i) => isMatch(objArr[i], item));\n }\n\n if (typeof source === 'object' && typeof object === 'object') {\n // Date has no own enumerable properties — compare by timestamp instead of falling through\n // to the empty Object.keys() loop below (which would vacuously return true).\n if (source instanceof Date || object instanceof Date) {\n return source instanceof Date && object instanceof Date && source.getTime() === object.getTime();\n }\n\n // Same reasoning for RegExp — compare by source pattern and flags.\n if (source instanceof RegExp || object instanceof RegExp) {\n return (\n source instanceof RegExp &&\n object instanceof RegExp &&\n source.source === object.source &&\n source.flags === object.flags\n );\n }\n\n // Map and Set are not structurally matched by key iteration — treat as opaque\n if (source instanceof Map || source instanceof Set || object instanceof Map || object instanceof Set) {\n return false;\n }\n\n for (const key of Object.keys(source as Record<string, unknown>)) {\n if (!isMatch((object as Record<string, unknown>)?.[key], (source as Record<string, unknown>)[key])) {\n return false;\n }\n }\n\n return true;\n }\n\n return object === source;\n}\n","/**\n * Type guard to check if a value is a primitive\n *\n * @example\n * ```ts\n * isPrimitive('Hello World'); // true\n * isPrimitive(42); // true\n * isPrimitive(true); // true\n * isPrimitive({}); // false\n * isPrimitive([]); // false\n * isPrimitive(() => {}); // false\n * ```\n * @param arg - The argument to be checked.\n *\n * @returns `true` if the value is a primitive, else `false`.\n */\nexport function isPrimitive(arg: unknown): arg is string | number | boolean {\n const type = typeof arg;\n\n return type === 'string' || type === 'boolean' || (type === 'number' && !Number.isNaN(arg));\n}\n","/**\n * Checks if the provided argument is a regular expression.\n *\n * @example\n * ```ts\n * isRegex(/abc/); // true\n * isRegex(new RegExp('abc')); // true\n * isRegex('abc'); // false\n * isRegex(123); // false\n * isRegex({}); // false\n * isRegex([]); // false\n * isRegex(null); // false\n * isRegex(undefined); // false\n * ```\n *\n * @param arg - The argument to be checked.\n *\n * @return `true` if the argument is a regular expression, otherwise `false`.\n */\nexport function isRegex(arg: unknown): arg is RegExp {\n return arg instanceof RegExp;\n}\n","/**\n * Compares two values for shallow equality.\n *\n * - Primitives are compared with `Object.is`.\n * - Arrays are compared element-by-element with `Object.is` (one level deep).\n * - Objects are compared key-by-key with `Object.is` on each value (one level deep).\n * - Different types (e.g. array vs object) return `false`.\n *\n * Uses `Object.is` for the primitive comparison, so `shallowEqual(NaN, NaN)` is `true` and\n * `shallowEqual(0, -0)` is `false` — the opposite of `isEqual`, which uses `===` and treats\n * `NaN` as never equal to itself and `-0` as equal to `0`.\n *\n * For recursive deep equality, use `isEqual`.\n *\n * @example\n * ```ts\n * const inner = { x: 1 };\n * shallowEqual({ a: inner }, { a: inner }); // true — same reference\n * shallowEqual({ a: { x: 1 } }, { a: { x: 1 } }); // false — different refs\n * shallowEqual([1, 2, 3], [1, 2, 3]); // true\n * shallowEqual(1, 1); // true\n * ```\n *\n * @param a - First value.\n * @param b - Second value.\n * @returns `true` if the values are shallowly equal.\n */\nexport function shallowEqual(a: unknown, b: unknown): boolean {\n if (Object.is(a, b)) return true;\n\n if (a === null || b === null || typeof a !== 'object' || typeof b !== 'object') return false;\n\n const isArrayA = Array.isArray(a);\n const isArrayB = Array.isArray(b);\n\n if (isArrayA !== isArrayB) return false;\n\n if (isArrayA && isArrayB) {\n if (a.length !== b.length) return false;\n\n for (let i = 0; i < a.length; i++) {\n if (!Object.is(a[i], b[i])) return false;\n }\n\n return true;\n }\n\n const aKeys = Object.keys(a as Record<string, unknown>);\n const bObj = b as Record<string, unknown>;\n const aObj = a as Record<string, unknown>;\n\n if (aKeys.length !== Object.keys(bObj).length) return false;\n\n for (const key of aKeys) {\n if (!Object.hasOwn(bObj, key) || !Object.is(aObj[key], bObj[key])) return false;\n }\n\n return true;\n}\n","/**\n * Returns the absolute value of a number.\n * Supports both regular numbers and bigint.\n *\n * @example\n * ```ts\n * abs(-5); // 5\n * abs(3); // 3\n * abs(-100n); // 100n\n * ```\n *\n * @param value - The number or bigint to get absolute value of\n * @returns Absolute value\n */\nexport function abs(value: number): number;\nexport function abs(value: bigint): bigint;\nexport function abs(value: number | bigint): number | bigint {\n if (typeof value === 'bigint') {\n return value < 0n ? -value : value;\n }\n\n return Math.abs(value);\n}\n","import { ArsenalValidationError } from '../errors';\n\n/**\n * Distributes an amount proportionally according to given ratios.\n * Handles rounding to ensure the sum equals the original amount exactly.\n * The indivisible remainder is allocated to the last bucket.\n * Critical for financial operations like splitting payments to avoid rounding errors.\n *\n * @example\n * ```ts\n * // Split $100 in ratio 1:2:3 (total ratio = 6)\n * allocate(100, [1, 2, 3]);\n * // [16, 33, 51] - sum is exactly 100\n *\n * // Split $100 evenly among 3 parts\n * allocate(100, 3);\n * // [33, 33, 34] - sum is exactly 100\n *\n * // Split with bigint (e.g., cents)\n * allocate(10000n, [1, 1, 1]);\n * // [3333n, 3333n, 3334n] - sum is exactly 10000n\n * ```\n *\n * @param amount - Total amount to allocate\n * @param ratios - Array of ratios for distribution or number of equal parts\n * @returns Array of allocated amounts with remainder applied to last bucket (sum equals original amount)\n * @throws {ArsenalValidationError} If ratios array is empty, contains negative values, sums to zero, or parts is not a positive integer\n */\nexport function allocate(amount: number, ratios: number[] | number): number[];\nexport function allocate(amount: bigint, ratios: number[] | number): bigint[];\nexport function allocate(amount: number | bigint, ratios: number[] | number): (number | bigint)[] {\n // If second param is a number, validate and treat it as number of equal parts\n if (typeof ratios === 'number') {\n if (!Number.isInteger(ratios) || ratios < 1) {\n throw new ArsenalValidationError(`Parts must be a positive integer, got ${ratios}`);\n }\n }\n\n const actualRatios = Array.isArray(ratios) ? ratios : Array(ratios).fill(1);\n\n if (actualRatios.length === 0) {\n throw new ArsenalValidationError('Ratios array cannot be empty');\n }\n\n if (actualRatios.some((r) => r < 0)) {\n throw new ArsenalValidationError('Ratios must be non-negative');\n }\n\n const totalRatio = actualRatios.reduce((sum, ratio) => sum + ratio, 0);\n\n if (totalRatio === 0) {\n throw new ArsenalValidationError('Total ratio cannot be zero');\n }\n\n if (typeof amount === 'bigint') {\n const totalRatioBigInt = BigInt(totalRatio);\n const results = Array.from(\n { length: actualRatios.length - 1 },\n (_, i) => (amount * BigInt(actualRatios[i])) / totalRatioBigInt,\n );\n\n results.push(amount - results.reduce((s, v) => s + v, 0n));\n\n return results;\n }\n\n // For number type, use proportional allocation for all ratios uniformly\n const results = Array.from({ length: actualRatios.length - 1 }, (_, i) =>\n Math.floor((amount * actualRatios[i]) / totalRatio),\n );\n\n results.push(amount - results.reduce((s, v) => s + v, 0));\n\n return results;\n}\n","import { ArsenalValidationError } from '../errors';\n\n/**\n * Sum numbers in an array or numbers mapped by a callback function.\n *\n * @example\n * ```ts\n * sum([1, 2, 3]) // 6\n * sum([{value: 1}, {value: 2}, {value: 3}], (item) => item.value) // 6\n * sum(['apple', 'banana', 'cherry']) // ArsenalValidationError\n * ```\n *\n * @param array - The array to sum.\n * @param callback - An optional callback function to map the values.\n *\n * @returns The sum of the numbers in the array or the sum of the mapped values.\n *\n * @throws {ArsenalValidationError} If (after an optional `callback` mapping) any item is not a finite number.\n */\nexport function sum<T>(array: T[], callback?: (item: T) => number): number {\n if (array.length === 0) return 0;\n\n return array.reduce<number>((acc, item) => {\n const val = callback ? callback(item) : (item as unknown as number);\n\n if (typeof val !== 'number' || Number.isNaN(val)) {\n throw new ArsenalValidationError(\n 'sum: encountered a non-numeric value; provide a callback to map non-number items',\n );\n }\n\n return acc + val;\n }, 0);\n}\n","import { sum } from './sum';\n\n/**\n * Calculates the average of an array of numbers.\n *\n * @example\n * ```ts\n * const arr = [1, 2, 3, 4, 5];\n * average(arr); // 3\n * average(arr, (num) => num * 2); // 6\n * ```\n *\n * @param array - The array to average.\n * @param callback - (optional) A callback function to map each item to a number.\n * @returns The average, or `undefined` if the array is empty or contains non-numeric values.\n */\nexport function average<T>(array: T[], callback?: (item: T) => number): number | undefined {\n if (array.length === 0) return undefined;\n\n try {\n const result = sum(array, callback) / array.length;\n\n return Number.isNaN(result) ? undefined : result;\n } catch {\n return undefined;\n }\n}\n","/**\n * Restricts a number to be within a specified range.\n * Both `min` and `max` are optional — omitting one leaves that end unconstrained.\n *\n * @example\n * ```ts\n * clamp(5, 1, 10) // 5 — within range\n * clamp(0, 1, 10) // 1 — below min\n * clamp(15, 1, 10) // 10 — above max\n * clamp(15, 1) // 15 — no max, above min\n * clamp(-5, undefined, 0) // -5 — no min, below max\n * ```\n *\n * @param n - The number to clamp.\n * @param min - Optional lower bound (inclusive).\n * @param max - Optional upper bound (inclusive).\n *\n * @returns The clamped number.\n */\nexport function clamp(n: number, min?: number, max?: number): number {\n if (min != null && n < min) return min;\n\n if (max != null && n > max) return max;\n\n return n;\n}\n","/**\n * Computes the greatest common divisor of two integers using the Euclidean algorithm.\n * The sign of the inputs is ignored — the result is always non-negative.\n *\n * @example\n * ```ts\n * gcd(12, 18); // 6\n * gcd(-12, 18); // 6\n * gcd(0, 5); // 5\n * gcd(0, 0); // 0\n * ```\n *\n * @param a - The first integer.\n * @param b - The second integer.\n * @returns The greatest common divisor of `a` and `b`.\n */\nexport function gcd(a: number, b: number): number {\n let x = Math.abs(a);\n let y = Math.abs(b);\n\n while (y !== 0) {\n const temp = y;\n\n y = x % y;\n x = temp;\n }\n\n return x;\n}\n","import { gcd } from './gcd';\n\n/**\n * Computes the least common multiple of two integers.\n *\n * @example\n * ```ts\n * lcm(4, 6); // 12\n * lcm(0, 5); // 0\n * ```\n *\n * @param a - The first integer.\n * @param b - The second integer.\n * @returns The least common multiple of `a` and `b`, or `0` if either is `0`.\n */\nexport function lcm(a: number, b: number): number {\n if (a === 0 || b === 0) return 0;\n\n return Math.abs(a * b) / gcd(a, b);\n}\n","/**\n * Linearly interpolates between `a` and `b` by factor `t`. `t` is not clamped, so values\n * outside `[0, 1]` extrapolate beyond the `[a, b]` range.\n *\n * @example\n * ```ts\n * lerp(0, 10, 0.5); // 5\n * lerp(0, 10, 1.5); // 15 (extrapolated — t is not clamped)\n * ```\n *\n * @param a - The start value (returned when `t` is `0`).\n * @param b - The end value (returned when `t` is `1`).\n * @param t - The interpolation factor.\n * @returns The interpolated value.\n */\nexport function lerp(a: number, b: number, t: number): number {\n return a + (b - a) * t;\n}\n","/**\n * Creates an array of evenly-spaced numbers from `start` to `end`.\n *\n * @example\n * ```ts\n * linspace(0, 10); // [0, 2.5, 5, 7.5, 10]\n * linspace(0, 10, 3); // [0, 5, 10]\n * linspace(0, 10, 1); // [0]\n * linspace(10, 0, 5); // [10, 7.5, 5, 2.5, 0]\n * ```\n *\n * @param start - The start of the range.\n * @param end - The end of the range.\n * @param steps - Number of evenly-spaced points to generate (default: 5).\n *\n * @returns An array of `steps` numbers from `start` to `end`.\n */\nexport function linspace(start: number, end: number, steps = 5): number[] {\n if (steps <= 0) return [];\n\n if (steps === 1) return [start];\n\n const stepSize = (end - start) / (steps - 1);\n\n return Array.from({ length: steps }, (_, i) => start + i * stepSize);\n}\n","import { compare } from '../array/compare';\n\n/**\n * Finds the maximum item in an array.\n *\n * @description\n * This function can be used to find the maximum number, string, or any other type of item in an array.\n *\n * @example\n * ```ts\n * max([1, 2, 3]); // 3\n * max([{ value: 1 }, { value: 2 }, { value: 3 }], item => item.value); // 3\n * max(['apple', 'banana', 'cherry']); // 'cherry'\n * max([new Date('2023-01-01'), new Date('2022-01-01')]); // 2023-01-01\n * ```\n *\n * @param array - The array to be searched.\n * @param [callback] - (optional) The function to invoke for each element in the array to determine its value.\n *\n * @return The item with the maximum value as determined by the callback function.\n */\nexport function max<T>(array: T[], callback?: (item: T) => string | number | Date): T | undefined {\n if (array.length === 0) return undefined;\n\n const fn = callback ?? ((item: T) => item);\n let current = array[0];\n\n for (let i = 1; i < array.length; i++) {\n if (compare(fn(array[i]), fn(current)) > 0) {\n current = array[i];\n }\n }\n\n return current;\n}\n","/**\n * Returns the median of an array of numbers.\n *\n * @example\n * ```ts\n * median([1, 2, 3, 4, 100]); // 3\n * median([1, 2, 3, 4, 5], (n) => n * 2); // 6\n * median([]); // undefined\n * median([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); // 5.5\n * ```\n *\n * @param arr - The array of numbers.\n * @param callback - (optional) A callback function to map each item to a number.\n * @returns The median, or `undefined` if the array is empty.\n */\nexport function median<T>(arr: T[], callback?: (item: T) => number): number | undefined {\n if (arr.length === 0) return undefined;\n\n const values = callback ? arr.map(callback) : [...(arr as unknown as number[])];\n\n values.sort((a, b) => a - b);\n\n const mid = Math.floor(values.length / 2);\n\n return values.length % 2 === 0 ? (values[mid - 1] + values[mid]) / 2 : values[mid];\n}\n","import { compare } from '../array/compare';\n\n/**\n * Finds the minimum item in an array.\n *\n * @description\n * This function can be used to find the minimum number, string, or any other type of item in an array.\n *\n * @example\n * ```ts\n * min([1, 2, 3]); // 1\n * min([{ value: 1 }, { value: 2 }, { value: 3 }], item => item.value); // 1\n * min(['apple', 'banana', 'cherry']); // 'apple'\n * min([new Date('2023-01-01'), new Date('2022-01-01')]); // 2022-01-01\n * ```\n *\n * @param array - The array to be searched.\n * @param [callback] - (optional) The function to invoke for each element in the array to determine its value.\n *\n * @return The item with the minimum value as determined by the callback function.\n */\nexport function min<T>(array: T[], callback?: (item: T) => string | number | Date): T | undefined {\n if (array.length === 0) return undefined;\n\n const fn = callback ?? ((item: T) => item);\n let current = array[0];\n\n for (let i = 1; i < array.length; i++) {\n if (compare(fn(array[i]), fn(current)) < 0) {\n current = array[i];\n }\n }\n\n return current;\n}\n","import { ArsenalValidationError } from '../errors';\n\n/**\n * Sign-correct modulo — unlike the native `%` operator, the result always has the same sign\n * as the divisor `b` (e.g. `mod(-1, 4)` is `3`, not `-1`).\n *\n * @example\n * ```ts\n * mod(-1, 4); // 3\n * mod(5, 3); // 2\n * ```\n *\n * @param a - The dividend.\n * @param b - The divisor. Must not be `0`.\n * @returns The sign-correct modulo of `a` by `b`.\n *\n * @throws {ArsenalValidationError} If `b` is `0`.\n */\nexport function mod(a: number, b: number): number {\n if (b === 0) throw new ArsenalValidationError('mod: divisor cannot be 0');\n\n return ((a % b) + b) % b;\n}\n","import { clamp } from './clamp';\n\n/**\n * Normalizes a value from the range `[min, max]` into `[0, 1]`. The result is clamped, so\n * values outside `[min, max]` map to `0` or `1` rather than extrapolating.\n *\n * @example\n * ```ts\n * normalize(5, 0, 10); // 0.5\n * normalize(-5, 0, 10); // 0 (clamped)\n * normalize(15, 0, 10); // 1 (clamped)\n * ```\n *\n * @param value - The value to normalize.\n * @param min - The lower bound of the source range.\n * @param max - The upper bound of the source range.\n * @returns The normalized value in `[0, 1]`, or `0` if `min === max`.\n */\nexport function normalize(value: number, min: number, max: number): number {\n if (min === max) return 0;\n\n return clamp((value - min) / (max - min), 0, 1);\n}\n","/**\n * Calculates what percentage `value` is of `total`.\n *\n * @example\n * ```ts\n * percent(25, 100); // 25\n * percent(1, 3); // 33.333...\n * percent(50, 200); // 25\n * percent(0, 100); // 0\n * percent(5, 0); // 0\n * ```\n *\n * @param value - The partial value.\n * @param total - The total value.\n *\n * @returns The percentage (0–100 scale). Returns 0 when `total` is 0.\n */\nexport function percent(value: number, total: number): number {\n if (total === 0) return 0;\n\n return (value / total) * 100;\n}\n","import { ArsenalValidationError } from '../errors';\n\n/**\n * Creates an array of numbers from `0` up to, but not including, `stop` with step `1`.\n *\n * @example\n * ```ts\n * range(5) // [0, 1, 2, 3, 4]\n * ```\n */\nexport function range(stop: number): number[];\n/**\n * Creates an array of numbers from `start` up to, but not including, `stop` with step `1`.\n *\n * @example\n * ```ts\n * range(2, 6) // [2, 3, 4, 5]\n * ```\n */\nexport function range(start: number, stop: number): number[];\n/**\n * Creates an array of numbers progressing from `start` up to, but not including, `stop` with a given `step`.\n *\n * @example\n * ```ts\n * range(0, 10, 2) // [0, 2, 4, 6, 8]\n * range(10, 0, -2) // [10, 8, 6, 4, 2]\n * ```\n *\n * @param start - The start of the range.\n * @param stop - The end of the range (exclusive).\n * @param step - The value to increment or decrement by.\n *\n * @returns The range of numbers.\n *\n * @throws {ArsenalValidationError} If start, stop, or step are not finite numbers, step is 0, or range exceeds maximum size.\n */\nexport function range(start: number, stop: number, step: number): number[];\nexport function range(startOrStop: number, stop?: number, step?: number): number[] {\n const [resolvedStart, resolvedStop, resolvedStep] =\n stop === undefined ? [0, startOrStop, 1] : step === undefined ? [startOrStop, stop, 1] : [startOrStop, stop, step];\n\n if (!Number.isFinite(resolvedStart) || !Number.isFinite(resolvedStop) || !Number.isFinite(resolvedStep)) {\n throw new ArsenalValidationError('range: start, stop, and step must be finite numbers');\n }\n\n if (resolvedStep === 0) throw new ArsenalValidationError('range: step cannot be 0');\n\n if (resolvedStart === resolvedStop) {\n return [];\n }\n\n const raw = (resolvedStop - resolvedStart) / resolvedStep;\n const length = Math.max(0, Number.isInteger(raw) ? raw : Math.ceil(raw + Number.EPSILON));\n\n if (length > 10_000_000) throw new ArsenalValidationError('range: exceeds maximum allowed size of 10,000,000');\n\n return Array.from({ length }, (_, i) => resolvedStart + i * resolvedStep);\n}\n","/**\n * Rounds a number to a specified number of decimal places.\n *\n * The `precision` argument is limited to be within the range of -323 to +292 to avoid NaN results.\n *\n * @example\n * ```ts\n * round(123.456) // 123\n * round(123.456, -1) // 120\n * round(123.456, 1, Math.ceil) // 123.5\n * round(123.456, 1, Math.floor) // 123.4\n * ```\n *\n * @param value - The number to round.\n * @param precision - The number of decimal places to round to.\n * @param [parser] - (optional) function to convert the number to a value.\n *\n * @returns The rounded number.\n */\nexport function round(value: number, precision = 0, parser: (value: number) => number = Math.round): number {\n if (precision === 0) return parser(value);\n\n const factor = 10 ** Math.max(-323, Math.min(precision, 292));\n\n return parser(value * factor) / factor;\n}\n","import { average } from './average';\n\n/**\n * Computes the population variance (average squared deviation from the mean) of an array of\n * numbers, or of values mapped by a callback.\n *\n * @example\n * ```ts\n * variance([2, 4, 4, 4, 5, 5, 7, 9]); // 4\n * variance([{ n: 1 }, { n: 3 }], (item) => item.n); // 1\n * variance([]); // 0\n * ```\n *\n * @param array - The array to compute variance over.\n * @param callback - An optional callback to map each item to a number.\n * @returns The population variance, or `0` for an empty array.\n */\nexport function variance<T>(array: T[], callback?: (item: T) => number): number {\n if (array.length === 0) return 0;\n\n const values = callback ? array.map(callback) : (array as unknown as number[]);\n const mean = average(values) ?? 0;\n\n return average(values.map((value) => (value - mean) ** 2)) ?? 0;\n}\n","import { variance } from './variance';\n\n/**\n * Computes the population standard deviation (square root of `variance`) of an array of\n * numbers, or of values mapped by a callback.\n *\n * @example\n * ```ts\n * standardDeviation([2, 4, 4, 4, 5, 5, 7, 9]); // 2\n * standardDeviation([]); // 0\n * ```\n *\n * @param array - The array to compute standard deviation over.\n * @param callback - An optional callback to map each item to a number.\n * @returns The population standard deviation, or `0` for an empty array.\n */\nexport function standardDeviation<T>(array: T[], callback?: (item: T) => number): number {\n return Math.sqrt(variance(array, callback));\n}\n","import type { Obj } from '../types';\n\nimport { isUnsafeKey } from '../_common/unsafePaths';\nimport { isPlainObject } from '../guards/isPlainObject';\n\n/**\n * Fills in `undefined` properties in `target` with values from `sources`. First source wins\n * — unlike `shallowMerge`, already-set keys are never overwritten.\n *\n * @example\n * ```ts\n * defaults({ a: 1, b: undefined }, { a: 99, b: 2, c: 3 });\n * // { a: 1, b: 2, c: 3 }\n * ```\n *\n * @param target - The object to fill in.\n * @param sources - One or more partial objects supplying default values.\n * @returns A new object with missing keys filled from `sources`.\n */\nexport function defaults<T extends Obj>(target: T, ...sources: Array<Partial<T>>): T {\n const out = { ...target };\n\n for (const source of sources) {\n if (!isPlainObject(source)) continue;\n\n for (const key of Object.keys(source) as Array<keyof T>) {\n if (isUnsafeKey(key as PropertyKey)) continue;\n\n if (out[key] === undefined) {\n out[key] = source[key] as T[keyof T];\n }\n }\n }\n\n return out;\n}\n","import type { Obj } from '../types';\n\nimport { isUnsafeKey } from '../_common/unsafePaths';\nimport { isEqual } from '../guards/isEqual';\n\nexport type DiffResult<T extends Obj> = {\n /** Keys present in `after` but not in `before`. */\n added: Array<keyof T & string>;\n /** Keys present in both objects whose values differ. Maps key → `{ before, after }`. */\n changed: { [K in keyof T]?: { after: T[K]; before: T[K] } };\n /** Keys present in `before` but not in `after`. */\n removed: Array<keyof T & string>;\n};\n\n/**\n * Computes the structural difference between two plain objects.\n * Returns an `{ added, removed, changed }` result — no sentinel symbols needed.\n * Dangerous keys (`__proto__`, `constructor`, `prototype`) are omitted from `changed`.\n *\n * @example\n * ```ts\n * diff({ a: 1, b: 2, c: 3 }, { a: 1, b: 99 });\n * // { added: [], removed: ['c'], changed: { b: { before: 2, after: 99 } } }\n *\n * diff({ x: { n: 1 } }, { x: { n: 2 } });\n * // { added: [], removed: [], changed: { x: { before: { n: 1 }, after: { n: 2 } } } }\n * ```\n *\n * @param before - The original object.\n * @param after - The updated object.\n * @param compareFn - Custom equality function. Defaults to deep `isEqual`.\n */\nexport function diff<T extends Obj>(\n before: T = {} as T,\n after: T = {} as T,\n compareFn: (a: unknown, b: unknown) => boolean = isEqual,\n): DiffResult<T> {\n const added: Array<keyof T & string> = [];\n const removed: Array<keyof T & string> = [];\n const changed: Record<string, { after: unknown; before: unknown }> = {};\n\n const beforeKeys = new Set(Object.keys(before));\n const afterKeys = new Set(Object.keys(after));\n\n for (const key of afterKeys) {\n if (!beforeKeys.has(key)) {\n added.push(key as keyof T & string);\n } else if (!isUnsafeKey(key) && !compareFn(before[key], after[key])) {\n changed[key] = { after: after[key], before: before[key] };\n }\n }\n\n for (const key of beforeKeys) {\n if (!afterKeys.has(key)) {\n removed.push(key as keyof T & string);\n }\n }\n\n return { added, changed: changed as DiffResult<T>['changed'], removed };\n}\n\nexport type ArrayDiff<T> = {\n added: T[];\n removed: T[];\n};\n\nexport type ArrayDiffOptions<T> = {\n compareFn?: (a: T, b: T) => boolean;\n};\n\n/**\n * Computes the set-difference between two arrays.\n * Items present in `after` but not `before` are `added`.\n * Items present in `before` but not `after` are `removed`.\n * Order-independent; uses deep equality by default.\n *\n * @example\n * ```ts\n * diffArrays([1, 2, 3], [2, 3, 4]); // { added: [4], removed: [1] }\n * diffArrays(\n * [{ id: 1 }, { id: 2 }],\n * [{ id: 2 }, { id: 3 }],\n * { compareFn: (a, b) => a.id === b.id },\n * ); // { added: [{ id: 3 }], removed: [{ id: 1 }] }\n * ```\n *\n * @param before - The original array.\n * @param after - The updated array.\n * @param [options.compareFn] - Custom equality function. Defaults to deep `isEqual`.\n * @returns An object with `added` and `removed` arrays.\n */\nexport function diffArrays<T>(before: T[], after: T[], options?: ArrayDiffOptions<T>): ArrayDiff<T> {\n const compareFn = options?.compareFn ?? ((a: T, b: T) => isEqual(a, b));\n\n return {\n added: after.filter((item) => !before.some((b) => compareFn(b, item))),\n removed: before.filter((item) => !after.some((a) => compareFn(item, a))),\n };\n}\n","import type { Obj } from '../types';\n\nimport { isUnsafeKey } from '../_common/unsafePaths';\n\n/**\n * Filters object entries using a value predicate. Dangerous keys (`__proto__`, `constructor`,\n * `prototype`) are always skipped.\n *\n * @example\n * ```ts\n * filterValues({ a: 1, b: 2, c: 3 }, (value) => value > 1); // { b: 2, c: 3 }\n * ```\n *\n * @param obj - The source object.\n * @param predicate - Returns `true` to keep an entry.\n * @returns A new object containing only entries for which `predicate` returned `true`.\n */\nexport function filterValues<T extends Obj>(\n obj: T,\n predicate: (value: T[keyof T], key: keyof T, obj: T) => boolean,\n): Partial<T> {\n const out: Partial<T> = {};\n\n for (const key of Object.keys(obj) as Array<keyof T>) {\n if (isUnsafeKey(key as PropertyKey)) continue;\n\n if (predicate(obj[key], key, obj)) {\n out[key] = obj[key];\n }\n }\n\n return out;\n}\n","import { UNSAFE_PATH_SEGMENTS } from '../_common/unsafePaths';\nimport { isPlainObject } from '../guards/isPlainObject';\n\n/**\n * Flattens a nested plain object into a map of dot-notation path keys to leaf values.\n * Keys containing unsafe segments (`__proto__`, `constructor`, `prototype`) are silently skipped.\n * Nesting beyond MAX_FLATTEN_DEPTH is treated as an opaque leaf value to prevent stack overflows.\n *\n * @example\n * ```ts\n * flattenPaths({ a: { b: 1, c: 2 }, d: 3 })\n * // { 'a.b': 1, 'a.c': 2, 'd': 3 }\n * ```\n */\nconst MAX_FLATTEN_DEPTH = 10;\n\nfunction _flattenPaths(obj: Record<string, unknown>, prefix: string, depth: number): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n\n for (const [key, val] of Object.entries(obj)) {\n if (UNSAFE_PATH_SEGMENTS.has(key)) continue;\n\n const fullKey = prefix ? `${prefix}.${key}` : key;\n\n if (isPlainObject(val) && depth < MAX_FLATTEN_DEPTH) {\n Object.assign(result, _flattenPaths(val as Record<string, unknown>, fullKey, depth + 1));\n } else {\n result[fullKey] = val;\n }\n }\n\n return result;\n}\n\nexport function flattenPaths(obj: Record<string, unknown>): Record<string, unknown> {\n return _flattenPaths(obj, '', 0);\n}\n\n/**\n * Reconstructs a nested plain object from a map of dot-notation path keys to leaf values.\n * Any path containing an unsafe segment is silently skipped.\n *\n * @example\n * ```ts\n * unflattenPaths({ 'a.b': 1, 'a.c': 2, 'd': 3 })\n * // { a: { b: 1, c: 2 }, d: 3 }\n * ```\n */\nexport function unflattenPaths(flat: Record<string, unknown>): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n\n for (const [key, val] of Object.entries(flat)) {\n const parts = key.split('.');\n\n if (parts.some((p) => UNSAFE_PATH_SEGMENTS.has(p))) continue;\n\n let obj = result;\n\n for (let i = 0; i < parts.length - 1; i++) {\n if (!isPlainObject(obj[parts[i]])) {\n obj[parts[i]] = {};\n }\n\n obj = obj[parts[i]] as Record<string, unknown>;\n }\n\n obj[parts[parts.length - 1]] = val;\n }\n\n return result;\n}\n","import type { Obj } from '../types';\n\nimport { UNSAFE_PATH_SEGMENTS } from '../_common/unsafePaths';\nimport { ArsenalValidationError } from '../errors';\n\ntype PathValue<T, P extends string> = P extends `${infer Key}.${infer Rest}`\n ? Key extends keyof T\n ? PathValue<T[Key], Rest>\n : undefined\n : P extends keyof T\n ? T[P]\n : undefined;\n\nexport type GetPathOptions = {\n /**\n * When `false`, throws an `ArsenalValidationError` on bracket-notation segments instead of\n * auto-converting them to dot notation. Default: `true`.\n */\n bracketNotation?: boolean;\n /**\n * Returned when the path is missing or resolves to `undefined`.\n * Mutually exclusive with `strict` — if both are set, `strict` takes precedence.\n */\n fallback?: unknown;\n /**\n * When `true`, throws an `ArsenalValidationError` if any path segment is missing.\n * Default: `false`.\n */\n strict?: boolean;\n};\n\n/**\n * Retrieves the value at a dot-notation path of an object.\n *\n * Bracket notation (`a[0].b`) is automatically converted to dot notation by default.\n * Unsafe path segments (`__proto__`, `constructor`, `prototype`) always return `options.fallback`.\n *\n * @example\n * ```ts\n * const obj = { a: { b: { c: 3 } }, d: [1, 2, 3] };\n *\n * getPath(obj, 'a.b.c'); // 3\n * getPath(obj, 'a.b.x', { fallback: 'fallback' }); // 'fallback'\n * getPath(obj, 'd[1]'); // 2 (bracket auto-converted)\n * getPath(obj, 'e.f.g', { strict: true }); // throws ArsenalValidationError\n * getPath(obj, 'a[0]', { bracketNotation: false }); // throws ArsenalValidationError\n * ```\n *\n * @template T - The object type.\n * @template P - The path string type.\n * @param item - The object to query.\n * @param path - The dot-separated path.\n * @param [options] - Options: `fallback`, `strict`, `bracketNotation`.\n * @returns The resolved value, or `options.fallback` if missing.\n * @throws {ArsenalValidationError} When `bracketNotation: false` and bracket syntax is used.\n * @throws {ArsenalValidationError} When `strict: true` and the path does not exist.\n */\nexport function getPath<T extends Obj, P extends string>(\n item: T,\n path: P,\n options: GetPathOptions = {},\n): PathValue<T, P> | undefined {\n const { bracketNotation = true, fallback: defaultValue, strict = false } = options;\n\n if (/[[\\]]/.test(path)) {\n if (!bracketNotation) {\n throw new ArsenalValidationError(\n `getPath: bracket notation is not supported. Use dot notation: '${path.replace(/\\[(\\d+)\\]/g, '.$1').replace(/^\\.|\\.$/g, '')}' or pass { bracketNotation: true }.`,\n );\n }\n\n path = path.replace(/\\[(\\d+)\\]/g, '.$1').replace(/^\\.|\\.$/g, '') as P;\n }\n\n const fragments = path.split('.').filter(Boolean);\n let current: unknown = item;\n\n for (const fragment of fragments) {\n if (UNSAFE_PATH_SEGMENTS.has(fragment)) return defaultValue as PathValue<T, P>;\n\n if (current == null || typeof current !== 'object') {\n if (strict) throw new ArsenalValidationError(`Cannot read property '${fragment}' of ${current}`);\n\n return defaultValue as PathValue<T, P>;\n }\n\n current = (current as Record<string, unknown>)[fragment];\n\n if (current === undefined) {\n if (strict) throw new ArsenalValidationError(`Property '${fragment}' does not exist`);\n\n return defaultValue as PathValue<T, P>;\n }\n }\n\n return current as PathValue<T, P>;\n}\n","import { isUnsafeKey } from '../_common/unsafePaths';\n\n/**\n * Inverts key-value pairs, so each value becomes a key and each key becomes its value.\n * Entries whose value is a dangerous key (`__proto__`, `constructor`, `prototype`) are skipped\n * to avoid prototype pollution. If multiple keys share the same value, the last one wins.\n *\n * @example\n * ```ts\n * invert({ a: 'x', b: 'y' }); // { x: 'a', y: 'b' }\n * ```\n *\n * @param obj - The source object. Values must be valid property keys (string, number, or symbol).\n * @returns A new object with keys and values swapped.\n */\nexport function invert<T extends Record<PropertyKey, PropertyKey>>(obj: T): Record<T[keyof T], keyof T> {\n const out = {} as Record<T[keyof T], keyof T>;\n\n for (const [key, value] of Object.entries(obj) as Array<[keyof T, T[keyof T]]>) {\n if (isUnsafeKey(value)) continue;\n\n out[value] = key;\n }\n\n return out;\n}\n","import type { Obj } from '../types';\n\nimport { isUnsafeKey } from '../_common/unsafePaths';\n\n/**\n * Maps object keys while preserving values. Both the original key and any mapped key that\n * resolve to a dangerous key (`__proto__`, `constructor`, `prototype`) are skipped.\n *\n * @example\n * ```ts\n * mapKeys({ a: 1, b: 2 }, (key) => `x_${String(key)}`); // { x_a: 1, x_b: 2 }\n * ```\n *\n * @param obj - The source object.\n * @param mapper - Function producing the new key for each entry.\n * @returns A new object with mapped keys and the original values.\n */\nexport function mapKeys<T extends Obj>(\n obj: T,\n mapper: (key: keyof T, value: T[keyof T], obj: T) => PropertyKey,\n): Record<PropertyKey, T[keyof T]> {\n const out: Record<PropertyKey, T[keyof T]> = {};\n\n for (const key of Object.keys(obj) as Array<keyof T>) {\n if (isUnsafeKey(key as PropertyKey)) continue;\n\n const mappedKey = mapper(key, obj[key], obj);\n\n if (isUnsafeKey(mappedKey)) continue;\n\n out[mappedKey] = obj[key];\n }\n\n return out;\n}\n","import type { Obj } from '../types';\n\nimport { isUnsafeKey } from '../_common/unsafePaths';\n\n/**\n * Maps object values while preserving the original keys. Dangerous keys (`__proto__`,\n * `constructor`, `prototype`) are always skipped.\n *\n * @example\n * ```ts\n * mapValues({ a: 1, b: 2 }, (value) => value * 2); // { a: 2, b: 4 }\n * ```\n *\n * @param obj - The source object.\n * @param mapper - Function producing the new value for each entry.\n * @returns A new object with the same keys and mapped values.\n */\nexport function mapValues<T extends Obj, R>(\n obj: T,\n mapper: (value: T[keyof T], key: keyof T, obj: T) => R,\n): { [K in keyof T]: R } {\n const out = {} as { [K in keyof T]: R };\n\n for (const key of Object.keys(obj) as Array<keyof T>) {\n if (isUnsafeKey(key as PropertyKey)) continue;\n\n out[key] = mapper(obj[key], key, obj);\n }\n\n return out;\n}\n","import type { Obj } from '../types';\n\nimport { isUnsafeKey } from '../_common/unsafePaths';\nimport { isPlainObject } from '../guards/isPlainObject';\n\nexport type DeepMergeOptions = {\n /** How to handle arrays when both source and target contain one. Default: `'replace'`. */\n arrayStrategy?: 'concat' | 'replace';\n};\n\ntype DeepMerge<T, U> = T extends Obj\n ? U extends Obj\n ? {\n [K in keyof T | keyof U]: K extends keyof T\n ? K extends keyof U\n ? DeepMerge<T[K], U[K]>\n : T[K]\n : K extends keyof U\n ? U[K]\n : never;\n }\n : U\n : U;\n\ntype Merge<T extends Obj[]> = T extends [infer First, ...infer Rest]\n ? First extends Obj\n ? Rest extends Obj[]\n ? DeepMerge<First, Merge<Rest>>\n : First\n : Obj\n : Obj;\n\nfunction mergeObjects<T extends Obj, U extends Obj>(target: T, source: U, options: DeepMergeOptions): DeepMerge<T, U> {\n if (!isPlainObject(source)) return source as DeepMerge<T, U>;\n\n const result = { ...target } as DeepMerge<T, U>;\n\n for (const key of Object.keys(source)) {\n // Guard against prototype pollution: skip dangerous keys\n if (isUnsafeKey(key)) {\n continue;\n }\n\n const sourceValue = source[key];\n const targetValue = result[key];\n\n (result as Record<string, unknown>)[key] =\n Array.isArray(sourceValue) && Array.isArray(targetValue)\n ? options.arrayStrategy === 'concat'\n ? [...targetValue, ...sourceValue]\n : sourceValue\n : isPlainObject(sourceValue) && isPlainObject(targetValue)\n ? mergeObjects(targetValue as Obj, sourceValue as Obj, options)\n : sourceValue;\n }\n\n return result;\n}\n\n/**\n * Deeply merges two or more objects. Arrays in source objects **replace** the target array by default.\n * Pass `{ arrayStrategy: 'concat' }` as the last argument to concatenate arrays instead.\n *\n * @example\n * ```ts\n * deepMerge({ a: 1, b: { x: 1 } }, { b: { y: 2 }, c: 3 });\n * // { a: 1, b: { x: 1, y: 2 }, c: 3 }\n *\n * deepMerge({ tags: ['a'] }, { tags: ['b'] });\n * // { tags: ['b'] } ← arrays replaced\n *\n * deepMerge({ tags: ['a'] }, { tags: ['b'] }, { arrayStrategy: 'concat' });\n * // { tags: ['a', 'b'] }\n * ```\n */\nexport function deepMerge<T extends Obj[]>(...args: [...T] | [...T, DeepMergeOptions]): Merge<T> {\n const lastArg = args[args.length - 1];\n const hasOptions =\n args.length > 0 &&\n typeof lastArg === 'object' &&\n lastArg !== null &&\n !Array.isArray(lastArg) &&\n 'arrayStrategy' in lastArg &&\n Object.keys(lastArg).length === 1 &&\n ((lastArg as DeepMergeOptions).arrayStrategy === 'concat' ||\n (lastArg as DeepMergeOptions).arrayStrategy === 'replace');\n\n const options: DeepMergeOptions = hasOptions ? (lastArg as DeepMergeOptions) : {};\n const items = (hasOptions ? args.slice(0, -1) : args) as Obj[];\n\n if (items.length === 0) return {} as Merge<T>;\n\n return items.reduce((acc: Obj, obj: Obj) => mergeObjects(acc, obj, options) as Obj, {} as Obj) as unknown as Merge<T>;\n}\n\n/**\n * Shallowly merges two or more objects. Later sources win for duplicate keys.\n * Dangerous keys (`__proto__`, `constructor`, `prototype`) are always skipped.\n *\n * @example\n * ```ts\n * shallowMerge({ a: 1, b: { x: 1 } }, { b: { y: 2 } });\n * // { a: 1, b: { y: 2 } } ← nested object replaced, not merged\n *\n * shallowMerge(defaults, overrides, extras);\n * ```\n */\nexport function shallowMerge<T extends Obj[]>(...items: [...T]): Merge<T> {\n if (items.length === 0) return {} as Merge<T>;\n\n const result: Obj = {};\n\n for (const item of items) {\n for (const key of Object.keys(item)) {\n if (isUnsafeKey(key)) continue;\n\n result[key] = item[key];\n }\n }\n\n return result as Merge<T>;\n}\n","import type { Obj } from '../types';\n\nimport { isUnsafeKey } from '../_common/unsafePaths';\n\n/**\n * Creates a new object without the selected keys. Only `obj`'s own enumerable keys are\n * considered; dangerous keys (`__proto__`, `constructor`, `prototype`) are always skipped.\n *\n * @example\n * ```ts\n * omit({ a: 1, b: 2, c: 3 }, ['b']); // { a: 1, c: 3 }\n * ```\n *\n * @param obj - The source object.\n * @param omittedKeys - The keys to exclude.\n * @returns A new object with `omittedKeys` removed.\n */\nexport function omit<T extends Obj, K extends keyof T>(obj: T, omittedKeys: readonly K[]): Omit<T, K> {\n const blacklist = new Set<PropertyKey>(omittedKeys as readonly PropertyKey[]);\n const out = {} as Omit<T, K>;\n\n for (const key of Object.keys(obj) as Array<keyof T>) {\n if (isUnsafeKey(key as PropertyKey)) continue;\n\n if (!blacklist.has(key)) {\n (out as T)[key] = obj[key];\n }\n }\n\n return out;\n}\n","import { isNil } from '../guards/isNil';\n\nexport type ParseJSONOptions<T> = {\n fallback?: T;\n reviver?: (key: string, value: unknown) => unknown;\n validator?: (parsed: unknown) => boolean;\n};\n\n/**\n * Parses a JSON string and returns the resulting value.\n * `null` and `undefined` inputs return `fallback` without throwing.\n *\n * @example\n * ```ts\n * parseJSON<Record<string, number>>('{\"a\":1}'); // { a: 1 }\n * parseJSON('bad json', { fallback: {} }); // {}\n * parseJSON(null, { fallback: 0 }); // 0\n *\n * // With a validator — returns fallback when validation fails\n * parseJSON('{\"id\":\"bad\"}', {\n * validator: (v) => typeof (v as Record<string, unknown>).id === 'number',\n * fallback: { id: 0 },\n * }); // { id: 0 }\n * ```\n *\n * @template T - The expected type of the parsed JSON.\n * @param json - The JSON string to parse. `null` / `undefined` return `fallback`.\n * @param [options.fallback] - Value to return when parsing fails, input is nullish, or validation fails.\n * @param [options.reviver] - Optional reviver function for `JSON.parse`.\n * @param [options.validator] - Optional predicate; if it returns `false`, `fallback` is returned.\n *\n * @returns The parsed value, or `fallback` on failure.\n */\nexport function parseJSON<T = unknown>(\n json: string | null | undefined,\n options: ParseJSONOptions<T> = {},\n): T | undefined {\n const { fallback, reviver, validator } = options;\n\n if (isNil(json)) return fallback;\n\n try {\n const value = JSON.parse(json, reviver as Parameters<typeof JSON.parse>[1]) as unknown;\n\n if (value === undefined) return fallback;\n\n if (validator && !validator(value)) return fallback;\n\n return value as T | undefined;\n } catch {\n return fallback;\n }\n}\n","import type { Obj } from '../types';\n\nimport { isUnsafeKey } from '../_common/unsafePaths';\n\n/**\n * Creates a new object containing only selected keys. Only `obj`'s own enumerable keys are\n * considered — inherited properties (e.g. `toString`) are never picked, and dangerous keys\n * (`__proto__`, `constructor`, `prototype`) are always skipped.\n *\n * @example\n * ```ts\n * pick({ a: 1, b: 2, c: 3 }, ['a', 'c']); // { a: 1, c: 3 }\n * ```\n *\n * @param obj - The source object.\n * @param selectedKeys - The keys to keep.\n * @returns A new object containing only `selectedKeys` that exist as own properties of `obj`.\n */\nexport function pick<T extends Obj, K extends keyof T>(obj: T, selectedKeys: readonly K[]): Pick<T, K> {\n const out = {} as Pick<T, K>;\n\n for (const key of selectedKeys) {\n if (isUnsafeKey(key as PropertyKey)) continue;\n\n if (Object.hasOwn(obj, key)) {\n out[key] = obj[key];\n }\n }\n\n return out;\n}\n","import { isUnsafeKey } from '../_common/unsafePaths';\nimport { filterMap } from '../array/filterMap';\nimport { isEmpty } from '../guards/isEmpty';\nimport { isNil } from '../guards/isNil';\nimport { isPlainObject } from '../guards/isPlainObject';\nimport { isString } from '../guards/isString';\n\n/**\n * Removes all nullable and empty values from strings, arrays, or objects.\n *\n * - For strings: trims whitespace and returns `undefined` if the result is empty.\n * - For arrays: recursively removes `null`, `undefined`, empty strings, and empty objects/arrays.\n * - For objects: recursively removes properties whose pruned value is empty. Dangerous keys\n * (`__proto__`, `constructor`, `prototype`) are always skipped.\n * - For any other type: returns the value unchanged.\n *\n * @example\n * ```ts\n * prune(' hello '); // 'hello'\n * prune(' '); // undefined\n * prune([1, null, '', 2, undefined, 3]); // [1, 2, 3]\n * prune({ a: 1, b: null, c: '', d: 2 }); // { a: 1, d: 2 }\n * prune({ a: { b: null, c: '' }, d: 1 }); // { d: 1 }\n * ```\n *\n * @param value - The value to prune.\n * @returns The pruned value, or `undefined` if the result would be empty.\n */\nexport function prune(value: string): string | undefined;\nexport function prune<T>(value: T[]): Array<NonNullable<T>> | undefined;\nexport function prune<T extends Record<string, unknown>>(value: T): Partial<T> | undefined;\nexport function prune<T>(value: T): T | undefined;\nexport function prune<T>(value: T): T | undefined {\n if (isNil(value)) return undefined;\n\n if (isString(value)) {\n const trimmed = value.trim();\n\n return (trimmed === '' ? undefined : trimmed) as T | undefined;\n }\n\n if (Array.isArray(value)) {\n const cleaned = filterMap(value as unknown[], (item) => {\n const pruned = prune(item);\n\n return isEmpty(pruned) ? undefined : (pruned as unknown);\n });\n\n return (cleaned.length === 0 ? undefined : cleaned) as T | undefined;\n }\n\n if (isPlainObject(value)) {\n const cleaned: Record<string, unknown> = {};\n\n for (const [key, val] of Object.entries(value)) {\n if (isUnsafeKey(key)) continue;\n\n const cleanedValue = prune(val);\n\n if (!isEmpty(cleanedValue)) {\n cleaned[key] = cleanedValue;\n }\n }\n\n return (Object.keys(cleaned).length === 0 ? undefined : cleaned) as T | undefined;\n }\n\n return value;\n}\n","import { ArsenalSerializationError } from '../errors';\n\nexport type HashOptions = {\n /**\n * What to do when a class instance is encountered (an object whose prototype is\n * neither `Object.prototype` nor `null`).\n *\n * - `'coerce'` (default) — calls `String(value)`.\n * - `'throw'` — throws an `ArsenalSerializationError`.\n */\n onClassInstance?: 'coerce' | 'throw';\n};\n\n/**\n * Produces a deterministic, order-independent string representation of any value.\n * Object keys are sorted alphabetically, so `{ b: 1, a: 2 }` and `{ a: 2, b: 1 }` produce\n * the same output. Handles `Date`, `RegExp`, `Set`, `Map`, and `bigint` in addition to plain JSON.\n *\n * Useful for generating stable cache keys from arbitrary query parameters or options objects.\n *\n * Class instances fall back to `String(value)` by default.\n * Pass `{ onClassInstance: 'throw' }` to throw an `ArsenalSerializationError` instead.\n *\n * @example\n * ```ts\n * hash({ b: 2, a: 1 }) // '{\"a\":1,\"b\":2}'\n * hash([3, 1, 2]) // '[3,1,2]'\n * hash(new Date('2024-01-01T00:00:00Z')) // '[Date:2024-01-01T00:00:00.000Z]'\n * hash(new Set([3, 1, 2])) // '[Set:1,2,3]'\n * hash(new MyClass(), { onClassInstance: 'throw' }) // throws ArsenalSerializationError\n * ```\n *\n * @throws {ArsenalSerializationError} If `options.onClassInstance` is `'throw'` and a class instance is encountered.\n */\nfunction _hash(value: unknown, options: HashOptions | undefined, visited: Set<object>): string {\n if (value === undefined) return 'undefined';\n\n if (value === null) return 'null';\n\n if (typeof value === 'bigint') return `${value}n`;\n\n if (typeof value !== 'object') return JSON.stringify(value);\n\n if (visited.has(value as object)) return '[Circular]';\n\n visited.add(value as object);\n\n if (value instanceof Date) return `[Date:${Number.isNaN(value.getTime()) ? 'Invalid' : value.toISOString()}]`;\n\n if (value instanceof RegExp) return `[RegExp:${value.source}/${value.flags}]`;\n\n if (value instanceof Set)\n return `[Set:${[...value]\n .map((v) => _hash(v, options, visited))\n .sort()\n .join(',')}]`;\n\n if (value instanceof Map) {\n const entries = [...value.entries()]\n .map(([key, entryValue]) => [_hash(key, options, visited), _hash(entryValue, options, visited)] as const)\n .sort(([leftKey, leftValue], [rightKey, rightValue]) =>\n leftKey === rightKey ? leftValue.localeCompare(rightValue) : leftKey.localeCompare(rightKey),\n );\n\n return `[Map:${entries.map(([key, entryValue]) => `${key}=>${entryValue}`).join(',')}]`;\n }\n\n if (Array.isArray(value)) return `[${value.map((v) => _hash(v, options, visited)).join(',')}]`;\n\n const proto = Object.getPrototypeOf(value) as unknown;\n\n if (proto !== Object.prototype && proto !== null) {\n if (options?.onClassInstance === 'throw') {\n throw new ArsenalSerializationError(\n `hash: unsupported type ${(value as { constructor?: { name?: string } }).constructor?.name ?? 'unknown'}`,\n );\n }\n\n return String(value);\n }\n\n const rec = value as Record<string, unknown>;\n const keys = Object.keys(rec)\n .filter((k) => rec[k] !== undefined)\n .sort();\n\n return `{${keys.map((k) => `${JSON.stringify(k)}:${_hash(rec[k], options, visited)}`).join(',')}}`;\n}\n\nexport function hash(value: unknown, options?: HashOptions): string {\n return _hash(value, options, new Set<object>());\n}\n","/**\n * Returns a cryptographically random integer in `[0, exclusiveMax)` via `crypto.getRandomValues`.\n * Shared by `random()`, `shuffle()`, and `drawMany()` — the single source of truth for converting\n * a random `Uint32` into a bounded index.\n *\n * Module-private: underscore-prefixed file is excluded from barrel exports.\n * @internal\n */\nexport function secureRandomIndex(exclusiveMax: number): number {\n // Divide by 0x100000000 (not 0xffffffff) to produce [0, 1) instead of [0, 1]\n const randomValue = crypto.getRandomValues(new Uint32Array(1))[0]! / 0x100000000;\n\n return Math.floor(randomValue * exclusiveMax);\n}\n","import { secureRandomIndex } from '../_common/_secureRandomIndex';\nimport { ArsenalValidationError } from '../errors';\n\n/**\n * Generates a random integer between two values, inclusive.\n *\n * @example\n * ```ts\n * random(1, 10); // a random integer between 1 and 10\n * ```\n *\n * @param min - The minimum value.\n * @param max - The maximum value.\n * @returns A random integer between min and max.\n */\nexport function random(min: number, max: number): number {\n if (min > max) throw new ArsenalValidationError('random: minimum value must not be greater than maximum value');\n\n return secureRandomIndex(max - min + 1) + min;\n}\n","import { secureRandomIndex } from '../_common/_secureRandomIndex';\nimport { random } from './random';\n\n/**\n * Picks a single random item from an array.\n * Returns `undefined` if the array is empty.\n *\n * @example\n * ```ts\n * draw([1, 2, 3]); // e.g. 2\n * draw([]); // undefined\n * ```\n */\nexport function draw<T>(array: T[]): T | undefined {\n if (array.length === 0) return undefined;\n\n return array[random(0, array.length - 1)];\n}\n\n/**\n * Picks up to `n` unique random items from an array using a cryptographically\n * random shuffle (Fisher-Yates via `crypto.getRandomValues`).\n * Returns a new array; does not mutate the input.\n *\n * @example\n * ```ts\n * drawMany([1, 2, 3, 4, 5], 3); // e.g. [4, 1, 3]\n * drawMany([1, 2], 10); // [1, 2] (clamped to array length)\n * ```\n */\nexport function drawMany<T>(array: T[], n: number): T[] {\n const count = Math.max(0, Math.min(array.length, Math.floor(n)));\n\n if (count === 0) return [];\n\n if (count === array.length) return [...array];\n\n const copy = [...array];\n\n for (let index = copy.length - 1; index > 0; index--) {\n const randomIndex = secureRandomIndex(index + 1);\n const temp = copy[index];\n\n copy[index] = copy[randomIndex]!;\n copy[randomIndex] = temp!;\n }\n\n return copy.slice(0, count);\n}\n","import { secureRandomIndex } from '../_common/_secureRandomIndex';\n\n/**\n * Returns a new randomly-shuffled copy of the array using Fisher-Yates\n * with `crypto.getRandomValues`. Does not mutate the input.\n *\n * @example\n * ```ts\n * const arr = [1, 2, 3, 4];\n * shuffle(arr); // e.g. [3, 1, 4, 2]\n * ```\n */\nexport function shuffle<T>(array: T[]): T[] {\n const result = [...array];\n\n for (let i = result.length - 1; i > 0; i--) {\n const j = secureRandomIndex(i + 1);\n\n [result[i], result[j]] = [result[j], result[i]];\n }\n\n return result;\n}\n","/**\n * Generates a unique identifier.\n *\n * @example\n * ```ts\n * uuid(); // a unique identifier, e.g., '22a746d0-08be-4aff-bbc2-4deddf0914e0'\n * ```\n *\n * @returns A unique identifier.\n */\nexport function uuid(): string {\n return crypto.randomUUID();\n}\n","/**\n * Shared regex pattern for splitting words in case conversion utilities.\n * Module-private (underscore-prefixed file is not barrel-exported).\n * Used only with String.prototype.replace — which always resets lastIndex.\n * Uses Unicode property escapes (`\\p{Ll}`/`\\p{Lu}`/`\\p{N}`) instead of `[a-z]`/`[A-Z]` so\n * accented and non-Latin letters (e.g. `café`, `日本語`) are treated as letters, not stripped.\n */\nconst CASE_SPLIT_PATTERN = /(\\p{Ll})(\\p{Lu}|\\p{N})|(\\p{Lu}|\\p{N})(\\p{Lu}\\p{Ll})|(\\p{N})(\\p{L})/gu;\n\n/** Escapes all regex metacharacters in a string (per MDN spec). */\nfunction escapeRegex(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\/-]/g, '\\\\$&');\n}\n\n/**\n * Normalizes a string by splitting on word boundaries and removing special characters\n *\n * @param str - The string to normalize\n * @param separator - The separator to use for splitting (default: space)\n * @returns The normalized string\n */\nexport function normalizeCase(str: string, separator = ' '): string {\n const escapedSep = escapeRegex(separator);\n\n return str\n .trim()\n .replace(CASE_SPLIT_PATTERN, `$1$3$5${separator}$2$4$6`)\n .replace(/[^\\p{L}\\p{N}]+/gu, separator)\n .replace(new RegExp(`^(?:${escapedSep})+|(?:${escapedSep})+$`, 'g'), '');\n}\n","import { normalizeCase } from './_caseUtils';\n\n/**\n * Converts a string to camel case.\n *\n * @example\n * ```ts\n * const text = 'hello world';\n * camelCase(text); // 'helloWorld'\n * ```\n *\n * @param str - The string to convert.\n * @returns The converted string.\n */\nexport function camelCase(str: string): string {\n return normalizeCase(str, ' ')\n .replace(/[^\\p{L}\\p{N}]+(.)/gu, (_, char) => char.toUpperCase())\n .replace(/^./, (char) => char.toLowerCase());\n}\n","/**\n * Type-safe endsWith wrapper.\n */\nexport function endsWith<S extends string>(value: string, suffix: S): value is `${string}${S}` {\n return value.endsWith(suffix);\n}\n","const escapeMap: Record<string, string> = {\n \"'\": ''',\n '\"': '"',\n '&': '&',\n '<': '<',\n '>': '>',\n};\n\n/**\n * Escapes HTML entities.\n */\nexport function escape(value: string): string {\n return value.replace(/[&<>\"']/g, (char) => escapeMap[char]);\n}\n","import { normalizeCase } from './_caseUtils';\n\n/**\n * Converts a string to kebab case.\n *\n * @example\n * ```ts\n * const text = 'Hello World';\n * kebabCase(text); // 'hello-world'\n * ```\n *\n * @param str - The string to convert.\n *\n * @returns The converted string.\n */\nexport function kebabCase(str: string): string {\n return normalizeCase(str, '-').toLowerCase();\n}\n","/**\n * Pads a string on both sides to reach the target length.\n */\nexport function pad(str: string, targetLength: number, fillString = ' '): string {\n if (targetLength <= str.length) return str;\n\n const total = targetLength - str.length;\n const left = Math.floor(total / 2);\n\n return str.padStart(str.length + left, fillString).padEnd(targetLength, fillString);\n}\n","import { normalizeCase } from './_caseUtils';\n\n/**\n * Converts a string to Pascal case.\n *\n * @example\n * ```ts\n * const text = 'Hello World';\n * pascalCase(text) // 'HelloWorld';\n * ```\n *\n * @param str - The string to convert.\n *\n * @returns The converted string.\n */\nexport function pascalCase(str: string): string {\n return normalizeCase(str, ' ')\n .replace(/(?:^|\\s)(\\p{L}|\\p{N})/gu, (_, char) => char.toUpperCase())\n .replace(/\\s+/g, '');\n}\n","import { normalizeCase } from './_caseUtils';\n\n/**\n * Converts a string to snake case.\n *\n * @example\n * ```ts\n * const text = 'Hello World';\n * snakeCase(text) // 'hello_world';\n * ```\n *\n * @param str - The string to convert.\n *\n * @returns The converted string.\n */\nexport function snakeCase(str: string): string {\n return normalizeCase(str, '_').toLowerCase();\n}\n","/**\n * Type-safe startsWith wrapper.\n */\nexport function startsWith<P extends string>(value: string, prefix: P): value is `${P}${string}` {\n return value.startsWith(prefix);\n}\n","import { normalizeCase } from './_caseUtils';\n\n/**\n * Splits a string into normalized words.\n */\nexport function words(str: string): string[] {\n const normalized = normalizeCase(str, ' ');\n\n if (!normalized) return [];\n\n return normalized.split(' ').filter(Boolean);\n}\n","import { words } from './words';\n\n/**\n * Converts a string to title case.\n */\nexport function titleCase(str: string): string {\n return words(str)\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())\n .join(' ');\n}\n","import { ArsenalValidationError } from '../errors';\n\nexport type TruncateOptions = {\n completeWords?: boolean;\n ellipsis?: string;\n};\n\n/**\n * Truncates a string if it is longer than the given maximum string length. The last characters of the truncated string are replaced with the ellipsis sign \"…\".\n *\n * @example\n * ```ts\n * const text = 'Hello World';\n * truncate(text, 5); // 'Hello…'\n * truncate(text, 8, { completeWords: true }); // 'Hello…'\n * truncate(text, 5, { ellipsis: '...' }); // 'Hello...'\n * ```\n *\n * @param str - The string to truncate.\n * @param limit - The maximum string length.\n * @param options - Options for truncation.\n * @param [options.completeWords] - If true, truncate to the nearest word boundary.\n * @param [options.ellipsis] - Suffix appended after truncation (default: '…').\n *\n * @returns The truncated string.\n *\n * @throws {ArsenalValidationError} If str is not a string or limit is not a non-negative finite number.\n */\nexport function truncate(\n str: string,\n limit = 25,\n { completeWords = false, ellipsis = '…' }: TruncateOptions = {},\n): string {\n if (typeof str !== 'string') {\n throw new ArsenalValidationError('truncate: str must be a string');\n }\n\n if (typeof limit !== 'number' || !Number.isFinite(limit) || limit < 0) {\n throw new ArsenalValidationError('truncate: limit must be a non-negative finite number');\n }\n\n if (str.length <= limit) {\n return str;\n }\n\n let end = limit;\n\n if (completeWords) {\n const wordEnd = str.substring(0, limit).lastIndexOf(' ');\n\n if (wordEnd > 0) end = wordEnd;\n }\n\n return `${str.substring(0, end).trim()}${ellipsis}`;\n}\n","const unescapeMap: Record<string, string> = {\n ''': \"'\",\n '&': '&',\n '>': '>',\n '<': '<',\n '"': '\"',\n};\n\n/**\n * Unescapes HTML entities.\n */\nexport function unescape(value: string): string {\n return value.replace(/&(amp|lt|gt|quot|#39);/g, (entity) => unescapeMap[entity] ?? entity);\n}\n"],"mappings":"mEACA,IAAa,EAAb,MAAa,UAAqB,KAAM,CACtC,YAAY,EAAiB,EAAqB,CAChD,MAAM,EAAS,CAAI,EACnB,KAAK,KAAO,IAAI,OAAO,KACvB,OAAO,eAAe,KAAM,IAAI,OAAO,SAAS,CAClD,CAEA,OAAO,GAAG,EAAmC,CAC3C,OAAO,aAAe,CACxB,CACF,EAOa,EAAb,cAA4C,CAAa,CAAC,EAO7C,EAAb,cAA+C,CAAa,CAAC,ECZ7D,SAAgB,EAAS,EAA6B,CACpD,OAAO,OAAO,GAAQ,QACxB,CCMA,SAAgB,EAAS,EAAqB,EAAO,EAAqB,CACxE,GAAI,CAAC,MAAM,QAAQ,CAAK,GAAK,CAAC,EAAS,CAAK,EAC1C,MAAM,IAAI,EAAuB,4CAA4C,EAE/E,GAAI,EAAO,EAAG,MAAM,IAAI,EAAuB,gCAAgC,EAE/E,OAAO,MAAM,KAAK,CAAE,OAAQ,KAAK,KAAK,EAAM,OAAS,CAAI,CAAE,GAAI,EAAG,IAAM,EAAM,MAAM,EAAI,EAAM,EAAI,EAAO,CAAI,CAAC,CAEhH,CCxBA,SAAgB,EAAW,EAAsC,CAC/D,OAAO,EAAM,OAAO,OAAO,CAC7B,CCwBA,IAAa,GAAW,EAAY,IAAuB,CACzD,GAAI,IAAM,EAAG,MAAO,GAEpB,GAAI,IAAM,IAAA,GAAW,MAAO,GAE5B,GAAI,IAAM,IAAA,GAAW,MAAO,GAE5B,GAAI,IAAM,KAAM,OAAO,IAAM,KAAO,EAAI,GAExC,GAAI,IAAM,KAAM,MAAO,GAEvB,GAAI,OAAO,GAAM,UAAY,OAAO,GAAM,SACxC,OAAO,EAAE,cAAc,CAAC,EAG1B,GAAI,OAAO,GAAM,UAAY,OAAO,GAAM,SACxC,OAAO,IAAM,EAAI,EAAI,EAAI,EAAI,EAAI,GAGnC,GAAI,aAAa,MAAQ,aAAa,KAAM,CAC1C,IAAM,EAAK,EAAE,QAAQ,EACf,EAAK,EAAE,QAAQ,EAErB,OAAO,IAAO,EAAK,EAAI,EAAK,EAAK,EAAI,EACvC,CAEA,MAAM,IAAI,EACR,+BAA+B,OAAO,EAAE,SAAS,OAAO,EAAE,qDAC5D,CACF,ECpCa,EAAgB,GAAwD,CACnF,IAAM,EAAU,OAAO,QAAQ,CAAS,EAExC,OAAQ,EAAM,IAAS,CACrB,IAAK,GAAM,CAAC,EAAK,KAAc,EAAS,CACtC,IAAM,EAAK,EAAE,GACP,EAAK,EAAE,GACP,EAAM,IAAc,OAAS,GAAK,EAElC,EAAM,EAAQ,EAAI,CAAE,EAE1B,GAAI,IAAQ,EAAG,OAAO,EAAM,CAC9B,CAEA,MAAO,EACT,CACF,EClBA,SAAgB,EAAQ,EAAY,EAAqB,CACvD,OAAO,EAAY,EAAG,EAAG,IAAI,OAAS,CACxC,CAEA,SAAS,EAAY,EAAY,EAAY,EAA2C,CAEtF,GAAI,IAAM,EAAG,MAAO,GAGpB,GAAI,GAAK,MAAQ,GAAK,MAAQ,OAAO,GAAM,OAAO,GAAK,OAAO,GAAM,UAAY,OAAO,GAAM,SAAU,MAAO,GAI9G,GAAI,EAAQ,IAAI,CAAW,EACzB,OAAO,EAAQ,IAAI,CAAW,IAAM,EAMtC,GAHA,EAAQ,IAAI,EAAa,CAAW,EAGhC,MAAM,QAAQ,CAAC,GAAK,MAAM,QAAQ,CAAC,EAGrC,MAFI,CAAC,MAAM,QAAQ,CAAC,GAAK,CAAC,MAAM,QAAQ,CAAC,GAAK,EAAE,SAAW,EAAE,OAAe,GAErE,EAAE,OAAO,EAAM,IAAQ,EAAY,EAAM,EAAE,GAAM,CAAO,CAAC,EAIlE,GAAI,aAAa,MAAQ,aAAa,KACpC,OAAO,EAAE,QAAQ,IAAM,EAAE,QAAQ,EAInC,GAAI,aAAa,KAAO,aAAa,IAAK,CACxC,GAAI,EAAE,OAAS,EAAE,KAAM,MAAO,GAE9B,IAAK,GAAM,CAAC,EAAG,KAAM,EACnB,GAAI,CAAC,EAAE,IAAI,CAAC,GAAK,CAAC,EAAY,EAAG,EAAE,IAAI,CAAC,EAAG,CAAO,EAAG,MAAO,GAG9D,MAAO,EACT,CAGA,GAAI,aAAa,KAAO,aAAa,IAAK,CACxC,GAAI,EAAE,OAAS,EAAE,KAAM,MAAO,GAE9B,IAAM,EAAS,CAAC,GAAG,CAAC,EAEpB,IAAK,IAAM,KAAK,EAEd,GAAI,OAAO,GAAM,UAAY,OAAO,GAAM,UAAY,OAAO,GAAM,WAAa,GAAM,SAChF,CAAC,EAAE,IAAI,CAAC,EAAG,MAAO,EAAA,MACjB,GAAI,CAAC,EAAO,KAAM,GAAO,EAAY,EAAG,EAAI,CAAO,CAAC,EACzD,MAAO,GAIX,MAAO,EACT,CAGA,GAAI,aAAa,QAAU,aAAa,OACtC,OAAO,aAAa,QAAU,aAAa,QAAU,EAAE,SAAW,EAAE,QAAU,EAAE,QAAU,EAAE,MAM9F,GAFI,aAAa,KAAO,aAAa,KAEjC,aAAa,KAAO,aAAa,IAAK,MAAO,GAGjD,IAAM,EAAQ,OAAO,KAAK,CAAC,EACrB,EAAQ,OAAO,KAAK,CAAC,EAE3B,GAAI,EAAM,SAAW,EAAM,OAAQ,MAAO,GAE1C,IAAK,IAAM,KAAO,EAChB,GACE,CAAC,OAAO,OAAO,EAAG,CAAG,GACrB,CAAC,EAAa,EAA8B,GAAO,EAA8B,GAAM,CAAO,EAE9F,MAAO,GAGX,MAAO,EACT,CCzFA,SAAgB,EAAY,EAAY,EAAyB,CAO/D,OAJ6C,OAAO,GAAU,WAA1D,EACK,EAAM,SAAS,CAAU,EAG3B,EAAM,KAAM,GAAQ,EAAQ,EAAK,CAAK,CAAC,CAChD,CCrBA,IAAa,EAAuB,IAAI,IAAI,CAAC,YAAa,cAAe,WAAW,CAAC,EA4BrF,SAAgB,EAAY,EAA2B,CACrD,OAAO,OAAO,GAAQ,UAAY,EAAqB,IAAI,CAAG,CAChE,CC1BA,SAAgB,EAAW,EAAY,EAA0D,CAC/F,IAAM,EAA8B,CAAC,EAErC,IAAK,IAAI,EAAQ,EAAG,EAAQ,EAAM,OAAQ,IAAS,CACjD,IAAM,EAAS,EAAS,EAAM,EAAM,EAC9B,EAAM,GAAmC,KAAO,IAAM,OAAO,CAAM,EAErE,EAAY,CAAG,IAEnB,EAAI,IAAQ,EAAI,IAAQ,GAAK,EAC/B,CAEA,OAAO,CACT,CCbA,SAAgB,EAAiB,EAAqB,EAAkD,CACtG,OAAO,IAAI,IAAI,EAAM,IAAK,GAAS,EAAS,CAAI,CAAC,CAAC,CACpD,CASA,SAAgB,EAAoB,EAAqB,EAAuC,CAC9F,IAAM,EAAO,IAAI,IACX,EAAW,CAAC,EAElB,IAAK,IAAM,KAAQ,EAAO,CACxB,IAAM,EAAM,EAAS,CAAI,EAErB,EAAK,IAAI,CAAG,IAEhB,EAAK,IAAI,CAAG,EACZ,EAAI,KAAK,CAAI,EACf,CAEA,OAAO,CACT,CC3BA,SAAgB,EAAc,EAAa,EAAY,EAAwC,CAC7F,GAAI,CAAC,EAAU,CACb,IAAM,EAAO,IAAI,IAAI,CAAK,EAE1B,OAAO,EAAO,OAAQ,GAAS,CAAC,EAAK,IAAI,CAAI,CAAC,CAChD,CAEA,IAAM,EAAO,EAAc,EAAO,CAAQ,EAE1C,OAAO,EAAO,OAAQ,GAAS,CAAC,EAAK,IAAI,EAAS,CAAI,CAAC,CAAC,CAC1D,CCdA,SAAgB,EAAQ,EAAY,EAAI,EAAQ,CAC9C,IAAM,EAAQ,KAAK,IAAI,EAAG,KAAK,MAAM,CAAC,CAAC,EAEvC,OAAO,EAAM,MAAM,CAAK,CAC1B,CCJA,SAAgB,EAAY,EAAY,EAAI,EAAQ,CAClD,IAAM,EAAQ,KAAK,IAAI,EAAG,KAAK,MAAM,CAAC,CAAC,EAIvC,OAFI,IAAU,EAAU,CAAC,GAAG,CAAK,EAE1B,EAAM,MAAM,EAAG,KAAK,IAAI,EAAG,EAAM,OAAS,CAAK,CAAC,CACzD,CCNA,SAAgB,EAAgB,EAAY,EAAsE,CAChH,IAAM,EAAc,CAAC,EAErB,IAAK,IAAI,EAAQ,EAAG,EAAQ,EAAM,OAAQ,IAAS,CACjD,IAAM,EAAQ,EAAS,EAAM,GAAQ,EAAO,CAAK,EAE7C,IAAU,IAAA,IACZ,EAAO,KAAK,CAAK,CAErB,CAEA,OAAO,CACT,CCZA,SAAgB,EAAS,EAAY,EAA6B,CAChE,OAAO,EAAM,OAAS,EAAI,EAAM,GAAK,CACvC,CCFA,SAAgB,EAAW,EAAkB,EAAQ,EAAQ,CAC3D,GAAI,EAAQ,EAAG,MAAO,CAAC,GAAG,CAAK,EAE/B,IAAM,EAAiB,CAAC,EAExB,IAAK,IAAM,KAAQ,EACb,MAAM,QAAQ,CAAI,EACpB,EAAI,KAAK,GAAG,EAAQ,EAAM,EAAQ,CAAC,CAAC,EAEpC,EAAI,KAAK,CAAI,EAIjB,OAAO,CACT,CCTA,SAAgB,EAAW,EAAY,EAAuD,CAC5F,IAAM,EAA8B,CAAC,EAErC,IAAK,IAAM,KAAQ,EAAO,CACxB,IAAM,EAAS,EAAS,CAAI,EACtB,EAAM,GAAmC,KAAO,IAAM,OAAO,CAAM,EAErE,EAAY,CAAG,IAEd,EAAO,KACV,EAAO,GAAO,CAAC,GAGjB,EAAO,EAAI,CAAC,KAAK,CAAI,EACvB,CAEA,OAAO,CACT,CCjBA,SAAgB,GAAW,EAAY,EAAqD,CAC1F,IAAM,EAA4B,CAAC,EAEnC,IAAK,IAAM,KAAQ,EAAO,CACxB,IAAM,EAAM,OAAO,EAAS,CAAI,CAAC,EAE7B,EAAY,CAAG,IAEnB,EAAO,GAAO,EAChB,CAEA,OAAO,CACT,CCbA,SAAgB,GAAgB,EAAa,EAAY,EAAwC,CAC/F,GAAI,CAAC,EAAU,CACb,IAAM,EAAQ,IAAI,IAAI,CAAK,EAE3B,OAAO,EAAO,OAAQ,GAAS,EAAM,IAAI,CAAI,CAAC,CAChD,CAEA,IAAM,EAAQ,EAAc,EAAO,CAAQ,EAE3C,OAAO,EAAO,OAAQ,GAAS,EAAM,IAAI,EAAS,CAAI,CAAC,CAAC,CAC1D,CCdA,SAAgB,GAAQ,EAAY,EAA6B,CAC/D,OAAO,EAAM,OAAS,EAAI,EAAM,EAAM,OAAS,GAAK,CACtD,CCFA,SAAgB,GAAa,EAAY,EAAwE,CAC/G,IAAM,EAAgB,CAAC,EACjB,EAAgB,CAAC,EAEvB,IAAK,IAAI,EAAQ,EAAG,EAAQ,EAAM,OAAQ,IACpC,EAAU,EAAM,GAAQ,EAAO,CAAK,EACtC,EAAS,KAAK,EAAM,EAAM,EAE1B,EAAS,KAAK,EAAM,EAAM,EAI9B,MAAO,CAAC,EAAU,CAAQ,CAC5B,CCCA,SAAgB,GAAW,EAAY,EAAyB,EAAe,CAC7E,IAAM,EAAQ,EAAM,UAAU,CAAS,EAIvC,OAFI,IAAU,GAAW,EAElB,CAAC,GAAG,EAAM,MAAM,EAAG,CAAK,EAAG,EAAO,GAAG,EAAM,MAAM,EAAQ,CAAC,CAAC,CACpE,CCPA,SAAgB,GAAU,EAAY,EAAmB,CAAE,OAAO,IAA8B,CAAC,EAAQ,CACvG,GAAI,EAAM,SAAW,EAAG,OAAO,EAE/B,IAAM,GAAkB,EAAY,EAAM,OAAU,EAAM,QAAU,EAAM,OACpE,EAAU,EAAM,MAAM,CAAa,EAEzC,OAAO,EAAO,CAAC,GAAG,EAAS,GAAG,EAAM,MAAM,EAAG,CAAa,CAAC,EAAI,CACjE,CCRA,SAAgB,EAAM,EAAuC,CAC3D,OAAO,GAA6B,IACtC,CCJA,SAAgB,EAAS,EAA6B,CACpD,OAAO,OAAO,GAAQ,UAAY,CAAC,OAAO,MAAM,CAAG,CACrD,CCOA,IAAM,EAAwB,IAE9B,SAAgB,EAAW,EAAc,EAAsB,CAC7D,GAAI,EAAK,OAAS,GAAyB,EAAK,OAAS,EACvD,MAAM,IAAI,EACR,6CAA6C,EAAsB,8CACrE,EAGF,IAAM,EAAI,EAAK,YAAY,EACrB,EAAI,EAAK,YAAY,EAE3B,GAAI,IAAM,EAAG,MAAO,GAEpB,GAAI,EAAE,SAAW,EAAG,MAAO,IAAE,SAAW,GAExC,GAAI,EAAE,SAAW,EAAG,MAAO,GAG3B,GAAM,CAAC,EAAS,GAAU,EAAE,OAAS,EAAE,OAAS,CAAC,EAAG,CAAC,EAAI,CAAC,EAAG,CAAC,EACxD,EAAgB,EAAQ,OACxB,EAAe,EAAO,OAExB,EAAU,MAAM,KAAK,CAAE,OAAQ,EAAgB,CAAE,GAAI,EAAG,IAAM,CAAC,EAC/D,EAAc,MAAM,EAAgB,CAAC,EAEzC,IAAK,IAAI,EAAI,EAAG,GAAK,EAAc,IAAK,CACtC,EAAQ,GAAK,EACb,IAAK,IAAI,EAAI,EAAG,GAAK,EAAe,IAAK,CACvC,IAAM,EAAO,EAAO,EAAI,KAAO,EAAQ,EAAI,GAAK,EAAI,EAEpD,EAAQ,GAAK,KAAK,IAChB,EAAQ,EAAI,GAAK,EACjB,EAAQ,GAAK,EACb,EAAQ,EAAI,GAAK,CACnB,CACF,CAEA,CAAC,EAAS,GAAW,CAAC,EAAS,CAAO,CACxC,CAKA,MAAO,GAFU,EAAQ,GAEH,KAAK,IAAI,EAAE,OAAQ,EAAE,MAAM,CACnD,CC5CA,IAAM,GAAyB,GAMzB,GAAsB,IAG5B,SAAS,EAAgB,EAAsC,CAC7D,GAAI,IAAa,IAAA,GAAW,OAAO,GAEnC,GAAI,CAAC,OAAO,UAAU,CAAQ,GAAK,EAAW,EAC5C,MAAM,IAAI,EAAuB,uDAAuD,GAAU,EAGpG,OAAO,KAAK,IAAI,EAAU,EAAmB,CAC/C,CAEA,IAAM,EAAgB,GAAsB,EAAE,UAAU,MAAM,CAAC,CAAC,QAAQ,UAAW,EAAE,EAErF,SAAS,EAAU,EAAe,EAAe,EAAoB,EAAkB,EAAQ,EAAW,CAuBxG,OAtBI,EAAQ,GAER,EAAM,CAAI,EAAU,EAEpB,EAAS,CAAI,GAAK,EAAS,CAAI,EAG1B,EAFG,EAAY,EAAa,OAAO,CAAI,CAAC,EAAI,OAAO,CAAI,EAEzC,CAAK,EAGxB,MAAM,QAAQ,CAAI,EACZ,EAAmB,QACxB,EAAK,IAAM,KAAK,IAAI,EAAK,EAAU,EAAG,EAAO,EAAW,EAAU,EAAQ,CAAC,CAAC,EAC7E,CACF,EAEE,OAAO,GAAS,SACX,OAAO,OAAO,CAA+B,CAAC,CAAC,QACnD,EAAK,IAAM,KAAK,IAAI,EAAK,EAAU,EAAG,EAAO,EAAW,EAAU,EAAQ,CAAC,CAAC,EAC7E,CACF,EAEK,CACT,CAEA,SAAS,EAAU,EAAe,EAAe,EAAmB,EAAoB,EAA2B,CACjH,OAAO,EAAU,EAAM,EAAO,EAAW,CAAQ,GAAK,CACxD,CAyBA,SAAgB,EAAe,EAAY,EAAe,EAA2B,CAAC,EAAQ,CAC5F,GAAM,CAAE,SAAQ,YAAY,GAAO,YAAY,KAAS,EAClD,EAAW,EAAgB,EAAQ,QAAQ,EAEjD,GAAI,CAAC,EAAO,MAAO,CAAC,GAAG,CAAK,EAE5B,IAAM,EAAM,EAAM,KAAK,CAAC,CAAC,YAAY,EAErC,GAAI,CAAC,EAAK,MAAO,CAAC,GAAG,CAAK,EAE1B,IAAM,EAAa,EAAY,EAAa,CAAG,EAAI,EAEnD,OAAO,EAAM,OAAQ,GACf,GAAU,EAAO,OAAS,GAAK,OAAO,GAAS,UAAY,EACtD,EAAO,KAAM,GAClB,EAAW,EAAiC,GAAQ,EAAY,EAAW,EAAW,CAAQ,CAChG,EAGK,EAAU,EAAM,EAAY,EAAW,EAAW,CAAQ,CAClE,CACH,CAyBA,SAAgB,EAAc,EAAY,EAAe,EAA2B,CAAC,EAAsB,CACzG,GAAM,CAAE,SAAQ,YAAY,GAAO,YAAY,KAAS,EAClD,EAAW,EAAgB,EAAQ,QAAQ,EAEjD,GAAI,CAAC,GAAS,CAAC,EAAM,KAAK,EACxB,OAAO,EAAM,IAAK,IAAU,CAAE,OAAM,MAAO,CAAE,EAAE,EAGjD,IAAM,EAAM,EAAM,KAAK,CAAC,CAAC,YAAY,EAC/B,EAAa,EAAY,EAAa,CAAG,EAAI,EAenD,OAbe,EAAM,IAAK,IAUjB,CAAE,OAAM,MARb,GAAU,EAAO,OAAS,GAAK,OAAO,GAAS,UAAY,EACvD,EAAO,QACJ,EAAK,IACJ,KAAK,IAAI,EAAK,EAAW,EAAiC,GAAQ,EAAY,EAAW,CAAQ,CAAC,EACpG,CACF,EACA,EAAU,EAAM,EAAY,EAAW,CAAQ,CAEhC,EAGhB,CAAA,CAAO,QAAQ,CAAE,WAAY,GAAS,CAAS,CAAC,CAAC,MAAM,EAAG,IAAM,EAAE,MAAQ,EAAE,KAAK,CAC1F,CAiBA,SAAgB,GACd,EACA,EACA,EAAkD,CAAC,EAC1B,CACzB,GAAM,CAAE,SAAQ,GAAG,GAAS,EAE5B,OAAO,EAAS,EAAW,EAAO,EAAO,CAAI,EAAI,EAAY,EAAO,EAAO,CAAI,CACjF,CCnKA,SAAgB,GACd,EACA,EACA,EAA2B,MACtB,CACL,GAAI,CAAC,MAAM,QAAQ,CAAK,EAAG,MAAM,IAAI,EAAuB,uCAAuC,EAEnG,GAAI,OAAO,GAAwB,WAAY,CAC7C,IAAM,EAAa,IAAc,OAAS,GAAK,EAE/C,MAAO,CAAC,GAAG,CAAK,CAAC,CAAC,MAAM,EAAG,IAAM,EAAQ,EAAoB,CAAC,EAAG,EAAoB,CAAC,CAAC,EAAI,CAAU,CACvG,CAEA,MAAO,CAAC,GAAG,CAAK,CAAC,CAAC,KAAK,EAAU,CAAmB,CAAC,CACvD,CCzCA,SAAgB,GAAQ,EAAY,EAAI,EAAQ,CAC9C,IAAM,EAAQ,KAAK,IAAI,EAAG,KAAK,MAAM,CAAC,CAAC,EAEvC,OAAO,EAAM,MAAM,EAAG,CAAK,CAC7B,CCJA,SAAgB,GAAY,EAAY,EAAI,EAAQ,CAClD,IAAM,EAAQ,KAAK,IAAI,EAAG,KAAK,MAAM,CAAC,CAAC,EAIvC,OAFI,IAAU,EAAU,CAAC,EAElB,EAAM,MAAM,KAAK,IAAI,EAAG,EAAM,OAAS,CAAK,CAAC,CACtD,CCiBA,SAAgB,GACd,EACA,EACA,EACA,EAA+C,CAAC,EAC3C,CACL,GAAM,CAAE,WAAW,UAAa,EAC1B,EAAY,EAAY,GAAU,EAAS,CAAE,IAAM,EAAS,CAAI,EAAK,GAAU,IAAO,EAEtF,EAAQ,EAAM,UAAU,CAAS,EAMvC,OAJI,IAAU,GAIP,IAAa,UAAY,CAAC,EAAM,GAAG,CAAK,EAAI,CAAC,GAAG,EAAO,CAAI,EAHzD,CAAC,GAAG,EAAM,MAAM,EAAG,CAAK,EAAG,GAAG,EAAM,MAAM,EAAQ,CAAC,CAAC,CAI/D,CCnCA,SAAgB,GAAS,EAAa,EAAY,EAAwC,CAKxF,OAJK,EAIE,EAAiB,CAAC,GAAG,EAAQ,GAAG,CAAK,EAAG,CAAQ,EAH9C,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,EAAQ,GAAG,CAAK,CAAC,CAAC,CAI7C,CCMA,SAAgB,GAAQ,EAAY,EAAwC,CAS1E,OARI,EAAM,QAAU,EACX,CAAC,GAAG,CAAK,EAGb,EAIE,EAAiB,EAAO,CAAQ,EAH9B,CAAC,GAAG,IAAI,IAAI,CAAK,CAAC,CAI7B,CC1BA,SAAgB,GAAoC,EAAqD,CACvG,GAAI,EAAK,SAAW,EAAG,MAAO,CAAC,EAE/B,IAAM,EAAQ,EAAK,EAAE,CAAC,OAChB,EAAM,MAAM,KAAK,CAAE,OAAQ,CAAM,MAAS,CAAC,CAAc,EAE/D,IAAK,IAAM,KAAO,EAChB,IAAK,IAAI,EAAQ,EAAG,EAAQ,EAAO,IACjC,EAAI,EAAM,CAAC,KAAK,EAAI,EAAM,EAI9B,OAAO,CACT,CCbA,SAAgB,GACd,GAAG,EACmF,CACtF,GAAI,EAAO,SAAW,EAAG,MAAO,CAAC,EAEjC,IAAM,EAAS,KAAK,IAAI,GAAG,EAAO,IAAK,GAAQ,EAAI,MAAM,CAAC,EACpD,EAAU,MAAM,CAAM,EAE5B,IAAK,IAAI,EAAQ,EAAG,EAAQ,EAAQ,IAClC,EAAI,GAAS,EAAO,IAAK,GAAU,EAAM,EAAM,EAGjD,OAAO,CACT,CCKA,SAAgB,EAAW,EAA+B,CACxD,OAAO,GAAQ,QAAU,IAAI,aAAa,UAAW,YAAY,CACnE,CCTA,SAAgB,GAAQ,EAA4D,CAClF,OAAO,EAAO,KAAO,EACvB,CAWA,SAAgB,GAAU,EAAmE,CAC3F,OAAO,EAAO,KAAO,EACvB,CA4BA,SAAgB,GAAW,EAAwE,CACjG,GAAI,CACF,IAAM,EAAS,EAAG,EASlB,OAPI,OAAQ,GAA2B,MAAS,WACtC,EAAsB,KAC3B,IAAW,CAAE,GAAI,GAAe,OAAM,GACtC,IAAW,CAAE,QAAO,GAAI,EAAe,EAC1C,EAGK,CAAE,GAAI,GAAM,MAAO,CAAY,CACxC,OAAS,EAAO,CACd,MAAO,CAAE,QAAO,GAAI,EAAM,CAC5B,CACF,CCtDA,SAAgB,GAAQ,EAAiB,EAAQ,IAAgB,CAC/D,IAAM,EAAI,KAAK,IAAI,EAAG,OAAO,MAAM,CAAO,EAAI,EAAI,KAAK,MAAM,CAAO,CAAC,EAErE,OAAO,KAAK,IAAI,KAAQ,GAAK,GAAK,GAAK,EAAa,GAAG,GAAK,CAAK,CACnE,CCiBA,eAAsB,GACpB,EACA,EACA,EAA4E,CAAC,EAC/D,CACd,GAAM,CAAE,eAAe,GAAO,QAAQ,IAAU,UAAW,EAE3D,GAAI,EAAQ,EACV,MAAM,IAAI,EAAuB,2CAA2C,GAAO,EAGrF,GAAI,GAAQ,QACV,MAAM,EAAW,CAAM,EAGzB,GAAI,EAAM,SAAW,EACnB,MAAO,CAAC,EAGV,IAAM,EAAmB,MAAM,EAAM,MAAM,EACvC,EAAe,EACb,EAAqB,EAAe,IAAI,gBAAoB,IAAA,GAE5D,EAAS,SAA2B,CACxC,OAAa,CACX,GAAI,GAAQ,QACV,MAAM,EAAW,CAAM,EAOzB,GAJI,GAAoB,OAAO,SAI3B,GAAgB,EAAM,OACxB,OAGF,IAAM,EAAQ,IAEd,GAAI,CACF,EAAQ,GAAS,MAAM,EAAS,EAAM,GAAS,EAAO,CAAK,CAC7D,OAAS,EAAK,CAEZ,MADA,GAAoB,MAAM,EACpB,CACR,CACF,CACF,EAEM,EAAc,KAAK,IAAI,EAAO,EAAM,MAAM,EAC1C,EAAU,MAAM,KAAK,CAAE,OAAQ,CAAY,MAAS,EAAO,CAAC,EAIlE,OAFA,MAAM,QAAQ,IAAI,CAAO,EAElB,CACT,CCpDA,SAAgB,GAAM,EAAoC,CAAC,EAAU,CACnE,GAAM,CAAE,cAAc,GAAM,EAE5B,GAAI,EAAc,EAAG,MAAM,IAAI,EAAuB,gCAAgC,EAEtF,IAAI,EAAc,EACd,EAAa,GACb,EAAoC,KACpC,EAAmC,KAEjC,EAKD,CAAC,EAEA,EAAmB,IAAI,IAEvB,MAA0B,CAC1B,IAAgB,GAAK,EAAM,SAAW,GAAK,IAC7C,EAAY,EACZ,EAAc,KACd,EAAc,KAElB,EAEM,EAAiB,GAAyC,CAC9D,IAAK,IAAM,KAAM,EACf,EAAG,CAAM,CAEb,EAEM,MAAoB,CACpB,MAMJ,KAFA,EAAa,GAEN,EAAc,GAAe,EAAM,OAAS,GAAG,CACpD,IAAM,EAAO,EAAM,MAAM,EAEzB,IAEA,QAAa,QAAQ,CAAC,CACnB,SAAW,EAAK,GAAG,CAAC,CAAC,CACrB,KAAM,GAAM,CACX,EAAc,CAAE,GAAI,GAAM,MAAO,CAAE,CAAC,EACpC,EAAK,QAAQ,CAAC,CAChB,CAAC,CAAC,CACD,MAAO,GAAe,CACrB,EAAc,CAAE,MAAO,EAAG,GAAI,EAAM,CAAC,EACrC,EAAK,OAAO,CAAC,CACf,CAAC,CAAC,CACD,YAAc,CACb,IACA,EAAM,EACN,EAAY,CACd,CAAC,CACL,CAEA,EAAa,GACb,EAAY,CAHZ,CAIF,EAEA,MAAO,CAIL,IAAI,QAAiB,CACnB,OAAO,CACT,EAUA,KAAS,EAAsB,IAAgD,CAC7E,GAAM,CAAE,UAAS,SAAQ,WAAY,QAAQ,cAAiB,EACxD,EAAW,GAAS,UAAY,EAEhC,EAAO,CACP,KACJ,WACA,SACS,SACX,EAEI,EAAI,EAAM,OAEd,KAAO,EAAI,GAAK,EAAM,EAAI,EAAE,CAAE,SAAW,GACvC,IAMF,OAHA,EAAM,OAAO,EAAG,EAAG,CAAI,EACvB,EAAM,EAEC,CACT,EAOA,MAAQ,GAA2B,CACjC,IAAM,EAAc,GAAc,MAAM,eAAe,EAEvD,IAAK,IAAM,KAAQ,EAAM,OAAO,CAAC,EAC/B,EAAK,OAAO,CAAW,EAGzB,EAAY,CACd,EAKA,WAA6B,CAC3B,GAAI,IAAgB,GAAK,EAAM,SAAW,EACxC,OAAO,QAAQ,QAAQ,EAGzB,GAAI,CAAC,EAAa,CAChB,IAAM,EAAW,QAAQ,cAAoB,EAE7C,EAAc,EAAS,QACvB,EAAc,EAAS,OACzB,CAEA,OAAO,CACT,EAyBA,UAAyB,IACvB,EAAiB,IAAI,CAA0B,MAElC,CACX,EAAiB,OAAO,CAA0B,CACpD,GAMF,IAAI,SAAkB,CACpB,OAAO,EAAM,MACf,EAKA,IAAI,MAAe,CACjB,OAAO,EAAc,EAAM,MAC7B,CACF,CACF,CC3MA,eAAsB,EAAM,EAAiB,EAAqC,CAShF,OARK,EAID,EAAO,QACF,QAAQ,OAAO,EAAW,CAAM,CAAC,EAGnC,IAAI,SAAe,EAAS,IAAW,CAC5C,IAAM,EAAK,eAAiB,CAC1B,EAAO,oBAAoB,QAAS,CAAO,EAC3C,EAAQ,CACV,EAAG,CAAO,EAEJ,MAAgB,CACpB,aAAa,CAAE,EACf,EAAO,oBAAoB,QAAS,CAAO,EAC3C,EAAO,EAAW,CAAM,CAAC,CAC3B,EAEA,EAAO,iBAAiB,QAAS,CAAO,CAC1C,CAAC,EApBQ,IAAI,QAAS,GAAY,WAAW,EAAS,CAAO,CAAC,CAqBhE,CC/BA,SAAS,GAAY,EAA6B,EAA0D,CAC1G,IAAM,EAAQ,CAAC,IAAY,IAAA,GAA2C,IAAA,GAA/B,YAAY,QAAQ,CAAO,EAAe,CAAM,CAAC,CAAC,OACtF,GAAwB,GAAK,IAChC,EAEI,KAAM,SAAW,EAIrB,OAFI,EAAM,SAAW,EAAU,EAAM,GAE9B,YAAY,IAAI,CAAK,CAC9B,CAsCA,eAAsB,GACpB,EACA,CAAE,QAAQ,IAAK,UAAS,cAAa,SAAQ,UAAS,QAAQ,GAAoB,CAAC,EACvE,CACZ,GAAI,CAAC,OAAO,UAAU,CAAK,GAAK,EAAQ,EACtC,MAAM,IAAI,EAAuB,gDAAgD,GAAO,EAG1F,IAAK,IAAI,EAAW,EAAG,GAAY,EAAO,IAAY,CACpD,GAAI,GAAQ,QAAS,MAAM,EAAW,CAAM,EAE5C,IAAM,EAAa,GAAY,EAAS,CAAM,EAE9C,GAAI,CACF,OAAO,MAAM,EAAG,CAAU,CAC5B,OAAS,EAAK,CAMZ,GALI,IAAa,GAKb,GAAe,CAAC,EAAY,EAAK,EAAW,CAAC,EAE/C,MADA,IAAU,CAAG,EACP,EAGR,IAAM,EAAK,OAAO,GAAU,WAAa,EAAM,EAAW,CAAC,EAAI,EAE3D,EAAK,GAAG,MAAM,EAAM,EAAI,CAAM,CACpC,CACF,CAIF,CC5DA,eAAsB,GACpB,EACA,CAAE,WAAW,IAAK,SAAQ,QAAS,EAAK,KAAyB,CAAC,EACnD,CACf,IAAM,EAAW,YAAY,QAAQ,CAAE,EACjC,EAAS,EAAS,YAAY,IAAI,CAAC,EAAQ,CAAQ,CAAC,EAAI,EAI9D,IAFA,EAAO,eAAe,IAET,CAGX,GAFA,EAAO,eAAe,EAElB,MAAM,EAAU,CAAM,EAAG,OAE7B,MAAM,EAAM,EAAU,CAAM,CAC9B,CACF,CC1CA,IAAa,GAAb,cAAkC,GAAU,CAC1C,QAEA,YAAY,EAAiB,CAC3B,MAAM,EACN,KAAK,QAAU,CACjB,CAEA,IAAa,EAAQ,EAAgB,CASnC,OAPI,KAAK,IAAI,CAAG,GAAG,KAAK,OAAO,CAAG,EAElC,MAAM,IAAI,EAAK,CAAK,EAGhB,KAAK,KAAO,KAAK,SAAS,KAAK,YAAY,EAExC,IACT,CAMA,YAAY,MAAgD,GAAe,CACzE,IAAK,GAAM,CAAC,EAAG,KAAM,KACnB,GAAI,EAAS,EAAG,CAAC,EAGf,OAFA,KAAK,OAAO,CAAC,EAEN,GAIX,MAAO,EACT,CACF,EC5BM,GAAqB,gBACrB,GAAe,UACf,GAA6B,gBAC7B,GAA6B,gBAC7B,GAAoB,eAEtB,GAAoB,EAClB,EAAc,IAAI,QAGxB,SAAS,GAAc,EAAgB,CACrC,IAAI,EAAK,EAAY,IAAI,CAAE,EAO3B,OALI,IAAO,IAAA,KACT,EAAK,KACL,EAAY,IAAI,EAAI,CAAE,GAGjB,CACT,CAEA,IAAM,GAAc,GAA4B,CAC9C,GAAI,CACF,OAAO,KAAK,UAAU,GAAO,EAAG,IAC1B,IAAU,IAAA,GAAkB,GAE5B,OAAO,GAAU,UAAY,OAAO,MAAM,CAAK,EAAU,GAEzD,IAAU,IAAiC,GAE3C,IAAU,KAAiC,GAE3C,OAAO,GAAU,WAAmB,GAAG,KAAoB,GAAc,CAAW,IAEjF,CACR,CACH,OAAS,EAAO,CAGd,MAAM,IAAI,EACR,yGAHa,aAAiB,OAAS,EAAM,QAAU,YAAY,EAAM,UAAY,KAIrF,CAAE,MAAO,CAAM,CACjB,CACF,CACF,EA8BA,SAAgB,GAAmB,EAAe,CAAE,MAAK,UAAU,KAA6B,CAAC,EAAgB,CAC/G,GAAI,IAAY,MAAa,CAAC,OAAO,UAAU,CAAO,GAAK,EAAU,GACnE,MAAM,IAAI,EAAuB,6DAA6D,GAAS,EAGzG,IAAM,EAAQ,IAAI,GAAmC,CAAO,EAEtD,GAAc,GAAG,IAAsC,EAAM,EAAI,GAAG,CAAI,EAAI,GAAW,CAAI,EAoB3F,EAAS,OAAO,QAlBJ,GAAG,IAAuC,CAC1D,IAAM,EAAW,EAAW,GAAG,CAAI,EAEnC,GAAI,EAAM,IAAI,CAAQ,EAAG,CACvB,IAAM,EAAS,EAAM,IAAI,CAAQ,EAIjC,OAFA,EAAM,IAAI,EAAU,CAAM,EAEnB,CACT,CAEA,IAAM,EAAQ,EAAG,GAAG,CAAI,EAIxB,OAFA,EAAM,IAAI,EAAU,CAAK,EAElB,CACT,EAEuC,CACrC,UAAa,EAAM,MAAM,EACzB,YAAa,GAAG,IAA8B,CAC5C,EAAM,OAAO,EAAW,GAAG,CAAI,CAAC,CAClC,CACF,CAAC,EAID,OAFA,OAAO,eAAe,EAAQ,OAAQ,CAAE,QAAW,EAAM,IAAK,CAAC,EAExD,CACT,CChHA,SAAgB,EAAU,EAAuC,CAC/D,OAAO,OAAO,GAAQ,YAAY,GAAgB,OAAQ,EAA2B,MAAS,UAChG,CCwGA,SAAgB,GAAqB,EAA8B,CAAC,EAAgB,CAClF,IAAM,EAAU,EAAQ,SAAW,IAEnC,GAAI,IAAY,MAAa,CAAC,OAAO,UAAU,CAAO,GAAK,EAAU,GACnE,MAAM,IAAI,EAAuB,8DAA8D,GAAS,EAG1G,IAAM,EAAQ,IAAI,IACZ,EAAW,IAAI,IACf,EAAW,IAAI,IACf,EAAO,EAAQ,OAAU,GAAW,OAAO,CAAG,GAC9C,EAAU,EAAQ,QAClB,EAAe,EAAQ,MACvB,EAAc,EAAQ,YACxB,EAAa,EACX,EAAuB,IAAI,IAEjC,SAAS,GAAkC,CACzC,GAAI,EAAM,KAAO,EAAS,CACxB,GAAM,CAAC,GAAa,EAAM,KAAK,EAE3B,IAAc,IAAA,IAChB,EAAa,CAAS,CAE1B,CACF,CAEA,SAAS,EAAe,EAAuB,CAC7C,IAAM,EAAK,EAAS,IAAI,CAAO,EAE3B,IAAO,IAAA,KACT,aAAa,CAAE,EACf,EAAS,OAAO,CAAO,EAE3B,CAEA,SAAS,EAAa,EAA0B,CAC9C,IAAM,EAAS,EAAM,IAAI,CAAO,EAWhC,OATA,EAAe,CAAO,EAElB,IACF,IAAU,EAAO,IAAK,EAAO,KAAK,EAClC,EAAM,OAAO,CAAO,GAGlB,EAAS,IAAI,CAAO,GAAG,EAAqB,IAAI,CAAO,EAEpD,IAAW,IAAA,EACpB,CAEA,SAAS,EAAiB,EAAiB,EAAuB,CAGhE,GAFA,EAAe,CAAO,EAElB,IAAY,IAA0B,OAE1C,GAAI,CAAC,OAAO,SAAS,CAAO,EAC1B,MAAM,IAAI,EAAuB,kDAAkD,EAGrF,GAAI,GAAW,EAAG,CAChB,EAAa,CAAO,EAEpB,MACF,CAEA,GAAI,CAAC,EAAM,IAAI,CAAO,EAAG,OAEzB,IAAM,EAAK,eAAiB,CAC1B,EAAS,OAAO,CAAO,EACvB,EAAa,CAAO,CACtB,EAAG,CAAO,EAEV,EAAS,IAAI,EAAS,CAAE,CAC1B,CAEA,SAAS,EAAiB,EAAW,CAGnC,OAFI,GAAe,OAAO,GAAQ,SAAiB,EAAY,YAAY,CAAG,EAEvE,CACT,CAEA,SAAS,EAAI,EAAuB,CAClC,IAAM,EAAS,EAAM,IAAI,EAAK,CAAG,CAAC,EAElC,OAAO,EAAS,EAAiB,EAAO,KAAK,EAAI,IAAA,EACnD,CAEA,SAAS,EAAI,EAAQ,EAAU,EAA8B,CAC3D,IAAM,EAAU,EAAK,CAAG,EAClB,EAAS,EAAe,EAAY,UAAU,CAAK,EAAqB,EAE9E,EAAe,CAAO,EACtB,EAAM,IAAI,EAAS,CAAE,MAAK,MAAO,CAAO,CAAC,EACzC,EAA0B,EAE1B,IAAM,EAAM,GAAM,OAAS,EAEvB,IAAQ,IAAA,IACV,EAAiB,EAAS,CAAG,CAEjC,CAEA,SAAS,EAAS,EAAQ,EAA+B,EAAwC,CAC/F,IAAM,EAAU,EAAK,CAAG,EAExB,GAAI,EAAM,IAAI,CAAO,GAAK,CAAC,GAAM,aAAc,OAAO,EAAI,CAAG,EAE7D,IAAM,EAAU,EAAS,IAAI,CAAO,EAEpC,GAAI,GAAW,CAAC,GAAM,aAAc,OAAO,EAE3C,IAAM,EAAQ,EAAQ,EAEtB,GAAI,EAAU,CAAK,EAAG,CACpB,IAAM,EAAqB,EACrB,EAAsB,EACzB,KAAM,IAGD,EAAS,IAAI,CAAO,IAAM,GAAS,EAAS,OAAO,CAAO,EAE1D,IAAe,GAAsB,CAAC,EAAqB,IAAI,CAAO,GACxE,EAAI,EAAK,EAAU,CAAI,EAGzB,EAAqB,OAAO,CAAO,EAE5B,EACR,CAAC,CACD,MAAO,GAAiB,CAIvB,MAHI,EAAS,IAAI,CAAO,IAAM,GAAS,EAAS,OAAO,CAAO,EAE9D,EAAqB,OAAO,CAAO,EAC7B,CACR,CAAC,EAIH,OAFA,EAAS,IAAI,EAAS,CAAO,EAEtB,CACT,CAIA,OAFA,EAAI,EAAK,EAAO,CAAI,EAEb,CACT,CAEA,SAAS,EAAI,EAAiB,CAC5B,OAAO,EAAa,EAAK,CAAG,CAAC,CAC/B,CAEA,SAAS,GAAc,CACrB,IACA,IAAK,IAAM,KAAM,EAAS,OAAO,EAAG,aAAa,CAAE,EAEnD,GAAI,EACF,IAAK,IAAM,KAAU,EAAM,OAAO,EAChC,EAAQ,EAAO,IAAK,EAAO,KAAK,EAIpC,EAAM,MAAM,EACZ,EAAS,MAAM,EACf,EAAS,MAAM,EACf,EAAqB,MAAM,CAC7B,CAEA,SAAU,GAAoC,CAC5C,IAAK,IAAM,KAAU,EAAM,OAAO,EAChC,KAAM,CAAC,EAAO,IAAK,EAAiB,EAAO,KAAK,CAAC,CAErD,CAEA,MAAO,CACL,QACA,OAAQ,EACR,UACA,MACU,WACV,MACA,IAAI,MAAO,CACT,OAAO,EAAM,IACf,CACF,CACF,CClSA,SAAgB,GAAO,EAAoB,EAAkB,EAA0D,CACrH,GAAI,CAAC,EAAW,MAAM,KAAK,GAAS,OAAQ,OAAO,GAAW,kBAAkB,CAClF,CCdA,SAAgB,GAAY,EAAmB,CAC7C,UAAa,CACf,CCLA,IAAM,GAAQ,CAAE,WAA8C,iBAG9D,SAAgB,GAAK,EAAmB,CAClC,IAAO,QAAQ,KAAK,uBAAuB,GAAK,CACtD,CC6BA,SAAgB,GACd,EACA,EAAQ,IACR,EAA2B,CAAE,QAAS,GAAO,SAAU,EAAK,EAC9C,CACd,IAAM,EAAU,EAAQ,SAAW,GAC7B,EAAW,EAAQ,UAAY,GAEjC,CAAC,GAAW,CAAC,GACf,GAAK,iGAAiG,EAGxG,IAAI,EACA,EACA,EACA,EAAe,GAEb,MAAmB,CACnB,IAAY,IAAA,KACd,aAAa,CAAO,EACpB,EAAU,IAAA,GAEd,EAEM,MAAuB,CAI3B,GAHA,EAAW,EACX,EAAe,GAEX,CAAC,EAAU,OAEf,IAAM,EAAO,EAKb,MAHA,GAAW,IAAA,GACX,EAAa,EAAG,GAAG,CAAI,EAEhB,CACT,EAEA,OAAO,OAAO,QACX,GAAG,KACF,EAAW,EAEP,GAAW,CAAC,IACd,EAAe,GACf,EAAa,EAAG,GAAG,CAAI,EAIvB,EAAW,IAAA,GAEP,CAAC,IAEH,EAAU,eAAiB,CACzB,EAAU,IAAA,GACV,EAAe,EACjB,EAAG,CAAK,EAED,GAKP,GAAW,CAAC,GAAY,EAAqB,GAEjD,EAAW,EACX,EAAU,WAAW,EAAgB,CAAK,EAEnC,IAET,CACE,WAAc,CACZ,EAAW,EACX,EAAW,IAAA,GACX,EAAe,EACjB,EACA,UAAwC,EAAe,EACvD,YAAe,IAAY,IAAA,EAC7B,CACF,CACF,CC9GA,SAAgB,GAAY,EAAa,CACvC,OAAO,CACT,CCyBA,IAAa,GAAsB,GAAmB,CACpD,IAAI,EACA,EAAS,GAEP,IAAc,GAAG,KACrB,AAEE,KADA,EAAS,EAAG,GAAG,CAAI,EACV,IAGJ,IAQT,MALA,GAAU,UAAc,CACtB,EAAS,IAAA,GACT,EAAS,EACX,EAEO,CACT,ECbA,SAAgB,GAAK,GAAG,EAAe,CACrC,GAAI,EAAI,SAAW,EAAG,MAAW,IAAY,EAE7C,GAAM,CAAC,EAAS,GAAG,GAAW,EAE9B,OAAQ,GAAG,IAAoB,EAAQ,QAAQ,EAAe,IAAO,EAAG,CAAI,EAAG,EAAS,GAAG,CAAI,CAAC,CAClG,CC/BA,SAAgB,GAAO,EAA8B,EAAoC,CACvF,IAAM,EAAoB,CAAC,EACrB,EAAM,EAAI,OAEhB,GAAI,GAAM,QACR,IAAK,IAAI,EAAI,EAAM,EAAG,GAAK,EAAG,IAC5B,GAAI,CACF,EAAI,EAAE,CAAE,CACV,OAAS,EAAK,CACZ,EAAO,KAAK,CAAG,CACjB,MAGF,IAAK,IAAM,KAAM,EACf,GAAI,CACF,EAAG,CACL,OAAS,EAAK,CACZ,EAAO,KAAK,CAAG,CACjB,CAIJ,GAAI,EAAO,OAAS,EAClB,MAAU,eAAe,EAAQ,8BAA8B,CAEnE,CCjCA,SAAgB,GAAO,EAAU,EAAiC,CAGhE,OAFA,EAAS,CAAK,EAEP,CACT,CCiBA,SAAgB,GACd,EACA,EAAQ,IACR,EAA2B,CAAE,QAAS,GAAM,SAAU,EAAM,EAC9C,CACd,IAAM,EAAU,EAAQ,SAAW,GAC7B,EAAW,EAAQ,UAAY,GAEjC,EACA,EAAiB,KACjB,EACA,EAEE,MAAmB,CACnB,IAAY,IAAA,KACd,aAAa,CAAO,EACpB,EAAU,IAAA,GAEd,EAEM,EAAiB,GAAoB,CACzC,EAAU,WAAW,EAAc,CAAO,CAC5C,EAEM,EAAU,GAAgB,CAI9B,GAHA,EAAiB,EACjB,EAAW,EAEP,CAAC,EAAU,OAEf,IAAM,EAAO,EAKb,MAHA,GAAW,IAAA,GACX,EAAa,EAAG,GAAG,CAAI,EAEhB,CACT,EAEM,EAAa,GAAgB,GAAS,EAAM,GAE5C,MAAqB,CACzB,IAAM,EAAM,KAAK,IAAI,EAEjB,GAAY,EAAU,CAAG,GAAK,EAEhC,EAAO,CAAG,EACD,EAET,EAAc,EAAU,CAAG,CAAC,EAE5B,EAAW,CAEf,EAEA,OAAO,OAAO,QACX,GAAG,IAAmD,CACrD,IAAM,EAAM,KAAK,IAAI,EAEjB,IAAmB,MAAa,CAAC,IAEnC,EAAiB,GAGnB,EAAW,EAEX,IAAM,EAAM,EAAU,CAAG,EAUzB,OARI,GAAO,EAEF,EAAO,CAAG,GACR,GAAY,CAAC,GAEtB,EAAc,CAAG,EAGZ,EACT,EACA,CACE,WAAc,CACZ,EAAW,EACX,EAAW,IAAA,GACX,EAAiB,IACnB,EACA,UAAwC,CACjC,KAEL,OAAO,EAAO,KAAK,IAAI,CAAC,CAC1B,EAEA,YAAe,IAAa,IAAA,IAAa,IAAY,IAAA,EACvD,CACF,CACF,CCpGA,SAAgB,GAAS,GAAG,EAA0C,CACpE,MAAQ,IAAU,EAAW,MAAO,GAAc,EAAU,CAAK,CAAC,CACpE,CAYA,SAAgB,GAAS,GAAG,EAA0C,CACpE,MAAQ,IAAU,EAAW,KAAM,GAAc,EAAU,CAAK,CAAC,CACnE,CAaA,SAAgB,GAAU,GAAG,EAA0C,CACrE,MAAQ,IAAU,EAAW,MAAO,GAAc,CAAC,EAAU,CAAK,CAAC,CACrE,CAUA,SAAgB,GAAO,EAAuC,CAC5D,MAAQ,IAAU,CAAC,EAAU,CAAK,CACpC,CC1CA,SAAgB,GAAa,EAAgC,CAC3D,OAAO,aAAiB,OAAS,EAAM,OAAS,YAClD,CCLA,SAAgB,GAAqB,EAAgB,EAAwD,CAK3G,OAJK,MAAM,QAAQ,CAAK,EAEpB,EAAkB,EAAM,MAAM,CAAS,EAEpC,GAJ2B,EAKpC,CCCA,SAAgB,GAAU,EAA8B,CACtD,OAAO,OAAO,GAAQ,SACxB,CCVA,SAAgB,GAAO,EAA2B,CAChD,OAAO,aAAe,MAAQ,CAAC,OAAO,MAAM,EAAI,QAAQ,CAAC,CAC3D,CCEA,SAAgB,GAAa,EAA8B,CACzD,OAAO,IAAQ,IAAA,EACjB,CCLA,SAAgB,EAAc,EAAkD,CAC9E,GAAqB,OAAO,GAAU,WAAlC,EAA4C,MAAO,GAEvD,IAAM,EAAY,OAAO,eAAe,CAAK,EAE7C,OAAO,IAAc,OAAO,WAAa,IAAc,IACzD,CCIA,SAAgB,EAAQ,EAAuB,CAS7C,OARI,EAAM,CAAG,GAAK,IAAQ,GAAW,GAEjC,MAAM,QAAQ,CAAG,EAAU,EAAI,SAAW,EAE1C,aAAe,KAAO,aAAe,IAAY,EAAI,OAAS,EAE9D,EAAc,CAAG,EAAU,OAAO,KAAK,CAAG,CAAC,CAAC,SAAW,EAEpD,EACT,CCrBA,SAAgB,GAAQ,EAAgC,CACtD,OAAO,aAAiB,KAC1B,CCDA,SAAgB,GAAW,EAA8C,CACvE,OAAO,OAAO,GAAQ,UACxB,CCKA,SAAgB,EAAQ,EAAiB,EAA0B,CACjE,GAAI,IAAW,EAAQ,MAAO,GAE9B,GAAI,GAAU,MAAQ,GAAU,KAAM,MAAO,GAE7C,IAAM,EAAa,MAAM,QAAQ,CAAM,EACjC,EAAa,MAAM,QAAQ,CAAM,EAEvC,GAAI,IAAe,EAAY,MAAO,GAEtC,GAAI,GAAc,EAAY,CAC5B,IAAM,EAAS,EACT,EAAS,EAIf,OAFI,EAAO,OAAS,EAAO,OAAe,GAEnC,EAAO,OAAO,EAAM,IAAM,EAAQ,EAAO,GAAI,CAAI,CAAC,CAC3D,CAEA,GAAI,OAAO,GAAW,UAAY,OAAO,GAAW,SAAU,CAG5D,GAAI,aAAkB,MAAQ,aAAkB,KAC9C,OAAO,aAAkB,MAAQ,aAAkB,MAAQ,EAAO,QAAQ,IAAM,EAAO,QAAQ,EAIjG,GAAI,aAAkB,QAAU,aAAkB,OAChD,OACE,aAAkB,QAClB,aAAkB,QAClB,EAAO,SAAW,EAAO,QACzB,EAAO,QAAU,EAAO,MAK5B,GAAI,aAAkB,KAAO,aAAkB,KAAO,aAAkB,KAAO,aAAkB,IAC/F,MAAO,GAGT,IAAK,IAAM,KAAO,OAAO,KAAK,CAAiC,EAC7D,GAAI,CAAC,EAAS,IAAqC,GAAO,EAAmC,EAAI,EAC/F,MAAO,GAIX,MAAO,EACT,CAEA,OAAO,IAAW,CACpB,CCxDA,SAAgB,GAAY,EAAgD,CAC1E,IAAM,EAAO,OAAO,EAEpB,OAAO,IAAS,UAAY,IAAS,WAAc,IAAS,UAAY,CAAC,OAAO,MAAM,CAAG,CAC3F,CCDA,SAAgB,GAAQ,EAA6B,CACnD,OAAO,aAAe,MACxB,CCMA,SAAgB,GAAa,EAAY,EAAqB,CAC5D,GAAI,OAAO,GAAG,EAAG,CAAC,EAAG,MAAO,GAE5B,GAAI,IAAM,MAAQ,IAAM,MAAQ,OAAO,GAAM,UAAY,OAAO,GAAM,SAAU,MAAO,GAEvF,IAAM,EAAW,MAAM,QAAQ,CAAC,EAC1B,EAAW,MAAM,QAAQ,CAAC,EAEhC,GAAI,IAAa,EAAU,MAAO,GAElC,GAAI,GAAY,EAAU,CACxB,GAAI,EAAE,SAAW,EAAE,OAAQ,MAAO,GAElC,IAAK,IAAI,EAAI,EAAG,EAAI,EAAE,OAAQ,IAC5B,GAAI,CAAC,OAAO,GAAG,EAAE,GAAI,EAAE,EAAE,EAAG,MAAO,GAGrC,MAAO,EACT,CAEA,IAAM,EAAQ,OAAO,KAAK,CAA4B,EAChD,EAAO,EACP,EAAO,EAEb,GAAI,EAAM,SAAW,OAAO,KAAK,CAAI,CAAC,CAAC,OAAQ,MAAO,GAEtD,IAAK,IAAM,KAAO,EAChB,GAAI,CAAC,OAAO,OAAO,EAAM,CAAG,GAAK,CAAC,OAAO,GAAG,EAAK,GAAM,EAAK,EAAI,EAAG,MAAO,GAG5E,MAAO,EACT,CC1CA,SAAgB,GAAI,EAAyC,CAK3D,OAJI,OAAO,GAAU,SACZ,EAAQ,GAAK,CAAC,EAAQ,EAGxB,KAAK,IAAI,CAAK,CACvB,CCQA,SAAgB,GAAS,EAAyB,EAAgD,CAEhG,GAAI,OAAO,GAAW,WAChB,CAAC,OAAO,UAAU,CAAM,GAAK,EAAS,GACxC,MAAM,IAAI,EAAuB,yCAAyC,GAAQ,EAItF,IAAM,EAAe,MAAM,QAAQ,CAAM,EAAI,EAAS,MAAM,CAAM,CAAC,CAAC,KAAK,CAAC,EAE1E,GAAI,EAAa,SAAW,EAC1B,MAAM,IAAI,EAAuB,8BAA8B,EAGjE,GAAI,EAAa,KAAM,GAAM,EAAI,CAAC,EAChC,MAAM,IAAI,EAAuB,6BAA6B,EAGhE,IAAM,EAAa,EAAa,QAAQ,EAAK,IAAU,EAAM,EAAO,CAAC,EAErE,GAAI,IAAe,EACjB,MAAM,IAAI,EAAuB,4BAA4B,EAG/D,GAAI,OAAO,GAAW,SAAU,CAC9B,IAAM,EAAmB,OAAO,CAAU,EACpC,EAAU,MAAM,KACpB,CAAE,OAAQ,EAAa,OAAS,CAAE,GACjC,EAAG,IAAO,EAAS,OAAO,EAAa,EAAE,EAAK,CACjD,EAIA,OAFA,EAAQ,KAAK,EAAS,EAAQ,QAAQ,EAAG,IAAM,EAAI,EAAG,EAAE,CAAC,EAElD,CACT,CAGA,IAAM,EAAU,MAAM,KAAK,CAAE,OAAQ,EAAa,OAAS,CAAE,GAAI,EAAG,IAClE,KAAK,MAAO,EAAS,EAAa,GAAM,CAAU,CACpD,EAIA,OAFA,EAAQ,KAAK,EAAS,EAAQ,QAAQ,EAAG,IAAM,EAAI,EAAG,CAAC,CAAC,EAEjD,CACT,CCvDA,SAAgB,EAAO,EAAY,EAAwC,CAGzE,OAFI,EAAM,SAAW,EAAU,EAExB,EAAM,QAAgB,EAAK,IAAS,CACzC,IAAM,EAAM,EAAW,EAAS,CAAI,EAAK,EAEzC,GAAI,OAAO,GAAQ,UAAY,OAAO,MAAM,CAAG,EAC7C,MAAM,IAAI,EACR,kFACF,EAGF,OAAO,EAAM,CACf,EAAG,CAAC,CACN,CCjBA,SAAgB,EAAW,EAAY,EAAoD,CACrF,KAAM,SAAW,EAErB,GAAI,CACF,IAAM,EAAS,EAAI,EAAO,CAAQ,EAAI,EAAM,OAE5C,OAAO,OAAO,MAAM,CAAM,EAAI,IAAA,GAAY,CAC5C,MAAQ,CACN,MACF,CACF,CCPA,SAAgB,EAAM,EAAW,EAAc,EAAsB,CAKnE,OAJI,GAAO,MAAQ,EAAI,EAAY,EAE/B,GAAO,MAAQ,EAAI,EAAY,EAE5B,CACT,CCTA,SAAgB,EAAI,EAAW,EAAmB,CAChD,IAAI,EAAI,KAAK,IAAI,CAAC,EACd,EAAI,KAAK,IAAI,CAAC,EAElB,KAAO,IAAM,GAAG,CACd,IAAM,EAAO,EAEb,EAAI,EAAI,EACR,EAAI,CACN,CAEA,OAAO,CACT,CCbA,SAAgB,GAAI,EAAW,EAAmB,CAGhD,OAFI,IAAM,GAAK,IAAM,EAAU,EAExB,KAAK,IAAI,EAAI,CAAC,EAAI,EAAI,EAAG,CAAC,CACnC,CCJA,SAAgB,GAAK,EAAW,EAAW,EAAmB,CAC5D,OAAO,GAAK,EAAI,GAAK,CACvB,CCAA,SAAgB,GAAS,EAAe,EAAa,EAAQ,EAAa,CACxE,GAAI,GAAS,EAAG,MAAO,CAAC,EAExB,GAAI,IAAU,EAAG,MAAO,CAAC,CAAK,EAE9B,IAAM,GAAY,EAAM,IAAU,EAAQ,GAE1C,OAAO,MAAM,KAAK,CAAE,OAAQ,CAAM,GAAI,EAAG,IAAM,EAAQ,EAAI,CAAQ,CACrE,CCJA,SAAgB,GAAO,EAAY,EAA+D,CAChG,GAAI,EAAM,SAAW,EAAG,OAExB,IAAM,EAAK,IAAc,GAAY,GACjC,EAAU,EAAM,GAEpB,IAAK,IAAI,EAAI,EAAG,EAAI,EAAM,OAAQ,IAC5B,EAAQ,EAAG,EAAM,EAAE,EAAG,EAAG,CAAO,CAAC,EAAI,IACvC,EAAU,EAAM,IAIpB,OAAO,CACT,CCnBA,SAAgB,GAAU,EAAU,EAAoD,CACtF,GAAI,EAAI,SAAW,EAAG,OAEtB,IAAM,EAAS,EAAW,EAAI,IAAI,CAAQ,EAAI,CAAC,GAAI,CAA2B,EAE9E,EAAO,MAAM,EAAG,IAAM,EAAI,CAAC,EAE3B,IAAM,EAAM,KAAK,MAAM,EAAO,OAAS,CAAC,EAExC,OAAO,EAAO,OAAS,GAAM,GAAK,EAAO,EAAM,GAAK,EAAO,IAAQ,EAAI,EAAO,EAChF,CCJA,SAAgB,GAAO,EAAY,EAA+D,CAChG,GAAI,EAAM,SAAW,EAAG,OAExB,IAAM,EAAK,IAAc,GAAY,GACjC,EAAU,EAAM,GAEpB,IAAK,IAAI,EAAI,EAAG,EAAI,EAAM,OAAQ,IAC5B,EAAQ,EAAG,EAAM,EAAE,EAAG,EAAG,CAAO,CAAC,EAAI,IACvC,EAAU,EAAM,IAIpB,OAAO,CACT,CChBA,SAAgB,GAAI,EAAW,EAAmB,CAChD,GAAI,IAAM,EAAG,MAAM,IAAI,EAAuB,0BAA0B,EAExE,OAAS,EAAI,EAAK,GAAK,CACzB,CCJA,SAAgB,GAAU,EAAe,EAAa,EAAqB,CAGzE,OAFI,IAAQ,EAAY,EAEjB,GAAO,EAAQ,IAAQ,EAAM,GAAM,EAAG,CAAC,CAChD,CCLA,SAAgB,GAAQ,EAAe,EAAuB,CAG5D,OAFI,IAAU,EAAU,EAEhB,EAAQ,EAAS,GAC3B,CCiBA,SAAgB,GAAM,EAAqB,EAAe,EAAyB,CACjF,GAAM,CAAC,EAAe,EAAc,GAClC,IAAS,IAAA,GAAY,CAAC,EAAG,EAAa,CAAC,EAAI,IAAS,IAAA,GAAY,CAAC,EAAa,EAAM,CAAC,EAAI,CAAC,EAAa,EAAM,CAAI,EAEnH,GAAI,CAAC,OAAO,SAAS,CAAa,GAAK,CAAC,OAAO,SAAS,CAAY,GAAK,CAAC,OAAO,SAAS,CAAY,EACpG,MAAM,IAAI,EAAuB,qDAAqD,EAGxF,GAAI,IAAiB,EAAG,MAAM,IAAI,EAAuB,yBAAyB,EAElF,GAAI,IAAkB,EACpB,MAAO,CAAC,EAGV,IAAM,GAAO,EAAe,GAAiB,EACvC,EAAS,KAAK,IAAI,EAAG,OAAO,UAAU,CAAG,EAAI,EAAM,KAAK,KAAK,QAAoB,CAAC,EAExF,GAAI,EAAS,IAAY,MAAM,IAAI,EAAuB,mDAAmD,EAE7G,OAAO,MAAM,KAAK,CAAE,QAAO,GAAI,EAAG,IAAM,EAAgB,EAAI,CAAY,CAC1E,CCvCA,SAAgB,GAAM,EAAe,EAAY,EAAG,EAAoC,KAAK,MAAe,CAC1G,GAAI,IAAc,EAAG,OAAO,EAAO,CAAK,EAExC,IAAM,EAAS,IAAM,KAAK,IAAI,KAAM,KAAK,IAAI,EAAW,GAAG,CAAC,EAE5D,OAAO,EAAO,EAAQ,CAAM,EAAI,CAClC,CCRA,SAAgB,EAAY,EAAY,EAAwC,CAC9E,GAAI,EAAM,SAAW,EAAG,MAAO,GAE/B,IAAM,EAAS,EAAW,EAAM,IAAI,CAAQ,EAAK,EAC3C,EAAO,EAAQ,CAAM,GAAK,EAEhC,OAAO,EAAQ,EAAO,IAAK,IAAW,EAAQ,IAAS,CAAC,CAAC,GAAK,CAChE,CCRA,SAAgB,GAAqB,EAAY,EAAwC,CACvF,OAAO,KAAK,KAAK,EAAS,EAAO,CAAQ,CAAC,CAC5C,CCCA,SAAgB,GAAwB,EAAW,GAAG,EAA+B,CACnF,IAAM,EAAM,CAAE,GAAG,CAAO,EAExB,IAAK,IAAM,KAAU,EACd,KAAc,CAAM,EAEzB,IAAK,IAAM,KAAO,OAAO,KAAK,CAAM,EAC9B,EAAY,CAAkB,GAE9B,EAAI,KAAS,IAAA,KACf,EAAI,GAAO,EAAO,IAKxB,OAAO,CACT,CCHA,SAAgB,GACd,EAAY,CAAC,EACb,EAAW,CAAC,EACZ,EAAiD,EAClC,CACf,IAAM,EAAiC,CAAC,EAClC,EAAmC,CAAC,EACpC,EAA+D,CAAC,EAEhE,EAAa,IAAI,IAAI,OAAO,KAAK,CAAM,CAAC,EACxC,EAAY,IAAI,IAAI,OAAO,KAAK,CAAK,CAAC,EAE5C,IAAK,IAAM,KAAO,EACX,EAAW,IAAI,CAAG,EAEZ,CAAC,EAAY,CAAG,GAAK,CAAC,EAAU,EAAO,GAAM,EAAM,EAAI,IAChE,EAAQ,GAAO,CAAE,MAAO,EAAM,GAAM,OAAQ,EAAO,EAAK,GAFxD,EAAM,KAAK,CAAuB,EAMtC,IAAK,IAAM,KAAO,EACX,EAAU,IAAI,CAAG,GACpB,EAAQ,KAAK,CAAuB,EAIxC,MAAO,CAAE,QAAgB,UAAqC,SAAQ,CACxE,CAgCA,SAAgB,GAAc,EAAa,EAAY,EAA6C,CAClG,IAAM,EAAY,GAAS,aAAe,EAAM,IAAS,EAAQ,EAAG,CAAC,GAErE,MAAO,CACL,MAAO,EAAM,OAAQ,GAAS,CAAC,EAAO,KAAM,GAAM,EAAU,EAAG,CAAI,CAAC,CAAC,EACrE,QAAS,EAAO,OAAQ,GAAS,CAAC,EAAM,KAAM,GAAM,EAAU,EAAM,CAAC,CAAC,CAAC,CACzE,CACF,CCjFA,SAAgB,GACd,EACA,EACY,CACZ,IAAM,EAAkB,CAAC,EAEzB,IAAK,IAAM,KAAO,OAAO,KAAK,CAAG,EAC3B,EAAY,CAAkB,GAE9B,EAAU,EAAI,GAAM,EAAK,CAAG,IAC9B,EAAI,GAAO,EAAI,IAInB,OAAO,CACT,CClBA,IAAM,GAAoB,GAE1B,SAAS,EAAc,EAA8B,EAAgB,EAAwC,CAC3G,IAAM,EAAkC,CAAC,EAEzC,IAAK,GAAM,CAAC,EAAK,KAAQ,OAAO,QAAQ,CAAG,EAAG,CAC5C,GAAI,EAAqB,IAAI,CAAG,EAAG,SAEnC,IAAM,EAAU,EAAS,GAAG,EAAO,GAAG,IAAQ,EAE1C,EAAc,CAAG,GAAK,EAAQ,GAChC,OAAO,OAAO,EAAQ,EAAc,EAAgC,EAAS,EAAQ,CAAC,CAAC,EAEvF,EAAO,GAAW,CAEtB,CAEA,OAAO,CACT,CAEA,SAAgB,GAAa,EAAuD,CAClF,OAAO,EAAc,EAAK,GAAI,CAAC,CACjC,CAYA,SAAgB,GAAe,EAAwD,CACrF,IAAM,EAAkC,CAAC,EAEzC,IAAK,GAAM,CAAC,EAAK,KAAQ,OAAO,QAAQ,CAAI,EAAG,CAC7C,IAAM,EAAQ,EAAI,MAAM,GAAG,EAE3B,GAAI,EAAM,KAAM,GAAM,EAAqB,IAAI,CAAC,CAAC,EAAG,SAEpD,IAAI,EAAM,EAEV,IAAK,IAAI,EAAI,EAAG,EAAI,EAAM,OAAS,EAAG,IAC/B,EAAc,EAAI,EAAM,GAAG,IAC9B,EAAI,EAAM,IAAM,CAAC,GAGnB,EAAM,EAAI,EAAM,IAGlB,EAAI,EAAM,EAAM,OAAS,IAAM,CACjC,CAEA,OAAO,CACT,CCbA,SAAgB,GACd,EACA,EACA,EAA0B,CAAC,EACE,CAC7B,GAAM,CAAE,kBAAkB,GAAM,SAAU,EAAc,SAAS,IAAU,EAE3E,GAAI,QAAQ,KAAK,CAAI,EAAG,CACtB,GAAI,CAAC,EACH,MAAM,IAAI,EACR,kEAAkE,EAAK,QAAQ,aAAc,KAAK,CAAC,CAAC,QAAQ,WAAY,EAAE,EAAE,qCAC9H,EAGF,EAAO,EAAK,QAAQ,aAAc,KAAK,CAAC,CAAC,QAAQ,WAAY,EAAE,CACjE,CAEA,IAAM,EAAY,EAAK,MAAM,GAAG,CAAC,CAAC,OAAO,OAAO,EAC5C,EAAmB,EAEvB,IAAK,IAAM,KAAY,EAAW,CAChC,GAAI,EAAqB,IAAI,CAAQ,EAAG,OAAO,EAE/C,GAAuB,OAAO,GAAY,WAAtC,EAAgD,CAClD,GAAI,EAAQ,MAAM,IAAI,EAAuB,yBAAyB,EAAS,OAAO,GAAS,EAE/F,OAAO,CACT,CAIA,GAFA,EAAW,EAAoC,GAE3C,IAAY,IAAA,GAAW,CACzB,GAAI,EAAQ,MAAM,IAAI,EAAuB,aAAa,EAAS,iBAAiB,EAEpF,OAAO,CACT,CACF,CAEA,OAAO,CACT,CCjFA,SAAgB,GAAmD,EAAqC,CACtG,IAAM,EAAM,CAAC,EAEb,IAAK,GAAM,CAAC,EAAK,KAAU,OAAO,QAAQ,CAAG,EACvC,EAAY,CAAK,IAErB,EAAI,GAAS,GAGf,OAAO,CACT,CCRA,SAAgB,GACd,EACA,EACiC,CACjC,IAAM,EAAuC,CAAC,EAE9C,IAAK,IAAM,KAAO,OAAO,KAAK,CAAG,EAAqB,CACpD,GAAI,EAAY,CAAkB,EAAG,SAErC,IAAM,EAAY,EAAO,EAAK,EAAI,GAAM,CAAG,EAEvC,EAAY,CAAS,IAEzB,EAAI,GAAa,EAAI,GACvB,CAEA,OAAO,CACT,CCjBA,SAAgB,GACd,EACA,EACuB,CACvB,IAAM,EAAM,CAAC,EAEb,IAAK,IAAM,KAAO,OAAO,KAAK,CAAG,EAC3B,EAAY,CAAkB,IAElC,EAAI,GAAO,EAAO,EAAI,GAAM,EAAK,CAAG,GAGtC,OAAO,CACT,CCEA,SAAS,EAA2C,EAAW,EAAW,EAA4C,CACpH,GAAI,CAAC,EAAc,CAAM,EAAG,OAAO,EAEnC,IAAM,EAAS,CAAE,GAAG,CAAO,EAE3B,IAAK,IAAM,KAAO,OAAO,KAAK,CAAM,EAAG,CAErC,GAAI,EAAY,CAAG,EACjB,SAGF,IAAM,EAAc,EAAO,GACrB,EAAc,EAAO,GAE3B,EAAoC,GAClC,MAAM,QAAQ,CAAW,GAAK,MAAM,QAAQ,CAAW,EACnD,EAAQ,gBAAkB,SACxB,CAAC,GAAG,EAAa,GAAG,CAAW,EAC/B,EACF,EAAc,CAAW,GAAK,EAAc,CAAW,EACrD,EAAa,EAAoB,EAAoB,CAAO,EAC5D,CACV,CAEA,OAAO,CACT,CAkBA,SAAgB,GAA2B,GAAG,EAAmD,CAC/F,IAAM,EAAU,EAAK,EAAK,OAAS,GAC7B,EACJ,EAAK,OAAS,GACd,OAAO,GAAY,YACnB,GACA,CAAC,MAAM,QAAQ,CAAO,GACtB,kBAAmB,GACnB,OAAO,KAAK,CAAO,CAAC,CAAC,SAAW,IAC9B,EAA6B,gBAAkB,UAC9C,EAA6B,gBAAkB,WAE9C,EAA4B,EAAc,EAA+B,CAAC,EAC1E,EAAS,EAAa,EAAK,MAAM,EAAG,EAAE,EAAI,EAIhD,OAFI,EAAM,SAAW,EAAU,CAAC,EAEzB,EAAM,QAAQ,EAAU,IAAa,EAAa,EAAK,EAAK,CAAO,EAAU,CAAC,CAAQ,CAC/F,CAcA,SAAgB,GAA8B,GAAG,EAAyB,CACxE,GAAI,EAAM,SAAW,EAAG,MAAO,CAAC,EAEhC,IAAM,EAAc,CAAC,EAErB,IAAK,IAAM,KAAQ,EACjB,IAAK,IAAM,KAAO,OAAO,KAAK,CAAI,EAC5B,EAAY,CAAG,IAEnB,EAAO,GAAO,EAAK,IAIvB,OAAO,CACT,CCxGA,SAAgB,GAAuC,EAAQ,EAAuC,CACpG,IAAM,EAAY,IAAI,IAAiB,CAAqC,EACtE,EAAM,CAAC,EAEb,IAAK,IAAM,KAAO,OAAO,KAAK,CAAG,EAC3B,EAAY,CAAkB,GAE7B,EAAU,IAAI,CAAG,IACpB,EAAW,GAAO,EAAI,IAI1B,OAAO,CACT,CCGA,SAAgB,GACd,EACA,EAA+B,CAAC,EACjB,CACf,GAAM,CAAE,WAAU,UAAS,aAAc,EAEzC,GAAI,EAAM,CAAI,EAAG,OAAO,EAExB,GAAI,CACF,IAAM,EAAQ,KAAK,MAAM,EAAM,CAA2C,EAM1E,OAJI,IAAU,IAAA,IAEV,GAAa,CAAC,EAAU,CAAK,EAAU,EAEpC,CACT,MAAQ,CACN,OAAO,CACT,CACF,CClCA,SAAgB,GAAuC,EAAQ,EAAwC,CACrG,IAAM,EAAM,CAAC,EAEb,IAAK,IAAM,KAAO,EACZ,EAAY,CAAkB,GAE9B,OAAO,OAAO,EAAK,CAAG,IACxB,EAAI,GAAO,EAAI,IAInB,OAAO,CACT,CCEA,SAAgB,EAAS,EAAyB,CAC5C,MAAM,CAAK,EAEf,IAAI,EAAS,CAAK,EAAG,CACnB,IAAM,EAAU,EAAM,KAAK,EAE3B,OAAQ,IAAY,GAAK,IAAA,GAAY,CACvC,CAEA,GAAI,MAAM,QAAQ,CAAK,EAAG,CACxB,IAAM,EAAU,EAAU,EAAqB,GAAS,CACtD,IAAM,EAAS,EAAM,CAAI,EAEzB,OAAO,EAAQ,CAAM,EAAI,IAAA,GAAa,CACxC,CAAC,EAED,OAAQ,EAAQ,SAAW,EAAI,IAAA,GAAY,CAC7C,CAEA,GAAI,EAAc,CAAK,EAAG,CACxB,IAAM,EAAmC,CAAC,EAE1C,IAAK,GAAM,CAAC,EAAK,KAAQ,OAAO,QAAQ,CAAK,EAAG,CAC9C,GAAI,EAAY,CAAG,EAAG,SAEtB,IAAM,EAAe,EAAM,CAAG,EAEzB,EAAQ,CAAY,IACvB,EAAQ,GAAO,EAEnB,CAEA,OAAQ,OAAO,KAAK,CAAO,CAAC,CAAC,SAAW,EAAI,IAAA,GAAY,CAC1D,CAEA,OAAO,CA5BP,CA6BF,CClCA,SAAS,EAAM,EAAgB,EAAkC,EAA8B,CAC7F,GAAI,IAAU,IAAA,GAAW,MAAO,YAEhC,GAAI,IAAU,KAAM,MAAO,OAE3B,GAAI,OAAO,GAAU,SAAU,MAAO,GAAG,EAAM,GAE/C,GAAI,OAAO,GAAU,SAAU,OAAO,KAAK,UAAU,CAAK,EAE1D,GAAI,EAAQ,IAAI,CAAe,EAAG,MAAO,aAIzC,GAFA,EAAQ,IAAI,CAAe,EAEvB,aAAiB,KAAM,MAAO,SAAS,OAAO,MAAM,EAAM,QAAQ,CAAC,EAAI,UAAY,EAAM,YAAY,EAAE,GAE3G,GAAI,aAAiB,OAAQ,MAAO,WAAW,EAAM,OAAO,GAAG,EAAM,MAAM,GAE3E,GAAI,aAAiB,IACnB,MAAO,QAAQ,CAAC,GAAG,CAAK,CAAC,CACtB,IAAK,GAAM,EAAM,EAAG,EAAS,CAAO,CAAC,CAAC,CACtC,KAAK,CAAC,CACN,KAAK,GAAG,EAAE,GAEf,GAAI,aAAiB,IAOnB,MAAO,QANS,CAAC,GAAG,EAAM,QAAQ,CAAC,CAAC,CACjC,KAAK,CAAC,EAAK,KAAgB,CAAC,EAAM,EAAK,EAAS,CAAO,EAAG,EAAM,EAAY,EAAS,CAAO,CAAC,CAAU,CAAC,CACxG,MAAM,CAAC,EAAS,GAAY,CAAC,EAAU,KACtC,IAAY,EAAW,EAAU,cAAc,CAAU,EAAI,EAAQ,cAAc,CAAQ,CAGhF,CAAA,CAAQ,KAAK,CAAC,EAAK,KAAgB,GAAG,EAAI,IAAI,GAAY,CAAC,CAAC,KAAK,GAAG,EAAE,GAGvF,GAAI,MAAM,QAAQ,CAAK,EAAG,MAAO,IAAI,EAAM,IAAK,GAAM,EAAM,EAAG,EAAS,CAAO,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,GAE5F,IAAM,EAAQ,OAAO,eAAe,CAAK,EAEzC,GAAI,IAAU,OAAO,WAAa,IAAU,KAAM,CAChD,GAAI,GAAS,kBAAoB,QAC/B,MAAM,IAAI,EACR,0BAA2B,EAA8C,aAAa,MAAQ,WAChG,EAGF,OAAO,OAAO,CAAK,CACrB,CAEA,IAAM,EAAM,EAKZ,MAAO,IAJM,OAAO,KAAK,CAAG,CAAC,CAC1B,OAAQ,GAAM,EAAI,KAAO,IAAA,EAAS,CAAC,CACnC,KAEQ,CAAA,CAAK,IAAK,GAAM,GAAG,KAAK,UAAU,CAAC,EAAE,GAAG,EAAM,EAAI,GAAI,EAAS,CAAO,GAAG,CAAC,CAAC,KAAK,GAAG,EAAE,EAClG,CAEA,SAAgB,GAAK,EAAgB,EAA+B,CAClE,OAAO,EAAM,EAAO,EAAS,IAAI,GAAa,CAChD,CCnFA,SAAgB,EAAkB,EAA8B,CAE9D,IAAM,EAAc,OAAO,gBAAgB,IAAI,YAAY,CAAC,CAAC,CAAC,CAAC,GAAM,WAErE,OAAO,KAAK,MAAM,EAAc,CAAY,CAC9C,CCEA,SAAgB,EAAO,EAAa,EAAqB,CACvD,GAAI,EAAM,EAAK,MAAM,IAAI,EAAuB,8DAA8D,EAE9G,OAAO,EAAkB,EAAM,EAAM,CAAC,EAAI,CAC5C,CCNA,SAAgB,GAAQ,EAA2B,CAC7C,KAAM,SAAW,EAErB,OAAO,EAAM,EAAO,EAAG,EAAM,OAAS,CAAC,EACzC,CAaA,SAAgB,GAAY,EAAY,EAAgB,CACtD,IAAM,EAAQ,KAAK,IAAI,EAAG,KAAK,IAAI,EAAM,OAAQ,KAAK,MAAM,CAAC,CAAC,CAAC,EAE/D,GAAI,IAAU,EAAG,MAAO,CAAC,EAEzB,GAAI,IAAU,EAAM,OAAQ,MAAO,CAAC,GAAG,CAAK,EAE5C,IAAM,EAAO,CAAC,GAAG,CAAK,EAEtB,IAAK,IAAI,EAAQ,EAAK,OAAS,EAAG,EAAQ,EAAG,IAAS,CACpD,IAAM,EAAc,EAAkB,EAAQ,CAAC,EACzC,EAAO,EAAK,GAElB,EAAK,GAAS,EAAK,GACnB,EAAK,GAAe,CACtB,CAEA,OAAO,EAAK,MAAM,EAAG,CAAK,CAC5B,CCpCA,SAAgB,GAAW,EAAiB,CAC1C,IAAM,EAAS,CAAC,GAAG,CAAK,EAExB,IAAK,IAAI,EAAI,EAAO,OAAS,EAAG,EAAI,EAAG,IAAK,CAC1C,IAAM,EAAI,EAAkB,EAAI,CAAC,EAEjC,CAAC,EAAO,GAAI,EAAO,IAAM,CAAC,EAAO,GAAI,EAAO,EAAE,CAChD,CAEA,OAAO,CACT,CCZA,SAAgB,IAAe,CAC7B,OAAO,OAAO,WAAW,CAC3B,CCLA,IAAM,GAAqB,uEAG3B,SAAS,GAAY,EAAqB,CACxC,OAAO,EAAI,QAAQ,wBAAyB,MAAM,CACpD,CASA,SAAgB,EAAc,EAAa,EAAY,IAAa,CAClE,IAAM,EAAa,GAAY,CAAS,EAExC,OAAO,EACJ,KAAK,CAAC,CACN,QAAQ,GAAoB,SAAS,EAAU,OAAO,CAAC,CACvD,QAAQ,mBAAoB,CAAS,CAAC,CACtC,QAAY,OAAO,OAAO,EAAW,QAAQ,EAAW,KAAM,GAAG,EAAG,EAAE,CAC3E,CCfA,SAAgB,GAAU,EAAqB,CAC7C,OAAO,EAAc,EAAK,GAAG,CAAC,CAC3B,QAAQ,uBAAwB,EAAG,IAAS,EAAK,YAAY,CAAC,CAAC,CAC/D,QAAQ,KAAO,GAAS,EAAK,YAAY,CAAC,CAC/C,CCfA,SAAgB,GAA2B,EAAe,EAAqC,CAC7F,OAAO,EAAM,SAAS,CAAM,CAC9B,CCLA,IAAM,GAAoC,CACxC,IAAK,QACL,IAAK,SACL,IAAK,QACL,IAAK,OACL,IAAK,MACP,EAKA,SAAgB,EAAO,EAAuB,CAC5C,OAAO,EAAM,QAAQ,WAAa,GAAS,GAAU,EAAK,CAC5D,CCEA,SAAgB,GAAU,EAAqB,CAC7C,OAAO,EAAc,EAAK,GAAG,CAAC,CAAC,YAAY,CAC7C,CCdA,SAAgB,GAAI,EAAa,EAAsB,EAAa,IAAa,CAC/E,GAAI,GAAgB,EAAI,OAAQ,OAAO,EAEvC,IAAM,EAAQ,EAAe,EAAI,OAC3B,EAAO,KAAK,MAAM,EAAQ,CAAC,EAEjC,OAAO,EAAI,SAAS,EAAI,OAAS,EAAM,CAAU,CAAC,CAAC,OAAO,EAAc,CAAU,CACpF,CCKA,SAAgB,GAAW,EAAqB,CAC9C,OAAO,EAAc,EAAK,GAAG,CAAC,CAC3B,QAAQ,2BAA4B,EAAG,IAAS,EAAK,YAAY,CAAC,CAAC,CACnE,QAAQ,OAAQ,EAAE,CACvB,CCJA,SAAgB,GAAU,EAAqB,CAC7C,OAAO,EAAc,EAAK,GAAG,CAAC,CAAC,YAAY,CAC7C,CCdA,SAAgB,GAA6B,EAAe,EAAqC,CAC/F,OAAO,EAAM,WAAW,CAAM,CAChC,CCAA,SAAgB,EAAM,EAAuB,CAC3C,IAAM,EAAa,EAAc,EAAK,GAAG,EAIzC,OAFK,EAEE,EAAW,MAAM,GAAG,CAAC,CAAC,OAAO,OAAO,EAFnB,CAAC,CAG3B,CCNA,SAAgB,GAAU,EAAqB,CAC7C,OAAO,EAAM,CAAG,CAAC,CACd,IAAK,GAAS,EAAK,OAAO,CAAC,CAAC,CAAC,YAAY,EAAI,EAAK,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CACzE,KAAK,GAAG,CACb,CCmBA,SAAgB,GACd,EACA,EAAQ,GACR,CAAE,gBAAgB,GAAO,WAAW,KAAyB,CAAC,EACtD,CACR,GAAI,OAAO,GAAQ,SACjB,MAAM,IAAI,EAAuB,gCAAgC,EAGnE,GAAI,OAAO,GAAU,UAAY,CAAC,OAAO,SAAS,CAAK,GAAK,EAAQ,EAClE,MAAM,IAAI,EAAuB,sDAAsD,EAGzF,GAAI,EAAI,QAAU,EAChB,OAAO,EAGT,IAAI,EAAM,EAEV,GAAI,EAAe,CACjB,IAAM,EAAU,EAAI,UAAU,EAAG,CAAK,CAAC,CAAC,YAAY,GAAG,EAEnD,EAAU,IAAG,EAAM,EACzB,CAEA,MAAO,GAAG,EAAI,UAAU,EAAG,CAAG,CAAC,CAAC,KAAK,IAAI,GAC3C,CCtDA,IAAM,GAAsC,CAC1C,QAAS,IACT,QAAS,IACT,OAAQ,IACR,OAAQ,IACR,SAAU,GACZ,EAKA,SAAgB,GAAS,EAAuB,CAC9C,OAAO,EAAM,QAAQ,0BAA4B,GAAW,GAAY,IAAW,CAAM,CAC3F"}
|
|
1
|
+
{"version":3,"file":"arsenal.cjs","names":[],"sources":["../src/errors.ts","../src/array/chunk.ts","../src/array/filterMap.ts","../src/_common/unsafePaths.ts","../src/array/groupBy.ts","../src/array/indexBy.ts","../src/array/partition.ts","../src/array/compare.ts","../src/array/compareBy.ts","../src/array/sort.ts","../src/_common/_selectorSet.ts","../src/array/uniq.ts","../src/async/attempt.ts","../src/async/abortError.ts","../src/async/parallel.ts","../src/async/sleep.ts","../src/async/retry.ts","../src/_dev.ts","../src/function/debounce.ts","../src/function/once.ts","../src/function/pipe.ts","../src/function/throttle.ts","../src/guards/combinators.ts","../src/guards/isDefined.ts","../src/guards/isEqual.ts","../src/guards/isNil.ts","../src/guards/isPlainObject.ts","../src/math/clamp.ts","../src/math/range.ts","../src/object/getPath.ts","../src/object/hash.ts","../src/object/omit.ts","../src/object/pick.ts","../src/random/uuid.ts","../src/string/_caseUtils.ts","../src/string/camelCase.ts"],"sourcesContent":["/** Base class for all arsenal errors. Use `instanceof ArsenalError` to catch any arsenal-originated error. */\nexport class ArsenalError extends Error {\n constructor(message: string, opts?: ErrorOptions) {\n super(message, opts);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n\n static is(err: unknown): err is ArsenalError {\n return err instanceof ArsenalError;\n }\n}\n\n/**\n * Thrown when converting a value to or from its serialized form fails — e.g. `memo`'s default\n * cache key (`JSON.stringify`) encountering a circular reference, or `hash` encountering an\n * unsupported class instance with `{ onClassInstance: 'throw' }`.\n */\nexport class ArsenalSerializationError extends ArsenalError {}\n","/**\n * Splits an array or string into chunks of a specified size.\n *\n * @example\n * ```ts\n * chunk([1, 2, 3, 4, 5], 2) // [[1, 2], [3, 4], [5]]\n * chunk('hello', 2) // ['he', 'll', 'o']\n * ```\n *\n * @param input - The input array or string to be chunked.\n * @param size - The size of each chunk (default 2).\n *\n * @returns An array of chunks.\n *\n * @throws {TypeError} If the input is not an array or string.\n * @throws {RangeError} If the chunk size is not a positive integer.\n */\nexport function chunk(input: string, size?: number): string[];\nexport function chunk<T>(input: T[], size?: number): T[][];\nexport function chunk<T>(input: T[] | string, size = 2): string[] | T[][] {\n if (!Array.isArray(input) && typeof input !== 'string')\n throw new TypeError('chunk: argument must be an array or string');\n\n if (!Number.isInteger(size) || size < 1) throw new RangeError('chunk: size must be a positive integer');\n\n return Array.from({ length: Math.ceil(input.length / size) }, (_, i) => input.slice(i * size, i * size + size)) as\n string[] | T[][];\n}\n","/**\n * Maps and filters in one pass. Returning `undefined` drops an item.\n */\nexport function filterMap<T, R>(array: T[], callback: (item: T, index: number, array: T[]) => R | undefined): R[] {\n const result: R[] = [];\n\n for (let index = 0; index < array.length; index++) {\n const value = callback(array[index], index, array);\n\n if (value !== undefined) {\n result.push(value);\n }\n }\n\n return result;\n}\n","/**\n * Path segments that must be rejected in any dot-notation traversal or mutation\n * to prevent prototype pollution reads and writes.\n * @internal\n */\nexport const UNSAFE_PATH_SEGMENTS = new Set(['__proto__', 'constructor', 'prototype']);\n\n/**\n * Returns `true` if every dot-notation segment in `key` is safe to use as a\n * plain-object property.\n *\n * @example\n * ```ts\n * isSafePath('user.name') // true\n * isSafePath('__proto__.polluted') // false\n * ```\n */\nexport function isSafePath(key: string): boolean {\n return key.split('.').every((s) => !UNSAFE_PATH_SEGMENTS.has(s));\n}\n\n/**\n * Returns `true` if `key` is one of the dangerous own-property names that can be used to\n * pollute `Object.prototype` (`__proto__`, `constructor`, `prototype`). Use this for plain\n * (non-dotted) property keys — e.g. object keys being copied or reassigned. For dotted paths,\n * use `isSafePath` instead.\n *\n * @example\n * ```ts\n * isUnsafeKey('name') // false\n * isUnsafeKey('__proto__') // true\n * ```\n */\nexport function isUnsafeKey(key: PropertyKey): boolean {\n return typeof key === 'string' && UNSAFE_PATH_SEGMENTS.has(key);\n}\n","import type { Primitive } from '../types';\n\nimport { isUnsafeKey } from '../_common/unsafePaths';\n\n/**\n * Groups elements by a selector function. Dangerous keys (`__proto__`, `constructor`,\n * `prototype`) are skipped.\n */\nexport function groupBy<T>(array: T[], selector: (item: T) => Primitive): Record<string, T[]> {\n const result: Record<string, T[]> = {};\n\n for (const item of array) {\n const rawKey = selector(item);\n const key = rawKey === undefined || rawKey === null ? '_' : String(rawKey);\n\n if (isUnsafeKey(key)) continue;\n\n if (!result[key]) {\n result[key] = [];\n }\n\n result[key].push(item);\n }\n\n return result;\n}\n","import type { Primitive } from '../types';\n\nimport { isUnsafeKey } from '../_common/unsafePaths';\n\n/**\n * Creates an object keyed by selector result. Last item wins on collisions. Dangerous keys\n * (`__proto__`, `constructor`, `prototype`) are skipped.\n */\nexport function indexBy<T>(array: T[], selector: (item: T) => Primitive): Record<string, T> {\n const result: Record<string, T> = {};\n\n for (const item of array) {\n const key = String(selector(item));\n\n if (isUnsafeKey(key)) continue;\n\n result[key] = item;\n }\n\n return result;\n}\n","/**\n * Splits an array into values that match and do not match the predicate.\n */\nexport function partition<T>(array: T[], predicate: (item: T, index: number, array: T[]) => boolean): [T[], T[]] {\n const accepted: T[] = [];\n const rejected: T[] = [];\n\n for (let index = 0; index < array.length; index++) {\n if (predicate(array[index], index, array)) {\n accepted.push(array[index]);\n } else {\n rejected.push(array[index]);\n }\n }\n\n return [accepted, rejected];\n}\n","/**\n * Compares two values and returns a number suitable for use as a sort comparator.\n *\n * - Numbers and Dates: returns `0`, `1`, or `-1`.\n * - Strings: delegates to `String.prototype.localeCompare`, which may return any integer\n * (not just `0`, `1`, `-1`) depending on locale and engine.\n * - `null` sorts before all non-null values; `undefined` sorts last.\n *\n * @example\n * ```ts\n * compare('a', 'b'); // negative (locale-dependent)\n * compare(1, 2); // -1\n * compare(new Date('2023-01-01'), new Date('2023-01-02')); // -1\n * compare('a', 'a'); // 0\n * compare(1, 1); // 0\n * compare(new Date('2023-01-01'), new Date('2023-01-01')); // 0\n * ```\n *\n * @param a - The first value to compare.\n * @param b - The second value to compare.\n *\n * @returns A negative number, zero, or a positive number.\n *\n * Pass directly as an `Array.sort` comparator:\n * ```ts\n * [3, 1, 2].sort(compare); // [1, 2, 3]\n * ['banana', 'apple', 'cherry'].sort(compare); // ['apple', 'banana', 'cherry']\n * ```\n */\nexport const compare = (a: unknown, b: unknown): number => {\n if (a === b) return 0;\n\n if (a === undefined) return 1;\n\n if (b === undefined) return -1;\n\n if (a === null) return b === null ? 0 : -1;\n\n if (b === null) return 1;\n\n if (typeof a === 'string' && typeof b === 'string') {\n return a.localeCompare(b);\n }\n\n if (typeof a === 'number' && typeof b === 'number') {\n return a === b ? 0 : a > b ? 1 : -1;\n }\n\n if (a instanceof Date && b instanceof Date) {\n const at = a.getTime();\n const bt = b.getTime();\n\n return at === bt ? 0 : at > bt ? 1 : -1;\n }\n\n throw new TypeError(\n `compare: unsupported types \"${typeof a}\" and \"${typeof b}\". Supported: number, string, Date, null, undefined.`,\n );\n};\n","import { compare } from './compare';\n\n/**\n * Compares two objects based on multiple selectors.\n * The comparison is done in the order of the selectors provided.\n * Each selector can be 'asc' for ascending or 'desc' for descending order.\n *\n * @example\n * ```ts\n * const compareByNameAndAge = compareBy<{ name: string; age: number }>({\n * name: 'asc',\n * age: 'desc',\n * });\n *\n * const a = { name: 'Alice', age: 30 };\n * const b = { name: 'Bob', age: 25 };\n *\n * console.log(compareByNameAndAge(a, b)); // -1 (Alice < Bob)\n * ```\n *\n * @param selectors - An object where keys are properties to compare and values are 'asc' or 'desc'.\n *\n * @returns A comparator for use with `Array.sort` or `sort()`.\n */\nexport const compareBy = <T>(selectors: Partial<Record<keyof T, 'asc' | 'desc'>>) => {\n const entries = Object.entries(selectors) as [keyof T, 'asc' | 'desc'][];\n\n return (a: T, b: T) => {\n for (const [key, direction] of entries) {\n const v1 = a[key];\n const v2 = b[key];\n const dir = direction === 'desc' ? -1 : 1;\n\n const cmp = compare(v1, v2);\n\n if (cmp !== 0) return cmp * dir;\n }\n\n return 0;\n };\n};\n","import { compare } from './compare';\nimport { compareBy } from './compareBy';\n\nexport type SortDirection = 'asc' | 'desc';\nexport type SortSelectors<T> = Partial<Record<keyof T, SortDirection>>;\n\n/**\n * Sorts an array by a selector function (single-field) or by a multi-field\n * object of `{ key: 'asc' | 'desc' }` entries.\n *\n * @example\n * ```ts\n * // Single field\n * sort([{ a: 2 }, { a: 1 }], item => item.a); // [{ a:1 }, { a:2 }]\n * sort([{ a: 2 }, { a: 1 }], item => item.a, 'desc'); // [{ a:2 }, { a:1 }]\n *\n * // Multi-field\n * sort(users, { name: 'asc', age: 'desc' });\n * ```\n *\n * @param array - The array to sort.\n * @param selector - A function extracting the sort key, or a multi-field object.\n * @param direction - `'asc'` (default) or `'desc'` — only applies to single-field mode.\n * @returns A new sorted array.\n *\n * @throws {TypeError} If the first argument is not an array.\n */\nexport function sort<T>(array: T[], selector: (item: T) => unknown, direction?: SortDirection): T[];\nexport function sort<T>(array: T[], selectors: SortSelectors<T>): T[];\nexport function sort<T>(\n array: T[],\n selectorOrSelectors: ((item: T) => unknown) | SortSelectors<T>,\n direction: SortDirection = 'asc',\n): T[] {\n if (!Array.isArray(array)) throw new TypeError('sort: first argument must be an array');\n\n if (typeof selectorOrSelectors === 'function') {\n const multiplier = direction === 'desc' ? -1 : 1;\n\n return [...array].sort((a, b) => compare(selectorOrSelectors(a), selectorOrSelectors(b)) * multiplier);\n }\n\n return [...array].sort(compareBy(selectorOrSelectors));\n}\n","import type { Primitive } from '../types';\n\n/**\n * Builds a `Set` of `selector(item)` results for O(1) membership checks — shared by\n * `intersection()` and `difference()`.\n *\n * Module-private: underscore-prefixed file is excluded from barrel exports.\n * @internal\n */\nexport function toSelectorSet<T>(items: readonly T[], selector: (item: T) => Primitive): Set<Primitive> {\n return new Set(items.map((item) => selector(item)));\n}\n\n/**\n * Returns `items` with duplicate `selector(item)` results removed, preserving the first\n * occurrence of each key — shared by `union()` and `uniq()`.\n *\n * Module-private: underscore-prefixed file is excluded from barrel exports.\n * @internal\n */\nexport function dedupeBySelector<T>(items: readonly T[], selector: (item: T) => Primitive): T[] {\n const seen = new Set<Primitive>();\n const out: T[] = [];\n\n for (const item of items) {\n const key = selector(item);\n\n if (seen.has(key)) continue;\n\n seen.add(key);\n out.push(item);\n }\n\n return out;\n}\n","import type { Primitive } from '../types';\n\nimport { dedupeBySelector } from '../_common/_selectorSet';\n\n/**\n * Creates a new array with duplicate values removed.\n *\n * @example\n * ```ts\n * uniq([1, 2, 2, 3, 3, 3]); // [1, 2, 3]\n * const arrObj = [{ id: 1 }, { id: 2 }, { id: 2 }, { id: 3 }, { id: 3 }, { id: 3 }];\n * uniq(arrObj, item => item.id); // [{ id: 1 }, { id: 2 }, { id: 3 }]\n * ```\n *\n * @param array - The array to process.\n * @param [selector] - Function used to generate comparison values for each item.\n\n * @returns A new duplicate-free array.\n */\nexport function uniq<T>(array: T[], selector?: (item: T) => Primitive): T[] {\n if (array.length <= 1) {\n return [...array];\n }\n\n if (!selector) {\n return [...new Set(array)];\n }\n\n return dedupeBySelector(array, selector);\n}\n","export type AttemptResult<T> =\n | { ok: true; value: T }\n // eslint-disable-next-line perfectionist/sort-object-types\n | { ok: false; error: unknown };\n\n/**\n * Narrows an `AttemptResult` to the success branch.\n * @example\n * ```ts\n * const result = await attempt(() => fetch('/api').then(r => r.json()));\n * if (isOk(result)) console.log(result.value);\n * ```\n */\n\nexport function isOk<T>(result: AttemptResult<T>): result is { ok: true; value: T } {\n return result.ok === true;\n}\n\n/**\n * Narrows an `AttemptResult` to the failure branch.\n * @example\n * ```ts\n * const result = await attempt(() => fetch('/api').then(r => r.json()));\n * if (isFail(result)) console.error(result.error);\n * ```\n */\n// eslint-disable-next-line perfectionist/sort-object-types\nexport function isFail<T>(result: AttemptResult<T>): result is { ok: false; error: unknown } {\n return result.ok === false;\n}\n\n/**\n * Executes a function — sync or async — and resolves to an `AttemptResult`.\n * Never throws.\n *\n * @example\n * ```ts\n * // Sync\n * const parsed = attempt(() => JSON.parse(rawJson));\n * if (parsed.ok) console.log(parsed.value);\n * else console.error(parsed.error);\n *\n * // Async\n * const result = await attempt(() => fetch('/api').then(r => r.json()));\n * if (result.ok) console.log(result.value);\n * else console.error(result.error);\n *\n * // Combined with retry()\n * const result = await attempt(() => retry(fn, { times: 3 }));\n * ```\n */\nexport async function attempt<T>(fn: () => T | Promise<T>): Promise<AttemptResult<T>> {\n try {\n return { ok: true, value: await fn() };\n } catch (error) {\n return { error, ok: false };\n }\n}\n","/**\n * Returns the abort error for the given signal.\n *\n * If the signal has a `reason`, that is returned directly (preserving the\n * original error thrown by `AbortController.abort(reason)`).\n * Otherwise, returns a `DOMException` with `name === 'AbortError'`.\n *\n * @example\n * ```ts\n * const ac = new AbortController();\n * ac.abort();\n * throw abortError(ac.signal); // DOMException { name: 'AbortError' }\n *\n * const ac2 = new AbortController();\n * ac2.abort(new TypeError('custom'));\n * throw abortError(ac2.signal); // TypeError('custom')\n * ```\n *\n * @param signal - The aborted signal to extract the error from.\n * @returns The abort reason, or a new `DOMException('Aborted', 'AbortError')`.\n */\nexport function abortError(signal?: AbortSignal): unknown {\n return signal?.reason ?? new DOMException('Aborted', 'AbortError');\n}\n","import { abortError } from './abortError';\n\n/**\n * Processes an array with an async callback with controlled parallelism.\n * Similar to Promise.all, but limits how many items are processed concurrently.\n * Returns an ordered array of results.\n *\n * @example\n * ```ts\n * // Process 3 items at a time\n * const results = await parallel([1, 2, 3, 4, 5], async (n) => {\n * await delay(100);\n * return n * 2;\n * }, { limit: 3 });\n * // [2, 4, 6, 8, 10]\n *\n * // With abort signal\n * const controller = new AbortController();\n * const results = await parallel(items, async (item) => {\n * return processItem(item);\n * }, { limit: 2, signal: controller.signal });\n *\n * // Stop other workers as soon as one item fails\n * await parallel(items, riskyOperation, { abortOnError: true, limit: 3 });\n * ```\n *\n * @param array - Array of items to process\n * @param callback - Async function to process each item\n * @param options - Optional options for concurrency and cancellation\n * @param [options.limit=Infinity] - Maximum number of concurrent operations. Defaults to unbounded.\n * @param [options.signal] - Optional AbortSignal to cancel processing\n * @param [options.abortOnError=false] - When `true`, stops other in-flight workers as soon as any\n * callback throws, instead of letting them keep running to completion unobserved. Default\n * preserves the existing best-effort-completion behavior.\n * @returns Promise resolving to an ordered array of results\n * @throws {RangeError} If limit is less than 1\n * @throws {DOMException} If aborted via signal\n */\nexport async function parallel<T, R>(\n array: readonly T[],\n callback: (item: T, index: number, array: readonly T[]) => Promise<R> | R,\n options: { abortOnError?: boolean; limit?: number; signal?: AbortSignal } = {},\n): Promise<R[]> {\n const { abortOnError = false, limit = Infinity, signal } = options;\n\n if (limit < 1) {\n throw new RangeError(`parallel: limit must be at least 1, got ${limit}`);\n }\n\n if (signal?.aborted) {\n throw abortError(signal);\n }\n\n if (array.length === 0) {\n return [];\n }\n\n const results: R[] = new Array(array.length);\n let currentIndex = 0;\n const failFastController = abortOnError ? new AbortController() : undefined;\n\n const worker = async (): Promise<void> => {\n while (true) {\n if (signal?.aborted) {\n throw abortError(signal);\n }\n\n if (failFastController?.signal.aborted) {\n return;\n }\n\n if (currentIndex >= array.length) {\n return;\n }\n\n const index = currentIndex++;\n\n try {\n results[index] = await callback(array[index]!, index, array);\n } catch (err) {\n failFastController?.abort();\n throw err;\n }\n }\n };\n\n const workerCount = Math.min(limit, array.length);\n const workers = Array.from({ length: workerCount }, () => worker());\n\n await Promise.all(workers);\n\n return results;\n}\n","import { abortError } from './abortError';\n\n/**\n * Creates a Promise that resolves after a specified amount of time.\n * If an `AbortSignal` is provided and fires before the delay elapses, the promise rejects with\n * the signal's reason (or a generic `DOMException('Aborted', 'AbortError')`).\n *\n * @example\n * ```ts\n * sleep(1000).then(() => console.log('Hello, world!')); // logs after 1 second\n *\n * // With abort support\n * const controller = new AbortController();\n * await sleep(5000, controller.signal); // rejects immediately when aborted\n * ```\n *\n * @param timeout - The number of milliseconds to wait before resolving the Promise.\n * @param signal - Optional AbortSignal to cancel the sleep early.\n *\n * @returns A Promise that resolves after the specified time.\n */\nexport async function sleep(timeout: number, signal?: AbortSignal): Promise<void> {\n if (!signal) {\n return new Promise((resolve) => setTimeout(resolve, timeout));\n }\n\n if (signal.aborted) {\n return Promise.reject(abortError(signal));\n }\n\n return new Promise<void>((resolve, reject) => {\n const id = setTimeout(() => {\n signal.removeEventListener('abort', onAbort);\n resolve();\n }, timeout);\n\n const onAbort = () => {\n clearTimeout(id);\n signal.removeEventListener('abort', onAbort);\n reject(abortError(signal));\n };\n\n signal.addEventListener('abort', onAbort);\n });\n}\n","import { abortError } from './abortError';\nimport { sleep } from './sleep';\n\nexport type RetryOptions = {\n delay?: number | ((attempt: number) => number);\n onError?: (error: unknown) => void;\n shouldRetry?: (error: unknown, attempt: number) => boolean;\n signal?: AbortSignal;\n timeout?: number;\n times?: number;\n};\n\nfunction buildSignal(timeout: number | undefined, signal: AbortSignal | undefined): AbortSignal | undefined {\n const parts = [timeout !== undefined ? AbortSignal.timeout(timeout) : undefined, signal].filter(\n (s): s is AbortSignal => s != null,\n );\n\n if (parts.length === 0) return undefined;\n\n if (parts.length === 1) return parts[0];\n\n return AbortSignal.any(parts);\n}\n\n/**\n * Retries an async function with optional per-attempt timeout, delay strategy, and abort support.\n * The function receives a merged AbortSignal from the per-attempt timeout and any external signal.\n * On total failure, throws the last error (use `attempt()` to get an `AttemptResult` without throwing).\n *\n * @example\n * ```ts\n * // Basic retry\n * const data = await retry(() => fetch('/api').then(r => r.json()), { times: 3 });\n *\n * // With per-attempt timeout and cancellation\n * const data = await retry(\n * async (signal) => fetch('/api', { signal }).then(r => r.json()),\n * { times: 3, timeout: 5000 },\n * );\n *\n * // As AttemptResult (never throws) — combine with attempt()\n * const result = await attempt(() => retry(fn, { times: 3 }));\n * ```\n *\n * @param fn - Async function to retry. Receives a merged AbortSignal when timeout or signal is set.\n * @param options - Retry configuration.\n * @param [options.times=3] - Total attempts including the first.\n * @param [options.delay=250] - Delay between retries in ms, or a function of (attemptIndex).\n * @param [options.timeout] - Per-attempt timeout in milliseconds.\n * @param [options.signal] - External AbortSignal to cancel all retries.\n * @param [options.shouldRetry] - Predicate called after each non-final failure.\n * Receives the error and the number of failures so far (0-indexed: `0` on the first failure,\n * `1` on the second, etc.). Return `false` to abort immediately. **Not called on the final attempt**\n * (use `onError` to observe the final error unconditionally).\n * @param [options.onError] - Called with the last error before rethrowing — both on final attempt exhaustion\n * and when `shouldRetry` returns `false` to abort early.\n * @returns The resolved value.\n * @throws {RangeError} If `times` is not a positive integer.\n * @throws The last error if all attempts fail.\n */\nexport async function retry<T>(\n fn: (signal?: AbortSignal) => Promise<T>,\n { delay = 250, onError, shouldRetry, signal, timeout, times = 3 }: RetryOptions = {},\n): Promise<T> {\n if (!Number.isInteger(times) || times < 1) {\n throw new RangeError(`retry: times must be a positive integer, got ${times}`);\n }\n\n for (let tryCount = 1; tryCount <= times; tryCount++) {\n if (signal?.aborted) throw abortError(signal);\n\n const callSignal = buildSignal(timeout, signal);\n\n try {\n return await fn(callSignal);\n } catch (err) {\n if (tryCount === times) {\n onError?.(err);\n throw err;\n }\n\n if (shouldRetry && !shouldRetry(err, tryCount - 1)) {\n onError?.(err);\n throw err;\n }\n\n const ms = typeof delay === 'function' ? delay(tryCount - 1) : delay;\n\n if (ms > 0) await sleep(ms, signal);\n }\n }\n\n /* unreachable — the loop always returns or throws before exhausting all attempts */\n return undefined as never;\n}\n","const isDev = !(globalThis as { __ARSENAL_PROD__?: boolean }).__ARSENAL_PROD__;\n\n/** @internal @security Messages may include user data. */\nexport function warn(msg: string): void {\n if (isDev) console.warn(`[@vielzeug/arsenal] ${msg}`);\n}\n","import type { Fn } from '../types';\n\nimport { warn } from '../_dev';\n\nexport type DebounceOptions = {\n /** Invoke on the leading edge of the delay window. Default: `false`. */\n leading?: boolean;\n /** Invoke on the trailing edge of the delay window. Default: `true`. */\n trailing?: boolean;\n};\n\nexport type Debounced<T extends Fn> = ((...args: Parameters<T>) => ReturnType<T> | undefined) & {\n cancel(): void;\n flush(): ReturnType<T> | undefined;\n pending(): boolean;\n};\n\n/**\n * Debounces a function. By default only the trailing edge fires (after input settles).\n * Pass `{ leading: true }` to fire immediately on the first call instead.\n * Pass `{ leading: true, trailing: true }` to fire on both edges.\n *\n * Use `flush()` to invoke immediately, `cancel()` to clear, and `pending()` to check\n * whether an invocation is scheduled.\n *\n * @example\n * ```ts\n * // Trailing (default) — fires after input settles\n * const save = debounce(persist, 500);\n *\n * // Leading — fires on the first keystroke, then silences during the window\n * const submit = debounce(sendRequest, 500, { leading: true, trailing: false });\n * ```\n */\nexport function debounce<T extends Fn>(\n fn: T,\n delay = 300,\n options: DebounceOptions = { leading: false, trailing: true },\n): Debounced<T> {\n const leading = options.leading ?? false;\n const trailing = options.trailing ?? true;\n\n if (!leading && !trailing) {\n warn('debounce: both `leading` and `trailing` are false — the wrapped function will never be invoked.');\n }\n\n let timerId: ReturnType<typeof setTimeout> | undefined;\n let lastArgs: Parameters<T> | undefined;\n let lastResult: ReturnType<T> | undefined;\n let leadingFired = false;\n\n const clearTimer = () => {\n if (timerId !== undefined) {\n clearTimeout(timerId);\n timerId = undefined;\n }\n };\n\n const invokeTrailing = () => {\n clearTimer();\n leadingFired = false;\n\n if (!lastArgs) return undefined;\n\n const args = lastArgs;\n\n lastArgs = undefined;\n lastResult = fn(...args) as ReturnType<T>;\n\n return lastResult;\n };\n\n return Object.assign(\n (...args: Parameters<T>): ReturnType<T> | undefined => {\n lastArgs = args;\n\n if (leading && !leadingFired) {\n leadingFired = true;\n lastResult = fn(...args) as ReturnType<T>;\n // Clear args regardless of `trailing` — the leading call already consumed this\n // invocation. The trailing timer below only re-invokes `fn` if a *further* call\n // arrives during the cooldown window and repopulates `lastArgs`.\n lastArgs = undefined;\n\n if (!trailing) {\n // Leading-only: start cooldown — no trailing call needed\n timerId = setTimeout(() => {\n timerId = undefined;\n leadingFired = false;\n }, delay);\n\n return lastResult;\n }\n }\n\n // When leading-only, ignore calls within the cooldown window\n if (leading && !trailing && leadingFired) return lastResult;\n\n clearTimer();\n timerId = setTimeout(invokeTrailing, delay);\n\n return lastResult;\n },\n {\n cancel: () => {\n clearTimer();\n lastArgs = undefined;\n leadingFired = false;\n },\n flush: (): ReturnType<T> | undefined => invokeTrailing(),\n pending: () => timerId !== undefined,\n },\n );\n}\n","import type { Fn } from '../types';\n\n/**\n * A wrapped function that executes `fn` at most once and exposes a `.reset()` method\n * to allow re-invocation.\n */\nexport type Once<T extends Fn> = T & { reset: () => void };\n\n/**\n * Create a function that runs once and returns the first result.\n *\n * If the first call throws, it does not count as \"called\" — the thrown error propagates to\n * that caller, and the next call will invoke `fn` again (rather than caching the failure).\n *\n * @example\n * ```ts\n * const onceRandom = once(() => Math.random())\n * onceRandom() // 0.3\n * onceRandom() // 0.3\n *\n * onceRandom.reset() // clears the cached result — allows one more invocation\n *\n * onceRandom() // 0.2\n * onceRandom() // 0.2\n * ```\n *\n * @param fn - The function to wrap.\n *\n * @returns A `Once<T>` — the wrapped function with a `.reset()` method to clear the cached result.\n */\nexport const once = <T extends Fn>(fn: T): Once<T> => {\n let result: ReturnType<T> | undefined;\n let called = false;\n\n const wrappedFn = ((...args: Parameters<T>): ReturnType<T> => {\n if (!called) {\n result = fn(...args) as ReturnType<T>;\n called = true;\n }\n\n return result as ReturnType<T>;\n }) as Once<T>;\n\n wrappedFn.reset = () => {\n result = undefined;\n called = false;\n };\n\n return wrappedFn;\n};\n","import type { Fn } from '../types';\n\ntype FirstParameters<T extends readonly Fn[]> = T extends [infer First extends Fn, ...unknown[]]\n ? Parameters<First>\n : never;\ntype LastReturnType<T extends readonly Fn[]> = T extends [...unknown[], infer Last extends Fn]\n ? ReturnType<Last>\n : never;\n\n/**\n * Pipes multiple functions into a single function. It starts from the leftmost function and proceeds to the right.\n *\n * The TypeScript overload captures the input type from the first function and the output type from the last.\n * Intermediate steps are typed as `unknown` at the call site — TypeScript cannot infer a safe chain across\n * heterogeneous function signatures without explicit overloads for every arity.\n *\n * `pipe()` with no arguments returns an identity function `<T>(x: T) => T`.\n *\n * @example\n * ```ts\n * const add = (x: number) => x + 2;\n * const multiply = (x: number) => x * 3;\n * const subtract = (x: number) => x - 4;\n * const pipedFn = pipe(subtract, multiply, add);\n *\n * pipedFn(5); // ((5-4) * 3) + 2 = 5\n *\n * // Zero-arg identity\n * pipe()(42); // 42\n * ```\n *\n * @param fns - List of functions to be piped.\n * @returns A new function that is the pipe of the input functions.\n */\nexport function pipe(): <T>(x: T) => T;\nexport function pipe<T extends readonly [Fn, ...Fn[]]>(...fns: T): (...args: FirstParameters<T>) => LastReturnType<T>;\nexport function pipe(...fns: Fn[]): Fn {\n if (fns.length === 0) return <T>(x: T): T => x;\n\n const [firstFn, ...restFns] = fns;\n\n return (...args: never[]) =>\n restFns.reduce(\n (prev: unknown, fn) => Reflect.apply(fn, undefined, [prev]),\n Reflect.apply(firstFn!, undefined, args),\n );\n}\n","import type { Fn } from '../types';\n\nexport type ThrottleOptions = {\n leading?: boolean; // invoke at the start of the window\n trailing?: boolean; // invoke at the end with the last args\n};\n\nexport type Throttled<T extends Fn> = ((...args: Parameters<T>) => ReturnType<T> | undefined) & {\n cancel(): void;\n flush(): ReturnType<T> | undefined;\n pending(): boolean; // whether there's a pending call that flush() would execute\n};\n\n/**\n * Throttles a function. By default, only the leading edge fires.\n * Pass `{ trailing: true }` to also invoke at the end of the throttle window.\n *\n * @example\n * ```ts\n * const fn = () => { ... };\n * const t = throttle(fn, 700);\n * const withTrailing = throttle(fn, 700, { trailing: true });\n * ```\n */\nexport function throttle<T extends Fn>(\n fn: T,\n delay = 700,\n options: ThrottleOptions = { leading: true, trailing: false },\n): Throttled<T> {\n const leading = options.leading ?? true;\n const trailing = options.trailing ?? false;\n\n let timerId: ReturnType<typeof setTimeout> | undefined;\n let lastInvokeTime = -Infinity;\n let lastArgs: Parameters<T> | undefined;\n let lastResult: ReturnType<T> | undefined;\n\n const clearTimer = () => {\n if (timerId !== undefined) {\n clearTimeout(timerId);\n timerId = undefined;\n }\n };\n\n const scheduleTimer = (delayMs: number) => {\n timerId = setTimeout(timerExpired, delayMs);\n };\n\n const invoke = (now: number) => {\n lastInvokeTime = now;\n clearTimer();\n\n if (!lastArgs) return undefined;\n\n const args = lastArgs;\n\n lastArgs = undefined;\n lastResult = fn(...args) as ReturnType<T>;\n\n return lastResult;\n };\n\n const remaining = (now: number) => delay - (now - lastInvokeTime);\n\n const timerExpired = () => {\n const now = Date.now();\n\n if (lastArgs && remaining(now) <= 0) {\n // trailing edge invoke\n invoke(now);\n } else if (lastArgs) {\n // reschedule until a window elapses\n scheduleTimer(remaining(now));\n } else {\n clearTimer();\n }\n };\n\n return Object.assign(\n (...args: Parameters<T>): ReturnType<T> | undefined => {\n const now = Date.now();\n\n if (lastInvokeTime === -Infinity && !leading) {\n // If leading is false, start the window now but don't invoke immediately\n lastInvokeTime = now;\n }\n\n lastArgs = args;\n\n const rem = remaining(now);\n\n if (rem <= 0) {\n // Window elapsed: invoke now\n return invoke(now);\n } else if (trailing && !timerId) {\n // Schedule trailing call if not already scheduled\n scheduleTimer(rem);\n }\n\n return lastResult;\n },\n {\n cancel: () => {\n clearTimer();\n lastArgs = undefined;\n lastInvokeTime = -Infinity;\n },\n flush: (): ReturnType<T> | undefined => {\n if (!lastArgs) return undefined;\n\n return invoke(Date.now());\n },\n // Pending if a trailing call is scheduled OR there are queued args.\n pending: () => lastArgs !== undefined || timerId !== undefined,\n },\n );\n}\n","import type { Predicate } from '../types';\n\n/**\n * Returns a predicate that is `true` only when every provided predicate is `true`.\n *\n * With zero predicates, returns `true` for all values (vacuous truth).\n *\n * @example\n * ```ts\n * const isPositiveEven = allOf(\n * (n) => n > 0,\n * (n) => n % 2 === 0,\n * );\n * [1, 2, 3, 4].filter(isPositiveEven); // [2, 4]\n * ```\n */\nexport function allOf<T>(...predicates: Predicate<T>[]): Predicate<T> {\n return (value) => predicates.every((predicate) => predicate(value));\n}\n\n/**\n * Returns a predicate that is `true` when at least one provided predicate is `true`.\n *\n * With zero predicates, returns `false` for all values (vacuous falsity).\n *\n * @example\n * ```ts\n * [1, 2, 3, 4].filter(anyOf((n) => n === 1, (n) => n === 3)); // [1, 3]\n * ```\n */\nexport function anyOf<T>(...predicates: Predicate<T>[]): Predicate<T> {\n return (value) => predicates.some((predicate) => predicate(value));\n}\n\n/**\n * Returns a predicate that is `true` when none of the provided predicates match.\n * With a single predicate this is equivalent to logical NOT.\n *\n * With zero predicates, returns `true` for all values (nothing fails — vacuous truth).\n *\n * @example\n * ```ts\n * [1, 2, 3, 4].filter(noneOf((n) => n % 2 === 0)); // [1, 3]\n * ```\n */\nexport function noneOf<T>(...predicates: Predicate<T>[]): Predicate<T> {\n return (value) => predicates.every((predicate) => !predicate(value));\n}\n\n/**\n * Returns a predicate that negates the given predicate.\n *\n * @example\n * ```ts\n * [1, 2, 3, 4].filter(not((n) => n % 2 === 0)); // [1, 3]\n * ```\n */\nexport function not<T>(predicate: Predicate<T>): Predicate<T> {\n return (value) => !predicate(value);\n}\n","/**\n * Checks if a value is defined (not `undefined`).\n *\n * @example\n * ```ts\n * isDefined(123); // true\n * isDefined(undefined); // false\n * isDefined('hello world'); // true\n * isDefined({}); // true\n * isDefined([]); // true\n * isDefined(null); // true\n * ```\n *\n * @param arg - The value to check.\n *\n * @returns `true` if the value is defined, else `false`.\n */\nexport function isDefined<T>(arg: T | undefined): arg is T {\n return arg !== undefined;\n}\n","/**\n * Recursively compares two values for deep equality.\n * Supports plain objects, arrays, `Date`, `Map`, `Set`, `RegExp`, and circular references.\n *\n * Uses `===` for the primitive comparison, so `isEqual(NaN, NaN)` is `false` and\n * `isEqual(0, -0)` is `true` — the opposite of `shallowEqual`, which uses `Object.is` and\n * treats `NaN` as equal to itself and `-0` as distinct from `0`.\n *\n * For one-level-deep reference equality, use `shallowEqual` instead.\n *\n * @example\n * ```ts\n * isEqual([1, 2, 3], [1, 2, 3]); // true\n * isEqual({ a: { b: 2 } }, { a: { b: 2 } }); // true\n * isEqual(new Date('2023-01-01'), new Date('2023-01-01')); // true\n * isEqual(new Map([['k', 1]]), new Map([['k', 1]])); // true\n * ```\n *\n * @param a - First value to compare.\n * @param b - Second value to compare.\n * @returns `true` if the values are deeply equal.\n */\nexport function isEqual(a: unknown, b: unknown): boolean {\n return safeIsEqual(a, b, new WeakMap());\n}\n\nfunction safeIsEqual(a: unknown, b: unknown, visited: WeakMap<object, object>): boolean {\n // Check for strict equality (handles primitives and references)\n if (a === b) return true;\n\n // If either is null or not an object, they're not equal\n if (a == null || b == null || typeof a !== typeof b || typeof a !== 'object' || typeof b !== 'object') return false;\n\n // Check for circular references\n // We only track 'a' because if 'a' is cyclical, 'b' must also be cyclic to be equal\n if (visited.has(a as object)) {\n return visited.get(a as object) === b;\n }\n\n visited.set(a as object, b as object);\n\n // Array comparison\n if (Array.isArray(a) || Array.isArray(b)) {\n if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length) return false;\n\n return a.every((item, idx) => safeIsEqual(item, b[idx], visited));\n }\n\n // Date comparison\n if (a instanceof Date && b instanceof Date) {\n return a.getTime() === b.getTime();\n }\n\n // Map comparison\n if (a instanceof Map && b instanceof Map) {\n if (a.size !== b.size) return false;\n\n for (const [k, v] of a) {\n if (!b.has(k) || !safeIsEqual(v, b.get(k), visited)) return false;\n }\n\n return true;\n }\n\n // Set comparison — fast path for primitive values, deep for objects\n if (a instanceof Set && b instanceof Set) {\n if (a.size !== b.size) return false;\n\n const bItems = [...b];\n\n for (const v of a) {\n // O(1) path for primitives — avoid the O(n) .some() scan\n if (typeof v === 'string' || typeof v === 'number' || typeof v === 'boolean' || v === null || v === undefined) {\n if (!b.has(v)) return false;\n } else if (!bItems.some((bv) => safeIsEqual(v, bv, visited))) {\n return false;\n }\n }\n\n return true;\n }\n\n // RegExp comparison\n if (a instanceof RegExp || b instanceof RegExp) {\n return a instanceof RegExp && b instanceof RegExp && a.source === b.source && a.flags === b.flags;\n }\n\n // Cross-type guards: Map/Set vs plain objects are never equal\n if (a instanceof Map || b instanceof Map) return false;\n\n if (a instanceof Set || b instanceof Set) return false;\n\n // Object comparison\n const keysA = Object.keys(a);\n const keysB = Object.keys(b);\n\n if (keysA.length !== keysB.length) return false;\n\n for (const key of keysA) {\n if (\n !Object.hasOwn(b, key) ||\n !safeIsEqual((a as Record<string, unknown>)[key], (b as Record<string, unknown>)[key], visited)\n )\n return false;\n }\n\n return true;\n}\n","/**\n * Determines if the passed value is null or undefined.\n *\n * @example\n * ```ts\n * isNil(null); // true\n * isNil(undefined); // true\n * isNil(''); // false\n * isNil(0); // false\n * ```\n *\n * @param arg - The argument to be checked.\n *\n * @returns `true` if the value is null or undefined, else `false`.\n */\nexport function isNil(arg: unknown): arg is null | undefined {\n return arg === undefined || arg === null;\n}\n","/**\n * Returns `true` if `value` is a plain object — one with `Object.prototype` or `null` as its\n * prototype. Class instances, `Map`, `Set`, `Array` and other built-ins all return `false`.\n *\n * @example\n * ```ts\n * isPlainObject({}) // true\n * isPlainObject({ a: 1 }) // true\n * isPlainObject(Object.create(null)) // true\n * isPlainObject(new Map()) // false\n * isPlainObject([]) // false\n * isPlainObject(null) // false\n * ```\n */\nexport function isPlainObject(value: unknown): value is Record<string, unknown> {\n if (value == null || typeof value !== 'object') return false;\n\n const prototype = Object.getPrototypeOf(value);\n\n return prototype === Object.prototype || prototype === null;\n}\n","/**\n * Restricts a number to be within a specified range.\n * Both `min` and `max` are optional — omitting one leaves that end unconstrained.\n *\n * @example\n * ```ts\n * clamp(5, 1, 10) // 5 — within range\n * clamp(0, 1, 10) // 1 — below min\n * clamp(15, 1, 10) // 10 — above max\n * clamp(15, 1) // 15 — no max, above min\n * clamp(-5, undefined, 0) // -5 — no min, below max\n * ```\n *\n * @param n - The number to clamp.\n * @param min - Optional lower bound (inclusive).\n * @param max - Optional upper bound (inclusive).\n *\n * @returns The clamped number.\n */\nexport function clamp(n: number, min?: number, max?: number): number {\n if (min != null && n < min) return min;\n\n if (max != null && n > max) return max;\n\n return n;\n}\n","/**\n * Creates an array of numbers from `0` up to, but not including, `stop` with step `1`.\n *\n * @example\n * ```ts\n * range(5) // [0, 1, 2, 3, 4]\n * ```\n */\nexport function range(stop: number): number[];\n/**\n * Creates an array of numbers from `start` up to, but not including, `stop` with step `1`.\n *\n * @example\n * ```ts\n * range(2, 6) // [2, 3, 4, 5]\n * ```\n */\nexport function range(start: number, stop: number): number[];\n/**\n * Creates an array of numbers progressing from `start` up to, but not including, `stop` with a given `step`.\n *\n * @example\n * ```ts\n * range(0, 10, 2) // [0, 2, 4, 6, 8]\n * range(10, 0, -2) // [10, 8, 6, 4, 2]\n * ```\n *\n * @param start - The start of the range.\n * @param stop - The end of the range (exclusive).\n * @param step - The value to increment or decrement by.\n *\n * @returns The range of numbers.\n *\n * @throws {RangeError} If start, stop, or step are not finite numbers, step is 0, or range exceeds maximum size.\n */\nexport function range(start: number, stop: number, step: number): number[];\nexport function range(startOrStop: number, stop?: number, step?: number): number[] {\n const [resolvedStart, resolvedStop, resolvedStep] =\n stop === undefined ? [0, startOrStop, 1] : step === undefined ? [startOrStop, stop, 1] : [startOrStop, stop, step];\n\n if (!Number.isFinite(resolvedStart) || !Number.isFinite(resolvedStop) || !Number.isFinite(resolvedStep)) {\n throw new RangeError('range: start, stop, and step must be finite numbers');\n }\n\n if (resolvedStep === 0) throw new RangeError('range: step cannot be 0');\n\n if (resolvedStart === resolvedStop) {\n return [];\n }\n\n const raw = (resolvedStop - resolvedStart) / resolvedStep;\n const length = Math.max(0, Number.isInteger(raw) ? raw : Math.ceil(raw + Number.EPSILON));\n\n if (length > 10_000_000) throw new RangeError('range: exceeds maximum allowed size of 10,000,000');\n\n return Array.from({ length }, (_, i) => resolvedStart + i * resolvedStep);\n}\n","import type { Obj } from '../types';\n\nimport { UNSAFE_PATH_SEGMENTS } from '../_common/unsafePaths';\n\ntype PathValue<T, P extends string> = P extends `${infer Key}.${infer Rest}`\n ? Key extends keyof T\n ? PathValue<T[Key], Rest>\n : undefined\n : P extends keyof T\n ? T[P]\n : undefined;\n\nfunction pathSegments(path: string): string[] {\n return path\n .replace(/\\[(\\d+)\\]/g, '.$1')\n .replace(/^\\.|\\.$/g, '')\n .split('.')\n .filter(Boolean);\n}\n\nfunction readPath(item: Obj, path: string): unknown {\n let current: unknown = item;\n\n for (const segment of pathSegments(path)) {\n if (UNSAFE_PATH_SEGMENTS.has(segment) || current == null || typeof current !== 'object') return undefined;\n\n current = (current as Record<string, unknown>)[segment];\n\n if (current === undefined) return undefined;\n }\n\n return current;\n}\n\n/**\n * Retrieves a value at a dot-notation or numeric bracket-notation path.\n * Returns `undefined` when the path is missing or contains an unsafe segment.\n * Use `getPathOr` to supply a fallback or `requirePath` to throw on a missing path.\n */\nexport function getPath<T extends Obj, P extends string>(item: T, path: P): PathValue<T, P> | undefined {\n return readPath(item, path) as PathValue<T, P> | undefined;\n}\n\n/**\n * Retrieves a value at a path or returns `fallback` when the path is missing.\n */\nexport function getPathOr<T extends Obj, P extends string, F>(item: T, path: P, fallback: F): PathValue<T, P> | F {\n const value = readPath(item, path);\n\n return (value === undefined ? fallback : value) as PathValue<T, P> | F;\n}\n\n/**\n * Retrieves a value at a path or throws when the path is missing.\n */\nexport function requirePath<T extends Obj, P extends string>(item: T, path: P): Exclude<PathValue<T, P>, undefined> {\n const value = readPath(item, path);\n\n if (value === undefined) throw new TypeError(`Path does not exist: '${path}'`);\n\n return value as Exclude<PathValue<T, P>, undefined>;\n}\n","import { ArsenalSerializationError } from '../errors';\n\nexport type HashOptions = {\n /**\n * What to do when a class instance is encountered (an object whose prototype is\n * neither `Object.prototype` nor `null`).\n *\n * - `'coerce'` (default) — calls `String(value)`.\n * - `'throw'` — throws an `ArsenalSerializationError`.\n */\n onClassInstance?: 'coerce' | 'throw';\n};\n\n/**\n * Produces a deterministic, order-independent string representation of any value.\n * Object keys are sorted alphabetically, so `{ b: 1, a: 2 }` and `{ a: 2, b: 1 }` produce\n * the same output. Handles `Date`, `RegExp`, `Set`, `Map`, and `bigint` in addition to plain JSON.\n *\n * Useful for generating stable cache keys from arbitrary query parameters or options objects.\n *\n * Class instances fall back to `String(value)` by default.\n * Pass `{ onClassInstance: 'throw' }` to throw an `ArsenalSerializationError` instead.\n *\n * @example\n * ```ts\n * hash({ b: 2, a: 1 }) // '{\"a\":1,\"b\":2}'\n * hash([3, 1, 2]) // '[3,1,2]'\n * hash(new Date('2024-01-01T00:00:00Z')) // '[Date:2024-01-01T00:00:00.000Z]'\n * hash(new Set([3, 1, 2])) // '[Set:1,2,3]'\n * hash(new MyClass(), { onClassInstance: 'throw' }) // throws ArsenalSerializationError\n * ```\n *\n * @throws {ArsenalSerializationError} If `options.onClassInstance` is `'throw'` and a class instance is encountered.\n */\nfunction _hash(value: unknown, options: HashOptions | undefined, visited: Set<object>): string {\n if (value === undefined) return 'undefined';\n\n if (value === null) return 'null';\n\n if (typeof value === 'bigint') return `${value}n`;\n\n if (typeof value !== 'object') return JSON.stringify(value);\n\n if (visited.has(value as object)) return '[Circular]';\n\n visited.add(value as object);\n\n if (value instanceof Date) return `[Date:${Number.isNaN(value.getTime()) ? 'Invalid' : value.toISOString()}]`;\n\n if (value instanceof RegExp) return `[RegExp:${value.source}/${value.flags}]`;\n\n if (value instanceof Set)\n return `[Set:${[...value]\n .map((v) => _hash(v, options, visited))\n .sort()\n .join(',')}]`;\n\n if (value instanceof Map) {\n const entries = [...value.entries()]\n .map(([key, entryValue]) => [_hash(key, options, visited), _hash(entryValue, options, visited)] as const)\n .sort(([leftKey, leftValue], [rightKey, rightValue]) =>\n leftKey === rightKey ? leftValue.localeCompare(rightValue) : leftKey.localeCompare(rightKey),\n );\n\n return `[Map:${entries.map(([key, entryValue]) => `${key}=>${entryValue}`).join(',')}]`;\n }\n\n if (Array.isArray(value)) return `[${value.map((v) => _hash(v, options, visited)).join(',')}]`;\n\n const proto = Object.getPrototypeOf(value) as unknown;\n\n if (proto !== Object.prototype && proto !== null) {\n if (options?.onClassInstance === 'throw') {\n throw new ArsenalSerializationError(\n `hash: unsupported type ${(value as { constructor?: { name?: string } }).constructor?.name ?? 'unknown'}`,\n );\n }\n\n return String(value);\n }\n\n const rec = value as Record<string, unknown>;\n const keys = Object.keys(rec)\n .filter((k) => rec[k] !== undefined)\n .sort();\n\n return `{${keys.map((k) => `${JSON.stringify(k)}:${_hash(rec[k], options, visited)}`).join(',')}}`;\n}\n\nexport function hash(value: unknown, options?: HashOptions): string {\n return _hash(value, options, new Set<object>());\n}\n","import type { Obj } from '../types';\n\nimport { isUnsafeKey } from '../_common/unsafePaths';\n\n/**\n * Creates a new object without the selected keys. Only `obj`'s own enumerable keys are\n * considered; dangerous keys (`__proto__`, `constructor`, `prototype`) are always skipped.\n *\n * @example\n * ```ts\n * omit({ a: 1, b: 2, c: 3 }, ['b']); // { a: 1, c: 3 }\n * ```\n *\n * @param obj - The source object.\n * @param omittedKeys - The keys to exclude.\n * @returns A new object with `omittedKeys` removed.\n */\nexport function omit<T extends Obj, K extends keyof T>(obj: T, omittedKeys: readonly K[]): Omit<T, K> {\n const blacklist = new Set<PropertyKey>(omittedKeys as readonly PropertyKey[]);\n const out = {} as Omit<T, K>;\n\n for (const key of Object.keys(obj) as Array<keyof T>) {\n if (isUnsafeKey(key as PropertyKey)) continue;\n\n if (!blacklist.has(key)) {\n (out as T)[key] = obj[key];\n }\n }\n\n return out;\n}\n","import type { Obj } from '../types';\n\nimport { isUnsafeKey } from '../_common/unsafePaths';\n\n/**\n * Creates a new object containing only selected keys. Only `obj`'s own enumerable keys are\n * considered — inherited properties (e.g. `toString`) are never picked, and dangerous keys\n * (`__proto__`, `constructor`, `prototype`) are always skipped.\n *\n * @example\n * ```ts\n * pick({ a: 1, b: 2, c: 3 }, ['a', 'c']); // { a: 1, c: 3 }\n * ```\n *\n * @param obj - The source object.\n * @param selectedKeys - The keys to keep.\n * @returns A new object containing only `selectedKeys` that exist as own properties of `obj`.\n */\nexport function pick<T extends Obj, K extends keyof T>(obj: T, selectedKeys: readonly K[]): Pick<T, K> {\n const out = {} as Pick<T, K>;\n\n for (const key of selectedKeys) {\n if (isUnsafeKey(key as PropertyKey)) continue;\n\n if (Object.hasOwn(obj, key)) {\n out[key] = obj[key];\n }\n }\n\n return out;\n}\n","/**\n * Generates a unique identifier.\n *\n * @example\n * ```ts\n * uuid(); // a unique identifier, e.g., '22a746d0-08be-4aff-bbc2-4deddf0914e0'\n * ```\n *\n * @returns A unique identifier.\n */\nexport function uuid(): string {\n return crypto.randomUUID();\n}\n","/**\n * Shared regex pattern for splitting words in case conversion utilities.\n * Module-private (underscore-prefixed file is not barrel-exported).\n * Used only with String.prototype.replace — which always resets lastIndex.\n * Uses Unicode property escapes (`\\p{Ll}`/`\\p{Lu}`/`\\p{N}`) instead of `[a-z]`/`[A-Z]` so\n * accented and non-Latin letters (e.g. `café`, `日本語`) are treated as letters, not stripped.\n */\nconst CASE_SPLIT_PATTERN = /(\\p{Ll})(\\p{Lu}|\\p{N})|(\\p{Lu}|\\p{N})(\\p{Lu}\\p{Ll})|(\\p{N})(\\p{L})/gu;\n\n/** Escapes all regex metacharacters in a string (per MDN spec). */\nfunction escapeRegex(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\/-]/g, '\\\\$&');\n}\n\n/**\n * Normalizes a string by splitting on word boundaries and removing special characters\n *\n * @param str - The string to normalize\n * @param separator - The separator to use for splitting (default: space)\n * @returns The normalized string\n */\nexport function normalizeCase(str: string, separator = ' '): string {\n const escapedSep = escapeRegex(separator);\n\n return str\n .trim()\n .replace(CASE_SPLIT_PATTERN, `$1$3$5${separator}$2$4$6`)\n .replace(/[^\\p{L}\\p{N}]+/gu, separator)\n .replace(new RegExp(`^(?:${escapedSep})+|(?:${escapedSep})+$`, 'g'), '');\n}\n","import { normalizeCase } from './_caseUtils';\n\n/**\n * Converts a string to camel case.\n *\n * @example\n * ```ts\n * const text = 'hello world';\n * camelCase(text); // 'helloWorld'\n * ```\n *\n * @param str - The string to convert.\n * @returns The converted string.\n */\nexport function camelCase(str: string): string {\n return normalizeCase(str, ' ')\n .replace(/[^\\p{L}\\p{N}]+(.)/gu, (_, char) => char.toUpperCase())\n .replace(/^./, (char) => char.toLowerCase());\n}\n"],"mappings":"mEACA,IAAa,EAAb,MAAa,UAAqB,KAAM,CACtC,YAAY,EAAiB,EAAqB,CAChD,MAAM,EAAS,CAAI,EACnB,KAAK,KAAO,WAAW,KACvB,OAAO,eAAe,KAAM,WAAW,SAAS,CAClD,CAEA,OAAO,GAAG,EAAmC,CAC3C,OAAO,aAAe,CACxB,CACF,EAOa,EAAb,cAA+C,CAAa,CAAC,ECC7D,SAAgB,EAAS,EAAqB,EAAO,EAAqB,CACxE,GAAI,CAAC,MAAM,QAAQ,CAAK,GAAK,OAAO,GAAU,SAC5C,MAAU,UAAU,4CAA4C,EAElE,GAAI,CAAC,OAAO,UAAU,CAAI,GAAK,EAAO,EAAG,MAAU,WAAW,wCAAwC,EAEtG,OAAO,MAAM,KAAK,CAAE,OAAQ,KAAK,KAAK,EAAM,OAAS,CAAI,CAAE,GAAI,EAAG,IAAM,EAAM,MAAM,EAAI,EAAM,EAAI,EAAO,CAAI,CAAC,CAEhH,CCxBA,SAAgB,EAAgB,EAAY,EAAsE,CAChH,IAAM,EAAc,CAAC,EAErB,IAAK,IAAI,EAAQ,EAAG,EAAQ,EAAM,OAAQ,IAAS,CACjD,IAAM,EAAQ,EAAS,EAAM,GAAQ,EAAO,CAAK,EAE7C,IAAU,IAAA,IACZ,EAAO,KAAK,CAAK,CAErB,CAEA,OAAO,CACT,CCVA,IAAa,EAAuB,IAAI,IAAI,CAAC,YAAa,cAAe,WAAW,CAAC,EA4BrF,SAAgB,EAAY,EAA2B,CACrD,OAAO,OAAO,GAAQ,UAAY,EAAqB,IAAI,CAAG,CAChE,CC3BA,SAAgB,EAAW,EAAY,EAAuD,CAC5F,IAAM,EAA8B,CAAC,EAErC,IAAK,IAAM,KAAQ,EAAO,CACxB,IAAM,EAAS,EAAS,CAAI,EACtB,EAAM,GAAmC,KAAO,IAAM,OAAO,CAAM,EAErE,EAAY,CAAG,IAEd,EAAO,KACV,EAAO,GAAO,CAAC,GAGjB,EAAO,EAAI,CAAC,KAAK,CAAI,EACvB,CAEA,OAAO,CACT,CCjBA,SAAgB,EAAW,EAAY,EAAqD,CAC1F,IAAM,EAA4B,CAAC,EAEnC,IAAK,IAAM,KAAQ,EAAO,CACxB,IAAM,EAAM,OAAO,EAAS,CAAI,CAAC,EAE7B,EAAY,CAAG,IAEnB,EAAO,GAAO,EAChB,CAEA,OAAO,CACT,CCjBA,SAAgB,EAAa,EAAY,EAAwE,CAC/G,IAAM,EAAgB,CAAC,EACjB,EAAgB,CAAC,EAEvB,IAAK,IAAI,EAAQ,EAAG,EAAQ,EAAM,OAAQ,IACpC,EAAU,EAAM,GAAQ,EAAO,CAAK,EACtC,EAAS,KAAK,EAAM,EAAM,EAE1B,EAAS,KAAK,EAAM,EAAM,EAI9B,MAAO,CAAC,EAAU,CAAQ,CAC5B,CCaA,IAAa,GAAW,EAAY,IAAuB,CACzD,GAAI,IAAM,EAAG,MAAO,GAEpB,GAAI,IAAM,IAAA,GAAW,MAAO,GAE5B,GAAI,IAAM,IAAA,GAAW,MAAO,GAE5B,GAAI,IAAM,KAAM,OAAO,IAAM,KAAO,EAAI,GAExC,GAAI,IAAM,KAAM,MAAO,GAEvB,GAAI,OAAO,GAAM,UAAY,OAAO,GAAM,SACxC,OAAO,EAAE,cAAc,CAAC,EAG1B,GAAI,OAAO,GAAM,UAAY,OAAO,GAAM,SACxC,OAAO,IAAM,EAAI,EAAI,EAAI,EAAI,EAAI,GAGnC,GAAI,aAAa,MAAQ,aAAa,KAAM,CAC1C,IAAM,EAAK,EAAE,QAAQ,EACf,EAAK,EAAE,QAAQ,EAErB,OAAO,IAAO,EAAK,EAAI,EAAK,EAAK,EAAI,EACvC,CAEA,MAAU,UACR,+BAA+B,OAAO,EAAE,SAAS,OAAO,EAAE,qDAC5D,CACF,EClCa,EAAgB,GAAwD,CACnF,IAAM,EAAU,OAAO,QAAQ,CAAS,EAExC,OAAQ,EAAM,IAAS,CACrB,IAAK,GAAM,CAAC,EAAK,KAAc,EAAS,CACtC,IAAM,EAAK,EAAE,GACP,EAAK,EAAE,GACP,EAAM,IAAc,OAAS,GAAK,EAElC,EAAM,EAAQ,EAAI,CAAE,EAE1B,GAAI,IAAQ,EAAG,OAAO,EAAM,CAC9B,CAEA,MAAO,EACT,CACF,ECXA,SAAgB,EACd,EACA,EACA,EAA2B,MACtB,CACL,GAAI,CAAC,MAAM,QAAQ,CAAK,EAAG,MAAU,UAAU,uCAAuC,EAEtF,GAAI,OAAO,GAAwB,WAAY,CAC7C,IAAM,EAAa,IAAc,OAAS,GAAK,EAE/C,MAAO,CAAC,GAAG,CAAK,CAAC,CAAC,MAAM,EAAG,IAAM,EAAQ,EAAoB,CAAC,EAAG,EAAoB,CAAC,CAAC,EAAI,CAAU,CACvG,CAEA,MAAO,CAAC,GAAG,CAAK,CAAC,CAAC,KAAK,EAAU,CAAmB,CAAC,CACvD,CCvBA,SAAgB,EAAoB,EAAqB,EAAuC,CAC9F,IAAM,EAAO,IAAI,IACX,EAAW,CAAC,EAElB,IAAK,IAAM,KAAQ,EAAO,CACxB,IAAM,EAAM,EAAS,CAAI,EAErB,EAAK,IAAI,CAAG,IAEhB,EAAK,IAAI,CAAG,EACZ,EAAI,KAAK,CAAI,EACf,CAEA,OAAO,CACT,CCfA,SAAgB,EAAQ,EAAY,EAAwC,CAS1E,OARI,EAAM,QAAU,EACX,CAAC,GAAG,CAAK,EAGb,EAIE,EAAiB,EAAO,CAAQ,EAH9B,CAAC,GAAG,IAAI,IAAI,CAAK,CAAC,CAI7B,CCfA,SAAgB,EAAQ,EAA4D,CAClF,OAAO,EAAO,KAAO,EACvB,CAWA,SAAgB,EAAU,EAAmE,CAC3F,OAAO,EAAO,KAAO,EACvB,CAsBA,eAAsB,EAAW,EAAqD,CACpF,GAAI,CACF,MAAO,CAAE,GAAI,GAAM,MAAO,MAAM,EAAG,CAAE,CACvC,OAAS,EAAO,CACd,MAAO,CAAE,QAAO,GAAI,EAAM,CAC5B,CACF,CCpCA,SAAgB,EAAW,EAA+B,CACxD,OAAO,GAAQ,QAAU,IAAI,aAAa,UAAW,YAAY,CACnE,CCeA,eAAsB,EACpB,EACA,EACA,EAA4E,CAAC,EAC/D,CACd,GAAM,CAAE,eAAe,GAAO,QAAQ,IAAU,UAAW,EAE3D,GAAI,EAAQ,EACV,MAAU,WAAW,2CAA2C,GAAO,EAGzE,GAAI,GAAQ,QACV,MAAM,EAAW,CAAM,EAGzB,GAAI,EAAM,SAAW,EACnB,MAAO,CAAC,EAGV,IAAM,EAAmB,MAAM,EAAM,MAAM,EACvC,EAAe,EACb,EAAqB,EAAe,IAAI,gBAAoB,IAAA,GAE5D,EAAS,SAA2B,CACxC,OAAa,CACX,GAAI,GAAQ,QACV,MAAM,EAAW,CAAM,EAOzB,GAJI,GAAoB,OAAO,SAI3B,GAAgB,EAAM,OACxB,OAGF,IAAM,EAAQ,IAEd,GAAI,CACF,EAAQ,GAAS,MAAM,EAAS,EAAM,GAAS,EAAO,CAAK,CAC7D,OAAS,EAAK,CAEZ,MADA,GAAoB,MAAM,EACpB,CACR,CACF,CACF,EAEM,EAAc,KAAK,IAAI,EAAO,EAAM,MAAM,EAC1C,EAAU,MAAM,KAAK,CAAE,OAAQ,CAAY,MAAS,EAAO,CAAC,EAIlE,OAFA,MAAM,QAAQ,IAAI,CAAO,EAElB,CACT,CCvEA,eAAsB,EAAM,EAAiB,EAAqC,CAShF,OARK,EAID,EAAO,QACF,QAAQ,OAAO,EAAW,CAAM,CAAC,EAGnC,IAAI,SAAe,EAAS,IAAW,CAC5C,IAAM,EAAK,eAAiB,CAC1B,EAAO,oBAAoB,QAAS,CAAO,EAC3C,EAAQ,CACV,EAAG,CAAO,EAEJ,MAAgB,CACpB,aAAa,CAAE,EACf,EAAO,oBAAoB,QAAS,CAAO,EAC3C,EAAO,EAAW,CAAM,CAAC,CAC3B,EAEA,EAAO,iBAAiB,QAAS,CAAO,CAC1C,CAAC,EApBQ,IAAI,QAAS,GAAY,WAAW,EAAS,CAAO,CAAC,CAqBhE,CChCA,SAAS,EAAY,EAA6B,EAA0D,CAC1G,IAAM,EAAQ,CAAC,IAAY,IAAA,GAA2C,IAAA,GAA/B,YAAY,QAAQ,CAAO,EAAe,CAAM,CAAC,CAAC,OACtF,GAAwB,GAAK,IAChC,EAEI,KAAM,SAAW,EAIrB,OAFI,EAAM,SAAW,EAAU,EAAM,GAE9B,YAAY,IAAI,CAAK,CAC9B,CAsCA,eAAsB,EACpB,EACA,CAAE,QAAQ,IAAK,UAAS,cAAa,SAAQ,UAAS,QAAQ,GAAoB,CAAC,EACvE,CACZ,GAAI,CAAC,OAAO,UAAU,CAAK,GAAK,EAAQ,EACtC,MAAU,WAAW,gDAAgD,GAAO,EAG9E,IAAK,IAAI,EAAW,EAAG,GAAY,EAAO,IAAY,CACpD,GAAI,GAAQ,QAAS,MAAM,EAAW,CAAM,EAE5C,IAAM,EAAa,EAAY,EAAS,CAAM,EAE9C,GAAI,CACF,OAAO,MAAM,EAAG,CAAU,CAC5B,OAAS,EAAK,CAMZ,GALI,IAAa,GAKb,GAAe,CAAC,EAAY,EAAK,EAAW,CAAC,EAE/C,MADA,IAAU,CAAG,EACP,EAGR,IAAM,EAAK,OAAO,GAAU,WAAa,EAAM,EAAW,CAAC,EAAI,EAE3D,EAAK,GAAG,MAAM,EAAM,EAAI,CAAM,CACpC,CACF,CAIF,CE5DA,SAAgB,EACd,EACA,EAAQ,IACR,EAA2B,CAAE,QAAS,GAAO,SAAU,EAAK,EAC9C,CACd,IAAM,EAAU,EAAQ,SAAW,GAC7B,EAAW,EAAQ,UAAY,GAMjC,EACA,EACA,EACA,EAAe,GAEb,MAAmB,CACnB,IAAY,IAAA,KACd,aAAa,CAAO,EACpB,EAAU,IAAA,GAEd,EAEM,MAAuB,CAI3B,GAHA,EAAW,EACX,EAAe,GAEX,CAAC,EAAU,OAEf,IAAM,EAAO,EAKb,MAHA,GAAW,IAAA,GACX,EAAa,EAAG,GAAG,CAAI,EAEhB,CACT,EAEA,OAAO,OAAO,QACX,GAAG,KACF,EAAW,EAEP,GAAW,CAAC,IACd,EAAe,GACf,EAAa,EAAG,GAAG,CAAI,EAIvB,EAAW,IAAA,GAEP,CAAC,IAEH,EAAU,eAAiB,CACzB,EAAU,IAAA,GACV,EAAe,EACjB,EAAG,CAAK,EAED,GAKP,GAAW,CAAC,GAAY,EAAqB,GAEjD,EAAW,EACX,EAAU,WAAW,EAAgB,CAAK,EAEnC,IAET,CACE,WAAc,CACZ,EAAW,EACX,EAAW,IAAA,GACX,EAAe,EACjB,EACA,UAAwC,EAAe,EACvD,YAAe,IAAY,IAAA,EAC7B,CACF,CACF,CCnFA,IAAa,EAAsB,GAAmB,CACpD,IAAI,EACA,EAAS,GAEP,IAAc,GAAG,KACrB,AAEE,KADA,EAAS,EAAG,GAAG,CAAI,EACV,IAGJ,IAQT,MALA,GAAU,UAAc,CACtB,EAAS,IAAA,GACT,EAAS,EACX,EAEO,CACT,ECbA,SAAgB,EAAK,GAAG,EAAe,CACrC,GAAI,EAAI,SAAW,EAAG,MAAW,IAAY,EAE7C,GAAM,CAAC,EAAS,GAAG,GAAW,EAE9B,OAAQ,GAAG,IACT,EAAQ,QACL,EAAe,IAAO,QAAQ,MAAM,EAAI,IAAA,GAAW,CAAC,CAAI,CAAC,EAC1D,QAAQ,MAAM,EAAU,IAAA,GAAW,CAAI,CACzC,CACJ,CCtBA,SAAgB,EACd,EACA,EAAQ,IACR,EAA2B,CAAE,QAAS,GAAM,SAAU,EAAM,EAC9C,CACd,IAAM,EAAU,EAAQ,SAAW,GAC7B,EAAW,EAAQ,UAAY,GAEjC,EACA,EAAiB,KACjB,EACA,EAEE,MAAmB,CACnB,IAAY,IAAA,KACd,aAAa,CAAO,EACpB,EAAU,IAAA,GAEd,EAEM,EAAiB,GAAoB,CACzC,EAAU,WAAW,EAAc,CAAO,CAC5C,EAEM,EAAU,GAAgB,CAI9B,GAHA,EAAiB,EACjB,EAAW,EAEP,CAAC,EAAU,OAEf,IAAM,EAAO,EAKb,MAHA,GAAW,IAAA,GACX,EAAa,EAAG,GAAG,CAAI,EAEhB,CACT,EAEM,EAAa,GAAgB,GAAS,EAAM,GAE5C,MAAqB,CACzB,IAAM,EAAM,KAAK,IAAI,EAEjB,GAAY,EAAU,CAAG,GAAK,EAEhC,EAAO,CAAG,EACD,EAET,EAAc,EAAU,CAAG,CAAC,EAE5B,EAAW,CAEf,EAEA,OAAO,OAAO,QACX,GAAG,IAAmD,CACrD,IAAM,EAAM,KAAK,IAAI,EAEjB,IAAmB,MAAa,CAAC,IAEnC,EAAiB,GAGnB,EAAW,EAEX,IAAM,EAAM,EAAU,CAAG,EAUzB,OARI,GAAO,EAEF,EAAO,CAAG,GACR,GAAY,CAAC,GAEtB,EAAc,CAAG,EAGZ,EACT,EACA,CACE,WAAc,CACZ,EAAW,EACX,EAAW,IAAA,GACX,EAAiB,IACnB,EACA,UAAwC,CACjC,KAEL,OAAO,EAAO,KAAK,IAAI,CAAC,CAC1B,EAEA,YAAe,IAAa,IAAA,IAAa,IAAY,IAAA,EACvD,CACF,CACF,CCpGA,SAAgB,EAAS,GAAG,EAA0C,CACpE,MAAQ,IAAU,EAAW,MAAO,GAAc,EAAU,CAAK,CAAC,CACpE,CAYA,SAAgB,EAAS,GAAG,EAA0C,CACpE,MAAQ,IAAU,EAAW,KAAM,GAAc,EAAU,CAAK,CAAC,CACnE,CAaA,SAAgB,EAAU,GAAG,EAA0C,CACrE,MAAQ,IAAU,EAAW,MAAO,GAAc,CAAC,EAAU,CAAK,CAAC,CACrE,CAUA,SAAgB,EAAO,EAAuC,CAC5D,MAAQ,IAAU,CAAC,EAAU,CAAK,CACpC,CC1CA,SAAgB,EAAa,EAA8B,CACzD,OAAO,IAAQ,IAAA,EACjB,CCGA,SAAgB,EAAQ,EAAY,EAAqB,CACvD,OAAO,EAAY,EAAG,EAAG,IAAI,OAAS,CACxC,CAEA,SAAS,EAAY,EAAY,EAAY,EAA2C,CAEtF,GAAI,IAAM,EAAG,MAAO,GAGpB,GAAI,GAAK,MAAQ,GAAK,MAAQ,OAAO,GAAM,OAAO,GAAK,OAAO,GAAM,UAAY,OAAO,GAAM,SAAU,MAAO,GAI9G,GAAI,EAAQ,IAAI,CAAW,EACzB,OAAO,EAAQ,IAAI,CAAW,IAAM,EAMtC,GAHA,EAAQ,IAAI,EAAa,CAAW,EAGhC,MAAM,QAAQ,CAAC,GAAK,MAAM,QAAQ,CAAC,EAGrC,MAFI,CAAC,MAAM,QAAQ,CAAC,GAAK,CAAC,MAAM,QAAQ,CAAC,GAAK,EAAE,SAAW,EAAE,OAAe,GAErE,EAAE,OAAO,EAAM,IAAQ,EAAY,EAAM,EAAE,GAAM,CAAO,CAAC,EAIlE,GAAI,aAAa,MAAQ,aAAa,KACpC,OAAO,EAAE,QAAQ,IAAM,EAAE,QAAQ,EAInC,GAAI,aAAa,KAAO,aAAa,IAAK,CACxC,GAAI,EAAE,OAAS,EAAE,KAAM,MAAO,GAE9B,IAAK,GAAM,CAAC,EAAG,KAAM,EACnB,GAAI,CAAC,EAAE,IAAI,CAAC,GAAK,CAAC,EAAY,EAAG,EAAE,IAAI,CAAC,EAAG,CAAO,EAAG,MAAO,GAG9D,MAAO,EACT,CAGA,GAAI,aAAa,KAAO,aAAa,IAAK,CACxC,GAAI,EAAE,OAAS,EAAE,KAAM,MAAO,GAE9B,IAAM,EAAS,CAAC,GAAG,CAAC,EAEpB,IAAK,IAAM,KAAK,EAEd,GAAI,OAAO,GAAM,UAAY,OAAO,GAAM,UAAY,OAAO,GAAM,WAAa,GAAM,KAChF,IAAA,CAAC,EAAE,IAAI,CAAC,EAAG,MAAO,EAAA,MACjB,GAAI,CAAC,EAAO,KAAM,GAAO,EAAY,EAAG,EAAI,CAAO,CAAC,EACzD,MAAO,GAIX,MAAO,EACT,CAGA,GAAI,aAAa,QAAU,aAAa,OACtC,OAAO,aAAa,QAAU,aAAa,QAAU,EAAE,SAAW,EAAE,QAAU,EAAE,QAAU,EAAE,MAM9F,GAFI,aAAa,KAAO,aAAa,KAEjC,aAAa,KAAO,aAAa,IAAK,MAAO,GAGjD,IAAM,EAAQ,OAAO,KAAK,CAAC,EACrB,EAAQ,OAAO,KAAK,CAAC,EAE3B,GAAI,EAAM,SAAW,EAAM,OAAQ,MAAO,GAE1C,IAAK,IAAM,KAAO,EAChB,GACE,CAAC,OAAO,OAAO,EAAG,CAAG,GACrB,CAAC,EAAa,EAA8B,GAAO,EAA8B,GAAM,CAAO,EAE9F,MAAO,GAGX,MAAO,EACT,CC5FA,SAAgB,EAAM,EAAuC,CAC3D,OAAO,GAA6B,IACtC,CCHA,SAAgB,EAAc,EAAkD,CAC9E,GAAqB,OAAO,GAAU,WAAlC,EAA4C,MAAO,GAEvD,IAAM,EAAY,OAAO,eAAe,CAAK,EAE7C,OAAO,IAAc,OAAO,WAAa,IAAc,IACzD,CCDA,SAAgB,EAAM,EAAW,EAAc,EAAsB,CAKnE,OAJI,GAAO,MAAQ,EAAI,EAAY,EAE/B,GAAO,MAAQ,EAAI,EAAY,EAE5B,CACT,CCWA,SAAgB,EAAM,EAAqB,EAAe,EAAyB,CACjF,GAAM,CAAC,EAAe,EAAc,GAClC,IAAS,IAAA,GAAY,CAAC,EAAG,EAAa,CAAC,EAAI,IAAS,IAAA,GAAY,CAAC,EAAa,EAAM,CAAC,EAAI,CAAC,EAAa,EAAM,CAAI,EAEnH,GAAI,CAAC,OAAO,SAAS,CAAa,GAAK,CAAC,OAAO,SAAS,CAAY,GAAK,CAAC,OAAO,SAAS,CAAY,EACpG,MAAU,WAAW,qDAAqD,EAG5E,GAAI,IAAiB,EAAG,MAAU,WAAW,yBAAyB,EAEtE,GAAI,IAAkB,EACpB,MAAO,CAAC,EAGV,IAAM,GAAO,EAAe,GAAiB,EACvC,EAAS,KAAK,IAAI,EAAG,OAAO,UAAU,CAAG,EAAI,EAAM,KAAK,KAAK,QAAoB,CAAC,EAExF,GAAI,EAAS,IAAY,MAAU,WAAW,mDAAmD,EAEjG,OAAO,MAAM,KAAK,CAAE,QAAO,GAAI,EAAG,IAAM,EAAgB,EAAI,CAAY,CAC1E,CC5CA,SAAS,EAAa,EAAwB,CAC5C,OAAO,EACJ,QAAQ,aAAc,KAAK,CAAC,CAC5B,QAAQ,WAAY,EAAE,CAAC,CACvB,MAAM,GAAG,CAAC,CACV,OAAO,OAAO,CACnB,CAEA,SAAS,EAAS,EAAW,EAAuB,CAClD,IAAI,EAAmB,EAEvB,IAAK,IAAM,KAAW,EAAa,CAAI,EAKrC,GAJI,EAAqB,IAAI,CAAO,GAAwB,OAAO,GAAY,WAAtC,IAEzC,EAAW,EAAoC,GAE3C,IAAY,IAAA,IAAW,OAG7B,OAAO,CACT,CAOA,SAAgB,EAAyC,EAAS,EAAsC,CACtG,OAAO,EAAS,EAAM,CAAI,CAC5B,CAKA,SAAgB,EAA8C,EAAS,EAAS,EAAkC,CAChH,IAAM,EAAQ,EAAS,EAAM,CAAI,EAEjC,OAAQ,IAAU,IAAA,GAAY,EAAW,CAC3C,CAKA,SAAgB,EAA6C,EAAS,EAA8C,CAClH,IAAM,EAAQ,EAAS,EAAM,CAAI,EAEjC,GAAI,IAAU,IAAA,GAAW,MAAU,UAAU,yBAAyB,EAAK,EAAE,EAE7E,OAAO,CACT,CC3BA,SAAS,EAAM,EAAgB,EAAkC,EAA8B,CAC7F,GAAI,IAAU,IAAA,GAAW,MAAO,YAEhC,GAAI,IAAU,KAAM,MAAO,OAE3B,GAAI,OAAO,GAAU,SAAU,MAAO,GAAG,EAAM,GAE/C,GAAI,OAAO,GAAU,SAAU,OAAO,KAAK,UAAU,CAAK,EAE1D,GAAI,EAAQ,IAAI,CAAe,EAAG,MAAO,aAIzC,GAFA,EAAQ,IAAI,CAAe,EAEvB,aAAiB,KAAM,MAAO,SAAS,OAAO,MAAM,EAAM,QAAQ,CAAC,EAAI,UAAY,EAAM,YAAY,EAAE,GAE3G,GAAI,aAAiB,OAAQ,MAAO,WAAW,EAAM,OAAO,GAAG,EAAM,MAAM,GAE3E,GAAI,aAAiB,IACnB,MAAO,QAAQ,CAAC,GAAG,CAAK,CAAC,CACtB,IAAK,GAAM,EAAM,EAAG,EAAS,CAAO,CAAC,CAAC,CACtC,KAAK,CAAC,CACN,KAAK,GAAG,EAAE,GAEf,GAAI,aAAiB,IAOnB,MAAO,QANS,CAAC,GAAG,EAAM,QAAQ,CAAC,CAAC,CACjC,KAAK,CAAC,EAAK,KAAgB,CAAC,EAAM,EAAK,EAAS,CAAO,EAAG,EAAM,EAAY,EAAS,CAAO,CAAC,CAAU,CAAC,CACxG,MAAM,CAAC,EAAS,GAAY,CAAC,EAAU,KACtC,IAAY,EAAW,EAAU,cAAc,CAAU,EAAI,EAAQ,cAAc,CAAQ,CAGhF,CAAA,CAAQ,KAAK,CAAC,EAAK,KAAgB,GAAG,EAAI,IAAI,GAAY,CAAC,CAAC,KAAK,GAAG,EAAE,GAGvF,GAAI,MAAM,QAAQ,CAAK,EAAG,MAAO,IAAI,EAAM,IAAK,GAAM,EAAM,EAAG,EAAS,CAAO,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,GAE5F,IAAM,EAAQ,OAAO,eAAe,CAAK,EAEzC,GAAI,IAAU,OAAO,WAAa,IAAU,KAAM,CAChD,GAAI,GAAS,kBAAoB,QAC/B,MAAM,IAAI,EACR,0BAA2B,EAA8C,aAAa,MAAQ,WAChG,EAGF,OAAO,OAAO,CAAK,CACrB,CAEA,IAAM,EAAM,EAKZ,MAAO,IAJM,OAAO,KAAK,CAAG,CAAC,CAC1B,OAAQ,GAAM,EAAI,KAAO,IAAA,EAAS,CAAC,CACnC,KAEQ,CAAA,CAAK,IAAK,GAAM,GAAG,KAAK,UAAU,CAAC,EAAE,GAAG,EAAM,EAAI,GAAI,EAAS,CAAO,GAAG,CAAC,CAAC,KAAK,GAAG,EAAE,EAClG,CAEA,SAAgB,EAAK,EAAgB,EAA+B,CAClE,OAAO,EAAM,EAAO,EAAS,IAAI,GAAa,CAChD,CC1EA,SAAgB,EAAuC,EAAQ,EAAuC,CACpG,IAAM,EAAY,IAAI,IAAiB,CAAqC,EACtE,EAAM,CAAC,EAEb,IAAK,IAAM,KAAO,OAAO,KAAK,CAAG,EAC3B,EAAY,CAAkB,GAE7B,EAAU,IAAI,CAAG,IACpB,EAAW,GAAO,EAAI,IAI1B,OAAO,CACT,CCZA,SAAgB,EAAuC,EAAQ,EAAwC,CACrG,IAAM,EAAM,CAAC,EAEb,IAAK,IAAM,KAAO,EACZ,EAAY,CAAkB,GAE9B,OAAO,OAAO,EAAK,CAAG,IACxB,EAAI,GAAO,EAAI,IAInB,OAAO,CACT,CCpBA,SAAgB,GAAe,CAC7B,OAAO,OAAO,WAAW,CAC3B,CCLA,IAAM,EAAqB,uEAG3B,SAAS,EAAY,EAAqB,CACxC,OAAO,EAAI,QAAQ,wBAAyB,MAAM,CACpD,CASA,SAAgB,EAAc,EAAa,EAAY,IAAa,CAClE,IAAM,EAAa,EAAY,CAAS,EAExC,OAAO,EACJ,KAAK,CAAC,CACN,QAAQ,EAAoB,SAAS,EAAU,OAAO,CAAC,CACvD,QAAQ,mBAAoB,CAAS,CAAC,CACtC,QAAY,OAAO,OAAO,EAAW,QAAQ,EAAW,KAAM,GAAG,EAAG,EAAE,CAC3E,CCfA,SAAgB,EAAU,EAAqB,CAC7C,OAAO,EAAc,EAAK,GAAG,CAAC,CAC3B,QAAQ,uBAAwB,EAAG,IAAS,EAAK,YAAY,CAAC,CAAC,CAC/D,QAAQ,KAAO,GAAS,EAAK,YAAY,CAAC,CAC/C"}
|