import { chai, equals, iterableEquality, subsetEquality, JestExtend, JestChaiExpect, JestAsymmetricMatchers, GLOBAL_EXPECT, ASYMMETRIC_MATCHERS_OBJECT, getState, setState, addCustomEqualityTesters, customMatchers } from '@vitest/expect';
import { getCurrentTest } from '@vitest/runner';
import { g as getWorkerState, i as isChildProcess, w as waitForImportsToResolve, r as resetModules } from './utils.DvEY5TfP.js';
import { getSafeTimers, delay } from '@vitest/utils/timers';
import { getNames } from '@vitest/runner/utils';
import { stripSnapshotIndentation, addSerializer, SnapshotClient } from '@vitest/snapshot';
import '@vitest/utils/error';
import { assertTypes, createSimpleStackTrace } from '@vitest/utils/helpers';
import { fn, spyOn, restoreAllMocks, resetAllMocks, clearAllMocks, isMockFunction } from '@vitest/spy';
import '@vitest/utils/offset';
import { parseSingleStack } from '@vitest/utils/source-map';
import { c as commonjsGlobal } from './_commonjsHelpers.D26ty3Ew.js';
import { R as RealDate, r as resetDate, m as mockDate } from './date.Bq6ZW5rf.js';

// these matchers are not supported because they don't make sense with poll
const unsupported = [
	"matchSnapshot",
	"toMatchSnapshot",
	"toMatchInlineSnapshot",
	"toThrowErrorMatchingSnapshot",
	"toThrowErrorMatchingInlineSnapshot",
	"throws",
	"Throw",
	"throw",
	"toThrow",
	"toThrowError"
];
/**
* Attaches a `cause` property to the error if missing, copies the stack trace from the source, and throws.
*
* @param error - The error to throw
* @param source - Error to copy the stack trace from
*
* @throws Always throws the provided error with an amended stack trace
*/
function throwWithCause(error, source) {
	if (error.cause == null) error.cause = /* @__PURE__ */ new Error("Matcher did not succeed in time.");
	throw copyStackTrace$1(error, source);
}
function createExpectPoll(expect) {
	return function poll(fn, options = {}) {
		const defaults = getWorkerState().config.expect?.poll ?? {};
		const { interval = defaults.interval ?? 50, timeout = defaults.timeout ?? 1e3, message } = options;
		// @ts-expect-error private poll access
		const assertion = expect(null, message).withContext({ poll: true });
		fn = fn.bind(assertion);
		const test = chai.util.flag(assertion, "vitest-test");
		if (!test) throw new Error("expect.poll() must be called inside a test");
		const proxy = new Proxy(assertion, { get(target, key, receiver) {
			const assertionFunction = Reflect.get(target, key, receiver);
			if (typeof assertionFunction !== "function") return assertionFunction instanceof chai.Assertion ? proxy : assertionFunction;
			if (key === "assert") return assertionFunction;
			if (typeof key === "string" && unsupported.includes(key)) throw new SyntaxError(`expect.poll() is not supported in combination with .${key}(). Use vi.waitFor() if your assertion condition is unstable.`);
			return function(...args) {
				const STACK_TRACE_ERROR = /* @__PURE__ */ new Error("STACK_TRACE_ERROR");
				const promise = async () => {
					const { setTimeout, clearTimeout } = getSafeTimers();
					let executionPhase = "fn";
					let hasTimedOut = false;
					const timerId = setTimeout(() => {
						hasTimedOut = true;
					}, timeout);
					chai.util.flag(assertion, "_name", key);
					try {
						while (true) {
							const isLastAttempt = hasTimedOut;
							if (isLastAttempt) chai.util.flag(assertion, "_isLastPollAttempt", true);
							try {
								executionPhase = "fn";
								const obj = await fn();
								chai.util.flag(assertion, "object", obj);
								executionPhase = "assertion";
								return await assertionFunction.call(assertion, ...args);
							} catch (err) {
								if (isLastAttempt || executionPhase === "assertion" && chai.util.flag(assertion, "_poll.assert_once")) throwWithCause(err, STACK_TRACE_ERROR);
								await delay(interval, setTimeout);
							}
						}
					} finally {
						clearTimeout(timerId);
					}
				};
				let awaited = false;
				test.onFinished ??= [];
				test.onFinished.push(() => {
					if (!awaited) {
						const negated = chai.util.flag(assertion, "negate") ? "not." : "";
						const assertionString = `expect.${chai.util.flag(assertion, "_poll.element") ? "element(locator)" : "poll(assertion)"}.${negated}${String(key)}()`;
						throw copyStackTrace$1(/* @__PURE__ */ new Error(`${assertionString} was not awaited. This assertion is asynchronous and must be awaited; otherwise, it is not executed to avoid unhandled rejections:\n\nawait ${assertionString}\n`), STACK_TRACE_ERROR);
					}
				});
				let resultPromise;
				// only .then is enough to check awaited, but we type this as `Promise<void>` in global types
				// so let's follow it
				return {
					then(onFulfilled, onRejected) {
						awaited = true;
						return (resultPromise ||= promise()).then(onFulfilled, onRejected);
					},
					catch(onRejected) {
						return (resultPromise ||= promise()).catch(onRejected);
					},
					finally(onFinally) {
						return (resultPromise ||= promise()).finally(onFinally);
					},
					[Symbol.toStringTag]: "Promise"
				};
			};
		} });
		return proxy;
	};
}
function copyStackTrace$1(target, source) {
	if (source.stack !== void 0) target.stack = source.stack.replace(source.message, target.message);
	return target;
}

function createAssertionMessage(util, assertion, hasArgs) {
	const not = util.flag(assertion, "negate") ? "not." : "";
	const name = `${util.flag(assertion, "_name")}(${"expected" })`;
	const promiseName = util.flag(assertion, "promise");
	return `expect(actual)${promiseName ? `.${promiseName}` : ""}.${not}${name}`;
}
function recordAsyncExpect(_test, promise, assertion, error) {
	const test = _test;
	// record promise for test, that resolves before test ends
	if (test && promise instanceof Promise) {
		// if promise is explicitly awaited, remove it from the list
		promise = promise.finally(() => {
			if (!test.promises) return;
			const index = test.promises.indexOf(promise);
			if (index !== -1) test.promises.splice(index, 1);
		});
		// record promise
		if (!test.promises) test.promises = [];
		test.promises.push(promise);
		let resolved = false;
		test.onFinished ??= [];
		test.onFinished.push(() => {
			if (!resolved) {
				const stack = (globalThis.__vitest_worker__?.onFilterStackTrace || ((s) => s || ""))(error.stack);
				console.warn([
					`Promise returned by \`${assertion}\` was not awaited. `,
					"Vitest currently auto-awaits hanging assertions at the end of the test, but this will cause the test to fail in Vitest 3. ",
					"Please remember to await the assertion.\n",
					stack
				].join(""));
			}
		});
		return {
			then(onFulfilled, onRejected) {
				resolved = true;
				return promise.then(onFulfilled, onRejected);
			},
			catch(onRejected) {
				return promise.catch(onRejected);
			},
			finally(onFinally) {
				return promise.finally(onFinally);
			},
			[Symbol.toStringTag]: "Promise"
		};
	}
	return promise;
}

let _client;
function getSnapshotClient() {
	if (!_client) _client = new SnapshotClient({ isEqual: (received, expected) => {
		return equals(received, expected, [iterableEquality, subsetEquality]);
	} });
	return _client;
}
function getError(expected, promise) {
	if (typeof expected !== "function") {
		if (!promise) throw new Error(`expected must be a function, received ${typeof expected}`);
		// when "promised", it receives thrown error
		return expected;
	}
	try {
		expected();
	} catch (e) {
		return e;
	}
	throw new Error("snapshot function didn't throw");
}
function getTestNames(test) {
	return {
		filepath: test.file.filepath,
		name: getNames(test).slice(1).join(" > "),
		testId: test.id
	};
}
const SnapshotPlugin = (chai, utils) => {
	function getTest(assertionName, obj) {
		const test = utils.flag(obj, "vitest-test");
		if (!test) throw new Error(`'${assertionName}' cannot be used without test context`);
		return test;
	}
	for (const key of ["matchSnapshot", "toMatchSnapshot"]) utils.addMethod(chai.Assertion.prototype, key, function(properties, message) {
		utils.flag(this, "_name", key);
		if (utils.flag(this, "negate")) throw new Error(`${key} cannot be used with "not"`);
		const expected = utils.flag(this, "object");
		const test = getTest(key, this);
		if (typeof properties === "string" && typeof message === "undefined") {
			message = properties;
			properties = void 0;
		}
		const errorMessage = utils.flag(this, "message");
		getSnapshotClient().assert({
			received: expected,
			message,
			isInline: false,
			properties,
			errorMessage,
			...getTestNames(test)
		});
	});
	utils.addMethod(chai.Assertion.prototype, "toMatchFileSnapshot", function(file, message) {
		utils.flag(this, "_name", "toMatchFileSnapshot");
		if (utils.flag(this, "negate")) throw new Error("toMatchFileSnapshot cannot be used with \"not\"");
		const error = /* @__PURE__ */ new Error("resolves");
		const expected = utils.flag(this, "object");
		const test = getTest("toMatchFileSnapshot", this);
		const errorMessage = utils.flag(this, "message");
		return recordAsyncExpect(test, getSnapshotClient().assertRaw({
			received: expected,
			message,
			isInline: false,
			rawSnapshot: { file },
			errorMessage,
			...getTestNames(test)
		}), createAssertionMessage(utils, this), error);
	});
	utils.addMethod(chai.Assertion.prototype, "toMatchInlineSnapshot", function __INLINE_SNAPSHOT__(properties, inlineSnapshot, message) {
		utils.flag(this, "_name", "toMatchInlineSnapshot");
		if (utils.flag(this, "negate")) throw new Error("toMatchInlineSnapshot cannot be used with \"not\"");
		const test = getTest("toMatchInlineSnapshot", this);
		if (test.each || test.suite?.each) throw new Error("InlineSnapshot cannot be used inside of test.each or describe.each");
		const expected = utils.flag(this, "object");
		const error = utils.flag(this, "error");
		if (typeof properties === "string") {
			message = inlineSnapshot;
			inlineSnapshot = properties;
			properties = void 0;
		}
		if (inlineSnapshot) inlineSnapshot = stripSnapshotIndentation(inlineSnapshot);
		const errorMessage = utils.flag(this, "message");
		getSnapshotClient().assert({
			received: expected,
			message,
			isInline: true,
			properties,
			inlineSnapshot,
			error,
			errorMessage,
			...getTestNames(test)
		});
	});
	utils.addMethod(chai.Assertion.prototype, "toThrowErrorMatchingSnapshot", function(message) {
		utils.flag(this, "_name", "toThrowErrorMatchingSnapshot");
		if (utils.flag(this, "negate")) throw new Error("toThrowErrorMatchingSnapshot cannot be used with \"not\"");
		const expected = utils.flag(this, "object");
		const test = getTest("toThrowErrorMatchingSnapshot", this);
		const promise = utils.flag(this, "promise");
		const errorMessage = utils.flag(this, "message");
		getSnapshotClient().assert({
			received: getError(expected, promise),
			message,
			errorMessage,
			...getTestNames(test)
		});
	});
	utils.addMethod(chai.Assertion.prototype, "toThrowErrorMatchingInlineSnapshot", function __INLINE_SNAPSHOT__(inlineSnapshot, message) {
		if (utils.flag(this, "negate")) throw new Error("toThrowErrorMatchingInlineSnapshot cannot be used with \"not\"");
		const test = getTest("toThrowErrorMatchingInlineSnapshot", this);
		if (test.each || test.suite?.each) throw new Error("InlineSnapshot cannot be used inside of test.each or describe.each");
		const expected = utils.flag(this, "object");
		const error = utils.flag(this, "error");
		const promise = utils.flag(this, "promise");
		const errorMessage = utils.flag(this, "message");
		if (inlineSnapshot) inlineSnapshot = stripSnapshotIndentation(inlineSnapshot);
		getSnapshotClient().assert({
			received: getError(expected, promise),
			message,
			inlineSnapshot,
			isInline: true,
			error,
			errorMessage,
			...getTestNames(test)
		});
	});
	utils.addMethod(chai.expect, "addSnapshotSerializer", addSerializer);
};

chai.use(JestExtend);
chai.use(JestChaiExpect);
chai.use(SnapshotPlugin);
chai.use(JestAsymmetricMatchers);

function createExpect(test) {
	const expect = ((value, message) => {
		const { assertionCalls } = getState(expect);
		setState({ assertionCalls: assertionCalls + 1 }, expect);
		const assert = chai.expect(value, message);
		const _test = test || getCurrentTest();
		if (_test)
 // @ts-expect-error internal
		return assert.withTest(_test);
		else return assert;
	});
	Object.assign(expect, chai.expect);
	Object.assign(expect, globalThis[ASYMMETRIC_MATCHERS_OBJECT]);
	expect.getState = () => getState(expect);
	expect.setState = (state) => setState(state, expect);
	// @ts-expect-error global is not typed
	const globalState = getState(globalThis[GLOBAL_EXPECT]) || {};
	setState({
		...globalState,
		assertionCalls: 0,
		isExpectingAssertions: false,
		isExpectingAssertionsError: null,
		expectedAssertionsNumber: null,
		expectedAssertionsNumberErrorGen: null,
		get testPath() {
			return getWorkerState().filepath;
		},
		currentTestName: test ? test.fullTestName ?? "" : globalState.currentTestName
	}, expect);
	expect.assert = chai.assert;
	// @ts-expect-error untyped
	expect.extend = (matchers) => chai.expect.extend(expect, matchers);
	expect.addEqualityTesters = (customTesters) => addCustomEqualityTesters(customTesters);
	expect.soft = (...args) => {
		// @ts-expect-error private soft access
		return expect(...args).withContext({ soft: true });
	};
	expect.poll = createExpectPoll(expect);
	expect.unreachable = (message) => {
		chai.assert.fail(`expected${message ? ` "${message}" ` : " "}not to be reached`);
	};
	function assertions(expected) {
		const errorGen = () => /* @__PURE__ */ new Error(`expected number of assertions to be ${expected}, but got ${expect.getState().assertionCalls}`);
		if (Error.captureStackTrace) Error.captureStackTrace(errorGen(), assertions);
		expect.setState({
			expectedAssertionsNumber: expected,
			expectedAssertionsNumberErrorGen: errorGen
		});
	}
	function hasAssertions() {
		const error = /* @__PURE__ */ new Error("expected any number of assertion, but got none");
		if (Error.captureStackTrace) Error.captureStackTrace(error, hasAssertions);
		expect.setState({
			isExpectingAssertions: true,
			isExpectingAssertionsError: error
		});
	}
	chai.util.addMethod(expect, "assertions", assertions);
	chai.util.addMethod(expect, "hasAssertions", hasAssertions);
	expect.extend(customMatchers);
	return expect;
}
const globalExpect = createExpect();
Object.defineProperty(globalThis, GLOBAL_EXPECT, {
	value: globalExpect,
	writable: true,
	configurable: true
});
const assert = chai.assert;
const should = chai.should;

/**
* Gives access to injected context provided from the main thread.
* This usually returns a value provided by `globalSetup` or an external library.
*/
function inject(key) {
	return getWorkerState().providedContext[key];
}

var fakeTimersSrc = {};

var global;
var hasRequiredGlobal;

function requireGlobal () {
	if (hasRequiredGlobal) return global;
	hasRequiredGlobal = 1;

	/**
	 * A reference to the global object
	 * @type {object} globalObject
	 */
	var globalObject;

	/* istanbul ignore else */
	if (typeof commonjsGlobal !== "undefined") {
	    // Node
	    globalObject = commonjsGlobal;
	} else if (typeof window !== "undefined") {
	    // Browser
	    globalObject = window;
	} else {
	    // WebWorker
	    globalObject = self;
	}

	global = globalObject;
	return global;
}

var throwsOnProto_1;
var hasRequiredThrowsOnProto;

function requireThrowsOnProto () {
	if (hasRequiredThrowsOnProto) return throwsOnProto_1;
	hasRequiredThrowsOnProto = 1;

	/**
	 * Is true when the environment causes an error to be thrown for accessing the
	 * __proto__ property.
	 * This is necessary in order to support `node --disable-proto=throw`.
	 *
	 * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto
	 * @type {boolean}
	 */
	let throwsOnProto;
	try {
	    const object = {};
	    // eslint-disable-next-line no-proto, no-unused-expressions
	    object.__proto__;
	    throwsOnProto = false;
	} catch (_) {
	    // This branch is covered when tests are run with `--disable-proto=throw`,
	    // however we can test both branches at the same time, so this is ignored
	    /* istanbul ignore next */
	    throwsOnProto = true;
	}

	throwsOnProto_1 = throwsOnProto;
	return throwsOnProto_1;
}

var copyPrototypeMethods;
var hasRequiredCopyPrototypeMethods;

function requireCopyPrototypeMethods () {
	if (hasRequiredCopyPrototypeMethods) return copyPrototypeMethods;
	hasRequiredCopyPrototypeMethods = 1;

	var call = Function.call;
	var throwsOnProto = requireThrowsOnProto();

	var disallowedProperties = [
	    // ignore size because it throws from Map
	    "size",
	    "caller",
	    "callee",
	    "arguments",
	];

	// This branch is covered when tests are run with `--disable-proto=throw`,
	// however we can test both branches at the same time, so this is ignored
	/* istanbul ignore next */
	if (throwsOnProto) {
	    disallowedProperties.push("__proto__");
	}

	copyPrototypeMethods = function copyPrototypeMethods(prototype) {
	    // eslint-disable-next-line @sinonjs/no-prototype-methods/no-prototype-methods
	    return Object.getOwnPropertyNames(prototype).reduce(function (
	        result,
	        name
	    ) {
	        if (disallowedProperties.includes(name)) {
	            return result;
	        }

	        if (typeof prototype[name] !== "function") {
	            return result;
	        }

	        result[name] = call.bind(prototype[name]);

	        return result;
	    },
	    Object.create(null));
	};
	return copyPrototypeMethods;
}

var array;
var hasRequiredArray;

function requireArray () {
	if (hasRequiredArray) return array;
	hasRequiredArray = 1;

	var copyPrototype = requireCopyPrototypeMethods();

	array = copyPrototype(Array.prototype);
	return array;
}

var calledInOrder_1;
var hasRequiredCalledInOrder;

function requireCalledInOrder () {
	if (hasRequiredCalledInOrder) return calledInOrder_1;
	hasRequiredCalledInOrder = 1;

	var every = requireArray().every;

	/**
	 * @private
	 */
	function hasCallsLeft(callMap, spy) {
	    if (callMap[spy.id] === undefined) {
	        callMap[spy.id] = 0;
	    }

	    return callMap[spy.id] < spy.callCount;
	}

	/**
	 * @private
	 */
	function checkAdjacentCalls(callMap, spy, index, spies) {
	    var calledBeforeNext = true;

	    if (index !== spies.length - 1) {
	        calledBeforeNext = spy.calledBefore(spies[index + 1]);
	    }

	    if (hasCallsLeft(callMap, spy) && calledBeforeNext) {
	        callMap[spy.id] += 1;
	        return true;
	    }

	    return false;
	}

	/**
	 * A Sinon proxy object (fake, spy, stub)
	 * @typedef {object} SinonProxy
	 * @property {Function} calledBefore - A method that determines if this proxy was called before another one
	 * @property {string} id - Some id
	 * @property {number} callCount - Number of times this proxy has been called
	 */

	/**
	 * Returns true when the spies have been called in the order they were supplied in
	 * @param  {SinonProxy[] | SinonProxy} spies An array of proxies, or several proxies as arguments
	 * @returns {boolean} true when spies are called in order, false otherwise
	 */
	function calledInOrder(spies) {
	    var callMap = {};
	    // eslint-disable-next-line no-underscore-dangle
	    var _spies = arguments.length > 1 ? arguments : spies;

	    return every(_spies, checkAdjacentCalls.bind(null, callMap));
	}

	calledInOrder_1 = calledInOrder;
	return calledInOrder_1;
}

var className_1;
var hasRequiredClassName;

function requireClassName () {
	if (hasRequiredClassName) return className_1;
	hasRequiredClassName = 1;

	/**
	 * Returns a display name for a value from a constructor
	 * @param  {object} value A value to examine
	 * @returns {(string|null)} A string or null
	 */
	function className(value) {
	    const name = value.constructor && value.constructor.name;
	    return name || null;
	}

	className_1 = className;
	return className_1;
}

var deprecated = {};

/* eslint-disable no-console */

var hasRequiredDeprecated;

function requireDeprecated () {
	if (hasRequiredDeprecated) return deprecated;
	hasRequiredDeprecated = 1;
	(function (exports$1) {

		/**
		 * Returns a function that will invoke the supplied function and print a
		 * deprecation warning to the console each time it is called.
		 * @param  {Function} func
		 * @param  {string} msg
		 * @returns {Function}
		 */
		exports$1.wrap = function (func, msg) {
		    var wrapped = function () {
		        exports$1.printWarning(msg);
		        return func.apply(this, arguments);
		    };
		    if (func.prototype) {
		        wrapped.prototype = func.prototype;
		    }
		    return wrapped;
		};

		/**
		 * Returns a string which can be supplied to `wrap()` to notify the user that a
		 * particular part of the sinon API has been deprecated.
		 * @param  {string} packageName
		 * @param  {string} funcName
		 * @returns {string}
		 */
		exports$1.defaultMsg = function (packageName, funcName) {
		    return `${packageName}.${funcName} is deprecated and will be removed from the public API in a future version of ${packageName}.`;
		};

		/**
		 * Prints a warning on the console, when it exists
		 * @param  {string} msg
		 * @returns {undefined}
		 */
		exports$1.printWarning = function (msg) {
		    /* istanbul ignore next */
		    if (typeof process === "object" && process.emitWarning) {
		        // Emit Warnings in Node
		        process.emitWarning(msg);
		    } else if (console.info) {
		        console.info(msg);
		    } else {
		        console.log(msg);
		    }
		}; 
	} (deprecated));
	return deprecated;
}

var every;
var hasRequiredEvery;

function requireEvery () {
	if (hasRequiredEvery) return every;
	hasRequiredEvery = 1;

	/**
	 * Returns true when fn returns true for all members of obj.
	 * This is an every implementation that works for all iterables
	 * @param  {object}   obj
	 * @param  {Function} fn
	 * @returns {boolean}
	 */
	every = function every(obj, fn) {
	    var pass = true;

	    try {
	        // eslint-disable-next-line @sinonjs/no-prototype-methods/no-prototype-methods
	        obj.forEach(function () {
	            if (!fn.apply(this, arguments)) {
	                // Throwing an error is the only way to break `forEach`
	                throw new Error();
	            }
	        });
	    } catch (e) {
	        pass = false;
	    }

	    return pass;
	};
	return every;
}

var functionName;
var hasRequiredFunctionName;

function requireFunctionName () {
	if (hasRequiredFunctionName) return functionName;
	hasRequiredFunctionName = 1;

	/**
	 * Returns a display name for a function
	 * @param  {Function} func
	 * @returns {string}
	 */
	functionName = function functionName(func) {
	    if (!func) {
	        return "";
	    }

	    try {
	        return (
	            func.displayName ||
	            func.name ||
	            // Use function decomposition as a last resort to get function
	            // name. Does not rely on function decomposition to work - if it
	            // doesn't debugging will be slightly less informative
	            // (i.e. toString will say 'spy' rather than 'myFunc').
	            (String(func).match(/function ([^\s(]+)/) || [])[1]
	        );
	    } catch (e) {
	        // Stringify may fail and we might get an exception, as a last-last
	        // resort fall back to empty string.
	        return "";
	    }
	};
	return functionName;
}

var orderByFirstCall_1;
var hasRequiredOrderByFirstCall;

function requireOrderByFirstCall () {
	if (hasRequiredOrderByFirstCall) return orderByFirstCall_1;
	hasRequiredOrderByFirstCall = 1;

	var sort = requireArray().sort;
	var slice = requireArray().slice;

	/**
	 * @private
	 */
	function comparator(a, b) {
	    // uuid, won't ever be equal
	    var aCall = a.getCall(0);
	    var bCall = b.getCall(0);
	    var aId = (aCall && aCall.callId) || -1;
	    var bId = (bCall && bCall.callId) || -1;

	    return aId < bId ? -1 : 1;
	}

	/**
	 * A Sinon proxy object (fake, spy, stub)
	 * @typedef {object} SinonProxy
	 * @property {Function} getCall - A method that can return the first call
	 */

	/**
	 * Sorts an array of SinonProxy instances (fake, spy, stub) by their first call
	 * @param  {SinonProxy[] | SinonProxy} spies
	 * @returns {SinonProxy[]}
	 */
	function orderByFirstCall(spies) {
	    return sort(slice(spies), comparator);
	}

	orderByFirstCall_1 = orderByFirstCall;
	return orderByFirstCall_1;
}

var _function;
var hasRequired_function;

function require_function () {
	if (hasRequired_function) return _function;
	hasRequired_function = 1;

	var copyPrototype = requireCopyPrototypeMethods();

	_function = copyPrototype(Function.prototype);
	return _function;
}

var map;
var hasRequiredMap;

function requireMap () {
	if (hasRequiredMap) return map;
	hasRequiredMap = 1;

	var copyPrototype = requireCopyPrototypeMethods();

	map = copyPrototype(Map.prototype);
	return map;
}

var object;
var hasRequiredObject;

function requireObject () {
	if (hasRequiredObject) return object;
	hasRequiredObject = 1;

	var copyPrototype = requireCopyPrototypeMethods();

	object = copyPrototype(Object.prototype);
	return object;
}

var set;
var hasRequiredSet;

function requireSet () {
	if (hasRequiredSet) return set;
	hasRequiredSet = 1;

	var copyPrototype = requireCopyPrototypeMethods();

	set = copyPrototype(Set.prototype);
	return set;
}

var string;
var hasRequiredString;

function requireString () {
	if (hasRequiredString) return string;
	hasRequiredString = 1;

	var copyPrototype = requireCopyPrototypeMethods();

	string = copyPrototype(String.prototype);
	return string;
}

var prototypes;
var hasRequiredPrototypes;

function requirePrototypes () {
	if (hasRequiredPrototypes) return prototypes;
	hasRequiredPrototypes = 1;

	prototypes = {
	    array: requireArray(),
	    function: require_function(),
	    map: requireMap(),
	    object: requireObject(),
	    set: requireSet(),
	    string: requireString(),
	};
	return prototypes;
}

var typeDetect$1 = {exports: {}};

var typeDetect = typeDetect$1.exports;

var hasRequiredTypeDetect;

function requireTypeDetect () {
	if (hasRequiredTypeDetect) return typeDetect$1.exports;
	hasRequiredTypeDetect = 1;
	(function (module, exports$1) {
		(function (global, factory) {
			module.exports = factory() ;
		}(typeDetect, (function () {
		/* !
		 * type-detect
		 * Copyright(c) 2013 jake luer <jake@alogicalparadox.com>
		 * MIT Licensed
		 */
		var promiseExists = typeof Promise === 'function';

		/* eslint-disable no-undef */
		var globalObject = typeof self === 'object' ? self : commonjsGlobal; // eslint-disable-line id-blacklist

		var symbolExists = typeof Symbol !== 'undefined';
		var mapExists = typeof Map !== 'undefined';
		var setExists = typeof Set !== 'undefined';
		var weakMapExists = typeof WeakMap !== 'undefined';
		var weakSetExists = typeof WeakSet !== 'undefined';
		var dataViewExists = typeof DataView !== 'undefined';
		var symbolIteratorExists = symbolExists && typeof Symbol.iterator !== 'undefined';
		var symbolToStringTagExists = symbolExists && typeof Symbol.toStringTag !== 'undefined';
		var setEntriesExists = setExists && typeof Set.prototype.entries === 'function';
		var mapEntriesExists = mapExists && typeof Map.prototype.entries === 'function';
		var setIteratorPrototype = setEntriesExists && Object.getPrototypeOf(new Set().entries());
		var mapIteratorPrototype = mapEntriesExists && Object.getPrototypeOf(new Map().entries());
		var arrayIteratorExists = symbolIteratorExists && typeof Array.prototype[Symbol.iterator] === 'function';
		var arrayIteratorPrototype = arrayIteratorExists && Object.getPrototypeOf([][Symbol.iterator]());
		var stringIteratorExists = symbolIteratorExists && typeof String.prototype[Symbol.iterator] === 'function';
		var stringIteratorPrototype = stringIteratorExists && Object.getPrototypeOf(''[Symbol.iterator]());
		var toStringLeftSliceLength = 8;
		var toStringRightSliceLength = -1;
		/**
		 * ### typeOf (obj)
		 *
		 * Uses `Object.prototype.toString` to determine the type of an object,
		 * normalising behaviour across engine versions & well optimised.
		 *
		 * @param {Mixed} object
		 * @return {String} object type
		 * @api public
		 */
		function typeDetect(obj) {
		  /* ! Speed optimisation
		   * Pre:
		   *   string literal     x 3,039,035 ops/sec ±1.62% (78 runs sampled)
		   *   boolean literal    x 1,424,138 ops/sec ±4.54% (75 runs sampled)
		   *   number literal     x 1,653,153 ops/sec ±1.91% (82 runs sampled)
		   *   undefined          x 9,978,660 ops/sec ±1.92% (75 runs sampled)
		   *   function           x 2,556,769 ops/sec ±1.73% (77 runs sampled)
		   * Post:
		   *   string literal     x 38,564,796 ops/sec ±1.15% (79 runs sampled)
		   *   boolean literal    x 31,148,940 ops/sec ±1.10% (79 runs sampled)
		   *   number literal     x 32,679,330 ops/sec ±1.90% (78 runs sampled)
		   *   undefined          x 32,363,368 ops/sec ±1.07% (82 runs sampled)
		   *   function           x 31,296,870 ops/sec ±0.96% (83 runs sampled)
		   */
		  var typeofObj = typeof obj;
		  if (typeofObj !== 'object') {
		    return typeofObj;
		  }

		  /* ! Speed optimisation
		   * Pre:
		   *   null               x 28,645,765 ops/sec ±1.17% (82 runs sampled)
		   * Post:
		   *   null               x 36,428,962 ops/sec ±1.37% (84 runs sampled)
		   */
		  if (obj === null) {
		    return 'null';
		  }

		  /* ! Spec Conformance
		   * Test: `Object.prototype.toString.call(window)``
		   *  - Node === "[object global]"
		   *  - Chrome === "[object global]"
		   *  - Firefox === "[object Window]"
		   *  - PhantomJS === "[object Window]"
		   *  - Safari === "[object Window]"
		   *  - IE 11 === "[object Window]"
		   *  - IE Edge === "[object Window]"
		   * Test: `Object.prototype.toString.call(this)``
		   *  - Chrome Worker === "[object global]"
		   *  - Firefox Worker === "[object DedicatedWorkerGlobalScope]"
		   *  - Safari Worker === "[object DedicatedWorkerGlobalScope]"
		   *  - IE 11 Worker === "[object WorkerGlobalScope]"
		   *  - IE Edge Worker === "[object WorkerGlobalScope]"
		   */
		  if (obj === globalObject) {
		    return 'global';
		  }

		  /* ! Speed optimisation
		   * Pre:
		   *   array literal      x 2,888,352 ops/sec ±0.67% (82 runs sampled)
		   * Post:
		   *   array literal      x 22,479,650 ops/sec ±0.96% (81 runs sampled)
		   */
		  if (
		    Array.isArray(obj) &&
		    (symbolToStringTagExists === false || !(Symbol.toStringTag in obj))
		  ) {
		    return 'Array';
		  }

		  // Not caching existence of `window` and related properties due to potential
		  // for `window` to be unset before tests in quasi-browser environments.
		  if (typeof window === 'object' && window !== null) {
		    /* ! Spec Conformance
		     * (https://html.spec.whatwg.org/multipage/browsers.html#location)
		     * WhatWG HTML$7.7.3 - The `Location` interface
		     * Test: `Object.prototype.toString.call(window.location)``
		     *  - IE <=11 === "[object Object]"
		     *  - IE Edge <=13 === "[object Object]"
		     */
		    if (typeof window.location === 'object' && obj === window.location) {
		      return 'Location';
		    }

		    /* ! Spec Conformance
		     * (https://html.spec.whatwg.org/#document)
		     * WhatWG HTML$3.1.1 - The `Document` object
		     * Note: Most browsers currently adher to the W3C DOM Level 2 spec
		     *       (https://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-26809268)
		     *       which suggests that browsers should use HTMLTableCellElement for
		     *       both TD and TH elements. WhatWG separates these.
		     *       WhatWG HTML states:
		     *         > For historical reasons, Window objects must also have a
		     *         > writable, configurable, non-enumerable property named
		     *         > HTMLDocument whose value is the Document interface object.
		     * Test: `Object.prototype.toString.call(document)``
		     *  - Chrome === "[object HTMLDocument]"
		     *  - Firefox === "[object HTMLDocument]"
		     *  - Safari === "[object HTMLDocument]"
		     *  - IE <=10 === "[object Document]"
		     *  - IE 11 === "[object HTMLDocument]"
		     *  - IE Edge <=13 === "[object HTMLDocument]"
		     */
		    if (typeof window.document === 'object' && obj === window.document) {
		      return 'Document';
		    }

		    if (typeof window.navigator === 'object') {
		      /* ! Spec Conformance
		       * (https://html.spec.whatwg.org/multipage/webappapis.html#mimetypearray)
		       * WhatWG HTML$8.6.1.5 - Plugins - Interface MimeTypeArray
		       * Test: `Object.prototype.toString.call(navigator.mimeTypes)``
		       *  - IE <=10 === "[object MSMimeTypesCollection]"
		       */
		      if (typeof window.navigator.mimeTypes === 'object' &&
		          obj === window.navigator.mimeTypes) {
		        return 'MimeTypeArray';
		      }

		      /* ! Spec Conformance
		       * (https://html.spec.whatwg.org/multipage/webappapis.html#pluginarray)
		       * WhatWG HTML$8.6.1.5 - Plugins - Interface PluginArray
		       * Test: `Object.prototype.toString.call(navigator.plugins)``
		       *  - IE <=10 === "[object MSPluginsCollection]"
		       */
		      if (typeof window.navigator.plugins === 'object' &&
		          obj === window.navigator.plugins) {
		        return 'PluginArray';
		      }
		    }

		    if ((typeof window.HTMLElement === 'function' ||
		        typeof window.HTMLElement === 'object') &&
		        obj instanceof window.HTMLElement) {
		      /* ! Spec Conformance
		      * (https://html.spec.whatwg.org/multipage/webappapis.html#pluginarray)
		      * WhatWG HTML$4.4.4 - The `blockquote` element - Interface `HTMLQuoteElement`
		      * Test: `Object.prototype.toString.call(document.createElement('blockquote'))``
		      *  - IE <=10 === "[object HTMLBlockElement]"
		      */
		      if (obj.tagName === 'BLOCKQUOTE') {
		        return 'HTMLQuoteElement';
		      }

		      /* ! Spec Conformance
		       * (https://html.spec.whatwg.org/#htmltabledatacellelement)
		       * WhatWG HTML$4.9.9 - The `td` element - Interface `HTMLTableDataCellElement`
		       * Note: Most browsers currently adher to the W3C DOM Level 2 spec
		       *       (https://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-82915075)
		       *       which suggests that browsers should use HTMLTableCellElement for
		       *       both TD and TH elements. WhatWG separates these.
		       * Test: Object.prototype.toString.call(document.createElement('td'))
		       *  - Chrome === "[object HTMLTableCellElement]"
		       *  - Firefox === "[object HTMLTableCellElement]"
		       *  - Safari === "[object HTMLTableCellElement]"
		       */
		      if (obj.tagName === 'TD') {
		        return 'HTMLTableDataCellElement';
		      }

		      /* ! Spec Conformance
		       * (https://html.spec.whatwg.org/#htmltableheadercellelement)
		       * WhatWG HTML$4.9.9 - The `td` element - Interface `HTMLTableHeaderCellElement`
		       * Note: Most browsers currently adher to the W3C DOM Level 2 spec
		       *       (https://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-82915075)
		       *       which suggests that browsers should use HTMLTableCellElement for
		       *       both TD and TH elements. WhatWG separates these.
		       * Test: Object.prototype.toString.call(document.createElement('th'))
		       *  - Chrome === "[object HTMLTableCellElement]"
		       *  - Firefox === "[object HTMLTableCellElement]"
		       *  - Safari === "[object HTMLTableCellElement]"
		       */
		      if (obj.tagName === 'TH') {
		        return 'HTMLTableHeaderCellElement';
		      }
		    }
		  }

		  /* ! Speed optimisation
		  * Pre:
		  *   Float64Array       x 625,644 ops/sec ±1.58% (80 runs sampled)
		  *   Float32Array       x 1,279,852 ops/sec ±2.91% (77 runs sampled)
		  *   Uint32Array        x 1,178,185 ops/sec ±1.95% (83 runs sampled)
		  *   Uint16Array        x 1,008,380 ops/sec ±2.25% (80 runs sampled)
		  *   Uint8Array         x 1,128,040 ops/sec ±2.11% (81 runs sampled)
		  *   Int32Array         x 1,170,119 ops/sec ±2.88% (80 runs sampled)
		  *   Int16Array         x 1,176,348 ops/sec ±5.79% (86 runs sampled)
		  *   Int8Array          x 1,058,707 ops/sec ±4.94% (77 runs sampled)
		  *   Uint8ClampedArray  x 1,110,633 ops/sec ±4.20% (80 runs sampled)
		  * Post:
		  *   Float64Array       x 7,105,671 ops/sec ±13.47% (64 runs sampled)
		  *   Float32Array       x 5,887,912 ops/sec ±1.46% (82 runs sampled)
		  *   Uint32Array        x 6,491,661 ops/sec ±1.76% (79 runs sampled)
		  *   Uint16Array        x 6,559,795 ops/sec ±1.67% (82 runs sampled)
		  *   Uint8Array         x 6,463,966 ops/sec ±1.43% (85 runs sampled)
		  *   Int32Array         x 5,641,841 ops/sec ±3.49% (81 runs sampled)
		  *   Int16Array         x 6,583,511 ops/sec ±1.98% (80 runs sampled)
		  *   Int8Array          x 6,606,078 ops/sec ±1.74% (81 runs sampled)
		  *   Uint8ClampedArray  x 6,602,224 ops/sec ±1.77% (83 runs sampled)
		  */
		  var stringTag = (symbolToStringTagExists && obj[Symbol.toStringTag]);
		  if (typeof stringTag === 'string') {
		    return stringTag;
		  }

		  var objPrototype = Object.getPrototypeOf(obj);
		  /* ! Speed optimisation
		  * Pre:
		  *   regex literal      x 1,772,385 ops/sec ±1.85% (77 runs sampled)
		  *   regex constructor  x 2,143,634 ops/sec ±2.46% (78 runs sampled)
		  * Post:
		  *   regex literal      x 3,928,009 ops/sec ±0.65% (78 runs sampled)
		  *   regex constructor  x 3,931,108 ops/sec ±0.58% (84 runs sampled)
		  */
		  if (objPrototype === RegExp.prototype) {
		    return 'RegExp';
		  }

		  /* ! Speed optimisation
		  * Pre:
		  *   date               x 2,130,074 ops/sec ±4.42% (68 runs sampled)
		  * Post:
		  *   date               x 3,953,779 ops/sec ±1.35% (77 runs sampled)
		  */
		  if (objPrototype === Date.prototype) {
		    return 'Date';
		  }

		  /* ! Spec Conformance
		   * (http://www.ecma-international.org/ecma-262/6.0/index.html#sec-promise.prototype-@@tostringtag)
		   * ES6$25.4.5.4 - Promise.prototype[@@toStringTag] should be "Promise":
		   * Test: `Object.prototype.toString.call(Promise.resolve())``
		   *  - Chrome <=47 === "[object Object]"
		   *  - Edge <=20 === "[object Object]"
		   *  - Firefox 29-Latest === "[object Promise]"
		   *  - Safari 7.1-Latest === "[object Promise]"
		   */
		  if (promiseExists && objPrototype === Promise.prototype) {
		    return 'Promise';
		  }

		  /* ! Speed optimisation
		  * Pre:
		  *   set                x 2,222,186 ops/sec ±1.31% (82 runs sampled)
		  * Post:
		  *   set                x 4,545,879 ops/sec ±1.13% (83 runs sampled)
		  */
		  if (setExists && objPrototype === Set.prototype) {
		    return 'Set';
		  }

		  /* ! Speed optimisation
		  * Pre:
		  *   map                x 2,396,842 ops/sec ±1.59% (81 runs sampled)
		  * Post:
		  *   map                x 4,183,945 ops/sec ±6.59% (82 runs sampled)
		  */
		  if (mapExists && objPrototype === Map.prototype) {
		    return 'Map';
		  }

		  /* ! Speed optimisation
		  * Pre:
		  *   weakset            x 1,323,220 ops/sec ±2.17% (76 runs sampled)
		  * Post:
		  *   weakset            x 4,237,510 ops/sec ±2.01% (77 runs sampled)
		  */
		  if (weakSetExists && objPrototype === WeakSet.prototype) {
		    return 'WeakSet';
		  }

		  /* ! Speed optimisation
		  * Pre:
		  *   weakmap            x 1,500,260 ops/sec ±2.02% (78 runs sampled)
		  * Post:
		  *   weakmap            x 3,881,384 ops/sec ±1.45% (82 runs sampled)
		  */
		  if (weakMapExists && objPrototype === WeakMap.prototype) {
		    return 'WeakMap';
		  }

		  /* ! Spec Conformance
		   * (http://www.ecma-international.org/ecma-262/6.0/index.html#sec-dataview.prototype-@@tostringtag)
		   * ES6$24.2.4.21 - DataView.prototype[@@toStringTag] should be "DataView":
		   * Test: `Object.prototype.toString.call(new DataView(new ArrayBuffer(1)))``
		   *  - Edge <=13 === "[object Object]"
		   */
		  if (dataViewExists && objPrototype === DataView.prototype) {
		    return 'DataView';
		  }

		  /* ! Spec Conformance
		   * (http://www.ecma-international.org/ecma-262/6.0/index.html#sec-%mapiteratorprototype%-@@tostringtag)
		   * ES6$23.1.5.2.2 - %MapIteratorPrototype%[@@toStringTag] should be "Map Iterator":
		   * Test: `Object.prototype.toString.call(new Map().entries())``
		   *  - Edge <=13 === "[object Object]"
		   */
		  if (mapExists && objPrototype === mapIteratorPrototype) {
		    return 'Map Iterator';
		  }

		  /* ! Spec Conformance
		   * (http://www.ecma-international.org/ecma-262/6.0/index.html#sec-%setiteratorprototype%-@@tostringtag)
		   * ES6$23.2.5.2.2 - %SetIteratorPrototype%[@@toStringTag] should be "Set Iterator":
		   * Test: `Object.prototype.toString.call(new Set().entries())``
		   *  - Edge <=13 === "[object Object]"
		   */
		  if (setExists && objPrototype === setIteratorPrototype) {
		    return 'Set Iterator';
		  }

		  /* ! Spec Conformance
		   * (http://www.ecma-international.org/ecma-262/6.0/index.html#sec-%arrayiteratorprototype%-@@tostringtag)
		   * ES6$22.1.5.2.2 - %ArrayIteratorPrototype%[@@toStringTag] should be "Array Iterator":
		   * Test: `Object.prototype.toString.call([][Symbol.iterator]())``
		   *  - Edge <=13 === "[object Object]"
		   */
		  if (arrayIteratorExists && objPrototype === arrayIteratorPrototype) {
		    return 'Array Iterator';
		  }

		  /* ! Spec Conformance
		   * (http://www.ecma-international.org/ecma-262/6.0/index.html#sec-%stringiteratorprototype%-@@tostringtag)
		   * ES6$21.1.5.2.2 - %StringIteratorPrototype%[@@toStringTag] should be "String Iterator":
		   * Test: `Object.prototype.toString.call(''[Symbol.iterator]())``
		   *  - Edge <=13 === "[object Object]"
		   */
		  if (stringIteratorExists && objPrototype === stringIteratorPrototype) {
		    return 'String Iterator';
		  }

		  /* ! Speed optimisation
		  * Pre:
		  *   object from null   x 2,424,320 ops/sec ±1.67% (76 runs sampled)
		  * Post:
		  *   object from null   x 5,838,000 ops/sec ±0.99% (84 runs sampled)
		  */
		  if (objPrototype === null) {
		    return 'Object';
		  }

		  return Object
		    .prototype
		    .toString
		    .call(obj)
		    .slice(toStringLeftSliceLength, toStringRightSliceLength);
		}

		return typeDetect;

		}))); 
	} (typeDetect$1));
	return typeDetect$1.exports;
}

var typeOf;
var hasRequiredTypeOf;

function requireTypeOf () {
	if (hasRequiredTypeOf) return typeOf;
	hasRequiredTypeOf = 1;

	var type = requireTypeDetect();

	/**
	 * Returns the lower-case result of running type from type-detect on the value
	 * @param  {*} value
	 * @returns {string}
	 */
	typeOf = function typeOf(value) {
	    return type(value).toLowerCase();
	};
	return typeOf;
}

var valueToString_1;
var hasRequiredValueToString;

function requireValueToString () {
	if (hasRequiredValueToString) return valueToString_1;
	hasRequiredValueToString = 1;

	/**
	 * Returns a string representation of the value
	 * @param  {*} value
	 * @returns {string}
	 */
	function valueToString(value) {
	    if (value && value.toString) {
	        // eslint-disable-next-line @sinonjs/no-prototype-methods/no-prototype-methods
	        return value.toString();
	    }
	    return String(value);
	}

	valueToString_1 = valueToString;
	return valueToString_1;
}

var lib;
var hasRequiredLib;

function requireLib () {
	if (hasRequiredLib) return lib;
	hasRequiredLib = 1;

	lib = {
	    global: requireGlobal(),
	    calledInOrder: requireCalledInOrder(),
	    className: requireClassName(),
	    deprecated: requireDeprecated(),
	    every: requireEvery(),
	    functionName: requireFunctionName(),
	    orderByFirstCall: requireOrderByFirstCall(),
	    prototypes: requirePrototypes(),
	    typeOf: requireTypeOf(),
	    valueToString: requireValueToString(),
	};
	return lib;
}

var hasRequiredFakeTimersSrc;

function requireFakeTimersSrc () {
	if (hasRequiredFakeTimersSrc) return fakeTimersSrc;
	hasRequiredFakeTimersSrc = 1;

	const globalObject = requireLib().global;
	let timersModule, timersPromisesModule;
	if (typeof __vitest_required__ !== 'undefined') {
	    try {
	        timersModule = __vitest_required__.timers;
	    } catch (e) {
	        // ignored
	    }
	    try {
	        timersPromisesModule = __vitest_required__.timersPromises;
	    } catch (e) {
	        // ignored
	    }
	}

	/**
	 * @typedef {object} IdleDeadline
	 * @property {boolean} didTimeout - whether or not the callback was called before reaching the optional timeout
	 * @property {function():number} timeRemaining - a floating-point value providing an estimate of the number of milliseconds remaining in the current idle period
	 */

	/**
	 * Queues a function to be called during a browser's idle periods
	 * @callback RequestIdleCallback
	 * @param {function(IdleDeadline)} callback
	 * @param {{timeout: number}} options - an options object
	 * @returns {number} the id
	 */

	/**
	 * @callback NextTick
	 * @param {VoidVarArgsFunc} callback - the callback to run
	 * @param {...*} args - optional arguments to call the callback with
	 * @returns {void}
	 */

	/**
	 * @callback SetImmediate
	 * @param {VoidVarArgsFunc} callback - the callback to run
	 * @param {...*} args - optional arguments to call the callback with
	 * @returns {NodeImmediate}
	 */

	/**
	 * @callback VoidVarArgsFunc
	 * @param {...*} callback - the callback to run
	 * @returns {void}
	 */

	/**
	 * @typedef RequestAnimationFrame
	 * @property {function(number):void} requestAnimationFrame
	 * @returns {number} - the id
	 */

	/**
	 * @typedef Performance
	 * @property {function(): number} now
	 */

	/* eslint-disable jsdoc/require-property-description */
	/**
	 * @typedef {object} Clock
	 * @property {number} now - the current time
	 * @property {Date} Date - the Date constructor
	 * @property {number} loopLimit - the maximum number of timers before assuming an infinite loop
	 * @property {RequestIdleCallback} requestIdleCallback
	 * @property {function(number):void} cancelIdleCallback
	 * @property {setTimeout} setTimeout
	 * @property {clearTimeout} clearTimeout
	 * @property {NextTick} nextTick
	 * @property {queueMicrotask} queueMicrotask
	 * @property {setInterval} setInterval
	 * @property {clearInterval} clearInterval
	 * @property {SetImmediate} setImmediate
	 * @property {function(NodeImmediate):void} clearImmediate
	 * @property {function():number} countTimers
	 * @property {RequestAnimationFrame} requestAnimationFrame
	 * @property {function(number):void} cancelAnimationFrame
	 * @property {function():void} runMicrotasks
	 * @property {function(string | number): number} tick
	 * @property {function(string | number): Promise<number>} tickAsync
	 * @property {function(): number} next
	 * @property {function(): Promise<number>} nextAsync
	 * @property {function(): number} runAll
	 * @property {function(): number} runToFrame
	 * @property {function(): Promise<number>} runAllAsync
	 * @property {function(): number} runToLast
	 * @property {function(): Promise<number>} runToLastAsync
	 * @property {function(): void} reset
	 * @property {function(number | Date): void} setSystemTime
	 * @property {function(number): void} jump
	 * @property {Performance} performance
	 * @property {function(number[]): number[]} hrtime - process.hrtime (legacy)
	 * @property {function(): void} uninstall Uninstall the clock.
	 * @property {Function[]} methods - the methods that are faked
	 * @property {boolean} [shouldClearNativeTimers] inherited from config
	 * @property {{methodName:string, original:any}[] | undefined} timersModuleMethods
	 * @property {{methodName:string, original:any}[] | undefined} timersPromisesModuleMethods
	 * @property {Map<function(): void, AbortSignal>} abortListenerMap
	 */
	/* eslint-enable jsdoc/require-property-description */

	/**
	 * Configuration object for the `install` method.
	 * @typedef {object} Config
	 * @property {number|Date} [now] a number (in milliseconds) or a Date object (default epoch)
	 * @property {string[]} [toFake] names of the methods that should be faked.
	 * @property {number} [loopLimit] the maximum number of timers that will be run when calling runAll()
	 * @property {boolean} [shouldAdvanceTime] tells FakeTimers to increment mocked time automatically (default false)
	 * @property {number} [advanceTimeDelta] increment mocked time every <<advanceTimeDelta>> ms (default: 20ms)
	 * @property {boolean} [shouldClearNativeTimers] forwards clear timer calls to native functions if they are not fakes (default: false)
	 * @property {boolean} [ignoreMissingTimers] default is false, meaning asking to fake timers that are not present will throw an error
	 */

	/* eslint-disable jsdoc/require-property-description */
	/**
	 * The internal structure to describe a scheduled fake timer
	 * @typedef {object} Timer
	 * @property {Function} func
	 * @property {*[]} args
	 * @property {number} delay
	 * @property {number} callAt
	 * @property {number} createdAt
	 * @property {boolean} immediate
	 * @property {number} id
	 * @property {Error} [error]
	 */

	/**
	 * A Node timer
	 * @typedef {object} NodeImmediate
	 * @property {function(): boolean} hasRef
	 * @property {function(): NodeImmediate} ref
	 * @property {function(): NodeImmediate} unref
	 */
	/* eslint-enable jsdoc/require-property-description */

	/* eslint-disable complexity */

	/**
	 * Mocks available features in the specified global namespace.
	 * @param {*} _global Namespace to mock (e.g. `window`)
	 * @returns {FakeTimers}
	 */
	function withGlobal(_global) {
	    const maxTimeout = Math.pow(2, 31) - 1; //see https://heycam.github.io/webidl/#abstract-opdef-converttoint
	    const idCounterStart = 1e12; // arbitrarily large number to avoid collisions with native timer IDs
	    const NOOP = function () {
	        return undefined;
	    };
	    const NOOP_ARRAY = function () {
	        return [];
	    };
	    const isPresent = {};
	    let timeoutResult,
	        addTimerReturnsObject = false;

	    if (_global.setTimeout) {
	        isPresent.setTimeout = true;
	        timeoutResult = _global.setTimeout(NOOP, 0);
	        addTimerReturnsObject = typeof timeoutResult === "object";
	    }
	    isPresent.clearTimeout = Boolean(_global.clearTimeout);
	    isPresent.setInterval = Boolean(_global.setInterval);
	    isPresent.clearInterval = Boolean(_global.clearInterval);
	    isPresent.hrtime =
	        _global.process && typeof _global.process.hrtime === "function";
	    isPresent.hrtimeBigint =
	        isPresent.hrtime && typeof _global.process.hrtime.bigint === "function";
	    isPresent.nextTick =
	        _global.process && typeof _global.process.nextTick === "function";
	    const utilPromisify = _global.process && _global.__vitest_required__ && _global.__vitest_required__.util.promisify;
	    isPresent.performance =
	        _global.performance && typeof _global.performance.now === "function";
	    const hasPerformancePrototype =
	        _global.Performance &&
	        (typeof _global.Performance).match(/^(function|object)$/);
	    const hasPerformanceConstructorPrototype =
	        _global.performance &&
	        _global.performance.constructor &&
	        _global.performance.constructor.prototype;
	    isPresent.queueMicrotask = _global.hasOwnProperty("queueMicrotask");
	    isPresent.requestAnimationFrame =
	        _global.requestAnimationFrame &&
	        typeof _global.requestAnimationFrame === "function";
	    isPresent.cancelAnimationFrame =
	        _global.cancelAnimationFrame &&
	        typeof _global.cancelAnimationFrame === "function";
	    isPresent.requestIdleCallback =
	        _global.requestIdleCallback &&
	        typeof _global.requestIdleCallback === "function";
	    isPresent.cancelIdleCallbackPresent =
	        _global.cancelIdleCallback &&
	        typeof _global.cancelIdleCallback === "function";
	    isPresent.setImmediate =
	        _global.setImmediate && typeof _global.setImmediate === "function";
	    isPresent.clearImmediate =
	        _global.clearImmediate && typeof _global.clearImmediate === "function";
	    isPresent.Intl = _global.Intl && typeof _global.Intl === "object";

	    if (_global.clearTimeout) {
	        _global.clearTimeout(timeoutResult);
	    }

	    const NativeDate = _global.Date;
	    const NativeIntl = isPresent.Intl
	        ? Object.defineProperties(
	              Object.create(null),
	              Object.getOwnPropertyDescriptors(_global.Intl),
	          )
	        : undefined;
	    let uniqueTimerId = idCounterStart;

	    if (NativeDate === undefined) {
	        throw new Error(
	            "The global scope doesn't have a `Date` object" +
	                " (see https://github.com/sinonjs/sinon/issues/1852#issuecomment-419622780)",
	        );
	    }
	    isPresent.Date = true;

	    /**
	     * The PerformanceEntry object encapsulates a single performance metric
	     * that is part of the browser's performance timeline.
	     *
	     * This is an object returned by the `mark` and `measure` methods on the Performance prototype
	     */
	    class FakePerformanceEntry {
	        constructor(name, entryType, startTime, duration) {
	            this.name = name;
	            this.entryType = entryType;
	            this.startTime = startTime;
	            this.duration = duration;
	        }

	        toJSON() {
	            return JSON.stringify({ ...this });
	        }
	    }

	    /**
	     * @param {number} num
	     * @returns {boolean}
	     */
	    function isNumberFinite(num) {
	        if (Number.isFinite) {
	            return Number.isFinite(num);
	        }

	        return isFinite(num);
	    }

	    let isNearInfiniteLimit = false;

	    /**
	     * @param {Clock} clock
	     * @param {number} i
	     */
	    function checkIsNearInfiniteLimit(clock, i) {
	        if (clock.loopLimit && i === clock.loopLimit - 1) {
	            isNearInfiniteLimit = true;
	        }
	    }

	    /**
	     *
	     */
	    function resetIsNearInfiniteLimit() {
	        isNearInfiniteLimit = false;
	    }

	    /**
	     * Parse strings like "01:10:00" (meaning 1 hour, 10 minutes, 0 seconds) into
	     * number of milliseconds. This is used to support human-readable strings passed
	     * to clock.tick()
	     * @param {string} str
	     * @returns {number}
	     */
	    function parseTime(str) {
	        if (!str) {
	            return 0;
	        }

	        const strings = str.split(":");
	        const l = strings.length;
	        let i = l;
	        let ms = 0;
	        let parsed;

	        if (l > 3 || !/^(\d\d:){0,2}\d\d?$/.test(str)) {
	            throw new Error(
	                "tick only understands numbers, 'm:s' and 'h:m:s'. Each part must be two digits",
	            );
	        }

	        while (i--) {
	            parsed = parseInt(strings[i], 10);

	            if (parsed >= 60) {
	                throw new Error(`Invalid time ${str}`);
	            }

	            ms += parsed * Math.pow(60, l - i - 1);
	        }

	        return ms * 1000;
	    }

	    /**
	     * Get the decimal part of the millisecond value as nanoseconds
	     * @param {number} msFloat the number of milliseconds
	     * @returns {number} an integer number of nanoseconds in the range [0,1e6)
	     *
	     * Example: nanoRemainer(123.456789) -> 456789
	     */
	    function nanoRemainder(msFloat) {
	        const modulo = 1e6;
	        const remainder = (msFloat * 1e6) % modulo;
	        const positiveRemainder =
	            remainder < 0 ? remainder + modulo : remainder;

	        return Math.floor(positiveRemainder);
	    }

	    /**
	     * Used to grok the `now` parameter to createClock.
	     * @param {Date|number} epoch the system time
	     * @returns {number}
	     */
	    function getEpoch(epoch) {
	        if (!epoch) {
	            return 0;
	        }
	        if (typeof epoch.getTime === "function") {
	            return epoch.getTime();
	        }
	        if (typeof epoch === "number") {
	            return epoch;
	        }
	        throw new TypeError("now should be milliseconds since UNIX epoch");
	    }

	    /**
	     * @param {number} from
	     * @param {number} to
	     * @param {Timer} timer
	     * @returns {boolean}
	     */
	    function inRange(from, to, timer) {
	        return timer && timer.callAt >= from && timer.callAt <= to;
	    }

	    /**
	     * @param {Clock} clock
	     * @param {Timer} job
	     */
	    function getInfiniteLoopError(clock, job) {
	        const infiniteLoopError = new Error(
	            `Aborting after running ${clock.loopLimit} timers, assuming an infinite loop!`,
	        );

	        if (!job.error) {
	            return infiniteLoopError;
	        }

	        // pattern never matched in Node
	        const computedTargetPattern = /target\.*[<|(|[].*?[>|\]|)]\s*/;
	        let clockMethodPattern = new RegExp(
	            String(Object.keys(clock).join("|")),
	        );

	        if (addTimerReturnsObject) {
	            // node.js environment
	            clockMethodPattern = new RegExp(
	                `\\s+at (Object\\.)?(?:${Object.keys(clock).join("|")})\\s+`,
	            );
	        }

	        let matchedLineIndex = -1;
	        job.error.stack.split("\n").some(function (line, i) {
	            // If we've matched a computed target line (e.g. setTimeout) then we
	            // don't need to look any further. Return true to stop iterating.
	            const matchedComputedTarget = line.match(computedTargetPattern);
	            /* istanbul ignore if */
	            if (matchedComputedTarget) {
	                matchedLineIndex = i;
	                return true;
	            }

	            // If we've matched a clock method line, then there may still be
	            // others further down the trace. Return false to keep iterating.
	            const matchedClockMethod = line.match(clockMethodPattern);
	            if (matchedClockMethod) {
	                matchedLineIndex = i;
	                return false;
	            }

	            // If we haven't matched anything on this line, but we matched
	            // previously and set the matched line index, then we can stop.
	            // If we haven't matched previously, then we should keep iterating.
	            return matchedLineIndex >= 0;
	        });

	        const stack = `${infiniteLoopError}\n${job.type || "Microtask"} - ${
	            job.func.name || "anonymous"
	        }\n${job.error.stack
	            .split("\n")
	            .slice(matchedLineIndex + 1)
	            .join("\n")}`;

	        try {
	            Object.defineProperty(infiniteLoopError, "stack", {
	                value: stack,
	            });
	        } catch (e) {
	            // noop
	        }

	        return infiniteLoopError;
	    }

	    //eslint-disable-next-line jsdoc/require-jsdoc
	    function createDate() {
	        class ClockDate extends NativeDate {
	            /**
	             * @param {number} year
	             * @param {number} month
	             * @param {number} date
	             * @param {number} hour
	             * @param {number} minute
	             * @param {number} second
	             * @param {number} ms
	             * @returns void
	             */
	            // eslint-disable-next-line no-unused-vars
	            constructor(year, month, date, hour, minute, second, ms) {
	                // Defensive and verbose to avoid potential harm in passing
	                // explicit undefined when user does not pass argument
	                if (arguments.length === 0) {
	                    super(ClockDate.clock.now);
	                } else {
	                    super(...arguments);
	                }

	                // ensures identity checks using the constructor prop still works
	                // this should have no other functional effect
	                Object.defineProperty(this, "constructor", {
	                    value: NativeDate,
	                    enumerable: false,
	                });
	            }

	            static [Symbol.hasInstance](instance) {
	                return instance instanceof NativeDate;
	            }
	        }

	        ClockDate.isFake = true;

	        if (NativeDate.now) {
	            ClockDate.now = function now() {
	                return ClockDate.clock.now;
	            };
	        }

	        if (NativeDate.toSource) {
	            ClockDate.toSource = function toSource() {
	                return NativeDate.toSource();
	            };
	        }

	        ClockDate.toString = function toString() {
	            return NativeDate.toString();
	        };

	        // noinspection UnnecessaryLocalVariableJS
	        /**
	         * A normal Class constructor cannot be called without `new`, but Date can, so we need
	         * to wrap it in a Proxy in order to ensure this functionality of Date is kept intact
	         * @type {ClockDate}
	         */
	        const ClockDateProxy = new Proxy(ClockDate, {
	            // handler for [[Call]] invocations (i.e. not using `new`)
	            apply() {
	                // the Date constructor called as a function, ref Ecma-262 Edition 5.1, section 15.9.2.
	                // This remains so in the 10th edition of 2019 as well.
	                if (this instanceof ClockDate) {
	                    throw new TypeError(
	                        "A Proxy should only capture `new` calls with the `construct` handler. This is not supposed to be possible, so check the logic.",
	                    );
	                }

	                return new NativeDate(ClockDate.clock.now).toString();
	            },
	        });

	        return ClockDateProxy;
	    }

	    /**
	     * Mirror Intl by default on our fake implementation
	     *
	     * Most of the properties are the original native ones,
	     * but we need to take control of those that have a
	     * dependency on the current clock.
	     * @returns {object} the partly fake Intl implementation
	     */
	    function createIntl() {
	        const ClockIntl = {};
	        /*
	         * All properties of Intl are non-enumerable, so we need
	         * to do a bit of work to get them out.
	         */
	        Object.getOwnPropertyNames(NativeIntl).forEach(
	            (property) => (ClockIntl[property] = NativeIntl[property]),
	        );

	        ClockIntl.DateTimeFormat = function (...args) {
	            const realFormatter = new NativeIntl.DateTimeFormat(...args);
	            const formatter = {};

	            ["formatRange", "formatRangeToParts", "resolvedOptions"].forEach(
	                (method) => {
	                    formatter[method] =
	                        realFormatter[method].bind(realFormatter);
	                },
	            );

	            ["format", "formatToParts"].forEach((method) => {
	                formatter[method] = function (date) {
	                    return realFormatter[method](date || ClockIntl.clock.now);
	                };
	            });

	            return formatter;
	        };

	        ClockIntl.DateTimeFormat.prototype = Object.create(
	            NativeIntl.DateTimeFormat.prototype,
	        );

	        ClockIntl.DateTimeFormat.supportedLocalesOf =
	            NativeIntl.DateTimeFormat.supportedLocalesOf;

	        return ClockIntl;
	    }

	    //eslint-disable-next-line jsdoc/require-jsdoc
	    function enqueueJob(clock, job) {
	        // enqueues a microtick-deferred task - ecma262/#sec-enqueuejob
	        if (!clock.jobs) {
	            clock.jobs = [];
	        }
	        clock.jobs.push(job);
	    }

	    //eslint-disable-next-line jsdoc/require-jsdoc
	    function runJobs(clock) {
	        // runs all microtick-deferred tasks - ecma262/#sec-runjobs
	        if (!clock.jobs) {
	            return;
	        }
	        for (let i = 0; i < clock.jobs.length; i++) {
	            const job = clock.jobs[i];
	            job.func.apply(null, job.args);

	            checkIsNearInfiniteLimit(clock, i);
	            if (clock.loopLimit && i > clock.loopLimit) {
	                throw getInfiniteLoopError(clock, job);
	            }
	        }
	        resetIsNearInfiniteLimit();
	        clock.jobs = [];
	    }

	    /**
	     * @param {Clock} clock
	     * @param {Timer} timer
	     * @returns {number} id of the created timer
	     */
	    function addTimer(clock, timer) {
	        if (timer.func === undefined) {
	            throw new Error("Callback must be provided to timer calls");
	        }

	        if (addTimerReturnsObject) {
	            // Node.js environment
	            if (typeof timer.func !== "function") {
	                throw new TypeError(
	                    `[ERR_INVALID_CALLBACK]: Callback must be a function. Received ${
	                        timer.func
	                    } of type ${typeof timer.func}`,
	                );
	            }
	        }

	        if (isNearInfiniteLimit) {
	            timer.error = new Error();
	        }

	        timer.type = timer.immediate ? "Immediate" : "Timeout";

	        if (timer.hasOwnProperty("delay")) {
	            if (typeof timer.delay !== "number") {
	                timer.delay = parseInt(timer.delay, 10);
	            }

	            if (!isNumberFinite(timer.delay)) {
	                timer.delay = 0;
	            }
	            timer.delay = timer.delay > maxTimeout ? 1 : timer.delay;
	            timer.delay = Math.max(0, timer.delay);
	        }

	        if (timer.hasOwnProperty("interval")) {
	            timer.type = "Interval";
	            timer.interval = timer.interval > maxTimeout ? 1 : timer.interval;
	        }

	        if (timer.hasOwnProperty("animation")) {
	            timer.type = "AnimationFrame";
	            timer.animation = true;
	        }

	        if (timer.hasOwnProperty("idleCallback")) {
	            timer.type = "IdleCallback";
	            timer.idleCallback = true;
	        }

	        if (!clock.timers) {
	            clock.timers = {};
	        }

	        timer.id = uniqueTimerId++;
	        timer.createdAt = clock.now;
	        timer.callAt =
	            clock.now + (parseInt(timer.delay) || (clock.duringTick ? 1 : 0));

	        clock.timers[timer.id] = timer;

	        if (addTimerReturnsObject) {
	            const res = {
	                refed: true,
	                ref: function () {
	                    this.refed = true;
	                    return res;
	                },
	                unref: function () {
	                    this.refed = false;
	                    return res;
	                },
	                hasRef: function () {
	                    return this.refed;
	                },
	                refresh: function () {
	                    timer.callAt =
	                        clock.now +
	                        (parseInt(timer.delay) || (clock.duringTick ? 1 : 0));

	                    // it _might_ have been removed, but if not the assignment is perfectly fine
	                    clock.timers[timer.id] = timer;

	                    return res;
	                },
	                [Symbol.toPrimitive]: function () {
	                    return timer.id;
	                },
	            };
	            return res;
	        }

	        return timer.id;
	    }

	    /* eslint consistent-return: "off" */
	    /**
	     * Timer comparitor
	     * @param {Timer} a
	     * @param {Timer} b
	     * @returns {number}
	     */
	    function compareTimers(a, b) {
	        // Sort first by absolute timing
	        if (a.callAt < b.callAt) {
	            return -1;
	        }
	        if (a.callAt > b.callAt) {
	            return 1;
	        }

	        // Sort next by immediate, immediate timers take precedence
	        if (a.immediate && !b.immediate) {
	            return -1;
	        }
	        if (!a.immediate && b.immediate) {
	            return 1;
	        }

	        // Sort next by creation time, earlier-created timers take precedence
	        if (a.createdAt < b.createdAt) {
	            return -1;
	        }
	        if (a.createdAt > b.createdAt) {
	            return 1;
	        }

	        // Sort next by id, lower-id timers take precedence
	        if (a.id < b.id) {
	            return -1;
	        }
	        if (a.id > b.id) {
	            return 1;
	        }

	        // As timer ids are unique, no fallback `0` is necessary
	    }

	    /**
	     * @param {Clock} clock
	     * @param {number} from
	     * @param {number} to
	     * @returns {Timer}
	     */
	    function firstTimerInRange(clock, from, to) {
	        const timers = clock.timers;
	        let timer = null;
	        let id, isInRange;

	        for (id in timers) {
	            if (timers.hasOwnProperty(id)) {
	                isInRange = inRange(from, to, timers[id]);

	                if (
	                    isInRange &&
	                    (!timer || compareTimers(timer, timers[id]) === 1)
	                ) {
	                    timer = timers[id];
	                }
	            }
	        }

	        return timer;
	    }

	    /**
	     * @param {Clock} clock
	     * @returns {Timer}
	     */
	    function firstTimer(clock) {
	        const timers = clock.timers;
	        let timer = null;
	        let id;

	        for (id in timers) {
	            if (timers.hasOwnProperty(id)) {
	                if (!timer || compareTimers(timer, timers[id]) === 1) {
	                    timer = timers[id];
	                }
	            }
	        }

	        return timer;
	    }

	    /**
	     * @param {Clock} clock
	     * @returns {Timer}
	     */
	    function lastTimer(clock) {
	        const timers = clock.timers;
	        let timer = null;
	        let id;

	        for (id in timers) {
	            if (timers.hasOwnProperty(id)) {
	                if (!timer || compareTimers(timer, timers[id]) === -1) {
	                    timer = timers[id];
	                }
	            }
	        }

	        return timer;
	    }

	    /**
	     * @param {Clock} clock
	     * @param {Timer} timer
	     */
	    function callTimer(clock, timer) {
	        if (typeof timer.interval === "number") {
	            clock.timers[timer.id].callAt += timer.interval;
	        } else {
	            delete clock.timers[timer.id];
	        }

	        if (typeof timer.func === "function") {
	            timer.func.apply(null, timer.args);
	        } else {
	            /* eslint no-eval: "off" */
	            const eval2 = eval;
	            (function () {
	                eval2(timer.func);
	            })();
	        }
	    }

	    /**
	     * Gets clear handler name for a given timer type
	     * @param {string} ttype
	     */
	    function getClearHandler(ttype) {
	        if (ttype === "IdleCallback" || ttype === "AnimationFrame") {
	            return `cancel${ttype}`;
	        }
	        return `clear${ttype}`;
	    }

	    /**
	     * Gets schedule handler name for a given timer type
	     * @param {string} ttype
	     */
	    function getScheduleHandler(ttype) {
	        if (ttype === "IdleCallback" || ttype === "AnimationFrame") {
	            return `request${ttype}`;
	        }
	        return `set${ttype}`;
	    }

	    /**
	     * Creates an anonymous function to warn only once
	     */
	    function createWarnOnce() {
	        let calls = 0;
	        return function (msg) {
	            // eslint-disable-next-line
	            !calls++ && console.warn(msg);
	        };
	    }
	    const warnOnce = createWarnOnce();

	    /**
	     * @param {Clock} clock
	     * @param {number} timerId
	     * @param {string} ttype
	     */
	    function clearTimer(clock, timerId, ttype) {
	        if (!timerId) {
	            // null appears to be allowed in most browsers, and appears to be
	            // relied upon by some libraries, like Bootstrap carousel
	            return;
	        }

	        if (!clock.timers) {
	            clock.timers = {};
	        }

	        // in Node, the ID is stored as the primitive value for `Timeout` objects
	        // for `Immediate` objects, no ID exists, so it gets coerced to NaN
	        const id = Number(timerId);

	        if (Number.isNaN(id) || id < idCounterStart) {
	            const handlerName = getClearHandler(ttype);

	            if (clock.shouldClearNativeTimers === true) {
	                const nativeHandler = clock[`_${handlerName}`];
	                return typeof nativeHandler === "function"
	                    ? nativeHandler(timerId)
	                    : undefined;
	            }
	            warnOnce(
	                `FakeTimers: ${handlerName} was invoked to clear a native timer instead of one created by this library.` +
	                    "\nTo automatically clean-up native timers, use `shouldClearNativeTimers`.",
	            );
	        }

	        if (clock.timers.hasOwnProperty(id)) {
	            // check that the ID matches a timer of the correct type
	            const timer = clock.timers[id];
	            if (
	                timer.type === ttype ||
	                (timer.type === "Timeout" && ttype === "Interval") ||
	                (timer.type === "Interval" && ttype === "Timeout")
	            ) {
	                delete clock.timers[id];
	            } else {
	                const clear = getClearHandler(ttype);
	                const schedule = getScheduleHandler(timer.type);
	                throw new Error(
	                    `Cannot clear timer: timer created with ${schedule}() but cleared with ${clear}()`,
	                );
	            }
	        }
	    }

	    /**
	     * @param {Clock} clock
	     * @param {Config} config
	     * @returns {Timer[]}
	     */
	    function uninstall(clock, config) {
	        let method, i, l;
	        const installedHrTime = "_hrtime";
	        const installedNextTick = "_nextTick";

	        for (i = 0, l = clock.methods.length; i < l; i++) {
	            method = clock.methods[i];
	            if (method === "hrtime" && _global.process) {
	                _global.process.hrtime = clock[installedHrTime];
	            } else if (method === "nextTick" && _global.process) {
	                _global.process.nextTick = clock[installedNextTick];
	            } else if (method === "performance") {
	                const originalPerfDescriptor = Object.getOwnPropertyDescriptor(
	                    clock,
	                    `_${method}`,
	                );
	                if (
	                    originalPerfDescriptor &&
	                    originalPerfDescriptor.get &&
	                    !originalPerfDescriptor.set
	                ) {
	                    Object.defineProperty(
	                        _global,
	                        method,
	                        originalPerfDescriptor,
	                    );
	                } else if (originalPerfDescriptor.configurable) {
	                    _global[method] = clock[`_${method}`];
	                }
	            } else {
	                if (_global[method] && _global[method].hadOwnProperty) {
	                    _global[method] = clock[`_${method}`];
	                } else {
	                    try {
	                        delete _global[method];
	                    } catch (ignore) {
	                        /* eslint no-empty: "off" */
	                    }
	                }
	            }
	            if (clock.timersModuleMethods !== undefined) {
	                for (let j = 0; j < clock.timersModuleMethods.length; j++) {
	                    const entry = clock.timersModuleMethods[j];
	                    timersModule[entry.methodName] = entry.original;
	                }
	            }
	            if (clock.timersPromisesModuleMethods !== undefined) {
	                for (
	                    let j = 0;
	                    j < clock.timersPromisesModuleMethods.length;
	                    j++
	                ) {
	                    const entry = clock.timersPromisesModuleMethods[j];
	                    timersPromisesModule[entry.methodName] = entry.original;
	                }
	            }
	        }

	        if (config.shouldAdvanceTime === true) {
	            _global.clearInterval(clock.attachedInterval);
	        }

	        // Prevent multiple executions which will completely remove these props
	        clock.methods = [];

	        for (const [listener, signal] of clock.abortListenerMap.entries()) {
	            signal.removeEventListener("abort", listener);
	            clock.abortListenerMap.delete(listener);
	        }

	        // return pending timers, to enable checking what timers remained on uninstall
	        if (!clock.timers) {
	            return [];
	        }
	        return Object.keys(clock.timers).map(function mapper(key) {
	            return clock.timers[key];
	        });
	    }

	    /**
	     * @param {object} target the target containing the method to replace
	     * @param {string} method the keyname of the method on the target
	     * @param {Clock} clock
	     */
	    function hijackMethod(target, method, clock) {
	        clock[method].hadOwnProperty = Object.prototype.hasOwnProperty.call(
	            target,
	            method,
	        );
	        clock[`_${method}`] = target[method];

	        if (method === "Date") {
	            target[method] = clock[method];
	        } else if (method === "Intl") {
	            target[method] = clock[method];
	        } else if (method === "performance") {
	            const originalPerfDescriptor = Object.getOwnPropertyDescriptor(
	                target,
	                method,
	            );
	            // JSDOM has a read only performance field so we have to save/copy it differently
	            if (
	                originalPerfDescriptor &&
	                originalPerfDescriptor.get &&
	                !originalPerfDescriptor.set
	            ) {
	                Object.defineProperty(
	                    clock,
	                    `_${method}`,
	                    originalPerfDescriptor,
	                );

	                const perfDescriptor = Object.getOwnPropertyDescriptor(
	                    clock,
	                    method,
	                );
	                Object.defineProperty(target, method, perfDescriptor);
	            } else {
	                target[method] = clock[method];
	            }
	        } else {
	            target[method] = function () {
	                return clock[method].apply(clock, arguments);
	            };

	            Object.defineProperties(
	                target[method],
	                Object.getOwnPropertyDescriptors(clock[method]),
	            );
	        }

	        target[method].clock = clock;
	    }

	    /**
	     * @param {Clock} clock
	     * @param {number} advanceTimeDelta
	     */
	    function doIntervalTick(clock, advanceTimeDelta) {
	        clock.tick(advanceTimeDelta);
	    }

	    /**
	     * @typedef {object} Timers
	     * @property {setTimeout} setTimeout
	     * @property {clearTimeout} clearTimeout
	     * @property {setInterval} setInterval
	     * @property {clearInterval} clearInterval
	     * @property {Date} Date
	     * @property {Intl} Intl
	     * @property {SetImmediate=} setImmediate
	     * @property {function(NodeImmediate): void=} clearImmediate
	     * @property {function(number[]):number[]=} hrtime
	     * @property {NextTick=} nextTick
	     * @property {Performance=} performance
	     * @property {RequestAnimationFrame=} requestAnimationFrame
	     * @property {boolean=} queueMicrotask
	     * @property {function(number): void=} cancelAnimationFrame
	     * @property {RequestIdleCallback=} requestIdleCallback
	     * @property {function(number): void=} cancelIdleCallback
	     */

	    /** @type {Timers} */
	    const timers = {
	        setTimeout: _global.setTimeout,
	        clearTimeout: _global.clearTimeout,
	        setInterval: _global.setInterval,
	        clearInterval: _global.clearInterval,
	        Date: _global.Date,
	    };

	    if (isPresent.setImmediate) {
	        timers.setImmediate = _global.setImmediate;
	    }

	    if (isPresent.clearImmediate) {
	        timers.clearImmediate = _global.clearImmediate;
	    }

	    if (isPresent.hrtime) {
	        timers.hrtime = _global.process.hrtime;
	    }

	    if (isPresent.nextTick) {
	        timers.nextTick = _global.process.nextTick;
	    }

	    if (isPresent.performance) {
	        timers.performance = _global.performance;
	    }

	    if (isPresent.requestAnimationFrame) {
	        timers.requestAnimationFrame = _global.requestAnimationFrame;
	    }

	    if (isPresent.queueMicrotask) {
	        timers.queueMicrotask = _global.queueMicrotask;
	    }

	    if (isPresent.cancelAnimationFrame) {
	        timers.cancelAnimationFrame = _global.cancelAnimationFrame;
	    }

	    if (isPresent.requestIdleCallback) {
	        timers.requestIdleCallback = _global.requestIdleCallback;
	    }

	    if (isPresent.cancelIdleCallback) {
	        timers.cancelIdleCallback = _global.cancelIdleCallback;
	    }

	    if (isPresent.Intl) {
	        timers.Intl = NativeIntl;
	    }

	    const originalSetTimeout = _global.setImmediate || _global.setTimeout;

	    /**
	     * @param {Date|number} [start] the system time - non-integer values are floored
	     * @param {number} [loopLimit] maximum number of timers that will be run when calling runAll()
	     * @returns {Clock}
	     */
	    function createClock(start, loopLimit) {
	        // eslint-disable-next-line no-param-reassign
	        start = Math.floor(getEpoch(start));
	        // eslint-disable-next-line no-param-reassign
	        loopLimit = loopLimit || 1000;
	        let nanos = 0;
	        const adjustedSystemTime = [0, 0]; // [millis, nanoremainder]

	        const clock = {
	            now: start,
	            Date: createDate(),
	            loopLimit: loopLimit,
	        };

	        clock.Date.clock = clock;

	        //eslint-disable-next-line jsdoc/require-jsdoc
	        function getTimeToNextFrame() {
	            return 16 - ((clock.now - start) % 16);
	        }

	        //eslint-disable-next-line jsdoc/require-jsdoc
	        function hrtime(prev) {
	            const millisSinceStart = clock.now - adjustedSystemTime[0] - start;
	            const secsSinceStart = Math.floor(millisSinceStart / 1000);
	            const remainderInNanos =
	                (millisSinceStart - secsSinceStart * 1e3) * 1e6 +
	                nanos -
	                adjustedSystemTime[1];

	            if (Array.isArray(prev)) {
	                if (prev[1] > 1e9) {
	                    throw new TypeError(
	                        "Number of nanoseconds can't exceed a billion",
	                    );
	                }

	                const oldSecs = prev[0];
	                let nanoDiff = remainderInNanos - prev[1];
	                let secDiff = secsSinceStart - oldSecs;

	                if (nanoDiff < 0) {
	                    nanoDiff += 1e9;
	                    secDiff -= 1;
	                }

	                return [secDiff, nanoDiff];
	            }
	            return [secsSinceStart, remainderInNanos];
	        }

	        /**
	         * A high resolution timestamp in milliseconds.
	         * @typedef {number} DOMHighResTimeStamp
	         */

	        /**
	         * performance.now()
	         * @returns {DOMHighResTimeStamp}
	         */
	        function fakePerformanceNow() {
	            const hrt = hrtime();
	            const millis = hrt[0] * 1000 + hrt[1] / 1e6;
	            return millis;
	        }

	        if (isPresent.hrtimeBigint) {
	            hrtime.bigint = function () {
	                const parts = hrtime();
	                return BigInt(parts[0]) * BigInt(1e9) + BigInt(parts[1]); // eslint-disable-line
	            };
	        }

	        if (isPresent.Intl) {
	            clock.Intl = createIntl();
	            clock.Intl.clock = clock;
	        }

	        clock.requestIdleCallback = function requestIdleCallback(
	            func,
	            timeout,
	        ) {
	            let timeToNextIdlePeriod = 0;

	            if (clock.countTimers() > 0) {
	                timeToNextIdlePeriod = 50; // const for now
	            }

	            const result = addTimer(clock, {
	                func: func,
	                args: Array.prototype.slice.call(arguments, 2),
	                delay:
	                    typeof timeout === "undefined"
	                        ? timeToNextIdlePeriod
	                        : Math.min(timeout, timeToNextIdlePeriod),
	                idleCallback: true,
	            });

	            return Number(result);
	        };

	        clock.cancelIdleCallback = function cancelIdleCallback(timerId) {
	            return clearTimer(clock, timerId, "IdleCallback");
	        };

	        clock.setTimeout = function setTimeout(func, timeout) {
	            return addTimer(clock, {
	                func: func,
	                args: Array.prototype.slice.call(arguments, 2),
	                delay: timeout,
	            });
	        };
	        if (typeof _global.Promise !== "undefined" && utilPromisify) {
	            clock.setTimeout[utilPromisify.custom] =
	                function promisifiedSetTimeout(timeout, arg) {
	                    return new _global.Promise(function setTimeoutExecutor(
	                        resolve,
	                    ) {
	                        addTimer(clock, {
	                            func: resolve,
	                            args: [arg],
	                            delay: timeout,
	                        });
	                    });
	                };
	        }

	        clock.clearTimeout = function clearTimeout(timerId) {
	            return clearTimer(clock, timerId, "Timeout");
	        };

	        clock.nextTick = function nextTick(func) {
	            return enqueueJob(clock, {
	                func: func,
	                args: Array.prototype.slice.call(arguments, 1),
	                error: isNearInfiniteLimit ? new Error() : null,
	            });
	        };

	        clock.queueMicrotask = function queueMicrotask(func) {
	            return clock.nextTick(func); // explicitly drop additional arguments
	        };

	        clock.setInterval = function setInterval(func, timeout) {
	            // eslint-disable-next-line no-param-reassign
	            timeout = parseInt(timeout, 10);
	            return addTimer(clock, {
	                func: func,
	                args: Array.prototype.slice.call(arguments, 2),
	                delay: timeout,
	                interval: timeout,
	            });
	        };

	        clock.clearInterval = function clearInterval(timerId) {
	            return clearTimer(clock, timerId, "Interval");
	        };

	        if (isPresent.setImmediate) {
	            clock.setImmediate = function setImmediate(func) {
	                return addTimer(clock, {
	                    func: func,
	                    args: Array.prototype.slice.call(arguments, 1),
	                    immediate: true,
	                });
	            };

	            if (typeof _global.Promise !== "undefined" && utilPromisify) {
	                clock.setImmediate[utilPromisify.custom] =
	                    function promisifiedSetImmediate(arg) {
	                        return new _global.Promise(
	                            function setImmediateExecutor(resolve) {
	                                addTimer(clock, {
	                                    func: resolve,
	                                    args: [arg],
	                                    immediate: true,
	                                });
	                            },
	                        );
	                    };
	            }

	            clock.clearImmediate = function clearImmediate(timerId) {
	                return clearTimer(clock, timerId, "Immediate");
	            };
	        }

	        clock.countTimers = function countTimers() {
	            return (
	                Object.keys(clock.timers || {}).length +
	                (clock.jobs || []).length
	            );
	        };

	        clock.requestAnimationFrame = function requestAnimationFrame(func) {
	            const result = addTimer(clock, {
	                func: func,
	                delay: getTimeToNextFrame(),
	                get args() {
	                    return [fakePerformanceNow()];
	                },
	                animation: true,
	            });

	            return Number(result);
	        };

	        clock.cancelAnimationFrame = function cancelAnimationFrame(timerId) {
	            return clearTimer(clock, timerId, "AnimationFrame");
	        };

	        clock.runMicrotasks = function runMicrotasks() {
	            runJobs(clock);
	        };

	        /**
	         * @param {number|string} tickValue milliseconds or a string parseable by parseTime
	         * @param {boolean} isAsync
	         * @param {Function} resolve
	         * @param {Function} reject
	         * @returns {number|undefined} will return the new `now` value or nothing for async
	         */
	        function doTick(tickValue, isAsync, resolve, reject) {
	            const msFloat =
	                typeof tickValue === "number"
	                    ? tickValue
	                    : parseTime(tickValue);
	            const ms = Math.floor(msFloat);
	            const remainder = nanoRemainder(msFloat);
	            let nanosTotal = nanos + remainder;
	            let tickTo = clock.now + ms;

	            if (msFloat < 0) {
	                throw new TypeError("Negative ticks are not supported");
	            }

	            // adjust for positive overflow
	            if (nanosTotal >= 1e6) {
	                tickTo += 1;
	                nanosTotal -= 1e6;
	            }

	            nanos = nanosTotal;
	            let tickFrom = clock.now;
	            let previous = clock.now;
	            // ESLint fails to detect this correctly
	            /* eslint-disable prefer-const */
	            let timer,
	                firstException,
	                oldNow,
	                nextPromiseTick,
	                compensationCheck,
	                postTimerCall;
	            /* eslint-enable prefer-const */

	            clock.duringTick = true;

	            // perform microtasks
	            oldNow = clock.now;
	            runJobs(clock);
	            if (oldNow !== clock.now) {
	                // compensate for any setSystemTime() call during microtask callback
	                tickFrom += clock.now - oldNow;
	                tickTo += clock.now - oldNow;
	            }

	            //eslint-disable-next-line jsdoc/require-jsdoc
	            function doTickInner() {
	                // perform each timer in the requested range
	                timer = firstTimerInRange(clock, tickFrom, tickTo);
	                // eslint-disable-next-line no-unmodified-loop-condition
	                while (timer && tickFrom <= tickTo) {
	                    if (clock.timers[timer.id]) {
	                        tickFrom = timer.callAt;
	                        clock.now = timer.callAt;
	                        oldNow = clock.now;
	                        try {
	                            runJobs(clock);
	                            callTimer(clock, timer);
	                        } catch (e) {
	                            firstException = firstException || e;
	                        }

	                        if (isAsync) {
	                            // finish up after native setImmediate callback to allow
	                            // all native es6 promises to process their callbacks after
	                            // each timer fires.
	                            originalSetTimeout(nextPromiseTick);
	                            return;
	                        }

	                        compensationCheck();
	                    }

	                    postTimerCall();
	                }

	                // perform process.nextTick()s again
	                oldNow = clock.now;
	                runJobs(clock);
	                if (oldNow !== clock.now) {
	                    // compensate for any setSystemTime() call during process.nextTick() callback
	                    tickFrom += clock.now - oldNow;
	                    tickTo += clock.now - oldNow;
	                }
	                clock.duringTick = false;

	                // corner case: during runJobs new timers were scheduled which could be in the range [clock.now, tickTo]
	                timer = firstTimerInRange(clock, tickFrom, tickTo);
	                if (timer) {
	                    try {
	                        clock.tick(tickTo - clock.now); // do it all again - for the remainder of the requested range
	                    } catch (e) {
	                        firstException = firstException || e;
	                    }
	                } else {
	                    // no timers remaining in the requested range: move the clock all the way to the end
	                    clock.now = tickTo;

	                    // update nanos
	                    nanos = nanosTotal;
	                }
	                if (firstException) {
	                    throw firstException;
	                }

	                if (isAsync) {
	                    resolve(clock.now);
	                } else {
	                    return clock.now;
	                }
	            }

	            nextPromiseTick =
	                isAsync &&
	                function () {
	                    try {
	                        compensationCheck();
	                        postTimerCall();
	                        doTickInner();
	                    } catch (e) {
	                        reject(e);
	                    }
	                };

	            compensationCheck = function () {
	                // compensate for any setSystemTime() call during timer callback
	                if (oldNow !== clock.now) {
	                    tickFrom += clock.now - oldNow;
	                    tickTo += clock.now - oldNow;
	                    previous += clock.now - oldNow;
	                }
	            };

	            postTimerCall = function () {
	                timer = firstTimerInRange(clock, previous, tickTo);
	                previous = tickFrom;
	            };

	            return doTickInner();
	        }

	        /**
	         * @param {string|number} tickValue number of milliseconds or a human-readable value like "01:11:15"
	         * @returns {number} will return the new `now` value
	         */
	        clock.tick = function tick(tickValue) {
	            return doTick(tickValue, false);
	        };

	        if (typeof _global.Promise !== "undefined") {
	            /**
	             * @param {string|number} tickValue number of milliseconds or a human-readable value like "01:11:15"
	             * @returns {Promise}
	             */
	            clock.tickAsync = function tickAsync(tickValue) {
	                return new _global.Promise(function (resolve, reject) {
	                    originalSetTimeout(function () {
	                        try {
	                            doTick(tickValue, true, resolve, reject);
	                        } catch (e) {
	                            reject(e);
	                        }
	                    });
	                });
	            };
	        }

	        clock.next = function next() {
	            runJobs(clock);
	            const timer = firstTimer(clock);
	            if (!timer) {
	                return clock.now;
	            }

	            clock.duringTick = true;
	            try {
	                clock.now = timer.callAt;
	                callTimer(clock, timer);
	                runJobs(clock);
	                return clock.now;
	            } finally {
	                clock.duringTick = false;
	            }
	        };

	        if (typeof _global.Promise !== "undefined") {
	            clock.nextAsync = function nextAsync() {
	                return new _global.Promise(function (resolve, reject) {
	                    originalSetTimeout(function () {
	                        try {
	                            const timer = firstTimer(clock);
	                            if (!timer) {
	                                resolve(clock.now);
	                                return;
	                            }

	                            let err;
	                            clock.duringTick = true;
	                            clock.now = timer.callAt;
	                            try {
	                                callTimer(clock, timer);
	                            } catch (e) {
	                                err = e;
	                            }
	                            clock.duringTick = false;

	                            originalSetTimeout(function () {
	                                if (err) {
	                                    reject(err);
	                                } else {
	                                    resolve(clock.now);
	                                }
	                            });
	                        } catch (e) {
	                            reject(e);
	                        }
	                    });
	                });
	            };
	        }

	        clock.runAll = function runAll() {
	            let numTimers, i;
	            runJobs(clock);
	            for (i = 0; i < clock.loopLimit; i++) {
	                if (!clock.timers) {
	                    resetIsNearInfiniteLimit();
	                    return clock.now;
	                }

	                numTimers = Object.keys(clock.timers).length;
	                if (numTimers === 0) {
	                    resetIsNearInfiniteLimit();
	                    return clock.now;
	                }

	                clock.next();
	                checkIsNearInfiniteLimit(clock, i);
	            }

	            const excessJob = firstTimer(clock);
	            throw getInfiniteLoopError(clock, excessJob);
	        };

	        clock.runToFrame = function runToFrame() {
	            return clock.tick(getTimeToNextFrame());
	        };

	        if (typeof _global.Promise !== "undefined") {
	            clock.runAllAsync = function runAllAsync() {
	                return new _global.Promise(function (resolve, reject) {
	                    let i = 0;
	                    /**
	                     *
	                     */
	                    function doRun() {
	                        originalSetTimeout(function () {
	                            try {
	                                runJobs(clock);

	                                let numTimers;
	                                if (i < clock.loopLimit) {
	                                    if (!clock.timers) {
	                                        resetIsNearInfiniteLimit();
	                                        resolve(clock.now);
	                                        return;
	                                    }

	                                    numTimers = Object.keys(
	                                        clock.timers,
	                                    ).length;
	                                    if (numTimers === 0) {
	                                        resetIsNearInfiniteLimit();
	                                        resolve(clock.now);
	                                        return;
	                                    }

	                                    clock.next();

	                                    i++;

	                                    doRun();
	                                    checkIsNearInfiniteLimit(clock, i);
	                                    return;
	                                }

	                                const excessJob = firstTimer(clock);
	                                reject(getInfiniteLoopError(clock, excessJob));
	                            } catch (e) {
	                                reject(e);
	                            }
	                        });
	                    }
	                    doRun();
	                });
	            };
	        }

	        clock.runToLast = function runToLast() {
	            const timer = lastTimer(clock);
	            if (!timer) {
	                runJobs(clock);
	                return clock.now;
	            }

	            return clock.tick(timer.callAt - clock.now);
	        };

	        if (typeof _global.Promise !== "undefined") {
	            clock.runToLastAsync = function runToLastAsync() {
	                return new _global.Promise(function (resolve, reject) {
	                    originalSetTimeout(function () {
	                        try {
	                            const timer = lastTimer(clock);
	                            if (!timer) {
	                                runJobs(clock);
	                                resolve(clock.now);
	                            }

	                            resolve(clock.tickAsync(timer.callAt - clock.now));
	                        } catch (e) {
	                            reject(e);
	                        }
	                    });
	                });
	            };
	        }

	        clock.reset = function reset() {
	            nanos = 0;
	            clock.timers = {};
	            clock.jobs = [];
	            clock.now = start;
	        };

	        clock.setSystemTime = function setSystemTime(systemTime) {
	            // determine time difference
	            const newNow = getEpoch(systemTime);
	            const difference = newNow - clock.now;
	            let id, timer;

	            adjustedSystemTime[0] = adjustedSystemTime[0] + difference;
	            adjustedSystemTime[1] = adjustedSystemTime[1] + nanos;
	            // update 'system clock'
	            clock.now = newNow;
	            nanos = 0;

	            // update timers and intervals to keep them stable
	            for (id in clock.timers) {
	                if (clock.timers.hasOwnProperty(id)) {
	                    timer = clock.timers[id];
	                    timer.createdAt += difference;
	                    timer.callAt += difference;
	                }
	            }
	        };

	        /**
	         * @param {string|number} tickValue number of milliseconds or a human-readable value like "01:11:15"
	         * @returns {number} will return the new `now` value
	         */
	        clock.jump = function jump(tickValue) {
	            const msFloat =
	                typeof tickValue === "number"
	                    ? tickValue
	                    : parseTime(tickValue);
	            const ms = Math.floor(msFloat);

	            for (const timer of Object.values(clock.timers)) {
	                if (clock.now + ms > timer.callAt) {
	                    timer.callAt = clock.now + ms;
	                }
	            }
	            clock.tick(ms);
	        };

	        if (isPresent.performance) {
	            clock.performance = Object.create(null);
	            clock.performance.now = fakePerformanceNow;
	        }

	        if (isPresent.hrtime) {
	            clock.hrtime = hrtime;
	        }

	        return clock;
	    }

	    /* eslint-disable complexity */

	    /**
	     * @param {Config=} [config] Optional config
	     * @returns {Clock}
	     */
	    function install(config) {
	        if (
	            arguments.length > 1 ||
	            config instanceof Date ||
	            Array.isArray(config) ||
	            typeof config === "number"
	        ) {
	            throw new TypeError(
	                `FakeTimers.install called with ${String(
	                    config,
	                )} install requires an object parameter`,
	            );
	        }

	        if (_global.Date.isFake === true) {
	            // Timers are already faked; this is a problem.
	            // Make the user reset timers before continuing.
	            throw new TypeError(
	                "Can't install fake timers twice on the same global object.",
	            );
	        }

	        // eslint-disable-next-line no-param-reassign
	        config = typeof config !== "undefined" ? config : {};
	        config.shouldAdvanceTime = config.shouldAdvanceTime || false;
	        config.advanceTimeDelta = config.advanceTimeDelta || 20;
	        config.shouldClearNativeTimers =
	            config.shouldClearNativeTimers || false;

	        if (config.target) {
	            throw new TypeError(
	                "config.target is no longer supported. Use `withGlobal(target)` instead.",
	            );
	        }

	        /**
	         * @param {string} timer/object the name of the thing that is not present
	         * @param timer
	         */
	        function handleMissingTimer(timer) {
	            if (config.ignoreMissingTimers) {
	                return;
	            }

	            throw new ReferenceError(
	                `non-existent timers and/or objects cannot be faked: '${timer}'`,
	            );
	        }

	        let i, l;
	        const clock = createClock(config.now, config.loopLimit);
	        clock.shouldClearNativeTimers = config.shouldClearNativeTimers;

	        clock.uninstall = function () {
	            return uninstall(clock, config);
	        };

	        clock.abortListenerMap = new Map();

	        clock.methods = config.toFake || [];

	        if (clock.methods.length === 0) {
	            clock.methods = Object.keys(timers);
	        }

	        if (config.shouldAdvanceTime === true) {
	            const intervalTick = doIntervalTick.bind(
	                null,
	                clock,
	                config.advanceTimeDelta,
	            );
	            const intervalId = _global.setInterval(
	                intervalTick,
	                config.advanceTimeDelta,
	            );
	            clock.attachedInterval = intervalId;
	        }

	        if (clock.methods.includes("performance")) {
	            const proto = (() => {
	                if (hasPerformanceConstructorPrototype) {
	                    return _global.performance.constructor.prototype;
	                }
	                if (hasPerformancePrototype) {
	                    return _global.Performance.prototype;
	                }
	            })();
	            if (proto) {
	                Object.getOwnPropertyNames(proto).forEach(function (name) {
	                    if (name !== "now") {
	                        clock.performance[name] =
	                            name.indexOf("getEntries") === 0
	                                ? NOOP_ARRAY
	                                : NOOP;
	                    }
	                });
	                // ensure `mark` returns a value that is valid
	                clock.performance.mark = (name) =>
	                    new FakePerformanceEntry(name, "mark", 0, 0);
	                clock.performance.measure = (name) =>
	                    new FakePerformanceEntry(name, "measure", 0, 100);
	                // `timeOrigin` should return the time of when the Window session started
	                // (or the Worker was installed)
	                clock.performance.timeOrigin = getEpoch(config.now);
	            } else if ((config.toFake || []).includes("performance")) {
	                return handleMissingTimer("performance");
	            }
	        }
	        if (_global === globalObject && timersModule) {
	            clock.timersModuleMethods = [];
	        }
	        if (_global === globalObject && timersPromisesModule) {
	            clock.timersPromisesModuleMethods = [];
	        }
	        for (i = 0, l = clock.methods.length; i < l; i++) {
	            const nameOfMethodToReplace = clock.methods[i];

	            if (!isPresent[nameOfMethodToReplace]) {
	                handleMissingTimer(nameOfMethodToReplace);
	                // eslint-disable-next-line
	                continue;
	            }

	            if (nameOfMethodToReplace === "hrtime") {
	                if (
	                    _global.process &&
	                    typeof _global.process.hrtime === "function"
	                ) {
	                    hijackMethod(_global.process, nameOfMethodToReplace, clock);
	                }
	            } else if (nameOfMethodToReplace === "nextTick") {
	                if (
	                    _global.process &&
	                    typeof _global.process.nextTick === "function"
	                ) {
	                    hijackMethod(_global.process, nameOfMethodToReplace, clock);
	                }
	            } else {
	                hijackMethod(_global, nameOfMethodToReplace, clock);
	            }
	            if (
	                clock.timersModuleMethods !== undefined &&
	                timersModule[nameOfMethodToReplace]
	            ) {
	                const original = timersModule[nameOfMethodToReplace];
	                clock.timersModuleMethods.push({
	                    methodName: nameOfMethodToReplace,
	                    original: original,
	                });
	                timersModule[nameOfMethodToReplace] =
	                    _global[nameOfMethodToReplace];
	            }
	            if (clock.timersPromisesModuleMethods !== undefined) {
	                if (nameOfMethodToReplace === "setTimeout") {
	                    clock.timersPromisesModuleMethods.push({
	                        methodName: "setTimeout",
	                        original: timersPromisesModule.setTimeout,
	                    });

	                    timersPromisesModule.setTimeout = (
	                        delay,
	                        value,
	                        options = {},
	                    ) =>
	                        new Promise((resolve, reject) => {
	                            const abort = () => {
	                                options.signal.removeEventListener(
	                                    "abort",
	                                    abort,
	                                );
	                                clock.abortListenerMap.delete(abort);

	                                // This is safe, there is no code path that leads to this function
	                                // being invoked before handle has been assigned.
	                                // eslint-disable-next-line no-use-before-define
	                                clock.clearTimeout(handle);
	                                reject(options.signal.reason);
	                            };

	                            const handle = clock.setTimeout(() => {
	                                if (options.signal) {
	                                    options.signal.removeEventListener(
	                                        "abort",
	                                        abort,
	                                    );
	                                    clock.abortListenerMap.delete(abort);
	                                }

	                                resolve(value);
	                            }, delay);

	                            if (options.signal) {
	                                if (options.signal.aborted) {
	                                    abort();
	                                } else {
	                                    options.signal.addEventListener(
	                                        "abort",
	                                        abort,
	                                    );
	                                    clock.abortListenerMap.set(
	                                        abort,
	                                        options.signal,
	                                    );
	                                }
	                            }
	                        });
	                } else if (nameOfMethodToReplace === "setImmediate") {
	                    clock.timersPromisesModuleMethods.push({
	                        methodName: "setImmediate",
	                        original: timersPromisesModule.setImmediate,
	                    });

	                    timersPromisesModule.setImmediate = (value, options = {}) =>
	                        new Promise((resolve, reject) => {
	                            const abort = () => {
	                                options.signal.removeEventListener(
	                                    "abort",
	                                    abort,
	                                );
	                                clock.abortListenerMap.delete(abort);

	                                // This is safe, there is no code path that leads to this function
	                                // being invoked before handle has been assigned.
	                                // eslint-disable-next-line no-use-before-define
	                                clock.clearImmediate(handle);
	                                reject(options.signal.reason);
	                            };

	                            const handle = clock.setImmediate(() => {
	                                if (options.signal) {
	                                    options.signal.removeEventListener(
	                                        "abort",
	                                        abort,
	                                    );
	                                    clock.abortListenerMap.delete(abort);
	                                }

	                                resolve(value);
	                            });

	                            if (options.signal) {
	                                if (options.signal.aborted) {
	                                    abort();
	                                } else {
	                                    options.signal.addEventListener(
	                                        "abort",
	                                        abort,
	                                    );
	                                    clock.abortListenerMap.set(
	                                        abort,
	                                        options.signal,
	                                    );
	                                }
	                            }
	                        });
	                } else if (nameOfMethodToReplace === "setInterval") {
	                    clock.timersPromisesModuleMethods.push({
	                        methodName: "setInterval",
	                        original: timersPromisesModule.setInterval,
	                    });

	                    timersPromisesModule.setInterval = (
	                        delay,
	                        value,
	                        options = {},
	                    ) => ({
	                        [Symbol.asyncIterator]: () => {
	                            const createResolvable = () => {
	                                let resolve, reject;
	                                const promise = new Promise((res, rej) => {
	                                    resolve = res;
	                                    reject = rej;
	                                });
	                                promise.resolve = resolve;
	                                promise.reject = reject;
	                                return promise;
	                            };

	                            let done = false;
	                            let hasThrown = false;
	                            let returnCall;
	                            let nextAvailable = 0;
	                            const nextQueue = [];

	                            const handle = clock.setInterval(() => {
	                                if (nextQueue.length > 0) {
	                                    nextQueue.shift().resolve();
	                                } else {
	                                    nextAvailable++;
	                                }
	                            }, delay);

	                            const abort = () => {
	                                options.signal.removeEventListener(
	                                    "abort",
	                                    abort,
	                                );
	                                clock.abortListenerMap.delete(abort);

	                                clock.clearInterval(handle);
	                                done = true;
	                                for (const resolvable of nextQueue) {
	                                    resolvable.resolve();
	                                }
	                            };

	                            if (options.signal) {
	                                if (options.signal.aborted) {
	                                    done = true;
	                                } else {
	                                    options.signal.addEventListener(
	                                        "abort",
	                                        abort,
	                                    );
	                                    clock.abortListenerMap.set(
	                                        abort,
	                                        options.signal,
	                                    );
	                                }
	                            }

	                            return {
	                                next: async () => {
	                                    if (options.signal?.aborted && !hasThrown) {
	                                        hasThrown = true;
	                                        throw options.signal.reason;
	                                    }

	                                    if (done) {
	                                        return { done: true, value: undefined };
	                                    }

	                                    if (nextAvailable > 0) {
	                                        nextAvailable--;
	                                        return { done: false, value: value };
	                                    }

	                                    const resolvable = createResolvable();
	                                    nextQueue.push(resolvable);

	                                    await resolvable;

	                                    if (returnCall && nextQueue.length === 0) {
	                                        returnCall.resolve();
	                                    }

	                                    if (options.signal?.aborted && !hasThrown) {
	                                        hasThrown = true;
	                                        throw options.signal.reason;
	                                    }

	                                    if (done) {
	                                        return { done: true, value: undefined };
	                                    }

	                                    return { done: false, value: value };
	                                },
	                                return: async () => {
	                                    if (done) {
	                                        return { done: true, value: undefined };
	                                    }

	                                    if (nextQueue.length > 0) {
	                                        returnCall = createResolvable();
	                                        await returnCall;
	                                    }

	                                    clock.clearInterval(handle);
	                                    done = true;

	                                    if (options.signal) {
	                                        options.signal.removeEventListener(
	                                            "abort",
	                                            abort,
	                                        );
	                                        clock.abortListenerMap.delete(abort);
	                                    }

	                                    return { done: true, value: undefined };
	                                },
	                            };
	                        },
	                    });
	                }
	            }
	        }

	        return clock;
	    }

	    /* eslint-enable complexity */

	    return {
	        timers: timers,
	        createClock: createClock,
	        install: install,
	        withGlobal: withGlobal,
	    };
	}

	/**
	 * @typedef {object} FakeTimers
	 * @property {Timers} timers
	 * @property {createClock} createClock
	 * @property {Function} install
	 * @property {withGlobal} withGlobal
	 */

	/* eslint-enable complexity */

	/** @type {FakeTimers} */
	const defaultImplementation = withGlobal(globalObject);

	fakeTimersSrc.timers = defaultImplementation.timers;
	fakeTimersSrc.createClock = defaultImplementation.createClock;
	fakeTimersSrc.install = defaultImplementation.install;
	fakeTimersSrc.withGlobal = withGlobal;
	return fakeTimersSrc;
}

var fakeTimersSrcExports = requireFakeTimersSrc();

class FakeTimers {
	_global;
	_clock;
	// | _fakingTime | _fakingDate |
	// +-------------+-------------+
	// | false       | falsy       | initial
	// | false       | truthy      | vi.setSystemTime called first (for mocking only Date without fake timers)
	// | true        | falsy       | vi.useFakeTimers called first
	// | true        | truthy      | unreachable
	_fakingTime;
	_fakingDate;
	_fakeTimers;
	_userConfig;
	_now = RealDate.now;
	constructor({ global, config }) {
		this._userConfig = config;
		this._fakingDate = null;
		this._fakingTime = false;
		this._fakeTimers = fakeTimersSrcExports.withGlobal(global);
		this._global = global;
	}
	clearAllTimers() {
		if (this._fakingTime) this._clock.reset();
	}
	dispose() {
		this.useRealTimers();
	}
	runAllTimers() {
		if (this._checkFakeTimers()) this._clock.runAll();
	}
	async runAllTimersAsync() {
		if (this._checkFakeTimers()) await this._clock.runAllAsync();
	}
	runOnlyPendingTimers() {
		if (this._checkFakeTimers()) this._clock.runToLast();
	}
	async runOnlyPendingTimersAsync() {
		if (this._checkFakeTimers()) await this._clock.runToLastAsync();
	}
	advanceTimersToNextTimer(steps = 1) {
		if (this._checkFakeTimers()) for (let i = steps; i > 0; i--) {
			this._clock.next();
			// Fire all timers at this point: https://github.com/sinonjs/fake-timers/issues/250
			this._clock.tick(0);
			if (this._clock.countTimers() === 0) break;
		}
	}
	async advanceTimersToNextTimerAsync(steps = 1) {
		if (this._checkFakeTimers()) for (let i = steps; i > 0; i--) {
			await this._clock.nextAsync();
			// Fire all timers at this point: https://github.com/sinonjs/fake-timers/issues/250
			this._clock.tick(0);
			if (this._clock.countTimers() === 0) break;
		}
	}
	advanceTimersByTime(msToRun) {
		if (this._checkFakeTimers()) this._clock.tick(msToRun);
	}
	async advanceTimersByTimeAsync(msToRun) {
		if (this._checkFakeTimers()) await this._clock.tickAsync(msToRun);
	}
	advanceTimersToNextFrame() {
		if (this._checkFakeTimers()) this._clock.runToFrame();
	}
	runAllTicks() {
		if (this._checkFakeTimers())
 // @ts-expect-error method not exposed
		this._clock.runMicrotasks();
	}
	useRealTimers() {
		if (this._fakingDate) {
			resetDate();
			this._fakingDate = null;
		}
		if (this._fakingTime) {
			this._clock.uninstall();
			this._fakingTime = false;
		}
	}
	useFakeTimers() {
		const fakeDate = this._fakingDate || Date.now();
		if (this._fakingDate) {
			resetDate();
			this._fakingDate = null;
		}
		if (this._fakingTime) this._clock.uninstall();
		const toFake = Object.keys(this._fakeTimers.timers).filter((timer) => timer !== "nextTick" && timer !== "queueMicrotask");
		if (this._userConfig?.toFake?.includes("nextTick") && isChildProcess()) throw new Error("process.nextTick cannot be mocked inside child_process");
		this._clock = this._fakeTimers.install({
			now: fakeDate,
			...this._userConfig,
			toFake: this._userConfig?.toFake || toFake,
			ignoreMissingTimers: true
		});
		this._fakingTime = true;
	}
	reset() {
		if (this._checkFakeTimers()) {
			const { now } = this._clock;
			this._clock.reset();
			this._clock.setSystemTime(now);
		}
	}
	setSystemTime(now) {
		const date = typeof now === "undefined" || now instanceof Date ? now : new Date(now);
		if (this._fakingTime) this._clock.setSystemTime(date);
		else {
			this._fakingDate = date ?? new Date(this.getRealSystemTime());
			mockDate(this._fakingDate);
		}
	}
	getMockedSystemTime() {
		return this._fakingTime ? new Date(this._clock.now) : this._fakingDate;
	}
	getRealSystemTime() {
		return this._now();
	}
	getTimerCount() {
		if (this._checkFakeTimers()) return this._clock.countTimers();
		return 0;
	}
	configure(config) {
		this._userConfig = config;
	}
	isFakeTimers() {
		return this._fakingTime;
	}
	_checkFakeTimers() {
		if (!this._fakingTime) throw new Error("A function to advance timers was called but the timers APIs are not mocked. Call `vi.useFakeTimers()` in the test file first.");
		return this._fakingTime;
	}
}

function copyStackTrace(target, source) {
	if (source.stack !== void 0) target.stack = source.stack.replace(source.message, target.message);
	return target;
}
function waitFor(callback, options = {}) {
	const { setTimeout, setInterval, clearTimeout, clearInterval } = getSafeTimers();
	const { interval = 50, timeout = 1e3 } = typeof options === "number" ? { timeout: options } : options;
	const STACK_TRACE_ERROR = /* @__PURE__ */ new Error("STACK_TRACE_ERROR");
	return new Promise((resolve, reject) => {
		let lastError;
		let promiseStatus = "idle";
		let timeoutId;
		let intervalId;
		const onResolve = (result) => {
			if (timeoutId) clearTimeout(timeoutId);
			if (intervalId) clearInterval(intervalId);
			resolve(result);
		};
		const handleTimeout = () => {
			if (intervalId) clearInterval(intervalId);
			let error = lastError;
			if (!error) error = copyStackTrace(/* @__PURE__ */ new Error("Timed out in waitFor!"), STACK_TRACE_ERROR);
			reject(error);
		};
		const checkCallback = () => {
			if (vi.isFakeTimers()) vi.advanceTimersByTime(interval);
			if (promiseStatus === "pending") return;
			try {
				const result = callback();
				if (result !== null && typeof result === "object" && typeof result.then === "function") {
					const thenable = result;
					promiseStatus = "pending";
					thenable.then((resolvedValue) => {
						promiseStatus = "resolved";
						onResolve(resolvedValue);
					}, (rejectedValue) => {
						promiseStatus = "rejected";
						lastError = rejectedValue;
					});
				} else {
					onResolve(result);
					return true;
				}
			} catch (error) {
				lastError = error;
			}
		};
		if (checkCallback() === true) return;
		timeoutId = setTimeout(handleTimeout, timeout);
		intervalId = setInterval(checkCallback, interval);
	});
}
function waitUntil(callback, options = {}) {
	const { setTimeout, setInterval, clearTimeout, clearInterval } = getSafeTimers();
	const { interval = 50, timeout = 1e3 } = typeof options === "number" ? { timeout: options } : options;
	const STACK_TRACE_ERROR = /* @__PURE__ */ new Error("STACK_TRACE_ERROR");
	return new Promise((resolve, reject) => {
		let promiseStatus = "idle";
		let timeoutId;
		let intervalId;
		const onReject = (error) => {
			if (intervalId) clearInterval(intervalId);
			if (!error) error = copyStackTrace(/* @__PURE__ */ new Error("Timed out in waitUntil!"), STACK_TRACE_ERROR);
			reject(error);
		};
		const onResolve = (result) => {
			if (!result) return;
			if (timeoutId) clearTimeout(timeoutId);
			if (intervalId) clearInterval(intervalId);
			resolve(result);
			return true;
		};
		const checkCallback = () => {
			if (vi.isFakeTimers()) vi.advanceTimersByTime(interval);
			if (promiseStatus === "pending") return;
			try {
				const result = callback();
				if (result !== null && typeof result === "object" && typeof result.then === "function") {
					const thenable = result;
					promiseStatus = "pending";
					thenable.then((resolvedValue) => {
						promiseStatus = "resolved";
						onResolve(resolvedValue);
					}, (rejectedValue) => {
						promiseStatus = "rejected";
						onReject(rejectedValue);
					});
				} else return onResolve(result);
			} catch (error) {
				onReject(error);
			}
		};
		if (checkCallback() === true) return;
		timeoutId = setTimeout(onReject, timeout);
		intervalId = setInterval(checkCallback, interval);
	});
}

function createVitest() {
	let _config = null;
	const state = () => getWorkerState();
	let _timers;
	const timers = () => _timers ||= new FakeTimers({
		global: globalThis,
		config: state().config.fakeTimers
	});
	const _stubsGlobal = /* @__PURE__ */ new Map();
	const _stubsEnv = /* @__PURE__ */ new Map();
	const _envBooleans = [
		"PROD",
		"DEV",
		"SSR"
	];
	const utils = {
		useFakeTimers(config) {
			if (isChildProcess()) {
				if (config?.toFake?.includes("nextTick") || state().config?.fakeTimers?.toFake?.includes("nextTick")) throw new Error("vi.useFakeTimers({ toFake: [\"nextTick\"] }) is not supported in node:child_process. Use --pool=threads if mocking nextTick is required.");
			}
			if (config) timers().configure({
				...state().config.fakeTimers,
				...config
			});
			else timers().configure(state().config.fakeTimers);
			timers().useFakeTimers();
			return utils;
		},
		isFakeTimers() {
			return timers().isFakeTimers();
		},
		useRealTimers() {
			timers().useRealTimers();
			return utils;
		},
		runOnlyPendingTimers() {
			timers().runOnlyPendingTimers();
			return utils;
		},
		async runOnlyPendingTimersAsync() {
			await timers().runOnlyPendingTimersAsync();
			return utils;
		},
		runAllTimers() {
			timers().runAllTimers();
			return utils;
		},
		async runAllTimersAsync() {
			await timers().runAllTimersAsync();
			return utils;
		},
		runAllTicks() {
			timers().runAllTicks();
			return utils;
		},
		advanceTimersByTime(ms) {
			timers().advanceTimersByTime(ms);
			return utils;
		},
		async advanceTimersByTimeAsync(ms) {
			await timers().advanceTimersByTimeAsync(ms);
			return utils;
		},
		advanceTimersToNextTimer() {
			timers().advanceTimersToNextTimer();
			return utils;
		},
		async advanceTimersToNextTimerAsync() {
			await timers().advanceTimersToNextTimerAsync();
			return utils;
		},
		advanceTimersToNextFrame() {
			timers().advanceTimersToNextFrame();
			return utils;
		},
		getTimerCount() {
			return timers().getTimerCount();
		},
		setSystemTime(time) {
			timers().setSystemTime(time);
			return utils;
		},
		getMockedSystemTime() {
			return timers().getMockedSystemTime();
		},
		getRealSystemTime() {
			return timers().getRealSystemTime();
		},
		clearAllTimers() {
			timers().clearAllTimers();
			return utils;
		},
		spyOn,
		fn,
		waitFor,
		waitUntil,
		hoisted(factory) {
			assertTypes(factory, "\"vi.hoisted\" factory", ["function"]);
			return factory();
		},
		mock(path, factory) {
			if (typeof path !== "string") throw new TypeError(`vi.mock() expects a string path, but received a ${typeof path}`);
			const importer = getImporter("mock");
			_mocker().queueMock(path, importer, typeof factory === "function" ? () => factory(() => _mocker().importActual(path, importer, _mocker().getMockContext().callstack)) : factory);
		},
		unmock(path) {
			if (typeof path !== "string") throw new TypeError(`vi.unmock() expects a string path, but received a ${typeof path}`);
			_mocker().queueUnmock(path, getImporter("unmock"));
		},
		doMock(path, factory) {
			if (typeof path !== "string") throw new TypeError(`vi.doMock() expects a string path, but received a ${typeof path}`);
			const importer = getImporter("doMock");
			_mocker().queueMock(path, importer, typeof factory === "function" ? () => factory(() => _mocker().importActual(path, importer, _mocker().getMockContext().callstack)) : factory);
		},
		doUnmock(path) {
			if (typeof path !== "string") throw new TypeError(`vi.doUnmock() expects a string path, but received a ${typeof path}`);
			const importer = getImporter("doUnmock");
			_mocker().queueUnmock(path, importer);
		},
		async importActual(path) {
			const importer = getImporter("importActual");
			return _mocker().importActual(path, importer, _mocker().getMockContext().callstack);
		},
		async importMock(path) {
			const importer = getImporter("importMock");
			return _mocker().importMock(path, importer);
		},
		mockObject(value, options) {
			return _mocker().mockObject({ value }, void 0, options?.spy ? "autospy" : "automock").value;
		},
		mocked(item, _options = {}) {
			return item;
		},
		isMockFunction(fn) {
			return isMockFunction(fn);
		},
		clearAllMocks() {
			clearAllMocks();
			return utils;
		},
		resetAllMocks() {
			resetAllMocks();
			return utils;
		},
		restoreAllMocks() {
			restoreAllMocks();
			return utils;
		},
		stubGlobal(name, value) {
			if (!_stubsGlobal.has(name)) _stubsGlobal.set(name, Object.getOwnPropertyDescriptor(globalThis, name));
			Object.defineProperty(globalThis, name, {
				value,
				writable: true,
				configurable: true,
				enumerable: true
			});
			return utils;
		},
		stubEnv(name, value) {
			const env = state().metaEnv;
			if (!_stubsEnv.has(name)) _stubsEnv.set(name, env[name]);
			if (_envBooleans.includes(name)) env[name] = value ? "1" : "";
			else if (value === void 0) delete env[name];
			else env[name] = String(value);
			return utils;
		},
		unstubAllGlobals() {
			_stubsGlobal.forEach((original, name) => {
				if (!original) Reflect.deleteProperty(globalThis, name);
				else Object.defineProperty(globalThis, name, original);
			});
			_stubsGlobal.clear();
			return utils;
		},
		unstubAllEnvs() {
			const env = state().metaEnv;
			_stubsEnv.forEach((original, name) => {
				if (original === void 0) delete env[name];
				else env[name] = original;
			});
			_stubsEnv.clear();
			return utils;
		},
		resetModules() {
			resetModules(state().evaluatedModules);
			return utils;
		},
		async dynamicImportSettled() {
			return waitForImportsToResolve();
		},
		setConfig(config) {
			if (!_config) _config = { ...state().config };
			Object.assign(state().config, config);
		},
		resetConfig() {
			if (_config) Object.assign(state().config, _config);
		}
	};
	return utils;
}
const vitest = createVitest();
const vi = vitest;
function _mocker() {
	// @ts-expect-error injected by vite-nide
	return typeof __vitest_mocker__ !== "undefined" ? __vitest_mocker__ : new Proxy({}, { get(_, name) {
		throw new Error(`Vitest mocker was not initialized in this environment. vi.${String(name)}() is forbidden.`);
	} });
}
function getImporter(name) {
	const stackArray = createSimpleStackTrace({ stackTraceLimit: 5 }).split("\n");
	return parseSingleStack(stackArray[stackArray.findLastIndex((stack) => {
		return stack.includes(` at Object.${name}`) || stack.includes(`${name}@`) || stack.includes(` at ${name} (`);
	}) + 1])?.file || "";
}

export { getSnapshotClient as a, assert as b, createExpect as c, vitest as d, globalExpect as g, inject as i, should as s, vi as v };
