@angular/core
Version:
Angular - the core framework
473 lines • 69.8 kB
JavaScript
/**
* @license
* Copyright Google LLC 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 { RuntimeError } from '../errors';
import { emitInstanceCreatedByInjectorEvent, emitProviderConfiguredEvent, runInInjectorProfilerContext, setInjectorProfilerContext } from '../render3/debug/injector_profiler';
import { getFactoryDef } from '../render3/definition_factory';
import { throwCyclicDependencyError, throwInvalidProviderError, throwMixedMultiProviderError } from '../render3/errors_di';
import { NG_ENV_ID } from '../render3/fields';
import { newArray } from '../util/array_utils';
import { EMPTY_ARRAY } from '../util/empty';
import { stringify } from '../util/stringify';
import { resolveForwardRef } from './forward_ref';
import { ENVIRONMENT_INITIALIZER } from './initializer_token';
import { setInjectImplementation } from './inject_switch';
import { InjectionToken } from './injection_token';
import { catchInjectorError, convertToBitFlags, injectArgs, NG_TEMP_TOKEN_PATH, setCurrentInjector, THROW_IF_NOT_FOUND, ɵɵinject } from './injector_compatibility';
import { INJECTOR } from './injector_token';
import { getInheritedInjectableDef, getInjectableDef } from './interface/defs';
import { InjectFlags } from './interface/injector';
import { isEnvironmentProviders } from './interface/provider';
import { INJECTOR_DEF_TYPES } from './internal_tokens';
import { NullInjector } from './null_injector';
import { isExistingProvider, isFactoryProvider, isTypeProvider, isValueProvider } from './provider_collection';
import { INJECTOR_SCOPE } from './scope';
/**
* Marker which indicates that a value has not yet been created from the factory function.
*/
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.
*/
const CIRCULAR = {};
/**
* A lazily initialized NullInjector.
*/
let NULL_INJECTOR = undefined;
export function getNullInjector() {
if (NULL_INJECTOR === undefined) {
NULL_INJECTOR = new NullInjector();
}
return NULL_INJECTOR;
}
/**
* An `Injector` that's part of the environment injector hierarchy, which exists outside of the
* component tree.
*/
export class EnvironmentInjector {
}
export class R3Injector extends EnvironmentInjector {
/**
* Flag indicating that this injector was previously destroyed.
*/
get destroyed() {
return this._destroyed;
}
constructor(providers, parent, source, scopes) {
super();
this.parent = parent;
this.source = source;
this.scopes = scopes;
/**
* Map of tokens to records which contain the instances of those tokens.
* - `null` value implies that we don't have the record. Used by tree-shakable injectors
* to prevent further searches.
*/
this.records = new Map();
/**
* Set of values instantiated by this injector which contain `ngOnDestroy` lifecycle hooks.
*/
this._ngOnDestroyHooks = new Set();
this._onDestroyHooks = [];
this._destroyed = false;
// Start off by creating Records for every provider.
forEachSingleProvider(providers, provider => this.processProvider(provider));
// Make sure the INJECTOR token provides this injector.
this.records.set(INJECTOR, makeRecord(undefined, this));
// And `EnvironmentInjector` if the current injector is supposed to be env-scoped.
if (scopes.has('environment')) {
this.records.set(EnvironmentInjector, makeRecord(undefined, this));
}
// Detect whether this injector has the APP_ROOT_SCOPE token and thus should provide
// any injectable scoped to APP_ROOT_SCOPE.
const record = this.records.get(INJECTOR_SCOPE);
if (record != null && typeof record.value === 'string') {
this.scopes.add(record.value);
}
this.injectorDefTypes = new Set(this.get(INJECTOR_DEF_TYPES, EMPTY_ARRAY, InjectFlags.Self));
}
/**
* 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.
*/
destroy() {
this.assertNotDestroyed();
// Set destroyed = true first, in case lifecycle hooks re-enter destroy().
this._destroyed = true;
try {
// Call all the lifecycle hooks.
for (const service of this._ngOnDestroyHooks) {
service.ngOnDestroy();
}
const onDestroyHooks = this._onDestroyHooks;
// Reset the _onDestroyHooks array before iterating over it to prevent hooks that unregister
// themselves from mutating the array during iteration.
this._onDestroyHooks = [];
for (const hook of onDestroyHooks) {
hook();
}
}
finally {
// Release all references.
this.records.clear();
this._ngOnDestroyHooks.clear();
this.injectorDefTypes.clear();
}
}
onDestroy(callback) {
this.assertNotDestroyed();
this._onDestroyHooks.push(callback);
return () => this.removeOnDestroy(callback);
}
runInContext(fn) {
this.assertNotDestroyed();
const previousInjector = setCurrentInjector(this);
const previousInjectImplementation = setInjectImplementation(undefined);
let prevInjectContext;
if (ngDevMode) {
prevInjectContext = setInjectorProfilerContext({ injector: this, token: null });
}
try {
return fn();
}
finally {
setCurrentInjector(previousInjector);
setInjectImplementation(previousInjectImplementation);
ngDevMode && setInjectorProfilerContext(prevInjectContext);
}
}
get(token, notFoundValue = THROW_IF_NOT_FOUND, flags = InjectFlags.Default) {
this.assertNotDestroyed();
if (token.hasOwnProperty(NG_ENV_ID)) {
return token[NG_ENV_ID](this);
}
flags = convertToBitFlags(flags);
// Set the injection context.
let prevInjectContext;
if (ngDevMode) {
prevInjectContext = setInjectorProfilerContext({ injector: this, token: token });
}
const previousInjector = setCurrentInjector(this);
const previousInjectImplementation = setInjectImplementation(undefined);
try {
// Check for the SkipSelf flag.
if (!(flags & InjectFlags.SkipSelf)) {
// SkipSelf isn't set, check if the record belongs to this injector.
let record = this.records.get(token);
if (record === undefined) {
// No record, but maybe the token is scoped to this injector. Look for an injectable
// def with a scope matching this injector.
const def = couldBeInjectableType(token) && getInjectableDef(token);
if (def && this.injectableDefInScope(def)) {
// Found an injectable def and it's scoped to this injector. Pretend as if it was here
// all along.
if (ngDevMode) {
runInInjectorProfilerContext(this, token, () => {
emitProviderConfiguredEvent(token);
});
}
record = makeRecord(injectableDefOrInjectorDefFactory(token), NOT_YET);
}
else {
record = null;
}
this.records.set(token, record);
}
// If a record was found, get the instance for it and return it.
if (record != null /* NOT null || 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.
const nextInjector = !(flags & InjectFlags.Self) ? this.parent : getNullInjector();
// Set the notFoundValue based on the Optional flag - if optional is set and notFoundValue
// is undefined, the value is null, otherwise it's the notFoundValue.
notFoundValue = (flags & InjectFlags.Optional) && notFoundValue === THROW_IF_NOT_FOUND ?
null :
notFoundValue;
return nextInjector.get(token, notFoundValue);
}
catch (e) {
if (e.name === 'NullInjectorError') {
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, restore the previous injection context.
setInjectImplementation(previousInjectImplementation);
setCurrentInjector(previousInjector);
ngDevMode && setInjectorProfilerContext(prevInjectContext);
}
}
/** @internal */
resolveInjectorInitializers() {
const previousInjector = setCurrentInjector(this);
const previousInjectImplementation = setInjectImplementation(undefined);
let prevInjectContext;
if (ngDevMode) {
prevInjectContext = setInjectorProfilerContext({ injector: this, token: null });
}
try {
const initializers = this.get(ENVIRONMENT_INITIALIZER, EMPTY_ARRAY, InjectFlags.Self);
if (ngDevMode && !Array.isArray(initializers)) {
throw new RuntimeError(-209 /* RuntimeErrorCode.INVALID_MULTI_PROVIDER */, 'Unexpected type of the `ENVIRONMENT_INITIALIZER` token value ' +
`(expected an array, but got ${typeof initializers}). ` +
'Please check that the `ENVIRONMENT_INITIALIZER` token is configured as a ' +
'`multi: true` provider.');
}
for (const initializer of initializers) {
initializer();
}
}
finally {
setCurrentInjector(previousInjector);
setInjectImplementation(previousInjectImplementation);
ngDevMode && setInjectorProfilerContext(prevInjectContext);
}
}
toString() {
const tokens = [];
const records = this.records;
for (const token of records.keys()) {
tokens.push(stringify(token));
}
return `R3Injector[${tokens.join(', ')}]`;
}
assertNotDestroyed() {
if (this._destroyed) {
throw new RuntimeError(205 /* RuntimeErrorCode.INJECTOR_ALREADY_DESTROYED */, ngDevMode && 'Injector has already been destroyed.');
}
}
/**
* Process a `SingleProvider` and add it.
*/
processProvider(provider) {
// Determine the token from the provider. Either it's its own token, or has a {provide: ...}
// property.
provider = resolveForwardRef(provider);
let token = isTypeProvider(provider) ? provider : resolveForwardRef(provider && provider.provide);
// Construct a `Record` for the provider.
const record = providerToRecord(provider);
if (ngDevMode) {
runInInjectorProfilerContext(this, token, () => {
// Emit InjectorProfilerEventType.Create if provider is a value provider because
// these are the only providers that do not go through the value hydration logic
// where this event would normally be emitted from.
if (isValueProvider(provider)) {
emitInstanceCreatedByInjectorEvent(provider.useValue);
}
emitProviderConfiguredEvent(provider);
});
}
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.
let multiRecord = this.records.get(token);
if (multiRecord) {
// It has. Throw a nice error if
if (ngDevMode && multiRecord.multi === undefined) {
throwMixedMultiProviderError();
}
}
else {
multiRecord = makeRecord(undefined, NOT_YET, true);
multiRecord.factory = () => injectArgs(multiRecord.multi);
this.records.set(token, multiRecord);
}
token = provider;
multiRecord.multi.push(provider);
}
else {
if (ngDevMode) {
const existing = this.records.get(token);
if (existing && existing.multi !== undefined) {
throwMixedMultiProviderError();
}
}
}
this.records.set(token, record);
}
hydrate(token, record) {
if (ngDevMode && record.value === CIRCULAR) {
throwCyclicDependencyError(stringify(token));
}
else if (record.value === NOT_YET) {
record.value = CIRCULAR;
if (ngDevMode) {
runInInjectorProfilerContext(this, token, () => {
record.value = record.factory();
emitInstanceCreatedByInjectorEvent(record.value);
});
}
else {
record.value = record.factory();
}
}
if (typeof record.value === 'object' && record.value && hasOnDestroy(record.value)) {
this._ngOnDestroyHooks.add(record.value);
}
return record.value;
}
injectableDefInScope(def) {
if (!def.providedIn) {
return false;
}
const providedIn = resolveForwardRef(def.providedIn);
if (typeof providedIn === 'string') {
return providedIn === 'any' || (this.scopes.has(providedIn));
}
else {
return this.injectorDefTypes.has(providedIn);
}
}
removeOnDestroy(callback) {
const destroyCBIdx = this._onDestroyHooks.indexOf(callback);
if (destroyCBIdx !== -1) {
this._onDestroyHooks.splice(destroyCBIdx, 1);
}
}
}
function injectableDefOrInjectorDefFactory(token) {
// Most tokens will have an injectable def directly on them, which specifies a factory directly.
const injectableDef = getInjectableDef(token);
const factory = injectableDef !== null ? injectableDef.factory : getFactoryDef(token);
if (factory !== null) {
return factory;
}
// InjectionTokens should have an injectable def (ɵprov) and thus should be handled above.
// If it's missing that, it's an error.
if (token instanceof InjectionToken) {
throw new RuntimeError(204 /* RuntimeErrorCode.INVALID_INJECTION_TOKEN */, ngDevMode && `Token ${stringify(token)} is missing a ɵprov 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 RuntimeError(204 /* RuntimeErrorCode.INVALID_INJECTION_TOKEN */, ngDevMode && 'unreachable');
}
function getUndecoratedInjectableFactory(token) {
// If the token has parameters then it has dependencies that we cannot resolve implicitly.
const paramLength = token.length;
if (paramLength > 0) {
throw new RuntimeError(204 /* RuntimeErrorCode.INVALID_INJECTION_TOKEN */, ngDevMode &&
`Can't resolve all parameters for ${stringify(token)}: (${newArray(paramLength, '?').join(', ')}).`);
}
// The constructor function appears to have no parameters.
// This might be because it inherits from a super-class. In which case, use an injectable
// def 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.
const inheritedInjectableDef = getInheritedInjectableDef(token);
if (inheritedInjectableDef !== null) {
return () => inheritedInjectableDef.factory(token);
}
else {
return () => new token();
}
}
function providerToRecord(provider) {
if (isValueProvider(provider)) {
return makeRecord(undefined, provider.useValue);
}
else {
const factory = providerToFactory(provider);
return makeRecord(factory, NOT_YET);
}
}
/**
* Converts a `SingleProvider` into a factory function.
*
* @param provider provider to convert to factory
*/
export function providerToFactory(provider, ngModuleType, providers) {
let factory = undefined;
if (ngDevMode && isEnvironmentProviders(provider)) {
throwInvalidProviderError(undefined, providers, provider);
}
if (isTypeProvider(provider)) {
const unwrappedProvider = resolveForwardRef(provider);
return getFactoryDef(unwrappedProvider) || injectableDefOrInjectorDefFactory(unwrappedProvider);
}
else {
if (isValueProvider(provider)) {
factory = () => resolveForwardRef(provider.useValue);
}
else if (isFactoryProvider(provider)) {
factory = () => provider.useFactory(...injectArgs(provider.deps || []));
}
else if (isExistingProvider(provider)) {
factory = () => ɵɵinject(resolveForwardRef(provider.useExisting));
}
else {
const classRef = resolveForwardRef(provider &&
(provider.useClass || provider.provide));
if (ngDevMode && !classRef) {
throwInvalidProviderError(ngModuleType, providers, provider);
}
if (hasDeps(provider)) {
factory = () => new (classRef)(...injectArgs(provider.deps));
}
else {
return getFactoryDef(classRef) || injectableDefOrInjectorDefFactory(classRef);
}
}
}
return factory;
}
function makeRecord(factory, value, multi = false) {
return {
factory: factory,
value: value,
multi: multi ? [] : undefined,
};
}
function hasDeps(value) {
return !!value.deps;
}
function hasOnDestroy(value) {
return value !== null && typeof value === 'object' &&
typeof value.ngOnDestroy === 'function';
}
function couldBeInjectableType(value) {
return (typeof value === 'function') ||
(typeof value === 'object' && value instanceof InjectionToken);
}
function forEachSingleProvider(providers, fn) {
for (const provider of providers) {
if (Array.isArray(provider)) {
forEachSingleProvider(provider, fn);
}
else if (provider && isEnvironmentProviders(provider)) {
forEachSingleProvider(provider.ɵproviders, fn);
}
else {
fn(provider);
}
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicjNfaW5qZWN0b3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9wYWNrYWdlcy9jb3JlL3NyYy9kaS9yM19pbmplY3Rvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7O0dBTUc7QUFFSCxPQUFPLHFCQUFxQixDQUFDO0FBRTdCLE9BQU8sRUFBQyxZQUFZLEVBQW1CLE1BQU0sV0FBVyxDQUFDO0FBR3pELE9BQU8sRUFBQyxrQ0FBa0MsRUFBRSwyQkFBMkIsRUFBMkIsNEJBQTRCLEVBQUUsMEJBQTBCLEVBQUMsTUFBTSxvQ0FBb0MsQ0FBQztBQUN0TSxPQUFPLEVBQVksYUFBYSxFQUFDLE1BQU0sK0JBQStCLENBQUM7QUFDdkUsT0FBTyxFQUFDLDBCQUEwQixFQUFFLHlCQUF5QixFQUFFLDRCQUE0QixFQUFDLE1BQU0sc0JBQXNCLENBQUM7QUFDekgsT0FBTyxFQUFDLFNBQVMsRUFBQyxNQUFNLG1CQUFtQixDQUFDO0FBQzVDLE9BQU8sRUFBQyxRQUFRLEVBQUMsTUFBTSxxQkFBcUIsQ0FBQztBQUM3QyxPQUFPLEVBQUMsV0FBVyxFQUFDLE1BQU0sZUFBZSxDQUFDO0FBQzFDLE9BQU8sRUFBQyxTQUFTLEVBQUMsTUFBTSxtQkFBbUIsQ0FBQztBQUU1QyxPQUFPLEVBQUMsaUJBQWlCLEVBQUMsTUFBTSxlQUFlLENBQUM7QUFDaEQsT0FBTyxFQUFDLHVCQUF1QixFQUFDLE1BQU0scUJBQXFCLENBQUM7QUFDNUQsT0FBTyxFQUFDLHVCQUF1QixFQUFDLE1BQU0saUJBQWlCLENBQUM7QUFDeEQsT0FBTyxFQUFDLGNBQWMsRUFBQyxNQUFNLG1CQUFtQixDQUFDO0FBRWpELE9BQU8sRUFBQyxrQkFBa0IsRUFBRSxpQkFBaUIsRUFBRSxVQUFVLEVBQUUsa0JBQWtCLEVBQUUsa0JBQWtCLEVBQUUsa0JBQWtCLEVBQUUsUUFBUSxFQUFDLE1BQU0sMEJBQTBCLENBQUM7QUFDakssT0FBTyxFQUFDLFFBQVEs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T0FBTyxLQUFLLEtBQUssVUFBVSxDQUFDO1FBQ2hDLENBQUMsT0FBTyxLQUFLLEtBQUssUUFBUSxJQUFJLEtBQUssWUFBWSxjQUFjLENBQUMsQ0FBQztBQUNyRSxDQUFDO0FBRUQsU0FBUyxxQkFBcUIsQ0FDMUIsU0FBK0MsRUFBRSxFQUFzQztJQUN6RixLQUFLLE1BQU0sUUFBUSxJQUFJLFNBQVMsRUFBRSxDQUFDO1FBQ2pDLElBQUksS0FBSyxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDO1lBQzVCLHFCQUFxQixDQUFDLFFBQVEsRUFBRSxFQUFFLENBQUMsQ0FBQztRQUN0QyxDQUFDO2FBQU0sSUFBSSxRQUFRLElBQUksc0JBQXNCLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQztZQUN4RCxxQkFBcUIsQ0FBQyxRQUFRLENBQUMsVUFBVSxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBQ2pELENBQUM7YUFBTSxDQUFDO1lBQ04sRUFBRSxDQUFDLFFBQTBCLENBQUMsQ0FBQztRQUNqQyxDQUFDO0lBQ0gsQ0FBQztBQUNILENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEBsaWNlbnNlXG4gKiBDb3B5cmlnaHQgR29vZ2xlIExMQyBBbGwgUmlnaHRzIFJlc2VydmVkLlxuICpcbiAqIFVzZSBvZiB0aGlzIHNvdXJjZSBjb2RlIGlzIGdvdmVybmVkIGJ5IGFuIE1JVC1zdHlsZSBsaWNlbnNlIHRoYXQgY2FuIGJlXG4gKiBmb3VuZCBpbiB0aGUgTElDRU5TRSBmaWxlIGF0IGh0dHBzOi8vYW5ndWxhci5pby9saWNlbnNlXG4gKi9cblxuaW1wb3J0ICcuLi91dGlsL25nX2Rldl9tb2RlJztcblxuaW1wb3J0IHtSdW50aW1lRXJyb3IsIFJ1bnRpbWVFcnJvckNvZGV9IGZyb20gJy4uL2Vycm9ycyc7XG5pbXBvcnQge09uRGVzdHJveX0gZnJvbSAnLi4vaW50ZXJmYWNlL2xpZmVjeWNsZV9ob29rcyc7XG5pbXBvcnQge1R5cGV9IGZyb20gJy4uL2ludGVyZmFjZS90eXBlJztcbmltcG9ydCB7ZW1pdEluc3RhbmNlQ3JlYXRlZEJ5SW5qZWN0b3JFdmVudCwgZW1pdFByb3ZpZGVyQ29uZmlndXJlZEV2ZW50LCBJbmplY3RvclByb2ZpbGVyQ29udGV4dCwgcnVuSW5JbmplY3RvclByb2ZpbGVyQ29udGV4dCwgc2V0SW5qZWN0b3JQcm9maWxlckNvbnRleHR9IGZyb20gJy4uL3JlbmRlcjMvZGVidWcvaW5qZWN0b3JfcHJvZmlsZXInO1xuaW1wb3J0IHtGYWN0b3J5Rm4sIGdldEZhY3RvcnlEZWZ9IGZyb20gJy4uL3JlbmRlcjMvZGVmaW5pdGlvbl9mYWN0b3J5JztcbmltcG9ydCB7dGhyb3dDeWNsaWNEZXBlbmRlbmN5RXJyb3IsIHRocm93SW52YWxpZFByb3ZpZGVyRXJyb3IsIHRocm93TWl4ZWRNdWx0aVByb3ZpZGVyRXJyb3J9IGZyb20gJy4uL3JlbmRlcjMvZXJyb3JzX2RpJztcbmltcG9ydCB7TkdfRU5WX0lEfSBmcm9tICcuLi9yZW5kZXIzL2ZpZWxkcyc7XG5pbXBvcnQge25ld0FycmF5fSBmcm9tICcuLi91dGlsL2FycmF5X3V0aWxzJztcbmltcG9ydCB7RU1QVFlfQVJSQVl9IGZyb20gJy4uL3V0aWwvZW1wdHknO1xuaW1wb3J0IHtzdHJpbmdpZnl9IGZyb20gJy4uL3V0aWwvc3RyaW5naWZ5JztcblxuaW1wb3J0IHtyZXNvbHZlRm9yd2FyZFJlZn0gZnJvbSAnLi9mb3J3YXJkX3JlZic7XG5pbXBvcnQge0VOVklST05NRU5UX0lOSVRJQUxJWkVSfSBmcm9tICcuL2luaXRpYWxpemVyX3Rva2VuJztcbmltcG9ydCB7c2V0SW5qZWN0SW1wbGVtZW50YXRpb259IGZyb20gJy4vaW5qZWN0X3N3aXRjaCc7XG5pbXBvcnQge0luamVjdGlvblRva2VufSBmcm9tICcuL2luamVjdGlvbl90b2tlbic7XG5pbXBvcnQge0luamVjdG9yfSBmcm9tICcuL2luamVjdG9yJztcbmltcG9ydCB7Y2F0Y2hJbmplY3RvckVycm9yLCBjb252ZXJ0VG9CaXRGbGFncywgaW5qZWN0QXJncywgTkdfVEVNUF9UT0tFTl9QQVRILCBzZXRDdXJyZW50SW5qZWN0b3IsIFRIUk9XX0lGX05PVF9GT1VORCwgybXJtWluamVjdH0gZnJvbSAnLi9pbmplY3Rvcl9jb21wYXRpYmlsaXR5JztcbmltcG9ydCB7SU5KRUNUT1J9IGZyb20gJy4vaW5qZWN0b3JfdG9rZW4nO1xuaW1wb3J0IHtnZXRJbmhlcml0ZWRJbmplY3RhYmxlRGVmLCBnZXRJbmplY3RhYmxlRGVmLCBJbmplY3RvclR5cGUsIMm1ybVJbmplY3RhYmxlRGVjbGFyYXRpb259IGZyb20gJy4vaW50ZXJmYWNlL2RlZnMnO1xuaW1wb3J0IHtJbmplY3RGbGFncywgSW5qZWN0T3B0aW9uc30gZnJvbSAnLi9pbnRlcmZhY2UvaW5qZWN0b3InO1xuaW1wb3J0IHtDbGFzc1Byb3ZpZGVyLCBDb25zdHJ1Y3RvclByb3ZpZGVyLCBFbnZpcm9ubWVudFByb3ZpZGVycywgSW50ZXJuYWxFbnZpcm9ubWVudFByb3ZpZGVycywgaXNFbnZpcm9ubWVudFByb3ZpZGVycywgUHJvdmlkZXIsIFN0YXRpY0NsYXNzUHJvdmlkZXIsIFR5cGVQcm92aWRlcn0gZnJvbSAnLi9pbnRlcmZhY2UvcHJvdmlkZXInO1xuaW1wb3J0IHtJTkpFQ1RPUl9ERUZfVFlQRVN9IGZyb20gJy4vaW50ZXJuYWxfdG9rZW5zJztcbmltcG9ydCB7TnVsbEluamVjdG9yfSBmcm9tICcuL251bGxfaW5qZWN0b3InO1xuaW1wb3J0IHtpc0V4aXN0aW5nUHJvdmlkZXIsIGlzRmFjdG9yeVByb3ZpZGVyLCBpc1R5cGVQcm92aWRlciwgaXNWYWx1ZVByb3ZpZGVyLCBTaW5nbGVQcm92aWRlcn0gZnJvbSAnLi9wcm92aWRlcl9jb2xsZWN0aW9uJztcbmltcG9ydCB7UHJvdmlkZXJUb2tlbn0gZnJvbSAnLi9wcm92aWRlcl90b2tlbic7XG5pbXBvcnQge0lOSkVDVE9SX1NDT1BFLCBJbmplY3RvclNjb3BlfSBmcm9tICcuL3Njb3BlJztcblxuLyoqXG4gKiBNYXJrZXIgd2hpY2ggaW5kaWNhdGVzIHRoYXQgYSB2YWx1ZSBoYXMgbm90IHlldCBiZWVuIGNyZWF0ZWQgZnJvbSB0aGUgZmFjdG9yeSBmdW5jdGlvbi5cbiAqL1xuY29uc3QgTk9UX1lFVCA9IHt9O1xuXG4vKipcbiAqIE1hcmtlciB3aGljaCBpbmRpY2F0ZXMgdGhhdCB0aGUgZmFjdG9yeSBmdW5jdGlvbiBmb3IgYSB0b2tlbiBpcyBpbiB0aGUgcHJvY2VzcyBvZiBiZWluZyBjYWxsZWQuXG4gKlxuICogSWYgdGhlIGluamVjdG9yIGlzIGFza2VkIHRvIGluamVjdCBhIHRva2VuIHdpdGggaXRzIHZhbHVlIHNldCB0byBDSVJDVUxBUiwgdGhhdCBpbmRpY2F0ZXNcbiAqIGluamVjdGlvbiBvZiBhIGRlcGVuZGVuY3kgaGFzIHJlY3Vyc2l2ZWx5IGF0dGVtcHRlZCB0byBpbmplY3QgdGhlIG9yaWdpbmFsIHRva2VuLCBhbmQgdGhlcmUgaXNcbiAqIGEgY2lyY3VsYXIgZGVwZW5kZW5jeSBhbW9uZyB0aGUgcHJvdmlkZXJzLlxuICovXG5jb25zdCBDSVJDVUxBUiA9IHt9O1xuXG4vKipcbiAqIEEgbGF6aWx5IGluaXRpYWxpemVkIE51bGxJbmplY3Rvci5cbiAqL1xubGV0IE5VTExfSU5KRUNUT1I6IEluamVjdG9yfHVuZGVmaW5lZCA9IHVuZGVmaW5lZDtcblxuZXhwb3J0IGZ1bmN0aW9uIGdldE51bGxJbmplY3RvcigpOiBJbmplY3RvciB7XG4gIGlmIChOVUxMX0lOSkVDVE9SID09PSB1bmRlZmluZWQpIHtcbiAgICBOVUxMX0lOSkVDVE9SID0gbmV3IE51bGxJbmplY3RvcigpO1xuICB9XG4gIHJldHVybiBOVUxMX0lOSkVDVE9SO1xufVxuXG4vKipcbiAqIEFuIGVudHJ5IGluIHRoZSBpbmplY3RvciB3aGljaCB0cmFja3MgaW5mb3JtYXRpb24gYWJvdXQgdGhlIGdpdmVuIHRva2VuLCBpbmNsdWRpbmcgYSBwb3NzaWJsZVxuICogY3VycmVudCB2YWx1ZS5cbiAqL1xuaW50ZXJmYWNlIFJlY29yZDxUPiB7XG4gIGZhY3Rvcnk6ICgoKSA9PiBUKXx1bmRlZmluZWQ7XG4gIHZhbHVlOiBUfHt9O1xuICBtdWx0aTogYW55W118dW5kZWZpbmVkO1xufVxuXG4vKipcbiAqIEFuIGBJbmplY3RvcmAgdGhhdCdzIHBhcnQgb2YgdGhlIGVudmlyb25tZW50IGluamVjdG9yIGhpZXJhcmNoeSwgd2hpY2ggZXhpc3RzIG91dHNpZGUgb2YgdGhlXG4gKiBjb21wb25lbnQgdHJlZS5cbiAqL1xuZXhwb3J0IGFic3RyYWN0IGNsYXNzIEVudmlyb25tZW50SW5qZWN0b3IgaW1wbGVtZW50cyBJbmplY3RvciB7XG4gIC8qKlxuICAgKiBSZXRyaWV2ZXMgYW4gaW5zdGFuY2UgZnJvbSB0aGUgaW5qZWN0b3IgYmFzZWQgb24gdGhlIHByb3ZpZGVkIHRva2VuLlxuICAgKiBAcmV0dXJucyBUaGUgaW5zdGFuY2UgZnJvbSB0aGUgaW5qZWN0b3IgaWYgZGVmaW5lZCwgb3RoZXJ3aXNlIHRoZSBgbm90Rm91bmRWYWx1ZWAuXG4gICAqIEB0aHJvd3MgV2hlbiB0aGUgYG5vdEZvdW5kVmFsdWVgIGlzIGB1bmRlZmluZWRgIG9yIGBJbmplY3Rvci5USFJPV19JRl9OT1RfRk9VTkRgLlxuICAgKi9cbiAgYWJzdHJhY3QgZ2V0PFQ+KHRva2VuOiBQcm92aWRlclRva2VuPFQ+LCBub3RGb3VuZFZhbHVlOiB1bmRlZmluZWQsIG9wdGlvbnM6IEluamVjdE9wdGlvbnMme1xuICAgIG9wdGlvbmFsPzogZmFsc2U7XG4gIH0pOiBUO1xuICAvKipcbiAgICogUmV0cmlldmVzIGFuIGluc3RhbmNlIGZyb20gdGhlIGluamVjdG9yIGJhc2VkIG9uIHRoZSBwcm92aWRlZCB0b2tlbi5cbiAgICogQHJldHVybnMgVGhlIGluc3RhbmNlIGZyb20gdGhlIGluamVjdG9yIGlmIGRlZmluZWQsIG90aGVyd2lzZSB0aGUgYG5vdEZvdW5kVmFsdWVgLlxuICAgKiBAdGhyb3dzIFdoZW4gdGhlIGBub3RGb3VuZFZhbHVlYCBpcyBgdW5kZWZpbmVkYCBvciBgSW5qZWN0b3IuVEhST1dfSUZfTk9UX0ZPVU5EYC5cbiAgICovXG4gIGFic3RyYWN0IGdldDxUPih0b2tlbjogUHJvdmlkZXJUb2tlbjxUPiwgbm90Rm91bmRWYWx1ZTogbnVsbHx1bmRlZmluZWQsIG9wdGlvbnM6IEluamVjdE9wdGlvbnMpOiBUXG4gICAgICB8bnVsbDtcbiAgLyoqXG4gICAqIFJldHJpZXZlcyBhbiBpbnN0YW5jZSBmcm9tIHRoZSBpbmplY3RvciBiYXNlZCBvbiB0aGUgcHJvdmlkZWQgdG9rZW4uXG4gICAqIEByZXR1cm5zIFRoZSBpbnN0YW5jZSBmcm9tIHRoZSBpbmplY3RvciBpZiBkZWZpbmVkLCBvdGhlcndpc2UgdGhlIGBub3RGb3VuZFZhbHVlYC5cbiAgICogQHRocm93cyBXaGVuIHRoZSBgbm90Rm91bmRWYWx1ZWAgaXMgYHVuZGVmaW5lZGAgb3IgYEluamVjdG9yLlRIUk9XX0lGX05PVF9GT1VORGAuXG4gICAqL1xuICBhYnN0cmFjdCBnZXQ8VD4odG9rZW46IFByb3ZpZGVyVG9rZW48VD4sIG5vdEZvdW5kVmFsdWU/OiBULCBvcHRpb25zPzogSW5qZWN0T3B0aW9ucyk6IFQ7XG4gIC8qKlxuICAgKiBSZXRyaWV2ZXMgYW4gaW5zdGFuY2UgZnJvbSB0aGUgaW5qZWN0b3IgYmFzZWQgb24gdGhlIHByb3ZpZGVkIHRva2VuLlxuICAgKiBAcmV0dXJucyBUaGUgaW5zdGFuY2UgZnJvbSB0aGUgaW5qZWN0b3IgaWYgZGVmaW5lZCwgb3RoZXJ3aXNlIHRoZSBgbm90Rm91bmRWYWx1ZWAuXG4gICAqIEB0aHJvd3MgV2hlbiB0aGUgYG5vdEZvdW5kVmFsdWVgIGlzIGB1bmRlZmluZWRgIG9yIGBJbmplY3Rvci5USFJPV19JRl9OT1RfRk9VTkRgLlxuICAgKiBAZGVwcmVjYXRlZCB1c2Ugb2JqZWN0LWJhc2VkIGZsYWdzIChgSW5qZWN0T3B0aW9uc2ApIGluc3RlYWQuXG4gICAqL1xuICBhYnN0cmFjdCBnZXQ8VD4odG9rZW46IFByb3ZpZGVyVG9rZW48VD4sIG5vdEZvdW5kVmFsdWU/OiBULCBmbGFncz86IEluamVjdEZsYWdzKTogVDtcbiAgLyoqXG4gICAqIEBkZXByZWNhdGVkIGZyb20gdjQuMC4wIHVzZSBQcm92aWRlclRva2VuPFQ+XG4gICAqIEBzdXBwcmVzcyB7ZHVwbGljYXRlfVxuICAgKi9cbiAgYWJzdHJhY3QgZ2V0KHRva2VuOiBhbnksIG5vdEZvdW5kVmFsdWU/OiBhbnkpOiBhbnk7XG5cbiAgLyoqXG4gICAqIFJ1bnMgdGhlIGdpdmVuIGZ1bmN0aW9uIGluIHRoZSBjb250ZXh0IG9mIHRoaXMgYEVudmlyb25tZW50SW5qZWN0b3JgLlxuICAgKlxuICAgKiBXaXRoaW4gdGhlIGZ1bmN0aW9uJ3Mgc3RhY2sgZnJhbWUsIFtgaW5qZWN0YF0oYXBpL2NvcmUvaW5qZWN0KSBjYW4gYmUgdXNlZCB0byBpbmplY3RcbiAgICogZGVwZW5kZW5jaWVzIGZyb20gdGhpcyBpbmplY3Rvci4gTm90ZSB0aGF0IGBpbmplY3RgIGlzIG9ubHkgdXNhYmxlIHN5bmNocm9ub3VzbHksIGFuZCBjYW5ub3QgYmVcbiAgICogdXNlZCBpbiBhbnkgYXN5bmNocm9ub3VzIGNhbGxiYWNrcyBvciBhZnRlciBhbnkgYGF3YWl0YCBwb2ludHMuXG4gICAqXG4gICAqIEBwYXJhbSBmbiB0aGUgY2xvc3VyZSB0byBiZSBydW4gaW4gdGhlIGNvbnRleHQgb2YgdGhpcyBpbmplY3RvclxuICAgKiBAcmV0dXJucyB0aGUgcmV0dXJuIHZhbHVlIG9mIHRoZSBmdW5jdGlvbiwgaWYgYW55XG4gICAqIEBkZXByZWNhdGVkIHVzZSB0aGUgc3RhbmRhbG9uZSBmdW5jdGlvbiBgcnVuSW5JbmplY3Rpb25Db250ZXh0YCBpbnN0ZWFkXG4gICAqL1xuICBhYnN0cmFjdCBydW5JbkNvbnRleHQ8UmV0dXJuVD4oZm46ICgpID0+IFJldHVyblQpOiBSZXR1cm5UO1xuXG4gIGFic3RyYWN0IGRlc3Ryb3koKTogdm9pZDtcblxuICAvKipcbiAgICogQGludGVybmFsXG4gICAqL1xuICBhYnN0cmFjdCBvbkRlc3Ryb3koY2FsbGJhY2s6ICgpID0+IHZvaWQpOiAoKSA9PiB2b2lkO1xufVxuXG5leHBvcnQgY2xhc3MgUjNJbmplY3RvciBleHRlbmRzIEVudmlyb25tZW50SW5qZWN0b3Ige1xuICAvKipcbiAgICogTWFwIG9mIHRva2VucyB0byByZWNvcmRzIHdoaWNoIGNvbnRhaW4gdGhlIGluc3RhbmNlcyBvZiB0aG9zZSB0b2tlbnMuXG4gICAqIC0gYG51bGxgIHZhbHVlIGltcGxpZXMgdGhhdCB3ZSBkb24ndCBoYXZlIHRoZSByZWNvcmQuIFVzZWQgYnkgdHJlZS1zaGFrYWJsZSBpbmplY3RvcnNcbiAgICogdG8gcHJldmVudCBmdXJ0aGVyIHNlYXJjaGVzLlxuICAgKi9cbiAgcHJpdmF0ZSByZWNvcmRzID0gbmV3IE1hcDxQcm92aWRlclRva2VuPGFueT4sIFJlY29yZDxhbnk+fG51bGw+KCk7XG5cbiAgLyoqXG4gICAqIFNldCBvZiB2YWx1ZXMgaW5zdGFudGlhdGVkIGJ5IHRoaXMgaW5qZWN0b3Igd2hpY2ggY29udGFpbiBgbmdPbkRlc3Ryb3lgIGxpZmVjeWNsZSBob29rcy5cbiAgICovXG4gIHByaXZhdGUgX25nT25EZXN0cm95SG9va3MgPSBuZXcgU2V0PE9uRGVzdHJveT4oKTtcblxuICBwcml2YXRlIF9vbkRlc3Ryb3lIb29rczogQXJyYXk8KCkgPT4gdm9pZD4gPSBbXTtcblxuICAvKipcbiAgICogRmxhZyBpbmRpY2F0aW5nIHRoYXQgdGhpcyBpbmplY3RvciB3YXMgcHJldmlvdXNseSBkZXN0cm95ZWQuXG4gICAqL1xuICBnZXQgZGVzdHJveWVkKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLl9kZXN0cm95ZWQ7XG4gIH1cbiAgcHJpdmF0ZSBfZGVzdHJveWVkID0gZmFsc2U7XG5cbiAgcHJpdmF0ZSBpbmplY3RvckRlZlR5cGVzOiBTZXQ8VHlwZTx1bmtub3duPj47XG5cbiAgY29uc3RydWN0b3IoXG4gICAgICBwcm92aWRlcnM6IEFycmF5PFByb3ZpZGVyfEVudmlyb25tZW50UHJvdmlkZXJzPiwgcmVhZG9ubHkgcGFyZW50OiBJbmplY3RvcixcbiAgICAgIHJlYWRvbmx5IHNvdXJjZTogc3RyaW5nfG51bGwsIHJlYWRvbmx5IHNjb3BlczogU2V0PEluamVjdG9yU2NvcGU+KSB7XG4gICAgc3VwZXIoKTtcbiAgICAvLyBTdGFydCBvZmYgYnkgY3JlYXRpbmcgUmVjb3JkcyBmb3IgZXZlcnkgcHJvdmlkZXIuXG4gICAgZm9yRWFjaFNpbmdsZVByb3ZpZGVyKFxuICAgICAgICBwcm92aWRlcnMgYXMgQXJyYXk8UHJvdmlkZXJ8SW50ZXJuYWxFbnZpcm9ubWVudFByb3ZpZGVycz4sXG4gICAgICAgIHByb3ZpZGVyID0+IHRoaXMucHJvY2Vzc1Byb3ZpZGVyKHByb3ZpZGVyKSk7XG5cbiAgICAvLyBNYWtlIHN1cmUgdGhlIElOSkVDVE9SIHRva2VuIHByb3ZpZGVzIHRoaXMgaW5qZWN0b3IuXG4gICAgdGhpcy5yZWNvcmRzLnNldChJTkpFQ1RPUiwgbWFrZVJlY29yZCh1bmRlZmluZWQsIHRoaXMpKTtcblxuICAgIC8vIEFuZCBgRW52aXJvbm1lbnRJbmplY3RvcmAgaWYgdGhlIGN1cnJlbnQgaW5qZWN0b3IgaXMgc3VwcG9zZWQgdG8gYmUgZW52LXNjb3BlZC5cbiAgICBpZiAoc2NvcGVzLmhhcygnZW52aXJvbm1lbnQnKSkge1xuICAgICAgdGhpcy5yZWNvcmRzLnNldChFbnZpcm9ubWVudEluamVjdG9yLCBtYWtlUmVjb3JkKHVuZGVmaW5lZCwgdGhpcykpO1xuICAgIH1cblxuICAgIC8vIERldGVjdCB3aGV0aGVyIHRoaXMgaW5qZWN0b3IgaGFzIHRoZSBBUFBfUk9PVF9TQ09QRSB0b2tlbiBhbmQgdGh1cyBzaG91bGQgcHJvdmlkZVxuICAgIC8vIGFueSBpbmplY3RhYmxlIHNjb3BlZCB0byBBUFBfUk9PVF9TQ09QRS5cbiAgICBjb25zdCByZWNvcmQgPSB0aGlzLnJlY29yZHMuZ2V0KElOSkVDVE9SX1NDT1BFKSBhcyBSZWNvcmQ8SW5qZWN0b3JTY29wZXxudWxsPjtcbiAgICBpZiAocmVjb3JkICE9IG51bGwgJiYgdHlwZW9mIHJlY29yZC52YWx1ZSA9PT0gJ3N0cmluZycpIHtcbiAgICAgIHRoaXMuc2NvcGVzLmFkZChyZWNvcmQudmFsdWUgYXMgSW5qZWN0b3JTY29wZSk7XG4gICAgfVxuXG4gICAgdGhpcy5pbmplY3RvckRlZlR5cGVzID0gbmV3IFNldCh0aGlzLmdldChJTkpFQ1RPUl9ERUZfVFlQRVMsIEVNUFRZX0FSUkFZLCBJbmplY3RGbGFncy5TZWxmKSk7XG4gIH1cblxuICAvKipcbiAgICogRGVzdHJveSB0aGUgaW5qZWN0b3IgYW5kIHJlbGVhc2UgcmVmZXJlbmNlcyB0byBldmVyeSBpbnN0YW5jZSBvciBwcm92aWRlciBhc3NvY2lhdGVkIHdpdGggaXQuXG4gICAqXG4gICAqIEFsc28gY2FsbHMgdGhlIGBPbkRlc3Ryb3lgIGxpZmVjeWNsZSBob29rcyBvZiBldmVyeSBpbnN0YW5jZSB0aGF0IHdhcyBjcmVhdGVkIGZvciB3aGljaCBhXG4gICAqIGhvb2sgd2FzIGZvdW5kLlxuICAgKi9cbiAgb3ZlcnJpZGUgZGVzdHJveSgpOiB2b2lkIHtcbiAgICB0aGlzLmFzc2VydE5vdERlc3Ryb3llZCgpO1xuXG4gICAgLy8gU2V0IGRlc3Ryb3llZCA9IHRydWUgZmlyc3QsIGluIGNhc2UgbGlmZWN5Y2xlIGhvb2tzIHJlLWVudGVyIGRlc3Ryb3koKS5cbiAgICB0aGlzLl9kZXN0cm95ZWQgPSB0cnVlO1xuICAgIHRyeSB7XG4gICAgICAvLyBDYWxsIGFsbCB0aGUgbGlmZWN5Y2xlIGhvb2tzLlxuICAgICAgZm9yIChjb25zdCBzZXJ2aWNlIG9mIHRoaXMuX25nT25EZXN0cm95SG9va3MpIHtcbiAgICAgICAgc2VydmljZS5uZ09uRGVzdHJveSgpO1xuICAgICAgfVxuICAgICAgY29uc3Qgb25EZXN0cm95SG9va3MgPSB0aGlzLl9vbkRlc3Ryb3lIb29rcztcbiAgICAgIC8vIFJlc2V0IHRoZSBfb25EZ