UNPKG

@angular/core

Version:

Angular - the core framework

702 lines 70.2 kB
/** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ /** * @license * Copyright Google Inc. All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ import '../util/ng_dev_mode'; import { throwCyclicDependencyError, throwInvalidProviderError, throwMixedMultiProviderError } from '../render3/errors'; import { stringify } from '../util/stringify'; import { resolveForwardRef } from './forward_ref'; import { InjectionToken } from './injection_token'; import { INJECTOR, NG_TEMP_TOKEN_PATH, NullInjector, THROW_IF_NOT_FOUND, USE_VALUE, catchInjectorError, injectArgs, setCurrentInjector, ɵɵinject } from './injector_compatibility'; import { getInheritedInjectableDef, getInjectableDef, getInjectorDef } from './interface/defs'; import { InjectFlags } from './interface/injector'; import { APP_ROOT } from './scope'; /** * Marker which indicates that a value has not yet been created from the factory function. * @type {?} */ const NOT_YET = {}; /** * Marker which indicates that the factory function for a token is in the process of being called. * * If the injector is asked to inject a token with its value set to CIRCULAR, that indicates * injection of a dependency has recursively attempted to inject the original token, and there is * a circular dependency among the providers. * @type {?} */ const CIRCULAR = {}; /** @type {?} */ const EMPTY_ARRAY = (/** @type {?} */ ([])); /** * A lazily initialized NullInjector. * @type {?} */ let NULL_INJECTOR = undefined; /** * @return {?} */ function getNullInjector() { if (NULL_INJECTOR === undefined) { NULL_INJECTOR = new NullInjector(); } return NULL_INJECTOR; } /** * An entry in the injector which tracks information about the given token, including a possible * current value. * @record * @template T */ function Record() { } if (false) { /** @type {?} */ Record.prototype.factory; /** @type {?} */ Record.prototype.value; /** @type {?} */ Record.prototype.multi; } /** * Create a new `Injector` which is configured using a `defType` of `InjectorType<any>`s. * * \@publicApi * @param {?} defType * @param {?=} parent * @param {?=} additionalProviders * @param {?=} name * @return {?} */ export function createInjector(defType, parent = null, additionalProviders = null, name) { parent = parent || getNullInjector(); return new R3Injector(defType, additionalProviders, parent, name); } export class R3Injector { /** * @param {?} def * @param {?} additionalProviders * @param {?} parent * @param {?=} source */ constructor(def, additionalProviders, parent, source = null) { this.parent = parent; /** * Map of tokens to records which contain the instances of those tokens. */ this.records = new Map(); /** * The transitive set of `InjectorType`s which define this injector. */ this.injectorDefTypes = new Set(); /** * Set of values instantiated by this injector which contain `ngOnDestroy` lifecycle hooks. */ this.onDestroy = new Set(); this._destroyed = false; // Start off by creating Records for every provider declared in every InjectorType // included transitively in `def`. /** @type {?} */ const dedupStack = []; deepForEach([def], (/** * @param {?} injectorDef * @return {?} */ injectorDef => this.processInjectorType(injectorDef, [], dedupStack))); additionalProviders && deepForEach(additionalProviders, (/** * @param {?} provider * @return {?} */ provider => this.processProvider(provider, def, additionalProviders))); // Make sure the INJECTOR token provides this injector. this.records.set(INJECTOR, makeRecord(undefined, this)); // Detect whether this injector has the APP_ROOT_SCOPE token and thus should provide // any injectable scoped to APP_ROOT_SCOPE. this.isRootInjector = this.records.has(APP_ROOT); // Eagerly instantiate the InjectorType classes themselves. this.injectorDefTypes.forEach((/** * @param {?} defType * @return {?} */ defType => this.get(defType))); // Source name, used for debugging this.source = source || (typeof def === 'object' ? null : stringify(def)); } /** * Flag indicating that this injector was previously destroyed. * @return {?} */ get destroyed() { return this._destroyed; } /** * Destroy the injector and release references to every instance or provider associated with it. * * Also calls the `OnDestroy` lifecycle hooks of every instance that was created for which a * hook was found. * @return {?} */ destroy() { this.assertNotDestroyed(); // Set destroyed = true first, in case lifecycle hooks re-enter destroy(). this._destroyed = true; try { // Call all the lifecycle hooks. this.onDestroy.forEach((/** * @param {?} service * @return {?} */ service => service.ngOnDestroy())); } finally { // Release all references. this.records.clear(); this.onDestroy.clear(); this.injectorDefTypes.clear(); } } /** * @template T * @param {?} token * @param {?=} notFoundValue * @param {?=} flags * @return {?} */ get(token, notFoundValue = THROW_IF_NOT_FOUND, flags = InjectFlags.Default) { this.assertNotDestroyed(); // Set the injection context. /** @type {?} */ const previousInjector = setCurrentInjector(this); try { // Check for the SkipSelf flag. if (!(flags & InjectFlags.SkipSelf)) { // SkipSelf isn't set, check if the record belongs to this injector. /** @type {?} */ let record = this.records.get(token); if (record === undefined) { // No record, but maybe the token is scoped to this injector. Look for an ngInjectableDef // with a scope matching this injector. /** @type {?} */ const def = couldBeInjectableType(token) && getInjectableDef(token); if (def && this.injectableDefInScope(def)) { // Found an ngInjectableDef and it's scoped to this injector. Pretend as if it was here // all along. record = makeRecord(injectableDefOrInjectorDefFactory(token), NOT_YET); this.records.set(token, record); } } // If a record was found, get the instance for it and return it. if (record !== undefined) { return this.hydrate(token, record); } } // Select the next injector based on the Self flag - if self is set, the next injector is // the NullInjector, otherwise it's the parent. /** @type {?} */ const nextInjector = !(flags & InjectFlags.Self) ? this.parent : getNullInjector(); return nextInjector.get(token, flags & InjectFlags.Optional ? null : notFoundValue); } catch (e) { if (e.name === 'NullInjectorError') { /** @type {?} */ const path = e[NG_TEMP_TOKEN_PATH] = e[NG_TEMP_TOKEN_PATH] || []; path.unshift(stringify(token)); if (previousInjector) { // We still have a parent injector, keep throwing throw e; } else { // Format & throw the final error message when we don't have any previous injector return catchInjectorError(e, token, 'R3InjectorError', this.source); } } else { throw e; } } finally { // Lastly, clean up the state by restoring the previous injector. setCurrentInjector(previousInjector); } } /** * @return {?} */ toString() { /** @type {?} */ const tokens = (/** @type {?} */ ([])); /** @type {?} */ const records = this.records; records.forEach((/** * @param {?} v * @param {?} token * @return {?} */ (v, token) => tokens.push(stringify(token)))); return `R3Injector[${tokens.join(', ')}]`; } /** * @private * @return {?} */ assertNotDestroyed() { if (this._destroyed) { throw new Error('Injector has already been destroyed.'); } } /** * Add an `InjectorType` or `InjectorTypeWithProviders` and all of its transitive providers * to this injector. * * If an `InjectorTypeWithProviders` that declares providers besides the type is specified, * the function will return "true" to indicate that the providers of the type definition need * to be processed. This allows us to process providers of injector types after all imports of * an injector definition are processed. (following View Engine semantics: see FW-1349) * @private * @param {?} defOrWrappedDef * @param {?} parents * @param {?} dedupStack * @return {?} */ processInjectorType(defOrWrappedDef, parents, dedupStack) { defOrWrappedDef = resolveForwardRef(defOrWrappedDef); if (!defOrWrappedDef) return false; // Either the defOrWrappedDef is an InjectorType (with ngInjectorDef) or an // InjectorDefTypeWithProviders (aka ModuleWithProviders). Detecting either is a megamorphic // read, so care is taken to only do the read once. // First attempt to read the ngInjectorDef. /** @type {?} */ let def = getInjectorDef(defOrWrappedDef); // If that's not present, then attempt to read ngModule from the InjectorDefTypeWithProviders. /** @type {?} */ const ngModule = (def == null) && ((/** @type {?} */ (defOrWrappedDef))).ngModule || undefined; // Determine the InjectorType. In the case where `defOrWrappedDef` is an `InjectorType`, // then this is easy. In the case of an InjectorDefTypeWithProviders, then the definition type // is the `ngModule`. /** @type {?} */ const defType = (ngModule === undefined) ? ((/** @type {?} */ (defOrWrappedDef))) : ngModule; // Check for circular dependencies. if (ngDevMode && parents.indexOf(defType) !== -1) { /** @type {?} */ const defName = stringify(defType); throw new Error(`Circular dependency in DI detected for type ${defName}. Dependency path: ${parents.map((/** * @param {?} defType * @return {?} */ defType => stringify(defType))).join(' > ')} > ${defName}.`); } // Check for multiple imports of the same module /** @type {?} */ const isDuplicate = dedupStack.indexOf(defType) !== -1; // Finally, if defOrWrappedType was an `InjectorDefTypeWithProviders`, then the actual // `InjectorDef` is on its `ngModule`. if (ngModule !== undefined) { def = getInjectorDef(ngModule); } // If no definition was found, it might be from exports. Remove it. if (def == null) { return false; } // Track the InjectorType and add a provider for it. this.injectorDefTypes.add(defType); this.records.set(defType, makeRecord(def.factory, NOT_YET)); // Add providers in the same way that @NgModule resolution did: // First, include providers from any imports. if (def.imports != null && !isDuplicate) { // Before processing defType's imports, add it to the set of parents. This way, if it ends // up deeply importing itself, this can be detected. ngDevMode && parents.push(defType); // Add it to the set of dedups. This way we can detect multiple imports of the same module dedupStack.push(defType); /** @type {?} */ let importTypesWithProviders; try { deepForEach(def.imports, (/** * @param {?} imported * @return {?} */ imported => { if (this.processInjectorType(imported, parents, dedupStack)) { if (importTypesWithProviders === undefined) importTypesWithProviders = []; // If the processed import is an injector type with providers, we store it in the // list of import types with providers, so that we can process those afterwards. importTypesWithProviders.push(imported); } })); } finally { // Remove it from the parents set when finished. ngDevMode && parents.pop(); } // Imports which are declared with providers (TypeWithProviders) need to be processed // after all imported modules are processed. This is similar to how View Engine // processes/merges module imports in the metadata resolver. See: FW-1349. if (importTypesWithProviders !== undefined) { for (let i = 0; i < importTypesWithProviders.length; i++) { const { ngModule, providers } = importTypesWithProviders[i]; deepForEach((/** @type {?} */ (providers)), (/** * @param {?} provider * @return {?} */ provider => this.processProvider(provider, ngModule, providers || EMPTY_ARRAY))); } } } // Next, include providers listed on the definition itself. /** @type {?} */ const defProviders = def.providers; if (defProviders != null && !isDuplicate) { /** @type {?} */ const injectorType = (/** @type {?} */ (defOrWrappedDef)); deepForEach(defProviders, (/** * @param {?} provider * @return {?} */ provider => this.processProvider(provider, injectorType, defProviders))); } return (ngModule !== undefined && ((/** @type {?} */ (defOrWrappedDef))).providers !== undefined); } /** * Process a `SingleProvider` and add it. * @private * @param {?} provider * @param {?} ngModuleType * @param {?} providers * @return {?} */ processProvider(provider, ngModuleType, providers) { // Determine the token from the provider. Either it's its own token, or has a {provide: ...} // property. provider = resolveForwardRef(provider); /** @type {?} */ let token = isTypeProvider(provider) ? provider : resolveForwardRef(provider && provider.provide); // Construct a `Record` for the provider. /** @type {?} */ const record = providerToRecord(provider, ngModuleType, providers); if (!isTypeProvider(provider) && provider.multi === true) { // If the provider indicates that it's a multi-provider, process it specially. // First check whether it's been defined already. /** @type {?} */ let multiRecord = this.records.get(token); if (multiRecord) { // It has. Throw a nice error if if (multiRecord.multi === undefined) { throwMixedMultiProviderError(); } } else { multiRecord = makeRecord(undefined, NOT_YET, true); multiRecord.factory = (/** * @return {?} */ () => injectArgs((/** @type {?} */ ((/** @type {?} */ (multiRecord)).multi)))); this.records.set(token, multiRecord); } token = provider; (/** @type {?} */ (multiRecord.multi)).push(provider); } else { /** @type {?} */ const existing = this.records.get(token); if (existing && existing.multi !== undefined) { throwMixedMultiProviderError(); } } this.records.set(token, record); } /** * @private * @template T * @param {?} token * @param {?} record * @return {?} */ hydrate(token, record) { if (record.value === CIRCULAR) { throwCyclicDependencyError(stringify(token)); } else if (record.value === NOT_YET) { record.value = CIRCULAR; record.value = (/** @type {?} */ (record.factory))(); } if (typeof record.value === 'object' && record.value && hasOnDestroy(record.value)) { this.onDestroy.add(record.value); } return (/** @type {?} */ (record.value)); } /** * @private * @param {?} def * @return {?} */ injectableDefInScope(def) { if (!def.providedIn) { return false; } else if (typeof def.providedIn === 'string') { return def.providedIn === 'any' || (def.providedIn === 'root' && this.isRootInjector); } else { return this.injectorDefTypes.has(def.providedIn); } } } if (false) { /** * Map of tokens to records which contain the instances of those tokens. * @type {?} * @private */ R3Injector.prototype.records; /** * The transitive set of `InjectorType`s which define this injector. * @type {?} * @private */ R3Injector.prototype.injectorDefTypes; /** * Set of values instantiated by this injector which contain `ngOnDestroy` lifecycle hooks. * @type {?} * @private */ R3Injector.prototype.onDestroy; /** * Flag indicating this injector provides the APP_ROOT_SCOPE token, and thus counts as the * root scope. * @type {?} * @private */ R3Injector.prototype.isRootInjector; /** @type {?} */ R3Injector.prototype.source; /** * @type {?} * @private */ R3Injector.prototype._destroyed; /** @type {?} */ R3Injector.prototype.parent; } /** * @param {?} token * @return {?} */ function injectableDefOrInjectorDefFactory(token) { // Most tokens will have an ngInjectableDef directly on them, which specifies a factory directly. /** @type {?} */ const injectableDef = getInjectableDef(token); if (injectableDef !== null) { return injectableDef.factory; } // If the token is an NgModule, it's also injectable but the factory is on its ngInjectorDef. /** @type {?} */ const injectorDef = getInjectorDef(token); if (injectorDef !== null) { return injectorDef.factory; } // InjectionTokens should have an ngInjectableDef and thus should be handled above. // If it's missing that, it's an error. if (token instanceof InjectionToken) { throw new Error(`Token ${stringify(token)} is missing an ngInjectableDef definition.`); } // Undecorated types can sometimes be created if they have no constructor arguments. if (token instanceof Function) { return getUndecoratedInjectableFactory(token); } // There was no way to resolve a factory for this token. throw new Error('unreachable'); } /** * @param {?} token * @return {?} */ function getUndecoratedInjectableFactory(token) { // If the token has parameters then it has dependencies that we cannot resolve implicitly. /** @type {?} */ const paramLength = token.length; if (paramLength > 0) { /** @type {?} */ const args = new Array(paramLength).fill('?'); throw new Error(`Can't resolve all parameters for ${stringify(token)}: (${args.join(', ')}).`); } // The constructor function appears to have no parameters. // This might be because it inherits from a super-class. In which case, use an ngInjectableDef // from an ancestor if there is one. // Otherwise this really is a simple class with no dependencies, so return a factory that // just instantiates the zero-arg constructor. /** @type {?} */ const inheritedInjectableDef = getInheritedInjectableDef(token); if (inheritedInjectableDef !== null) { return (/** * @return {?} */ () => inheritedInjectableDef.factory((/** @type {?} */ (token)))); } else { return (/** * @return {?} */ () => new ((/** @type {?} */ (token)))()); } } /** * @param {?} provider * @param {?} ngModuleType * @param {?} providers * @return {?} */ function providerToRecord(provider, ngModuleType, providers) { /** @type {?} */ let factory = providerToFactory(provider, ngModuleType, providers); if (isValueProvider(provider)) { return makeRecord(undefined, provider.useValue); } else { return makeRecord(factory, NOT_YET); } } /** * Converts a `SingleProvider` into a factory function. * * @param {?} provider provider to convert to factory * @param {?=} ngModuleType * @param {?=} providers * @return {?} */ export function providerToFactory(provider, ngModuleType, providers) { /** @type {?} */ let factory = undefined; if (isTypeProvider(provider)) { return injectableDefOrInjectorDefFactory(resolveForwardRef(provider)); } else { if (isValueProvider(provider)) { factory = (/** * @return {?} */ () => resolveForwardRef(provider.useValue)); } else if (isExistingProvider(provider)) { factory = (/** * @return {?} */ () => ɵɵinject(resolveForwardRef(provider.useExisting))); } else if (isFactoryProvider(provider)) { factory = (/** * @return {?} */ () => provider.useFactory(...injectArgs(provider.deps || []))); } else { /** @type {?} */ const classRef = resolveForwardRef(provider && (((/** @type {?} */ (provider))).useClass || provider.provide)); if (!classRef) { throwInvalidProviderError(ngModuleType, providers, provider); } if (hasDeps(provider)) { factory = (/** * @return {?} */ () => new (classRef)(...injectArgs(provider.deps))); } else { return injectableDefOrInjectorDefFactory(classRef); } } } return factory; } /** * @template T * @param {?} factory * @param {?} value * @param {?=} multi * @return {?} */ function makeRecord(factory, value, multi = false) { return { factory: factory, value: value, multi: multi ? [] : undefined, }; } /** * @template T * @param {?} input * @param {?} fn * @return {?} */ function deepForEach(input, fn) { input.forEach((/** * @param {?} value * @return {?} */ value => Array.isArray(value) ? deepForEach(value, fn) : fn(value))); } /** * @param {?} value * @return {?} */ function isValueProvider(value) { return value !== null && typeof value == 'object' && USE_VALUE in value; } /** * @param {?} value * @return {?} */ function isExistingProvider(value) { return !!(value && ((/** @type {?} */ (value))).useExisting); } /** * @param {?} value * @return {?} */ function isFactoryProvider(value) { return !!(value && ((/** @type {?} */ (value))).useFactory); } /** * @param {?} value * @return {?} */ export function isTypeProvider(value) { return typeof value === 'function'; } /** * @param {?} value * @return {?} */ export function isClassProvider(value) { return !!((/** @type {?} */ (value))).useClass; } /** * @param {?} value * @return {?} */ function hasDeps(value) { return !!((/** @type {?} */ (value))).deps; } /** * @param {?} value * @return {?} */ function hasOnDestroy(value) { return value !== null && typeof value === 'object' && typeof ((/** @type {?} */ (value))).ngOnDestroy === 'function'; } /** * @param {?} value * @return {?} */ function couldBeInjectableType(value) { return (typeof value === 'function') || (typeof value === 'object' && value instanceof InjectionToken); } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicjNfaW5qZWN0b3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9wYWNrYWdlcy9jb3JlL3NyYy9kaS9yM19pbmplY3Rvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7OztBQVFBLE9BQU8scUJBQXFCLENBQUM7QUFJN0IsT0FBTyxFQUFDLDBCQUEwQixFQUFFLHlCQUF5QixFQUFFLDRCQUE0QixFQUFDLE1BQU0sbUJBQW1CLENBQUM7QUFDdEgsT0FBTyxFQUFDLFNBQVMsRUFBQyxNQUFNLG1CQUFtQixDQUFDO0FBRTVDLE9BQU8sRUFBQyxpQkFBaUIsRUFBQyxNQUFNLGVBQWUsQ0FBQztBQUNoRCxPQUFPLEVBQUMsY0FBYyxFQUFDLE1BQU0sbUJBQW1CLENBQUM7QUFFakQsT0FBTyxFQUFDLFFBQVEsRUFBRSxrQkFBa0IsRUFBRSxZQUFZLEVBQUUsa0JBQWtCLEVBQUUsU0FBUyxFQUFFLGtCQUFrQixFQUFFLFVBQVUsRUFBRSxrQkFBa0IsRUFBRSxRQUFRLEVBQUMsTUFBTSwwQkFBMEIsQ0FBQztBQUNqTCxPQUFPLEVBQTBDLHlCQUF5QixFQUFFLGdCQUFnQixFQUFFLGNBQWMsRUFBa0IsTUFBTSxrQkFBa0IsQ0FBQztBQUN2SixPQUFPLEVBQUMsV0FBVyxFQUFDLE1BQU0sc0JBQXNCLENBQUM7QUFFakQsT0FBTyxFQUFDLFFBQVEsRUFBQyxNQUFNLFNBQVMsQ0FBQzs7Ozs7TUFhM0IsT0FBTyxHQUFHLEVBQUU7Ozs7Ozs7OztNQVNaLFFBQVEsR0FBRyxFQUFFOztNQUViLFdBQVcsR0FBRyxtQkFBQSxFQUFFLEVBQVM7Ozs7O0lBSzNCLGFBQWEsR0FBdUIsU0FBUzs7OztBQUVqRCxTQUFTLGVBQWU7SUFDdEIsSUFBSSxhQUFhLEtBQUssU0FBUyxFQUFFO1FBQy9CLGFBQWEsR0FBRyxJQUFJLFlBQVksRUFBRSxDQUFDO0tBQ3BDO0lBQ0QsT0FBTyxhQUFhLENBQUM7QUFDdkIsQ0FBQzs7Ozs7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b3B5cmlnaHQgR29vZ2xlIEluYy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqXG4gKiBVc2Ugb2YgdGhpcyBzb3VyY2UgY29kZSBpcyBnb3Zlcm5lZCBieSBhbiBNSVQtc3R5bGUgbGljZW5zZSB0aGF0IGNhbiBiZVxuICogZm91bmQgaW4gdGhlIExJQ0VOU0UgZmlsZSBhdCBodHRwczovL2FuZ3VsYXIuaW8vbGljZW5zZVxuICovXG5cbmltcG9ydCAnLi4vdXRpbC9uZ19kZXZfbW9kZSc7XG5cbmltcG9ydCB7T25EZXN0cm95fSBmcm9tICcuLi9pbnRlcmZhY2UvbGlmZWN5Y2xlX2hvb2tzJztcbmltcG9ydCB7VHlwZX0gZnJvbSAnLi4vaW50ZXJmYWNlL3R5cGUnO1xuaW1wb3J0IHt0aHJvd0N5Y2xpY0RlcGVuZGVuY3lFcnJvciwgdGhyb3dJbnZhbGlkUHJvdmlkZXJFcnJvciwgdGhyb3dNaXhlZE11bHRpUHJvdmlkZXJFcnJvcn0gZnJvbSAnLi4vcmVuZGVyMy9lcnJvcnMnO1xuaW1wb3J0IHtzdHJpbmdpZnl9IGZyb20gJy4uL3V0aWwvc3RyaW5naWZ5JztcblxuaW1wb3J0IHtyZXNvbHZlRm9yd2FyZFJlZn0gZnJvbSAnLi9mb3J3YXJkX3JlZic7XG5pbXBvcnQge0luamVjdGlvblRva2VufSBmcm9tICcuL2luamVjdGlvbl90b2tlbic7XG5pbXBvcnQge0luamVjdG9yfSBmcm9tICcuL2luamVjdG9yJztcbmltcG9ydCB7SU5KRUNUT1IsIE5HX1RFTVBfVE9LRU5fUEFUSCwgTnVsbEluamVjdG9yLCBUSFJPV19JRl9OT1RfRk9VTkQsIFVTRV9WQUxVRSwgY2F0Y2hJbmplY3RvckVycm9yLCBpbmplY3RBcmdzLCBzZXRDdXJyZW50SW5qZWN0b3IsIMm1ybVpbmplY3R9IGZyb20gJy4vaW5qZWN0b3JfY29tcGF0aWJpbGl0eSc7XG5pbXBvcnQge0luamVjdG9yVHlwZSwgSW5qZWN0b3JUeXBlV2l0aFByb3ZpZGVycywgZ2V0SW5oZXJpdGVkSW5qZWN0YWJsZURlZiwgZ2V0SW5qZWN0YWJsZURlZiwgZ2V0SW5qZWN0b3JEZWYsIMm1ybVJbmplY3RhYmxlRGVmfSBmcm9tICcuL2ludGVyZmFjZS9kZWZzJztcbmltcG9ydCB7SW5qZWN0RmxhZ3N9IGZyb20gJy4vaW50ZXJmYWNlL2luamVjdG9yJztcbmltcG9ydCB7Q2xhc3NQcm92aWRlciwgQ29uc3RydWN0b3JQcm92aWRlciwgRXhpc3RpbmdQcm92aWRlciwgRmFjdG9yeVByb3ZpZGVyLCBTdGF0aWNDbGFzc1Byb3ZpZGVyLCBTdGF0aWNQcm92aWRlciwgVHlwZVByb3ZpZGVyLCBWYWx1ZVByb3ZpZGVyfSBmcm9tICcuL2ludGVyZmFjZS9wcm92aWRlcic7XG5pbXBvcnQge0FQUF9ST09UfSBmcm9tICcuL3Njb3BlJztcblxuXG5cbi8qKlxuICogSW50ZXJuYWwgdHlwZSBmb3IgYSBzaW5nbGUgcHJvdmlkZXIgaW4gYSBkZWVwIHByb3ZpZGVyIGFycmF5LlxuICovXG50eXBlIFNpbmdsZVByb3ZpZGVyID0gVHlwZVByb3ZpZGVyIHwgVmFsdWVQcm92aWRlciB8IENsYXNzUHJvdmlkZXIgfCBDb25zdHJ1Y3RvclByb3ZpZGVyIHxcbiAgICBFeGlzdGluZ1Byb3ZpZGVyIHwgRmFjdG9yeVByb3ZpZGVyIHwgU3RhdGljQ2xhc3NQcm92aWRlcjtcblxuLyoqXG4gKiBNYXJrZXIgd2hpY2ggaW5kaWNhdGVzIHRoYXQgYSB2YWx1ZSBoYXMgbm90IHlldCBiZWVuIGNyZWF0ZWQgZnJvbSB0aGUgZmFjdG9yeSBmdW5jdGlvbi5cbiAqL1xuY29uc3QgTk9UX1lFVCA9IHt9O1xuXG4vKipcbiAqIE1hcmtlciB3aGljaCBpbmRpY2F0ZXMgdGhhdCB0aGUgZmFjdG9yeSBmdW5jdGlvbiBmb3IgYSB0b2tlbiBpcyBpbiB0aGUgcHJvY2VzcyBvZiBiZWluZyBjYWxsZWQuXG4gKlxuICogSWYgdGhlIGluamVjdG9yIGlzIGFza2VkIHRvIGluamVjdCBhIHRva2VuIHdpdGggaXRzIHZhbHVlIHNldCB0byBDSVJDVUxBUiwgdGhhdCBpbmRpY2F0ZXNcbiAqIGluamVjdGlvbiBvZiBhIGRlcGVuZGVuY3kgaGFzIHJlY3Vyc2l2ZWx5IGF0dGVtcHRlZCB0byBpbmplY3QgdGhlIG9yaWdpbmFsIHRva2VuLCBhbmQgdGhlcmUgaXNcbiAqIGEgY2lyY3VsYXIgZGVwZW5kZW5jeSBhbW9uZyB0aGUgcHJvdmlkZXJzLlxuICovXG5jb25zdCBDSVJDVUxBUiA9IHt9O1xuXG5jb25zdCBFTVBUWV9BUlJBWSA9IFtdIGFzIGFueVtdO1xuXG4vKipcbiAqIEEgbGF6aWx5IGluaXRpYWxpemVkIE51bGxJbmplY3Rvci5cbiAqL1xubGV0IE5VTExfSU5KRUNUT1I6IEluamVjdG9yfHVuZGVmaW5lZCA9IHVuZGVmaW5lZDtcblxuZnVuY3Rpb24gZ2V0TnVsbEluamVjdG9yKCk6IEluamVjdG9yIHtcbiAgaWYgKE5VTExfSU5KRUNUT1IgPT09IHVuZGVmaW5lZCkge1xuICAgIE5VTExfSU5KRUNUT1IgPSBuZXcgTnVsbEluamVjdG9yKCk7XG4gIH1cbiAgcmV0dXJuIE5VTExfSU5KRUNUT1I7XG59XG5cbi8qKlxuICogQW4gZW50cnkgaW4gdGhlIGluamVjdG9yIHdoaWNoIHRyYWNrcyBpbmZvcm1hdGlvbiBhYm91dCB0aGUgZ2l2ZW4gdG9rZW4sIGluY2x1ZGluZyBhIHBvc3NpYmxlXG4gKiBjdXJyZW50IHZhbHVlLlxuICovXG5pbnRlcmZhY2UgUmVjb3JkPFQ+IHtcbiAgZmFjdG9yeTogKCgpID0+IFQpfHVuZGVmaW5lZDtcbiAgdmFsdWU6IFR8e307XG4gIG11bHRpOiBhbnlbXXx1bmRlZmluZWQ7XG59XG5cbi8qKlxuICogQ3JlYXRlIGEgbmV3IGBJbmplY3RvcmAgd2hpY2ggaXMgY29uZmlndXJlZCB1c2luZyBhIGBkZWZUeXBlYCBvZiBgSW5qZWN0b3JUeXBlPGFueT5gcy5cbiAqXG4gKiBAcHVibGljQXBpXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVJbmplY3RvcihcbiAgICBkZWZUeXBlOiAvKiBJbmplY3RvclR5cGU8YW55PiAqLyBhbnksIHBhcmVudDogSW5qZWN0b3IgfCBudWxsID0gbnVsbCxcbiAgICBhZGRpdGlvbmFsUHJvdmlkZXJzOiBTdGF0aWNQcm92aWRlcltdIHwgbnVsbCA9IG51bGwsIG5hbWU/OiBzdHJpbmcpOiBJbmplY3RvciB7XG4gIHBhcmVudCA9IHBhcmVudCB8fCBnZXROdWxsSW5qZWN0b3IoKTtcbiAgcmV0dXJuIG5ldyBSM0luamVjdG9yKGRlZlR5cGUsIGFkZGl0aW9uYWxQcm92aWRlcnMsIHBhcmVudCwgbmFtZSk7XG59XG5cbmV4cG9ydCBjbGFzcyBSM0luamVjdG9yIHtcbiAgLyoqXG4gICAqIE1hcCBvZiB0b2tlbnMgdG8gcmVjb3JkcyB3aGljaCBjb250YWluIHRoZSBpbnN0YW5jZXMgb2YgdGhvc2UgdG9rZW5zLlxuICAgKi9cbiAgcHJpdmF0ZSByZWNvcmRzID0gbmV3IE1hcDxUeXBlPGFueT58SW5qZWN0aW9uVG9rZW48YW55PiwgUmVjb3JkPGFueT4+KCk7XG5cbiAgLyoqXG4gICAqIFRoZSB0cmFuc2l0aXZlIHNldCBvZiBgSW5qZWN0b3JUeXBlYHMgd2hpY2ggZGVmaW5lIHRoaXMgaW5qZWN0b3IuXG4gICAqL1xuICBwcml2YXRlIGluamVjdG9yRGVmVHlwZXMgPSBuZXcgU2V0PEluamVjdG9yVHlwZTxhbnk+PigpO1xuXG4gIC8qKlxuICAgKiBTZXQgb2YgdmFsdWVzIGluc3RhbnRpYXRlZCBieSB0aGlzIGluamVjdG9yIHdoaWNoIGNvbnRhaW4gYG5nT25EZXN0cm95YCBsaWZlY3ljbGUgaG9va3MuXG4gICAqL1xuICBwcml2YXRlIG9uRGVzdHJveSA9IG5ldyBTZXQ8T25EZXN0cm95PigpO1xuXG4gIC8qKlxuICAgKiBGbGFnIGluZGljYXRpbmcgdGhpcyBpbmplY3RvciBwcm92aWRlcyB0aGUgQVBQX1JPT1RfU0NPUEUgdG9rZW4sIGFuZCB0aHVzIGNvdW50cyBhcyB0aGVcbiAgICogcm9vdCBzY29wZS5cbiAgICovXG4gIHByaXZhdGUgcmVhZG9ubHkgaXNSb290SW5qZWN0b3I6IGJvb2xlYW47XG5cbiAgcmVhZG9ubHkgc291cmNlOiBzdHJpbmd8bnVsbDtcblxuICAvKipcbiAgICogRmxhZyBpbmRpY2F0aW5nIHRoYXQgdGhpcyBpbmplY3RvciB3YXMgcHJldmlvdXNseSBkZXN0cm95ZWQuXG4gICAqL1xuICBnZXQgZGVzdHJveWVkKCk6IGJvb2xlYW4geyByZXR1cm4gdGhpcy5fZGVzdHJveWVkOyB9XG4gIHByaXZhdGUgX2Rlc3Ryb3llZCA9IGZhbHNlO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgICAgZGVmOiBJbmplY3RvclR5cGU8YW55PiwgYWRkaXRpb25hbFByb3ZpZGVyczogU3RhdGljUHJvdmlkZXJbXXxudWxsLCByZWFkb25seSBwYXJlbnQ6IEluamVjdG9yLFxuICAgICAgc291cmNlOiBzdHJpbmd8bnVsbCA9IG51bGwpIHtcbiAgICAvLyBTdGFydCBvZmYgYnkgY3JlYXRpbmcgUmVjb3JkcyBmb3IgZXZlcnkgcHJvdmlkZXIgZGVjbGFyZWQgaW4gZXZlcnkgSW5qZWN0b3JUeXBlXG4gICAgLy8gaW5jbHVkZWQgdHJhbnNpdGl2ZWx5IGluIGBkZWZgLlxuICAgIGNvbnN0IGRlZHVwU3RhY2s6IEluamVjdG9yVHlwZTxhbnk+W10gPSBbXTtcbiAgICBkZWVwRm9yRWFjaChbZGVmXSwgaW5qZWN0b3JEZWYgPT4gdGhpcy5wcm9jZXNzSW5qZWN0b3JUeXBlKGluamVjdG9yRGVmLCBbXSwgZGVkdXBTdGFjaykpO1xuXG4gICAgYWRkaXRpb25hbFByb3ZpZGVycyAmJiBkZWVwRm9yRWFjaChcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZGRpdGlvbmFsUHJvdmlkZXJzLCBwcm92aWRlciA9PiB0aGlzLnByb2Nlc3NQcm92aWRlcihcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvdmlkZXIsIGRlZiwgYWRkaXRpb25hbFByb3ZpZGVycykpO1xuXG5cbiAgICAvLyBNYWtlIHN1cmUgdGhlIElOSkVDVE9SIHRva2VuIHByb3ZpZGVzIHRoaXMgaW5qZWN0b3IuXG4gICAgdGhpcy5yZWNvcmRzLnNldChJTkpFQ1RPUiwgbWFrZVJlY29yZCh1bmRlZmluZWQsIHRoaXMpKTtcblxuICAgIC8vIERldGVjdCB3aGV0aGVyIHRoaXMgaW5qZWN0b3IgaGFzIHRoZSBBUFBfUk9PVF9TQ09QRSB0b2tlbiBhbmQgdGh1cyBzaG91bGQgcHJvdmlkZVxuICAgIC8vIGFueSBpbmplY3RhYmxlIHNjb3BlZCB0byBBUFBfUk9PVF9TQ09QRS5cbiAgICB0aGlzLmlzUm9vdEluamVjdG9yID0gdGhpcy5yZWNvcmRzLmhhcyhBUFBfUk9PVCk7XG5cbiAgICAvLyBFYWdlcmx5IGluc3RhbnRpYXRlIHRoZSBJbmplY3RvclR5cGUgY2xhc3NlcyB0aGVtc2VsdmVzLlxuICAgIHRoaXMuaW5qZWN0b3JEZWZUeXBlcy5mb3JFYWNoKGRlZlR5cGUgPT4gdGhpcy5nZXQoZGVmVHlwZSkpO1xuXG4gICAgLy8gU291cmNlIG5hbWUsIHVzZWQgZm9yIGRlYnVnZ2luZ1xuICAgIHRoaXMuc291cmNlID0gc291cmNlIHx8ICh0eXBlb2YgZGVmID09PSAnb2JqZWN0JyA/IG51bGwgOiBzdHJpbmdpZnkoZGVmKSk7XG4gIH1cblxuICAvKipcbiAgICogRGVzdHJveSB0aGUgaW5qZWN0b3IgYW5kIHJlbGVhc2UgcmVmZXJlbmNlcyB0byBldmVyeSBpbnN0YW5jZSBvciBwcm92aWRlciBhc3NvY2lhdGVkIHdpdGggaXQuXG4gICAqXG4gICAqIEFsc28gY2FsbHMgdGhlIGBPbkRlc3Ryb3lgIGxpZmVjeWNsZSBob29rcyBvZiBldmVyeSBpbnN0YW5jZSB0aGF0IHdhcyBjcmVhdGVkIGZvciB3aGljaCBhXG4gICAqIGhvb2sgd2FzIGZvdW5kLlxuICAgKi9cbiAgZGVzdHJveSgpOiB2b2lkIHtcbiAgICB0aGlzLmFzc2VydE5vdERlc3Ryb3llZCgpO1xuXG4gICAgLy8gU2V0IGRlc3Ryb3llZCA9IHRydWUgZmlyc3QsIGluIGNhc2UgbGlmZWN5Y2xlIGhvb2tzIHJlLWVudGVyIGRlc3Ryb3koKS5cbiAgICB0aGlzLl9kZXN0cm95ZWQgPSB0cnVlO1xuICAgIHRyeSB7XG4gICAgICAvLyBDYWxsIGFsbCB0aGUgbGlmZWN5Y2xlIGhvb2tzLlxuICAgICAgdGhpcy5vbkRlc3Ryb3kuZm9yRWFjaChzZXJ2aWNlID0+IHNlcnZpY2UubmdPbkRlc3Ryb3koKSk7XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgIC8vIFJlbGVhc2UgYWxsIHJlZmVyZW5jZXMuXG4gICAgICB0aGlzLnJlY29yZHMuY2xlYXIoKTtcbiAgICAgIHRoaXMub25EZXN0cm95LmNsZWFyKCk7XG4gICAgICB0aGlzLmluamVjdG9yRGVmVHlwZXMuY2xlYXIoKTtcbiAgICB9XG4gIH1cblxuICBnZXQ8VD4oXG4gICAgICB0b2tlbjogVHlwZTxUPnxJbmplY3Rpb25Ub2tlbjxUPiwgbm90Rm91bmRWYWx1ZTogYW55ID0gVEhST1dfSUZfTk9UX0ZPVU5ELFxuICAgICAgZmxhZ3MgPSBJbmplY3RGbGFncy5EZWZhdWx0KTogVCB7XG4gICAgdGhpcy5hc3NlcnROb3REZXN0cm95ZWQoKTtcbiAgICAvLyBTZXQgdGhlIGluamVjdGlvbiBjb250ZXh0LlxuICAgIGNvbnN0IHByZXZpb3VzSW5qZWN0b3IgPSBzZXRDdXJyZW50SW5qZWN0b3IodGhpcyk7XG4gICAgdHJ5IHtcbiAgICAgIC8vIENoZWNrIGZvciB0aGUgU2tpcFNlbGYgZmxhZy5cbiAgICAgIGlmICghKGZsYW