UNPKG

fluxject

Version:

A strongly-typed dependency injection library.

615 lines (606 loc) 93.1 kB
import { isPromise } from 'util/types'; // src/polyfills.js function addPolyfills() { Symbol.asyncDispose ??= Symbol.for("asyncDispose"); Symbol.dispose ??= Symbol.for("dispose"); } function needsPolyfills() { return typeof Symbol.dispose !== "symbol" || typeof Symbol.asyncDispose !== "symbol"; } // src/util.js var AsyncFunction = (async () => { }).constructor; function isConstructor(fn) { if (typeof fn !== "function") { return false; } if (fn instanceof AsyncFunction) { return false; } const prototype = fn.prototype; return prototype && typeof prototype === "object" && prototype.constructor === fn; } // src/errors.js var FluxjectError = class extends Error { /** * @param {string} message */ constructor(message) { super(message); this.name = "FluxjectError"; } }; // src/lazy-reference.js var LazyReference = class { /** * True if the service has been asynchronously disposed of. * @type {boolean} */ #asyncDisposed; /** * True if the service has been synchronously disposed of. * @type {boolean} */ #syncDisposed; /** * The actual instance of the service. * @type {TInstanceType|undefined} */ #instance; /** * Proxied `this` object, that intercepts properties and ensures instantation before actual property accessors are invoked. */ #proxy; /** * True if the service is transient. */ #isTransient; /** * Create a new lazy reference to an instance * @param {() => TInstanceType} instantiator * The function that will be used to instantiate the reference. * @param {boolean} isTransient * True if the reference is transient (will be disposed of after property de-referencing) */ constructor(instantiator, isTransient) { this.#syncDisposed = false; this.#instance = void 0; this.#isTransient = isTransient; this.#proxy = this.#createProxy(instantiator); return this.#proxy; } /** * Creates a Proxy for this object that intercepts property accessors and ensures that the instance is instantiated before access. * @param {() => TInstanceType} instantiator * The function that will be used to instantiate the reference. */ #createProxy(instantiator) { return new Proxy(this, { /** * Trap for getting properties, while instantiating if necessary, on the service. */ get: (target, property, receiver) => { if (this.#syncDisposed && this.#asyncDisposed) { return void 0; } if (this.#isTransient) { return this.#handleTransient(instantiator, property); } if (property === Symbol.dispose) { this.#syncDisposed = true; if (this.#instance === void 0) { return void 0; } } if (property === Symbol.asyncDispose) { this.#asyncDisposed = true; if (this.#instance === void 0) { return void 0; } } if (this.#instance === void 0) { this.#instance = instantiator(); } if (isPromise(this.#instance) && property !== "then") { return void 0; } const val = this.#instance[property]; if (val instanceof Function) { return (...args) => { const returnValue = val.bind(this.#instance)(...args); if (returnValue === this.#instance) { return this.#proxy; } return returnValue; }; } if (val === this.#instance) { return this.#proxy; } return val; }, /** * Trap for setting properties, while instantiating if necessary, on the service. */ set: (target, property, value) => { if (this.#isTransient) { throw new FluxjectError(`Cannot set properties on a transient reference.`); } if (property === Symbol.dispose || property === Symbol.asyncDispose) { throw new FluxjectError(`Cannot set dispose methods on services.`); } if (this.#instance === void 0) { this.#instance = instantiator(); } this.#instance[property] = value; return true; }, /** * Trap for checking if a property exists, while instantiating if necessary, on the service. */ has: (target, property) => { if (this.#isTransient) { throw new FluxjectError(`Cannot check for property existence on a transient reference.`); } if (this.#instance === void 0) { if (property === Symbol.dispose || property === Symbol.asyncDispose) { throw new FluxjectError(`Cannot check for dispose methods.`); } this.#instance = instantiator(); } return property in /** @type {any} */ this.#instance; }, /** * Trap for getting the prototype, while instantiating if necessary, of the service. */ getPrototypeOf: (target) => { if (this.#isTransient) { return false; } if (this.#instance === void 0) { this.#instance = instantiator(); } return Object.getPrototypeOf(this.#instance); }, /** * Trap for constructing the return value, while instantiating if necessary, of the service. */ construct: (target, args, newTarget) => { if (this.#instance === void 0) { this.#instance = instantiator(); } if (!isConstructor(this.#instance)) { throw new FluxjectError(`Cannot construct a non-constructor instance.`); } return new this.#instance(...args); } }); } /** * Handles the get trap for transient services. * @param {() => TInstanceType} instantiator * Instantiation function that will return the service. * @param {string|symbol} property * The property that is being requested from the service. */ #handleTransient(instantiator, property) { this.#asyncDisposed = false; this.#syncDisposed = false; this.#instance = void 0; if (property === Symbol.dispose || property === Symbol.asyncDispose) { return void 0; } if (property === "then") { return this.#proxy; } const instance = instantiator(); if (instance[property] instanceof Function) { return (...args) => { const returnValue2 = instance[property].bind(instance)(...args); if (isPromise(returnValue2)) { return returnValue2.then(async (promiseReturnValue) => { instance[Symbol.dispose]?.(); await instance[Symbol.asyncDispose]?.(); if (promiseReturnValue === instance) { return this.#proxy; } return promiseReturnValue; }); } instance[Symbol.dispose]?.(); instance[Symbol.asyncDispose]?.(); if (returnValue2 === instance) { return this.#proxy; } return returnValue2; }; } const returnValue = instance[property]; instance[Symbol.dispose]?.(); instance[Symbol.asyncDispose]?.(); if (returnValue === instance) { return this.#proxy; } return returnValue; } }; // src/provider.js var FluxjectHostServiceProvider = class { #registrations; /** @type {Record<string, LazyReference<any>|undefined>} */ #references; /** @type {FluxjectScopedServiceProvider[]} */ #scopedServices; /** * Construct a new `FluxjectHostServiceProvider` instance. * @param {TRegistrations} registrations * Registrations configured on the container. */ constructor(registrations) { this.#scopedServices = []; const registrationEntries = Object.entries(registrations); const referenceEntries = registrationEntries.filter(([name, registration]) => registration.lifetime !== "scoped").map(([name, registration]) => { if (registration.lifetime === "transient") { return [name, reference(name, registration, injectable(this, name), true)]; } if (registration.lifetime === "singleton") { return [name, reference(name, registration, injectable(this, name), false)]; } throw new Error(`Unknown lifetime ${registration.lifetime}`); }); const newReferences = Object.fromEntries(referenceEntries); this.#registrations = { ...this.#registrations, ...registrations }; this.#references = { ...this.#references, ...newReferences }; for (const serviceName in this.#references) { Object.defineProperty(this, serviceName, { get: () => { return this.#references[serviceName]; } }); } } /** * Create a new scoped service provider. All Scoped Services will * @returns {Types.Widen<FluxjectScopedServiceProvider<TRegistrations> & Types.InferInstanceTypes<TRegistrations>>} * A new Scoped Service Provider. */ createScope() { const scopedService = new FluxjectScopedServiceProvider(this.#references, this.#registrations); this.#scopedServices.push(scopedService); const originalDispose = scopedService.dispose; scopedService.dispose = () => { const index = this.#scopedServices.indexOf(scopedService); if (index === -1) { return; } this.#scopedServices.splice(index, 1); return originalDispose.bind(scopedService)(); }; return ( /** @type {any} */ scopedService ); } /** * Dispose of all services under this provider. * * This will also dispose of all scoped services that have been created by this provider. * * @returns {keyof {[K in keyof Types.InferInstanceTypes<TRegistrations, "singleton"|"transient"> as Types.InferInstanceTypes<TRegistrations, "singleton"|"transient">[K] extends { [Symbol.asyncDispose]: () => Promise<void> } ? K : never]: undefined} extends never ? void : Promise<void>} * Returns a Promise if any of the services have the `Symbol.asyncDispose` method defined. */ dispose() { try { this.#registrations; } catch (err) { if (err instanceof TypeError && err.message.startsWith("Cannot read properties of undefined")) { throw new Error("Cannot call dispose from receiver other than the original provider. (If you are passing [{provider}.dispose] around, then try using [() => {provider}.dispose()] instead)"); } throw err; } const disposeScopes = () => { const promises = []; for (const scopedService of this.#scopedServices) { const maybePromise = scopedService.dispose(); if (isPromise(maybePromise)) { promises.push(maybePromise); } } if (promises.length > 0) { return Promise.all(promises).then(() => { this.#scopedServices = []; }); } this.#scopedServices = []; }; const disposeSingletons = () => { const promises = []; for (const key in this.#references) { const service = this.#references[key]; if (!service) { continue; } service[Symbol.dispose]?.(); const maybePromise = ( /** @type {any} */ service[Symbol.asyncDispose]?.() ); if (isPromise(maybePromise)) { promises.push(maybePromise); } delete this.#references[key]; } if (promises.length > 0) { return Promise.all(promises).then(() => { this.#references = {}; }); } this.#references = {}; }; const disposeScopesResult = disposeScopes(); if (isPromise(disposeScopesResult)) { return ( /** @type {any} */ disposeScopesResult.then(disposeSingletons).then(() => void 0) ); } return ( /** @type {any} */ disposeSingletons() ); } }; var FluxjectScopedServiceProvider = class { #registrations; /** @type {Record<string, LazyReference<any>|undefined>} */ #references; /** * Construct a new `FluxjectScopedServiceProvider` instance. * @param {Record<string, LazyReference<any>|undefined>} references * References to Singletons and Transients from the Host Service Provider. * @param {TRegistrations} registrations * Registrations configured on the container. */ constructor(references, registrations) { const registrationEntries = Object.entries(registrations); const referenceEntries = registrationEntries.filter(([name, registration]) => registration.lifetime === "scoped").map(([name, registration]) => { return [name, reference(name, registration, injectable(this, name), false)]; }); const newReferences = Object.fromEntries(referenceEntries); this.#registrations = { ...registrations }; this.#references = { ...references, ...newReferences }; for (const registrationName in registrations) { Object.defineProperty(this, registrationName, { get: () => { return this.#references[registrationName]; } }); } } /** * Dispose of all Scoped services under this provider. * * This will also dispose of all scoped services that have been created by this provider. * * @returns {keyof {[K in keyof Types.InferInstanceTypes<TRegistrations, "scoped"> as Types.InferInstanceTypes<TRegistrations, "scoped">[K] extends { [Symbol.asyncDispose]: () => Promise<void> } ? K : never]: undefined} extends never ? void : Promise<void>} * Returns a Promise if any of the services have the `Symbol.asyncDispose` method defined. */ dispose() { try { this.#registrations; } catch (err) { if (err instanceof TypeError && err.message.startsWith("Cannot read properties of undefined")) { throw new Error("Cannot call dispose from receiver other than the original provider. (If you are passing [{provider}.dispose] around, then try using [() => {provider}.dispose()] instead)"); } throw err; } let promises = []; for (const key in this.#registrations) { const registration = this.#registrations[key]; if (registration.lifetime !== "scoped") { continue; } const service = this.#references[key]; if (!service) { continue; } service[Symbol.dispose]?.(); const maybePromise = ( /** @type {any} */ service[Symbol.asyncDispose]?.() ); if (isPromise(maybePromise)) { promises.push(maybePromise); } delete this.#references[key]; } this.#references = {}; if (promises.length > 0) { return Promise.all(promises).then(() => { }); } return ( /** @type {void} */ void 0 ); } }; var CircularDependencyError = class extends RangeError { /** * @param {string} serviceName * @param {any} stackTrace */ constructor(serviceName, stackTrace) { super(`Cannot resolve circular dependency (Origin: ${serviceName})`); this.name = "CircularDependencyError"; Error.prepareStackTrace?.(this, stackTrace); } }; function reference(name, registration, scope, isTransient) { const factory = registration.factory; const stackTrace = {}; const instantiator = () => { try { if (isConstructor(factory)) { const instance = new factory(scope); return instance; } return factory(scope); } catch (err) { if (err instanceof RangeError) { throw new CircularDependencyError(name, stackTrace); } throw err; } }; Error.captureStackTrace(stackTrace, instantiator); return new LazyReference(instantiator, isTransient); } function injectable(provider, registrationName) { return new Proxy(provider, { get: (t, p, r) => { if (p === registrationName || p === "createScope" || p === "dispose") { return void 0; } return provider[p]; }, has: (t, p) => { if (p === registrationName || p === "createScope" || p === "dispose") { return false; } return p in provider; } }); } // src/builder.js var RegistrationBuilder = class { /** * Register a new set of dependencies with the lifetime of "scoped". * @template {Record<string, Types.Instantiator<any>>} TInstantiators * Inferred instantiators from `newRegistrations` * @param {TInstantiators} newRegistrations * An object containing the new registrations to add, where the values are class constructors or factory functions. * @returns {{[K in keyof TInstantiators]: Types.Registration<TInstantiators[K], "scoped">}} * A new set of registrations with the lifetime of "scoped". */ scoped(newRegistrations) { let registrations = {}; for (const key in newRegistrations) { registrations[key] = { lifetime: "scoped", factory: newRegistrations[key] }; } return registrations; } /** * Register a new set of dependencies with the lifetime of "singleton". * @template {Record<string, Types.Instantiator<any>>} TInstantiators * Inferred instantiators from `newRegistrations` * @param {TInstantiators} newRegistrations * An object containing the new registrations to add, where the values are class constructors or factory functions. * @returns {{[K in keyof TInstantiators]: Types.Registration<TInstantiators[K], "singleton">}} * A new set of registrations with the lifetime of "singleton". */ singleton(newRegistrations) { let registrations = {}; for (const key in newRegistrations) { registrations[key] = { lifetime: "singleton", factory: newRegistrations[key] }; } return registrations; } /** * Register a new set of dependencies with * @template {Record<string, Types.Instantiator<any>>} TInstantiators * Inferred instantiators from `newRegistrations` * @param {TInstantiators} newRegistrations * An object containing the new registrations to add, where the values are class constructors or factory functions. * @returns {{[K in keyof TInstantiators]: Types.Registration<TInstantiators[K], "transient">}} * A new set of registrations with the lifetime of "transient". */ transient(newRegistrations) { let registrations = {}; for (const key in newRegistrations) { registrations[key] = { lifetime: "transient", factory: newRegistrations[key] }; } return registrations; } }; // src/container.js var Container = class _Container { #registrations; /** * Create a new container for managing dependencies. (Alias of `fluxject()`) * @returns {Container<{}>} */ static create() { return new _Container({}); } /** * @protected * @param {TRegistrations} registrations */ constructor(registrations) { this.#registrations = registrations; } /** * Register a new set of dependencies to the container * @template {Record<string, Types.Registration<any, any>>} TNewRegistrations * The new registrations as inferred from the return type of the callback. * @param {(serviceBuilder: RegistrationBuilder) => TNewRegistrations} callback * The callback that will be used to register new services. * @returns {Container<TRegistrations & TNewRegistrations>} * A new container with the new registrations added. */ register(callback) { const registrations = callback(new RegistrationBuilder()); return new _Container({ ...this.#registrations, ...registrations }); } /** * Prepare the container for consumption. * @returns {Types.Widen<FluxjectHostServiceProvider<TRegistrations> & Types.InferInstanceTypes<TRegistrations, "singleton"|"transient">>} */ prepare() { return ( /** @type {any} */ new FluxjectHostServiceProvider(this.#registrations) ); } }; // src/index.js if (needsPolyfills()) { addPolyfills(); } function fluxject() { return Container.create(); } function abstract(registration) { return ( /** @type {any} */ registration ); } export { Container, abstract, fluxject }; //# sourceMappingURL=index.js.map //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NyYy9wb2x5ZmlsbHMuanMiLCIuLi9zcmMvdXRpbC5qcyIsIi4uL3NyYy9lcnJvcnMuanMiLCIuLi9zcmMvbGF6eS1yZWZlcmVuY2UuanMiLCIuLi9zcmMvcHJvdmlkZXIuanMiLCIuLi9zcmMvYnVpbGRlci5qcyIsIi4uL3NyYy9jb250YWluZXIuanMiLCIuLi9zcmMvaW5kZXguanMiXSwibmFtZXMiOlsicmV0dXJuVmFsdWUiLCJpc1Byb21pc2UiXSwibWFwcGluZ3MiOiI7OztBQUVPLFNBQVMsWUFBZSxHQUFBO0FBRTNCLEVBQU8sTUFBQSxDQUFBLFlBQUEsS0FBaUIsTUFBTyxDQUFBLEdBQUEsQ0FBSSxjQUFjLENBQUE7QUFFakQsRUFBTyxNQUFBLENBQUEsT0FBQSxLQUFZLE1BQU8sQ0FBQSxHQUFBLENBQUksU0FBUyxDQUFBO0FBQzNDO0FBRU8sU0FBUyxjQUFpQixHQUFBO0FBQzdCLEVBQUEsT0FBTyxPQUFPLE1BQU8sQ0FBQSxPQUFBLEtBQVksUUFBWSxJQUFBLE9BQU8sT0FBTyxZQUFpQixLQUFBLFFBQUE7QUFDaEY7OztBQ1JBLElBQU0saUJBQWlCLFlBQVk7QUFBQyxDQUFHLEVBQUEsV0FBQTtBQVdoQyxTQUFTLGNBQWMsRUFBSSxFQUFBO0FBQzlCLEVBQUcsSUFBQSxPQUFPLE9BQU8sVUFBWSxFQUFBO0FBQ3pCLElBQU8sT0FBQSxLQUFBO0FBQUE7QUFFWCxFQUFBLElBQUcsY0FBYyxhQUFlLEVBQUE7QUFDNUIsSUFBTyxPQUFBLEtBQUE7QUFBQTtBQUVYLEVBQUEsTUFBTSxZQUFZLEVBQUcsQ0FBQSxTQUFBO0FBQ3JCLEVBQUEsT0FBTyxTQUFhLElBQUEsT0FBTyxTQUFjLEtBQUEsUUFBQSxJQUFZLFVBQVUsV0FBZ0IsS0FBQSxFQUFBO0FBQ25GOzs7QUNnQ08sSUFBTSxhQUFBLEdBQU4sY0FBNEIsS0FBTSxDQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUEsRUFJckMsWUFBWSxPQUFTLEVBQUE7QUFDakIsSUFBQSxLQUFBLENBQU0sT0FB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dCI6WyIvL0B0cy1jaGVja1xuXG5leHBvcnQgZnVuY3Rpb24gYWRkUG9seWZpbGxzKCkge1xuICAgIC8vQHRzLWlnbm9yZVxuICAgIFN5bWJvbC5hc3luY0Rpc3Bvc2UgPz89IFN5bWJvbC5mb3IoXCJhc3luY0Rpc3Bvc2VcIik7XG4gICAgLy9AdHMtaWdub3JlXG4gICAgU3ltYm9sLmRpc3Bvc2UgPz89IFN5bWJvbC5mb3IoXCJkaXNwb3NlXCIpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gbmVlZHNQb2x5ZmlsbHMoKSB7XG4gICAgcmV0dXJuIHR5cGVvZiBTeW1ib2wuZGlzcG9zZSAhPT0gXCJzeW1ib2xcIiB8fCB0eXBlb2YgU3ltYm9sLmFzeW5jRGlzcG9zZSAhPT0gXCJzeW1ib2xcIjtcbn0iLCIvL0B0cy1jaGVja1xuXG4vKiogQHJlYWRvbmx5ICovXG5jb25zdCBBc3luY0Z1bmN0aW9uID0gKGFzeW5jICgpID0+IHt9KS5jb25zdHJ1Y3RvcjtcblxuLyoqXG4gKiBDaGVjayBpZiB0aGUgZ2l2ZW4gZnVuY3Rpb24sIGBmbmAsIGlzIGEgY29uc3RydWN0b3IuXG4gKiBcbiAqIFRoaXMgd2lsbCBub3QgaW52b2tlIHRoZSBjb25zdHJ1Y3RvclxuICogQHBhcmFtIHthbnl9IGZuIFxuICogRnVuY3Rpb24gdG8gY2hlY2suXG4gKiBAcmV0dXJucyB7Zm4gaXMgKG5ldyAoLi4uYXJnczogYW55W10pID0+IGFueSl9XG4gKiBUcnVlIGlmIHRoZSBmdW5jdGlvbiBpcyBhIGNvbnN0cnVjdG9yLCBvdGhlcndpc2UgZmFsc2UuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc0NvbnN0cnVjdG9yKGZuKSB7XG4gICAgaWYodHlwZW9mIGZuICE9PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICBpZihmbiBpbnN0YW5jZW9mIEFzeW5jRnVuY3Rpb24pIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICBjb25zdCBwcm90b3R5cGUgPSBmbi5wcm90b3R5cGU7XG4gICAgcmV0dXJuIHByb3RvdHlwZSAmJiB0eXBlb2YgcHJvdG90eXBlID09PSAnb2JqZWN0JyAmJiBwcm90b3R5cGUuY29uc3RydWN0b3IgPT09IGZuO1xufSIsIi8vQHRzLWNoZWNrXG4vKipcbiAqIFRocm93biB3aGVuIGEgY2lyY3VsYXIgZGVwZW5kZW5jeSBpcyBkZXRlY3RlZC4gIFxuICogXG4gKiBUaGlzIHR5cGljYWxseSBvY2N1cnMgd2hlbiB0d28gc2VydmljZXMgZGVwZW5kIG9uIGVhY2ggb3RoZXIgaW5zaWRlIHRoZWlyIGNvbnN0cnVjdG9ycy5cbiAqIFxuICogWW91IGNhbiByZXNvbHZlIHRoaXMgYnkgZGVmZXJyaW5nIGFueSBkZS1yZWZlcmVuY2Ugb2YgeW91ciBkZXBlbmRlbmNpZXMgdW50aWwgYWZ0ZXIgdGhlIGNvbnN0cnVjdG9yIGhhcyBjb21wbGV0ZWQuXG4gKiBcbiAqIEBleGFtcGxlXG4gKiBgYGB0c1xuICogLy8gVGhpcyB3b3VsZCBjYXVzZSBhIGNpcmN1bGFyIGRlcGVuZGVuY3lcbiAqIGNsYXNzIERlcGVuZGVuY3lBIHtcbiAqICAgdGVzdCA9IDE7XG4gKiAgIGNvbnN0cnVjdG9yKHsgZGVwZW5kZW5jeUIgfSkge1xuICogICAgIGRlcGVuZGVuY3lCLnRlc3Q7XG4gKiAgIH1cbiAqIH1cbiAqIFxuICogY2xhc3MgRGVwZW5kZW5jeUIge1xuICogICB0ZXN0ID0gMjtcbiAqICAgY29uc3RydWN0b3IoeyBkZXBlbmRlbmN5QSB9KSB7XG4gKiAgICAgZGVwZW5kZW5jeUEudGVzdDtcbiAqICAgfVxuICogfVxuICogXG4gKiAvLyBidXQgdGhpcyB3b3VsZCBiZSBva1xuICogY2xhc3MgRGVwZW5kZW5jeUMge1xuICogICB0ZXN0ID0gMTtcbiAqICAgI2RlcGVuZGVuY3lEO1xuICogICBjb25zdHJ1Y3Rvcih7IGRlcGVuZGVuY3lEIH0pIHtcbiAqICAgICB0aGlzLiNkZXBlbmRlbmN5RCA9IGRlcGVuZGVuY3lEO1xuICogICB9XG4gKiB9XG4gKiBcbiAqIC8vIFlvdSBjYW4gc3RpbGwgZGUtcmVmZXJlbmNlIGZyb20gb25lIG9mIHRoZSBkZXBlbmRlbmNpZXMsIHRob3VnaDpcbiAqIGNsYXNzIERlcGVuZGVuY3lEIHtcbiAqICAgdGVzdCA9IDI7XG4gKiAgIGNvbnN0cnVjdG9yKHsgZGVwZW5kZW5jeUMgfSkge1xuICogICAgIGRlcGVuZGVuY3lDLnRlc3Q7XG4gKiAgIH1cbiAqIH1cbiAqIGBgYFxuICovXG5leHBvcnQgY2xhc3MgQ2lyY3VsYXJEZXBlbmRlbmN5RXJyb3IgZXh0ZW5kcyBSYW5nZUVycm9yIHtcbiAgICAvKipcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gc2VydmljZU5hbWUgXG4gICAgICogQHBhcmFtIHthbnl9IHN0YWNrVHJhY2VcbiAgICAgKi9cbiAgICBjb25zdHJ1Y3RvcihzZXJ2aWNlTmFtZSwgc3RhY2tUcmFjZSkge1xuICAgICAgICBzdXBlcihgQ2Fubm90IHJlc29sdmUgY2lyY3VsYXIgZGVwZW5kZW5jeSAoT3JpZ2luOiAke3NlcnZpY2VOYW1lfSlgKTtcbiAgICAgICAgdGhpcy5uYW1lID0gXCJDaXJjdWxhckRlcGVuZGVuY3lFcnJvclwiO1xuICAgICAgICBFcnJvci5wcmVwYXJlU3RhY2tUcmFjZT8uKHRoaXMsIHN0YWNrVHJhY2UpO1xuICAgIH1cbn07XG5cbmV4cG9ydCBjbGFzcyBGbHV4amVjdEVycm9yIGV4dGVuZHMgRXJyb3Ige1xuICAgIC8qKlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBtZXNzYWdlIFxuICAgICAqL1xuICAgIGNvbnN0cnVjdG9yKG1lc3NhZ2UpIHtcbiAgICAgICAgc3VwZXIobWVzc2FnZSk7XG4gICAgICAgIHRoaXMubmFtZSA9IFwiRmx1eGplY3RFcnJvclwiO1xuICAgIH1cbn0iLCJcbi8vQHRzLWNoZWNrXG5pbXBvcnQgeyBpc1Byb21pc2UgfSBmcm9tIFwidXRpbC90eXBlc1wiO1xuaW1wb3J0IHsgaXNDb25zdHJ1Y3RvciB9IGZyb20gXCIuL3V0aWwuanNcIjtcbmltcG9ydCB7IEZsdXhqZWN0RXJyb3IgfSBmcm9tIFwiLi9lcnJvcnMuanNcIjtcblxuLyoqXG4gKiBPYmplY3QgdGhhdCBhbGxvd3MgZm9yIHNlcnZpY2VzIHRvIGJlIGxhemlseSBpbnN0YW50aWF0ZWQuXG4gKiBcbiAqICAgLSBTaW5nbGV0b24gYW5kIFNjb3BlZCBzZXJ2aWNlcyB3aWxsIHN0b3JlIHRoZWlyIGluc3RhbmNlIGFmdGVyIHRoZSBmaXJzdCBwcm9wZXJ0eSBhY2Nlc3MuXG4gKiAgIC0gVHJhbnNpZW50IHNlcnZpY2VzIHdpbGwgZGlzcG9zZSBvZiB0aGVpciBpbnN0YW5jZSBpbW1lZGlhdGVseSBhZnRlciB0aGUgZmlyc3QgcHJvcGVydHkgYWNjZXNzLlxuICogICAgIC0gSWYgdGhlIHByb3BlcnR5IGFjY2Vzc29yIHdhcyBhIGZ1bmN0aW9uLCB0aGUgaW5zdGFuY2Ugd2lsbCBiZSBkaXNwb3NlZCBvZiBhZnRlciB0aGUgZnVuY3Rpb24gaXMgaW52b2tlZC5cbiAqIEB0ZW1wbGF0ZSBUSW5zdGFuY2VUeXBlXG4gKi9cbmV4cG9ydCBjbGFzcyBMYXp5UmVmZXJlbmNlIHtcbiAgICAvKipcbiAgICAgKiBUcnVlIGlmIHRoZSBzZXJ2aWNlIGhhcyBiZWVuIGFzeW5jaHJvbm91c2x5IGRpc3Bvc2VkIG9mLiBcbiAgICAgKiBAdHlwZSB7Ym9vbGVhbn0gXG4gICAgICovXG4gICAgI2FzeW5jRGlzcG9zZWQ7XG4gICAgLyoqXG4gICAgICogVHJ1ZSBpZiB0aGUgc2VydmljZSBoYXMgYmVlbiBzeW5jaHJvbm91c2x5IGRpc3Bvc2VkIG9mLiBcbiAgICAgKiBAdHlwZSB7Ym9vbGVhbn0gXG4gICAgICovXG4gICAgI3N5bmNEaXNwb3NlZDtcbiAgICAvKiogXG4gICAgICogVGhlIGFjdHVhbCBpbnN0YW5jZSBvZiB0aGUgc2VydmljZS5cbiAgICAgKiBAdHlwZSB7VEluc3RhbmNlVHlwZXx1bmRlZmluZWR9IFxuICAgICAqL1xuICAgICNpbnN0YW5jZTtcblxuICAgIC8qKlxuICAgICAqIFByb3hpZWQgYHRoaXNgIG9iamVjdCwgdGhhdCBpbnRlcmNlcHRzIHByb3BlcnRpZXMgYW5kIGVuc3VyZXMgaW5zdGFudGF0aW9uIGJlZm9yZSBhY3R1YWwgcHJvcGVydHkgYWNjZXNzb3JzIGFyZSBpbnZva2VkLlxuICAgICAqL1xuICAgICNwcm94eTtcblxuICAgIC8qKlxuICAgICAqIFRydWUgaWYgdGhlIHNlcnZpY2UgaXMgdHJhbnNpZW50LlxuICAgICAqL1xuICAgICNpc1RyYW5zaWVudDtcblxuICAgIC8qKlxuICAgICAqIENyZWF0ZSBhIG5ldyBsYXp5IHJlZmVyZW5jZSB0byBhbiBpbnN0YW5jZVxuICAgICAqIEBwYXJhbSB7KCkgPT4gVEluc3RhbmNlVHlwZX0gaW5zdGFudGlhdG9yIFxuICAgICAqIFRoZSBmdW5jdGlvbiB0aGF0IHdpbGwgYmUgdXNlZCB0byBpbnN0YW50aWF0ZSB0aGUgcmVmZXJlbmNlLlxuICAgICAqIEBwYXJhbSB7Ym9vbGVhbn0gaXNUcmFuc2llbnRcbiAgICAgKiBUcnVlIGlmIHRoZSByZWZlcmVuY2UgaXMgdHJhbnNpZW50ICh3aWxsIGJlIGRpc3Bvc2VkIG9mIGFmdGVyIHByb3BlcnR5IGRlLXJlZmVyZW5jaW5nKVxuICAgICAqL1xuICAgIGNvbnN0cnVjdG9yKGluc3RhbnRpYXRvciwgaXNUcmFuc2llbnQpIHtcbiAgICAgICAgdGhpcy4jc3luY0Rpc3Bvc2VkID0gZmFsc2U7XG4gICAgICAgIHRoaXMuI2luc3RhbmNlID0gdW5kZWZpbmVkO1xuICAgICAgICB0aGlzLiNpc1RyYW5zaWVudCA9IGlzVHJhbnNpZW50O1xuICAgICAgICB0aGlzLiNwcm94eSA9IHRoaXMuI2NyZWF0ZVByb3h5KGluc3RhbnRpYXRvcik7XG4gICAgICAgIHJldHVybiB0aGlzLiNwcm94eTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGEgUHJveHkgZm9yIHRoaXMgb2JqZWN0IHRoYXQgaW50ZXJjZXB0cyBwcm9wZXJ0eSBhY2Nlc3NvcnMgYW5kIGVuc3VyZXMgdGhhdCB0aGUgaW5zdGFuY2UgaXMgaW5zdGFudGlhdGVkIGJlZm9yZSBhY2Nlc3MuXG4gICAgICogQHBhcmFtIHsoKSA9PiBUSW5zdGFuY2VUeXBlfSBpbnN0YW50aWF0b3IgXG4gICAgICogVGhlIGZ1bmN0aW9uIHRoYXQgd2lsbCBiZSB1c2VkIHRvIGluc3RhbnRpYXRlIHRoZSByZWZlcmVuY2UuXG4gICAgICovXG4gICAgI2NyZWF0ZVByb3h5KGluc3RhbnRpYXRvcikge1xuICAgICAgICByZXR1cm4gbmV3IFByb3h5KHRoaXMsIHtcbiAgICAgICAgICAgIC8qKlxuICAgICAgICAgICAgICogVHJhcCBmb3IgZ2V0dGluZyBwcm9wZXJ0aWVzLCB3aGlsZSBpbnN0YW50aWF0aW5nIGlmIG5lY2Vzc2FyeSwgb24gdGhlIHNlcnZpY2UuXG4gICAgICAgICAgICAgKi9cbiAgICAgICAgICAgIGdldDogKHRhcmdldCxwcm9wZXJ0eSxyZWNlaXZlcikgPT4ge1xuICAgICAgICAgICAgICAgIC8vIElmIHRoZSBzZXJ2aWNlIGhhcyBhbHJlYWR5IGJlZW4gZnVsbHkgZGlzcG9zZWQsIHJldHVybiB1bmRlZmluZWQuXG4gICAgICAgICAgICAgICAgaWYodGhpcy4jc3luY0Rpc3Bvc2VkICYmIHRoaXMuI2FzeW5jRGlzcG9zZWQpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAvLyBJZiB0aGUgc2VydmljZSBpcyBhIFRyYW5zaWVudCBzZXJ2aWNlLCB0aGVuIHRoZXkgd2lsbCB1bmRlcmdvIGEgZGlmZmVyZW50IHByb2Nlc3MuXG4gICAgICAgICAgICAgICAgaWYodGhpcy4jaXNUcmFuc2llbnQpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuI2hhbmRsZVRyYW5zaWVudChpbnN0YW50aWF0b3IsIHByb3BlcnR5KTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAvLyBJZiB0aGUgcHJvcGVydHkgaXMgYSBzeW5jaHJvbm91cyBkaXNwb3NlIG1ldGhvZCwgdGhlbiB0cmFjayB0aGF0IHRoaXMgc2VydmljZSBpcyBkaXNwb3NlZCAoc3luY2hyb25vdXNseSkuXG4gICAgICAgICAgICAgICAgaWYocHJvcGVydHkgPT09IFN5bWJvbC5kaXNwb3NlKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuI3N5bmNEaXNwb3NlZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgICAgIC8vIFByZXZlbnQgdXNlcnMgZnJvbSBkaXNwb3NpbmcgYW4gaW5zdGFuY2UgdGhhdCBoYXMgbm90IGJlZW4gaW5zdGFudGlhdGVkIHlldC5cbiAgICAgICAgICAgICAgICAgICAgaWYodGhpcy4jaW5zdGFuY2UgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIC8vIElmIHRoZSBwcm9wZXJ0eSBpcyBhbiBhc3luY2hyb25vdXMgZGlzcG9zZSBtZXRob2QsIHRoZW4gdHJhY2sgdGhhdCB0aGlzIHNlcnZpY2UgaXMgZGlzcG9zZWQgKGFzeW5jaHJvbm91c2x5KS5cbiAgICAgICAgICAgICAgICBpZihwcm9wZXJ0eSA9PT0gU3ltYm9sLmFzeW5jRGlzcG9zZSkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLiNhc3luY0Rpc3Bvc2VkID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICAgICAgLy8gUHJldmVudCB1c2VycyBmcm9tIGRpc3Bvc2luZyBhbiBpbnN0YW5jZSB0aGF0IGhhcyBub3QgYmVlbiBpbnN0YW50aWF0ZWQgeWV0LlxuICAgICAgICAgICAgICAgICAgICBpZih0aGlzLiNpbnN0YW5jZSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgLy8gSWYgdGhlIGluc3RhbmNlIGhhcyBub3QgYmVlbiBpbnN0YW50aWF0ZWQgeWV0LCB0aGVuIGluc3RhbnRpYXRlIGl0LlxuICAgICAgICAgICAgICAgIGlmKHRoaXMuI2luc3RhbmNlID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy4jaW5zdGFuY2UgPSBpbnN0YW50aWF0b3IoKTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAvLyBJZiB0aGUgaW5zdGFuY2UgaXMgYSBwcm9taXNlIGFuZCB0aGUgcHJvcGVydHkgaXMgbm90IGB0aGVuYCwgdGhlbiByZXR1cm4gdW5kZWZpbmVkLlxuICAgICAgICAgICAgICAgIGlmKGlzUHJvbWlzZSh0aGlzLiNpbnN0YW5jZSkgJiYgcHJvcGVydHkgIT09IFwidGhlblwiKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIFxuICAgICAgICAgICAgICAgIC8vIEdldCB0aGUgdmFsdWUgb2YgdGhlIHByb3BlcnR5LlxuICAgICAgICAgICAgICAgIGNvbnN0IHZhbCA9IHRoaXMuI2luc3RhbmNlW3Byb3BlcnR5XTtcbiAgICAgICAgICAgICAgICBcbiAgICAgICAgICAgICAgICAvLyBJZiB0aGUgdmFsdWUgaXMgYSBmdW5jdGlvbiwgYmluZCB0aGUgZnVuY3Rpb24gdG8gdGhlIGluc3RhbmNlLlxuICAgICAgICAgICAgICAgIGlmKHZhbCBpbnN0YW5jZW9mIEZ1bmN0aW9uKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiAoLi4uYXJncykgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgcmV0dXJuVmFsdWUgPSB2YWwuYmluZCh0aGlzLiNpbnN0YW5jZSkoLi4uYXJncyk7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIElmIHRoZSByZXR1cm4gdmFsdWUgaXMgYSByZWZlcmVuY2UgdG8gdGhpcyBzZXJ2aWNlLCB0aGVuIHJldHVybiB0aGlzIHJlZmVyZW5jZS5cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vICAgVGhpcyBpcyB0byBlbnN1cmUgdGhhdCBpZiB0aGUgcHJvdmlkZXIgaXMgZGlzcG9zZWQsIHRoZSB1c2VyIGNhbm5vdCBhY2NpZGVudGFsbHlcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vICAgcmVmZXJlbmNlIGRhdGEgdGhhdCBtYXkgbm8gbG9uZ2VyIGV4aXN0cy5cbiAgICAgICAgICAgICAgICAgICAgICAgIGlmKHJldHVyblZhbHVlID09PSB0aGlzLiNpbnN0YW5jZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLiNwcm94eTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiByZXR1cm5WYWx1ZTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIC8vIElmIHRoZSB2YWx1ZSBpcyBhIHJlZmVyZW5jZSB0byB0aGlzIHNlcnZpY2UsIHRoZW4gcmV0dXJuIHRoaXMgcmVmZXJlbmNlLlxuICAgICAgICAgICAgICAgIC8vICAgVGhpcyBpcyB0byBlbnN1cmUgdGhhdCBpZiB0aGUgcHJvdmlkZXIgaXMgZGlzcG9zZWQsIHRoZSB1c2VyIGNhbm5vdCBhY2NpZGVudGFsbHlcbiAgICAgICAgICAgICAgICAvLyAgIHJlZmVyZW5jZSBkYXRhIHRoYXQgbWF5IG5vIGxvbmdlciBleGlzdHMuXG4gICAgICAgICAgICAgICAgaWYodmFsID09PSB0aGlzLiNpbnN0YW5jZSkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy4jcHJveHk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgLy8gUmVxdWVzdGVkIHByb3BlcnR5IGlzIG5vdCBhIGZ1bmN0aW9uLCByZXR1cm4gdGhlIHZhbHVlLlxuICAgICAgICAgICAgICAgIHJldHVybiB2YWw7XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgLyoqXG4gICAgICAgICAgICAgKiBUcmFwIGZvciBzZXR0aW5nIHByb3BlcnRpZXMsIHdoaWxlIGluc3RhbnRpYXRpbmcgaWYgbmVjZXNzYXJ5LCBvbiB0aGUgc2VydmljZS5cbiAgICAgICAgICAgICAqL1xuICAgICAgICAgICAgc2V0OiAodGFyZ2V0LHByb3BlcnR5LHZhbHVlKSA9PiB7XG4gICAgICAgICAgICAgICAgLy8gSWYgdGhlIHNlcnZpY2UgaXMgdHJhbnNpZW50LCB0aGVuIHRocm93IGFuIGVycm9yLlxuICAgICAgICAgICAgICAgIGlmKHRoaXMuI2lzVHJhbnNpZW50KSB7XG4gICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBGbHV4amVjdEVycm9yKGBDYW5ub3Qgc2V0IHByb3BlcnRpZXMgb24gYSB0cmFuc2llbnQgcmVmZXJlbmNlLmApO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIC8vIElmIHRoZSBwcm9wZXJ0eSBpcyBhIGRpc3Bvc2UgbWV0aG9kLCB0aGVuIHRocm93IGFuIGVycm9yLiBcbiAgICAgICAgICAgICAgICBpZihwcm9wZXJ0eSA9PT0gU3ltYm9sLmRpc3Bvc2UgfHwgcHJvcGVydHkgPT09IFN5bWJvbC5hc3luY0Rpc3Bvc2UpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEZsdXhqZWN0RXJyb3IoYENhbm5vdCBzZXQgZGlzcG9zZSBtZXRob2RzIG9uIHNlcnZpY2VzLmApO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIC8vIElmIHRoZSBpbnN0YW5jZSBoYXMgbm90IGJlZW4gaW5zdGFudG