fluxject
Version:
A strongly-typed dependency injection library.
615 lines (606 loc) • 93.1 kB
JavaScript
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