{"version":3,"file":"core.umd.cjs","names":["#Mulberry32","#Split"],"sources":["../src/helpers.ts","../src/models/exceptions/core.ts","../src/models/exceptions/index.ts","../src/models/iterators/smart-iterator.ts","../src/models/aggregators/reduced-iterator.ts","../src/models/aggregators/aggregated-async-iterator.ts","../src/models/iterators/smart-async-iterator.ts","../src/models/aggregators/aggregated-iterator.ts","../src/models/callbacks/callable-object.ts","../src/models/callbacks/callback-chain.ts","../src/models/callbacks/publisher.ts","../src/models/callbacks/switchable-callback.ts","../src/models/collections/array-view.ts","../src/models/collections/map-view.ts","../src/models/collections/set-view.ts","../src/models/json/json-storage.ts","../src/models/promises/smart-promise.ts","../src/models/promises/deferred-promise.ts","../src/models/promises/timed-promise.ts","../src/models/promises/promise-queue.ts","../src/utils/date.ts","../src/models/timers/game-loop.ts","../src/models/timers/clock.ts","../src/models/timers/countdown.ts","../src/utils/curve.ts","../src/utils/random.ts","../src/utils/async.ts","../src/utils/dom.ts","../src/utils/iterator.ts","../src/utils/math.ts","../src/utils/string.ts","../src/index.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/ban-ts-comment */\n\n/**\n * An utility constant that indicates whether the current environment is a browser.\n */\n// @ts-ignore\nexport const isBrowser = ((typeof window !== \"undefined\") && (typeof window.document !== \"undefined\"));\n\n/**\n * An utility constant that indicates whether the current environment is a Node.js runtime.\n */\n// @ts-ignore\nexport const isNode = ((typeof process !== \"undefined\") && !!(process.versions?.node));\n\n/**\n * An utility constant that indicates whether the current environment is a Web Worker.\n */\n// @ts-ignore\nexport const isWorker = ((typeof self === \"object\") && (self.constructor?.name === \"DedicatedWorkerGlobalScope\"));\n","/**\n * A class representing an exception, subclass of the native {@link Error} class.  \n * It's the base class for any other further exception.\n *\n * It allows to chain exceptions together, tracking the initial cause of an error and\n * storing its stack trace while providing a clear and friendly message to the user.\n *\n * ---\n *\n * @example\n * ```ts\n * try { loadGameSaves(); }\n * catch (error)\n * {\n *     throw new Exception(\"The game saves may be corrupted. Try to restart the game.\", error);\n *     // Uncaught Exception: The game saves may be corrupted. Try to restart the game.\n *     //     at /src/game/index.ts:37:15\n *     //     at /src/main.ts:23:17\n *     // Caused by: SyntaxError: Unexpected end of JSON input\n *     //     at /src/models/saves.ts:47:17\n *     //     at /src/game/index.ts:12:9\n *     //     at /src/main.ts:23:17\n * }\n * ```\n */\nexport default class Exception extends Error\n{\n    /**\n     * A static method to convert a generic caught error, ensuring it's an instance of the {@link Exception} class.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * try { [...] }\n     * catch (error)\n     * {\n     *     const exc = Exception.FromUnknown(error);\n     *\n     *     [...]\n     * }\n     * ```\n     *\n     * ---\n     *\n     * @param error The caught error to convert.\n     *\n     * @returns An instance of the {@link Exception} class.\n     */\n    public static FromUnknown(error: unknown): Exception\n    {\n        if (error instanceof Exception)\n        {\n            return error;\n        }\n        if (error instanceof Error)\n        {\n            const exc = new Exception(error.message);\n\n            exc.stack = error.stack;\n            exc.cause = error.cause;\n            exc.name = error.name;\n\n            return exc;\n        }\n\n        return new Exception(`${error}`);\n    }\n\n    /**\n     * Initializes a new instance of the {@link Exception} class.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * throw new Exception(\"An error occurred while processing the request.\");\n     * ```\n     *\n     * ---\n     *\n     * @param message The message that describes the error.\n     * @param cause The previous caught error that caused this one, if any.\n     * @param name The name of the exception. Default is `\"Exception\"`.\n     */\n    public constructor(message: string, cause?: unknown, name = \"Exception\")\n    {\n        super(message);\n\n        this.cause = cause;\n        this.name = name;\n    }\n\n    public readonly [Symbol.toStringTag]: string = \"Exception\";\n}\n\n/**\n * An utility class representing that kind of situation where the program should never reach.  \n * Also commonly used to satisfy the type-system, but not part of a real feasible scenario.\n *\n * It provides a clear and friendly message by default.\n *\n * ---\n *\n * @example\n * ```ts\n * function checkCase(value: \"A\" | \"B\" | \"C\"): 1 | 2 | 3\n * {\n *     switch (value)\n *     {\n *         case \"A\": return 1;\n *         case \"B\": return 2;\n *         case \"C\": return 3;\n *         default: throw new FatalErrorException();\n *     }\n * }\n * ```\n */\nexport class FatalErrorException extends Exception\n{\n    /**\n     * Initializes a new instance of the {@link FatalErrorException} class.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * throw new FatalErrorException(\"This error should never happen. Please, contact the support team.\");\n     * ```\n     *\n     * ---\n     *\n     * @param message The message that describes the error.\n     * @param cause The previous caught error that caused this one, if any.\n     * @param name The name of the exception. Default is `\"FatalErrorException\"`.\n     */\n    public constructor(message?: string, cause?: unknown, name = \"FatalErrorException\")\n    {\n        if (message === undefined)\n        {\n            message = \"The program has encountered an unrecoverable error and cannot continue as expected. \" +\n                \"Please, try again later. If the problem persists, contact the support team.\";\n        }\n\n        super(message, cause, name);\n    }\n\n    public override readonly [Symbol.toStringTag]: string = \"FatalErrorException\";\n}\n\n/**\n * An utility class representing a situation where a feature isn't implemented yet.  \n * It's commonly used as a placeholder for future implementations.\n *\n * It provides a clear and friendly message by default.\n *\n * ---\n *\n * @example\n * ```ts\n * class Database\n * {\n *     public async connect(): Promise<void>\n *     {\n *         throw new NotImplementedException();\n *     }\n * }\n * ```\n */\nexport class NotImplementedException extends FatalErrorException\n{\n    /**\n     * Initializes a new instance of the {@link NotImplementedException} class.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * throw new NotImplementedException(\"This method hasn't been implemented yet. Check back later.\");\n     * ```\n     *\n     * ---\n     *\n     * @param message The message that describes the error.\n     * @param cause The previous caught error that caused this one, if any.\n     * @param name The name of the exception. Default is `\"NotImplementedException\"`.\n     */\n    public constructor(message?: string, cause?: unknown, name = \"NotImplementedException\")\n    {\n        if (message === undefined)\n        {\n            message = \"This feature isn't implemented yet. Please, try again later.\";\n        }\n\n        super(message, cause, name);\n    }\n\n    public override readonly [Symbol.toStringTag]: string = \"NotImplementedException\";\n}\n","import Exception from \"./core.js\";\n\n/**\n * A class representing a generic exception that can be thrown when a file\n * operation fails, such as reading, writing, copying, moving, deleting, etc...\n *\n * It can also be used to catch all file-related exceptions at once.\n *\n * ---\n *\n * @example\n * ```ts\n * try { [...] }\n * catch (error)\n * {\n *     if (error instanceof FileException)\n *     {\n *         // A file-related exception occurred. Handle it...\n *     }\n * }\n * ```\n */\nexport class FileException extends Exception\n{\n    /**\n     * Initializes a new instance of the {@link FileException} class.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * throw new FileException(\"An error occurred while trying to read the file.\");\n     * ```\n     *\n     * ---\n     *\n     * @param message The message that describes the error.\n     * @param cause The previous caught error that caused this one, if any.\n     * @param name The name of the exception. Default is `\"FileException\"`.\n     */\n    public constructor(message: string, cause?: unknown, name = \"FileException\")\n    {\n        super(message, cause, name);\n    }\n\n    public override readonly [Symbol.toStringTag]: string = \"FileException\";\n}\n\n/**\n * A class representing an exception that can be thrown when a file already exists.\n *\n * ---\n *\n * @example\n * ```ts\n * import { existsSync } from \"node:fs\";\n *\n * if (existsSync(\"file.txt\"))\n * {\n *     throw new FileExistsException(\"The file named 'file.txt' already exists.\");\n * }\n * ```\n */\nexport class FileExistsException extends FileException\n{\n    /**\n     * Initializes a new instance of the {@link FileExistsException} class.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * throw new FileExistsException(\"The file named 'data.json' already exists on the server.\");\n     * ```\n     *\n     * ---\n     *\n     * @param message The message that describes the error.\n     * @param cause The previous caught error that caused this one, if any.\n     * @param name The name of the exception. Default is `\"FileExistsException\"`.\n     */\n    public constructor(message: string, cause?: unknown, name = \"FileExistsException\")\n    {\n        super(message, cause, name);\n    }\n\n    public override readonly [Symbol.toStringTag]: string = \"FileExistsException\";\n}\n\n/**\n * A class representing an exception that can be thrown when a file isn't found.\n *\n * ---\n *\n * @example\n * ```ts\n * import { existsSync } from \"node:fs\";\n *\n * if (!existsSync(\"file.txt\"))\n * {\n *     throw new FileNotFoundException(\"The file named 'file.txt' wasn't found.\");\n * }\n * ```\n */\nexport class FileNotFoundException extends FileException\n{\n    /**\n     * Initializes a new instance of the {@link FileNotFoundException} class.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * throw new FileNotFoundException(\"The file named 'data.json' wasn't found on the server.\");\n     * ```\n     *\n     * ---\n     *\n     * @param message The message that describes the error.\n     * @param cause The previous caught error that caused this one, if any.\n     * @param name The name of the exception. Default is `\"FileNotFoundException\"`.\n     */\n    public constructor(message: string, cause?: unknown, name = \"FileNotFoundException\")\n    {\n        super(message, cause, name);\n    }\n\n    public override readonly [Symbol.toStringTag]: string = \"FileNotFoundException\";\n}\n\n/**\n * A class representing an exception that can be thrown when a key is invalid or not found.  \n * It's commonly used when working with dictionaries, maps, objects, sets, etc...\n *\n * ---\n *\n * @example\n * ```ts\n * const map = new Map<string, number>();\n * if (!map.has(\"hash\"))\n * {\n *     throw new KeyException(\"The key 'hash' wasn't found in the collection.\");\n * }\n * ```\n */\nexport class KeyException extends Exception\n{\n    /**\n     * Initializes a new instance of the {@link KeyException} class.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * throw new KeyException(\"The 'id' key wasn't found in the dictionary.\");\n     * ```\n     *\n     * ---\n     *\n     * @param message The message that describes the error.\n     * @param cause The previous caught error that caused this one, if any.\n     * @param name The name of the exception. Default is `\"KeyException\"`.\n     */\n    public constructor(message: string, cause?: unknown, name = \"KeyException\")\n    {\n        super(message, cause, name);\n    }\n\n    public override readonly [Symbol.toStringTag]: string = \"KeyException\";\n}\n\n/**\n * A class representing an exception that can be thrown when a network operation fails.  \n * It's commonly used when it's unable to connect to a server or when a request times out.\n *\n * ---\n *\n * @example\n * ```ts\n * try { await fetch(\"https://api.example.com/data\"); }\n * catch (error)\n * {\n *     throw new NetworkException(\n *         \"Unable to establish a connection to the server. \" +\n *         \"Please, check your internet connection and try again.\",\n *         error\n *     );\n * }\n * ```\n */\nexport class NetworkException extends Exception\n{\n    /**\n     * Initializes a new instance of the {@link NetworkException} class.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * throw new NetworkException(\"Couldn't connect to the server. Please, try again later.\");\n     * ```\n     *\n     * ---\n     *\n     * @param message The message that describes the error.\n     * @param cause The previous caught error that caused this one, if any.\n     * @param name The name of the exception. Default is `\"NetworkException\"`.\n     */\n    public constructor(message: string, cause?: unknown, name = \"NetworkException\")\n    {\n        super(message, cause, name);\n    }\n\n    public override readonly [Symbol.toStringTag]: string = \"NetworkException\";\n}\n\n/**\n * A class representing an exception that can be thrown when a response is not valid or fails.  \n * It's commonly used when a request returns an error status code or when the response body is malformed.\n *\n * ---\n *\n * @example\n * ```ts\n * const response = await fetch(\"https://api.example.com/data\");\n * if (!response.ok)\n * {\n *     throw new ResponseException(response);\n * }\n * ```\n */\nexport class ResponseException extends NetworkException\n{\n    public readonly response: Response;\n\n    /**\n     * Initializes a new instance of the {@link ResponseException} class.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * throw new ResponseException(response);\n     * ```\n     *\n     * ---\n     *\n     * @param response The response that caused the error.\n     * @param cause The previous caught error that caused this one, if any.\n     * @param name The name of the exception. Default is `\"ResponseException\"`.\n     */\n    public constructor(response: Response, cause?: unknown, name = \"ResponseException\")\n    {\n        let message: string;\n\n        const url = response.url ? ` to \"${response.url}\"` : \"\";\n        const status = response.statusText ? `${response.status} (${response.statusText})` : response.status;\n        if (response.statusText)\n        {\n            message = `The request${url} failed with status ${status}.`;\n        }\n        else\n        {\n            message = `The request${url} failed with status ${status}.`;\n        }\n\n        super(message, cause, name);\n\n        this.response = response;\n    }\n\n    public override readonly [Symbol.toStringTag]: string = \"ResponseException\";\n}\n\n/**\n * A class representing an exception that can be thrown when a permission is denied.  \n * It's commonly used when an user tries to access a restricted resource or perform a forbidden action.\n *\n * ---\n *\n * @example\n * ```ts\n * const $user = useUserStore();\n * if (!$user.isAdmin)\n * {\n *     throw new PermissionException(\"You don't have permission to perform this action.\");\n * }\n * ```\n */\nexport class PermissionException extends Exception\n{\n    /**\n     * Initializes a new instance of the {@link PermissionException} class.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * throw new PermissionException(\"You don't have permission to access this resource.\");\n     * ```\n     *\n     * ---\n     *\n     * @param message The message that describes the error.\n     * @param cause The previous caught error that caused this one, if any.\n     * @param name The name of the exception. Default is `\"PermissionException\"`.\n     */\n    public constructor(message: string, cause?: unknown, name = \"PermissionException\")\n    {\n        super(message, cause, name);\n    }\n\n    public override readonly [Symbol.toStringTag]: string = \"PermissionException\";\n}\n\n/**\n * A class representing an exception that can be thrown when a reference is invalid or not found.  \n * It's commonly used when a variable is `null`, `undefined` or when an object doesn't exist.\n *\n * ---\n *\n * @example\n * ```ts\n * const $el = document.getElementById(\"app\");\n * if ($el === null)\n * {\n *     throw new ReferenceException(\"The element with the ID 'app' wasn't found in the document.\");\n * }\n * ```\n */\nexport class ReferenceException extends Exception\n{\n    /**\n     * Initializes a new instance of the {@link ReferenceException} class.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * throw new ReferenceException(\"The 'canvas' element wasn't found in the document.\");\n     * ```\n     *\n     * ---\n     *\n     * @param message The message that describes the error.\n     * @param cause The previous caught error that caused this one, if any.\n     * @param name The name of the exception. Default is `\"ReferenceException\"`.\n     */\n    public constructor(message: string, cause?: unknown, name = \"ReferenceException\")\n    {\n        super(message, cause, name);\n    }\n\n    public override readonly [Symbol.toStringTag]: string = \"ReferenceException\";\n}\n\n/**\n * A class representing an exception that can be thrown when a runtime error occurs.  \n * It's commonly used when an unexpected condition is encountered during the execution of a program.\n *\n * ---\n *\n * @example\n * ```ts\n * let status: \"enabled\" | \"disabled\" = \"enabled\";\n *\n * function enable(): void\n * {\n *     if (status === \"enabled\") { throw new RuntimeException(\"The feature is already enabled.\"); }\n *     status = \"enabled\";\n * }\n * ```\n */\nexport class RuntimeException extends Exception\n{\n    /**\n     * Initializes a new instance of the {@link RuntimeException} class.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * throw new RuntimeException(\"The received input seems to be malformed or corrupted.\");\n     * ```\n     *\n     * ---\n     *\n     * @param message The message that describes the error.\n     * @param cause The previous caught error that caused this one, if any.\n     * @param name The name of the exception. Default is `\"RuntimeException\"`.\n     */\n    public constructor(message: string, cause?: unknown, name = \"RuntimeException\")\n    {\n        super(message, cause, name);\n    }\n\n    public override readonly [Symbol.toStringTag]: string = \"RuntimeException\";\n}\n\n/**\n * A class representing an exception that can be thrown when an environment\n * isn't properly configured or when a required variable isn't set.  \n * It can also be used when the environment on which the program is running is unsupported.\n *\n * ---\n *\n * @example\n * ```ts\n * if (!navigator.geolocation)\n * {\n *     throw new EnvironmentException(\"The Geolocation API isn't supported in this environment.\");\n * }\n * ```\n */\nexport class EnvironmentException extends RuntimeException\n{\n    /**\n     * Initializes a new instance of the {@link EnvironmentException} class.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * throw new EnvironmentException(\"The required environment variable 'API_KEY' isn't set.\");\n     * ```\n     *\n     * ---\n     *\n     * @param message The message that describes the error.\n     * @param cause The previous caught error that caused this one, if any.\n     * @param name The name of the exception. Default is `\"EnvironmentException\"`.\n     */\n    public constructor(message: string, cause?: unknown, name = \"EnvironmentException\")\n    {\n        super(message, cause, name);\n    }\n\n    public override readonly [Symbol.toStringTag]: string = \"EnvironmentException\";\n}\n\n/**\n * A class representing an exception that can be thrown when a timeout occurs.  \n * It's commonly used when a task takes too long to complete or when a request times out.\n *\n * ---\n *\n * @example\n * ```ts\n * const timeoutId = setTimeout(() => { throw new TimeoutException(\"The request timed out.\"); }, 5_000);\n * const response = await fetch(\"https://api.example.com/data\");\n *\n * clearTimeout(timeoutId);\n * ```\n */\nexport class TimeoutException extends Exception\n{\n    /**\n     * Initializes a new instance of the {@link TimeoutException} class.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * throw new TimeoutException(\"The task took too long to complete.\");\n     * ```\n     *\n     * ---\n     *\n     * @param message The message that describes the error.\n     * @param cause The previous caught error that caused this one, if any.\n     * @param name The name of the exception. Default is `\"TimeoutException\"`.\n     */\n    public constructor(message: string, cause?: unknown, name = \"TimeoutException\")\n    {\n        super(message, cause, name);\n    }\n\n    public override readonly [Symbol.toStringTag]: string = \"TimeoutException\";\n}\n\n/**\n * A class representing an exception that can be thrown when a type is invalid or not supported.  \n * It's commonly used when a function receives an unexpected type of argument.\n *\n * ---\n *\n * @example\n * ```ts\n * function greet(name: string): void\n * {\n *     if (typeof name !== \"string\")\n *     {\n *         throw new TypeException(\"The 'name' argument must be a valid string.\");\n *     }\n * }\n * ```\n */\nexport class TypeException extends Exception\n{\n    /**\n     * Initializes a new instance of the {@link TypeException} class.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * throw new TypeException(\"The 'username' argument must be a valid string.\");\n     * ```\n     *\n     * ---\n     *\n     * @param message The message that describes the error.\n     * @param cause The previous caught error that caused this one, if any.\n     * @param name The name of the exception. Default is `\"TypeException\"`.\n     */\n    public constructor(message: string, cause?: unknown, name = \"TypeException\")\n    {\n        super(message, cause, name);\n    }\n\n    public override readonly [Symbol.toStringTag]: string = \"TypeException\";\n}\n\n/**\n * A class representing an exception that can be thrown when a value is invalid.  \n * It's commonly used when a function receives an unexpected value as an argument.\n *\n * ---\n *\n * @example\n * ```ts\n * function setVolume(value: number): void\n * {\n *     if (value < 0)\n *     {\n *         throw new ValueException(\"The 'value' argument must be greater than or equal to 0.\");\n *     }\n * }\n * ```\n */\nexport class ValueException extends Exception\n{\n    /**\n     * Initializes a new instance of the {@link ValueException} class.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * throw new ValueException(\"The 'grade' argument cannot be negative.\");\n     * ```\n     *\n     * ---\n     *\n     * @param message The message that describes the error.\n     * @param cause The previous caught error that caused this one, if any.\n     * @param name The name of the exception. Default is `\"ValueException\"`.\n     */\n    public constructor(message: string, cause?: unknown, name = \"ValueException\")\n    {\n        super(message, cause, name);\n    }\n\n    public override readonly [Symbol.toStringTag]: string = \"ValueException\";\n}\n\n/**\n * A class representing an exception that can be thrown when a value is out of range.  \n * It's commonly used when a function receives an unexpected value as an argument.\n *\n * ---\n *\n * @example\n * ```ts\n * function setVolume(value: number): void\n * {\n *     if ((value < 0) || (value > 100))\n *     {\n *         throw new RangeException(\"The 'value' argument must be between 0 and 100.\");\n *     }\n * }\n * ```\n */\nexport class RangeException extends ValueException\n{\n    /**\n     * Initializes a new instance of the {@link RangeException} class.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * throw new RangeException(\"The 'percentage' argument must be between 0 and 100.\");\n     * ```\n     *\n     * ---\n     *\n     * @param message The message that describes the error.\n     * @param cause The previous caught error that caused this one, if any.\n     * @param name The name of the exception. Default is `\"RangeException\"`.\n     */\n    public constructor(message: string, cause?: unknown, name = \"RangeException\")\n    {\n        super(message, cause, name);\n    }\n\n    public override readonly [Symbol.toStringTag]: string = \"RangeException\";\n}\n\nexport { Exception };\nexport { FatalErrorException, NotImplementedException } from \"./core.js\";\n","import AggregatedIterator from \"../aggregators/aggregated-iterator.js\";\nimport { ValueException } from \"../exceptions/index.js\";\n\nimport type { GeneratorFunction, Iteratee, TypeGuardPredicate, Reducer, IteratorLike } from \"./types.js\";\n\n/**\n * A wrapper class representing an enhanced and instantiable version\n * of the native {@link Iterable} & {@link Iterator} interfaces.\n *\n * It provides a set of utility methods to better manipulate and\n * transform iterators in a functional and highly performant way.  \n * It takes inspiration from the native {@link Array} methods like\n * {@link Array.map}, {@link Array.filter}, {@link Array.reduce}, etc...\n *\n * The class is lazy, meaning that the transformations are applied\n * only when the resulting iterator is materialized, not before.  \n * This allows to chain multiple transformations without\n * the need to iterate over the elements multiple times.\n *\n * ---\n *\n * @example\n * ```ts\n * const result = new SmartIterator<number>([\"-5\", \"-4\", \"-3\", \"-2\", \"-1\", \"0\", \"1\", \"2\", \"3\", \"4\", \"5\"])\n *     .map(Number)\n *     .map((value) => value + Math.ceil(Math.abs(value / 2)))\n *     .filter((value) => value >= 0)\n *     .map((value) => value + 1)\n *     .reduce((acc, value) => acc + value);\n *\n * console.log(result); // 31\n * ```\n *\n * ---\n *\n * @template T The type of elements in the iterator.\n * @template R The type of the final result of the iterator. Default is `void`.\n * @template N The type of the argument required by the `next` method. Default is `undefined`.\n */\nexport default class SmartIterator<T, R = void, N = undefined> implements Iterator<T, R, N>\n{\n    /**\n     * The native {@link Iterator} object that is being wrapped by this instance.\n     */\n    protected readonly _iterator: Iterator<T, R, N>;\n\n    /**\n     * Initializes a new instance of the {@link SmartIterator} class.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const iterator = new SmartIterator<string>([\"A\", \"B\", \"C\"]);\n     * ```\n     *\n     * ---\n     *\n     * @param iterable The iterable object to wrap.\n     */\n    public constructor(iterable: Iterable<T, R, N>);\n\n    /**\n     * Initializes a new instance of the {@link SmartIterator} class.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const iterator = new SmartIterator<number, void, number>({\n     *     _sum: 0, _count: 0,\n     *\n     *     next: function(value: number)\n     *     {\n     *         this._sum += value;\n     *         this._count += 1;\n     *\n     *         return { done: false, value: this._sum / this._count };\n     *     }\n     * })\n     * ```\n     *\n     * ---\n     *\n     * @param iterator The iterator object to wrap.\n     */\n    public constructor(iterator: Iterator<T, R, N>);\n\n    /**\n     * Initializes a new instance of the {@link SmartIterator} class.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const iterator = new SmartIterator<number>(function* ()\n     * {\n     *     for (let i = 2; i < 65_536; i *= 2) { yield (i - 1); }\n     * });\n     * ```\n     *\n     * ---\n     *\n     * @param generatorFn The generator function to wrap.\n     */\n    public constructor(generatorFn: GeneratorFunction<T, R, N>);\n\n    /**\n     * Initializes a new instance of the {@link SmartIterator} class.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const iterator = new SmartIterator(values);\n     * ```\n     *\n     * ---\n     *\n     * @param argument The iterable, iterator or generator function to wrap.\n     */\n    public constructor(argument: IteratorLike<T, R, N> | GeneratorFunction<T, R, N>);\n    public constructor(argument: IteratorLike<T, R, N> | GeneratorFunction<T, R, N>)\n    {\n        if (argument instanceof Function)\n        {\n            this._iterator = argument();\n        }\n        else if (Symbol.iterator in argument)\n        {\n            this._iterator = argument[Symbol.iterator]() as Iterator<T, R, N>;\n        }\n        else\n        {\n            this._iterator = argument;\n        }\n    }\n\n    /**\n     * Determines whether all elements of the iterator satisfy a given condition.\n     * See also {@link SmartIterator.some}.\n     *\n     * This method will iterate over all elements of the iterator checking if they satisfy the condition.  \n     * Once a single element doesn't satisfy the condition, the method will return `false` immediately.\n     *\n     * This may lead to an unknown final state of the iterator, which may be entirely or partially consumed.  \n     * For this reason, it's recommended to consider it as consumed in any case and to not use it anymore.  \n     * Consider using {@link SmartIterator.find} instead.\n     *\n     * If the iterator is infinite and every element satisfies the condition, the method will never return.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const iterator = new SmartIterator<number>([-2, -1, 0, 1, 2]);\n     * const result = iterator.every((value) => value < 0);\n     *\n     * console.log(result); // false\n     * ```\n     *\n     * ---\n     *\n     * @param predicate The condition to check for each element of the iterator.\n     *\n     * @returns `true` if all elements satisfy the condition, `false` otherwise.\n     */\n    public every(predicate: Iteratee<T, boolean>): boolean\n    {\n        let index = 0;\n\n        while (true)\n        {\n            const result = this._iterator.next();\n\n            if (result.done) { return true; }\n            if (!(predicate(result.value, index))) { return false; }\n\n            index += 1;\n        }\n    }\n\n    /**\n     * Determines whether any element of the iterator satisfies a given condition.\n     * See also {@link SmartIterator.every}.\n     *\n     * This method will iterate over all elements of the iterator checking if they satisfy the condition.  \n     * Once a single element satisfies the condition, the method will return `true` immediately.\n     *\n     * This may lead to an unknown final state of the iterator, which may be entirely or partially consumed.  \n     * For this reason, it's recommended to consider it as consumed in any case and to not use it anymore.  \n     * Consider using {@link SmartIterator.find} instead.\n     *\n     * If the iterator is infinite and no element satisfies the condition, the method will never return.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const iterator = new SmartIterator<number>([-2, -1, 0, 1, 2]);\n     * const result = iterator.some((value) => value < 0);\n     *\n     * console.log(result); // true\n     * ```\n     *\n     * ---\n     *\n     * @param predicate The condition to check for each element of the iterator.\n     *\n     * @returns `true` if any element satisfies the condition, `false` otherwise.\n     */\n    public some(predicate: Iteratee<T, boolean>): boolean\n    {\n        let index = 0;\n\n        while (true)\n        {\n            const result = this._iterator.next();\n\n            if (result.done) { return false; }\n            if (predicate(result.value, index)) { return true; }\n\n            index += 1;\n        }\n    }\n\n    /**\n     * Filters the elements of the iterator using a given condition.\n     *\n     * This method will iterate over all elements of the iterator checking if they satisfy the condition.  \n     * If the condition is met, the element will be included in the new iterator.\n     *\n     * Since the iterator is lazy, the filtering process will\n     * be executed once the resulting iterator is materialized.\n     *\n     * A new iterator will be created, holding the reference to the original one.  \n     * This means that the original iterator won't be consumed until the\n     * new one is and that consuming one of them will consume the other as well.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const iterator = new SmartIterator<number>([-2, -1, 0, 1, 2]);\n     * const result = iterator.filter((value) => value < 0);\n     *\n     * console.log(result.toArray()); // [-2, -1]\n     * ```\n     *\n     * ---\n     *\n     * @param predicate The condition to check for each element of the iterator.\n     *\n     * @returns A new {@link SmartIterator} containing only the elements that satisfy the condition.\n     */\n    public filter(predicate: Iteratee<T, boolean>): SmartIterator<T, R>;\n\n    /**\n     * Filters the elements of the iterator using a given condition.\n     *\n     * This method will iterate over all elements of the iterator checking if they satisfy the condition.  \n     * If the condition is met, the element will be included in the new iterator.\n     *\n     * Since the iterator is lazy, the filtering process will\n     * be executed once the resulting iterator is materialized.\n     *\n     * A new iterator will be created, holding the reference to the original one.  \n     * This means that the original iterator won't be consumed until the\n     * new one is and that consuming one of them will consume the other as well.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const iterator = new SmartIterator<number | string>([-2, \"-1\", \"0\", 1, \"2\"]);\n     * const result = iterator.filter<number>((value) => typeof value === \"number\");\n     *\n     * console.log(result.toArray()); // [-2, 1]\n     * ```\n     *\n     * ---\n     *\n     * @template S\n     * The type of the elements that satisfy the condition.  \n     * This allows the type-system to infer the correct type of the new iterator.\n     *\n     * It must be a subtype of the original type of the elements.\n     *\n     * @param predicate The type guard condition to check for each element of the iterator.\n     *\n     * @returns A new {@link SmartIterator} containing only the elements that satisfy the condition.\n     */\n    public filter<S extends T>(predicate: TypeGuardPredicate<T, S>): SmartIterator<S, R>;\n    public filter(predicate: Iteratee<T, boolean>): SmartIterator<T, R>\n    {\n        const iterator = this._iterator;\n\n        return new SmartIterator<T, R>(function* ()\n        {\n            let index = 0;\n            while (true)\n            {\n                const result = iterator.next();\n                if (result.done) { return result.value; }\n                if (predicate(result.value, index)) { yield result.value; }\n\n                index += 1;\n            }\n        });\n    }\n\n    /**\n     * Maps the elements of the iterator using a given transformation function.\n     *\n     * This method will iterate over all elements of the iterator applying the transformation function.  \n     * The result of each transformation will be included in the new iterator.\n     *\n     * Since the iterator is lazy, the mapping process will\n     * be executed once the resulting iterator is materialized.\n     *\n     * A new iterator will be created, holding the reference to the original one.  \n     * This means that the original iterator won't be consumed until the\n     * new one is and that consuming one of them will consume the other as well.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const iterator = new SmartIterator<number>([-2, -1, 0, 1, 2]);\n     * const result = iterator.map((value) => Math.abs(value));\n     *\n     * console.log(result.toArray()); // [2, 1, 0, 1, 2]\n     * ```\n     *\n     * ---\n     *\n     * @template V The type of the elements after the transformation.\n     *\n     * @param iteratee The transformation function to apply to each element of the iterator.\n     *\n     * @returns A new {@link SmartIterator} containing the transformed elements.\n     */\n    public map<V>(iteratee: Iteratee<T, V>): SmartIterator<V, R>\n    {\n        const iterator = this._iterator;\n\n        return new SmartIterator<V, R>(function* ()\n        {\n            let index = 0;\n            while (true)\n            {\n                const result = iterator.next();\n                if (result.done) { return result.value; }\n\n                yield iteratee(result.value, index);\n\n                index += 1;\n            }\n        });\n    }\n\n    /**\n     * Reduces the elements of the iterator using a given reducer function.  \n     * This method will consume the entire iterator in the process.\n     *\n     * It will iterate over all elements of the iterator applying the reducer function.  \n     * The result of each iteration will be passed as the accumulator to the next one.\n     *\n     * The first accumulator value will be the first element of the iterator.  \n     * The last accumulator value will be the final result of the reduction.\n     *\n     * Also note that:\n     * - If an empty iterator is provided, a {@link ValueException} will be thrown.\n     * - If the iterator is infinite, the method will never return.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const iterator = new SmartIterator<number>([1, 2, 3, 4, 5]);\n     * const result = iterator.reduce((acc, value) => acc + value);\n     *\n     * console.log(result); // 15\n     * ```\n     *\n     * ---\n     *\n     * @param reducer The reducer function to apply to each element of the iterator.\n     *\n     * @returns The final result of the reduction.\n     */\n    public reduce(reducer: Reducer<T, T>): T;\n\n    /**\n     * Reduces the elements of the iterator using a given reducer function.  \n     * This method will consume the entire iterator in the process.\n     *\n     * It will iterate over all elements of the iterator applying the reducer function.  \n     * The result of each iteration will be passed as the accumulator to the next one.\n     *\n     * The first accumulator value will be the provided initial value.  \n     * The last accumulator value will be the final result of the reduction.\n     *\n     * If the iterator is infinite, the method will never return.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const iterator = new SmartIterator<number>([1, 2, 3, 4, 5]);\n     * const result = iterator.reduce((acc, value) => acc + value, 10);\n     *\n     * console.log(result); // 25\n     * ```\n     *\n     * ---\n     *\n     * @template A The type of the accumulator value which will also be the type of the final result of the reduction.\n     *\n     * @param reducer The reducer function to apply to each element of the iterator.\n     * @param initialValue The initial value of the accumulator.\n     *\n     * @returns The final result of the reduction.\n     */\n    public reduce<A>(reducer: Reducer<T, A>, initialValue: A): A;\n    public reduce<A>(reducer: Reducer<T, A>, initialValue?: A): A\n    {\n        let index = 0;\n        let accumulator = initialValue;\n        if (accumulator === undefined)\n        {\n            const result = this._iterator.next();\n            if (result.done) { throw new ValueException(\"Cannot reduce an empty iterator without an initial value.\"); }\n\n            accumulator = (result.value as unknown) as A;\n            index += 1;\n        }\n\n        while (true)\n        {\n            const result = this._iterator.next();\n            if (result.done) { return accumulator; }\n\n            accumulator = reducer(accumulator, result.value, index);\n\n            index += 1;\n        }\n    }\n\n    /**\n     * Flattens the elements of the iterator using a given transformation function.\n     *\n     * This method will iterate over all elements of the iterator applying the transformation function.  \n     * The result of each transformation will be flattened into the new iterator.\n     *\n     * Since the iterator is lazy, the flattening process will\n     * be executed once the resulting iterator is materialized.\n     *\n     * A new iterator will be created, holding the reference to the original one.  \n     * This means that the original iterator won't be consumed until the\n     * new one is and that consuming one of them will consume the other as well.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const iterator = new SmartIterator<number[]>([[-2, -1], 0, 1, 2, [3, 4, 5]]);\n     * const result = iterator.flatMap((value) => value);\n     *\n     * console.log(result.toArray()); // [-2, -1, 0, 1, 2, 3, 4, 5]\n     * ```\n     *\n     * ---\n     *\n     * @template V The type of the elements after the transformation.\n     *\n     * @param iteratee The transformation function to apply to each element of the iterator.\n     *\n     * @returns A new {@link SmartIterator} containing the flattened elements.\n     */\n    public flatMap<V>(iteratee: Iteratee<T, V | readonly V[]>): SmartIterator<V, R>\n    {\n        const iterator = this._iterator;\n\n        return new SmartIterator<V, R>(function* ()\n        {\n            let index = 0;\n            while (true)\n            {\n                const result = iterator.next();\n                if (result.done) { return result.value; }\n\n                const elements = iteratee(result.value, index);\n                if (elements instanceof Array)\n                {\n                    for (const value of elements) { yield value; }\n                }\n                else { yield elements; }\n\n                index += 1;\n            }\n        });\n    }\n\n    /**\n     * Drops a given number of elements at the beginning of the iterator.  \n     * The remaining elements will be included in a new iterator.\n     * See also {@link SmartIterator.take}.\n     *\n     * Since the iterator is lazy, the dropping process will\n     * be executed once the resulting iterator is materialized.\n     *\n     * A new iterator will be created, holding the reference to the original one.  \n     * This means that the original iterator won't be consumed until the\n     * new one is and that consuming one of them will consume the other as well.\n     *\n     * Only the dropped elements will be consumed in the process.  \n     * The rest of the iterator will be consumed only once the new one is.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const iterator = new SmartIterator<number>([-2, -1, 0, 1, 2]);\n     * const result = iterator.drop(3);\n     *\n     * console.log(result.toArray()); // [1, 2]\n     * ```\n     *\n     * ---\n     *\n     * @param count The number of elements to drop.\n     *\n     * @returns A new {@link SmartIterator} containing the remaining elements.\n     */\n    public drop(count: number): SmartIterator<T, R | undefined>\n    {\n        const iterator = this._iterator;\n\n        return new SmartIterator<T, R | undefined>(function* ()\n        {\n            let index = 0;\n            while (index < count)\n            {\n                const result = iterator.next();\n                if (result.done) { return; }\n\n                index += 1;\n            }\n\n            while (true)\n            {\n                const result = iterator.next();\n                if (result.done) { return result.value; }\n\n                yield result.value;\n            }\n        });\n    }\n\n    /**\n     * Takes a given number of elements at the beginning of the iterator.  \n     * These elements will be included in a new iterator.\n     * See also {@link SmartIterator.drop}.\n     *\n     * Since the iterator is lazy, the taking process will\n     * be executed once the resulting iterator is materialized.\n     *\n     * A new iterator will be created, holding the reference to the original one.  \n     * This means that the original iterator won't be consumed until the\n     * new one is and that consuming one of them will consume the other as well.\n     *\n     * Only the taken elements will be consumed from the original iterator.  \n     * The rest of the original iterator will be available for further consumption.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const iterator = new SmartIterator<number>([-2, -1, 0, 1, 2]);\n     * const result = iterator.take(3);\n     *\n     * console.log(result.toArray());   // [-2, -1, 0]\n     * console.log(iterator.toArray()); // [1, 2]\n     * ```\n     *\n     * ---\n     *\n     * @param limit The number of elements to take.\n     *\n     * @returns A new {@link SmartIterator} containing the taken elements.\n     */\n    public take(limit: number): SmartIterator<T, R | undefined>\n    {\n        const iterator = this._iterator;\n\n        return new SmartIterator<T, R | undefined>(function* ()\n        {\n            let index = 0;\n            while (index < limit)\n            {\n                const result = iterator.next();\n                if (result.done) { return result.value; }\n\n                yield result.value;\n\n                index += 1;\n            }\n\n            return;\n        });\n    }\n\n    /**\n     * Finds the first element of the iterator that satisfies a given condition.\n     *\n     * This method will iterate over all elements of the iterator checking if they satisfy the condition.  \n     * The first element that satisfies the condition will be returned immediately.\n     *\n     * Only the elements that are necessary to find the first\n     * satisfying one will be consumed from the original iterator.  \n     * The rest of the original iterator will be available for further consumption.\n     *\n     * Also note that:\n     * - If no element satisfies the condition, `undefined` will be returned once the entire iterator is consumed.\n     * - If the iterator is infinite and no element satisfies the condition, the method will never return.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const iterator = new SmartIterator<number>([-2, -1, 0, 1, 2]);\n     * const result = iterator.find((value) => value > 0);\n     *\n     * console.log(result); // 1\n     * ```\n     *\n     * ---\n     *\n     * @param predicate The condition to check for each element of the iterator.\n     *\n     * @returns The first element that satisfies the condition, `undefined` otherwise.\n     */\n    public find(predicate: Iteratee<T, boolean>): T | undefined;\n\n    /**\n     * Finds the first element of the iterator that satisfies a given condition.\n     *\n     * This method will iterate over all elements of the iterator checking if they satisfy the condition.  \n     * The first element that satisfies the condition will be returned immediately.\n     *\n     * Only the elements that are necessary to find the first\n     * satisfying one will be consumed from the original iterator.  \n     * The rest of the original iterator will be available for further consumption.\n     *\n     * Also note that:\n     * - If no element satisfies the condition, `undefined` will be returned once the entire iterator is consumed.\n     * - If the iterator is infinite and no element satisfies the condition, the method will never return.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const iterator = new SmartIterator<number | string>([-2, \"-1\", \"0\", 1, \"2\"]);\n     * const result = iterator.find<number>((value) => typeof value === \"number\");\n     *\n     * console.log(result); // -2\n     * ```\n     *\n     * ---\n     *\n     * @template S\n     * The type of the element that satisfies the condition.  \n     * This allows the type-system to infer the correct type of the result.\n     *\n     * It must be a subtype of the original type of the elements.\n     *\n     * @param predicate The type guard condition to check for each element of the iterator.\n     *\n     * @returns The first element that satisfies the condition, `undefined` otherwise.\n     */\n    public find<S extends T>(predicate: TypeGuardPredicate<T, S>): S | undefined;\n    public find(predicate: Iteratee<T, boolean>): T | undefined\n    {\n        let index = 0;\n\n        while (true)\n        {\n            const result = this._iterator.next();\n\n            if (result.done) { return; }\n            if (predicate(result.value, index)) { return result.value; }\n\n            index += 1;\n        }\n    }\n\n    /**\n     * Enumerates the elements of the iterator.  \n     * Each element is be paired with its index in a new iterator.\n     *\n     * Since the iterator is lazy, the enumeration process will\n     * be executed once the resulting iterator is materialized.\n     *\n     * A new iterator will be created, holding the reference to the original one.  \n     * This means that the original iterator won't be consumed until the\n     * new one is and that consuming one of them will consume the other as well.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const iterator = new SmartIterator<string>([\"A\", \"M\", \"N\", \"Z\"]);\n     * const result = iterator.enumerate();\n     *\n     * console.log(result.toArray()); // [[0, \"A\"], [1, \"M\"], [2, \"N\"], [3, \"Z\"]]\n     * ```\n     *\n     * ---\n     *\n     * @returns A new {@link SmartIterator} containing the enumerated elements.\n     */\n    public enumerate(): SmartIterator<[number, T], R>\n    {\n        return this.map((value, index) => [index, value]);\n    }\n\n    /**\n     * Removes all duplicate elements from the iterator.  \n     * The first occurrence of each element will be kept.\n     *\n     * Since the iterator is lazy, the deduplication process will\n     * be executed once the resulting iterator is materialized.\n     *\n     * A new iterator will be created, holding the reference to the original one.  \n     * This means that the original iterator won't be consumed until the\n     * new one is and that consuming one of them will consume the other as well.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const iterator = new SmartIterator<number>([1, 1, 2, 3, 2, 3, 4, 5, 5, 4]);\n     * const result = iterator.unique();\n     *\n     * console.log(result.toArray()); // [1, 2, 3, 4, 5]\n     * ```\n     *\n     * ---\n     *\n     * @returns A new {@link SmartIterator} containing only the unique elements.\n     */\n    public unique(): SmartIterator<T, R>\n    {\n        const iterator = this._iterator;\n\n        return new SmartIterator<T, R>(function* ()\n        {\n            const values = new Set<T>();\n            while (true)\n            {\n                const result = iterator.next();\n                if (result.done) { return result.value; }\n                if (values.has(result.value)) { continue; }\n                values.add(result.value);\n\n                yield result.value;\n            }\n        });\n    }\n\n    /**\n     * Counts the number of elements in the iterator.  \n     * This method will consume the entire iterator in the process.\n     *\n     * If the iterator is infinite, the method will never return.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const iterator = new SmartIterator<number>([1, 2, 3, 4, 5]);\n     * const result = iterator.count();\n     *\n     * console.log(result); // 5\n     * ```\n     *\n     * ---\n     *\n     * @returns The number of elements in the iterator.\n     */\n    public count(): number\n    {\n        let index = 0;\n\n        while (true)\n        {\n            const result = this._iterator.next();\n            if (result.done) { return index; }\n\n            index += 1;\n        }\n    }\n\n    /**\n     * Iterates over all elements of the iterator.  \n     * The elements are passed to the function along with their index.\n     *\n     * This method will consume the entire iterator in the process.  \n     * If the iterator is infinite, the method will never return.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const iterator = new SmartIterator<number>([\"A\", \"M\", \"N\", \"Z\"]);\n     * iterator.forEach((value, index) =>\n     * {\n     *     console.log(`${index}: ${value}`); // \"0: A\", \"1: M\", \"2: N\", \"3: Z\"\n     * }\n     * ```\n     *\n     * ---\n     *\n     * @param iteratee The function to apply to each element of the iterator.\n     */\n    public forEach(iteratee: Iteratee<T>): void\n    {\n        let index = 0;\n\n        while (true)\n        {\n            const result = this._iterator.next();\n            if (result.done) { return; }\n\n            iteratee(result.value, index);\n\n            index += 1;\n        }\n    }\n\n    /**\n     * Advances the iterator to the next element and returns the result.  \n     * If the iterator requires it, a value must be provided to be passed to the next element.\n     *\n     * Once the iterator is done, the method will return an object with the `done` property set to `true`.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const iterator = new SmartIterator<number>([1, 2, 3, 4, 5]);\n     *\n     * let result = iterator.next();\n     * while (!result.done)\n     * {\n     *     console.log(result.value); // 1, 2, 3, 4, 5\n     *\n     *     result = iterator.next();\n     * }\n     *\n     * console.log(result); // { done: true, value: undefined }\n     * ```\n     *\n     * ---\n     *\n     * @param values The value to pass to the next element, if required.\n     *\n     * @returns The result of the iteration, containing the value of the operation.\n     */\n    public next(...values: N extends undefined ? [] : [N]): IteratorResult<T, R>\n    {\n        return this._iterator.next(...values);\n    }\n\n    /**\n     * An utility method that may be used to close the iterator gracefully,\n     * free the resources and perform any cleanup operation.  \n     * It may also be used to signal the end or to compute a specific final result of the iteration process.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const iterator = new SmartIterator<number>({\n     *     _index: 0,\n     *     next: function()\n     *     {\n     *         return { done: false, value: this._index += 1 };\n     *     },\n     *     return: function() { console.log(\"Closing the iterator...\"); }\n     * });\n     *\n     * for (const value of iterator)\n     * {\n     *     if (value > 5) { break; } // \"Closing the iterator...\"\n     *\n     *     console.log(value); // 1, 2, 3, 4, 5\n     * }\n     * ```\n     *\n     * ---\n     *\n     * @param value The final value of the iterator.\n     *\n     * @returns The result of the iterator.\n     */\n    public return(value?: R): IteratorResult<T, R>\n    {\n        if (this._iterator.return) { return this._iterator.return(value); }\n\n        return { done: true, value: value as R };\n    }\n\n    /**\n     * An utility method that may be used to close the iterator due to an error,\n     * free the resources and perform any cleanup operation.  \n     * It may also be used to signal that an error occurred during the iteration process or to handle it.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const iterator = new SmartIterator<number>({\n     *     _index: 0,\n     *     next: function()\n     *     {\n     *         return { done: this._index > 10, value: this._index += 1 };\n     *     },\n     *     throw: function(error)\n     *     {\n     *         console.warn(error.message);\n     *\n     *         this._index = 0;\n     *     }\n     * });\n     *\n     * for (const value of iterator) // 1, 2, 3, 4, 5, \"The index is too high.\", 1, 2, 3, 4, 5, ...\n     * {\n     *     try\n     *     {\n     *         if (value > 5) { throw new Exception(\"The index is too high.\"); }\n     *\n     *         console.log(value); // 1, 2, 3, 4, 5\n     *     }\n     *     catch (error) { iterator.throw(error); }\n     * }\n     * ```\n     *\n     * ---\n     *\n     * @param error The error to throw into the iterator.\n     *\n     * @returns The final result of the iterator.\n     */\n    public throw(error: unknown): IteratorResult<T, R>\n    {\n        if (this._iterator.throw) { return this._iterator.throw(error); }\n\n        throw error;\n    }\n\n    /**\n     * An utility method that aggregates the elements of the iterator using a given key function.  \n     * The elements will be grouped by the resulting keys in a new specialized iterator.\n     * See {@link AggregatedIterator}.\n     *\n     * Since the iterator is lazy, the grouping process will\n     * be executed once the resulting iterator is materialized.\n     *\n     * A new iterator will be created, holding the reference to the original one.  \n     * This means that the original iterator won't be consumed until the\n     * the new one is and that consuming one of them will consume the other as well.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const iterator = new SmartIterator<number>([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);\n     * const result = iterator.groupBy<string>((value) => value % 2 === 0 ? \"even\" : \"odd\");\n     *\n     * console.log(result.toObject()); // { odd: [1, 3, 5, 7, 9], even: [2, 4, 6, 8, 10] }\n     * ```\n     *\n     * ---\n     *\n     * @template K The type of the keys used to group the elements.\n     *\n     * @param iteratee The key function to apply to each element of the iterator.\n     *\n     * @returns A new instance of the {@link AggregatedIterator} class containing the grouped elements.\n     */\n    public groupBy<K extends PropertyKey>(iteratee: Iteratee<T, K>): AggregatedIterator<K, T>\n    {\n        return new AggregatedIterator(this.map((element, index) =>\n        {\n            const key = iteratee(element, index);\n\n            return [key, element] as [K, T];\n        }));\n    }\n\n    /**\n     * Materializes the iterator into an array.  \n     * This method will consume the entire iterator in the process.\n     *\n     * If the iterator is infinite, the method will never return.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const iterator = new SmartIterator(function* ()\n     * {\n     *     for (let i = 0; i < 5; i += 1) { yield i; }\n     * });\n     * const result = iterator.toArray();\n     *\n     * console.log(result); // [0, 1, 2, 3, 4]\n     * ```\n     *\n     * ---\n     *\n     * @returns The {@link Array} containing all elements of the iterator.\n     */\n    public toArray(): T[]\n    {\n        return Array.from(this as Iterable<T>);\n    }\n\n    public readonly [Symbol.toStringTag]: string = \"SmartIterator\";\n\n    public [Symbol.iterator](): SmartIterator<T, R, N> { return this; }\n}\n","import { ValueException } from \"../exceptions/index.js\";\nimport { SmartIterator } from \"../iterators/index.js\";\nimport type { GeneratorFunction } from \"../iterators/types.js\";\n\nimport AggregatedIterator from \"./aggregated-iterator.js\";\nimport type { KeyedIteratee, KeyedReducer, KeyedTypeGuardPredicate } from \"./types.js\";\n\n/**\n * A class representing an aggregated iterator that has been reduced in a lazy and optimized way.\n *\n * It's part of the {@link AggregatedIterator} and {@link AggregatedAsyncIterator} implementations,\n * providing a way to reduce them into a single value or another aggregated iterable.  \n * For this reason, it isn't recommended to instantiate this class directly\n * (although it's still possible), but rather use the reducing methods provided by the aggregated iterators.\n *\n * It isn't directly iterable, just like its parent class, and needs to specify on what you want to iterate.  \n * See the {@link ReducedIterator.keys}, {@link ReducedIterator.entries}\n * & {@link ReducedIterator.values} methods.  \n * It does, however, provide the same set of methods to perform\n * operations and transformation on the elements of the iterator,  \n * having also the knowledge and context of the groups to which\n * they belong, allowing to handle them in a grouped manner.\n *\n * This is particularly useful when you have group elements and\n * need perform specific operations on the reduced elements.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n *     .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n *     .count();\n *\n * console.log(results.toObject()); // { odd: 4, even: 4 }\n * ```\n *\n * ---\n *\n * @template K The type of the key used to group the elements.\n * @template T The type of the elements in the iterator.\n */\nexport default class ReducedIterator<K extends PropertyKey, T>\n{\n    /**\n     * The internal {@link SmartIterator} object that holds the reduced elements.\n     */\n    protected readonly _elements: SmartIterator<[K, T]>;\n\n    /**\n     * Initializes a new instance of the {@link ReducedIterator} class.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const results = new ReducedIterator<string, number>([[\"A\", 1], [\"B\", 2], [\"C\", 4]]);\n     * ```\n     *\n     * ---\n     *\n     * @param iterable A reduced iterable object.\n     */\n    public constructor(iterable: Iterable<[K, T]>);\n\n    /**\n     * Initializes a new instance of the {@link ReducedIterator} class.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const results = new ReducedIterator<string, number>({\n     *     _index: 0,\n     *     next: () =>\n     *     {\n     *         if (this._index >= 3) { return { done: true, value: undefined }; }\n     *         this._index += 1;\n     *\n     *         return { done: false, value: [[\"A\", \"B\", \"C\"][this._index], (this._index + 1)] };\n     *     }\n     * });\n     * ```\n     *\n     * ---\n     *\n     * @param iterator An reduced iterator object.\n     */\n    public constructor(iterator: Iterator<[K, T]>);\n\n    /**\n     * Initializes a new instance of the {@link ReducedIterator} class.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * import { range, Random } from \"@byloth/core\";\n     *\n     * const results = new ReducedIterator<string, number>(function* ()\n     * {\n     *     for (const index of range(3))\n     *     {\n     *         yield [[\"A\", \"B\", \"C\"][index], (index + 1)];\n     *     }\n     * });\n     * ```\n     *\n     * ---\n     *\n     * @param generatorFn A generator function that produces the reduced elements.\n     */\n    public constructor(generatorFn: GeneratorFunction<[K, T]>);\n\n    /**\n     * Initializes a new instance of the {@link ReducedIterator} class.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const results = new ReducedIterator(reducedValues);\n     * ```\n     *\n     * ---\n     *\n     * @param argument An iterable, iterator or generator function that produces the reduced elements.\n     */\n    public constructor(argument: Iterable<[K, T]> | Iterator<[K, T]> | GeneratorFunction<[K, T]>);\n    public constructor(argument: Iterable<[K, T]> | Iterator<[K, T]> | GeneratorFunction<[K, T]>)\n    {\n        this._elements = new SmartIterator(argument);\n    }\n\n    /**\n     * Determines whether all elements of the reduced iterator satisfy the given condition.\n     * See also {@link ReducedIterator.some}.\n     *\n     * This method will iterate over all the elements of the iterator checking if they satisfy the condition.  \n     * Once a single element doesn't satisfy the condition, the method will return `false` immediately.\n     *\n     * This may lead to an unknown final state of the iterator, which may be entirely or partially consumed.  \n     * For this reason, it's recommended to consider it as consumed in any case and to not use it anymore.  \n     * Consider using {@link ReducedIterator.find} instead.\n     *\n     * If the iterator is infinite and every element satisfies the condition, the method will never return.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n     *     .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n     *     .reduce((key, accumulator, value) => accumulator + value)\n     *     .every((key, value) => value > 0);\n     *\n     * console.log(results); // true\n     * ```\n     *\n     * ---\n     *\n     * @param predicate The condition to check for each element of the iterator.\n     *\n     * @returns `true` if all elements satisfy the condition, `false` otherwise.\n     */\n    public every(predicate: KeyedIteratee<K, T, boolean>): boolean\n    {\n        for (const [index, [key, element]] of this._elements.enumerate())\n        {\n            if (!(predicate(key, element, index))) { return false; }\n        }\n\n        return true;\n    }\n\n    /**\n     * Determines whether any element of the reduced iterator satisfies the given condition.\n     * See also {@link ReducedIterator.every}.\n     *\n     * This method will iterate over all the elements of the iterator checking if they satisfy the condition.  \n     * Once a single element satisfies the condition, the method will return `true` immediately.\n     *\n     * This may lead to an unknown final state of the iterator, which may be entirely or partially consumed.  \n     * For this reason, it's recommended to consider it as consumed in any case and to not use it anymore.  \n     * Consider using {@link ReducedIterator.find} instead.\n     *\n     * If the iterator is infinite and no element satisfies the condition, the method will never return.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n     *     .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n     *     .reduce((key, accumulator, value) => accumulator + value)\n     *     .some((key, value) => value > 0);\n     *\n     * console.log(results); // true\n     * ```\n     *\n     * ---\n     *\n     * @param predicate The condition to check for each element of the iterator.\n     *\n     * @returns `true` if any element satisfies the condition, `false` otherwise.\n     */\n    public some(predicate: KeyedIteratee<K, T, boolean>): boolean\n    {\n        for (const [index, [key, element]] of this._elements.enumerate())\n        {\n            if (predicate(key, element, index)) { return true; }\n        }\n\n        return false;\n    }\n\n    /**\n     * Filters the elements of the reduced iterator using a given condition.\n     *\n     * This method will iterate over all the elements of the iterator checking if they satisfy the condition.  \n     * If the condition is met, the element will be included in the new iterator.\n     *\n     * Since the iterator is lazy, the filtering process will\n     * be executed once the resulting iterator is materialized.\n     *\n     * A new iterator will be created, holding the reference to the original one.  \n     * This means that the original iterator won't be consumed until the\n     * new one is and that consuming one of them will consume the other as well.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n     *     .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n     *     .reduce((key, accumulator, value) => accumulator + value)\n     *     .filter((key, value) => value > 0);\n     *\n     * console.log(results.toObject()); // { odd: 4, even: 16 }\n     * ```\n     *\n     * ---\n     *\n     * @param predicate The condition to check for each element of the iterator.\n     *\n     * @returns A new {@link ReducedIterator} containing only the elements that satisfy the condition.\n     */\n    public filter(predicate: KeyedIteratee<K, T, boolean>): ReducedIterator<K, T>;\n\n    /**\n     * Filters the elements of the reduced iterator using a given type guard predicate.\n     *\n     * This method will iterate over all the elements of the iterator checking if they satisfy the condition.  \n     * If the condition is met, the element will be included in the new iterator.\n     *\n     * Since the iterator is lazy, the filtering process will\n     * be executed once the resulting iterator is materialized.\n     *\n     * A new iterator will be created, holding the reference to the original one.  \n     * This means that the original iterator won't be consumed until the\n     * new one is and that consuming one of them will consume the other as well.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const results = new SmartIterator<number | string>([-3, -1, \"0\", \"2\", 3, 5, \"6\", \"8\"])\n     *     .groupBy((value) => Number(value) % 2 === 0 ? \"even\" : \"odd\")\n     *     .reduce((key, accumulator, value) => accumulator + value)\n     *     .filter<number>((key, value) => typeof value === \"number\");\n     *\n     * console.log(results.toObject()); // { odd: 4 }\n     * ```\n     *\n     * ---\n     *\n     * @template S\n     * The type of the elements that satisfy the condition.  \n     * This allows the type-system to infer the correct type of the iterator.\n     *\n     * It must be a subtype of the original type of the elements.\n     *\n     * @param predicate The type guard condition to check for each element of the iterator.\n     *\n     * @returns A new {@link ReducedIterator} containing only the elements that satisfy the condition.\n     */\n    public filter<S extends T>(predicate: KeyedTypeGuardPredicate<K, T, S>): ReducedIterator<K, S>;\n    public filter(predicate: KeyedIteratee<K, T, boolean>): ReducedIterator<K, T>\n    {\n        const elements = this._elements.enumerate();\n\n        return new ReducedIterator(function* (): Generator<[K, T]>\n        {\n            for (const [index, [key, element]] of elements)\n            {\n                if (predicate(key, element, index)) { yield [key, element]; }\n            }\n        });\n    }\n\n    /**\n     * Maps the elements of the reduced iterator using a given transformation function.\n     *\n     * This method will iterate over all the elements of the iterator applying the transformation function.  \n     * The result of the transformation will be included in the new iterator.\n     *\n     * Since the iterator is lazy, the mapping process will\n     * be executed once the resulting iterator is materialized.\n     *\n     * A new iterator will be created, holding the reference to the original one.  \n     * This means that the original iterator won't be consumed until the\n     * new one is and that consuming one of them will consume the other as well.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n     *     .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n     *     .reduce((key, accumulator, value) => accumulator + value)\n     *     .map((key, value) => value * 2);\n     *\n     * console.log(results.toObject()); // { odd: 8, even: 32 }\n     * ```\n     *\n     * ---\n     *\n     * @template V The type of the elements after the transformation.\n     *\n     * @param iteratee The transformation function to apply to each element of the iterator.\n     *\n     * @returns A new {@link ReducedIterator} containing the transformed elements.\n     */\n    public map<V>(iteratee: KeyedIteratee<K, T, V>): ReducedIterator<K, V>\n    {\n        const elements = this._elements.enumerate();\n\n        return new ReducedIterator(function* (): Generator<[K, V]>\n        {\n            for (const [index, [key, element]] of elements)\n            {\n                yield [key, iteratee(key, element, index)];\n            }\n        });\n    }\n\n    /**\n     * Reduces the elements of the reduced iterator using a given reducer function.  \n     * This method will consume the entire iterator in the process.\n     *\n     * It will iterate over all the elements of the iterator applying the reducer function.  \n     * The result of each iteration will be passed as the accumulator to the next one.\n     *\n     * The first accumulator value will be the first element of the iterator.  \n     * The last accumulator value will be the final result of the reduction.\n     *\n     * Also note that:\n     * - If an empty iterator is provided, a {@link ValueException} will be thrown.\n     * - If the iterator is infinite, the method will never return.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const result = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n     *     .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n     *     .reduce((key, accumulator, value) => accumulator + value)\n     *     .reduce((key, accumulator, value) => accumulator + value);\n     *\n     * console.log(result); // 20\n     * ```\n     *\n     * ---\n     *\n     * @param reducer The reducer function to apply to the elements of the iterator.\n     *\n     * @returns The final value after reducing all the elements of the iterator.\n     */\n    public reduce(reducer: KeyedReducer<K, T, T>): T;\n\n    /**\n     * Reduces the elements of the reduced iterator using a given reducer function.  \n     * This method will consume the entire iterator in the process.\n     *\n     * It will iterate over all the elements of the iterator applying the reducer function.  \n     * The result of each iteration will be passed as the accumulator to the next one.\n     *\n     * The first accumulator value will be the provided initial value.  \n     * The last accumulator value will be the final result of the reduction.\n     *\n     * If the iterator is infinite, the method will never return.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const result = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n     *     .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n     *     .reduce((key, accumulator, value) => accumulator + value)\n     *     .reduce((key, { value }, currentValue) => ({ value: value + currentValue }), { value: 0 });\n     *\n     * console.log(result); // { value: 20 }\n     * ```\n     *\n     * ---\n     *\n     * @template A The type of the accumulator value which will also be the type of the final result of the reduction.\n     *\n     * @param reducer The reducer function to apply to the elements of the iterator.\n     * @param initialValue The initial value of the accumulator.\n     *\n     * @returns The final result of the reduction.\n     */\n    public reduce<A>(reducer: KeyedReducer<K, T, A>, initialValue: A): A;\n    public reduce<A>(reducer: KeyedReducer<K, T, A>, initialValue?: A): A\n    {\n        let index = 0;\n        let accumulator = initialValue;\n        if (accumulator === undefined)\n        {\n            const result = this._elements.next();\n            if (result.done) { throw new ValueException(\"Cannot reduce an empty iterator without an initial value.\"); }\n\n            accumulator = (result.value[1] as unknown) as A;\n            index += 1;\n        }\n\n        for (const [key, element] of this._elements)\n        {\n            accumulator = reducer(key, accumulator, element, index);\n\n            index += 1;\n        }\n\n        return accumulator;\n    }\n\n    /**\n     * Flattens the elements of the reduced iterator using a given transformation function.\n     *\n     * This method will iterate over all the elements of the iterator applying the transformation function.  \n     * The result of each transformation will be flattened into the new iterator.\n     *\n     * Since the iterator is lazy, the flattening process will\n     * be executed once the resulting iterator is materialized.\n     *\n     * A new iterator will be created, holding the reference to the original one.  \n     * This means that the original iterator won't be consumed until the\n     * new one is and that consuming one of them will consume the other as well.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n     *     .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n     *     .reduce((key, accumulator, value) => accumulator.concat([value]), () => [])\n     *     .flatMap((key, value) => value);\n     *\n     * console.log(results.toObject()); // { odd: [-3, -1, 3, 5], even: [0, 2, 6, 8] }\n     * ```\n     *\n     * ---\n     *\n     * @template V The type of the elements after the transformation.\n     *\n     * @param iteratee The transformation function to apply to each element of the iterator.\n     *\n     * @returns A new {@link AggregatedIterator} containing the flattened elements.\n     */\n    public flatMap<V>(iteratee: KeyedIteratee<K, T, V | readonly V[]>): AggregatedIterator<K, V>\n    {\n        const elements = this._elements.enumerate();\n\n        return new AggregatedIterator(function* (): Generator<[K, V]>\n        {\n            for (const [index, [key, element]] of elements)\n            {\n                const values = iteratee(key, element, index);\n\n                if (values instanceof Array)\n                {\n                    for (const value of values) { yield [key, value]; }\n                }\n                else { yield [key, values]; }\n            }\n        });\n    }\n\n    /**\n     * Drops a given number of elements at the beginning of the reduced iterator.  \n     * The remaining elements will be included in the new iterator.\n     * See also {@link ReducedIterator.take}.\n     *\n     * Since the iterator is lazy, the dropping process will\n     * be executed once the resulting iterator is materialized.\n     *\n     * A new iterator will be created, holding the reference to the original one.  \n     * This means that the original iterator won't be consumed until the\n     * new one is and that consuming one of them will consume the other as well.\n     *\n     * Only the dropped elements will be consumed in the process.  \n     * The rest of the iterator will be consumed once the new iterator is.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n     *     .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n     *     .reduce((key, accumulator, value) => accumulator.concat(value), () => [])\n     *     .drop(1);\n     *\n     * console.log(results.toObject()); // { even: [0, 2, 6, 8] }\n     * ```\n     *\n     * ---\n     *\n     * @param count The number of elements to drop.\n     *\n     * @returns A new {@link ReducedIterator} containing the remaining elements.\n     */\n    public drop(count: number): ReducedIterator<K, T>\n    {\n        const elements = this._elements.enumerate();\n\n        return new ReducedIterator(function* (): Generator<[K, T]>\n        {\n            for (const [index, [key, element]] of elements)\n            {\n                if (index >= count) { yield [key, element]; }\n            }\n        });\n    }\n\n    /**\n     * Takes a given number of elements at the beginning of the reduced iterator.  \n     * The elements will be included in the new iterator.\n     * See also {@link ReducedIterator.drop}.\n     *\n     * Since the iterator is lazy, the taking process will\n     * be executed once the resulting iterator is materialized.\n     *\n     * A new iterator will be created, holding the reference to the original one.  \n     * This means that the original iterator won't be consumed until the\n     * new one is and that consuming one of them will consume the other as well.\n     *\n     * Only the taken elements will be consumed from the original reduced iterator.  \n     * The rest of the original reduced iterator will be available for further consumption.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const reduced = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n     *     .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n     *     .reduce((key, accumulator, value) => accumulator.concat(value), () => []);\n     *\n     * const results = iterator.take(1);\n     *\n     * console.log(results.toObject()); // { odd: [-3, -1, 3, 5] }\n     * console.log(reduced.toObject()); // { even: [0, 2, 6, 8] }\n     * ```\n     *\n     * ---\n     *\n     * @param limit The number of elements to take.\n     *\n     * @returns A new {@link ReducedIterator} containing the taken elements.\n     */\n    public take(limit: number): ReducedIterator<K, T>\n    {\n        const elements = this._elements.enumerate();\n\n        return new ReducedIterator(function* (): Generator<[K, T]>\n        {\n            for (const [index, [key, element]] of elements)\n            {\n                if (index >= limit) { break; }\n                yield [key, element];\n            }\n        });\n    }\n\n    /**\n     * Finds the first element of the reduced iterator that satisfies the given condition.\n     *\n     * This method will iterate over all the elements of the iterator checking if they satisfy the condition.  \n     * The first element that satisfies the condition will be returned immediately.\n     *\n     * Only the elements that are necessary to find the first\n     * satisfying one will be consumed from the original iterator.  \n     * The rest of the iterator will be available for further consumption.\n     *\n     * Also note that:\n     * - If no element satisfies the condition, `undefined` will be returned once the entire iterator is consumed.\n     * - If the iterator is infinite and no element satisfies the condition, the method will never return.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const results = new SmartIterator<number>([-3, -3, -1, 0, 1, 2, 5, 6, 8])\n     *     .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n     *     .reduce((key, accumulator, value) => accumulator + value)\n     *     .find((key, value) => value > 0);\n     *\n     * console.log(results); // 16\n     * ```\n     *\n     * ---\n     *\n     * @param predicate The condition to check for each element of the iterator.\n     *\n     * @returns The first element that satisfies the condition, `undefined` otherwise.\n     */\n    public find(predicate: KeyedIteratee<K, T, boolean>): T | undefined;\n\n    /**\n     * Finds the first element of the reduced iterator that satisfies the given type guard predicate.\n     *\n     * This method will iterate over all the elements of the iterator checking if they satisfy the condition.  \n     * The first element that satisfies the condition will be returned immediately.\n     *\n     * Only the elements that are necessary to find the first\n     * satisfying one will be consumed from the original iterator.  \n     * The rest of the iterator will be available for further consumption.\n     *\n     * Also note that:\n     * - If no element satisfies the condition, `undefined` will be returned once the entire iterator is consumed.\n     * - If the iterator is infinite and no element satisfies the condition, the method will never return.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const results = new SmartIterator<number | string>([\"-3\", -3, \"-1\", 0, 1, 2, \"5\", 6, 8])\n     *     .groupBy((value) => Number(value) % 2 === 0 ? \"even\" : \"odd\")\n     *     .reduce((key, accumulator, value) => accumulator + value)\n     *     .find<number>((key, value) => typeof value === \"number\");\n     *\n     * console.log(results); // 16\n     * ```\n     *\n     * ---\n     *\n     * @template S\n     * The type of the elements that satisfy the condition.  \n     * This allows the type-system to infer the correct type of the result.\n     *\n     * It must be a subtype of the original type of the elements.\n     *\n     * @param predicate The type guard condition to check for each element of the iterator.\n     *\n     * @returns The first element that satisfies the condition, `undefined` otherwise.\n     */\n    public find<S extends T>(predicate: KeyedTypeGuardPredicate<K, T, S>): S | undefined;\n    public find(predicate: KeyedIteratee<K, T, boolean>): T | undefined\n    {\n        for (const [index, [key, element]] of this._elements.enumerate())\n        {\n            if (predicate(key, element, index)) { return element; }\n        }\n\n        return undefined;\n    }\n\n    /**\n     * Enumerates the elements of the reduced iterator.  \n     * Each element is paired with its index in a new iterator.\n     *\n     * Since the iterator is lazy, the enumeration process will\n     * be executed once the resulting iterator is materialized.\n     *\n     * A new iterator will be created, holding the reference to the original one.  \n     * This means that the original iterator won't be consumed until the\n     * new one is and that consuming one of them will consume the other as well.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const results = new ReducedIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n     *     .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n     *     .reduce((key, accumulator, value) => accumulator + value)\n     *     .enumerate();\n     *\n     * console.log(results.toObject()); // [[0, 4], [1, 16]]\n     * ```\n     *\n     * ---\n     *\n     * @returns A new {@link ReducedIterator} object containing the enumerated elements.\n     */\n    public enumerate(): ReducedIterator<K, [number, T]>\n    {\n        return this.map((_, element, index) => [index, element]);\n    }\n\n    /**\n     * Removes all duplicate elements from the reduced iterator.  \n     * The first occurrence of each element will be kept.\n     *\n     * Since the iterator is lazy, the deduplication process will\n     * be executed once the resulting iterator is materialized.\n     *\n     * A new iterator will be created, holding the reference to the original one.  \n     * This means that the original iterator won't be consumed until the\n     * new one is and that consuming one of them will consume the other as well.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const results = new ReducedIterator<number>([-3, -1, 0, 2, 3, 6, -3, -1, 1, 5, 6, 8, 7, 2])\n     *     .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n     *     .map((key, value) => Math.abs(value))\n     *     .reduce((key, accumulator, value) => accumulator + value)\n     *     .unique();\n     *\n     * console.log(results.toObject()); // { odd: 24 }\n     *\n     * @returns A new {@link ReducedIterator} containing only the unique elements.\n     */\n    public unique(): ReducedIterator<K, T>\n    {\n        const elements = this._elements;\n\n        return new ReducedIterator(function* (): Generator<[K, T]>\n        {\n            const values = new Set<T>();\n            for (const [key, element] of elements)\n            {\n                if (values.has(element)) { continue; }\n                values.add(element);\n\n                yield [key, element];\n            }\n        });\n    }\n\n    /**\n     * Counts the number of elements in the reduced iterator.  \n     * This method will consume the entire iterator in the process.\n     *\n     * If the iterator is infinite, the method will never return.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n     *     .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n     *     .reduce((key, accumulator, value) => accumulator + value)\n     *     .count();\n     *\n     * console.log(results); // 2\n     * ```\n     *\n     * ---\n     *\n     * @returns The number of elements in the iterator.\n     */\n    public count(): number\n    {\n        let index = 0;\n\n        for (const _ of this._elements) { index += 1; }\n\n        return index;\n    }\n\n    /**\n     * Iterates over all elements of the reduced iterator.  \n     * The elements are passed to the function along with their key and index.\n     *\n     * This method will consume the entire iterator in the process.  \n     * If the iterator is infinite, the method will never return.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const reduced = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n     *     .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n     *     .reduce((key, accumulator, value) => accumulator + value);\n     *\n     * reduced.forEach((key, value, index) =>\n     * {\n     *     console.log(`#${index} - ${key}: ${value}`); // \"#0 - odd: 4\", \"#1 - even: 16\"\n     * });\n     * ```\n     *\n     * ---\n     *\n     * @param iteratee The function to apply to each element of the reduced iterator.\n     */\n    public forEach(iteratee: KeyedIteratee<K, T>): void\n    {\n        for (const [index, [key, element]] of this._elements.enumerate())\n        {\n            iteratee(key, element, index);\n        }\n    }\n\n    /**\n     * Reaggregates the elements of the reduced iterator.  \n     * The elements are grouped by a new key computed by the given iteratee function.\n     *\n     * Since the iterator is lazy, the reorganizing process will\n     * be executed once the resulting iterator is materialized.\n     *\n     * A new iterator will be created, holding the reference to the original one.  \n     * This means that the original iterator won't be consumed until the\n     * new one is and that consuming one of them will consume the other as well.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, -6, -8])\n     *     .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n     *     .reduce((key, accumulator, value) => accumulator + value)\n     *     .reorganizeBy((key, value) => value > 0 ? \"positive\" : \"negative\");\n     *\n     * console.log(results.toObject()); // { positive: 4, negative: -12 }\n     * ```\n     *\n     * ---\n     *\n     * @template J The type of the new keys used to group the elements.\n     *\n     * @param iteratee The function to determine the new key of each element of the iterator.\n     *\n     * @returns A new {@link AggregatedIterator} containing the elements reorganized by the new keys.\n     */\n    public reorganizeBy<J extends PropertyKey>(iteratee: KeyedIteratee<K, T, J>): AggregatedIterator<J, T>\n    {\n        const elements = this._elements.enumerate();\n\n        return new AggregatedIterator(function* (): Generator<[J, T]>\n        {\n            for (const [index, [key, element]] of elements)\n            {\n                yield [iteratee(key, element, index), element];\n            }\n        });\n    }\n\n    /**\n     * An utility method that returns a new {@link SmartIterator}\n     * object containing all the keys of the iterator.\n     *\n     * Since the iterator is lazy, the keys will be extracted\n     * be executed once the resulting iterator is materialized.\n     *\n     * A new iterator will be created, holding the reference to the original one.  \n     * This means that the original iterator won't be consumed until the\n     * new one is and that consuming one of them will consume the other as well.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const keys = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n     *     .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n     *     .reduce((key, accumulator, value) => accumulator + value)\n     *     .keys();\n     *\n     * console.log(keys.toArray()); // [\"odd\", \"even\"]\n     * ```\n     *\n     * ---\n     *\n     * @returns A new {@link SmartIterator} containing all the keys of the iterator.\n     */\n    public keys(): SmartIterator<K>\n    {\n        const elements = this._elements;\n\n        return new SmartIterator<K>(function* ()\n        {\n            for (const [key] of elements)\n            {\n                yield key;\n            }\n        });\n    }\n\n    /**\n     * An utility method that returns a new {@link SmartIterator}\n     * object containing all the entries of the iterator.  \n     * Each entry is a tuple containing the key and the element.\n     *\n     * Since the iterator is lazy, the entries will be extracted\n     * be executed once the resulting iterator is materialized.\n     *\n     * A new iterator will be created, holding the reference to the original one.  \n     * This means that the original iterator won't be consumed until the\n     * new one is and that consuming one of them will consume the other as well.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const entries = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n     *     .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n     *     .reduce((key, accumulator, value) => accumulator + value)\n     *     .entries();\n     *\n     * console.log(entries.toArray()); // [[\"odd\", 4], [\"even\", 16]]\n     * ```\n     *\n     * ---\n     *\n     * @returns A new {@link SmartIterator} containing all the entries of the iterator.\n     */\n    public entries(): SmartIterator<[K, T]>\n    {\n        return this._elements;\n    }\n\n    /**\n     * An utility method that returns a new {@link SmartIterator}\n     * object containing all the values of the iterator.\n     *\n     * Since the iterator is lazy, the values will be extracted\n     * be executed once the resulting iterator is materialized.\n     *\n     * A new iterator will be created, holding the reference to the original one.  \n     * This means that the original iterator won't be consumed until the\n     * new one is and that consuming one of them will consume the other as well.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const values = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n     *     .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n     *     .reduce((key, accumulator, value) => accumulator + value)\n     *     .values();\n     *\n     * console.log(values.toArray()); // [4, 16]\n     * ```\n     *\n     * ---\n     *\n     * @returns A new {@link SmartIterator} containing all the values of the iterator.\n     */\n    public values(): SmartIterator<T>\n    {\n        const elements = this._elements;\n\n        return new SmartIterator<T>(function* ()\n        {\n            for (const [_, element] of elements)\n            {\n                yield element;\n            }\n        });\n    }\n\n    /**\n     * Materializes the iterator into an array.  \n     * This method will consume the entire iterator in the process.\n     *\n     * If the iterator is infinite, the method will never return.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const reduced = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n     *     .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n     *     .reduce((key, accumulator, value) => accumulator + value);\n     *\n     * console.log(reduced.toArray()); // [4, 16]\n     * ```\n     *\n     * ---\n     *\n     * @returns The {@link Array} containing all elements of the iterator.\n     */\n    public toArray(): T[]\n    {\n        return Array.from(this.values());\n    }\n\n    /**\n     * Materializes the iterator into a map.  \n     * This method will consume the entire iterator in the process.\n     *\n     * If the iterator is infinite, the method will never return.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const reduced = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n     *     .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n     *     .reduce((key, accumulator, value) => accumulator + value);\n     *\n     * console.log(reduced.toMap()); // Map(2) { \"odd\" => 4, \"even\" => 16 }\n     * ```\n     *\n     * ---\n     *\n     * @returns The {@link Map} containing all elements of the iterator.\n     */\n    public toMap(): Map<K, T>\n    {\n        return new Map(this.entries());\n    }\n\n    /**\n     * Materializes the iterator into an object.  \n     * This method will consume the entire iterator in the process.\n     *\n     * If the iterator is infinite, the method will never return.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const reduced = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n     *     .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n     *     .reduce((key, accumulator, value) => accumulator + value);\n     *\n     * console.log(reduced.toObject()); // { odd: 4, even: 16 }\n     * ```\n     *\n     * ---\n     *\n     * @returns The {@link Object} containing all elements of the iterator.\n     */\n    public toObject(): Record<K, T>\n    {\n        return Object.fromEntries(this.entries()) as Record<K, T>;\n    }\n\n    public readonly [Symbol.toStringTag]: string = \"ReducedIterator\";\n}\n","import { SmartAsyncIterator } from \"../iterators/index.js\";\nimport type {\n    GeneratorFunction,\n    AsyncGeneratorFunction,\n    MaybeAsyncGeneratorFunction,\n    MaybeAsyncIteratorLike\n\n} from \"../iterators/types.js\";\nimport type { MaybePromise } from \"../types.js\";\n\nimport ReducedIterator from \"./reduced-iterator.js\";\nimport type { MaybeAsyncKeyedIteratee, MaybeAsyncKeyedReducer } from \"./types.js\";\n\n/**\n * A class representing an iterator that aggregates elements in a lazy and optimized way.\n *\n * It's part of the {@link SmartAsyncIterator} implementation,\n * providing a way to group elements of an iterable by key.  \n * For this reason, it isn't recommended to instantiate this class directly\n * (although it's still possible), but rather use the {@link SmartAsyncIterator.groupBy} method.\n *\n * It isn't directly iterable like its parent class but rather needs to specify on what you want to iterate.  \n * See the {@link AggregatedAsyncIterator.keys}, {@link AggregatedAsyncIterator.entries}\n * & {@link AggregatedAsyncIterator.values} methods.  \n * It does, however, provide the same set of methods to perform\n * operations and transformations on the elements of the iterator,\n * having also the knowledge and context of the groups to which\n * they belong, allowing to handle them in a grouped manner.\n *\n * This is particularly useful when you need to group elements and\n * then perform specific operations on the groups themselves.\n *\n * ---\n *\n * @example\n * ```ts\n * const elements = fetch([...]); // Promise<[-3, -1, 0, 2, 3, 5, 6, 8]>;\n * const results = new SmartAsyncIterator(elements)\n *     .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\")\n *     .count();\n *\n * console.log(await results.toObject()); // { odd: 4, even: 4 }\n * ```\n *\n * ---\n *\n * @template K The type of the keys used to group the elements.\n * @template T The type of the elements to aggregate.\n */\nexport default class AggregatedAsyncIterator<K extends PropertyKey, T>\n{\n    /**\n     * The internal {@link SmartAsyncIterator} object that holds the elements to aggregate.\n     */\n    protected readonly _elements: SmartAsyncIterator<[K, T]>;\n\n    /**\n     * Initializes a new instance of the {@link AggregatedAsyncIterator} class.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const iterator = new AggregatedAsyncIterator<string, number>([[\"A\", 1], [\"B\", 2], [\"A\", 3], [\"C\", 4], [\"B\", 5]]);\n     * ```\n     *\n     * ---\n     *\n     * @param iterable The iterable to aggregate.\n     */\n    public constructor(iterable: Iterable<[K, T]>);\n\n    /**\n     * Initializes a new instance of the {@link AggregatedAsyncIterator} class.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const elements = fetch([...]); // Promise<[[\"A\", 1], [\"B\", 2], [\"A\", 3], [\"C\", 4], [\"B\", 5]]>\n     * const iterator = new AggregatedAsyncIterator<string, number>(elements);\n     * ```\n     *\n     * ---\n     *\n     * @param iterable The iterable to aggregate.\n     */\n    public constructor(iterable: AsyncIterable<[K, T]>);\n\n    /**\n     * Initializes a new instance of the {@link AggregatedAsyncIterator} class.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * import { Random } from \"@byloth/core\";\n     *\n     * const iterator = new AggregatedAsyncIterator<string, number>({\n     *     _index: 0,\n     *     next: () =>\n     *     {\n     *         if (this._index >= 5) { return { done: true, value: undefined }; }\n     *         this._index += 1;\n     *\n     *         return { done: false, value: [Random.Choice([\"A\", \"B\", \"C\"]), (this._index + 1)] };\n     *     }\n     * });\n     * ```\n     *\n     * ---\n     *\n     * @param iterator The iterator to aggregate.\n     */\n    public constructor(iterator: Iterator<[K, T]>);\n\n    /**\n     * Initializes a new instance of the {@link AggregatedAsyncIterator} class.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * import { Random } from \"@byloth/core\";\n     *\n     * const iterator = new AggregatedAsyncIterator<string, number>({\n     *     _index: 0,\n     *     next: async () =>\n     *     {\n     *         if (this._index >= 5) { return { done: true, value: undefined }; }\n     *         this._index += 1;\n     *\n     *         return { done: false, value: [Random.Choice([\"A\", \"B\", \"C\"]), (this._index + 1)] };\n     *     }\n     * });\n     * ```\n     *\n     * ---\n     *\n     * @param iterator The iterator to aggregate.\n     */\n    public constructor(iterator: AsyncIterator<[K, T]>);\n\n    /**\n     * Initializes a new instance of the {@link AggregatedAsyncIterator} class.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * import { range, Random } from \"@byloth/core\";\n     *\n     * const iterator = new AggregatedAsyncIterator<string, number>(function* ()\n     * {\n     *     for (const index of range(5))\n     *     {\n     *         yield [Random.Choice([\"A\", \"B\", \"C\"]), (index + 1)];\n     *     }\n     * });\n     * ```\n     *\n     * ---\n     *\n     * @param generatorFn The generator function to aggregate.\n     */\n    public constructor(generatorFn: GeneratorFunction<[K, T]>);\n\n    /**\n     * Initializes a new instance of the {@link AggregatedAsyncIterator} class.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * import { range, Random } from \"@byloth/core\";\n     *\n     * const iterator = new AggregatedAsyncIterator<string, number>(async function* ()\n     * {\n     *     for await (const index of range(5))\n     *     {\n     *         yield [Random.Choice([\"A\", \"B\", \"C\"]), (index + 1)];\n     *     }\n     * });\n     * ```\n     *\n     * ---\n     *\n     * @param generatorFn The generator function to aggregate.\n     */\n    public constructor(generatorFn: AsyncGeneratorFunction<[K, T]>);\n\n    /**\n     * Initializes a new instance of the {@link AggregatedAsyncIterator} class.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const iterator = new AggregatedAsyncIterator(asyncKeyedValues);\n     * ```\n     *\n     * ---\n     *\n     * @param argument The iterable, iterator or generator function to aggregate.\n     */\n    public constructor(argument: MaybeAsyncIteratorLike<[K, T]> | MaybeAsyncGeneratorFunction<[K, T]>);\n    public constructor(argument: MaybeAsyncIteratorLike<[K, T]> | MaybeAsyncGeneratorFunction<[K, T]>)\n    {\n        this._elements = new SmartAsyncIterator(argument);\n    }\n\n    /**\n     * Determines whether all elements of each group of the iterator satisfy a given condition.\n     * See also {@link AggregatedAsyncIterator.some}.  \n     * This method will consume the entire iterator in the process.\n     *\n     * It will iterate over all elements of the iterator checjing if they satisfy the condition.  \n     * Once a single element of one group doesn't satisfy the condition,\n     * the result for the respective group will be `false`.\n     *\n     * Eventually, it will return a new {@link ReducedIterator}\n     * object that will contain all the boolean results for each group.  \n     * If the iterator is infinite, the method will never return.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const results = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n     *     .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\")\n     *     .every(async (key, value) => value >= 0);\n     *\n     * console.log(await results.toObject()); // { odd: false, even: true }\n     * ```\n     *\n     * ---\n     *\n     * @param predicate The condition to check for each element of the iterator.\n     *\n     * @returns\n     * A {@link Promise} resolving to a new {@link ReducedIterator} containing the boolean results for each group.\n     */\n    public async every(predicate: MaybeAsyncKeyedIteratee<K, T, boolean>): Promise<ReducedIterator<K, boolean>>\n    {\n        const values = new Map<K, [number, boolean]>();\n\n        for await (const [key, element] of this._elements)\n        {\n            const [index, result] = values.get(key) ?? [0, true];\n\n            if (!(result)) { continue; }\n\n            values.set(key, [index + 1, await predicate(key, element, index)]);\n        }\n\n        return new ReducedIterator(function* (): Generator<[K, boolean]>\n        {\n            for (const [key, [_, result]] of values) { yield [key, result]; }\n        });\n    }\n\n    /**\n     * Determines whether any element of each group of the iterator satisfies a given condition.\n     * See also {@link AggregatedAsyncIterator.every}.  \n     * This method will consume the entire iterator in the process.\n     *\n     * It will iterate over all elements of the iterator checjing if they satisfy the condition.  \n     * Once a single element of one group satisfies the condition,\n     * the result for the respective group will be `true`.\n     *\n     * Eventually, it will return a new {@link ReducedIterator}\n     * object that will contain all the boolean results for each group.  \n     * If the iterator is infinite, the method will never return.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const results = new SmartAsyncIterator<number>([-5, -4, -3, -2, -1, 0])\n     *     .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\")\n     *     .some(async (key, value) => value >= 0);\n     *\n     * console.log(await results.toObject()); // { odd: false, even: true }\n     * ```\n     *\n     * ---\n     *\n     * @param predicate The condition to check for each element of the iterator.\n     *\n     * @returns\n     * A {@link Promise} resolving to a new {@link ReducedIterator} containing the boolean results for each group.\n     */\n    public async some(predicate: MaybeAsyncKeyedIteratee<K, T, boolean>): Promise<ReducedIterator<K, boolean>>\n    {\n        const values = new Map<K, [number, boolean]>();\n\n        for await (const [key, element] of this._elements)\n        {\n            const [index, result] = values.get(key) ?? [0, false];\n\n            if (result) { continue; }\n\n            values.set(key, [index + 1, await predicate(key, element, index)]);\n        }\n\n        return new ReducedIterator(function* (): Generator<[K, boolean]>\n        {\n            for (const [key, [_, result]] of values) { yield [key, result]; }\n        });\n    }\n\n    /**\n     * Filters the elements of the iterator based on a given condition.\n     *\n     * This method will iterate over all elements of the iterator checking if they satisfy the condition.  \n     * If the condition is met, the element will be included in the new iterator.\n     *\n     * A new iterator will be created, holding the reference to the original one.  \n     * This means that the original iterator won't be consumed until the\n     * new one is and that consuming one of them will consume the other as well.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const results = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n     *     .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\")\n     *     .filter(async (key, value) => value >= 0);\n     *\n     * console.log(await results.toObject()); // { odd: [3, 5], even: [0, 2, 6, 8] }\n     * ```\n     *\n     * ---\n     *\n     * @param predicate The condition to check for each element of the iterator.\n     *\n     * @returns A new {@link AggregatedAsyncIterator} containing the elements that satisfy the condition.\n     */\n    public filter(predicate: MaybeAsyncKeyedIteratee<K, T, boolean>): AggregatedAsyncIterator<K, T>;\n\n    /**\n     * Filters the elements of the iterator based on a given condition.\n     *\n     * This method will iterate over all elements of the iterator checking if they satisfy the condition.  \n     * If the condition is met, the element will be included in the new iterator.\n     *\n     * A new iterator will be created, holding the reference to the original one.  \n     * This means that the original iterator won't be consumed until the\n     * new one is and that consuming one of them will consume the other as well.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const results = new SmartAsyncIterator<number>([-3, \"-1\", 0, \"2\", \"3\", 5, 6, \"8\"])\n     *     .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\")\n     *     .filter<number>(async (key, value) => typeof value === \"number\");\n     *\n     * console.log(await results.toObject()); // { odd: [-3, 5], even: [0, 6] }\n     * ```\n     *\n     * ---\n     *\n     * @template S\n     * The type of the elements that satisfy the condition.  \n     * This allows the type-system to infer the correct type of the new iterator.\n     *\n     * It must be a subtype of the original type of the elements.\n     *\n     * @param predicate The type guard condition to check for each element of the iterator.\n     *\n     * @returns A new {@link AggregatedAsyncIterator} containing the elements that satisfy the condition.\n     */\n    public filter<S extends T>(predicate: MaybeAsyncKeyedIteratee<K, T, boolean>): AggregatedAsyncIterator<K, S>;\n    public filter(predicate: MaybeAsyncKeyedIteratee<K, T, boolean>): AggregatedAsyncIterator<K, T>\n    {\n        const elements = this._elements;\n\n        return new AggregatedAsyncIterator(async function* (): AsyncGenerator<[K, T]>\n        {\n            const indexes = new Map<K, number>();\n            for await (const [key, element] of elements)\n            {\n                const index = indexes.get(key) ?? 0;\n                if (await predicate(key, element, index)) { yield [key, element]; }\n\n                indexes.set(key, index + 1);\n            }\n        });\n    }\n\n    /**\n     * Maps the elements of the iterator using a given transformation function.\n     *\n     * This method will iterate over all elements of the iterator applying the condition.  \n     * The result of each transformation will be included in the new iterator.\n     *\n     * Since the iterator is lazy, the mapping process will\n     * be executed once the resulting iterator is materialized.\n     *\n     * A new iterator will be created, holding the reference to the original one.  \n     * This means that the original iterator won't be consumed until the\n     * new one is and that consuming one of them will consume the other as well.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const results = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n     *     .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\")\n     *     .map(async (key, value) => Math.abs(value));\n     *\n     * console.log(await results.toObject()); // { odd: [3, 1, 3, 5], even: [0, 2, 6, 8] }\n     * ```\n     *\n     * ---\n     *\n     * @template V The type of the elements after the transformation.\n     *\n     * @param iteratee The transformation function to apply to each element of the iterator.\n     *\n     * @returns A new {@link AggregatedAsyncIterator} containing the transformed elements.\n     */\n    public map<V>(iteratee: MaybeAsyncKeyedIteratee<K, T, V>): AggregatedAsyncIterator<K, V>\n    {\n        const elements = this._elements;\n\n        return new AggregatedAsyncIterator(async function* (): AsyncGenerator<[K, V]>\n        {\n            const indexes = new Map<K, number>();\n            for await (const [key, element] of elements)\n            {\n                const index = indexes.get(key) ?? 0;\n                yield [key, await iteratee(key, element, index)];\n\n                indexes.set(key, index + 1);\n            }\n        });\n    }\n\n    /**\n     * Reduces the elements of the iterator using a given reducer function.  \n     * This method will consume the entire iterator in the process.\n     *\n     * It will iterate over all elements of the iterator applying the reducer function.  \n     * The result of each iteration will be passed as the accumulator to the next one.\n     *\n     * The first accoumulator value will be the first element of the iterator.  \n     * The last accumulator value will be the final result of the reduction.\n     *\n     * Eventually, it will return a new {@link ReducedIterator}\n     * object that will contain all the reduced results for each group.  \n     * If the iterator is infinite, the method will never return.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const results = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n     *     .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\")\n     *     .reduce(async (key, accumulator, value) => accumulator + value);\n     *\n     * console.log(await results.toObject()); // { odd: 4, even: 16 }\n     * ```\n     *\n     * ---\n     *\n     * @param reducer The reducer function to apply to each element of the iterator.\n     *\n     * @returns\n     * A {@link Promise} resolving to a new {@link ReducedIterator} containing the reduced results for each group.\n     */\n    public async reduce(reducer: MaybeAsyncKeyedReducer<K, T, T>): Promise<ReducedIterator<K, T>>;\n\n    /**\n     * Reduces the elements of the iterator using a given reducer function.  \n     * This method will consume the entire iterator in the process.\n     *\n     * It will iterate over all elements of the iterator applying the reducer function.  \n     * The result of each iteration will be passed as the accumulator to the next one.\n     *\n     * The first accoumulator value will be the provided initial value.  \n     * The last accumulator value will be the final result of the reduction.\n     *\n     * Eventually, it will return a new {@link ReducedIterator}\n     * object that will contain all the reduced results for each group.  \n     * If the iterator is infinite, the method will never return.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const results = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n     *     .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\")\n     *     .reduce(async (key, accumulator, value) => accumulator + value, 0);\n     *\n     * console.log(await results.toObject()); // { odd: 4, even: 16 }\n     * ```\n     *\n     * ---\n     *\n     * @template A The type of the accumulator value which will also be the final result of the reduction.\n     *\n     * @param reducer The reducer function to apply to each element of the iterator.\n     * @param initialValue The initial value for the accumulator.\n     *\n     * @returns\n     * A {@link Promise} resolving to a new {@link ReducedIterator} containing the reduced results for each group.\n     */\n    public async reduce<A extends PropertyKey>(\n        reducer: MaybeAsyncKeyedReducer<K, T, A>, initialValue: MaybePromise<A>\n    ): Promise<ReducedIterator<K, A>>;\n\n    /**\n     * Reduces the elements of the iterator using a given reducer function.  \n     * This method will consume the entire iterator in the process.\n     *\n     * It will iterate over all elements of the iterator applying the reducer function.  \n     * The result of each iteration will be passed as the accumulator to the next one.\n     *\n     * The first accoumulator value will be the provided initial value by the given function.  \n     * The last accumulator value will be the final result of the reduction.\n     *\n     * Eventually, it will return a new {@link ReducedIterator}\n     * object that will contain all the reduced results for each group.  \n     * If the iterator is infinite, the method will never return.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const results = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n     *     .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\")\n     *     .reduce(async (key, { value }, currentValue) => ({ value: value + currentValue }), (key) => ({ value: 0 }));\n     *\n     * console.log(await results.toObject()); // { odd: { value: 4 }, even: { value: 16 } }\n     * ```\n     *\n     * ---\n     *\n     * @template A The type of the accumulator value which will also be the final result of the reduction.\n     *\n     * @param reducer The reducer function to apply to each element of the iterator.\n     * @param initialValue The function that provides the initial value for the accumulator.\n     *\n     * @returns\n     * A {@link Promise} resolving to a new {@link ReducedIterator} containing the reduced results for each group.\n     */\n    public async reduce<A>(\n        reducer: MaybeAsyncKeyedReducer<K, T, A>, initialValue: (key: K) => MaybePromise<A>\n    ): Promise<ReducedIterator<K, A>>;\n    public async reduce<A>(\n        reducer: MaybeAsyncKeyedReducer<K, T, A>, initialValue?: MaybePromise<A> | ((key: K) => MaybePromise<A>)\n    ): Promise<ReducedIterator<K, A>>\n    {\n        const values = new Map<K, [number, A]>();\n\n        for await (const [key, element] of this._elements)\n        {\n            let index: number;\n            let accumulator: A;\n\n            if (values.has(key)) { [index, accumulator] = values.get(key)!; }\n            else if (initialValue !== undefined)\n            {\n                index = 0;\n\n                if (initialValue instanceof Function) { accumulator = await initialValue(key); }\n                else { accumulator = await initialValue; }\n            }\n            else\n            {\n                values.set(key, [0, (element as unknown) as A]);\n\n                continue;\n            }\n\n            values.set(key, [index + 1, await reducer(key, accumulator, element, index)]);\n        }\n\n        return new ReducedIterator(function* (): Generator<[K, A]>\n        {\n            for (const [key, [_, accumulator]] of values) { yield [key, accumulator]; }\n        });\n    }\n\n    /**\n     * Flattens the elements of the iterator using a given transformation function.\n     *\n     * This method will iterate over all elements of the iterator applying the transformation function.  \n     * The result of each transformation will be included in the new iterator.\n     *\n     * Since the iterator is lazy, the mapping process will\n     * be executed once the resulting iterator is materialized.\n     *\n     * A new iterator will be created, holding the reference to the original one.  \n     * This means that the original iterator won't be consumed until the\n     * new one is and that consuming one of them will consume the other as well.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const results = new SmartAsyncIterator<number>([[-3, -1], 0, 2, 3, 5, [6, 8]])\n     *      .groupBy(async (values) =>\n     *      {\n     *          const value = values instanceof Array ? values[0] : values;\n     *          return value % 2 === 0 ? \"even\" : \"odd\";\n     *      })\n     *     .flatMap(async (key, values) => values);\n     *\n     * console.log(await results.toObject()); // { odd: [-3, -1, 3, 5], even: [0, 2, 6, 8] }\n     * ```\n     *\n     * ---\n     *\n     * @template V The type of the elements after the transformation.\n     *\n     * @param iteratee The transformation function to apply to each element of the iterator.\n     *\n     * @returns A new {@link AggregatedAsyncIterator} containing the transformed elements.\n     */\n    public flatMap<V>(iteratee: MaybeAsyncKeyedIteratee<K, T, V | readonly V[]>): AggregatedAsyncIterator<K, V>\n    {\n        const elements = this._elements;\n\n        return new AggregatedAsyncIterator(async function* (): AsyncGenerator<[K, V]>\n        {\n            const indexes = new Map<K, number>();\n            for await (const [key, element] of elements)\n            {\n                const index = indexes.get(key) ?? 0;\n                const values = await iteratee(key, element, index);\n\n                if (values instanceof Array)\n                {\n                    for (const value of values) { yield [key, value]; }\n                }\n                else { yield [key, values]; }\n\n                indexes.set(key, index + 1);\n            }\n        });\n    }\n\n    /**\n     * Drops a given number of elements from the beginning of each group of the iterator.  \n     * The remaining elements will be included in the new iterator.\n     * See also {@link AggregatedAsyncIterator.take}.\n     *\n     * Since the iterator is lazy, the dropping process will\n     * be executed once the resulting iterator is materialized.\n     *\n     * A new iterator will be created, holding the reference to the original one.  \n     * This means that the original iterator won't be consumed until the\n     * new one is and that consuming one of them will consume the other as well.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const results = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n     *     .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\")\n     *     .drop(2);\n     *\n     * console.log(await results.toObject()); // { odd: [3, 5], even: [6, 8] }\n     * ```\n     *\n     * ---\n     *\n     * @param count The number of elements to drop from the beginning of each group.\n     *\n     * @returns A new {@link AggregatedAsyncIterator} containing the remaining elements.\n     */\n    public drop(count: number): AggregatedAsyncIterator<K, T>\n    {\n        const elements = this._elements;\n\n        return new AggregatedAsyncIterator(async function* (): AsyncGenerator<[K, T]>\n        {\n            const indexes = new Map<K, number>();\n            for await (const [key, element] of elements)\n            {\n                const index = indexes.get(key) ?? 0;\n                if (index < count)\n                {\n                    indexes.set(key, index + 1);\n\n                    continue;\n                }\n\n                yield [key, element];\n            }\n        });\n    }\n\n    /**\n     * Takes a given number of elements from the beginning of each group of the iterator.  \n     * The elements will be included in the new iterator.\n     * See also {@link AggregatedAsyncIterator.drop}.\n     *\n     * Since the iterator is lazy, the taking process will\n     * be executed once the resulting iterator is materialized.\n     *\n     * A new iterator will be created, holding the reference to the original one.  \n     * This means that the original iterator won't be consumed until the\n     * new one is and that consuming one of them will consume the other as well.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const results = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n     *     .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\")\n     *     .take(2);\n     *\n     * console.log(await results.toObject()); // { odd: [-3, -1], even: [0, 2] }\n     * ```\n     *\n     * ---\n     *\n     * @param limit The number of elements to take from the beginning of each group.\n     *\n     * @returns A new {@link AggregatedAsyncIterator} containing the taken elements.\n     */\n    public take(limit: number): AggregatedAsyncIterator<K, T>\n    {\n        const elements = this._elements;\n\n        return new AggregatedAsyncIterator(async function* (): AsyncGenerator<[K, T]>\n        {\n            const indexes = new Map<K, number>();\n            for await (const [key, element] of elements)\n            {\n                const index = indexes.get(key) ?? 0;\n                if (index >= limit) { continue; }\n\n                yield [key, element];\n\n                indexes.set(key, index + 1);\n            }\n        });\n    }\n\n    /**\n     * Finds the first element of each group of the iterator that satisfies a given condition.  \n     * This method will consume the entire iterator in the process.\n     *\n     * It will iterate over all elements of the iterator checking if they satisfy the condition.  \n     * Once the first element of one group satisfies the condition,\n     * the result for the respective group will be the element itself.\n     *\n     * Eventually, it will return a new {@link ReducedIterator}\n     * object that will contain the first element that satisfies the condition for each group.  \n     * If the iterator is infinite, the method will never return.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const results = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n     *     .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\")\n     *     .find(async (key, value) => value > 0);\n     *\n     * console.log(await results.toObject()); // { odd: 3, even: 2 }\n     * ```\n     *\n     * ---\n     *\n     * @param predicate The condition to check for each element of the iterator.\n     *\n     * @returns\n     * A {@link Promise} resolving to a new {@link ReducedIterator} containing\n     * the first element that satisfies the condition for each group.\n     */\n    public async find(predicate: MaybeAsyncKeyedIteratee<K, T, boolean>): Promise<ReducedIterator<K, T | undefined>>;\n\n    /**\n     * Finds the first element of each group of the iterator that satisfies a given condition.  \n     * This method will consume the entire iterator in the process.\n     *\n     * It will iterate over all elements of the iterator checking if they satisfy the condition.  \n     * Once the first element of one group satisfies the condition,\n     * the result for the respective group will be the element itself.\n     *\n     * Eventually, it will return a new {@link ReducedIterator}\n     * object that will contain the first element that satisfies the condition for each group.  \n     * If the iterator is infinite, the method will never return.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const results = new SmartAsyncIterator<number | string>([-3, \"-1\", 0, \"2\", \"3\", 5, 6, \"8\"])\n     *     .groupBy(async (value) => Number(value) % 2 === 0 ? \"even\" : \"odd\")\n     *     .find<number>(async (key, value) => typeof value === \"number\");\n     *\n     * console.log(await results.toObject()); // { odd: -3, even: 0 }\n     * ```\n     *\n     * ---\n     *\n     * @template S\n     * The type of the elements that satisfy the condition.  \n     * This allows the type-system to infer the correct type of the new iterator.\n     *\n     * It must be a subtype of the original type of the elements.\n     *\n     * @param predicate The type guard condition to check for each element of the iterator.\n     *\n     * @returns\n     * A {@link Promise} resolving to a new {@link ReducedIterator} containing\n     * the first element that satisfies the condition for each group.\n     */\n    public async find<S extends T>(\n        predicate: MaybeAsyncKeyedIteratee<K, T, boolean>\n    ): Promise<ReducedIterator<K, S | undefined>>;\n    public async find(predicate: MaybeAsyncKeyedIteratee<K, T, boolean>): Promise<ReducedIterator<K, T | undefined>>\n    {\n        const values = new Map<K, [number, T | undefined]>();\n\n        for await (const [key, element] of this._elements)\n        {\n            let [index, finding] = values.get(key) ?? [0, undefined];\n\n            if (finding !== undefined) { continue; }\n            if (await predicate(key, element, index)) { finding = element; }\n\n            values.set(key, [index + 1, finding]);\n        }\n\n        return new ReducedIterator(function* (): Generator<[K, T | undefined]>\n        {\n            for (const [key, [_, finding]] of values) { yield [key, finding]; }\n        });\n    }\n\n    /**\n     * Enumerates the elements of the iterator.  \n     * Each element is paired with its index within the group in the new iterator.\n     *\n     * Since the iterator is lazy, the enumeration process will\n     * be executed once the resulting iterator is materialized.\n     *\n     * A new iterator will be created, holding the reference to the original one.  \n     * This means that the original iterator won't be consumed until the\n     * new one is and that consuming one of them will consume the other as well.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const results = new SmartAsyncIterator<number>([-3, 0, 2, -1, 3])\n     *     .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\")\n     *     .enumerate();\n     *\n     * console.log(results.toObject()); // { odd: [[0, -3], [1, -1], [2, 3]], even: [[0, 0], [1, 2]] }\n     * ```\n     *\n     * ---\n     *\n     * @returns A new {@link AggregatedAsyncIterator} containing the enumerated elements.\n     */\n    public enumerate(): AggregatedAsyncIterator<K, [number, T]>\n    {\n        return this.map((key, value, index) => [index, value]);\n    }\n\n    /**\n     * Removes all duplicate elements from within each group of the iterator.  \n     * The first occurrence of each element will be included in the new iterator.\n     *\n     * Since the iterator is lazy, the deduplication process will\n     * be executed once the resulting iterator is materialized.\n     *\n     * A new iterator will be created, holding the reference to the original one.  \n     * This means that the original iterator won't be consumed until the\n     * new one is and that consuming one of them will consume the other as well.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const results = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 6, -3, -1, 0, 5, 6, 8, 0, 2])\n     *     .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\")\n     *     .unique();\n     *\n     * console.log(await results.toObject()); // { odd: [-3, -1, 3, 5], even: [0, 2, 6, 8] }\n     * ```\n     *\n     * ---\n     *\n     * @returns A new {@link AggregatedAsyncIterator} containing only the unique elements.\n     */\n    public unique(): AggregatedAsyncIterator<K, T>\n    {\n        const elements = this._elements;\n\n        return new AggregatedAsyncIterator(async function* (): AsyncGenerator<[K, T]>\n        {\n            const keys = new Map<K, Set<T>>();\n            for await (const [key, element] of elements)\n            {\n                const values = keys.get(key) ?? new Set<T>();\n                if (values.has(element)) { continue; }\n\n                values.add(element);\n                keys.set(key, values);\n\n                yield [key, element];\n            }\n        });\n    }\n\n    /**\n     * Counts the number of elements within each group of the iterator.  \n     * This method will consume the entire iterator in the process.\n     *\n     * If the iterator is infinite, the method will never return.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const results = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n     *     .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\")\n     *     .count();\n     *\n     * console.log(await results.toObject()); // { odd: 4, even: 4 }\n     * ```\n     *\n     * ---\n     *\n     * @returns\n     * A {@link Promise} resolving to a new {@link ReducedIterator} containing the number of elements for each group.\n     */\n    public async count(): Promise<ReducedIterator<K, number>>\n    {\n        const counters = new Map<K, number>();\n\n        for await (const [key] of this._elements)\n        {\n            const count = counters.get(key) ?? 0;\n\n            counters.set(key, count + 1);\n        }\n\n        return new ReducedIterator(function* (): Generator<[K, number]>\n        {\n            for (const [key, count] of counters) { yield [key, count]; }\n        });\n    }\n\n    /**\n     * Iterates over the elements of the iterator.  \n     * The elements are passed to the given iteratee function along with their key and index within the group.\n     *\n     * This method will consume the entire iterator in the process.  \n     * If the iterator is infinite, the method will never return.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const aggregator = new SmartAsyncIterator<number>([-3, 0, 2, -1, 3])\n     *     .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\");\n     *\n     * await aggregator.forEach(async (key, value, index) =>\n     * {\n     *     console.log(`${index}: ${value}`); // \"0: -3\", \"0: 0\", \"1: 2\", \"1: -1\", \"2: 3\"\n     * };\n     * ```\n     *\n     * ---\n     *\n     * @param iteratee The function to execute for each element of the iterator.\n     *\n     * @returns A {@link Promise} that will resolve once the iteration is complete.\n     */\n    public async forEach(iteratee: MaybeAsyncKeyedIteratee<K, T>): Promise<void>\n    {\n        const indexes = new Map<K, number>();\n\n        for await (const [key, element] of this._elements)\n        {\n            const index = indexes.get(key) ?? 0;\n\n            await iteratee(key, element, index);\n\n            indexes.set(key, index + 1);\n        }\n    }\n\n    /**\n     * Changes the key of each element on which the iterator is aggregated.  \n     * The new key is determined by the given iteratee function.\n     *\n     * Since the iterator is lazy, the reorganization process will\n     * be executed once the resulting iterator is materialized.\n     *\n     * A new iterator will be created, holding the reference to the original one.  \n     * This means that the original iterator won't be consumed until the\n     * new one is and that consuming one of them will consume the other as well.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const results = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n     *     .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\")\n     *     .map(async (key, value, index) => index % 2 === 0 ? value : -value)\n     *     .reorganizeBy(async (key, value) => value >= 0 ? \"+\" : \"-\");\n     *\n     * console.log(await results.toObject()); // { \"+\": [1, 0, 3, 6], \"-\": [-3, -2, -5, -8] }\n     * ```\n     *\n     * ---\n     *\n     * @template J The type of the new key.\n     *\n     * @param iteratee The function to determine the new key for each element of the iterator.\n     *\n     * @returns A new {@link AggregatedAsyncIterator} containing the elements reorganized by the new keys.\n     */\n    public reorganizeBy<J extends PropertyKey>(\n        iteratee: MaybeAsyncKeyedIteratee<K, T, J>\n    ): AggregatedAsyncIterator<J, T>\n    {\n        const elements = this._elements;\n\n        return new AggregatedAsyncIterator(async function* (): AsyncGenerator<[J, T]>\n        {\n            const indexes = new Map<K, number>();\n            for await (const [key, element] of elements)\n            {\n                const index = indexes.get(key) ?? 0;\n                yield [await iteratee(key, element, index), element];\n\n                indexes.set(key, index + 1);\n            }\n        });\n    }\n\n    /**\n     * An utility method that returns a new {@link SmartAsyncIterator}\n     * object containing all the keys of the iterator.\n     *\n     * Since the iterator is lazy, the keys will be extracted\n     * be executed once the resulting iterator is materialized.\n     *\n     * A new iterator will be created, holding the reference to the original one.  \n     * This means that the original iterator won't be consumed until the\n     * new one is and that consuming one of them will consume the other as well.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const keys = new SmartAsyncIterator([-3, Symbol(), \"A\", { }, null, [1 , 2, 3], false])\n     *     .groupBy(async (value) => typeof value)\n     *     .keys();\n     *\n     * console.log(await keys.toArray()); // [\"number\", \"symbol\", \"string\", \"object\", \"boolean\"]\n     * ```\n     *\n     * ---\n     *\n     * @returns A new {@link SmartAsyncIterator} containing all the keys of the iterator.\n     */\n    public keys(): SmartAsyncIterator<K>\n    {\n        const elements = this._elements;\n\n        return new SmartAsyncIterator<K>(async function* ()\n        {\n            const keys = new Set<K>();\n            for await (const [key] of elements)\n            {\n                if (keys.has(key)) { continue; }\n                keys.add(key);\n\n                yield key;\n            }\n        });\n    }\n\n    /**\n     * An utility method that returns a new {@link SmartAsyncIterator}\n     * object containing all the entries of the iterator.  \n     * Each entry is a tuple containing the key and the element.\n     *\n     * Since the iterator is lazy, the entries will be extracted\n     * be executed once the resulting iterator is materialized.\n     *\n     * A new iterator will be created, holding the reference to the original one.  \n     * This means that the original iterator won't be consumed until the\n     * new one is and that consuming one of them will consume the other as well.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const entries = new SmartAsyncIterator<number>([-3, 0, 2, -1, 3])\n     *     .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\")\n     *     .entries();\n     *\n     * console.log(await entries.toArray()); // [[\"odd\", -3], [\"even\", 0], [\"even\", 2], [\"odd\", -1], [\"odd\", 3]]\n     * ```\n     *\n     * ---\n     *\n     * @returns A new {@link SmartAsyncIterator} containing all the entries of the iterator.\n     */\n    public entries(): SmartAsyncIterator<[K, T]>\n    {\n        return this._elements;\n    }\n\n    /**\n     * An utility method that returns a new {@link SmartAsyncIterator}\n     * object containing all the values of the iterator.\n     *\n     * Since the iterator is lazy, the values will be extracted\n     * be executed once the resulting iterator is materialized.\n     *\n     * A new iterator will be created, holding the reference to the original one.  \n     * This means that the original iterator won't be consumed until the\n     * new one is and that consuming one of them will consume the other as well.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const values = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n     *     .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\")\n     *     .values();\n     *\n     * console.log(await values.toArray()); // [-3, -1, 0, 2, 3, 5, 6, 8]\n     * ```\n     *\n     * ---\n     *\n     * @returns A new {@link SmartAsyncIterator} containing all the values of the iterator.\n     */\n    public values(): SmartAsyncIterator<T>\n    {\n        const elements = this._elements;\n\n        return new SmartAsyncIterator<T>(async function* ()\n        {\n            for await (const [_, element] of elements) { yield element; }\n        });\n    }\n\n    /**\n     * Materializes the iterator into an array of arrays.  \n     * This method will consume the entire iterator in the process.\n     *\n     * If the iterator is infinite, the method will never return.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const aggregator = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n     *     .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\");\n     *\n     * console.log(await aggregator.toArray()); // [[-3, -1, 3, 5], [0, 2, 6, 8]]\n     * ```\n     *\n     * ---\n     *\n     * @returns A {@link Promise} resolving to an {@link Array} containing all the values of the iterator.\n     */\n    public async toArray(): Promise<T[][]>\n    {\n        const map = await this.toMap();\n\n        return Array.from(map.values());\n    }\n\n    /**\n     * Materializes the iterator into a map.  \n     * This method will consume the entire iterator in the process.\n     *\n     * If the iterator is infinite, the method will never return.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const aggregator = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n     *     .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\");\n     *\n     * console.log(await aggregator.toMap()); // Map(2) { \"odd\" => [-3, -1, 3, 5], \"even\" => [0, 2, 6, 8] }\n     * ```\n     *\n     * ---\n     *\n     * @returns A {@link Promise} resolving to a {@link Map} containing all the entries of the iterator.\n     */\n    public async toMap(): Promise<Map<K, T[]>>\n    {\n        const groups = new Map<K, T[]>();\n\n        for await (const [key, element] of this._elements)\n        {\n            const value = groups.get(key) ?? [];\n\n            value.push(element);\n            groups.set(key, value);\n        }\n\n        return groups;\n    }\n\n    /**\n     * Materializes the iterator into an object.  \n     * This method will consume the entire iterator in the process.\n     *\n     * If the iterator is infinite, the method will never return.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const aggregator = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n     *     .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\");\n     *\n     * console.log(await aggregator.toObject()); // { odd: [-3, -1, 3, 5], even: [0, 2, 6, 8] }\n     * ```\n     *\n     * ---\n     *\n     * @returns A {@link Promise} resolving to an object containing all the entries of the iterator.\n     */\n    public async toObject(): Promise<Record<K, T[]>>\n    {\n        const groups = { } as Record<K, T[]>;\n\n        for await (const [key, element] of this._elements)\n        {\n            const value = groups[key] ?? [];\n\n            value.push(element);\n            groups[key] = value;\n        }\n\n        return groups;\n    }\n\n    public readonly [Symbol.toStringTag]: string = \"AggregatedAsyncIterator\";\n}\n","import AggregatedAsyncIterator from \"../aggregators/aggregated-async-iterator.js\";\nimport { ValueException } from \"../exceptions/index.js\";\nimport type { MaybePromise } from \"../types.js\";\n\nimport type {\n    GeneratorFunction,\n    AsyncGeneratorFunction,\n    MaybeAsyncGeneratorFunction,\n    MaybeAsyncIteratee,\n    MaybeAsyncReducer,\n    MaybeAsyncIteratorLike\n\n} from \"./types.js\";\n\n/**\n * A wrapper class representing an enhanced and instantiable version\n * of the native {@link AsyncIterable} & {@link AsyncIterator} interfaces.\n *\n * It provides a set of utility methods to better manipulate and transform\n * asynchronous iterators in a functional and highly performant way.  \n * It takes inspiration from the native {@link Array} methods like\n * {@link Array.map}, {@link Array.filter}, {@link Array.reduce}, etc...\n *\n * The class is lazy, meaning that the transformations are applied\n * only when the resulting iterator is materialized, not before.  \n * This allows to chain multiple transformations without\n * the need to iterate over the elements multiple times.\n *\n * ---\n *\n * @example\n * ```ts\n * const result = new SmartAsyncIterator<number>([\"-5\", \"-4\", \"-3\", \"-2\", \"-1\", \"0\", \"1\", \"2\", \"3\", \"4\", \"5\"])\n *     .map((value) => Number(value))\n *     .map((value) => value + Math.ceil(Math.abs(value / 2)))\n *     .filter((value) => value >= 0)\n *     .map((value) => value + 1)\n *     .reduce((acc, value) => acc + value);\n *\n * console.log(await result); // 31\n * ```\n *\n * ---\n *\n * @template T The type of elements in the iterator.\n * @template R The type of the final result of the iterator. Default is `void`.\n * @template N The type of the argument passed to the `next` method. Default is `undefined`.\n */\nexport default class SmartAsyncIterator<T, R = void, N = undefined> implements AsyncIterator<T, R, N>\n{\n    /**\n     * The native {@link AsyncIterator} object that is being wrapped by this instance.\n     */\n    protected readonly _iterator: AsyncIterator<T, R, N>;\n\n    /**\n     * Initializes a new instance of the {@link SmartAsyncIterator} class.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const iterator = new SmartAsyncIterator<string>([\"A\", \"B\", \"C\"]);\n     * ```\n     *\n     * ---\n     *\n     * @param iterable The iterable object to wrap.\n     */\n    public constructor(iterable: Iterable<T>);\n\n    /**\n     * Initializes a new instance of the {@link SmartAsyncIterator} class.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const iterator = new SmartAsyncIterator<number>([1, 2, 3, 4, 5]);\n     * ```\n     *\n     * ---\n     *\n     * @param iterable The asynchronous iterable object to wrap.\n     */\n    public constructor(iterable: AsyncIterable<T>);\n\n    /**\n     * Initializes a new instance of the {@link SmartAsyncIterator} class.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const iterator = new SmartAsyncIterator<number, void, number>({\n     *     _sum: 0, _count: 0,\n     *\n     *     next: function(value: number)\n     *     {\n     *         this._sum += value;\n     *         this._count += 1;\n     *\n     *         return { done: false, value: this._sum / this._count };\n     *     }\n     * })\n     * ```\n     *\n     * ---\n     *\n     * @param iterator The iterator object to wrap.\n     */\n    public constructor(iterator: Iterator<T, R, N>);\n\n    /**\n     * Initializes a new instance of the {@link SmartAsyncIterator} class.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const iterator = new SmartAsyncIterator<number, void, number>({\n     *     _sum: 0, _count: 0,\n     *\n     *     next: async function(value: number)\n     *     {\n     *         this._sum += value;\n     *         this._count += 1;\n     *\n     *         return { done: false, value: this._sum / this._count };\n     *     }\n     * })\n     * ```\n     *\n     * ---\n     *\n     * @param iterator The asynchronous iterator object to wrap.\n     */\n    public constructor(iterator: AsyncIterator<T, R, N>);\n\n    /**\n     * Initializes a new instance of the {@link SmartAsyncIterator} class.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const iterator = new SmartAsyncIterator<number>(function* ()\n     * {\n     *     for (let i = 2; i < 65_536; i *= 2) { yield (i - 1); }\n     * });\n     * ```\n     *\n     * ---\n     *\n     * @param generatorFn The generator function to wrap.\n     */\n    public constructor(generatorFn: GeneratorFunction<T, R, N>);\n\n    /**\n     * Initializes a new instance of the {@link SmartAsyncIterator} class.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const iterator = new SmartAsyncIterator<number>(async function* ()\n     * {\n     *     for await (let i = 2; i < 65_536; i *= 2) { yield (i - 1); }\n     * });\n     * ```\n     *\n     * ---\n     *\n     * @param generatorFn The asynchronous generator function to wrap.\n     */\n    public constructor(generatorFn: AsyncGeneratorFunction<T, R, N>);\n\n    /**\n     * Initializes a new instance of the {@link SmartAsyncIterator} class.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const iterator = new SmartAsyncIterator(values);\n     * ```\n     *\n     * ---\n     *\n     * @param argument The synchronous or asynchronous iterable, iterator or generator function to wrap.\n     */\n    public constructor(argument: MaybeAsyncIteratorLike<T, R, N> | MaybeAsyncGeneratorFunction<T, R, N>);\n    public constructor(argument: MaybeAsyncIteratorLike<T, R, N> | MaybeAsyncGeneratorFunction<T, R, N>)\n    {\n        if (argument instanceof Function)\n        {\n            const generator = argument();\n            if (Symbol.asyncIterator in generator)\n            {\n                this._iterator = generator;\n            }\n            else\n            {\n                this._iterator = (async function* ()\n                {\n                    let next: [] | [N] = [];\n\n                    while (true)\n                    {\n                        const result = generator.next(...next);\n                        if (result.done) { return result.value; }\n\n                        next = [yield result.value];\n                    }\n                })();\n            }\n        }\n        else if (Symbol.asyncIterator in argument)\n        {\n            this._iterator = argument[Symbol.asyncIterator]() as AsyncIterator<T, R, N>;\n        }\n        else if (Symbol.iterator in argument)\n        {\n            const iterator = argument[Symbol.iterator]();\n            this._iterator = (async function* ()\n            {\n                while (true)\n                {\n                    const result = iterator.next();\n                    if (result.done) { return result.value; }\n\n                    yield result.value;\n                }\n            })();\n        }\n        else\n        {\n            this._iterator = (async function* ()\n            {\n                let next: [] | [N] = [];\n\n                while (true)\n                {\n                    const result: IteratorResult<T, R> = await argument.next(...next);\n                    if (result.done) { return result.value; }\n\n                    next = [yield result.value];\n                }\n            })();\n        }\n    }\n\n    /**\n     * Determines whether all elements of the iterator satisfy a given condition.\n     * See also {@link SmartAsyncIterator.some}.\n     *\n     * This method will iterate over all elements of the iterator checking if they satisfy the condition.  \n     * Once a single element doesn't satisfy the condition, the method will return `false` immediately.\n     *\n     * This may lead to an unknown final state of the iterator, which may be entirely or partially consumed.  \n     * For this reason, it's recommended to consider it as consumed in any case and to not use it anymore.  \n     * Consider using {@link SmartAsyncIterator.find} instead.\n     *\n     * If the iterator is infinite and every element satisfies the condition, the method will never return.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const iterator = new SmartAsyncIterator<number>([-2, -1, 0, 1, 2]);\n     * const result = await iterator.every(async (value) => value < 0);\n     *\n     * console.log(result); // false\n     * ```\n     *\n     * ---\n     *\n     * @param predicate The condition to check for each element of the iterator.\n     *\n     * @returns\n     * A {@link Promise} that will resolve to `true` if all elements satisfy the condition, `false` otherwise.\n     */\n    public async every(predicate: MaybeAsyncIteratee<T, boolean>): Promise<boolean>\n    {\n        let index = 0;\n\n        while (true)\n        {\n            const result = await this._iterator.next();\n\n            if (result.done) { return true; }\n            if (!(await predicate(result.value, index))) { return false; }\n\n            index += 1;\n        }\n    }\n\n    /**\n     * Determines whether any element of the iterator satisfies a given condition.\n     * See also {@link SmartAsyncIterator.every}.\n     *\n     * This method will iterate over all elements of the iterator checking if they satisfy the condition.  \n     * Once a single element satisfies the condition, the method will return `true` immediately.\n     *\n     * This may lead to an unknown final state of the iterator, which may be entirely or partially consumed.  \n     * For this reason, it's recommended to consider it as consumed in any case and to not use it anymore.  \n     * Consider using {@link SmartAsyncIterator.find} instead.\n     *\n     * If the iterator is infinite and no element satisfies the condition, the method will never return.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const iterator = new SmartAsyncIterator<number>([-2, -1, 0, 1, 2]);\n     * const result = await iterator.some(async (value) => value > 0);\n     *\n     * console.log(result); // true\n     * ```\n     *\n     * ---\n     *\n     * @param predicate The condition to check for each element of the iterator.\n     *\n     * @returns\n     * A {@link Promise} that will resolve to `true` if any element satisfies the condition, `false` otherwise.\n     */\n    public async some(predicate: MaybeAsyncIteratee<T, boolean>): Promise<boolean>\n    {\n        let index = 0;\n\n        while (true)\n        {\n            const result = await this._iterator.next();\n\n            if (result.done) { return false; }\n            if (await predicate(result.value, index)) { return true; }\n\n            index += 1;\n        }\n    }\n\n    /**\n     * Filters the elements of the iterator using a given condition.\n     *\n     * This method will iterate over all elements of the iterator checking if they satisfy the condition.  \n     * If the condition is met, the element will be included in the new iterator.\n     *\n     * Since the iterator is lazy, the filtering process will\n     * be executed once the resulting iterator is materialized.\n     *\n     * A new iterator will be created, holding the reference to the original one.  \n     * This means that the original iterator won't be consumed until the\n     * new one is and that consuming one of them will consume the other as well.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const iterator = new SmartAsyncIterator<number>([-2, -1, 0, 1, 2]);\n     * const result = iterator.filter(async (value) => value < 0);\n     *\n     * console.log(await result.toArray()); // [-2, -1]\n     * ```\n     *\n     * ---\n     *\n     * @param predicate The condition to check for each element of the iterator.\n     *\n     * @returns A new {@link SmartAsyncIterator} containing only the elements that satisfy the condition.\n     */\n    public filter(predicate: MaybeAsyncIteratee<T, boolean>): SmartAsyncIterator<T, R>;\n\n    /**\n     * Filters the elements of the iterator using a given condition.\n     *\n     * This method will iterate over all elements of the iterator checking if they satisfy the condition.  \n     * If the condition is met, the element will be included in the new iterator.\n     *\n     * Since the iterator is lazy, the filtering process will\n     * be executed once the resulting iterator is materialized.\n     *\n     * A new iterator will be created, holding the reference to the original one.  \n     * This means that the original iterator won't be consumed until the\n     * new one is and that consuming one of them will consume the other as well.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const iterator = new SmartAsyncIterator<number | string>([-2, \"-1\", \"0\", 1, \"2\"]);\n     * const result = iterator.filter<number>(async (value) => typeof value === \"number\");\n     *\n     * console.log(await result.toArray()); // [-2, 1]\n     * ```\n     *\n     * ---\n     *\n     * @template S\n     * The type of the elements that satisfy the condition.  \n     * This allows the type-system to infer the correct type of the new iterator.\n     *\n     * It must be a subtype of the original type of the elements.\n     *\n     * @param predicate The type guard condition to check for each element of the iterator.\n     *\n     * @returns A new {@link SmartAsyncIterator} containing only the elements that satisfy the condition.\n     */\n    public filter<S extends T>(predicate: MaybeAsyncIteratee<T, boolean>): SmartAsyncIterator<S, R>;\n    public filter(predicate: MaybeAsyncIteratee<T, boolean>): SmartAsyncIterator<T, R>\n    {\n        const iterator = this._iterator;\n\n        return new SmartAsyncIterator<T, R>(async function* ()\n        {\n            let index = 0;\n            while (true)\n            {\n                const result = await iterator.next();\n                if (result.done) { return result.value; }\n                if (await predicate(result.value, index)) { yield result.value; }\n\n                index += 1;\n            }\n        });\n    }\n\n    /**\n     * Maps the elements of the iterator using a given transformation function.\n     *\n     * This method will iterate over all elements of the iterator applying the transformation function.  \n     * The result of each transformation will be included in the new iterator.\n     *\n     * Since the iterator is lazy, the mapping process will\n     * be executed once the resulting iterator is materialized.\n     *\n     * A new iterator will be created, holding the reference to the original one.  \n     * This means that the original iterator won't be consumed until the\n     * new one is and that consuming one of them will consume the other as well.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const iterator = new SmartAsyncIterator<number>([-2, -1, 0, 1, 2]);\n     * const result = iterator.map(async (value) => Math.abs(value));\n     *\n     * console.log(await result.toArray()); // [2, 1, 0, 1, 2]\n     * ```\n     *\n     * ---\n     *\n     * @template V The type of the elements after the transformation.\n     *\n     * @param iteratee The transformation function to apply to each element of the iterator.\n     *\n     * @returns A new {@link SmartAsyncIterator} containing the transformed elements.\n     */\n    public map<V>(iteratee: MaybeAsyncIteratee<T, V>): SmartAsyncIterator<V, R>\n    {\n        const iterator = this._iterator;\n\n        return new SmartAsyncIterator<V, R>(async function* ()\n        {\n            let index = 0;\n            while (true)\n            {\n                const result = await iterator.next();\n                if (result.done) { return result.value; }\n\n                yield await iteratee(result.value, index);\n\n                index += 1;\n            }\n        });\n    }\n\n    /**\n     * Reduces the elements of the iterator using a given reducer function.  \n     * This method will consume the entire iterator in the process.\n     *\n     * It will iterate over all elements of the iterator applying the reducer function.  \n     * The result of each iteration will be passed as the accumulator to the next one.\n     *\n     * The first accumulator value will be the first element of the iterator.  \n     * The last accumulator value will be the final result of the reduction.\n     *\n     * Also note that:\n     * - If an empty iterator is provided, a {@link ValueException} will be thrown.\n     * - If the iterator is infinite, the method will never return.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const iterator = new SmartAsyncIterator<number>([1, 2, 3, 4, 5]);\n     * const result = await iterator.reduce(async (acc, value) => acc + value);\n     *\n     * console.log(result); // 15\n     * ```\n     *\n     * ---\n     *\n     * @param reducer The reducer function to apply to each element of the iterator.\n     *\n     * @returns A {@link Promise} that will resolve to the final result of the reduction.\n     */\n    public async reduce(reducer: MaybeAsyncReducer<T, T>): Promise<T>;\n\n    /**\n     * Reduces the elements of the iterator using a given reducer function.  \n     * This method will consume the entire iterator in the process.\n     *\n     * It will iterate over all elements of the iterator applying the reducer function.  \n     * The result of each iteration will be passed as the accumulator to the next one.\n     *\n     * The first accumulator value will be the provided initial value.  \n     * The last accumulator value will be the final result of the reduction.\n     *\n     * If the iterator is infinite, the method will never return.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const iterator = new SmartAsyncIterator<number>([1, 2, 3, 4, 5]);\n     * const result = await iterator.reduce(async (acc, value) => acc + value, 10);\n     *\n     * console.log(result); // 25\n     * ```\n     *\n     * ---\n     *\n     * @template A The type of the accumulator value which will also be the type of the final result of the reduction.\n     *\n     * @param reducer The reducer function to apply to each element of the iterator.\n     * @param initialValue The initial value of the accumulator.\n     *\n     * @returns A {@link Promise} that will resolve to the final result of the reduction.\n     */\n    public async reduce<A>(reducer: MaybeAsyncReducer<T, A>, initialValue: A): Promise<A>;\n    public async reduce<A>(reducer: MaybeAsyncReducer<T, A>, initialValue?: A): Promise<A>\n    {\n        let index = 0;\n        let accumulator = initialValue;\n        if (accumulator === undefined)\n        {\n            const result = await this._iterator.next();\n            if (result.done) { throw new ValueException(\"Cannot reduce an empty iterator without an initial value.\"); }\n\n            accumulator = (result.value as unknown) as A;\n            index += 1;\n        }\n\n        while (true)\n        {\n            const result = await this._iterator.next();\n            if (result.done) { return accumulator; }\n\n            accumulator = await reducer(accumulator, result.value, index);\n\n            index += 1;\n        }\n    }\n\n    /**\n     * Flattens the elements of the iterator using a given transformation function.\n     *\n     * This method will iterate over all elements of the iterator applying the transformation function.  \n     * The result of each transformation will be flattened and included in the new iterator.\n     *\n     * Since the iterator is lazy, the flattening process will\n     * be executed once the resulting iterator is materialized.\n     *\n     * A new iterator will be created, holding the reference to the original one.  \n     * This means that the original iterator won't be consumed until the\n     * new one is and that consuming one of them will consume the other as well.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const iterator = new SmartAsyncIterator<number[]>([[-2, -1], 0, 1, 2, [3, 4, 5]]);\n     * const result = iterator.flatMap(async (value) => value);\n     *\n     * console.log(await result.toArray()); // [-2, -1, 0, 1, 2, 3, 4, 5]\n     * ```\n     *\n     * ---\n     *\n     * @template V The type of the elements after the transformation.\n     *\n     * @param iteratee The transformation function to apply to each element of the iterator.\n     *\n     * @returns A new {@link SmartAsyncIterator} containing the flattened elements.\n     */\n    public flatMap<V>(iteratee: MaybeAsyncIteratee<T, V | readonly V[]>): SmartAsyncIterator<V, R>\n    {\n        const iterator = this._iterator;\n\n        return new SmartAsyncIterator<V, R>(async function* ()\n        {\n            let index = 0;\n            while (true)\n            {\n                const result = await iterator.next();\n                if (result.done) { return result.value; }\n\n                const elements = await iteratee(result.value, index);\n                if (elements instanceof Array)\n                {\n                    for (const value of elements) { yield value; }\n                }\n                else { yield elements; }\n\n                index += 1;\n            }\n        });\n    }\n\n    /**\n     * Drops a given number of elements at the beginning of the iterator.  \n     * The remaining elements will be included in a new iterator.\n     * See also {@link SmartAsyncIterator.take}.\n     *\n     * Since the iterator is lazy, the dropping process will\n     * be executed once the resulting iterator is materialized.\n     *\n     * A new iterator will be created, holding the reference to the original one.  \n     * This means that the original iterator won't be consumed until the\n     * new one is and that consuming one of them will consume the other as well.\n     *\n     * Only the dropped elements will be consumed in the process.  \n     * The rest of the iterator will be consumed only once the new one is.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const iterator = new SmartAsyncIterator<number>([-2, -1, 0, 1, 2]);\n     * const result = iterator.drop(3);\n     *\n     * console.log(await result.toArray()); // [1, 2]\n     * ```\n     *\n     * ---\n     *\n     * @param count The number of elements to drop.\n     *\n     * @returns A new {@link SmartAsyncIterator} containing the remaining elements.\n     */\n    public drop(count: number): SmartAsyncIterator<T, R | undefined>\n    {\n        const iterator = this._iterator;\n\n        return new SmartAsyncIterator<T, R | undefined>(async function* ()\n        {\n            let index = 0;\n            while (index < count)\n            {\n                const result = await iterator.next();\n                if (result.done) { return; }\n\n                index += 1;\n            }\n\n            while (true)\n            {\n                const result = await iterator.next();\n                if (result.done) { return result.value; }\n\n                yield result.value;\n            }\n        });\n    }\n\n    /**\n     * Takes a given number of elements at the beginning of the iterator.  \n     * These elements will be included in a new iterator.\n     * See also {@link SmartAsyncIterator.drop}.\n     *\n     * Since the iterator is lazy, the taking process will\n     * be executed once the resulting iterator is materialized.\n     *\n     * A new iterator will be created, holding the reference to the original one.  \n     * This means that the original iterator won't be consumed until the\n     * new one is and that consuming one of them will consume the other as well.\n     *\n     * Only the taken elements will be consumed from the original iterator.  \n     * The rest of the original iterator will be available for further consumption.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const iterator = new SmartAsyncIterator<number>([-2, -1, 0, 1, 2]);\n     * const result = iterator.take(3);\n     *\n     * console.log(await result.toArray());   // [-2, -1, 0]\n     * console.log(await iterator.toArray()); // [1, 2]\n     * ```\n     *\n     * ---\n     *\n     * @param limit The number of elements to take.\n     *\n     * @returns A new {@link SmartAsyncIterator} containing the taken elements.\n     */\n    public take(limit: number): SmartAsyncIterator<T, R | undefined>\n    {\n        const iterator = this._iterator;\n\n        return new SmartAsyncIterator<T, R | undefined>(async function* ()\n        {\n            let index = 0;\n            while (index < limit)\n            {\n                const result = await iterator.next();\n                if (result.done) { return result.value; }\n\n                yield result.value;\n\n                index += 1;\n            }\n\n            return;\n        });\n    }\n\n    /**\n     * Finds the first element of the iterator that satisfies a given condition.\n     *\n     * This method will iterate over all elements of the iterator checking if they satisfy the condition.  \n     * The first element that satisfies the condition will be returned immediately.\n     *\n     * Only the elements that are necessary to find the first\n     * satisfying one will be consumed from the original iterator.  \n     * The rest of the original iterator will be available for further consumption.\n     *\n     * Also note that:\n     * - If no element satisfies the condition, `undefined` will be returned once the entire iterator is consumed.\n     * - If the iterator is infinite and no element satisfies the condition, the method will never return.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const iterator = new SmartAsyncIterator<number>([-2, -1, 0, 1, 2]);\n     * const result = await iterator.find(async (value) => value > 0);\n     *\n     * console.log(result); // 1\n     * ```\n     *\n     * ---\n     *\n     * @param predicate The condition to check for each element of the iterator.\n     *\n     * @returns\n     * A {@link Promise} that will resolve to the first element that satisfies the condition, `undefined` otherwise.\n     */\n    public async find(predicate: MaybeAsyncIteratee<T, boolean>): Promise<T | undefined>;\n\n    /**\n     * Finds the first element of the iterator that satisfies a given condition.\n     *\n     * This method will iterate over all elements of the iterator checking if they satisfy the condition.  \n     * The first element that satisfies the condition will be returned immediately.\n     *\n     * Only the elements that are necessary to find the first\n     * satisfying one will be consumed from the original iterator.  \n     * The rest of the original iterator will be available for further consumption.\n     *\n     * Also note that:\n     * - If no element satisfies the condition, `undefined` will be returned once the entire iterator is consumed.\n     * - If the iterator is infinite and no element satisfies the condition, the method will never return.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const iterator = new SmartAsyncIterator<number | string>([-2, \"-1\", \"0\", 1, \"2\"]);\n     * const result = await iterator.find<number>(async (value) => typeof value === \"number\");\n     *\n     * console.log(result); // -2\n     * ```\n     *\n     * ---\n     *\n     * @template S\n     * The type of the element that satisfies the condition.  \n     * This allows the type-system to infer the correct type of the result.\n     *\n     * It must be a subtype of the original type of the elements.\n     *\n     * @param predicate The type guard condition to check for each element of the iterator.\n     *\n     * @returns\n     * A {@link Promise} that will resolve to the first element that satisfies the condition, `undefined` otherwise. \n     */\n    public async find<S extends T>(predicate: MaybeAsyncIteratee<T, boolean>): Promise<S | undefined>;\n    public async find(predicate: MaybeAsyncIteratee<T, boolean>): Promise<T | undefined>\n    {\n        let index = 0;\n\n        while (true)\n        {\n            const result = await this._iterator.next();\n\n            if (result.done) { return; }\n            if (await predicate(result.value, index)) { return result.value; }\n\n            index += 1;\n        }\n    }\n\n    /**\n     * Enumerates the elements of the iterator.  \n     * Each element is be paired with its index in a new iterator.\n     *\n     * Since the iterator is lazy, the enumeration process will\n     * be executed once the resulting iterator is materialized.\n     *\n     * A new iterator will be created, holding the reference to the original one.  \n     * This means that the original iterator won't be consumed until the\n     * new one is and that consuming one of them will consume the other as well.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const iterator = new SmartAsyncIterator<string>([\"A\", \"M\", \"N\", \"Z\"]);\n     * const result = iterator.enumerate();\n     *\n     * for await (const [index, value] of result)\n     * {\n     *     console.log(`${index}: ${value}`); // \"0: A\", \"1: M\", \"2: N\", \"3: Z\"\n     * }\n     * ```\n     *\n     * ---\n     *\n     * @returns A new {@link SmartAsyncIterator} containing the enumerated elements.\n     */\n    public enumerate(): SmartAsyncIterator<[number, T], R>\n    {\n        return this.map((value, index) => [index, value]);\n    }\n\n    /**\n     * Removes all duplicate elements from the iterator.  \n     * The first occurrence of each element will be kept.\n     *\n     * Since the iterator is lazy, the deduplication process will\n     * be executed once the resulting iterator is materialized.\n     *\n     * A new iterator will be created, holding the reference to the original one.  \n     * This means that the original iterator won't be consumed until the\n     * new one is and that consuming one of them will consume the other as well.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const iterator = new SmartAsyncIterator<number>([1, 1, 2, 3, 2, 3, 4, 5, 5, 4]);\n     * const result = iterator.unique();\n     *\n     * console.log(await result.toArray()); // [1, 2, 3, 4, 5]\n     * ```\n     *\n     * ---\n     *\n     * @returns A new {@link SmartAsyncIterator} containing only the unique elements.\n     */\n    public unique(): SmartAsyncIterator<T, R>\n    {\n        const iterator = this._iterator;\n\n        return new SmartAsyncIterator<T, R>(async function* ()\n        {\n            const values = new Set<T>();\n            while (true)\n            {\n                const result = await iterator.next();\n                if (result.done) { return result.value; }\n                if (values.has(result.value)) { continue; }\n\n                values.add(result.value);\n\n                yield result.value;\n            }\n        });\n    }\n\n    /**\n     * Counts the number of elements in the iterator.  \n     * This method will consume the entire iterator in the process.\n     *\n     * If the iterator is infinite, the method will never return.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const iterator = new SmartAsyncIterator<number>([1, 2, 3, 4, 5]);\n     * const result = await iterator.count();\n     *\n     * console.log(result); // 5\n     * ```\n     *\n     * ---\n     *\n     * @returns A {@link Promise} that will resolve to the number of elements in the iterator.\n     */\n    public async count(): Promise<number>\n    {\n        let index = 0;\n\n        while (true)\n        {\n            const result = await this._iterator.next();\n            if (result.done) { return index; }\n\n            index += 1;\n        }\n    }\n\n    /**\n     * Iterates over all elements of the iterator.  \n     * The elements are passed to the function along with their index.\n     *\n     * This method will consume the entire iterator in the process.  \n     * If the iterator is infinite, the method will never return.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const iterator = new SmartAsyncIterator<number>([\"A\", \"M\", \"N\", \"Z\"]);\n     * await iterator.forEach(async (value, index) =>\n     * {\n     *     console.log(`${index}: ${value}`); // \"0: A\", \"1: M\", \"2: N\", \"3: Z\"\n     * }\n     * ```\n     *\n     * ---\n     *\n     * @param iteratee The function to apply to each element of the iterator.\n     *\n     * @returns A {@link Promise} that will resolve once the iteration is complete.\n     */\n    public async forEach(iteratee: MaybeAsyncIteratee<T>): Promise<void>\n    {\n        let index = 0;\n\n        while (true)\n        {\n            const result = await this._iterator.next();\n            if (result.done) { return; }\n\n            await iteratee(result.value, index);\n\n            index += 1;\n        }\n    }\n\n    /**\n     * Advances the iterator to the next element and returns the result.  \n     * If the iterator requires it, a value must be provided to be passed to the next element.\n     *\n     * Once the iterator is done, the method will return an object with the `done` property set to `true`.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const iterator = new SmartAsyncIterator<number>([1, 2, 3, 4, 5]);\n     *\n     * let result = await iterator.next();\n     * while (!result.done)\n     * {\n     *     console.log(result.value); // 1, 2, 3, 4, 5\n     *\n     *     result = await iterator.next();\n     * }\n     *\n     * console.log(result); // { done: true, value: undefined }\n     * ```\n     *\n     * ---\n     *\n     * @param values The value to pass to the next element, if required.\n     *\n     * @returns\n     * A {@link Promise} that will resolve to the result of the iteration, containing the value of the operation.\n     */\n    public next(...values: N extends undefined ? [] : [N]): Promise<IteratorResult<T, R>>\n    {\n        return this._iterator.next(...values);\n    }\n\n    /**\n     * An utility method that may be used to close the iterator gracefully,\n     * free the resources and perform any cleanup operation.  \n     * It may also be used to signal the end or to compute a specific final result of the iteration process.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const iterator = new SmartAsyncIterator<number>({\n     *     _index: 0,\n     *     next: async function()\n     *     {\n     *         return { done: false, value: this._index += 1 };\n     *     },\n     *     return: async function() { console.log(\"Closing the iterator...\"); }\n     * });\n     *\n     * for await (const value of iterator)\n     * {\n     *     if (value > 5) { break; } // \"Closing the iterator...\"\n     *\n     *     console.log(value); // 1, 2, 3, 4, 5\n     * }\n     * ```\n     *\n     * ---\n     *\n     * @param value The final value of the iterator.\n     *\n     * @returns A {@link Promise} that will resolve to the final result of the iterator.\n     */\n    public async return(value?: MaybePromise<R>): Promise<IteratorResult<T, R>>\n    {\n        const _value = (await value) as R;\n\n        if (this._iterator.return) { return await this._iterator.return(_value); }\n\n        return { done: true, value: _value };\n    }\n\n    /**\n     * An utility method that may be used to close the iterator due to an error,\n     * free the resources and perform any cleanup operation.  \n     * It may also be used to signal that an error occurred during the iteration process or to handle it.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const iterator = new SmartAsyncIterator<number>({\n     *     _index: 0,\n     *     next: async function()\n     *     {\n     *         return { done: this._index > 10, value: this._index += 1 };\n     *     },\n     *     throw: async function(error)\n     *     {\n     *         console.warn(error.message);\n     *\n     *         this._index = 0;\n     *     }\n     * });\n     *\n     * for await (const value of iterator) // 1, 2, 3, 4, 5, \"The index is too high.\", 1, 2, 3, 4, 5, ...\n     * {\n     *     try\n     *     {\n     *         if (value > 5) { throw new Exception(\"The index is too high.\"); }\n     *\n     *         console.log(value); // 1, 2, 3, 4, 5\n     *     }\n     *     catch (error) { await iterator.throw(error); }\n     * }\n     * ```\n     *\n     * ---\n     *\n     * @param error The error to throw into the iterator.\n     *\n     * @returns A {@link Promise} that will resolve to the final result of the iterator.\n     */\n    public throw(error: unknown): Promise<IteratorResult<T, R>>\n    {\n        if (this._iterator.throw) { return this._iterator.throw(error); }\n\n        throw error;\n    }\n\n    /**\n     * An utility method that aggregates the elements of the iterator using a given key function.  \n     * The elements will be grouped by the resulting keys in a new specialized iterator.\n     * See {@link AggregatedAsyncIterator}.\n     *\n     * Since the iterator is lazy, the grouping process will\n     * be executed once the resulting iterator is materialized.\n     *\n     * A new iterator will be created, holding the reference to the original one.  \n     * This means that the original iterator won't be consumed until the\n     * the new one is and that consuming one of them will consume the other as well.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const iterator = new SmartAsyncIterator<number>([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);\n     * const result = iterator.groupBy<string>(async (value) => value % 2 === 0 ? \"even\" : \"odd\");\n     *\n     * console.log(await result.toObject()); // { odd: [1, 3, 5, 7, 9], even: [2, 4, 6, 8, 10] }\n     * ```\n     *\n     * ---\n     *\n     * @template K The type of the keys used to group the elements.\n     *\n     * @param iteratee The key function to apply to each element of the iterator.\n     *\n     * @returns A new instance of the {@link AggregatedAsyncIterator} class containing the grouped elements.\n     */\n    public groupBy<K extends PropertyKey>(iteratee: MaybeAsyncIteratee<T, K>): AggregatedAsyncIterator<K, T>\n    {\n        return new AggregatedAsyncIterator(this.map(async (element, index) =>\n        {\n            const key = await iteratee(element, index);\n\n            return [key, element] as [K, T];\n        }));\n    }\n\n    /**\n     * Materializes the iterator into an array.  \n     * This method will consume the entire iterator in the process.\n     *\n     * If the iterator is infinite, the method will never return.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const iterator = new SmartAsyncIterator(async function* ()\n     * {\n     *     for (let i = 0; i < 5; i += 1) { yield i; }\n     * });\n     * const result = await iterator.toArray();\n     *\n     * console.log(result); // [0, 1, 2, 3, 4]\n     * ```\n     *\n     * ---\n     *\n     * @returns A {@link Promise} that will resolve to an array containing all elements of the iterator.\n     */\n    public toArray(): Promise<T[]>\n    {\n        return Array.fromAsync(this as AsyncIterable<T>);\n    }\n\n    public readonly [Symbol.toStringTag]: string = \"SmartAsyncIterator\";\n\n    public [Symbol.asyncIterator](): SmartAsyncIterator<T, R, N> { return this; }\n}\n","import { SmartIterator } from \"../iterators/index.js\";\nimport type { GeneratorFunction, IteratorLike } from \"../iterators/types.js\";\n\nimport ReducedIterator from \"./reduced-iterator.js\";\nimport type { KeyedIteratee, KeyedTypeGuardPredicate, KeyedReducer } from \"./types.js\";\n\n/**\n * A class representing an iterator that aggregates elements in a lazy and optimized way.\n *\n * It's part of the {@link SmartIterator} implementation, providing a way to group elements of an iterable by key.  \n * For this reason, it isn't recommended to instantiate this class directly\n * (although it's still possible), but rather use the {@link SmartIterator.groupBy} method.\n *\n * It isn't directly iterable like its parent class but rather needs to specify on what you want to iterate.  \n * See the {@link AggregatedIterator.keys}, {@link AggregatedIterator.entries}\n * & {@link AggregatedIterator.values} methods.  \n * It does, however, provide the same set of methods to perform\n * operations and transformation on the elements of the iterator,  \n * having also the knowledge and context of the groups to which\n * they belong, allowing to handle them in a grouped manner.\n *\n * This is particularly useful when you need to group elements and\n * then perform specific operations on the groups themselves.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n *     .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n *     .count();\n *\n * console.log(results.toObject()); // { odd: 4, even: 4 }\n * ```\n *\n * ---\n *\n * @template K The type of the keys used to group the elements.\n * @template T The type of the elements to aggregate.\n */\nexport default class AggregatedIterator<K extends PropertyKey, T>\n{\n    /**\n     * The internal {@link SmartIterator} object that holds the elements to aggregate.\n     */\n    protected readonly _elements: SmartIterator<[K, T]>;\n\n    /**\n     * Initializes a new instance of the {@link AggregatedIterator} class.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const iterator = new AggregatedIterator<string, number>([[\"A\", 1], [\"B\", 2], [\"A\", 3], [\"C\", 4], [\"B\", 5]]);\n     * ```\n     *\n     * ---\n     *\n     * @param iterable The iterable to aggregate.\n     */\n    public constructor(iterable: Iterable<[K, T]>);\n\n    /**\n     * Initializes a new instance of the {@link AggregatedIterator} class.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * import { Random } from \"@byloth/core\";\n     *\n     * const iterator = new AggregatedIterator<string, number>({\n     *     _index: 0,\n     *     next: () =>\n     *     {\n     *         if (this._index >= 5) { return { done: true, value: undefined }; }\n     *         this._index += 1;\n     *\n     *         return { done: false, value: [Random.Choice([\"A\", \"B\", \"C\"]), (this._index + 1)] };\n     *     }\n     * });\n     * ```\n     *\n     * ---\n     *\n     * @param iterator The iterator to aggregate.\n     */\n    public constructor(iterator: Iterator<[K, T]>);\n\n    /**\n     * Initializes a new instance of the {@link AggregatedIterator} class.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * import { range, Random } from \"@byloth/core\";\n     *\n     * const iterator = new AggregatedIterator<string, number>(function* ()\n     * {\n     *     for (const index of range(5))\n     *     {\n     *         yield [Random.Choice([\"A\", \"B\", \"C\"]), (index + 1)];\n     *     }\n     * });\n     * ```\n     *\n     * ---\n     *\n     * @param generatorFn The generator function to aggregate.\n     */\n    public constructor(generatorFn: GeneratorFunction<[K, T]>);\n\n    /**\n     * Initializes a new instance of the {@link AggregatedIterator} class.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const iterator = new AggregatedIterator(keyedValues);\n     * ```\n     *\n     * ---\n     *\n     * @param argument The iterable, iterator or generator function to aggregate.\n     */\n    public constructor(argument: IteratorLike<[K, T]> | GeneratorFunction<[K, T]>);\n    public constructor(argument: IteratorLike<[K, T]> | GeneratorFunction<[K, T]>)\n    {\n        this._elements = new SmartIterator(argument);\n    }\n\n    /**\n     * Determines whether all elements of each group of the iterator satisfy a given condition.\n     * See also {@link AggregatedIterator.some}.  \n     * This method will consume the entire iterator in the process.\n     *\n     * It will iterate over all elements of the iterator checking if they satisfy the condition.  \n     * Once a single element of one group doesn't satisfy the condition,\n     * the result for the respective group will be `false`.\n     *\n     * Eventually, it will return a new {@link ReducedIterator}\n     * object that will contain all the boolean results for each group.  \n     * If the iterator is infinite, the method will never return.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n     *     .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n     *     .every((key, value) => value >= 0);\n     *\n     * console.log(results.toObject()); // { odd: false, even: true }\n     * ```\n     *\n     * ---\n     *\n     * @param predicate The condition to check for each element of the iterator.\n     *\n     * @returns A new {@link ReducedIterator} containing the boolean results for each group.\n     */\n    public every(predicate: KeyedIteratee<K, T, boolean>): ReducedIterator<K, boolean>\n    {\n        const values = new Map<K, [number, boolean]>();\n\n        for (const [key, element] of this._elements)\n        {\n            const [index, result] = values.get(key) ?? [0, true];\n\n            if (!(result)) { continue; }\n\n            values.set(key, [index + 1, predicate(key, element, index)]);\n        }\n\n        return new ReducedIterator(function* (): Generator<[K, boolean]>\n        {\n            for (const [key, [_, result]] of values) { yield [key, result]; }\n        });\n    }\n\n    /**\n     * Determines whether any elements of each group of the iterator satisfy a given condition.\n     * See also {@link AggregatedIterator.every}.  \n     * This method will consume the entire iterator in the process.\n     *\n     * It will iterate over all elements of the iterator checking if they satisfy the condition.  \n     * Once a single element of one group satisfies the condition,\n     * the result for the respective group will be `true`.\n     *\n     * Eventually, it will return a new {@link ReducedIterator}\n     * object that will contain all the boolean results for each group.  \n     * If the iterator is infinite, the method will never return.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const results = new SmartIterator<number>([-5, -4, -3, -2, -1, 0])\n     *     .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n     *     .some((key, value) => value >= 0);\n     *\n     * console.log(results.toObject()); // { odd: false, even: true }\n     * ```\n     *\n     * ---\n     *\n     * @param predicate The condition to check for each element of the iterator.\n     *\n     * @returns A {@link ReducedIterator} containing the boolean results for each group.\n     */\n    public some(predicate: KeyedIteratee<K, T, boolean>): ReducedIterator<K, boolean>\n    {\n        const values = new Map<K, [number, boolean]>();\n\n        for (const [key, element] of this._elements)\n        {\n            const [index, result] = values.get(key) ?? [0, false];\n\n            if (result) { continue; }\n\n            values.set(key, [index + 1, predicate(key, element, index)]);\n        }\n\n        return new ReducedIterator(function* (): Generator<[K, boolean]>\n        {\n            for (const [key, [_, result]] of values) { yield [key, result]; }\n        });\n    }\n\n    /**\n     * Filters the elements of the iterator using a given condition.\n     *\n     * This method will iterate over all elements of the iterator checking if they satisfy the condition.  \n     * If the condition is met, the element will be included in the new iterator.\n     *\n     * Since the iterator is lazy, the filtering process will\n     * be executed once the resulting iterator is materialized.\n     *\n     * A new iterator will be created, holding the reference to the original one.  \n     * This means that the original iterator won't be consumed until the\n     * new one is and that consuming one of them will consume the other as well.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n     *     .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n     *     .filter((key, value) => value >= 0);\n     *\n     * console.log(results.toObject()); // { odd: [3, 5], even: [0, 2, 6, 8] }\n     * ```\n     *\n     * ---\n     *\n     * @param predicate The condition to check for each element of the iterator.\n     *\n     * @returns A new {@link AggregatedIterator} containing only the elements that satisfy the condition.\n     */\n    public filter(predicate: KeyedIteratee<K, T, boolean>): AggregatedIterator<K, T>;\n\n    /**\n     * Filters the elements of the iterator using a given condition.\n     *\n     * This method will iterate over all elements of the iterator checking if they satisfy the condition.  \n     * If the condition is met, the element will be included in the new iterator.\n     *\n     * Since the iterator is lazy, the filtering process will\n     * be executed once the resulting iterator is materialized.\n     *\n     * A new iterator will be created, holding the reference to the original one.  \n     * This means that the original iterator won't be consumed until the\n     * new one is and that consuming one of them will consume the other as well.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const results = new SmartIterator<number | string>([-3, \"-1\", 0, \"2\", \"3\", 5, 6, \"8\"])\n     *     .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n     *     .filter<number>((key, value) => typeof value === \"number\");\n     *\n     * console.log(results.toObject()); // { odd: [-3, 5], even: [0, 6] }\n     * ```\n     *\n     * ---\n     *\n     * @template S\n     * The type of the elements that satisfy the condition.  \n     * This allows the type-system to infer the correct type of the new iterator.\n     *\n     * It must be a subtype of the original type of the elements.\n     *\n     * @param predicate The type guard condition to check for each element of the iterator.\n     *\n     * @returns A new {@link AggregatedIterator} containing only the elements that satisfy the condition.\n     */\n    public filter<S extends T>(predicate: KeyedTypeGuardPredicate<K, T, S>): AggregatedIterator<K, S>;\n    public filter(predicate: KeyedIteratee<K, T, boolean>): AggregatedIterator<K, T>\n    {\n        const elements = this._elements;\n\n        return new AggregatedIterator(function* (): Generator<[K, T]>\n        {\n            const indexes = new Map<K, number>();\n            for (const [key, element] of elements)\n            {\n                const index = indexes.get(key) ?? 0;\n                if (predicate(key, element, index)) { yield [key, element]; }\n\n                indexes.set(key, index + 1);\n            }\n        });\n    }\n\n    /**\n     * Maps the elements of the iterator using a given transformation function.\n     *\n     * This method will iterate over all elements of the iterator applying the transformation function.  \n     * The result of each transformation will be included in the new iterator.\n     *\n     * Since the iterator is lazy, the mapping process will\n     * be executed once the resulting iterator is materialized.\n     *\n     * A new iterator will be created, holding the reference to the original one.  \n     * This means that the original iterator won't be consumed until the\n     * new one is and that consuming one of them will consume the other as well.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n     *     .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n     *     .map((key, value) => Math.abs(value));\n     *\n     * console.log(results.toObject()); // { odd: [3, 1, 3, 5], even: [0, 2, 6, 8] }\n     * ```\n     *\n     * ---\n     *\n     * @template V The type of the elements after the transformation.\n     *\n     * @param iteratee The transformation function to apply to each element of the iterator.\n     *\n     * @returns A new {@link AggregatedIterator} containing the transformed elements.\n     */\n    public map<V>(iteratee: KeyedIteratee<K, T, V>): AggregatedIterator<K, V>\n    {\n        const elements = this._elements;\n\n        return new AggregatedIterator(function* (): Generator<[K, V]>\n        {\n            const indexes = new Map<K, number>();\n            for (const [key, element] of elements)\n            {\n                const index = indexes.get(key) ?? 0;\n                yield [key, iteratee(key, element, index)];\n\n                indexes.set(key, index + 1);\n            }\n        });\n    }\n\n    /**\n     * Reduces the elements of the iterator using a given reducer function.  \n     * This method will consume the entire iterator in the process.\n     *\n     * It will iterate over all elements of the iterator applying the reducer function.  \n     * The result of each iteration will be passed as the accumulator to the next one.\n     *\n     * The first accumulator value will be the first element of the iterator.  \n     * The last accumulator value will be the final result of the reduction.\n     *\n     * Eventually, it will return a new {@link ReducedIterator}\n     * object that will contain all the reduced results for each group.  \n     * If the iterator is infinite, the method will never return.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n     *     .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n     *     .reduce((key, accumulator, value) => accumulator + value);\n     *\n     * console.log(results.toObject()); // { odd: 4, even: 16 }\n     * ```\n     *\n     * ---\n     *\n     * @param reducer The reducer function to apply to each element of the iterator.\n     *\n     * @returns A new {@link ReducedIterator} containing the reduced results for each group.\n     */\n    public reduce(reducer: KeyedReducer<K, T, T>): ReducedIterator<K, T>;\n\n    /**\n     * Reduces the elements of the iterator using a given reducer function.  \n     * This method will consume the entire iterator in the process.\n     *\n     * It will iterate over all elements of the iterator applying the reducer function.  \n     * The result of each iteration will be passed as the accumulator to the next one.\n     *\n     * The first accumulator value will be the provided initial value.  \n     * The last accumulator value will be the final result of the reduction.\n     *\n     * Eventually, it will return a new {@link ReducedIterator}\n     * object that will contain all the reduced results for each group.  \n     * If the iterator is infinite, the method will never return.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n     *     .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n     *     .reduce((key, accumulator, value) => accumulator + value, 0);\n     *\n     * console.log(results.toObject()); // { odd: 4, even: 16 }\n     * ```\n     *\n     * ---\n     *\n     * @template A The type of the accumulator value which will also be the type of the final result of the reduction.\n     *\n     * @param reducer The reducer function to apply to each element of the iterator.\n     * @param initialValue The initial value of the accumulator.\n     *\n     * @returns A new {@link ReducedIterator} containing the reduced results for each group.\n     */\n    public reduce<A extends PropertyKey>(reducer: KeyedReducer<K, T, A>, initialValue: A): ReducedIterator<K, A>;\n\n    /**\n     * Reduces the elements of the iterator using a given reducer function.  \n     * This method will consume the entire iterator in the process.\n     *\n     * It will iterate over all elements of the iterator applying the reducer function.  \n     * The result of each iteration will be passed as the accumulator to the next one.\n     *\n     * The first accumulator value will be the provided initial value by the given function.  \n     * The last accumulator value will be the final result of the reduction.\n     *\n     * Eventually, it will return a new {@link ReducedIterator}\n     * object that will contain all the reduced results for each group.  \n     * If the iterator is infinite, the method will never return.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n     *     .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n     *     .reduce((key, { value }, currentValue) => ({ value: value + currentValue }), (key) => ({ value: 0 }));\n     *\n     * console.log(results.toObject()); // { odd: { value: 4 }, even: { value: 16 } }\n     * ```\n     *\n     * ---\n     *\n     * @template A The type of the accumulator value which will also be the type of the final result of the reduction.\n     *\n     * @param reducer The reducer function to apply to each element of the iterator.\n     * @param initialValue The function that provides the initial value for the accumulator.\n     *\n     * @returns A new {@link ReducedIterator} containing the reduced results for each group.\n     */\n    public reduce<A>(reducer: KeyedReducer<K, T, A>, initialValue: (key: K) => A): ReducedIterator<K, A>;\n    public reduce<A>(reducer: KeyedReducer<K, T, A>, initialValue?: A | ((key: K) => A)): ReducedIterator<K, A>\n    {\n        const values = new Map<K, [number, A]>();\n\n        for (const [key, element] of this._elements)\n        {\n            let index: number;\n            let accumulator: A;\n\n            if (values.has(key)) { [index, accumulator] = values.get(key)!; }\n            else if (initialValue !== undefined)\n            {\n                index = 0;\n\n                if (initialValue instanceof Function) { accumulator = initialValue(key); }\n                else { accumulator = initialValue; }\n            }\n            else\n            {\n                values.set(key, [0, (element as unknown) as A]);\n\n                continue;\n            }\n\n            values.set(key, [index + 1, reducer(key, accumulator, element, index)]);\n        }\n\n        return new ReducedIterator(function* (): Generator<[K, A]>\n        {\n            for (const [key, [_, accumulator]] of values) { yield [key, accumulator]; }\n        });\n    }\n\n    /**\n     * Flattens the elements of the iterator using a given transformation function.\n     *\n     * This method will iterate over all elements of the iterator applying the transformation function.  \n     * The result of each transformation will be included in the new iterator.\n     *\n     * Since the iterator is lazy, the flattening process will\n     * be executed once the resulting iterator is materialized.\n     *\n     * A new iterator will be created, holding the reference to the original one.  \n     * This means that the original iterator won't be consumed until the\n     * new one is and that consuming one of them will consume the other as well.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const results = new SmartIterator<number[]>([[-3, -1], 0, 2, 3, 5, [6, 8]])\n     *      .groupBy((values) =>\n     *      {\n     *          const value = values instanceof Array ? values[0] : values;\n     *          return value % 2 === 0 ? \"even\" : \"odd\";\n     *      })\n     *     .flatMap((key, values) => values);\n     *\n     * console.log(results.toObject()); // { odd: [-3, -1, 3, 5], even: [0, 2, 6, 8] }\n     * ```\n     *\n     * ---\n     *\n     * @template V The type of the elements after the transformation.\n     *\n     * @param iteratee The transformation function to apply to each element of the iterator.\n     *\n     * @returns A new {@link AggregatedIterator} containing the transformed elements.\n     */\n    public flatMap<V>(iteratee: KeyedIteratee<K, T, V | readonly V[]>): AggregatedIterator<K, V>\n    {\n        const elements = this._elements;\n\n        return new AggregatedIterator(function* (): Generator<[K, V]>\n        {\n            const indexes = new Map<K, number>();\n            for (const [key, element] of elements)\n            {\n                const index = indexes.get(key) ?? 0;\n                const values = iteratee(key, element, index);\n\n                if (values instanceof Array)\n                {\n                    for (const value of values) { yield [key, value]; }\n                }\n                else { yield [key, values]; }\n\n                indexes.set(key, index + 1);\n            }\n        });\n    }\n\n    /**\n     * Drops a given number of elements from the beginning of each group of the iterator.  \n     * The remaining elements will be included in the new iterator.\n     * See also {@link AggregatedIterator.take}.\n     *\n     * Since the iterator is lazy, the dropping process will\n     * be executed once the resulting iterator is materialized.\n     *\n     * A new iterator will be created, holding the reference to the original one.  \n     * This means that the original iterator won't be consumed until the\n     * new one is and that consuming one of them will consume the other as well.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n     *     .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n     *     .drop(2);\n     *\n     * console.log(results.toObject()); // { odd: [3, 5], even: [6, 8] }\n     * ```\n     *\n     * ---\n     *\n     * @param count The number of elements to drop from the beginning of each group.\n     *\n     * @returns A new {@link AggregatedIterator} containing the remaining elements.\n     */\n    public drop(count: number): AggregatedIterator<K, T>\n    {\n        const elements = this._elements;\n\n        return new AggregatedIterator(function* (): Generator<[K, T]>\n        {\n            const indexes = new Map<K, number>();\n            for (const [key, element] of elements)\n            {\n                const index = indexes.get(key) ?? 0;\n                if (index < count)\n                {\n                    indexes.set(key, index + 1);\n\n                    continue;\n                }\n\n                yield [key, element];\n            }\n        });\n    }\n\n    /**\n     * Takes a given number of elements from the beginning of each group of the iterator.  \n     * The elements will be included in the new iterator.\n     * See also {@link AggregatedIterator.drop}.\n     *\n     * Since the iterator is lazy, the taking process will\n     * be executed once the resulting iterator is materialized.\n     *\n     * A new iterator will be created, holding the reference to the original one.  \n     * This means that the original iterator won't be consumed until the\n     * new one is and that consuming one of them will consume the other as well.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n     *     .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n     *     .take(2);\n     *\n     * console.log(results.toObject()); // { odd: [-3, -1], even: [0, 2] }\n     * ```\n     *\n     * ---\n     *\n     * @param limit The number of elements to take from the beginning of each group.\n     *\n     * @returns A new {@link AggregatedIterator} containing the taken elements.\n     */\n    public take(limit: number): AggregatedIterator<K, T>\n    {\n        const elements = this._elements;\n\n        return new AggregatedIterator(function* (): Generator<[K, T]>\n        {\n            const indexes = new Map<K, number>();\n            for (const [key, element] of elements)\n            {\n                const index = indexes.get(key) ?? 0;\n                if (index >= limit) { continue; }\n                yield [key, element];\n\n                indexes.set(key, index + 1);\n            }\n        });\n    }\n\n    /**\n     * Finds the first element of each group of the iterator that satisfies a given condition.  \n     * This method will consume the entire iterator in the process.\n     *\n     * It will iterate over all elements of the iterator checking if they satisfy the condition.  \n     * Once the first element of one group satisfies the condition,\n     * the result for the respective group will be the element itself.\n     *\n     * Eventually, it will return a new {@link ReducedIterator}\n     * object that will contain the first element that satisfies the condition for each group.  \n     * If the iterator is infinite, the method will never return.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n     *     .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n     *     .find((key, value) => value > 0);\n     *\n     * console.log(results.toObject()); // { odd: 3, even: 2 }\n     * ```\n     *\n     * ---\n     *\n     * @param predicate The condition to check for each element of the iterator.\n     *\n     * @returns A new {@link ReducedIterator} containing the first element that satisfies the condition for each group.\n     */\n    public find(predicate: KeyedIteratee<K, T, boolean>): ReducedIterator<K, T | undefined>;\n\n    /**\n     * Finds the first element of each group of the iterator that satisfies a given condition.  \n     * This method will consume the entire iterator in the process.\n     *\n     * It will iterate over all elements of the iterator checking if they satisfy the condition.  \n     * Once the first element of one group satisfies the condition,\n     * the result for the respective group will be the element itself.\n     *\n     * Eventually, it will return a new {@link ReducedIterator}\n     * object that will contain the first element that satisfies the condition for each group.  \n     * If the iterator is infinite, the method will never return.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const results = new SmartIterator<number | string>([-3, \"-1\", 0, \"2\", \"3\", 5, 6, \"8\"])\n     *     .groupBy((value) => Number(value) % 2 === 0 ? \"even\" : \"odd\")\n     *     .find<number>((key, value) => typeof value === \"number\");\n     *\n     * console.log(results.toObject()); // { odd: -3, even: 0 }\n     * ```\n     *\n     * ---\n     *\n     * @template S\n     * The type of the elements that satisfy the condition.  \n     * This allows the type-system to infer the correct type of the new iterator.\n     *\n     * It must be a subtype of the original type of the elements.\n     *\n     * @param predicate The type guard condition to check for each element of the iterator.\n     *\n     * @returns A new {@link ReducedIterator} containing the first element that satisfies the condition for each group.\n     */\n    public find<S extends T>(predicate: KeyedTypeGuardPredicate<K, T, S>): ReducedIterator<K, S | undefined>;\n    public find(predicate: KeyedIteratee<K, T, boolean>): ReducedIterator<K, T | undefined>\n    {\n        const values = new Map<K, [number, T | undefined]>();\n\n        for (const [key, element] of this._elements)\n        {\n            let [index, finding] = values.get(key) ?? [0, undefined];\n\n            if (finding !== undefined) { continue; }\n            if (predicate(key, element, index)) { finding = element; }\n\n            values.set(key, [index + 1, finding]);\n        }\n\n        return new ReducedIterator(function* (): Generator<[K, T | undefined]>\n        {\n            for (const [key, [_, finding]] of values) { yield [key, finding]; }\n        });\n    }\n\n    /**\n     * Enumerates the elements of the iterator.  \n     * Each element is paired with its index within the group in a new iterator.\n     *\n     * Since the iterator is lazy, the enumeration process will\n     * be executed once the resulting iterator is materialized.\n     *\n     * A new iterator will be created, holding the reference to the original one.  \n     * This means that the original iterator won't be consumed until the\n     * new one is and that consuming one of them will consume the other as well.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const results = new SmartIterator<number>([-3, 0, 2, -1, 3])\n     *     .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n     *     .enumerate();\n     *\n     * console.log(results.toObject()); // { odd: [[0, -3], [1, -1], [2, 3]], even: [[0, 0], [1, 2]] }\n     * ```\n     *\n     * ---\n     *\n     * @returns A new {@link AggregatedIterator} containing the enumerated elements.\n     */\n    public enumerate(): AggregatedIterator<K, [number, T]>\n    {\n        return this.map((_, value, index) => [index, value]);\n    }\n\n    /**\n     * Removes all duplicate elements from within each group of the iterator.  \n     * The first occurrence of each element will be included in the new iterator.\n     *\n     * Since the iterator is lazy, the deduplication process will\n     * be executed once the resulting iterator is materialized.\n     *\n     * A new iterator will be created, holding the reference to the original one.  \n     * This means that the original iterator won't be consumed until the\n     * new one is and that consuming one of them will consume the other as well.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 6, -3, -1, 0, 5, 6, 8, 0, 2])\n     *     .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n     *     .unique();\n     *\n     * console.log(results.toObject()); // { odd: [-3, -1, 3, 5], even: [0, 2, 6, 8] }\n     * ```\n     *\n     * ---\n     *\n     * @returns A new {@link AggregatedIterator} containing only the unique elements.\n     */\n    public unique(): AggregatedIterator<K, T>\n    {\n        const elements = this._elements;\n\n        return new AggregatedIterator(function* (): Generator<[K, T]>\n        {\n            const keys = new Map<K, Set<T>>();\n            for (const [key, element] of elements)\n            {\n                const values = keys.get(key) ?? new Set<T>();\n                if (values.has(element)) { continue; }\n\n                values.add(element);\n                keys.set(key, values);\n\n                yield [key, element];\n            }\n        });\n    }\n\n    /**\n     * Counts the number of elements within each group of the iterator.  \n     * This method will consume the entire iterator in the process.\n     *\n     * If the iterator is infinite, the method will never return.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n     *     .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n     *     .count();\n     *\n     * console.log(results.toObject()); // { odd: 4, even: 4 }\n     * ```\n     *\n     * ---\n     *\n     * @returns A new {@link ReducedIterator} containing the number of elements for each group.\n     */\n    public count(): ReducedIterator<K, number>\n    {\n        const counters = new Map<K, number>();\n\n        for (const [key] of this._elements)\n        {\n            const count = counters.get(key) ?? 0;\n\n            counters.set(key, count + 1);\n        }\n\n        return new ReducedIterator(function* (): Generator<[K, number]>\n        {\n            for (const [key, count] of counters) { yield [key, count]; }\n        });\n    }\n\n    /**\n     * Iterates over the elements of the iterator.  \n     * The elements are passed to the given iteratee function along with their key and index within the group.\n     *\n     * This method will consume the entire iterator in the process.  \n     * If the iterator is infinite, the method will never return.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const aggregator = new SmartIterator<number>([-3, 0, 2, -1, 3])\n     *     .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\");\n     *\n     * aggregator.forEach((key, value, index) =>\n     * {\n     *     console.log(`${index}: ${value}`); // \"0: -3\", \"0: 0\", \"1: 2\", \"1: -1\", \"2: 3\"\n     * };\n     * ```\n     *\n     * ---\n     *\n     * @param iteratee The function to execute for each element of the iterator.\n     */\n    public forEach(iteratee: KeyedIteratee<K, T>): void\n    {\n        const indexes = new Map<K, number>();\n        for (const [key, element] of this._elements)\n        {\n            const index = indexes.get(key) ?? 0;\n            iteratee(key, element, index);\n\n            indexes.set(key, index + 1);\n        }\n    }\n\n    /**\n     * Changes the key of each element on which the iterator is aggregated.  \n     * The new key is determined by the given iteratee function.\n     *\n     * Since the iterator is lazy, the reorganization process will\n     * be executed once the resulting iterator is materialized.\n     *\n     * A new iterator will be created, holding the reference to the original one.  \n     * This means that the original iterator won't be consumed until the\n     * new one is and that consuming one of them will consume the other as well.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n     *     .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n     *     .map((key, value, index) => index % 2 === 0 ? value : -value)\n     *     .reorganizeBy((key, value) => value >= 0 ? \"+\" : \"-\");\n     *\n     * console.log(results.toObject()); // { \"+\": [1, 0, 3, 6], \"-\": [-3, -2, -5, -8] }\n     * ```\n     *\n     * ---\n     *\n     * @template J The type of the new key.\n     *\n     * @param iteratee The function to determine the new key for each element of the iterator.\n     *\n     * @returns A new {@link AggregatedIterator} containing the elements reorganized by the new keys.\n     */\n    public reorganizeBy<J extends PropertyKey>(iteratee: KeyedIteratee<K, T, J>): AggregatedIterator<J, T>\n    {\n        const elements = this._elements;\n\n        return new AggregatedIterator(function* (): Generator<[J, T]>\n        {\n            const indexes = new Map<K, number>();\n            for (const [key, element] of elements)\n            {\n                const index = indexes.get(key) ?? 0;\n                yield [iteratee(key, element, index), element];\n\n                indexes.set(key, index + 1);\n            }\n        });\n    }\n\n    /**\n     * An utility method that returns a new {@link SmartIterator}\n     * object containing all the keys of the iterator.\n     *\n     * Since the iterator is lazy, the keys will be extracted\n     * be executed once the resulting iterator is materialized.\n     *\n     * A new iterator will be created, holding the reference to the original one.  \n     * This means that the original iterator won't be consumed until the\n     * new one is and that consuming one of them will consume the other as well.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const keys = new SmartIterator([-3, Symbol(), \"A\", { }, null, [1 , 2, 3], false])\n     *     .groupBy((value) => typeof value)\n     *     .keys();\n     *\n     * console.log(keys.toArray()); // [\"number\", \"symbol\", \"string\", \"object\", \"boolean\"]\n     * ```\n     *\n     * ---\n     *\n     * @returns A new {@link SmartIterator} containing all the keys of the iterator.\n     */\n    public keys(): SmartIterator<K>\n    {\n        const elements = this._elements;\n\n        return new SmartIterator<K>(function* ()\n        {\n            const keys = new Set<K>();\n            for (const [key] of elements)\n            {\n                if (keys.has(key)) { continue; }\n                keys.add(key);\n\n                yield key;\n            }\n        });\n    }\n\n    /**\n     * An utility method that returns a new {@link SmartIterator}\n     * object containing all the entries of the iterator.  \n     * Each entry is a tuple containing the key and the element.\n     *\n     * Since the iterator is lazy, the entries will be extracted\n     * be executed once the resulting iterator is materialized.\n     *\n     * A new iterator will be created, holding the reference to the original one.  \n     * This means that the original iterator won't be consumed until the\n     * new one is and that consuming one of them will consume the other as well.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const entries = new SmartIterator<number>([-3, 0, 2, -1, 3])\n     *     .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n     *     .entries();\n     *\n     * console.log(entries.toArray()); // [[\"odd\", -3], [\"even\", 0], [\"even\", 2], [\"odd\", -1], [\"odd\", 3]]\n     * ```\n     *\n     * ---\n     *\n     * @returns A new {@link SmartIterator} containing all the entries of the iterator.\n     */\n    public entries(): SmartIterator<[K, T]>\n    {\n        return this._elements;\n    }\n\n    /**\n     * An utility method that returns a new {@link SmartIterator}\n     * object containing all the values of the iterator.\n     *\n     * Since the iterator is lazy, the values will be extracted\n     * be executed once the resulting iterator is materialized.\n     *\n     * A new iterator will be created, holding the reference to the original one.  \n     * This means that the original iterator won't be consumed until the\n     * new one is and that consuming one of them will consume the other as well.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const values = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n     *     .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n     *     .values();\n     *\n     * console.log(values.toArray()); // [-3, -1, 0, 2, 3, 5, 6, 8]\n     * ```\n     *\n     * ---\n     *\n     * @returns A new {@link SmartIterator} containing all the values of the iterator.\n     */\n    public values(): SmartIterator<T>\n    {\n        const elements = this._elements;\n\n        return new SmartIterator<T>(function* ()\n        {\n            for (const [_, element] of elements) { yield element; }\n        });\n    }\n\n    /**\n     * Materializes the iterator into an array of arrays.  \n     * This method will consume the entire iterator in the process.\n     *\n     * If the iterator is infinite, the method will never return.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const aggregator = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n     *     .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\");\n     *\n     * console.log(aggregator.toArray()); // [[-3, -1, 3, 5], [0, 2, 6, 8]]\n     * ```\n     *\n     * ---\n     *\n     * @returns An {@link Array} of arrays containing the elements of the iterator.\n     */\n    public toArray(): T[][]\n    {\n        const map = this.toMap();\n\n        return Array.from(map.values());\n    }\n\n    /**\n     * Materializes the iterator into a map.  \n     * This method will consume the entire iterator in the process.\n     *\n     * If the iterator is infinite, the method will never return.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const aggregator = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n     *     .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\");\n     *\n     * console.log(aggregator.toMap()); // Map(2) { \"odd\" => [-3, -1, 3, 5], \"even\" => [0, 2, 6, 8] }\n     * ```\n     *\n     * ---\n     *\n     * @returns A {@link Map} containing the elements of the iterator.\n     */\n    public toMap(): Map<K, T[]>\n    {\n        const groups = new Map<K, T[]>();\n\n        for (const [key, element] of this._elements)\n        {\n            const value = groups.get(key) ?? [];\n\n            value.push(element);\n            groups.set(key, value);\n        }\n\n        return groups;\n    }\n\n    /**\n     * Materializes the iterator into an object.  \n     * This method will consume the entire iterator in the process.\n     *\n     * If the iterator is infinite, the method will never return.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const aggregator = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n     *     .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\");\n     *\n     * console.log(aggregator.toObject()); // { odd: [-3, -1, 3, 5], even: [0, 2, 6, 8] }\n     * ```\n     *\n     * ---\n     *\n     * @returns An {@link Object} containing the elements of the iterator.\n     */\n    public toObject(): Record<K, T[]>\n    {\n        const groups = { } as Record<K, T[]>;\n\n        for (const [key, element] of this._elements)\n        {\n            const value = groups[key] ?? [];\n\n            value.push(element);\n            groups[key] = value;\n        }\n\n        return groups;\n    }\n\n    public readonly [Symbol.toStringTag]: string = \"AggregatedIterator\";\n}\n","import type { Callback } from \"./types.js\";\n\nconst SmartFunction = (Function as unknown) as new<A extends unknown[] = [], R = void>(...args: string[])\n=> Callback<A, R>;\n\n/**\n * An abstract class that can be used to implement callable objects.\n *\n * ---\n *\n * @example\n * ```ts\n * class ActivableCallback extends CallableObject<(evt: PointerEvent) => void>\n * {\n *     public enabled = false;\n *     protected _invoke(): void\n *     {\n *         if (this.enabled) { [...] }\n *     }\n * }\n *\n * const callback = new ActivableCallback();\n *\n * window.addEventListener(\"pointerdown\", () => { callback.enabled = true; });\n * window.addEventListener(\"pointermove\", callback);\n * window.addEventListener(\"pointerup\", () => { callback.enabled = false; });\n * ```\n *\n * ---\n *\n * @template T\n * The type signature of the callback function.  \n * It must be a function. Default is `() => void`.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport default abstract class CallableObject<T extends Callback<any[], any> = Callback>\n    extends SmartFunction<Parameters<T>, ReturnType<T>>\n{\n    /**\n     * Initializes a new instance of the {@link CallableObject} class.\n     */\n    public constructor()\n    {\n        super(\"return this._invoke(...arguments);\");\n\n        const self = this.bind(this);\n        Object.setPrototypeOf(this, self);\n\n        return self as this;\n    }\n\n    /**\n     * The method that will be called when the object is invoked.  \n     * It must be implemented by the derived classes.\n     *\n     * ---\n     *\n     * @param args The arguments that have been passed to the object.\n     *\n     * @returns The return value of the method.\n     */\n    protected abstract _invoke(...args: Parameters<T>): ReturnType<T>;\n\n    public readonly [Symbol.toStringTag]: string = \"CallableObject\";\n}\n","import CallableObject from \"./callable-object.js\";\nimport type { Callback } from \"./types.js\";\n\n/**\n * A class that collects multiple functions or callbacks and executes them sequentially when invoked.\n *\n * This is particularly useful for managing multiple cleanup operations, such as\n * collecting unsubscribe callbacks from event subscriptions and calling them all at once.\n *\n * ---\n *\n * @example\n * ```ts\n * const unsubscribeAll = new CallbackChain<() => void>()\n *     .add(() => console.log(\"Doing something...\"))\n *     .add(() => console.log(\"Doing something else...\"))\n *     .add(() => console.log(\"Doing yet another thing...\"));\n *\n * unsubscribeAll(); // Doing something...\n *                   // Doing something else...\n *                   // Doing yet another thing...\n * ```\n *\n * ---\n *\n * @template T\n * The type signature of the functions in the chain.  \n * All functions must share the same signature. Default is `() => void`.\n */\nexport default class CallbackChain<\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    T extends Callback<any[], any> = Callback,\n    P extends Parameters<T> = Parameters<T>,\n    R extends ReturnType<T> = ReturnType<T>\n> extends CallableObject<Callback<P, R[]>>\n{\n    /**\n     * The array containing all the functions in the chain.\n     */\n    protected readonly _callbacks: T[];\n\n    /**\n     * Gets the number of functions currently in the chain.\n     */\n    public get size(): number\n    {\n        return this._callbacks.length;\n    }\n\n    /**\n     * Initializes a new instance of the {@link CallbackChain} class.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const chain = new CallbackChain();\n     * ```\n     *\n     * ---\n     *\n     * @param callback Optional initial functions to add to the chain.\n     */\n    public constructor(...callback: T[])\n    {\n        super();\n\n        this._callbacks = callback;\n    }\n\n    /**\n     * Executes all functions in the chain sequentially with the provided arguments.\n     *\n     * ---\n     *\n     * @param args The arguments to pass to each function in the chain.\n     *\n     * @returns An array containing the return values of all functions.\n     */\n    protected override _invoke(...args: Parameters<T>): ReturnType<T>[]\n    {\n        const length = this._callbacks.length;\n        const results = new Array<ReturnType<T>>(length);\n        for (let i = 0; i < length; i += 1)\n        {\n            results[i] = this._callbacks[i](...args);\n        }\n\n        return results;\n    }\n\n    /**\n     * Adds a function to the chain.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const chain = new CallbackChain();\n     * const cleanup = () => console.log(\"Cleaning up...\"));\n     *\n     * chain.add(cleanup);\n     * ```\n     *\n     * ---\n     *\n     * @param callback The function to add to the chain.\n     *\n     * @returns The current instance for method chaining.\n     */\n    public add(callback: T): this\n    {\n        this._callbacks.push(callback);\n\n        return this;\n    }\n\n    /**\n     * Removes a specific function from the chain.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const chain = new CallbackChain();\n     * const cleanup = () => console.log(\"Cleaning up...\"));\n     *\n     * chain.add(cleanup);\n     * chain.remove(cleanup);\n     * ```\n     *\n     * ---\n     *\n     * @param callback The function to remove from the chain.\n     *\n     * @returns `true` if the function was found and removed, `false` otherwise.\n     */\n    public remove(callback: T): boolean\n    {\n        const index = this._callbacks.indexOf(callback);\n        if (index < 0) { return false; }\n\n        this._callbacks.splice(index, 1);\n\n        return true;\n    }\n\n    /**\n     * Removes all functions from the chain.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const chain = new CallbackChain();\n     *\n     * chain.add(() => console.log(\"Doing something...\"));\n     * chain.add(() => console.log(\"Doing something else...\"));\n     * chain.add(() => console.log(\"Doing yet another thing...\"));\n     *\n     * chain.clear();\n     * ```\n     */\n    public clear(): void\n    {\n        this._callbacks.length = 0;\n    }\n\n    public override readonly [Symbol.toStringTag]: string = \"CallbackChain\";\n}\n","import { ReferenceException } from \"../exceptions/index.js\";\n\nimport type { Callback, CallbackMap, InternalsEventsMap, WildcardEventsMap } from \"./types.js\";\n\ntype P = InternalsEventsMap;\ntype S = WildcardEventsMap & InternalsEventsMap;\n\n/**\n * A class implementing the\n * {@link https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern|Publish-subscribe} pattern.\n *\n * It can be used to create a simple event system where objects can subscribe\n * to events and receive notifications when the events are published.  \n * It's a simple and efficient way to decouple the objects and make them communicate with each other.\n *\n * Using generics, it's also possible to define the type of the events and the callbacks that can be subscribed to them.\n *\n * ---\n *\n * @example\n * ```ts\n * interface EventsMap\n * {\n *     \"player:spawn\": (evt: SpawnEvent) => void;\n *     \"player:move\": ({ x, y }: Point) => void;\n *     \"player:death\": () => void;\n * }\n *\n * const publisher = new Publisher<EventsMap>();\n *\n * let unsubscribe: () => void;\n * publisher.subscribe(\"player:death\", unsubscribe);\n * publisher.subscribe(\"player:spawn\", (evt) =>\n * {\n *     unsubscribe = publisher.subscribe(\"player:move\", ({ x, y }) => { [...] });\n * });\n * ```\n *\n * ---\n *\n * @template T\n * A map containing the names of the emittable events and the\n * related callback signatures that can be subscribed to them.  \n * Default is `Record<string, (...args: unknown[]) => unknown>`.\n */\nexport default class Publisher<T extends CallbackMap<T> = CallbackMap>\n{\n    /**\n     * A map containing all the subscribers for each event.\n     *\n     * The keys are the names of the events they are subscribed to.  \n     * The values are the arrays of the subscribers themselves.\n     */\n    protected readonly _subscribers: Map<string, Callback<unknown[], unknown>[]>;\n\n    /**\n     * Initializes a new instance of the {@link Publisher} class.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const publisher = new Publisher();\n     * ```\n     */\n    public constructor()\n    {\n        this._subscribers = new Map();\n    }\n\n    /**\n     * Creates a new scoped instance of the {@link Publisher} class,\n     * which can be used to publish and subscribe events within a specific context.\n     *\n     * It can receive all events published to the parent publisher while also allowing\n     * the scoped publisher to handle its own events independently.  \n     * In fact, events published to the scoped publisher won't be propagated back to the parent publisher.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const publisher = new Publisher();\n     * const context = publisher.createScope();\n     *\n     * publisher.subscribe(\"player:death\", () => console.log(\"Player has died.\"));\n     * context.subscribe(\"player:spawn\", () => console.log(\"Player has spawned.\"));\n     *\n     * publisher.publish(\"player:spawn\"); // \"Player has spawned.\"\n     * context.publish(\"player:death\");   // * no output *\n     * ```\n     *\n     * ---\n     *\n     * @template U\n     * A map containing the additional names of the emittable events and\n     * the related callback signatures that can be subscribed to them.\n     * Default is `{ }`.\n     *\n     * @return\n     * A new instance of the {@link Publisher} class that can be\n     * used to publish and subscribe events within a specific context.\n     */\n\n    // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n    public createScope<U extends CallbackMap<U> = { }>(): Publisher<U & T>\n    {\n        const scope = new Publisher();\n\n        this.subscribe(\"__internals__:clear\", () => scope.clear());\n        this.subscribe(\"*\", (event, ...args): void => { scope.publish(event, ...args); });\n\n        return scope;\n    }\n\n    /**\n     * Publishes an event to all the subscribers.  \n     * This events will trigger the wildcard listeners as well, if any.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * publisher.subscribe(\"player:move\", (coords) => { [...] });\n     * publisher.subscribe(\"player:move\", ({ x, y }) => { [...] });\n     * publisher.subscribe(\"player:move\", (evt) => { [...] });\n     *\n     * publisher.publish(\"player:move\", { x: 10, y: 20 });\n     * ```\n     *\n     * ---\n     *\n     * @template K The key of the map containing the callback signature to publish.\n     *\n     * @param event The name of the event to publish.\n     * @param args The arguments to pass to the subscribers.\n     *\n     * @returns An array containing the return values of all the subscribers.\n     */\n    public publish<K extends keyof T>(event: K & string, ...args: Parameters<T[K]>): ReturnType<T[K]>[];\n\n    /**\n     * Publishes an internal event to all the subscribers.\n     *\n     * Internal events follow the pattern `__${string}__:${string}` and are used for internal\n     * communication within the publisher system. These events won't trigger wildcard listeners.  \n     * Please note to use this method only if you know what you are doing.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * publisher.subscribe(\"__internals__:clear\", () => console.log(\"Clearing...\"));\n     * publisher.publish(\"__internals__:clear\"); // \"Clearing...\"\n     * ```\n     *\n     * ---\n     *\n     * @template K The key of the internal events map containing the callback signature to publish.\n     *\n     * @param event The name of the internal event to publish.\n     * @param args The arguments to pass to the subscribers.\n     *\n     * @returns An array containing the return values of all the subscribers.\n     */\n    public publish<K extends keyof P>(event: K & string, ...args: Parameters<P[K]>): ReturnType<P[K]>[];\n    public publish(event: string, ...args: unknown[]): unknown[]\n    {\n        let results: unknown[];\n        let subscribers = this._subscribers.get(event);\n        if (subscribers)\n        {\n            const _subscribers = subscribers.slice();\n            const _length = _subscribers.length;\n\n            results = new Array<unknown>(_length);\n            for (let i = 0; i < _length; i += 1)\n            {\n                results[i] = _subscribers[i](...args);\n            }\n        }\n        else { results = []; }\n\n        if (!(event.startsWith(\"__\")))\n        {\n            subscribers = this._subscribers.get(\"*\");\n            if (subscribers)\n            {\n                subscribers.slice()\n                    .forEach((subscriber) => subscriber(event, ...args));\n            }\n        }\n\n        return results;\n    }\n\n    /**\n     * Subscribes to an event and adds a subscriber to be executed when the event is published.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * let unsubscribe: () => void;\n     * publisher.subscribe(\"player:death\", unsubscribe);\n     * publisher.subscribe(\"player:spawn\", (evt) =>\n     * {\n     *     unsubscribe = publisher.subscribe(\"player:move\", ({ x, y }) => { [...] });\n     * });\n     * ```\n     *\n     * ---\n     *\n     * @template K The key of the map containing the callback signature to subscribe.\n     *\n     * @param event The name of the event to subscribe to.\n     * @param subscriber The subscriber to execute when the event is published.\n     *\n     * @returns A function that can be used to unsubscribe the subscriber from the event.\n     */\n    public subscribe<K extends keyof T>(event: K & string, subscriber: T[K]): Callback;\n\n    /**\n     * Subscribes to the wildcard event to listen to all published events.\n     *\n     * The wildcard subscriber will be called for every event published, receiving\n     * the event type as the first parameter followed by all event arguments.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * publisher.subscribe(\"*\", (type, ...args) =>\n     * {\n     *     console.log(`Event \"${type}\" was fired with args:`, args);\n     * });\n     * ```\n     *\n     * ---\n     *\n     * @template K The key of the wildcard events map (always `*`).\n     *\n     * @param event The wildcard event name (`*`).\n     * @param subscriber The subscriber to execute for all published events.\n     *\n     * @returns A function that can be used to unsubscribe the subscriber from the wildcard event.\n     */\n    public subscribe<K extends keyof S>(event: K & string, subscriber: S[K]): Callback;\n    public subscribe(event: string, subscriber: Callback<unknown[], unknown>): Callback\n    {\n        const subscribers = this._subscribers.get(event) ?? [];\n        subscribers.push(subscriber);\n\n        this._subscribers.set(event, subscribers);\n\n        return () =>\n        {\n            const index = subscribers.indexOf(subscriber);\n            if (index < 0)\n            {\n                throw new ReferenceException(\"Unable to unsubscribe the required subscriber. \" +\n                    \"The subscription was already unsubscribed.\");\n            }\n\n            subscribers.splice(index, 1);\n        };\n    }\n\n    /**\n     * Unsubscribes from an event and removes a subscriber from being executed when the event is published.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const onPlayerMove = ({ x, y }: Point) => { [...] };\n     *\n     * publisher.subscribe(\"player:spawn\", (evt) => publisher.subscribe(\"player:move\", onPlayerMove));\n     * publisher.subscribe(\"player:death\", () => publisher.unsubscribe(\"player:move\", onPlayerMove));\n     * ```\n     *\n     * ---\n     *\n     * @template K The key of the map containing the callback signature to unsubscribe.\n     *\n     * @param event The name of the event to unsubscribe from.\n     * @param subscriber The subscriber to remove from the event.\n     */\n    public unsubscribe<K extends keyof T>(event: K & string, subscriber: T[K]): void;\n\n    /**\n     * Unsubscribes from the wildcard event and removes a subscriber from being executed for all events.\n     *\n     * This removes a previously registered wildcard listener that was capturing all published events.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const wildcardHandler = (type: string, ...args: unknown[]) => console.log(type, args);\n     * \n     * publisher.subscribe(\"*\", wildcardHandler);\n     * publisher.unsubscribe(\"*\", wildcardHandler);\n     * ```\n     *\n     * ---\n     *\n     * @template K The key of the wildcard events map (always `*`).\n     *\n     * @param event The wildcard event name (`*`).\n     * @param subscriber The wildcard subscriber to remove.\n     */\n    public unsubscribe<K extends keyof S>(event: K & string, subscriber: S[K]): void;\n    public unsubscribe(event: string, subscriber: Callback<unknown[], unknown>): void\n    {\n        const subscribers = this._subscribers.get(event);\n        if (!(subscribers))\n        {\n            throw new ReferenceException(\"Unable to unsubscribe the required subscriber. \" +\n                \"The subscription was already unsubscribed or was never subscribed.\");\n        }\n\n        const index = subscribers.indexOf(subscriber);\n        if (index < 0)\n        {\n            throw new ReferenceException(\"Unable to unsubscribe the required subscriber. \" +\n                \"The subscription was already unsubscribed or was never subscribed.\");\n        }\n\n        subscribers.splice(index, 1);\n        if (subscribers.length === 0) { this._subscribers.delete(event); }\n    }\n\n    /**\n     * Unsubscribes all subscribers from a specific event and removes\n     * them from being executed when the event is published.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * publisher.subscribe(\"player:spawn\", (evt) => { [...] });\n     * publisher.subscribe(\"player:move\", (coords) => { [...] });\n     * publisher.subscribe(\"player:move\", () => { [...] });\n     * publisher.subscribe(\"player:move\", ({ x, y }) => { [...] });\n     * publisher.subscribe(\"player:death\", () => { [...] });\n     *\n     * // All these subscribers are working fine...\n     *\n     * publisher.unsubscribeAll(\"player:move\");\n     *\n     * // ... but now \"player:move\" subscribers are gone!\n     * ```\n     *\n     * ---\n     *\n     * @template K The key of the map containing the event to clear.\n     *\n     * @param event The name of the event to unsubscribe all subscribers from.\n     */\n    public unsubscribeAll<K extends keyof T>(event: K & string): void;\n\n    /**\n     * Unsubscribes all subscribers from the wildcard event and removes\n     * them from being executed for all published events.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * publisher.subscribe(\"player:spawn\", (evt) => { [...] });\n     * publisher.subscribe(\"*\", (type, ...args) => { [...] });\n     * publisher.subscribe(\"*\", (type, arg1, arg2, arg3) => { [...] });\n     * publisher.subscribe(\"*\", (_, arg, ...rest) => { [...] });\n     * publisher.subscribe(\"player:death\", () => { [...] });\n     *\n     * // All these subscribers are working fine...\n     *\n     * publisher.unsubscribeAll(\"*\");\n     *\n     * // ... but now wildcard subscribers are gone!\n     * ```\n     *\n     * ---\n     *\n     * @template K The key of the wildcard events map (`*`).\n     *\n     * @param event The wildcard event name (`*`).\n     */\n    public unsubscribeAll<K extends keyof S>(event: K & string): void;\n    public unsubscribeAll(event: string): void\n    {\n        this._subscribers.delete(event);\n    }\n\n    /**\n     * Unsubscribes all the subscribers from all the events.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * publisher.subscribe(\"player:spawn\", (evt) => { [...] });\n     * publisher.subscribe(\"player:move\", (coords) => { [...] });\n     * publisher.subscribe(\"*\", () => { [...] });\n     * publisher.subscribe(\"player:move\", ({ x, y }) => { [...] });\n     * publisher.subscribe(\"player:death\", () => { [...] });\n     *\n     * // All these subscribers are working fine...\n     *\n     * publisher.clear();\n     *\n     * // ... but now they're all gone!\n     * ```\n     */\n    public clear(): void\n    {\n        this.publish(\"__internals__:clear\");\n\n        this._subscribers.clear();\n    }\n\n    public readonly [Symbol.toStringTag]: string = \"Publisher\";\n}\n","import { KeyException, NotImplementedException, RuntimeException } from \"../exceptions/index.js\";\n\nimport CallableObject from \"./callable-object.js\";\nimport type { Callback } from \"./types.js\";\n\nconst Disabler = () => { /* ... */ };\nconst NotImplemented = () =>\n{\n    throw new NotImplementedException(\n        \"The `SwitchableCallback` has no callback defined yet. Did you forget to call the `register` method?\"\n    );\n};\n\n/**\n * A class representing a callback that can be switched between multiple implementations.\n *\n * It can be used to implement different behaviors for the same event handler, allowing\n * it to respond to different states without incurring any overhead during execution.\n *\n * ---\n *\n * @example\n * ```ts\n * const onPointerMove = new SwitchableCallback<(evt: PointerEvent) => void>();\n *\n * onPointerMove.register(\"released\", () => { [...] });\n * onPointerMove.register(\"pressed\", () => { [...] });\n *\n * window.addEventListener(\"pointerdown\", () => onPointerMove.switch(\"pressed\"));\n * window.addEventListener(\"pointermove\", onPointerMove);\n * window.addEventListener(\"pointerup\", () => onPointerMove.switch(\"released\"));\n * ```\n *\n * ---\n *\n * @template T The type signature of the callback. Default is `() => void`.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport default class SwitchableCallback<T extends Callback<any[], any> = Callback> extends CallableObject<T>\n{\n    /**\n     * The currently selected implementation of the callback.\n     */\n    protected _callback: T;\n\n    /**\n     * All the implementations that have been registered for the callback.\n     *\n     * The keys are the names of the implementations they were registered with.  \n     * The values are the implementations themselves.\n     */\n    protected readonly _callbacks: Map<string, T>;\n\n    /**\n     * A flag indicating whether the callback is enabled or not.\n     *\n     * This protected property is the only one that can be modified directly by the derived classes.  \n     * If you're looking for the public and readonly property, use\n     * the {@link SwitchableCallback.isEnabled} getter instead.\n     */\n    protected _isEnabled: boolean;\n\n    /**\n     * A flag indicating whether the callback is enabled or not.\n     *\n     * It indicates whether the callback is currently able to execute the currently selected implementation.  \n     * If it's disabled, the callback will be invoked without executing anything.\n     */\n    public get isEnabled(): boolean { return this._isEnabled; }\n\n    /**\n     * The key that is associated with the currently selected implementation.\n     *\n     * This protected property is the only one that can be modified directly by the derived classes.  \n     * If you're looking for the public and readonly property, use the {@link SwitchableCallback.key} getter instead.\n     */\n    protected _key: string;\n\n    /**\n     * The key that is associated with the currently selected implementation.\n     */\n    public get key(): string { return this._key; }\n\n    /**\n     * The function that will be called by the extended class when the object is invoked as a function.\n     */\n    protected readonly _invoke: (...args: Parameters<T>) => ReturnType<T>;\n\n    /**\n     * Initializes a new instance of the {@link SwitchableCallback} class.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const onPointerMove = new SwitchableCallback<(evt: PointerEvent) => void>();\n     * ```\n     */\n    public constructor();\n\n    /**\n     * Initializes a new instance of the {@link SwitchableCallback}\n     * class with the specified callback enabled by default.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const onPointerMove = new SwitchableCallback<(evt: PointerEvent) => void>((evt) => { [...] });\n     * ```\n     *\n     * ---\n     *\n     * @param callback The callback that will be executed when the object is invoked as a function by default.\n     * @param key The key that is associated by default to the given callback. Default is `default`.\n     */\n    public constructor(callback: T, key?: string);\n    public constructor(callback?: T, key = \"default\")\n    {\n        super();\n\n        this._callbacks = new Map<string, T>();\n        this._isEnabled = true;\n\n        if (callback)\n        {\n            this._callbacks.set(key, callback);\n        }\n        else\n        {\n            key = \"\";\n            callback = (NotImplemented as unknown) as T;\n        }\n\n        this._key = key;\n\n        this._callback = callback;\n        this._invoke = (...args: Parameters<T>): ReturnType<T> => this._callback(...args);\n    }\n\n    /**\n     * Enables the callback, allowing it to execute the currently selected implementation.\n     *\n     * Also note that:\n     * - If any implementation has been registered yet, a {@link KeyException} will be thrown.  \n     * - If any key is given and it doesn't have any associated\n     * implementation yet, a {@link KeyException} will be thrown.\n     * - If the callback is already enabled, a {@link RuntimeException} will be thrown.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * window.addEventListener(\"pointerdown\", () => onPointerMove.enable());\n     * window.addEventListener(\"pointermove\", onPointerMove);\n     * ```\n     *\n     * ---\n     *\n     * @param key\n     * The key that is associated with the implementation to enable. Default is the currently selected implementation.\n     */\n    public enable(key?: string): void\n    {\n        if (key === undefined)\n        {\n            if (!(this._key))\n            {\n                throw new KeyException(\n                    \"The `SwitchableCallback` has no callback defined yet. \" +\n                    \"Did you forget to call the `register` method?\"\n                );\n            }\n\n            key = this._key;\n        }\n        else if (!(key))\n        {\n            throw new KeyException(\"The key must be a non-empty string.\");\n        }\n        else if (!(this._callbacks.has(key)))\n        {\n            throw new KeyException(`The key '${key}' doesn't yet have any associated callback.`);\n        }\n\n        if (this._isEnabled)\n        {\n            throw new RuntimeException(\"The `SwitchableCallback` is already enabled.\");\n        }\n\n        this._callback = this._callbacks.get(key)!;\n        this._isEnabled = true;\n    }\n\n    /**\n     * Disables the callback, allowing it to be invoked without executing any implementation.\n     *\n     * If the callback is already disabled, a {@link RuntimeException} will be thrown.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * window.addEventListener(\"pointermove\", onPointerMove);\n     * window.addEventListener(\"pointerup\", () => onPointerMove.disable());\n     * ```\n     */\n    public disable(): void\n    {\n        if (!(this._isEnabled))\n        {\n            throw new RuntimeException(\"The `SwitchableCallback` is already disabled.\");\n        }\n\n        this._callback = Disabler as T;\n        this._isEnabled = false;\n    }\n\n    /**\n     * Registers a new implementation for the callback.\n     *\n     * Also note that:\n     * - If the callback has no other implementation registered yet, this one will be selected as default.\n     * - If the key has already been used for another implementation, a {@link KeyException} will be thrown.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * onPointerMove.register(\"pressed\", () => { [...] });\n     * onPointerMove.register(\"released\", () => { [...] });\n     * ```\n     *\n     * ---\n     *\n     * @param key The key that will be associated with the implementation.\n     * @param callback The implementation to register.\n     */\n    public register(key: string, callback: T): void\n    {\n        if (this._callbacks.size === 0)\n        {\n            this._key = key;\n            this._callback = callback;\n        }\n        else if (this._callbacks.has(key))\n        {\n            throw new KeyException(`The key '${key}' has already been used for another callback.`);\n        }\n\n        this._callbacks.set(key, callback);\n    }\n\n    /**\n     * Unregisters an implementation for the callback.\n     *\n     * Also note that:\n     * - If the key is the currently selected implementation, a {@link KeyException} will be thrown.\n     * - If the key has no associated implementation yet, a {@link KeyException} will be thrown.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * onPointerMove.unregister(\"released\");\n     * ```\n     *\n     * ---\n     *\n     * @param key The key that is associated with the implementation to unregister.\n     */\n    public unregister(key: string): void\n    {\n        if (this._key === key)\n        {\n            throw new KeyException(\"Unable to unregister the currently selected callback.\");\n        }\n        if (!(this._callbacks.has(key)))\n        {\n            throw new KeyException(`The key '${key}' doesn't yet have any associated callback.`);\n        }\n\n        this._callbacks.delete(key);\n    }\n\n    /**\n     * Switches the callback to the implementation associated with the given key.\n     *\n     * If the key has no associated implementation yet, a {@link KeyException} will be thrown.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * window.addEventListener(\"pointerdown\", () => onPointerMove.switch(\"pressed\"));\n     * window.addEventListener(\"pointermove\", onPointerMove);\n     * window.addEventListener(\"pointerup\", () => onPointerMove.switch(\"released\"));\n     * ```\n     *\n     * ---\n     *\n     * @param key The key that is associated with the implementation to switch to.\n     */\n    public switch(key: string): void\n    {\n        if (!(this._callbacks.has(key)))\n        {\n            throw new KeyException(`The key '${key}' doesn't yet have any associated callback.`);\n        }\n\n        if (this._key === key) { return; }\n        this._key = key;\n\n        if (this._isEnabled)\n        {\n            this._callback = this._callbacks.get(key)!;\n        }\n    }\n\n    /**\n     * Resets the callback to its initial state, unregistering all the implementations at once.\n     *\n     * After calling this method, the callback will behave as if it had just been constructed:\n     * a {@link NotImplementedException} will be thrown when invoked before registering a new implementation.\n     *\n     * This will also re-enable the object, restoring the {@link SwitchableCallback.isEnabled} state to `true`.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * onPointerMove.reset();\n     * ```\n     */\n    public reset(): void;\n\n    /**\n     * Resets the callback to its initial state, unregistering all the previous\n     * implementations at once and setting the given one as the new default.\n     *\n     * After calling this method, the callback will behave as if it had just\n     * been constructed with the specified implementation enabled by default.\n     *\n     * This will also re-enable the object, restoring the {@link SwitchableCallback.isEnabled} state to `true`.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * onPointerMove.reset((evt) => { [...] });\n     * ```\n     *\n     * ---\n     *\n     * @param callback The callback that will be executed when the object is invoked as a function by default.\n     * @param key The key that is associated by default to the given callback. Default is `default`.\n     */\n    public reset(callback: T, key?: string): void;\n    public reset(callback?: T, key = \"default\"): void\n    {\n        this._callbacks.clear();\n        this._isEnabled = true;\n\n        if (callback)\n        {\n            this._callbacks.set(key, callback);\n        }\n        else\n        {\n            key = \"\";\n            callback = (NotImplemented as unknown) as T;\n        }\n\n        this._key = key;\n        this._callback = callback;\n    }\n\n    public override readonly [Symbol.toStringTag]: string = \"SwitchableCallback\";\n}\n","import Publisher from \"../callbacks/publisher.js\";\nimport type { Callback } from \"../types.js\";\n\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nimport type MapView from \"./map-view.js\";\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nimport type SetView from \"./set-view.js\";\n\ninterface ArrayViewEventsMap<T>\n{\n    \"add\": (value: T, index: number) => void;\n    \"remove\": (value: T, index: number) => void;\n\n    \"clear\": () => void;\n}\n\n/**\n * A wrapper class around the native {@link Array} class that provides additional functionality\n * for publishing events when entries are added, removed or the collection is cleared.\n * There are also complementary classes that work with the native `Map` and `Set` classes.\n * See also {@link MapView} and {@link SetView}.\n *\n * ---\n *\n * @example\n * ```ts\n * const array = new ArrayView<number>();\n *\n * array.onAdd((value: number, index: number) => console.log(`Added ${value} at index ${index}`));\n * array.push(42); // \"Added 42 at index 0\"\n * ```\n *\n * ---\n *\n * @template T The type of the values in the array.\n */\nexport default class ArrayView<T> extends Array<T>\n{\n    /**\n     * The internal {@link Publisher} instance used to publish events.\n     */\n    protected readonly _publisher: Publisher<ArrayViewEventsMap<T>>;\n\n    /**\n     * Initializes a new instance of the {@link ArrayView} class.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const array = new ArrayView<number>();\n     * ```\n     */\n    public constructor();\n\n    /**\n     * Initializes a new instance of the {@link ArrayView} class.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const array = new ArrayView<number>(3);\n     * ```\n     *\n     * ---\n     *\n     * @param length The initial length of the {@link Array}.\n     */\n    public constructor(length: number);\n\n    /**\n     * Initializes a new instance of the {@link ArrayView} class.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const array = new ArrayView<number>(2, 4, 8);\n     * ```\n     *\n     * ---\n     *\n     * @param items The items to initialize the {@link Array} with.\n     */\n    public constructor(...items: T[]);\n    public constructor(...items: T[])\n    {\n        super(...items);\n\n        this._publisher = new Publisher();\n    }\n\n    /**\n     * Appends new elements to the end of the {@link Array} and returns the new length of the array.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const array = new ArrayView<number>();\n     * array.push(2, 4, 8);\n     *\n     * console.log(array); // ArrayView(3) [2, 4, 8]\n     * ```\n     *\n     * ---\n     *\n     * @param items New elements to add to the array.\n     *\n     * @returns The new length of the array.\n     */\n    public override push(...items: T[]): number\n    {\n        const startIndex = this.length;\n\n        const result = super.push(...items);\n        for (let i = 0; i < items.length; i += 1)\n        {\n            this._publisher.publish(\"add\", items[i], startIndex + i);\n        }\n\n        return result;\n    }\n\n    /**\n     * Removes the last element from the {@link Array} and returns it.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const array = new ArrayView<number>(2, 4, 8);\n     * array.pop(); // 8\n     *\n     * console.log(array); // ArrayView(2) [2, 4]\n     * ```\n     *\n     * ---\n     *\n     * @returns The removed element, or `undefined` if the array is empty.\n     */\n    public override pop(): T | undefined\n    {\n        const index = this.length - 1;\n        if (index < 0) { return undefined; }\n\n        const value = super.pop();\n        this._publisher.publish(\"remove\", value!, index);\n\n        return value;\n    }\n\n    /**\n     * Removes the first element from the {@link Array} and returns it.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const array = new ArrayView<number>(2, 4, 8);\n     * array.shift(); // 2\n     *\n     * console.log(array); // ArrayView(2) [4, 8]\n     * ```\n     *\n     * ---\n     *\n     * @returns The removed element, or `undefined` if the array is empty.\n     */\n    public override shift(): T | undefined\n    {\n        if (this.length === 0) { return undefined; }\n\n        const value = super.shift();\n        this._publisher.publish(\"remove\", value!, 0);\n\n        return value;\n    }\n\n    /**\n     * Inserts new elements at the start of the {@link Array} and returns the new length of the array.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const array = new ArrayView<number>(4, 8);\n     * array.unshift(2);\n     *\n     * console.log(array); // ArrayView(3) [2, 4, 8]\n     * ```\n     *\n     * ---\n     *\n     * @param items Elements to insert at the start of the array.\n     *\n     * @returns The new length of the array.\n     */\n    public override unshift(...items: T[]): number\n    {\n        const result = super.unshift(...items);\n        for (let i = 0; i < items.length; i += 1)\n        {\n            this._publisher.publish(\"add\", items[i], i);\n        }\n\n        return result;\n    }\n\n    /**\n     * Removes elements from the {@link Array} and, if necessary, inserts new elements in their place,\n     * returning the deleted elements.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const array = new ArrayView<number>(2, 4, 8, 16);\n     * array.splice(1, 2, 32, 64); // [4, 8]\n     *\n     * console.log(array); // ArrayView(4) [2, 32, 64, 16]\n     * ```\n     *\n     * ---\n     *\n     * @param start The zero-based location in the array from which to start removing elements.\n     * @param deleteCount The number of elements to remove.\n     * @param items Elements to insert into the array in place of the deleted elements.\n     *\n     * @returns An array containing the elements that were deleted.\n     */\n    public override splice(start: number, deleteCount?: number, ...items: T[]): T[]\n    {\n        const normalizedStart = start < 0 ? Math.max(this.length + start, 0) : Math.min(start, this.length);\n\n        const actualDeleteCount = deleteCount === undefined ?\n            this.length - normalizedStart :\n            Math.min(Math.max(deleteCount, 0), this.length - normalizedStart);\n\n        const removed = super.splice(start, actualDeleteCount, ...items);\n        for (let i = 0; i < removed.length; i += 1)\n        {\n            this._publisher.publish(\"remove\", removed[i], normalizedStart + i);\n        }\n\n        for (let i = 0; i < items.length; i += 1)\n        {\n            this._publisher.publish(\"add\", items[i], normalizedStart + i);\n        }\n\n        return removed;\n    }\n\n    /**\n     * Removes all elements from the {@link Array}.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const array = new ArrayView<number>(2, 4, 8);\n     * array.clear();\n     *\n     * console.log(array); // ArrayView(0) []\n     * ```\n     */\n    public clear(): void\n    {\n        const length = this.length;\n        this.length = 0;\n\n        if (length > 0) { this._publisher.publish(\"clear\"); }\n    }\n\n    /**\n     * Subscribes to the `add` event of the array with a callback that will be executed when an element is added.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * array.onAdd((value, index) => console.log(`Added ${value} at index ${index}`));\n     *\n     * array.push(2);  // \"Added 2 at index 0\"\n     * array.push(42); // \"Added 42 at index 1\"\n     * ```\n     *\n     * ---\n     *\n     * @param callback The callback that will be executed when an element is added to the array.\n     *\n     * @returns A function that can be used to unsubscribe from the event.\n     */\n    public onAdd(callback: (value: T, index: number) => void): Callback\n    {\n        return this._publisher.subscribe(\"add\", callback);\n    }\n\n    /**\n     * Subscribes to the `remove` event of the array with a callback that will be executed when an element is removed.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * array.onRemove((value, index) => console.log(`Removed ${value} at index ${index}`));\n     *\n     * array.pop();   // \"Removed 8 at index 2\"\n     * array.shift(); // \"Removed 2 at index 0\"\n     * ```\n     *\n     * ---\n     *\n     * @param callback The callback that will be executed when an element is removed from the array.\n     *\n     * @returns A function that can be used to unsubscribe from the event.\n     */\n    public onRemove(callback: (value: T, index: number) => void): Callback\n    {\n        return this._publisher.subscribe(\"remove\", callback);\n    }\n\n    /**\n     * Subscribes to the `clear` event of the array with a callback that will be executed when the array is cleared.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * array.onClear(() => console.log(\"The array has been cleared.\"));\n     * array.clear(); // \"The array has been cleared.\"\n     * ```\n     *\n     * ---\n     *\n     * @param callback The callback that will be executed when the array is cleared.\n     *\n     * @returns A function that can be used to unsubscribe from the event.\n     */\n    public onClear(callback: () => void): Callback\n    {\n        return this._publisher.subscribe(\"clear\", callback);\n    }\n\n    public readonly [Symbol.toStringTag]: string = \"ArrayView\";\n    public static override readonly [Symbol.species]: typeof Array = Array;\n}\n","import Publisher from \"../callbacks/publisher.js\";\nimport type { Callback } from \"../types.js\";\n\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nimport type ArrayView from \"./array-view.js\";\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nimport type SetView from \"./set-view.js\";\n\ninterface MapViewEventsMap<K, V>\n{\n    \"add\": (key: K, value: V) => void;\n    \"remove\": (key: K, value: V) => void;\n\n    \"clear\": () => void;\n}\n\n/**\n * A wrapper class around the native {@link Map} class that provides additional functionality\n * for publishing events when entries are added, removed or the collection is cleared.  \n * There are also complementary classes that work with the native `Array` and `Set` classes.\n * See also {@link ArrayView} and {@link SetView}.\n *\n * ---\n *\n * @example\n * ```ts\n * const map = new MapView<string, number>();\n *\n * map.onAdd((key: string, value: number) => console.log(`Added ${key}: ${value}`));\n * map.set(\"answer\", 42); // \"Added answer: 42\"\n * ```\n *\n * ---\n *\n * @template K The type of the keys in the map.\n * @template V The type of the values in the map.\n */\nexport default class MapView<K, V> extends Map<K, V>\n{\n    /**\n     * The internal {@link Publisher} instance used to publish events.\n     */\n    protected readonly _publisher: Publisher<MapViewEventsMap<K, V>>;\n\n    /**\n     * Initializes a new instance of the {@link MapView} class.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const map = new MapView<string, number>([[\"key1\", 2], [\"key2\", 4], [\"key3\", 8]]);\n     * ```\n     *\n     * ---\n     *\n     * @param iterable An optional iterable of key-value pairs to initialize the {@link Map} with.\n     */\n    public constructor(iterable?: Iterable<[K, V]> | null)\n    {\n        super();\n\n        this._publisher = new Publisher();\n\n        if (iterable)\n        {\n            for (const [key, value] of iterable) { super.set(key, value); }\n        }\n    }\n\n    /**\n     * Adds a new entry with a specified key and value to the {@link Map}.  \n     * If an entry with the same key already exists, the entry will be overwritten with the new value.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const map = new MapView<string, number>();\n     * map.set(\"key1\", 2)\n     *     .set(\"key2\", 4)\n     *     .set(\"key3\", 8);\n     *\n     * console.log(map); // MapView { \"key1\" => 2, \"key2\" => 4, \"key3\" => 8 }\n     * ```\n     *\n     * ---\n     *\n     * @param key The key of the entry to add.\n     * @param value The value of the entry to add.\n     *\n     * @returns The current instance of the {@link MapView} class.\n     */\n    public override set(key: K, value: V): this\n    {\n        super.set(key, value);\n\n        this._publisher.publish(\"add\", key, value);\n\n        return this;\n    }\n\n    /**\n     * Removes an entry with a specified key from the {@link Map}.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const map = new MapView<string, number>([[\"key1\", 2], [\"key2\", 4], [\"key3\", 8]]);\n     * map.delete(\"key2\"); // true\n     * map.delete(\"key4\"); // false\n     *\n     * console.log(map); // MapView { \"key1\" => 2, \"key3\" => 8 }\n     * ```\n     *\n     * ---\n     *\n     * @param key The key of the entry to remove.\n     *\n     * @returns `true` if the entry existed and has been removed; otherwise `false` if the entry doesn't exist.\n     */\n    public override delete(key: K): boolean\n    {\n        const value = this.get(key);\n        if (value === undefined) { return false; }\n\n        super.delete(key);\n\n        this._publisher.publish(\"remove\", key, value);\n\n        return true;\n    }\n\n    /**\n     * Removes all entries from the {@link Map}.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const map = new MapView<string, number>([[\"key1\", 2], [\"key2\", 4], [\"key3\", 8]]);\n     * map.clear();\n     *\n     * console.log(map); // MapView { }\n     * ```\n     */\n    public override clear(): void\n    {\n        const size = this.size;\n\n        super.clear();\n        if (size > 0) { this._publisher.publish(\"clear\"); }\n    }\n\n    /**\n     * Subscribes to the `add` event of the map with a callback that will be executed when an entry is added.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * map.onAdd((key, value) => console.log(`Added ${key}: ${value}`));\n     *\n     * map.set(\"key1\", 2);    // \"Added key1: 2\"\n     * map.set(\"answer\", 42); // \"Added answer: 42\"\n     * ```\n     *\n     * ---\n     *\n     * @param callback The callback that will be executed when an entry is added to the map.\n     *\n     * @returns A function that can be used to unsubscribe from the event.\n     */\n    public onAdd(callback: (key: K, value: V) => void): Callback\n    {\n        return this._publisher.subscribe(\"add\", callback);\n    }\n\n    /**\n     * Subscribes to the `remove` event of the map with a callback that will be executed when an entry is removed.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * map.onRemove((key, value) => console.log(`Removed ${key}: ${value}`));\n     *\n     * map.delete(\"key1\");   // \"Removed key1: 2\"\n     * map.delete(\"answer\"); // \"Removed answer: 42\"\n     * ```\n     *\n     * ---\n     *\n     * @param callback The callback that will be executed when an entry is removed from the map.\n     *\n     * @returns A function that can be used to unsubscribe from the event.\n     */\n    public onRemove(callback: (key: K, value: V) => void): Callback\n    {\n        return this._publisher.subscribe(\"remove\", callback);\n    }\n\n    /**\n     * Subscribes to the `clear` event of the map with a callback that will be executed when the map is cleared.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * map.onClear(() => console.log(\"The map has all been cleared.\"));\n     * map.clear(); // \"The map has all been cleared.\"\n     * ```\n     *\n     * ---\n     *\n     * @param callback The callback that will be executed when the map is cleared.\n     *\n     * @returns A function that can be used to unsubscribe from the event.\n     */\n    public onClear(callback: () => void): Callback\n    {\n        return this._publisher.subscribe(\"clear\", callback);\n    }\n\n    public override readonly [Symbol.toStringTag]: string = \"MapView\";\n}\n","import Publisher from \"../callbacks/publisher.js\";\nimport type { Callback } from \"../types.js\";\n\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nimport type ArrayView from \"./array-view.js\";\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nimport type MapView from \"./map-view.js\";\n\ninterface SetViewEventsMap<T>\n{\n    \"add\": (value: T) => void;\n    \"remove\": (value: T) => void;\n\n    \"clear\": () => void;\n}\n\n/**\n * A wrapper class around the native {@link Set} class that provides additional functionality\n * for publishing events when entries are added, removed or the collection is cleared.  \n * There are also complementary classes that work with the native `Array` and `Map` classes.\n * See also {@link ArrayView} and {@link MapView}.\n *\n * ---\n *\n * @example\n * ```ts\n * const set = new SetView<number>();\n *\n * set.onAdd((value: number) => console.log(`Added ${value}`));\n * set.add(42); // \"Added 42\"\n * ```\n *\n * ---\n *\n * @template T The type of the values in the set.\n */\nexport default class SetView<T> extends Set<T>\n{\n    /**\n     * The internal {@link Publisher} instance used to publish events.\n     */\n    protected readonly _publisher: Publisher<SetViewEventsMap<T>>;\n\n    /**\n     * Initializes a new instance of the {@link SetView} class.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const set = new SetView<number>([2, 4, 8]);\n     * ```\n     *\n     * ---\n     *\n     * @param iterable An optional iterable of values to initialize the {@link Set} with.\n     */\n    public constructor(iterable?: Iterable<T> | null)\n    {\n        super();\n\n        this._publisher = new Publisher();\n\n        if (iterable)\n        {\n            for (const value of iterable) { super.add(value); }\n        }\n    }\n\n    /**\n     * Appends a new element with a specified value to the end of the {@link Set}.  \n     * If the value already exists, it will not be added again.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const set = new SetView<number>();\n     * set.add(2)\n     *     .add(4)\n     *     .add(8);\n     *\n     * console.log(set); // SetView(3) { 2, 4, 8 }\n     * ```\n     *\n     * ---\n     *\n     * @param value The value to add.\n     *\n     * @returns The current instance of the {@link SetView} class.\n     */\n    public override add(value: T): this\n    {\n        super.add(value);\n\n        this._publisher.publish(\"add\", value);\n\n        return this;\n    }\n\n    /**\n     * Removes the specified value from the {@link Set}.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const set = new SetView<number>([2, 4, 8]);\n     * set.delete(4);  // true\n     * set.delete(16); // false\n     *\n     * console.log(set); // SetView(2) { 2, 8 }\n     * ```\n     *\n     * ---\n     *\n     * @param value The value to remove.\n     *\n     * @returns `true` if the entry existed and has been removed; otherwise `false` if the entry doesn't exist.\n     */\n    public override delete(value: T): boolean\n    {\n        const result = super.delete(value);\n        if (result) { this._publisher.publish(\"remove\", value); }\n\n        return result;\n    }\n\n    /**\n     * Removes all entries from the {@link Set}.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const set = new SetView<number>([2, 4, 8]);\n     * set.clear();\n     *\n     * console.log(set); // SetView(0) { }\n     * ```\n     */\n    public override clear(): void\n    {\n        const size = this.size;\n\n        super.clear();\n        if (size > 0) { this._publisher.publish(\"clear\"); }\n    }\n\n    /**\n     * Subscribes to the `add` event of the set with a callback that will be executed when a value is added.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * set.onAdd((value) => console.log(`Added ${value}`));\n     *\n     * set.add(2);  // \"Added 2\"\n     * set.add(42); // \"Added 42\"\n     * ```\n     *\n     * ---\n     *\n     * @param callback The callback that will be executed when a value is added to the set.\n     *\n     * @returns A function that can be used to unsubscribe from the event.\n     */\n    public onAdd(callback: (value: T) => void): Callback\n    {\n        return this._publisher.subscribe(\"add\", callback);\n    }\n\n    /**\n     * Subscribes to the `remove` event of the set with a callback that will be executed when a value is removed.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * set.onRemove((value) => console.log(`Removed ${value}`));\n     *\n     * set.delete(2);  // \"Removed 2\"\n     * set.delete(42); // \"Removed 42\"\n     * ```\n     *\n     * ---\n     *\n     * @param callback The callback that will be executed when a value is removed from the set.\n     *\n     * @returns A function that can be used to unsubscribe from the event.\n     */\n    public onRemove(callback: (value: T) => void): Callback\n    {\n        return this._publisher.subscribe(\"remove\", callback);\n    }\n\n    /**\n     * Subscribes to the `clear` event of the set with a callback that will be executed when the set is cleared.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * set.onClear(() => console.log(\"The set has all been cleared.\"));\n     * set.clear(); // \"The set has all been cleared.\"\n     * ```\n     *\n     * ---\n     *\n     * @param callback The callback that will be executed when the set is cleared.\n     *\n     * @returns A function that can be used to unsubscribe from the event.\n     */\n    public onClear(callback: () => void): Callback\n    {\n        return this._publisher.subscribe(\"clear\", callback);\n    }\n\n    public override readonly [Symbol.toStringTag]: string = \"SetView\";\n}\n","import { isBrowser } from \"../../helpers.js\";\nimport { EnvironmentException } from \"../exceptions/index.js\";\n\nimport type { JSONValue } from \"./types.js\";\n\n/**\n * A wrapper around the {@link Storage} API to better store and easily retrieve\n * typed JSON values using the classical key-value pair storage system.\n *\n * It allows to handle either the volatile {@link sessionStorage} or the persistent\n * {@link localStorage} at the same time, depending on what's your required use case.\n *\n * ---\n *\n * @example\n * ```ts\n * const jsonStorage = new JSONStorage();\n *\n * jsonStorage.write(\"user:cookieAck\", { value: true, version: \"2023-02-15\" });\n * // ... between sessions ...\n * const cookieAck = jsonStorage.read<{ value: boolean; version: string; }>(\"user:cookieAck\");\n * ```\n */\nexport default class JSONStorage\n{\n    /**\n     * Whether to prefer the {@link localStorage} over the {@link sessionStorage} when calling an ambivalent method.\n     *\n     * If `true`, the persistent storage is preferred. If `false`, the volatile storage is preferred.  \n     * Default is `true`.\n     */\n    protected readonly _preferPersistence: boolean;\n\n    /**\n     * A reference to the volatile {@link sessionStorage} storage.\n     */\n    protected readonly _volatile: Storage;\n\n    /**\n     * A reference to the persistent {@link localStorage} storage.\n     */\n    protected readonly _persistent: Storage;\n\n    /**\n     * Initializes a new instance of the {@link JSONStorage} class.  \n     * It cannot be instantiated outside of a browser environment or an {@link EnvironmentException} is thrown.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const jsonStorage = new JSONStorage();\n     * ```\n     *\n     * ---\n     *\n     * @param preferPersistence\n     * Whether to prefer the {@link localStorage} over the {@link sessionStorage} when calling an ambivalent method.  \n     * If omitted, it defaults to `true` to prefer the persistent storage.\n     */\n    public constructor(preferPersistence = true)\n    {\n        if (!(isBrowser))\n        {\n            throw new EnvironmentException(\n                \"The `JSONStorage` class can only be instantiated within a browser environment.\"\n            );\n        }\n\n        this._preferPersistence = preferPersistence;\n\n        this._volatile = window.sessionStorage;\n        this._persistent = window.localStorage;\n    }\n\n    protected _get<T extends JSONValue>(storage: Storage, key: string): T | undefined;\n    protected _get<T extends JSONValue>(storage: Storage, key: string, defaultValue: T): T;\n    protected _get<T extends JSONValue>(storage: Storage, key: string, defaultValue?: T): T | undefined;\n    protected _get<T extends JSONValue>(storage: Storage, key: string, defaultValue?: T): T | undefined\n    {\n        const value = storage.getItem(key);\n        if (value)\n        {\n            try\n            {\n                return JSON.parse(value);\n            }\n            catch\n            {\n                // eslint-disable-next-line no-console\n                console.warn(\n                    `The \"${value}\" value for \"${key}\"` +\n                    \" property cannot be parsed. Clearing the storage...\");\n\n                storage.removeItem(key);\n            }\n        }\n\n        return defaultValue;\n    }\n    protected _set<T extends JSONValue>(storage: Storage, key: string, newValue?: T): void\n    {\n        const encodedValue = JSON.stringify(newValue);\n        if (encodedValue)\n        {\n            storage.setItem(key, encodedValue);\n        }\n        else\n        {\n            storage.removeItem(key);\n        }\n    }\n\n    /**\n     * Retrieves the value with the specified key from the default storage.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const value: TValue = jsonStorage.get<TValue>(\"key\");\n     * ```\n     *\n     * ---\n     *\n     * @template T The type of the value to retrieve.\n     *\n     * @param key The key of the value to retrieve.\n     *\n     * @returns The value with the specified key or `undefined` if the key doesn't exist.\n     */\n    public get<T extends JSONValue>(key: string): T | undefined;\n\n    /**\n     * Retrieves the value with the specified key from the default storage.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const value: TValue = jsonStorage.get<TValue>(\"key\", defaultValue);\n     * ```\n     *\n     * ---\n     *\n     * @template T The type of the value to retrieve.\n     *\n     * @param key The key of the value to retrieve.\n     * @param defaultValue The default value to return if the key doesn't exist.\n     * @param persistent\n     * Whether to prefer the persistent {@link localStorage} over the volatile {@link sessionStorage}.  \n     * If omitted, it defaults to the `preferPersistence` value set in the constructor.\n     *\n     * @returns The value with the specified key or the provided default value if the key doesn't exist.\n     */\n    public get<T extends JSONValue>(key: string, defaultValue: T, persistent?: boolean): T;\n\n    /**\n     * Retrieves the value with the specified key from the default storage.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const value: TValue = jsonStorage.get<TValue>(\"key\", obj?.value);\n     * ```\n     *\n     * ---\n     *\n     * @template T The type of the value to retrieve.\n     *\n     * @param key The key of the value to retrieve.\n     * @param defaultValue The default value to return (which may be `undefined`) if the key doesn't exist.\n     * @param persistent\n     * Whether to prefer the persistent {@link localStorage} over the volatile {@link sessionStorage}.  \n     * If omitted, it defaults to the `preferPersistence` value set in the constructor.\n     *\n     * @returns The value with the specified key or the default value if the key doesn't exist.\n     */\n    public get<T extends JSONValue>(key: string, defaultValue?: T, persistent?: boolean): T | undefined;\n    public get<T extends JSONValue>(key: string, defaultValue?: T, persistent = this._preferPersistence): T | undefined\n    {\n        const storage = persistent ? this._persistent : this._volatile;\n\n        return this._get<T>(storage, key, defaultValue);\n    }\n\n    /**\n     * Retrieves the value with the specified key from the volatile {@link sessionStorage}.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const value: TValue = jsonStorage.recall<TValue>(\"key\");\n     * ```\n     *\n     * ---\n     *\n     * @template T The type of the value to retrieve.\n     *\n     * @param key The key of the value to retrieve.\n     *\n     * @returns The value with the specified key or `undefined` if the key doesn't exist.\n     */\n    public recall<T extends JSONValue>(key: string): T | undefined;\n\n    /**\n     * Retrieves the value with the specified key from the volatile {@link sessionStorage}.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const value: TValue = jsonStorage.recall<TValue>(\"key\", defaultValue);\n     * ```\n     *\n     * ---\n     *\n     * @template T The type of the value to retrieve.\n     *\n     * @param key The key of the value to retrieve.\n     * @param defaultValue The default value to return if the key doesn't exist.\n     *\n     * @returns The value with the specified key or the default value if the key doesn't exist.\n     */\n    public recall<T extends JSONValue>(key: string, defaultValue: T): T;\n\n    /**\n     * Retrieves the value with the specified key from the volatile {@link sessionStorage}.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const value: TValue = jsonStorage.recall<TValue>(\"key\", obj?.value);\n     * ```\n     *\n     * ---\n     *\n     * @template T The type of the value to retrieve.\n     *\n     * @param key The key of the value to retrieve.\n     * @param defaultValue The default value to return (which may be `undefined`) if the key doesn't exist.\n     *\n     * @returns The value with the specified key or the default value if the key doesn't exist.\n     */\n    public recall<T extends JSONValue>(key: string, defaultValue?: T): T | undefined;\n    public recall<T extends JSONValue>(key: string, defaultValue?: T): T | undefined\n    {\n        return this._get<T>(this._volatile, key, defaultValue);\n    }\n\n    /**\n     * Retrieves the value with the specified key looking first in the volatile\n     * {@link sessionStorage} and then, if not found, in the persistent {@link localStorage}.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const value: TValue = jsonStorage.retrieve<TValue>(\"key\");\n     * ```\n     *\n     * ---\n     *\n     * @template T The type of the value to retrieve.\n     *\n     * @param key The key of the value to retrieve.\n     *\n     * @returns The value with the specified key or `undefined` if the key doesn't exist.\n     */\n    public retrieve<T extends JSONValue>(key: string): T | undefined;\n\n    /**\n     * Retrieves the value with the specified key looking first in the volatile\n     * {@link sessionStorage} and then, if not found, in the persistent {@link localStorage}.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const value: TValue = jsonStorage.retrieve<TValue>(\"key\", defaultValue);\n     * ```\n     *\n     * ---\n     *\n     * @template T The type of the value to retrieve.\n     *\n     * @param key The key of the value to retrieve.\n     * @param defaultValue The default value to return if the key doesn't exist.\n     *\n     * @returns The value with the specified key or the default value if the key doesn't exist.\n     */\n    public retrieve<T extends JSONValue>(key: string, defaultValue: T): T;\n\n    /**\n     * Retrieves the value with the specified key looking first in the volatile\n     * {@link sessionStorage} and then, if not found, in the persistent {@link localStorage}.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const value: TValue = jsonStorage.retrieve<TValue>(\"key\", obj?.value);\n     * ```\n     *\n     * ---\n     *\n     * @template T The type of the value to retrieve.\n     *\n     * @param key The key of the value to retrieve.\n     * @param defaultValue The default value to return (which may be `undefined`) if the key doesn't exist.\n     *\n     * @returns The value with the specified key or the default value if the key doesn't exist.\n     */\n    public retrieve<T extends JSONValue>(key: string, defaultValue?: T): T | undefined;\n    public retrieve<T extends JSONValue>(key: string, defaultValue?: T): T | undefined\n    {\n        return this.recall<T>(key) ?? this.read<T>(key, defaultValue);\n    }\n\n    /**\n     * Retrieves the value with the specified key from the persistent {@link localStorage}.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const value: TValue = jsonStorage.read<TValue>(\"key\");\n     * ```\n     *\n     * ---\n     *\n     * @template T The type of the value to retrieve.\n     *\n     * @param key The key of the value to retrieve.\n     *\n     * @returns The value with the specified key or `undefined` if the key doesn't exist.\n     */\n    public read<T extends JSONValue>(key: string): T | undefined;\n\n    /**\n     * Retrieves the value with the specified key from the persistent {@link localStorage}.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const value: TValue = jsonStorage.read<TValue>(\"key\", defaultValue);\n     * ```\n     *\n     * ---\n     *\n     * @template T The type of the value to retrieve.\n     *\n     * @param key The key of the value to retrieve.\n     * @param defaultValue The default value to return if the key doesn't exist.\n     *\n     * @returns The value with the specified key or the default value if the key doesn't exist.\n     */\n    public read<T extends JSONValue>(key: string, defaultValue: T): T;\n\n    /**\n     * Retrieves the value with the specified key from the persistent {@link localStorage}.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const value: TValue = jsonStorage.read<TValue>(\"key\", obj?.value);\n     * ```\n     *\n     * ---\n     *\n     * @template T The type of the value to retrieve.\n     *\n     * @param key The key of the value to retrieve.\n     * @param defaultValue The default value to return (which may be `undefined`) if the key doesn't exist.\n     *\n     * @returns The value with the specified key or the default value if the key doesn't exist.\n     */\n    public read<T extends JSONValue>(key: string, defaultValue?: T): T | undefined;\n    public read<T extends JSONValue>(key: string, defaultValue?: T): T | undefined\n    {\n        return this._get<T>(this._persistent, key, defaultValue);\n    }\n\n    /**\n     * Checks whether the value with the specified key exists within the default storage.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * if (jsonStorage.has(\"key\"))\n     * {\n     *    // The key exists. Do something...\n     * }\n     * ```\n     *\n     * ---\n     *\n     * @param key The key of the value to check.\n     * @param persistent\n     * Whether to prefer the persistent {@link localStorage} over the volatile {@link sessionStorage}.  \n     * If omitted, it defaults to the `preferPersistence` value set in the constructor.\n     *\n     * @returns `true` if the key exists, `false` otherwise.\n     */\n    public has(key: string, persistent?: boolean): boolean\n    {\n        const storage = persistent ? this._persistent : this._volatile;\n\n        return storage.getItem(key) !== null;\n    }\n\n    /**\n     * Checks whether the value with the specified key exists within the volatile {@link sessionStorage}.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * if (jsonStorage.knows(\"key\"))\n     * {\n     *    // The key exists. Do something...\n     * }\n     * ```\n     *\n     * ---\n     *\n     * @param key The key of the value to check.\n     *\n     * @returns `true` if the key exists, `false` otherwise.\n     */\n    public knows(key: string): boolean\n    {\n        return this._volatile.getItem(key) !== null;\n    }\n\n    /**\n     * Checks whether the value with the specified key exists looking first in the\n     * volatile {@link sessionStorage} and then, if not found, in the persistent {@link localStorage}.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * if (jsonStorage.find(\"key\"))\n     * {\n     *    // The key exists. Do something...\n     * }\n     * ```\n     *\n     * ---\n     *\n     * @param key The key of the value to check.\n     *\n     * @returns `true` if the key exists, `false` otherwise.\n     */\n    public find(key: string): boolean\n    {\n        return this.knows(key) ?? this.exists(key);\n    }\n\n    /**\n     * Checks whether the value with the specified key exists within the persistent {@link localStorage}.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * if (jsonStorage.exists(\"key\"))\n     * {\n     *    // The key exists. Do something...\n     * }\n     * ```\n     *\n     * ---\n     *\n     * @param key The key of the value to check.\n     *\n     * @returns `true` if the key exists, `false` otherwise.\n     */\n    public exists(key: string): boolean\n    {\n        return this._persistent.getItem(key) !== null;\n    }\n\n    /**\n     * Sets the value with the specified key in the default storage.  \n     * If the value is `undefined` or omitted, the key is removed from the storage.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * jsonStorage.set(\"key\");\n     * jsonStorage.set(\"key\", value);\n     * jsonStorage.set(\"key\", obj?.value);\n     * ```\n     *\n     * ---\n     *\n     * @template T The type of the value to set.\n     *\n     * @param key The key of the value to set.\n     * @param newValue The new value to set. If it's `undefined` or omitted, the key is removed instead.\n     * @param persistent\n     * Whether to prefer the persistent {@link localStorage} over the volatile {@link sessionStorage}.  \n     * If omitted, it defaults to the `preferPersistence` value set in the constructor.\n     */\n    public set<T extends JSONValue>(key: string, newValue?: T, persistent = this._preferPersistence): void\n    {\n        const storage = persistent ? this._persistent : this._volatile;\n\n        this._set<T>(storage, key, newValue);\n    }\n\n    /**\n     * Sets the value with the specified key in the volatile {@link sessionStorage}.  \n     * If the value is `undefined` or omitted, the key is removed from the storage.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * jsonStorage.remember(\"key\");\n     * jsonStorage.remember(\"key\", value);\n     * jsonStorage.remember(\"key\", obj?.value);\n     * ```\n     *\n     * ---\n     *\n     * @template T The type of the value to set.\n     *\n     * @param key The key of the value to set.\n     * @param newValue The new value to set. If it's `undefined` or omitted, the key is removed instead.\n     */\n    public remember<T extends JSONValue>(key: string, newValue?: T): void\n    {\n        this._set<T>(this._volatile, key, newValue);\n    }\n\n    /**\n     * Sets the value with the specified key in the persistent {@link localStorage}.  \n     * If the value is `undefined` or omitted, the key is removed from the storage.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * jsonStorage.write(\"key\");\n     * jsonStorage.write(\"key\", value);\n     * jsonStorage.write(\"key\", obj?.value);\n     * ```\n     *\n     * ---\n     *\n     * @template T The type of the value to set.\n     *\n     * @param key The key of the value to set.\n     * @param newValue The new value to set. If it's `undefined` or omitted, the key is removed instead.\n     */\n    public write<T extends JSONValue>(key: string, newValue?: T): void\n    {\n        this._set<T>(this._persistent, key, newValue);\n    }\n\n    /**\n     * Removes the value with the specified key from the default storage.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * jsonStorage.delete(\"key\");\n     * ```\n     *\n     * ---\n     *\n     * @param key The key of the value to remove.\n     * @param persistent\n     * Whether to prefer the persistent {@link localStorage} over the volatile {@link sessionStorage}.  \n     * If omitted, it defaults to the `preferPersistence` value set in the constructor.\n     */\n    public delete(key: string, persistent?: boolean): void\n    {\n        const storage = persistent ? this._persistent : this._volatile;\n\n        storage.removeItem(key);\n    }\n\n    /**\n     * Removes the value with the specified key from the volatile {@link sessionStorage}.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * jsonStorage.forget(\"key\");\n     * ```\n     *\n     * ---\n     *\n     * @param key The key of the value to remove.\n     */\n    public forget(key: string): void\n    {\n        this._volatile.removeItem(key);\n    }\n\n    /**\n     * Removes the value with the specified key from the persistent {@link localStorage}.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * jsonStorage.erase(\"key\");\n     * ```\n     *\n     * ---\n     *\n     * @param key The key of the value to remove.\n     */\n    public erase(key: string): void\n    {\n        this._persistent.removeItem(key);\n    }\n\n    /**\n     * Removes the value with the specified key from both the\n     * volatile {@link sessionStorage} and the persistent {@link localStorage}.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * jsonStorage.clear(\"key\");\n     * ```\n     *\n     * ---\n     *\n     * @param key The key of the value to remove.\n     */\n    public clear(key: string): void\n    {\n        this._volatile.removeItem(key);\n        this._persistent.removeItem(key);\n    }\n\n    public readonly [Symbol.toStringTag]: string = \"JSONStorage\";\n}\n","import type { Callback } from \"../types.js\";\nimport type { FulfilledHandler, PromiseExecutor, RejectedHandler } from \"./types.js\";\n\n/**\n * A wrapper class representing an enhanced version of the native {@link Promise} object.\n *\n * It provides additional properties to check the state of the promise itself.  \n * The state can be either `pending`, `fulfilled` or `rejected` and is accessible through\n * the {@link SmartPromise.isPending}, {@link SmartPromise.isFulfilled} & {@link SmartPromise.isRejected} properties.\n *\n * ---\n *\n * @example\n * ```ts\n * const promise = new SmartPromise<string>((resolve, reject) =>\n * {\n *     setTimeout(() => resolve(\"Hello, World!\"), 1_000);\n * });\n *\n * console.log(promise.isPending);   // true\n * console.log(promise.isFulfilled); // false\n *\n * console.log(await promise); // \"Hello, World!\"\n *\n * console.log(promise.isPending);   // false\n * console.log(promise.isFulfilled); // true\n * ```\n *\n * ---\n *\n * @template T The type of value the promise will eventually resolve to. Default is `void`.\n */\nexport default class SmartPromise<T = void> implements Promise<T>\n{\n    /**\n     * Wraps a new {@link SmartPromise} object around an existing native {@link Promise} object.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const response = fetch(\"https://api.example.com/data\");\n     * const smartResponse = SmartPromise.FromPromise(response);\n     *\n     * console.log(response.isPending);      // Throws an error: `isPending` is not a property of `Promise`.\n     * console.log(smartResponse.isPending); // true\n     *\n     * const response = await response;\n     * console.log(smartResponse.isFulfilled); // true\n     * ```\n     *\n     * ---\n     *\n     * @param promise The promise to wrap.\n     *\n     * @returns A new {@link SmartPromise} object that wraps the provided promise.\n     */\n    public static FromPromise<T>(promise: Promise<T>): SmartPromise<T>\n    {\n        return new SmartPromise((resolve, reject) => promise.then(resolve, reject));\n    }\n\n    /**\n     * A flag indicating whether the promise is still pending or not.\n     *\n     * The protected property is the only one that can be modified directly by the derived classes.  \n     * If you're looking for the public and readonly property, use the {@link SmartPromise.isPending} getter instead.\n     */\n    protected _isPending: boolean;\n\n    /**\n     * A flag indicating whether the promise is still pending or not.\n     */\n    public get isPending(): boolean\n    {\n        return this._isPending;\n    }\n\n    /**\n     * A flag indicating whether the promise has been fulfilled or not.\n     *\n     * The protected property is the only one that can be modified directly by the derived classes.  \n     * If you're looking for the public and readonly property, use the {@link SmartPromise.isFulfilled} getter instead.\n     */\n    protected _isFulfilled: boolean;\n\n    /**\n     * A flag indicating whether the promise has been fulfilled or not.\n     */\n    public get isFulfilled(): boolean\n    {\n        return this._isFulfilled;\n    }\n\n    /**\n     * A flag indicating whether the promise has been rejected or not.\n     *\n     * The protected property is the only one that can be modified directly by the derived classes.  \n     * If you're looking for the public and readonly property, use the {@link SmartPromise.isRejected} getter instead.\n     */\n    protected _isRejected: boolean;\n\n    /**\n     * A flag indicating whether the promise has been rejected or not.\n     */\n    public get isRejected(): boolean\n    {\n        return this._isRejected;\n    }\n\n    /**\n     * The native {@link Promise} object wrapped by this instance.\n     */\n    protected readonly _promise: Promise<T>;\n\n    /**\n     * Initializes a new instance of the {@link SmartPromise} class.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const promise = new SmartPromise<string>((resolve, reject) =>\n     * {\n     *     setTimeout(() => resolve(\"Hello, World!\"), 1_000);\n     * });\n     * ```\n     *\n     * ---\n     *\n     * @param executor\n     * The function responsible for eventually resolving or rejecting the promise.  \n     * Similarly to the native {@link Promise} object, it's immediately executed after the promise is created.\n     */\n    public constructor(executor: PromiseExecutor<T>)\n    {\n        this._isPending = true;\n        this._isFulfilled = false;\n        this._isRejected = false;\n\n        const _onFulfilled = (result: T): T =>\n        {\n            this._isPending = false;\n            this._isFulfilled = true;\n\n            return result;\n        };\n        const _onRejected = (reason: unknown): never =>\n        {\n            this._isPending = false;\n            this._isRejected = true;\n\n            throw reason;\n        };\n\n        this._promise = new Promise<T>(executor)\n            .then(_onFulfilled, _onRejected);\n    }\n\n    /**\n     * Creates a new {@link Promise} identical to the one wrapped by this instance, with a different reference.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const promise = new SmartPromise<string>((resolve, reject) =>\n     * {\n     *     setTimeout(() => resolve(\"Hello, World!\"), 1_000);\n     * });\n     *\n     * console.log(await promise.then()); // \"Hello, World!\"\n     * ```\n     *\n     * ---\n     *\n     * @returns A new {@link Promise} identical to the original one.\n     */\n    public then(onFulfilled?: null): Promise<T>;\n\n    /**\n     * Attaches a callback that executes right after the promise is fulfilled.\n     *\n     * The previous result of the promise is passed as the argument to the callback.  \n     * The callback's return value is considered the new promise's result instead.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const promise = new SmartPromise<string>((resolve, reject) =>\n     * {\n     *     setTimeout(() => resolve(\"Hello, World!\"), 1_000);\n     * });\n     *\n     * promise.then((result) => console.log(result)); // \"Hello, World!\"\n     * ```\n     *\n     * ---\n     *\n     * @template F The type of value the new promise will eventually resolve to. Default is `T`.\n     *\n     * @param onFulfilled The callback to execute once the promise is fulfilled.\n     *\n     * @returns A new {@link Promise} resolved with the return value of the callback.\n     */\n    public then<F = T>(onFulfilled: FulfilledHandler<T, F>, onRejected?: null): Promise<F>;\n\n    /**\n     * Attaches callbacks that executes right after the promise is fulfilled or rejected.\n     *\n     * The previous result of the promise is passed as the argument to the fulfillment callback.  \n     * The fulfillment callback's return value is considered the new promise's result instead.\n     *\n     * If an error is thrown during execution, the rejection callback is then executed instead.\n     *\n     * Also note that:\n     * - If the rejection callback runs properly, the error is considered handled.  \n     * The rejection callback's return value is considered the new promise's result.\n     * - If the rejection callback throws an error, the new promise is rejected with that error.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const promise = new SmartPromise((resolve, reject) =>\n     * {\n     *     setTimeout(resolve, Math.random() * 1_000);\n     *     setTimeout(reject, Math.random() * 1_000);\n     * });\n     *\n     * promise.then(() => console.log(\"OK!\"), () => console.log(\"KO!\")); // \"OK!\" or \"KO!\"\n     * ```\n     *\n     * ---\n     *\n     * @template F The type of value the new promise will eventually resolve to. Default is `T`.\n     * @template R The type of value the new promise will eventually resolve to. Default is `never`.\n     *\n     * @param onFulfilled The callback to execute once the promise is fulfilled.\n     * @param onRejected The callback to execute once the promise is rejected.\n     *\n     * @returns A new {@link Promise} resolved or rejected based on the callbacks.\n     */\n    public then<F = T, R = never>(\n        onFulfilled: FulfilledHandler<T, F>, onRejected: RejectedHandler<unknown, R>\n    ): Promise<F | R>;\n    public then<F = T, R = never>(\n        onFulfilled?: FulfilledHandler<T, F> | null, onRejected?: RejectedHandler<unknown, R> | null\n    ): Promise<F | R>\n    {\n        return this._promise.then(onFulfilled, onRejected);\n    }\n\n    /**\n     * Creates a new {@link Promise} identical to the one wrapped by this instance, with a different reference.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const promise = new SmartPromise((resolve, reject) =>\n     * {\n     *     setTimeout(() => reject(new Exception(\"An unknown error occurred.\")), 1_000);\n     * });\n     *\n     * promise.catch(); // \"Uncaught Exception: An unknown error occurred.\"\n     * ```\n     *\n     * ---\n     *\n     * @returns A new {@link Promise} identical to the original one.\n     */\n    public catch(onRejected?: null): Promise<T>;\n\n    /**\n     * Attaches a callback to handle the potential rejection of the promise.  \n     * If it happens, the callback is then executed.\n     *\n     * Also note that:\n     * - If the callback runs properly, the error is considered handled.  \n     * The callback's return value is considered the new promise's result.\n     * - If the callback throws an error, the new promise is rejected with that error.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const promise = new SmartPromise((resolve, reject) =>\n     * {\n     *     setTimeout(() => reject(new Exception(\"An unknown error occurred.\")), 1_000);\n     * });\n     *\n     * promise.catch((reason) => console.error(reason)); // \"Uncaught Exception: An unknown error occurred.\"\n     * ```\n     *\n     * ---\n     *\n     * @template R The type of value the new promise will eventually resolve to. Default is `T`.\n     *\n     * @param onRejected The callback to execute once the promise is rejected.\n     *\n     * @returns A new {@link Promise} able to catch and handle the potential error.\n     */\n    public catch<R = never>(onRejected: RejectedHandler<unknown, R>): Promise<T | R>;\n    public catch<R = never>(onRejected?: RejectedHandler<unknown, R> | null): Promise<T | R>\n    {\n        return this._promise.catch(onRejected);\n    }\n\n    /**\n     * Attaches a callback that executes right after the promise is settled, regardless of the outcome.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const promise = new SmartPromise((resolve, reject) =>\n     * {\n     *     setTimeout(resolve, Math.random() * 1_000);\n     *     setTimeout(reject, Math.random() * 1_000);\n     * });\n     *\n     *\n     * promise\n     *     .then(() => console.log(\"OK!\"))       // Logs \"OK!\" if the promise is fulfilled.\n     *     .catch(() => console.log(\"KO!\"))      // Logs \"KO!\" if the promise is rejected.\n     *     .finally(() => console.log(\"Done!\")); // Always logs \"Done!\".\n     * ```\n     *\n     * ---\n     *\n     * @param onFinally The callback to execute when once promise is settled.\n     *\n     * @returns A new {@link Promise} that executes the callback once the promise is settled.\n     */\n    public finally(onFinally?: Callback | null): Promise<T>\n    {\n        return this._promise.finally(onFinally);\n    }\n\n    public readonly [Symbol.toStringTag]: string = \"SmartPromise\";\n}\n","import type { PromiseResolver, PromiseRejecter, FulfilledHandler, RejectedHandler } from \"./types.js\";\n\nimport SmartPromise from \"./smart-promise.js\";\n\n/**\n * A class representing a {@link SmartPromise} that can be resolved or rejected from the \"outside\".  \n * The `resolve` and `reject` methods are exposed to allow the promise to be settled from another context.\n *\n * It's particularly useful in scenarios where the promise is created and needs to be awaited in one place,  \n * while being resolved or rejected in another (e.g. an event handler for an user interaction).\n *\n * This is a change in the approach to promises: instead of defining how the promise will be resolved (or rejected),  \n * you define how to handle the resolution (or rejection) when it occurs.\n *\n * ---\n *\n * @example\n * ```ts\n * const promise = new DeferredPromise<string, string[]>((value: string) => value.split(\" \"));\n *\n * promise.then((result) => console.log(result)); // [\"Hello,\", \"World!\"]\n * promise.resolve(\"Hello, World!\");\n * ```\n *\n * ---\n *\n * @template T The type of value the promise expects to initially be resolved with. Default is `void`.\n * @template F\n * The type of value returned by the `onFulfilled` callback.  \n * This will be the actual type of value the promise will eventually resolve to. Default is `T`.\n * @template R\n * The type of value possibly returned by the `onRejected` callback.  \n * This will be coupled with the type of value the promise will eventually resolve to, if provided. Default is `never`.\n */\nexport default class DeferredPromise<T = void, F = T, R = never> extends SmartPromise<F | R>\n{\n    /**\n     * The exposed function that allows to resolve the promise.\n     *\n     * This protected property is the only one that can be modified directly by the derived classes.  \n     * If you're looking for the public and readonly property, use the {@link DeferredPromise.resolve} getter instead.\n     */\n    protected readonly _resolve: PromiseResolver<T>;\n\n    /**\n     * The exposed function that allows to reject the promise.\n     */\n    public get resolve(): PromiseResolver<T> { return this._resolve; }\n\n    /**\n     * The exposed function that allows to reject the promise.\n     *\n     * This protected property is the only one that can be modified directly by the derived classes.  \n     * If you're looking for the public and readonly property, use the {@link DeferredPromise.reject} getter instead.\n     */\n    protected readonly _reject: PromiseRejecter;\n\n    /**\n     * The exposed function that allows to reject the promise.\n     */\n    public get reject(): PromiseRejecter { return this._reject; }\n\n    /**\n     * The native {@link Promise} object wrapped by this instance.\n     */\n    declare protected readonly _promise: Promise<F | R>;\n\n    /**\n     * Initializes a new instance of the {@link DeferredPromise} class.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const promise = new DeferredPromise<string, string[]>((value: string) => value.split(\" \"));\n     * ```\n     *\n     * ---\n     *\n     * @param onFulfilled The callback to execute once the promise is fulfilled.\n     * @param onRejected The callback to execute once the promise is rejected.\n     */\n    public constructor(onFulfilled?: FulfilledHandler<T, F> | null, onRejected?: RejectedHandler<unknown, R> | null)\n    {\n        let _resolve: PromiseResolver<T>;\n        let _reject: PromiseRejecter;\n\n        super((resolve, reject) =>\n        {\n            // ReferenceError: Must call super constructor in derived class before accessing\n            //                  'this' or returning from derived constructor.\n            //\n            _resolve = resolve as PromiseResolver<T>;\n            _reject = reject;\n        });\n\n        this._promise = this._promise.then(onFulfilled as FulfilledHandler<F | R>, onRejected);\n\n        this._resolve = _resolve!;\n        this._reject = _reject!;\n    }\n\n    /**\n     * Watches another promise and resolves or rejects this promise when the other one is settled.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const promise = new Promise<string>((resolve) => setTimeout(() => resolve(\"Hello, World!\"), 1_000));\n     * const deferred = new DeferredPromise<string, string[]>((value: string) => value.split(\" \"));\n     *\n     * deferred.then((result) => console.log(result)); // [\"Hello,\", \"World!\"]\n     * deferred.watch(promise);\n     * ```\n     *\n     * ---\n     *\n     * @param otherPromise The promise to watch.\n     *\n     * @returns The current instance of the {@link DeferredPromise} class.\n     */\n    public watch(otherPromise: PromiseLike<T>): this\n    {\n        otherPromise.then(this.resolve, this.reject);\n\n        return this;\n    }\n\n    public override readonly [Symbol.toStringTag]: string = \"DeferredPromise\";\n}\n","import { TimeoutException } from \"../exceptions/index.js\";\n\nimport SmartPromise from \"./smart-promise.js\";\nimport type { MaybePromise, PromiseExecutor } from \"./types.js\";\n\n/**\n * A class representing a {@link SmartPromise} that rejects automatically after a given time.  \n * It's useful for operations that must be completed within a certain time frame.\n *\n * If the operation takes longer than the specified time, the promise is rejected with a {@link TimeoutException}.\n *\n * ---\n *\n * @example\n * ```ts\n * const promise = new TimedPromise<string>((resolve, reject) =>\n * {\n *     setTimeout(() => resolve(\"Hello, World!\"), Math.random() * 10_000);\n *\n * }, 5_000);\n *\n * promise\n *     .then((result) => console.log(result))   // \"Hello, World!\"\n *     .catch((error) => console.error(error)); // \"Uncaught TimeoutException: The operation has timed out.\"\n * ```\n *\n * ---\n *\n * @template T The type of value the promise will eventually resolve to. Default is `void`.\n */\nexport default class TimedPromise<T = void> extends SmartPromise<T>\n{\n    /**\n     * Initializes a new instance of the {@link TimedPromise} class.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const promise = new TimedPromise<string>((resolve, reject) =>\n     * {\n     *    setTimeout(() => resolve(\"Hello, World!\"), Math.random() * 10_000);\n     *\n     * }, 5_000);\n     * ```\n     *\n     * ---\n     *\n     * @param executor\n     * The function responsible for eventually resolving or rejecting the promise.  \n     * Similarly to the native {@link Promise} object, it's immediately executed after the promise is created.\n     *\n     * @param timeout The maximum time in milliseconds that the operation can take before timing out.\n     */\n    public constructor(executor: PromiseExecutor<T>, timeout?: number)\n    {\n        super((resolve, reject) =>\n        {\n            const _resolve = (result: MaybePromise<T>) =>\n            {\n                clearTimeout(_timeoutId);\n                resolve(result);\n            };\n            const _reject = (reason: unknown) =>\n            {\n                clearTimeout(_timeoutId);\n                reject(reason);\n            };\n\n            const _timeout = () => _reject(new TimeoutException(\"The operation has timed out.\"));\n            const _timeoutId = setTimeout(_timeout, timeout);\n\n            executor(_resolve, _reject);\n        });\n    }\n\n    public override readonly [Symbol.toStringTag]: string = \"TimedPromise\";\n}\n","import type { Callback } from \"../callbacks/types.js\";\n\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nimport { TimeoutException, ValueException } from \"../exceptions/index.js\";\n\nimport DeferredPromise from \"./deferred-promise.js\";\nimport SmartPromise from \"./smart-promise.js\";\nimport TimedPromise from \"./timed-promise.js\";\nimport type { MaybePromise, PromiseRejecter, PromiseResolver } from \"./types.js\";\n\n/**\n * A class that represents a queue of asynchronous operations, allowing them to be executed sequentially.\n *\n * It extends the {@link SmartPromise} class, providing a way to manage multiple promises in a controlled manner.   \n * This class is useful for scenarios where you need to ensure\n * that only one asynchronous operation is executed at a time,\n * such as when dealing with API requests, file operations or any other\n * asynchronous tasks that need to be handled in a specific order.\n *\n * ---\n *\n * @example\n * ```ts\n * const queue = new PromiseQueue();\n *\n * queue.enqueue(() => new Promise((resolve) => setTimeout(() => resolve(\"First\"), 2000)))\n * queue.enqueue(() => new Promise((resolve) => setTimeout(() => resolve(\"Second\"), 500)))\n * queue.enqueue(() => new Promise((resolve) => setTimeout(() => resolve(\"Third\"), 1000)))\n *\n * await queue; // \"First\", \"Second\", \"Third\"\n * ```\n */\nexport default class PromiseQueue extends SmartPromise<void>\n{\n    /**\n     * The number of promises currently in the queue.\n     */\n    protected _count: number;\n\n    /**\n     * A flag indicating whether the promise is still pending or not.\n     */\n    public override get isPending(): boolean\n    {\n        return this._count > 0;\n    }\n    /**\n     * A flag indicating whether the promise has been fulfilled or not.\n     */\n    public override get isFulfilled(): boolean\n    {\n        return this._count === 0;\n    }\n\n    /**\n     * A flag indicating whether the promise has been rejected or not.\n     *\n     * Please note the {@link PromiseQueue} doesn't support rejection states.  \n     * Accessing this property will always result in a {@link ValueException}.\n     */\n    public override get isRejected(): never\n    {\n        throw new ValueException(\"`PromiseQueue` doesn't support rejection states.\");\n    }\n\n    /**\n     * The native {@link Promise} object wrapped by this instance.\n     */\n    declare protected _promise: Promise<void>;\n\n    /**\n     * Initializes a new instance of the {@link PromiseQueue} class.\n     */\n    public constructor()\n    {\n        super((resolve) => resolve());\n\n        this._count = 0;\n\n        this._isPending = false;\n        this._isFulfilled = false;\n        this._isRejected = false;\n    }\n\n    /**\n     * Enqueues a {@link DeferredPromise} into the queue.\n     *\n     * The promise will be executed in sequence after previously enqueued promises.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const queue = new PromiseQueue();\n     * const deferred = new DeferredPromise(() => console.log(\"Hello, world!\"));\n     * \n     * queue.enqueue(deferred); // \"Hello, world!\"\n     * ```\n     *\n     * ---\n     *\n     * @template T The type of value the promise will eventually resolve to.\n     *\n     * @param promise A `DeferredPromise<void, T>` instance to enqueue.\n     *\n     * @returns A {@link SmartPromise} that resolves to the value of the enqueued promise.\n     */\n    public enqueue<T>(promise: DeferredPromise<void, T>): SmartPromise<T>;\n\n    /**\n     * Enqueues a {@link DeferredPromise} into the queue with an optional timeout.\n     *\n     * The promise will be executed in sequence after previously enqueued promises.  \n     * If the promise takes longer than the specified timeout, it will be rejected with a {@link TimeoutException}.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const queue = new PromiseQueue();\n     * const deferred = new DeferredPromise(() => console.log(\"Hello, world!\"));\n     *\n     * queue.enqueue(deferred, 5000); // \"Hello, world!\"\n     * ```\n     *\n     * ---\n     *\n     * @template T The type of value the promise will eventually resolve to.\n     *\n     * @param promise A `DeferredPromise<void, T>` instance to enqueue.\n     * @param timeout The maximum time in milliseconds that the operation can take before timing out.\n     *\n     * @returns\n     * A {@link TimedPromise} that resolves to the value of the enqueued promise or rejects\n     * with a `TimeoutException` if the operation takes longer than the specified timeout.\n     */\n    public enqueue<T>(promise: DeferredPromise<void, T>, timeout: number): TimedPromise<T>;\n\n    /**\n     * Enqueues a callback that returns a {@link MaybePromise} value of type `T` into the queue.\n     *\n     * The executor will be executed in sequence after previously enqueued promises.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const queue = new PromiseQueue();\n     *\n     * queue.enqueue(() => console.log(\"Hello, world!\")); // \"Hello, world!\"\n     * ```\n     *\n     * ---\n     *\n     * @template T The type of value the promise will eventually resolve to.\n     *\n     * @param executor A callback that returns a `MaybePromise<T>` value to enqueue.\n     *\n     * @returns A {@link SmartPromise} that resolves to the value of the enqueued executor.\n     */\n    public enqueue<T>(executor: Callback<[], MaybePromise<T>>): SmartPromise<T>;\n\n    /**\n     * Enqueues a callback that returns a {@link MaybePromise}\n     * value of type `T` into the queue with an optional timeout.\n     *\n     * The executor will be executed in sequence after previously enqueued promises.  \n     * If the executor takes longer than the specified timeout, it will be rejected with a {@link TimeoutException}.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const queue = new PromiseQueue();\n     *\n     * queue.enqueue(() => console.log(\"Hello, world!\"), 5000); // \"Hello, world!\"\n     * ```\n     *\n     * ---\n     *\n     * @template T The type of value the promise will eventually resolve to.\n     *\n     * @param executor A callback that returns a `MaybePromise<T>` value to enqueue.\n     * @param timeout The maximum time in milliseconds that the operation can take before timing out.\n     *\n     * @returns\n     * A {@link TimedPromise} that resolves to the value of the enqueued executor or rejects\n     * with a `TimeoutException` if the operation takes longer than the specified timeout.\n     */\n    public enqueue<T>(executor: Callback<[], MaybePromise<T>>, timeout?: number): TimedPromise<T>;\n    public enqueue<T>(\n        executor: DeferredPromise<void, T> | Callback<[], MaybePromise<T>>, timeout?: number\n    ): SmartPromise<T> | TimedPromise<T>\n    {\n        this._count += 1;\n\n        if (executor instanceof DeferredPromise)\n        {\n            const _executor = executor as DeferredPromise<void, T>;\n\n            executor = () =>\n            {\n                _executor.resolve();\n\n                return _executor;\n            };\n        }\n\n        const _executor = (resolve: PromiseResolver<T>, reject: PromiseRejecter) =>\n        {\n            this._promise = this._promise\n                .then(executor)\n                .then((value) => { this._count -= 1; resolve(value); })\n                .catch((value) => { this._count -= 1; reject(value); });\n        };\n\n        if (timeout) { return new TimedPromise<T>(_executor, timeout); }\n\n        return new SmartPromise<T>(_executor);\n    }\n\n    public override readonly [Symbol.toStringTag]: string = \"PromiseQueue\";\n}\n","/* eslint-disable @typescript-eslint/prefer-literal-enum-member */\n\nimport { RangeException, SmartIterator } from \"../models/index.js\";\n\n/**\n * An enumeration that represents the time units and their conversion factors.  \n * It can be used as utility to express time values in a more\n * readable way or to convert time values between different units.\n *\n * ---\n *\n * @example\n * ```ts\n * setTimeout(() => { [...] }, 5 * TimeUnit.Minute);\n * ```\n */\nexport enum TimeUnit\n{\n    /**\n     * A millisecond: the base time unit.\n     */\n    Millisecond = 1,\n\n    /**\n     * A second: 1000 milliseconds.\n     */\n    Second = 1_000,\n\n    /**\n     * A minute: 60 seconds.\n     */\n    Minute = 60 * Second,\n\n    /**\n     * An hour: 60 minutes.\n     */\n    Hour = 60 * Minute,\n\n    /**\n     * A day: 24 hours.\n     */\n    Day = 24 * Hour,\n\n    /**\n     * A week: 7 days.\n     */\n    Week = 7 * Day,\n\n    /**\n     * A month: 30 days.\n     */\n    Month = 30 * Day,\n\n    /**\n     * A year: 365 days.\n     */\n    Year = 365 * Day\n}\n\n/**\n * An enumeration that represents the days of the week.  \n * It can be used as utility to identify the days of the week when working with dates.\n *\n * ---\n *\n * @example\n * ```ts\n * const today = new Date();\n * if (today.getUTCDay() === WeekDay.Sunday)\n * {\n *     // Today is Sunday. Do something...\n * }\n * ```\n */\nexport enum WeekDay\n{\n    /**\n     * Sunday\n     */\n    Sunday = 0,\n\n    /**\n     * Monday\n     */\n    Monday = 1,\n\n    /**\n     * Tuesday\n     */\n    Tuesday = 2,\n\n    /**\n     * Wednesday\n     */\n    Wednesday = 3,\n\n    /**\n     * Thursday\n     */\n    Thursday = 4,\n\n    /**\n     * Friday\n     */\n    Friday = 5,\n\n    /**\n     * Saturday\n     */\n    Saturday = 6\n}\n\n/**\n * An utility function that calculates the difference between two dates.  \n * The difference can be expressed in different time units.\n *\n * ---\n *\n * @example\n * ```ts\n * const start = new Date(\"2025-01-01\");\n * const end = new Date(\"2025-01-31\");\n *\n * dateDifference(start, end, TimeUnit.Minute); // 43200\n * ```\n *\n * ---\n *\n * @param start The start date.\n * @param end The end date.\n * @param unit The time unit to express the difference. `TimeUnit.Day` by default.\n *\n * @returns The difference between the two dates in the specified time unit.\n */\nexport function dateDifference(start: number | string | Date, end: number | string | Date, unit = TimeUnit.Day): number\n{\n    let _round: (value: number) => number;\n\n    start = new Date(start);\n    end = new Date(end);\n\n    if (start < end) { _round = Math.floor; }\n    else { _round = Math.ceil; }\n\n    return _round((end.getTime() - start.getTime()) / unit);\n}\n\n/**\n * An utility function that generates an iterator over a range of dates.  \n * The step between the dates can be expressed in different time units.\n *\n * ---\n *\n * @example\n * ```ts\n * const start = new Date(\"2025-01-01\");\n * const end = new Date(\"2025-01-31\");\n *\n * for (const date of dateRange(start, end, TimeUnit.Week))\n * {\n *     date.toISOString().slice(8, 10); // \"01\", \"08\", \"15\", \"22\", \"29\"\n * }\n * ```\n *\n * ---\n *\n * @param start The start date (included).\n * @param end\n * The end date (excluded).\n *\n * Must be greater than the start date. Otherwise, a {@link RangeException} will be thrown.\n *\n * @param step The time unit to express the step between the dates. `TimeUnit.Day` by default.\n *\n * @returns A {@link SmartIterator} object that generates the dates in the range.\n */\nexport function dateRange(\n    start: number | string | Date, end: number | string | Date, step = TimeUnit.Day\n): SmartIterator<Date>\n{\n    start = new Date(start);\n    end = new Date(end);\n\n    if (start >= end) { throw new RangeException(\"The end date must be greater than the start date.\"); }\n\n    return new SmartIterator<Date>(function* ()\n    {\n        const endTime = end.getTime();\n\n        let unixTime: number = start.getTime();\n        while (unixTime < endTime)\n        {\n            yield new Date(unixTime);\n\n            unixTime += step;\n        }\n    });\n}\n\n/**\n * An utility function that rounds a date to the nearest time unit.  \n * The rounding can be expressed in different time units.\n *\n * ---\n *\n * @example\n * ```ts\n * const date = new Date(\"2025-01-01T12:34:56.789Z\");\n *\n * dateRound(date, TimeUnit.Hour); // 2025-01-01T12:00:00.000Z\n * ```\n *\n * ---\n *\n * @param date The date to round.\n * @param unit\n * The time unit to express the rounding. `TimeUnit.Day` by default.\n *\n * Must be greater than a millisecond and less than or equal to a day.  \n * Otherwise, a {@link RangeException} will be thrown.\n *\n * @returns The rounded date.\n */\nexport function dateRound(date: number | string | Date, unit = TimeUnit.Day): Date\n{\n    if (unit <= TimeUnit.Millisecond)\n    {\n        throw new RangeException(\n            \"Rounding a timestamp by milliseconds or less makes no sense.\" +\n            \"Use the timestamp value directly instead.\"\n        );\n    }\n    if (unit > TimeUnit.Day)\n    {\n        throw new RangeException(\n            \"Rounding by more than a day leads to unexpected results. \" +\n            \"Consider using other methods to round dates by weeks, months or years.\"\n        );\n    }\n\n    date = new Date(date);\n    return new Date(Math.floor(date.getTime() / unit) * unit);\n}\n\n/**\n * An utility function that gets the week of a date.  \n * The first day of the week can be optionally specified.\n *\n * ---\n *\n * @example\n * ```ts\n * const date = new Date(\"2025-01-01\");\n *\n * getWeek(date, WeekDay.Monday); // 2024-12-30\n * ```\n *\n * ---\n *\n * @param date The date to get the week of.\n * @param firstDay The first day of the week. `WeekDay.Sunday` by default.\n *\n * @returns The first day of the week of the specified date.\n */\nexport function getWeek(date: number | string | Date, firstDay = WeekDay.Sunday): Date\n{\n    date = new Date(date);\n\n    const startCorrector = 7 - firstDay;\n    const weekDayIndex = (date.getUTCDay() + startCorrector) % 7;\n    const firstDayTime = date.getTime() - (TimeUnit.Day * weekDayIndex);\n\n    return dateRound(new Date(firstDayTime));\n}\n\nexport function getMonth(date: number | string | Date): Date\n{\n    date = new Date(date);\n    return new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth()));\n}\nexport function getYear(date: number | string | Date): Date\n{\n    date = new Date(date);\n    return new Date(Date.UTC(date.getUTCFullYear()));\n}\n","import type { Interval } from \"../../core/types.js\";\nimport { isBrowser } from \"../../helpers.js\";\n\nimport Publisher from \"../callbacks/publisher.js\";\nimport { FatalErrorException, RuntimeException } from \"../exceptions/index.js\";\nimport type { Callback } from \"../types.js\";\n\ninterface GameLoopEventsMap\n{\n    \"start\": () => void;\n    \"stop\": () => void;\n}\n\n/**\n * A class representing a {@link https://en.wikipedia.org/wiki/Video_game_programming#Game_structure|game loop} pattern\n * that allows to run a function at a specific frame rate.\n *\n * In a browser environment, it uses the native {@link requestAnimationFrame}\n * function to run the callback at the refresh rate of the screen.  \n * In a non-browser environment, however, it uses the {@link setInterval}\n * function to run the callback at the specified fixed interval of time.\n *\n * Every time the callback is executed, it receives the\n * elapsed time since the start of the game loop.  \n * It's also possible to subscribe to the `start` & `stop` events to receive notifications when they occur.\n *\n * ---\n *\n * @example\n * ```ts\n * const loop = new GameLoop((elapsedTime: number) =>\n * {\n *     console.log(`The game loop has been running for ${elapsedTime}ms.`);\n * });\n *\n * loop.onStart(() => console.log(\"The game loop has started.\"));\n * loop.onStop(() => console.log(\"The game loop has stopped.\"));\n *\n * loop.start();\n * ```\n */\nexport default class GameLoop\n{\n    /**\n     * The handle of the interval or the animation frame, depending on the environment.  \n     * It's used to stop the game loop when the {@link GameLoop._stop} method is called.\n     */\n    protected _handle?: number | Interval;\n\n    /**\n     * The time when the game loop has started.  \n     * In addition to indicating the {@link https://en.wikipedia.org/wiki/Unix_time|Unix timestamp}\n     * of the start of the game loop, it's also used to calculate the elapsed time.\n     *\n     * This protected property is the only one that can be modified directly by the derived classes.  \n     * If you're looking for the public and readonly property, use the {@link GameLoop.startTime} getter instead.\n     */\n    protected _startTime: number;\n\n    /**\n     * The time when the game loop has started.  \n     * In addition to indicating the {@link https://en.wikipedia.org/wiki/Unix_time|Unix timestamp}\n     * of the start of the game loop, it's also used to calculate the elapsed time.\n     */\n    public get startTime(): number\n    {\n        return this._startTime;\n    }\n\n    /**\n     * A flag indicating whether the game loop is currently running or not.\n     *\n     * This protected property is the only one that can be modified directly by the derived classes.  \n     * If you're looking for the public and readonly property, use the {@link GameLoop.isRunning} getter instead.\n     */\n    protected _isRunning: boolean;\n\n    /**\n     * A flag indicating whether the game loop is currently running or not.\n     */\n    public get isRunning(): boolean\n    {\n        return this._isRunning;\n    }\n\n    /**\n     * The elapsed time since the start of the game loop.  \n     * It's calculated as the difference between the current time and the {@link GameLoop.startTime}.\n     */\n    public get elapsedTime(): number\n    {\n        return performance.now() - this._startTime;\n    }\n\n    /**\n     * The {@link Publisher} object that will be used to publish the events of the game loop.\n     */\n    protected readonly _publisher: Publisher<GameLoopEventsMap>;\n\n    /**\n     * The internal method actually responsible for starting the game loop.\n     *\n     * Depending on the current environment, it could use the\n     * {@link requestAnimationFrame} or the {@link setInterval} function.\n     */\n    protected readonly _start: Callback;\n\n    /**\n     * The internal method actually responsible for stopping the game loop.\n     *\n     * Depending on the current environment, it could use the\n     * {@link cancelAnimationFrame} or the {@link clearInterval} function.\n     */\n    protected readonly _stop: Callback;\n\n    /**\n     * Initializes a new instance of the {@link GameLoop} class.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const loop = new GameLoop((elapsedTime: number) => { [...] });\n     * ```\n     *\n     * ---\n     *\n     * @param callback The function that will be executed at each iteration of the game loop.\n     * @param msIfNotBrowser\n     * The interval in milliseconds that will be used if the current environment isn't a browser. Default is `40`.\n     */\n    public constructor(callback: FrameRequestCallback, msIfNotBrowser = 40)\n    {\n        this._startTime = 0;\n        this._isRunning = false;\n\n        if (isBrowser)\n        {\n            this._start = () =>\n            {\n                callback(this.elapsedTime);\n\n                this._handle = window.requestAnimationFrame(this._start);\n            };\n\n            this._stop = () => window.cancelAnimationFrame(this._handle as number);\n        }\n        else\n        {\n            // eslint-disable-next-line no-console\n            console.warn(\n                \"Not a browser environment detected. \" +\n                `Using setInterval@${msIfNotBrowser}ms instead of requestAnimationFrame...`\n            );\n\n            this._start = () =>\n            {\n                this._handle = setInterval(() => callback(this.elapsedTime), msIfNotBrowser);\n            };\n\n            this._stop = () => clearInterval(this._handle as Interval);\n        }\n\n        this._publisher = new Publisher();\n    }\n\n    /**\n     * Starts the execution of the game loop.\n     *\n     * If the game loop is already running, a {@link RuntimeException} will be thrown.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * loop.onStart(() => { [...] }); // This callback will be executed.\n     * loop.start();\n     * ```\n     *\n     * ---\n     *\n     * @param elapsedTime The elapsed time to set as default when the game loop starts. Default is `0`.\n     */\n    public start(elapsedTime = 0): void\n    {\n        if (this._isRunning) { throw new RuntimeException(\"The game loop has already been started.\"); }\n\n        this._startTime = performance.now() - elapsedTime;\n        this._start();\n        this._isRunning = true;\n\n        this._publisher.publish(\"start\");\n    }\n\n    /**\n     * Stops the execution of the game loop.\n     *\n     * If the game loop hasn't yet started, a {@link RuntimeException} will be thrown.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * loop.onStop(() => { [...] }); // This callback will be executed.\n     * loop.stop();\n     * ```\n     */\n    public stop(): void\n    {\n        if (!(this._isRunning))\n        {\n            throw new RuntimeException(\"The game loop had already stopped or hadn't yet started.\");\n        }\n        if (!(this._handle)) { throw new FatalErrorException(); }\n\n        this._stop();\n        this._handle = undefined;\n        this._isRunning = false;\n\n        this._publisher.publish(\"stop\");\n    }\n\n    /**\n     * Subscribes to the `start` event of the game loop.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * loop.onStart(() => console.log(\"The game loop has started.\"));\n     * ```\n     *\n     * ---\n     *\n     * @param callback The function that will be executed when the game loop starts.\n     *\n     * @returns A function that can be used to unsubscribe from the event.\n     */\n    public onStart(callback: Callback): Callback\n    {\n        return this._publisher.subscribe(\"start\", callback);\n    }\n\n    /**\n     * Subscribes to the `stop` event of the game loop.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * loop.onStop(() => console.log(\"The game loop has stopped.\"));\n     * ```\n     *\n     * ---\n     *\n     * @param callback The function that will be executed when the game loop stops.\n     *\n     * @returns A function that can be used to unsubscribe from the event.\n     */\n    public onStop(callback: Callback): Callback\n    {\n        return this._publisher.subscribe(\"stop\", callback);\n    }\n\n    public readonly [Symbol.toStringTag]: string = \"GameLoop\";\n}\n","import { TimeUnit } from \"../../utils/date.js\";\n\nimport type Publisher from \"../callbacks/publisher.js\";\nimport { FatalErrorException, RangeException, RuntimeException } from \"../exceptions/index.js\";\nimport type { Callback } from \"../types.js\";\n\nimport GameLoop from \"./game-loop.js\";\n\ninterface ClockEventsMap\n{\n    \"start\": () => void;\n    \"stop\": () => void;\n    \"tick\": (elapsedTime: number) => void;\n}\n\n/**\n * A class representing a clock.\n *\n * It can be started, stopped and, when running, it ticks at a specific frame rate.  \n * It's possible to subscribe to these events to receive notifications when they occur.\n *\n * ---\n *\n * @example\n * ```ts\n * const clock = new Clock();\n *\n * clock.onStart(() => console.log(\"The clock has started.\"));\n * clock.onTick((elapsedTime) => console.log(`The clock has ticked at ${elapsedTime}ms.`));\n * clock.onStop(() => console.log(\"The clock has stopped.\"));\n *\n * clock.start();\n * ```\n */\nexport default class Clock extends GameLoop\n{\n    /**\n     * The {@link Publisher} object that will be used to publish the events of the clock.\n     */\n    declare protected readonly _publisher: Publisher<ClockEventsMap>;\n\n    /**\n     * Initializes a new instance of the {@link Clock} class.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const clock = new Clock();\n     * ```\n     *\n     * ---\n     *\n     * @param msIfNotBrowser\n     * The interval in milliseconds at which the clock will tick if the environment is not a browser.  \n     * `TimeUnit.Second` by default.\n     */\n    public constructor(msIfNotBrowser: number = TimeUnit.Second)\n    {\n        super((elapsedTime) => this._publisher.publish(\"tick\", elapsedTime), msIfNotBrowser);\n    }\n\n    /**\n     * Starts the execution of the clock.\n     *\n     * If the clock is already running, a {@link RuntimeException} will be thrown.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * clock.onStart(() => { [...] }); // This callback will be executed.\n     * clock.start();\n     * ```\n     *\n     * ---\n     *\n     * @param elapsedTime The elapsed time to set as default when the clock starts. Default is `0`.\n     */\n    public override start(elapsedTime = 0): void\n    {\n        if (this._isRunning) { throw new RuntimeException(\"The clock has already been started.\"); }\n\n        this._startTime = performance.now() - elapsedTime;\n        this._start();\n        this._isRunning = true;\n\n        this._publisher.publish(\"start\");\n    }\n\n    /**\n     * Stops the execution of the clock.\n     *\n     * If the clock hasn't yet started, a {@link RuntimeException} will be thrown.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * clock.onStop(() => { [...] }); // This callback will be executed.\n     * clock.stop();\n     * ```\n     */\n    public override stop(): void\n    {\n        if (!(this._isRunning)) { throw new RuntimeException(\"The clock had already stopped or hadn't yet started.\"); }\n        if (!(this._handle)) { throw new FatalErrorException(); }\n\n        this._stop();\n        this._handle = undefined;\n        this._isRunning = false;\n\n        this._publisher.publish(\"stop\");\n    }\n\n    /**\n     * Subscribes to the `tick` event of the clock.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * clock.onTick((elapsedTime) => { [...] }); // This callback will be executed.\n     * clock.start();\n     * ```\n     *\n     * ---\n     *\n     * @param callback The callback that will be executed when the clock ticks.\n     * @param tickStep\n     * The minimum time in milliseconds that must pass from the previous execution of the callback to the next one.\n     *\n     * - If it's a positive number, the callback will be executed only if the\n     * time passed from the previous execution is greater than this number.\n     * - If it's `0`, the callback will be executed every tick without even checking for the time.\n     * - If it's a negative number, a {@link RangeException} will be thrown.\n     *\n     * @returns A function that can be used to unsubscribe from the event.\n     */\n    public onTick(callback: (elapsedTime: number) => void, tickStep = 0): Callback\n    {\n        if (tickStep < 0) { throw new RangeException(\"The tick step must be a non-negative number.\"); }\n        if (tickStep === 0) { return this._publisher.subscribe(\"tick\", callback); }\n\n        let lastTick = 0;\n\n        return this._publisher.subscribe(\"tick\", (elapsedTime: number) =>\n        {\n            if ((elapsedTime - lastTick) < tickStep) { return; }\n\n            callback(elapsedTime);\n            lastTick = elapsedTime;\n        });\n    }\n\n    public override readonly [Symbol.toStringTag]: string = \"Clock\";\n}\n","import { TimeUnit } from \"../../utils/date.js\";\n\nimport type Publisher from \"../callbacks/publisher.js\";\nimport { FatalErrorException, RangeException, RuntimeException } from \"../exceptions/index.js\";\nimport type { SmartPromise } from \"../promises/index.js\";\nimport { DeferredPromise } from \"../promises/index.js\";\nimport type { Callback } from \"../types.js\";\n\nimport GameLoop from \"./game-loop.js\";\n\ninterface CountdownEventsMap\n{\n    start: () => void;\n    stop: (reason: unknown) => void;\n    tick: (remainingTime: number) => void;\n    expire: () => void;\n}\n\n/**\n * A class representing a countdown.\n *\n * It can be started, stopped, when running it ticks at a specific frame rate and it expires when the time's up.  \n * It's possible to subscribe to these events to receive notifications when they occur.\n *\n * ---\n *\n * @example\n * ```ts\n * const countdown = new Countdown(10_000);\n *\n * countdown.onStart(() => console.log(\"The countdown has started.\"));\n * countdown.onTick((remainingTime) => console.log(`The countdown has ${remainingTime}ms remaining.`));\n * countdown.onStop((reason) => console.log(`The countdown has stopped because of ${reason}.`));\n * countdown.onExpire(() => console.log(\"The countdown has expired.\"));\n *\n * countdown.start();\n * ```\n */\nexport default class Countdown extends GameLoop\n{\n    /**\n     * The {@link Publisher} object that will be used to publish the events of the countdown.\n     */\n    declare protected readonly _publisher: Publisher<CountdownEventsMap>;\n\n    /**\n     * The total duration of the countdown in milliseconds.\n     *\n     * This protected property is the only one that can be modified directly by the derived classes.  \n     * If you're looking for the public and readonly property, use the {@link Countdown.duration} getter instead.\n     */\n    protected _duration: number;\n\n    /**\n     * The total duration of the countdown in milliseconds.\n     */\n    public get duration(): number\n    {\n        return this._duration;\n    }\n\n    /**\n     * The remaining time of the countdown in milliseconds.  \n     * It's calculated as the difference between the total duration and the elapsed time.\n     */\n    public get remainingTime(): number\n    {\n        return this._duration - this.elapsedTime;\n    }\n\n    /**\n     * The {@link DeferredPromise} that will be resolved or rejected when the countdown expires or stops.\n     */\n    protected _deferrer?: DeferredPromise<void>;\n\n    /**\n     * Initializes a new instance of the {@link Countdown} class.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const countdown = new Countdown(10_000);\n     * ```\n     *\n     * ---\n     *\n     * @param duration\n     * The total duration of the countdown in milliseconds.\n     *\n     * @param msIfNotBrowser\n     * The interval in milliseconds at which the countdown will tick if the environment is not a browser.  \n     * `TimeUnit.Second` by default.\n     */\n    public constructor(duration: number, msIfNotBrowser: number = TimeUnit.Second)\n    {\n        const callback = () =>\n        {\n            const remainingTime = this.remainingTime;\n            if (remainingTime <= 0)\n            {\n                this._deferrerStop();\n\n                this._publisher.publish(\"tick\", 0);\n                this._publisher.publish(\"expire\");\n            }\n            else\n            {\n                this._publisher.publish(\"tick\", remainingTime);\n            }\n        };\n\n        super(callback, msIfNotBrowser);\n\n        this._duration = duration;\n    }\n\n    /**\n     * The internal method actually responsible for stopping the\n     * countdown and resolving or rejecting the {@link Countdown._deferrer} promise.\n     *\n     * ---\n     *\n     * @param reason\n     * The reason why the countdown has stopped.\n     *\n     * - If it's `undefined`, the promise will be resolved.\n     * - If it's a value, the promise will be rejected with that value.\n     */\n    protected _deferrerStop(reason?: unknown): void\n    {\n        if (!(this._isRunning)) { throw new RuntimeException(\"The countdown hadn't yet started.\"); }\n        if (!(this._deferrer)) { throw new FatalErrorException(); }\n\n        this._stop();\n        this._handle = undefined;\n        this._isRunning = false;\n\n        if (reason !== undefined) { this._deferrer.reject(reason); }\n        else { this._deferrer.resolve(); }\n\n        this._deferrer = undefined;\n    }\n\n    /**\n     * Starts the execution of the countdown.\n     *\n     * If the countdown is already running, a {@link RuntimeException} will be thrown.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * countdown.onStart(() => { [...] }); // This callback will be executed.\n     * countdown.start();\n     * ```\n     *\n     * ---\n     *\n     * @param remainingTime\n     * The remaining time to set as default when the countdown starts.  \n     * Default is the {@link Countdown.duration} itself.\n     *\n     * @returns A {@link SmartPromise} that will be resolved or rejected when the countdown expires or stops.\n     */\n    public override start(remainingTime: number = this.duration): SmartPromise<void>\n    {\n        if (this._isRunning) { throw new RuntimeException(\"The countdown had already stopped or hadn't yet started.\"); }\n        if (this._deferrer) { throw new FatalErrorException(); }\n\n        this._deferrer = new DeferredPromise();\n        super.start(this.duration - remainingTime);\n\n        this._publisher.publish(\"start\");\n\n        return this._deferrer;\n    }\n\n    /**\n     * Stops the execution of the countdown.\n     *\n     * If the countdown hasn't yet started, a {@link RuntimeException} will be thrown.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * countdown.onStop(() => { [...] }); // This callback will be executed.\n     * countdown.stop();\n     * ```\n     *\n     * ---\n     *\n     * @param reason\n     * The reason why the countdown has stopped.\n     *\n     * - If it's `undefined`, the promise will be resolved.\n     * - If it's a value, the promise will be rejected with that value.\n     */\n    public override stop(reason?: unknown): void\n    {\n        // TODO: Once solved Issues #6 & #10, make the `reason` parameter required.\n        //       - https://github.com/Byloth/core/issues/6\n        //       - https://github.com/Byloth/core/issues/10\n        //\n        this._deferrerStop(reason);\n\n        this._publisher.publish(\"stop\", reason);\n    }\n\n    /**\n     * Subscribes to the `tick` event of the countdown.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * countdown.onTick((remainingTime) => { [...] }); // This callback will be executed.\n     * countdown.start();\n     * ```\n     *\n     * ---\n     *\n     * @param callback The callback that will be executed when the countdown ticks.\n     * @param tickStep\n     * The minimum time in milliseconds that must pass from the previous execution of the callback to the next one.\n     *\n     * - If it's a positive number, the callback will be executed only if the\n     * time passed from the previous execution is greater than this number.\n     * - If it's `0`, the callback will be executed every tick without even checking for the time.\n     * - If it's a negative number, a {@link RangeException} will be thrown.\n     *\n     * @returns A function that can be used to unsubscribe from the event.\n     */\n    public onTick(callback: (remainingTime: number) => void, tickStep = 0): Callback\n    {\n        if (tickStep < 0) { throw new RangeException(\"The tick step must be a non-negative number.\"); }\n        if (tickStep === 0) { return this._publisher.subscribe(\"tick\", callback); }\n\n        let lastTick = this.remainingTime;\n\n        return this._publisher.subscribe(\"tick\", (remainingTime: number) =>\n        {\n            if ((lastTick - remainingTime) < tickStep) { return; }\n\n            callback(remainingTime);\n            lastTick = remainingTime;\n        });\n    }\n\n    /**\n     * Subscribes to the `expire` event of the countdown.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * countdown.onExpire(() => { [...] }); // This callback will be executed once the countdown has expired.\n     * countdown.start();\n     * ```\n     *\n     * ---\n     *\n     * @param callback The callback that will be executed when the countdown expires.\n     *\n     * @returns A function that can be used to unsubscribe from the event.\n     */\n    public onExpire(callback: Callback): Callback\n    {\n        return this._publisher.subscribe(\"expire\", callback);\n    }\n\n    public override readonly [Symbol.toStringTag]: string = \"Countdown\";\n}\n","import { SmartIterator, ValueException } from \"../models/index.js\";\n\n/**\n * An utility class that provides a set of methods to generate sequences of numbers following specific curves.  \n * It can be used to generate sequences of values that can be\n * used in animations, transitions and other different scenarios.\n *\n * It cannot be instantiated directly.\n */\nexport default class Curve\n{\n    /**\n     * Generates a given number of values following a linear curve.  \n     * The values are equally spaced and normalized between 0 and 1.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * for (const value of Curve.Linear(5))\n     * {\n     *     console.log(value); // 0, 0.25, 0.5, 0.75, 1\n     * }\n     * ```\n     *\n     * ---\n     *\n     * @param values The number of values to generate.\n     *\n     * @returns A {@link SmartIterator} object that generates the values following a linear curve.\n     */\n    public static Linear(values: number): SmartIterator<number>\n    {\n        const steps = (values - 1);\n\n        return new SmartIterator<number>(function* ()\n        {\n            for (let index = 0; index < values; index += 1) { yield index / steps; }\n        });\n    }\n\n    /**\n     * Generates a given number of values following an exponential curve.  \n     * The values are equally spaced and normalized between 0 and 1.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * for (const value of Curve.Exponential(6))\n     * {\n     *     console.log(value); // 0, 0.04, 0.16, 0.36, 0.64, 1\n     * }\n     * ```\n     *\n     * ---\n     *\n     * @param values The number of values to generate.\n     * @param base\n     * The base of the exponential curve. Default is `2`.\n     *\n     * Also note that:\n     * - If it's equal to `1`, the curve will be linear.\n     * - If it's included between `0` and `1`, the curve will be logarithmic.\n     *\n     * The base cannot be negative. If so, a {@link ValueException} will be thrown.\n     *\n     * @returns A {@link SmartIterator} object that generates the values following an exponential curve.\n     */\n    public static Exponential(values: number, base = 2): SmartIterator<number>\n    {\n        if (base < 0) { throw new ValueException(\"The base of the exponential curve cannot be negative.\"); }\n\n        const steps = (values - 1);\n\n        return new SmartIterator<number>(function* ()\n        {\n            for (let index = 0; index < values; index += 1) { yield Math.pow(index / steps, base); }\n        });\n    }\n\n    private constructor() { /* ... */ }\n\n    public readonly [Symbol.toStringTag]: string = \"Curve\";\n}\n","import { ValueException } from \"../models/index.js\";\n\n/**\n * A wrapper class around the native {@link Math.random} function that\n * provides a set of methods to generate random values more easily.\n * It can be used to generate random numbers, booleans and other different values.\n *\n * The class exposes two coexisting surfaces:\n * - A **static API** (`Random.Integer`, `Random.Boolean`, …) that uses\n *   {@link Math.random} and is therefore non-deterministic.\n * - An **instance API** with the same method names that uses a seeded PRNG\n *   (Mulberry32) for reproducible sequences. Instances are created via the\n *   {@link Random.FromSeed} factory; the constructor is private.\n */\nexport default class Random\n{\n    static #Mulberry32(seed: number): () => number\n    {\n        let state = seed | 0;\n\n        return () =>\n        {\n            state = (state + 0x6D2B79F5) | 0;\n\n            let t = state;\n            t = Math.imul(t ^ (t >>> 15), t | 1);\n            t ^= t + Math.imul(t ^ (t >>> 7), t | 61);\n\n            return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n        };\n    }\n\n    private static _Boolean(random: () => number, ratio: number): boolean\n    {\n        return (random() < ratio);\n    }\n\n    private static _Integer(random: () => number, min: number, max?: number): number\n    {\n        if (max === undefined) { return Math.floor(random() * min); }\n\n        return Math.floor(random() * (max - min) + min);\n    }\n\n    private static _Decimal(random: () => number, min?: number, max?: number): number\n    {\n        if (min === undefined) { return random(); }\n        if (max === undefined) { return (random() * min); }\n\n        return (random() * (max - min) + min);\n    }\n\n    private static _Index<T>(random: () => number, elements: readonly T[]): number\n    {\n        if (elements.length === 0) { throw new ValueException(\"You must provide at least one element.\"); }\n\n        return Random._Integer(random, elements.length);\n    }\n\n    private static _Choice<T>(random: () => number, elements: readonly T[]): T\n    {\n        return elements[Random._Index(random, elements)];\n    }\n\n    private static _Sample<T>(\n        random: () => number,\n        elements: readonly T[],\n        count: number,\n        weights?: readonly number[]\n    ): T[]\n    {\n        const length = elements.length;\n\n        if (length === 0) { throw new ValueException(\"You must provide at least one element.\"); }\n        if (count < 0) { throw new ValueException(\"Count must be non-negative.\"); }\n        if (count > length) { throw new ValueException(\"Count cannot exceed the number of elements.\"); }\n\n        if (count === 0) { return []; }\n\n        if (weights === undefined)\n        {\n            const pool = Array.from(elements);\n            const result: T[] = new Array(count);\n\n            for (let index = 0; index < count; index += 1)\n            {\n                const randomIndex = Random._Integer(random, index, length);\n\n                result[index] = pool[randomIndex];\n                pool[randomIndex] = pool[index];\n            }\n\n            return result;\n        }\n\n        if (weights.length !== length)\n        {\n            throw new ValueException(\"Weights array must have the same length as elements array.\");\n        }\n\n        const keys: ({ index: number, key: number })[] = new Array(length);\n        for (let index = 0; index < length; index += 1)\n        {\n            if (weights[index] <= 0)\n            {\n                throw new ValueException(`Weight for element #${index} must be greater than zero.`);\n            }\n\n            keys[index] = { index: index, key: Math.pow(random(), 1 / weights[index]) };\n        }\n\n        keys.sort((a, b) => b.key - a.key);\n\n        const result: T[] = new Array(count);\n        for (let index = 0; index < count; index += 1)\n        {\n            result[index] = elements[keys[index].index];\n        }\n\n        return result;\n    }\n\n    static #Split(random: () => number, total: number, parts: number): number[]\n    {\n        const cuts: number[] = new Array(parts - 1);\n        for (let index = 0; index < cuts.length; index += 1)\n        {\n            cuts[index] = random() * total;\n        }\n\n        cuts.sort((a, b) => (a - b));\n\n        const boundaries = [0, ...cuts, total];\n        const values: number[] = new Array(parts);\n\n        for (let index = 0; index < parts; index += 1)\n        {\n            values[index] = Math.floor(boundaries[index + 1] - boundaries[index]);\n        }\n\n        let remainder = total - values.reduce((sum, val) => (sum + val), 0);\n        while (remainder > 0)\n        {\n            values[Random._Integer(random, parts)] += 1;\n\n            remainder -= 1;\n        }\n\n        return values;\n    }\n\n    private static _Split<T>(\n        random: () => number,\n        totalOrElements: number | Iterable<T>,\n        parts: number\n    ): number[] | T[][]\n    {\n        if (parts < 1) { throw new ValueException(\"The number of splits must be greater than zero.\"); }\n\n        if (typeof totalOrElements === \"number\")\n        {\n            if (totalOrElements < 0) { throw new ValueException(\"The total must be a non-negative number.\"); }\n\n            return Random.#Split(random, totalOrElements, parts);\n        }\n\n        const elements = Array.from(totalOrElements);\n        const length = elements.length;\n\n        if (length === 0) { throw new ValueException(\"You must provide at least one element.\"); }\n        if (parts > length)\n        {\n            throw new ValueException(\"The number of splits cannot exceed the number of elements.\");\n        }\n\n        const sizes = Random.#Split(random, length, parts);\n        const groups: T[][] = new Array(parts);\n\n        let offset = 0;\n        for (let index = 0; index < parts; index += 1)\n        {\n            groups[index] = elements.slice(offset, offset + sizes[index]);\n\n            offset += sizes[index];\n        }\n\n        return groups;\n    }\n\n    /**\n     * Generates a random boolean value.  \n     * See also {@link Random.boolean} for the seeded & deterministic counterpart.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * if (Random.Boolean())\n     * {\n     *    // Do something...\n     * }\n     * ```\n     *\n     * ---\n     *\n     * @param ratio\n     * The probability of generating `true`.\n     *\n     * It must be included between `0` and `1`. Default is `0.5`.\n     *\n     * @returns A random boolean value.\n     */\n    public static Boolean(ratio = 0.5): boolean\n    {\n        return Random._Boolean(Math.random, ratio);\n    }\n\n    /**\n     * Generates a random integer value between `0` (included) and `max` (excluded).  \n     * See also {@link Random.integer} for the seeded & deterministic counterpart.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * Random.Integer(5); // [0, 5)\n     * ```\n     *\n     * ---\n     *\n     * @param max The maximum value (excluded).\n     *\n     * @returns A random integer value.\n     */\n    public static Integer(max: number): number;\n\n    /**\n     * Generates a random integer value between `min` (included) and `max` (excluded).  \n     * See also {@link Random.integer} for the seeded & deterministic counterpart.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * Random.Integer(2, 7); // [2, 7)\n     * ```\n     *\n     * ---\n     *\n     * @param min The minimum value (included).\n     * @param max The maximum value (excluded).\n     *\n     * @returns A random integer value.\n     */\n    public static Integer(min: number, max: number): number;\n    public static Integer(min: number, max?: number): number\n    {\n        return Random._Integer(Math.random, min, max);\n    }\n\n    /**\n     * Generates a random decimal value between `0` (included) and `1` (excluded).  \n     * See also {@link Random.decimal} for the seeded & deterministic counterpart.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * Random.Decimal(); // e.g. 0.123456789\n     * ```\n     *\n     * ---\n     *\n     * @returns A random decimal value.\n     */\n    public static Decimal(): number;\n\n    /**\n     * Generates a random decimal value between `0` (included) and `max` (excluded).  \n     * See also {@link Random.decimal} for the seeded & deterministic counterpart.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * Random.Decimal(5); // e.g. 2.3456789\n     * ```\n     *\n     * ---\n     *\n     * @param max The maximum value (excluded).\n     *\n     * @returns A random decimal value.\n     */\n    public static Decimal(max: number): number;\n\n    /**\n     * Generates a random decimal value between `min` (included) and `max` (excluded).  \n     * See also {@link Random.decimal} for the seeded & deterministic counterpart.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * Random.Decimal(2, 7); // e.g. 4.56789\n     * ```\n     *\n     * ---\n     *\n     * @param min The minimum value (included).\n     * @param max The maximum value (excluded).\n     *\n     * @returns A random decimal value.\n     */\n    public static Decimal(min: number, max: number): number;\n    public static Decimal(min?: number, max?: number): number\n    {\n        return Random._Decimal(Math.random, min, max);\n    }\n\n    /**\n     * Picks a random valid index from a given array of elements.  \n     * See also {@link Random.index} for the seeded & deterministic counterpart.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const elements = [\"a\", \"b\", \"c\"];\n     *\n     * Random.Index(elements); // 0, 1, or 2\n     * ```\n     *\n     * ---\n     *\n     * @template T The type of the elements in the array.\n     *\n     * @param elements\n     * The array of elements to pick from.\n     *\n     * It must contain at least one element. Otherwise, a {@link ValueException} will be thrown.\n     *\n     * @returns A valid random index from the given array.\n     */\n    public static Index<T>(elements: readonly T[]): number\n    {\n        return Random._Index(Math.random, elements);\n    }\n\n    /**\n     * Picks a random element from a given array of elements.  \n     * See also {@link Random.choice} for the seeded & deterministic counterpart.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const elements = [\"a\", \"b\", \"c\"];\n     *\n     * Random.Choice(elements); // \"a\", \"b\", or \"c\"\n     * ```\n     *\n     * ---\n     *\n     * @template T The type of the elements in the array.\n     *\n     * @param elements\n     * The array of elements to pick from.\n     *\n     * It must contain at least one element. Otherwise, a {@link ValueException} will be thrown.\n     *\n     * @returns A random element from the given array.\n     */\n    public static Choice<T>(elements: readonly T[]): T\n    {\n        return Random._Choice(Math.random, elements);\n    }\n\n    /**\n     * Picks a random sample of elements from a given array without replacement.  \n     * See also {@link Random.sample} for the seeded & deterministic counterpart.\n     *\n     * Uses the Fisher-Yates shuffle algorithm for uniform sampling,\n     * which is O(count) instead of O(n log n) for a full shuffle.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * Random.Sample([1, 2, 3, 4, 5], 3); // e.g. [4, 1, 5]\n     * ```\n     *\n     * ---\n     *\n     * @template T The type of the elements in the array.\n     *\n     * @param elements\n     * The array of elements to sample from.\n     *\n     * It must contain at least one element. Otherwise, a {@link ValueException} will be thrown.\n     *\n     * @param count\n     * The number of elements to sample.\n     *\n     * It must be between `0` and `elements.length`. Otherwise, a {@link ValueException} will be thrown.\n     *\n     * @returns An array containing the randomly sampled elements.\n     */\n    public static Sample<T>(elements: readonly T[], count: number): T[];\n\n    /**\n     * Picks a weighted random sample of elements from a given array without replacement.  \n     * See also {@link Random.sample} for the seeded & deterministic counterpart.\n     *\n     * Uses the Efraimidis-Spirakis algorithm for weighted sampling.\n     * Elements with higher weights have a higher probability of being selected.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * // Element \"a\" is 3x more likely to be picked than \"b\" or \"c\"\n     * Random.Sample([\"a\", \"b\", \"c\"], 2, [3, 1, 1]); // e.g. [\"a\", \"c\"]\n     * ```\n     *\n     * ---\n     *\n     * @template T The type of the elements in the array.\n     *\n     * @param elements\n     * The array of elements to sample from.\n     *\n     * It must contain at least one element. Otherwise, a {@link ValueException} will be thrown.\n     *\n     * @param count\n     * The number of elements to sample.\n     *\n     * It must be between `0` and `elements.length`. Otherwise, a {@link ValueException} will be thrown.\n     *\n     * @param weights\n     * The weights associated with each element.\n     *\n     * It must have the same length as the elements array.\n     * All weights must be greater than zero. Otherwise, a {@link ValueException} will be thrown.\n     *\n     * @returns An array containing the randomly sampled elements.\n     */\n    public static Sample<T>(elements: readonly T[], count: number, weights: readonly number[]): T[];\n    public static Sample<T>(elements: readonly T[], count: number, weights?: readonly number[]): T[]\n    {\n        return Random._Sample(Math.random, elements, count, weights);\n    }\n\n    /**\n     * Splits a total amount into a given number of randomly balanced integer parts that sum to the total.  \n     * See also {@link Random.split} for the seeded & deterministic counterpart.\n     *\n     * Uses random cut-points to generate a uniform distribution of parts.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * Random.Split(100, 3); // e.g. [28, 41, 31]\n     * Random.Split(10, 4);  // e.g. [3, 1, 4, 2]\n     * ```\n     *\n     * ---\n     *\n     * @param total\n     * The total amount to split.\n     *\n     * It must be non-negative. Otherwise, a {@link ValueException} will be thrown.\n     *\n     * @param parts\n     * The number of parts to split the total into.\n     *\n     * It must be at least `1`. Otherwise, a {@link ValueException} will be thrown.\n     *\n     * @returns An array of integers that sum to the given total.\n     */\n    public static Split(total: number, parts: number): number[];\n\n    /**\n     * Splits an iterable of elements into a given number of randomly balanced groups.  \n     * See also {@link Random.split} for the seeded & deterministic counterpart.\n     *\n     * The elements are distributed into groups whose sizes are\n     * determined by a random split of the total number of elements.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * Random.Split([1, 2, 3, 4, 5], 2); // e.g. [[1, 2], [3, 4, 5]]\n     * Random.Split([1, 2, 3, 4, 5], 2); // e.g. [[1, 2, 3, 4], [5]]\n     * Random.Split(\"abcdef\", 3);        // e.g. [[\"a\"], [\"b\", \"c\", \"d\"], [\"e\", \"f\"]]\n     * ```\n     *\n     * ---\n     *\n     * @template T The type of the elements in the iterable.\n     *\n     * @param elements\n     * The iterable of elements to split into groups.\n     *\n     * It must contain at least one element. Otherwise, a {@link ValueException} will be thrown.\n     *\n     * @param groups\n     * The number of groups to split the elements into.\n     *\n     * It must be between `1` and the number of elements.\n     * Otherwise, a {@link ValueException} will be thrown.\n     *\n     * @returns An array of arrays, each containing a subset of the original elements.\n     */\n    public static Split<T>(elements: Iterable<T>, groups: number): T[][];\n    public static Split<T>(totalOrElements: number | Iterable<T>, parts: number): number[] | T[][]\n    {\n        return Random._Split(Math.random, totalOrElements, parts);\n    }\n\n    /**\n     * Creates a new seedable {@link Random} generator instance.\n     *\n     * The returned instance exposes the same API as the static {@link Random} class,\n     * but produces deterministic sequences driven by the given seed.\n     * Two instances built with the same seed will emit the same values in the same order.\n     *\n     * Internally, values are produced by a Mulberry32 PRNG.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const rng = Random.FromSeed(42); // deterministic — same seed, same sequence\n     *\n     * rng.integer(100); // 60\n     * rng.decimal();    // 0.44829055899754167\n     * ```\n     *\n     * ---\n     *\n     * @param seed The 32-bit integer seed used to initialize the generator.\n     *\n     * @returns A new {@link Random} instance bound to the given seed.\n     */\n    public static FromSeed(seed: number): Random\n    {\n        return new Random(seed);\n    }\n\n    private readonly _next: () => number;\n\n    private constructor(seed: number)\n    {\n        this._next = Random.#Mulberry32(seed);\n    }\n\n    /**\n     * Generates a random boolean value.  \n     * See also {@link Random.Boolean} for the static & non-deterministic counterpart.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const rng = Random.FromSeed(...);\n     *\n     * if (rng.boolean())\n     * {\n     *    // Do something...\n     * }\n     * ```\n     *\n     * ---\n     *\n     * @param ratio\n     * The probability of generating `true`.\n     *\n     * It must be included between `0` and `1`. Default is `0.5`.\n     *\n     * @returns A random boolean value.\n     */\n    public boolean(ratio = 0.5): boolean\n    {\n        return Random._Boolean(this._next, ratio);\n    }\n\n    /**\n     * Generates a random integer value between `0` (included) and `max` (excluded).  \n     * See also {@link Random.Integer} for the static & non-deterministic counterpart.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const rng = Random.FromSeed(...);\n     * \n     * rng.integer(5); // [0, 5)\n     * ```\n     *\n     * ---\n     *\n     * @param max The maximum value (excluded).\n     *\n     * @returns A random integer value.\n     */\n    public integer(max: number): number;\n\n    /**\n     * Generates a random integer value between `min` (included) and `max` (excluded).  \n     * See also {@link Random.Integer} for the static & non-deterministic counterpart.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const rng = Random.FromSeed(...);\n     *\n     * rng.integer(2, 7); // [2, 7)\n     * ```\n     *\n     * ---\n     *\n     * @param min The minimum value (included).\n     * @param max The maximum value (excluded).\n     *\n     * @returns A random integer value.\n     */\n    public integer(min: number, max: number): number;\n    public integer(min: number, max?: number): number\n    {\n        return Random._Integer(this._next, min, max);\n    }\n\n    /**\n     * Generates a random decimal value between `0` (included) and `1` (excluded).  \n     * See also {@link Random.Decimal} for the static & non-deterministic counterpart.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const rng = Random.FromSeed(...);\n     *\n     * rng.decimal(); // e.g. 0.123456789\n     * ```\n     *\n     * ---\n     *\n     * @returns A random decimal value.\n     */\n    public decimal(): number;\n\n    /**\n     * Generates a random decimal value between `0` (included) and `max` (excluded).  \n     * See also {@link Random.Decimal} for the static & non-deterministic counterpart.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const rng = Random.FromSeed(...);\n     *\n     * rng.decimal(5); // e.g. 2.3456789\n     * ```\n     *\n     * ---\n     *\n     * @param max The maximum value (excluded).\n     *\n     * @returns A random decimal value.\n     */\n    public decimal(max: number): number;\n\n    /**\n     * Generates a random decimal value between `min` (included) and `max` (excluded).  \n     * See also {@link Random.Decimal} for the static & non-deterministic counterpart.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const rng = Random.FromSeed(...);\n     *\n     * rng.decimal(2, 7); // e.g. 4.56789\n     * ```\n     *\n     * ---\n     *\n     * @param min The minimum value (included).\n     * @param max The maximum value (excluded).\n     *\n     * @returns A random decimal value.\n     */\n    public decimal(min: number, max: number): number;\n    public decimal(min?: number, max?: number): number\n    {\n        return Random._Decimal(this._next, min, max);\n    }\n\n    /**\n     * Picks a random valid index from a given array of elements.  \n     * See also {@link Random.Index} for the static & non-deterministic counterpart.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const rng = Random.FromSeed(...);\n     *\n     * rng.index([\"a\", \"b\", \"c\"]); // 0, 1, or 2\n     * ```\n     *\n     * ---\n     *\n     * @template T The type of the elements in the array.\n     *\n     * @param elements\n     * The array of elements to pick from.\n     *\n     * It must contain at least one element. Otherwise, a {@link ValueException} will be thrown.\n     *\n     * @returns A valid random index from the given array.\n     */\n    public index<T>(elements: readonly T[]): number\n    {\n        return Random._Index(this._next, elements);\n    }\n\n    /**\n     * Picks a random element from a given array of elements.  \n     * See also {@link Random.Choice} for the static & non-deterministic counterpart.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const rng = Random.FromSeed(...);\n     *\n     * rng.choice([\"a\", \"b\", \"c\"]); // \"a\", \"b\", or \"c\"\n     * ```\n     *\n     * ---\n     *\n     * @template T The type of the elements in the array.\n     *\n     * @param elements\n     * The array of elements to pick from.\n     *\n     * It must contain at least one element. Otherwise, a {@link ValueException} will be thrown.\n     *\n     * @returns A random element from the given array.\n     */\n    public choice<T>(elements: readonly T[]): T\n    {\n        return Random._Choice(this._next, elements);\n    }\n\n    /**\n     * Picks a random sample of elements from a given array without replacement.  \n     * See also {@link Random.Sample} for the static & non-deterministic counterpart.\n     *\n     * Uses the Fisher-Yates shuffle algorithm for uniform sampling,\n     * which is O(count) instead of O(n log n) for a full shuffle.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const rng = Random.FromSeed(...);\n     *\n     * rng.sample([1, 2, 3, 4, 5], 3); // e.g. [4, 1, 5]\n     * ```\n     *\n     * ---\n     *\n     * @template T The type of the elements in the array.\n     *\n     * @param elements\n     * The array of elements to sample from.\n     *\n     * It must contain at least one element. Otherwise, a {@link ValueException} will be thrown.\n     *\n     * @param count\n     * The number of elements to sample.\n     *\n     * It must be between `0` and `elements.length`. Otherwise, a {@link ValueException} will be thrown.\n     *\n     * @returns An array containing the randomly sampled elements.\n     */\n    public sample<T>(elements: readonly T[], count: number): T[];\n\n    /**\n     * Picks a weighted random sample of elements from a given array without replacement.  \n     * See also {@link Random.Sample} for the static & non-deterministic counterpart.\n     *\n     * Uses the Efraimidis-Spirakis algorithm for weighted sampling.\n     * Elements with higher weights have a higher probability of being selected.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const rng = Random.FromSeed(...);\n     *\n     * // Element \"a\" is 3x more likely to be picked than \"b\" or \"c\"\n     * rng.sample([\"a\", \"b\", \"c\"], 2, [3, 1, 1]); // e.g. [\"a\", \"c\"]\n     * ```\n     *\n     * ---\n     *\n     * @template T The type of the elements in the array.\n     *\n     * @param elements\n     * The array of elements to sample from.\n     *\n     * It must contain at least one element. Otherwise, a {@link ValueException} will be thrown.\n     *\n     * @param count\n     * The number of elements to sample.\n     *\n     * It must be between `0` and `elements.length`. Otherwise, a {@link ValueException} will be thrown.\n     *\n     * @param weights\n     * The weights associated with each element.\n     *\n     * It must have the same length as the elements array.\n     * All weights must be greater than zero. Otherwise, a {@link ValueException} will be thrown.\n     *\n     * @returns An array containing the randomly sampled elements.\n     */\n    public sample<T>(elements: readonly T[], count: number, weights: readonly number[]): T[];\n    public sample<T>(elements: readonly T[], count: number, weights?: readonly number[]): T[]\n    {\n        return Random._Sample(this._next, elements, count, weights);\n    }\n\n    /**\n     * Splits a total amount into a given number of randomly balanced integer parts that sum to the total.  \n     * See also {@link Random.Split} for the static & non-deterministic counterpart.\n     *\n     * Uses random cut-points to generate a uniform distribution of parts.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const rng = Random.FromSeed(...);\n     *\n     * rng.split(100, 3); // e.g. [28, 41, 31]\n     * rng.split(10, 4);  // e.g. [3, 1, 4, 2]\n     * ```\n     *\n     * ---\n     *\n     * @param total\n     * The total amount to split.\n     *\n     * It must be non-negative. Otherwise, a {@link ValueException} will be thrown.\n     *\n     * @param parts\n     * The number of parts to split the total into.\n     *\n     * It must be at least `1`. Otherwise, a {@link ValueException} will be thrown.\n     *\n     * @returns An array of integers that sum to the given total.\n     */\n    public split(total: number, parts: number): number[];\n\n    /**\n     * Splits an iterable of elements into a given number of randomly balanced groups.  \n     * See also {@link Random.Split} for the static & non-deterministic counterpart.\n     *\n     * The elements are distributed into groups whose sizes are\n     * determined by a random split of the total number of elements.\n     *\n     * ---\n     *\n     * @example\n     * ```ts\n     * const rng = Random.FromSeed(...);\n     *\n     * rng.split([1, 2, 3, 4, 5], 2); // e.g. [[1, 2], [3, 4, 5]]\n     * rng.split([1, 2, 3, 4, 5], 2); // e.g. [[1, 2, 3, 4], [5]]\n     * rng.split(\"abcdef\", 3);        // e.g. [[\"a\"], [\"b\", \"c\", \"d\"], [\"e\", \"f\"]]\n     * ```\n     *\n     * ---\n     *\n     * @template T The type of the elements in the iterable.\n     *\n     * @param elements\n     * The iterable of elements to split into groups.\n     *\n     * It must contain at least one element. Otherwise, a {@link ValueException} will be thrown.\n     *\n     * @param groups\n     * The number of groups to split the elements into.\n     *\n     * It must be between `1` and the number of elements.\n     * Otherwise, a {@link ValueException} will be thrown.\n     *\n     * @returns An array of arrays, each containing a subset of the original elements.\n     */\n    public split<T>(elements: Iterable<T>, groups: number): T[][];\n    public split<T>(totalOrElements: number | Iterable<T>, parts: number): number[] | T[][]\n    {\n        return Random._Split(this._next, totalOrElements, parts);\n    }\n\n    public readonly [Symbol.toStringTag]: string = \"Random\";\n}\n","import { SmartPromise } from \"../models/index.js\";\n\n/**\n * Returns a promise that resolves after a certain number of milliseconds.  \n * It can be used to pause or delay the execution of an asynchronous function.\n *\n * ---\n *\n * @example\n * ```ts\n * doSomething();\n * await delay(1_000);\n * doSomethingElse();\n * ```\n *\n * ---\n *\n * @param milliseconds The number of milliseconds to wait before resolving the promise.\n *\n * @returns A {@link SmartPromise} that resolves after the specified number of milliseconds.\n */\nexport function delay(milliseconds: number): SmartPromise<void>\n{\n    return new SmartPromise((resolve) => setTimeout(resolve, milliseconds));\n}\n\n/**\n * Returns a promise that resolves on the next animation frame.  \n * It can be used to synchronize operations with the browser's rendering cycle.\n *\n * ---\n *\n * @example\n * ```ts\n * const $el = document.querySelector(\".element\");\n *\n * $el.classList.add(\"animate\");\n * await nextAnimationFrame();\n * $el.style.opacity = \"1\";\n * ```\n *\n * ---\n *\n * @returns A {@link SmartPromise} that resolves on the next animation frame.\n */\nexport function nextAnimationFrame(): SmartPromise<void>\n{\n    return new SmartPromise((resolve) => requestAnimationFrame(() => resolve()));\n}\n\n/**\n * Returns a promise that resolves on the next microtask.  \n * It can be used to yield to the event loop in long-running operations to prevent blocking the main thread.\n *\n * ---\n *\n * @example\n * ```ts\n * for (let i = 0; i < 100_000_000; i += 1)\n * {\n *     doSomething(i);\n *\n *     if (i % 100 === 0) await yieldToEventLoop();\n * }\n * ```\n *\n * ---\n *\n * @returns A {@link SmartPromise} that resolves on the next microtask.\n */\nexport function yieldToEventLoop(): SmartPromise<void>\n{\n    return new SmartPromise((resolve) => setTimeout(resolve));\n}\n","import { SmartPromise } from \"../models/index.js\";\n\n/**\n * Appends a script element to the document body.  \n * It can be used to load external scripts dynamically.\n *\n * ---\n *\n * @example\n * ```ts\n * await loadScript(\"https://analytics.service/script.js?id=0123456789\");\n * ```\n *\n * ---\n *\n * @param scriptUrl The URL of the script to load.\n * @param scriptType The type of the script to load. Default is `\"text/javascript\"`.\n *\n * @returns\n * A {@link SmartPromise} that resolves when the script has been loaded successfully or rejects if an error occurs.\n */\nexport function loadScript(scriptUrl: string, scriptType = \"text/javascript\"): SmartPromise<void>\n{\n    return new SmartPromise<void>((resolve, reject) =>\n    {\n        const script = document.createElement(\"script\");\n\n        script.async = true;\n        script.defer = true;\n        script.src = scriptUrl;\n        script.type = scriptType;\n\n        script.onload = (evt) => resolve();\n        script.onerror = (reason) => reject(reason);\n\n        document.body.appendChild(script);\n    });\n}\n","import { RangeException, SmartIterator } from \"../models/index.js\";\n\n/**\n * An utility function that chains multiple iterables into a single one.\n *\n * Since the iterator is lazy, the chaining process will be\n * executed only once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one.  \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * for (const value of chain([1, 2, 3], [4, 5, 6], [7, 8, 9]))\n * {\n *     console.log(value); // 1, 2, 3, 4, 5, 6, 7, 8, 9\n * }\n * ```\n *\n * ---\n *\n * @template T The type of elements in the iterables.\n *\n * @param iterables The list of iterables to chain.\n *\n * @returns A new {@link SmartIterator} object that chains the iterables into a single one.\n */\nexport function chain<T>(...iterables: readonly Iterable<T>[]): SmartIterator<T>\n{\n    return new SmartIterator<T>(function* ()\n    {\n        for (const iterable of iterables)\n        {\n            for (const element of iterable) { yield element; }\n        }\n    });\n}\n\n/**\n * An utility function that counts the number of elements in an iterable.\n *\n * Also note that:\n * - If the iterable isn't an {@link Array}, it will be consumed entirely in the process.\n * - If the iterable is an infinite generator, the function will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * count([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); // 10\n * ```\n *\n * ---\n *\n * @template T The type of elements in the iterable.\n *\n * @param elements The iterable to count.\n *\n * @returns The number of elements in the iterable.\n */\nexport function count<T>(elements: Iterable<T>): number\n{\n    if (elements instanceof Array) { return elements.length; }\n\n    let _count = 0;\n    for (const _ of elements) { _count += 1; }\n\n    return _count;\n}\n\n/**\n * An utility function that enumerates the elements of an iterable.  \n * Each element is paired with its index in a new iterator.\n *\n * Since the iterator is lazy, the enumeration process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one.  \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * for (const [index, value] of enumerate([\"A\", \"M\", \"N\", \"Z\"]))\n * {\n *     console.log(`${index}: ${value}`); // \"0: A\", \"1: M\", \"2: N\", \"3: Z\"\n * }\n * ```\n *\n * ---\n *\n * @template T The type of elements in the iterable.\n *\n * @param elements The iterable to enumerate.\n *\n * @returns A new {@link SmartIterator} object containing the enumerated elements.\n */\nexport function enumerate<T>(elements: Iterable<T>): SmartIterator<[number, T]>\n{\n    return new SmartIterator<[number, T]>(function* (): Generator<[number, T]>\n    {\n        let index = 0;\n        for (const element of elements)\n        {\n            yield [index, element];\n\n            index += 1;\n        }\n    });\n}\n\n/**\n * An utility function that generates an iterator over a range of numbers.  \n * The values are included between `0` (included) and `end` (excluded).\n *\n * The default step between the numbers is `1`.\n *\n * ---\n *\n * @example\n * ```ts\n * for (const number of range(5))\n * {\n *    console.log(number); // 0, 1, 2, 3, 4\n * }\n * ```\n *\n * ---\n *\n * @param end\n * The end value (excluded).\n *\n * If the `end` value is negative, the step will be `-1` leading to generate the numbers in reverse order.\n *\n * @returns A {@link SmartIterator} object that generates the numbers in the range.\n */\nexport function range(end: number): SmartIterator<number>;\n\n/**\n * An utility function that generates an iterator over a range of numbers.  \n * The values are included between `start` (included) and `end` (excluded).\n *\n * The step between the numbers can be specified with a custom value. Default is `1`.\n *\n * ---\n *\n * @example\n * ```ts\n * for (const number of range(2, 7))\n * {\n *    console.log(number); // 2, 3, 4, 5, 6\n * }\n * ```\n *\n * ---\n *\n * @param start\n * The start value (included).\n *\n * If the `start` value is greater than the `end` value, the iterator will generate the numbers in reverse order.\n *\n * @param end\n * The end value (excluded).\n *\n * If the `end` value is less than the `start` value, the iterator will generate the numbers in reverse order.\n *\n * @param step\n * The step between the numbers. Default is `1`.\n *\n * Must be a positive number. Otherwise, a {@link RangeError} will be thrown.\n *\n * @returns A {@link SmartIterator} object that generates the numbers in the range.\n */\nexport function range(start: number, end: number, step?: number): SmartIterator<number>;\nexport function range(start: number, end?: number, step = 1): SmartIterator<number>\n{\n    if (step <= 0)\n    {\n        throw new RangeException(\n            \"Step must be always a positive number, even when generating numbers in reverse order.\"\n        );\n    }\n\n    if (end === undefined)\n    {\n        end = start;\n        start = 0;\n    }\n\n    if (start > end)\n    {\n        return new SmartIterator<number>(function* ()\n        {\n            for (let index = start; index > end; index -= step) { yield index; }\n        });\n    }\n\n    return new SmartIterator<number>(function* ()\n    {\n        for (let index = start; index < end; index += step) { yield index; }\n    });\n}\n\n/**\n * An utility function shuffles the elements of a given iterable.\n *\n * The function uses the {@link https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle|Fisher-Yates}\n * algorithm to shuffle the elements.\n *\n * Also note that:\n * - If the iterable is an {@link Array}, it won't be modified since the shuffling isn't done in-place.\n * - If the iterable isn't an {@link Array}, it will be consumed entirely in the process.\n * - If the iterable is an infinite generator, the function will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * shuffle([1, 2, 3, 4, 5]); // [3, 1, 5, 2, 4]\n * ```\n *\n * ---\n *\n * @template T The type of elements in the iterable.\n *\n * @param iterable The iterable to shuffle.\n *\n * @returns A new `Array` containing the shuffled elements of the given iterable.\n */\nexport function shuffle<T>(iterable: Iterable<T>): T[]\n{\n    const array = Array.from(iterable);\n\n    for (let index = array.length - 1; index > 0; index -= 1)\n    {\n        const jndex = Math.floor(Math.random() * (index + 1));\n\n        [array[index], array[jndex]] = [array[jndex], array[index]];\n    }\n\n    return array;\n}\n\n/**\n * An utility function that filters the elements of an iterable ensuring that they are all unique.\n *\n * ---\n *\n * @example\n * ```ts\n * for (const value of unique([1, 1, 2, 3, 2, 3, 4, 5, 5, 4]))\n * {\n *     console.log(value); // 1, 2, 3, 4, 5\n * }\n * ```\n *\n * ---\n *\n * @template T The type of elements in the iterable.\n *\n * @param elements The iterable to filter.\n *\n * @returns A {@link SmartIterator} object that iterates over the unique elements of the given iterable.\n */\nexport function unique<T>(elements: Iterable<T>): SmartIterator<T>\n{\n    return new SmartIterator<T>(function* ()\n    {\n        const values = new Set<T>();\n        for (const element of elements)\n        {\n            if (values.has(element)) { continue; }\n\n            values.add(element);\n\n            yield element;\n        }\n    });\n}\n\n/**\n * An utility function that zips two iterables into a single one.  \n * The resulting iterable will contain the elements of the two iterables paired together.\n *\n * The function will stop when one of the two iterables is exhausted.\n *\n * ---\n *\n * @example\n * ```ts\n * for (const [number, char] of zip([1, 2, 3, 4], [\"A\", \"M\", \"N\" \"Z\"]))\n * {\n *     console.log(`${number} - ${char}`); // \"1 - A\", \"2 - M\", \"3 - N\", \"4 - Z\"\n * }\n * ```\n *\n * ---\n *\n * @template T The type of elements in the first iterable.\n * @template U The type of elements in the second iterable.\n *\n * @param first The first iterable to zip.\n * @param second The second iterable to zip.\n *\n * @returns A {@link SmartIterator} object that iterates over the zipped elements of the two given iterables.\n */\nexport function zip<T, U>(first: Iterable<T>, second: Iterable<U>): SmartIterator<[T, U]>\n{\n    const firstIterator = first[Symbol.iterator]();\n    const secondIterator = second[Symbol.iterator]();\n\n    return new SmartIterator<[T, U]>(function* (): Generator<[T, U]>\n    {\n        while (true)\n        {\n            const firstResult = firstIterator.next();\n            const secondResult = secondIterator.next();\n\n            if ((firstResult.done) || (secondResult.done)) { break; }\n\n            yield [firstResult.value, secondResult.value];\n        }\n    });\n}\n","import { ValueException } from \"../models/exceptions/index.js\";\nimport { zip } from \"./iterator.js\";\n\n/**\n * Computes the average of a given list of values.  \n * The values can be weighted using an additional list of weights.\n *\n * ---\n *\n * @example\n * ```ts\n * average([1, 2, 3, 4, 5]);        // 3\n * average([6, 8.5, 4], [3, 2, 1]); // 6.5\n * ```\n *\n * ---\n *\n * @template T The type of the values in the list. It must be or extend a `number` object.\n *\n * @param values\n * The list of values to compute the average.\n *\n * It must contain at least one element. Otherwise, a {@link ValueException} will be thrown.\n *\n * @param weights\n * The list of weights to apply to the values.  \n * It should contain the same number of elements as the values list or\n * the smaller number of elements between the two lists will be considered.\n *\n * The sum of the weights must be greater than zero. Otherwise, a {@link ValueException} will be thrown.\n *\n * @returns The average of the specified values.\n */\nexport function average<T extends number>(values: Iterable<T>, weights?: Iterable<number>): number\n{\n    if (weights === undefined)\n    {\n        let _sum = 0;\n        let _index = 0;\n\n        for (const value of values)\n        {\n            _sum += value;\n            _index += 1;\n        }\n\n        if (_index === 0) { throw new ValueException(\"You must provide at least one value.\"); }\n\n        return _sum / _index;\n    }\n\n    let _sum = 0;\n    let _count = 0;\n    let _index = 0;\n\n    for (const [value, weight] of zip(values, weights))\n    {\n        if (weight <= 0)\n        {\n            throw new ValueException(`The weight for the value #${_index} must be greater than zero.`);\n        }\n\n        _sum += value * weight;\n        _count += weight;\n        _index += 1;\n    }\n\n    if (_index === 0) { throw new ValueException(\"You must provide at least one value and weight.\"); }\n    if (_count <= 0) { throw new ValueException(\"The sum of weights must be greater than zero.\"); }\n\n    return _sum / _count;\n}\n\n/**\n * Clamps a given value between a minimum and a maximum bound.\n *\n * ---\n *\n * @example\n * ```ts\n * clamp(5, 0, 10);  // 5\n * clamp(-3, 0, 10); // 0\n * clamp(15, 0, 10); // 10\n * ```\n *\n * ---\n *\n * @param value The value to clamp.\n * @param min The minimum bound.\n * @param max The maximum bound.\n *\n * @returns The clamped value between the specified bounds.\n */\nexport function clamp(value: number, min: number, max: number): number\n{\n    if (min > max)\n    {\n        throw new ValueException(\"The minimum bound must be less than or equal to the maximum bound.\");\n    }\n\n    if (value < min) { return min; }\n    if (value > max) { return max; }\n\n    return value;\n}\n\n/**\n * An utility function to compute the hash of a given string.\n *\n * The hash is computed using a simple variation of the\n * {@link http://www.cse.yorku.ca/~oz/hash.html#djb2|djb2} algorithm.  \n * However, the hash is garanteed to be a 32-bit signed integer.\n *\n * ---\n *\n * @example\n * ```ts\n * hash(\"Hello, world!\"); // -1880044555\n * hash(\"How are you?\");  // 1761539132\n * ```\n *\n * ---\n *\n * @param value The string to hash.\n *\n * @returns The hash of the specified string.\n */\nexport function hash(value: string): number\n{\n    let hashedValue = 0;\n    for (let index = 0; index < value.length; index += 1)\n    {\n        const char = value.charCodeAt(index);\n\n        hashedValue = ((hashedValue << 5) - hashedValue) + char;\n        hashedValue |= 0;\n    }\n\n    return hashedValue;\n}\n\n/**\n * Sums all the values of a given list.\n *\n * ---\n *\n * @example\n * ```ts\n * sum([1, 2, 3, 4, 5]); // 15\n * ```\n *\n * ---\n *\n * @template T The type of the values in the list. It must be or extend a `number` object.\n *\n * @param values The list of values to sum.\n *\n * @returns The sum of the specified values.\n */\nexport function sum<T extends number>(values: Iterable<T>): number\n{\n    let _sum = 0;\n    for (const value of values) { _sum += value; }\n\n    return _sum;\n}\n","/**\n * Capitalize the first letter of a string.\n *\n * ---\n *\n * @example\n * ```ts\n * capitalize('hello'); // 'Hello'\n * ```\n *\n * ---\n *\n * @param value The string to capitalize.\n *\n * @returns The capitalized string.\n */\nexport function capitalize(value: string): string\n{\n    return `${value.charAt(0).toUpperCase()}${value.slice(1)}`;\n}\n","export const VERSION = \"2.2.9\";\n\nexport type { Constructor, Interval, Timeout, ValueOf } from \"./core/types.js\";\n\nexport { isBrowser, isNode, isWorker } from \"./helpers.js\";\nexport {\n    AggregatedIterator,\n    AggregatedAsyncIterator,\n    ArrayView,\n    CallableObject,\n    CallbackChain,\n    Clock,\n    Countdown,\n    DeferredPromise,\n    EnvironmentException,\n    Exception,\n    FatalErrorException,\n    FileException,\n    FileExistsException,\n    FileNotFoundException,\n    GameLoop,\n    JSONStorage,\n    KeyException,\n    MapView,\n    NotImplementedException,\n    NetworkException,\n    PermissionException,\n    PromiseQueue,\n    Publisher,\n    RangeException,\n    ReducedIterator,\n    ReferenceException,\n    ResponseException,\n    RuntimeException,\n    SetView,\n    SmartIterator,\n    SmartAsyncIterator,\n    SmartPromise,\n    SwitchableCallback,\n    TimeoutException,\n    TimedPromise,\n    TypeException,\n    ValueException\n\n} from \"./models/index.js\";\n\nexport type {\n    AsyncGeneratorFunction,\n    AsyncIteratee,\n    AsyncIteratorLike,\n    AsyncKeyedIteratee,\n    AsyncKeyedReducer,\n    AsyncReducer,\n    Callback,\n    CallbackMap,\n    FulfilledHandler,\n    GeneratorFunction,\n    InternalsEventsMap,\n    Iteratee,\n    IteratorLike,\n    JSONArray,\n    JSONObject,\n    JSONValue,\n    KeyedIteratee,\n    KeyedReducer,\n    KeyedTypeGuardPredicate,\n    MaybeAsyncKeyedIteratee,\n    MaybeAsyncKeyedReducer,\n    MaybeAsyncGeneratorFunction,\n    MaybeAsyncIteratee,\n    MaybeAsyncIteratorLike,\n    MaybeAsyncReducer,\n    MaybePromise,\n    PromiseExecutor,\n    PromiseRejecter,\n    PromiseResolver,\n    Publishable,\n    ReadonlyMapView,\n    ReadonlySetView,\n    Reducer,\n    RejectedHandler,\n    Subscribable,\n    TypeGuardPredicate,\n    WildcardEventsMap\n\n} from \"./models/types.js\";\n\nexport {\n    average,\n    clamp,\n    capitalize,\n    chain,\n    count,\n    Curve,\n    delay,\n    dateDifference,\n    dateRange,\n    dateRound,\n    TimeUnit,\n    enumerate,\n    getWeek,\n    hash,\n    loadScript,\n    nextAnimationFrame,\n    Random,\n    range,\n    shuffle,\n    sum,\n    unique,\n    WeekDay,\n    yieldToEventLoop,\n    zip\n\n} from \"./utils/index.js\";\n"],"mappings":"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"}