@tsclean/core
Version:
Plugin for API Rest Full development, based on Clean Architecture, IoC and Dependency Injection.
322 lines • 56.7 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.DependenciesScanner = void 0;
const iterare_1 = require("iterare");
const application_config_1 = require("./application-config");
const constants_1 = require("./constants");
const errors_1 = require("../errors");
const helpers_1 = require("../helpers");
const core_1 = require("../core");
const contracts_1 = require("../contracts");
const helpers_2 = require("../helpers");
const utils_1 = require("../utils");
class DependenciesScanner {
constructor(container, metadataScanner, graphInspector, applicationConfig = new application_config_1.ApplicationConfig()) {
this.container = container;
this.metadataScanner = metadataScanner;
this.graphInspector = graphInspector;
this.applicationConfig = applicationConfig;
this.applicationProvidersApplyMap = [];
}
async scan(module) {
await this.registerCoreModule();
await this.scanForModules(module);
await this.scanModulesForDependencies();
await this.calculateModulesDistance();
this.addScopedEnhancersMetadata();
this.container.bindGlobalScope();
}
async scanForModules(moduleDefinition, scope = [], ctxRegistry = []) {
const moduleInstance = await this.insertModule(moduleDefinition, scope);
moduleDefinition =
moduleDefinition instanceof Promise
? await moduleDefinition
: moduleDefinition;
ctxRegistry.push(moduleDefinition);
if (this.isForwardReference(moduleDefinition))
moduleDefinition = moduleDefinition.forwardRef();
const modules = !this.isDynamicModule(moduleDefinition)
? this.reflectMetadata(moduleDefinition, helpers_2.MODULE_METADATA.IMPORTS)
: [
...this.reflectMetadata(moduleDefinition.module, helpers_2.MODULE_METADATA.IMPORTS),
...(moduleDefinition.imports || [])
];
let registeredModuleRefs = [];
for (const [index, innerModule] of modules.entries()) {
if (innerModule === undefined)
throw new errors_1.UndefinedModuleException(moduleDefinition, index, scope);
if (!innerModule)
throw new errors_1.InvalidModuleException(moduleDefinition, index, scope);
if (ctxRegistry.includes(innerModule)) {
continue;
}
const moduleRefs = await this.scanForModules(innerModule, [].concat(scope, moduleDefinition), ctxRegistry);
registeredModuleRefs = registeredModuleRefs.concat(moduleRefs);
}
if (!moduleInstance) {
return registeredModuleRefs;
}
return [moduleInstance].concat(registeredModuleRefs);
}
async insertModule(module, scope) {
if (module && module.forwardRef)
return this.container.addModule(module.forwardRef(), scope);
return this.container.addModule(module, scope);
}
async scanModulesForDependencies(modules = this.container.getModules()) {
for (const [token, { metaType }] of modules) {
await this.reflectImports(metaType, token, metaType.name);
this.reflectProviders(metaType, token);
this.reflectControllers(metaType, token);
this.reflectExports(metaType, token);
}
}
async reflectImports(module, token, context) {
const modules = [
...this.reflectMetadata(module, helpers_2.MODULE_METADATA.IMPORTS),
...this.container.getDynamicMetadataByToken(token, helpers_2.MODULE_METADATA.IMPORTS)
];
for (const related of modules) {
await this.insertImport(related, token, context);
}
}
reflectProviders(module, token) {
const providers = [
...this.reflectMetadata(module, helpers_2.MODULE_METADATA.PROVIDERS),
...this.container.getDynamicMetadataByToken(token, helpers_2.MODULE_METADATA.PROVIDERS)
];
providers.forEach(provider => {
this.insertProvider(provider, token);
this.reflectDynamicMetadata(provider, token);
});
}
reflectControllers(module, token) {
const controllers = [
...this.reflectMetadata(module, helpers_2.MODULE_METADATA.CONTROLLERS),
...this.container.getDynamicMetadataByToken(token, helpers_2.MODULE_METADATA.CONTROLLERS)
];
controllers.forEach(item => {
this.insertController(item, token);
this.reflectDynamicMetadata(item, token);
});
}
reflectDynamicMetadata(obj, token) {
if (!obj || !obj.prototype) {
return;
}
this.reflectInjectables(obj, token, helpers_2.RESOURCES_METADATA);
this.reflectInjectables(obj, token, helpers_2.INTERCEPTORS_METADATA);
this.reflectInjectables(obj, token, helpers_2.EXCEPTION_FILTERS_METADATA);
this.reflectInjectables(obj, token, helpers_2.HANDLER_METADATA);
this.reflectParamInjectables(obj, token, helpers_2.ROUTE_ARGS_METADATA);
}
reflectExports(module, token) {
const exports = [
...this.reflectMetadata(module, helpers_2.MODULE_METADATA.EXPORTS),
...this.container.getDynamicMetadataByToken(token, helpers_2.MODULE_METADATA.EXPORTS)
];
exports.forEach(exportedProvider => this.insertExportedProvider(exportedProvider, token));
}
reflectInjectables(component, token, metadataKey) {
const controllerInjectables = this.reflectMetadata(component, metadataKey);
const methodInjectables = this.metadataScanner
.getAllMethodNames(component.prototype)
.reduce((acc, method) => {
const methodInjectable = this.reflectKeyMetadata(component, metadataKey, method) || { metadata: [] };
if (methodInjectable) {
acc.push(methodInjectable);
}
return acc;
}, []);
controllerInjectables.forEach(injectable => this.insertInjectable(injectable, token, component, helpers_1.ENHANCER_KEY_TO_SUBTYPE_MAP[metadataKey]));
methodInjectables.forEach(methodInjectable => {
if (methodInjectable.metadata) {
methodInjectable.metadata.forEach(injectable => this.insertInjectable(injectable, token, component, helpers_1.ENHANCER_KEY_TO_SUBTYPE_MAP[metadataKey], methodInjectable.methodKey));
}
else {
console.warn(`No metadata found for method ${methodInjectable.methodKey}`);
}
});
}
reflectParamInjectables(component, token, metadataKey) {
const paramsMethods = this.metadataScanner.getAllMethodNames(component.prototype);
paramsMethods.forEach(methodKey => {
const metadata = Reflect.getMetadata(metadataKey, component, methodKey);
if (!metadata) {
return;
}
const params = Object.values(metadata);
params
.map(item => item.pipes)
.flat(1)
.forEach(injectable => this.insertInjectable(injectable, token, component, 'resource', methodKey));
});
}
reflectKeyMetadata(component, key, method) {
let prototype = component.prototype;
do {
const descriptor = Reflect.getOwnPropertyDescriptor(prototype, method);
if (!descriptor)
continue;
return Reflect.getMetadata(key, descriptor.value);
} while ((prototype = Reflect.getPrototypeOf(prototype)) &&
prototype !== Object.prototype &&
prototype);
return undefined;
}
async calculateModulesDistance() {
const modulesGenerator = this.container.getModules().values();
modulesGenerator.next();
const modulesStack = [];
const calculateDistance = (moduleRef, distance = 1) => {
if (modulesStack.includes(moduleRef))
return;
modulesStack.push(moduleRef);
const moduleImports = moduleRef.imports;
moduleImports.forEach(importedModuleRef => {
if (importedModuleRef) {
importedModuleRef.distance = distance;
calculateDistance(importedModuleRef, distance + 1);
}
});
};
const rootModule = modulesGenerator.next().value;
calculateDistance(rootModule);
}
async insertImport(related, token, context) {
if ((0, utils_1.isUndefined)(related)) {
throw new errors_1.CircularDependencyException(context);
}
if (related && related.forwardRef)
return this.container.addImport(related.forwardRef(), token);
await this.container.addImport(related, token);
}
isCustomProvider(provider) {
return provider && !(0, utils_1.isNil)(provider.provide);
}
insertProvider(provider, token) {
const isCustomProvider = this.isCustomProvider(provider);
if (!isCustomProvider)
return this.container.addProvider(provider, token);
const applyProvidersMap = this.getApplyProvidersMap();
const providersKeys = Object.keys(applyProvidersMap);
const type = provider.provide;
if (!providersKeys.includes(type))
return this.container.addProvider(provider, token);
const providerToken = `${type} (UUID: ${(0, utils_1.randomStringGenerator)()})`;
let scope = provider.scope;
if ((0, utils_1.isNil)(scope) && provider.useClass)
scope = (0, helpers_1.getClassScope)(provider.useClass);
this.applicationProvidersApplyMap.push({
type,
moduleKey: token,
providerKey: providerToken,
scope
});
const newProvider = Object.assign(Object.assign({}, provider), { provide: providerToken, scope });
const enhancerSubtype = constants_1.ENHANCER_TOKEN_TO_SUBTYPE_MAP[type];
const factoryOrClassProvider = newProvider;
if (DependenciesScanner.isRequestOrTransient(factoryOrClassProvider.scope))
return this.container.addInjectable(newProvider, token, enhancerSubtype);
this.container.addProvider(newProvider, token, enhancerSubtype);
}
insertInjectable(injectable, token, host, subtype, methodKey) {
if ((0, utils_1.isFunction)(injectable)) {
const instanceWrapper = this.container.addInjectable(injectable, token, subtype, host);
this.graphInspector.insertEnhancerMetadataCache({
moduleToken: token,
classRef: host,
enhancerInstanceWrapper: instanceWrapper,
targetNodeId: instanceWrapper.id,
subtype,
methodKey
});
return instanceWrapper;
}
else {
this.graphInspector.insertEnhancerMetadataCache({
moduleToken: token,
classRef: host,
enhancerRef: injectable,
methodKey,
subtype
});
}
}
insertExportedProvider(exportedProvider, token) {
this.container.addExportedProvider(exportedProvider, token);
}
insertController(controller, token) {
this.container.addController(controller, token);
}
reflectMetadata(metaType, metadataKey) {
return Reflect.getMetadata(metadataKey, metaType) || [];
}
async registerCoreModule() {
const moduleDefinition = core_1.InternalCoreModuleFactory.create(this.container, this, this.container.getModuleCompiler(), this.container.getHttpAdapterHostRef());
const [instance] = await this.scanForModules(moduleDefinition);
this.container.registerCoreModuleRef(instance);
}
addScopedEnhancersMetadata() {
(0, iterare_1.iterate)(this.applicationProvidersApplyMap)
.filter(wrapper => DependenciesScanner.isRequestOrTransient(wrapper.scope))
.forEach(({ moduleKey, providerKey }) => {
const modulesContainer = this.container.getModules();
const { injectables } = modulesContainer.get(moduleKey);
const instanceWrapper = injectables.get(providerKey);
(0, iterare_1.iterate)(modulesContainer.values())
.map(module => module.controllers.values())
.flatten()
.forEach(controller => controller.addEnhancerMetadata(instanceWrapper));
});
}
applyApplicationProviders() {
const applyProvidersMap = this.getApplyProvidersMap();
const applyRequestProvidersMap = this.getApplyRequestProvidersMap();
const getInstanceWrapper = (moduleKey, providerKey, collectionKey) => {
const modules = this.container.getModules();
const collection = modules.get(moduleKey)[collectionKey];
return collection.get(providerKey);
};
this.applicationProvidersApplyMap.forEach(({ moduleKey, providerKey, type, scope }) => {
let instanceWrapper;
if (DependenciesScanner.isRequestOrTransient(scope)) {
instanceWrapper = getInstanceWrapper(moduleKey, providerKey, 'injectables');
return applyRequestProvidersMap[type](instanceWrapper);
}
instanceWrapper = getInstanceWrapper(moduleKey, providerKey, 'providers');
applyProvidersMap[type](instanceWrapper.instance);
});
}
getApplyProvidersMap() {
return {
[constants_1.APP_INTERCEPTOR]: (interceptor) => this.applicationConfig.addGlobalInterceptor(interceptor),
[constants_1.APP_HANDLER]: (handler) => this.applicationConfig.addGlobalHandler(handler),
[constants_1.APP_RESOURCE]: (guard) => this.applicationConfig.addGlobalAccessResource(guard),
[constants_1.APP_FILTER]: (filter) => this.applicationConfig.addGlobalFilter(filter)
};
}
getApplyRequestProvidersMap() {
return {
[constants_1.APP_INTERCEPTOR]: (interceptor) => this.applicationConfig.addGlobalRequestInterceptor(interceptor),
[constants_1.APP_HANDLER]: (handler) => this.applicationConfig.addGlobalRequestHandler(handler),
[constants_1.APP_GUARD]: (guard) => this.applicationConfig.addGlobalRequestGuard(guard),
[constants_1.APP_RESOURCE]: (guard) => this.applicationConfig.addGlobalRequestAccessResource(guard),
[constants_1.APP_FILTER]: (filter) => this.applicationConfig.addGlobalRequestFilter(filter)
};
}
isDynamicModule(module) {
return module && !!module.module;
}
isForwardReference(module) {
return module && !!module.forwardRef;
}
static flatten(arr) {
return arr.reduce((a, b) => a.concat(b), []);
}
static isRequestOrTransient(scope) {
return scope === contracts_1.Scope.REQUEST || scope === contracts_1.Scope.TRANSIENT;
}
}
exports.DependenciesScanner = DependenciesScanner;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2Nhbm5lci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9hcHAvc2Nhbm5lci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSxxQ0FBaUM7QUFDakMsNkRBQXdEO0FBQ3hELDJDQU9vQjtBQUNwQixzQ0FJa0I7QUFDbEIsd0NBSW1CO0FBQ25CLGtDQUtnQjtBQUVoQiw0Q0FjcUI7QUFDckIsd0NBT21CO0FBQ25CLG9DQUFnRjtBQUtoRixNQUFhLG1CQUFtQjtJQUk5QixZQUNtQixTQUF1QixFQUN2QixlQUFnQyxFQUNoQyxjQUE4QixFQUM5QixvQkFBb0IsSUFBSSxzQ0FBaUIsRUFBRTtRQUgzQyxjQUFTLEdBQVQsU0FBUyxDQUFjO1FBQ3ZCLG9CQUFlLEdBQWYsZUFBZSxDQUFpQjtRQUNoQyxtQkFBYyxHQUFkLGNBQWMsQ0FBZ0I7UUFDOUIsc0JBQWlCLEdBQWpCLGlCQUFpQixDQUEwQjtRQVA3QyxpQ0FBNEIsR0FDM0MsRUFBRSxDQUFBO0lBT0EsQ0FBQztJQUVFLEtBQUssQ0FBQyxJQUFJLENBQUMsTUFBaUI7UUFDakMsTUFBTSxJQUFJLENBQUMsa0JBQWtCLEVBQUUsQ0FBQTtRQUMvQixNQUFNLElBQUksQ0FBQyxjQUFjLENBQUMsTUFBTSxDQUFDLENBQUE7UUFDakMsTUFBTSxJQUFJLENBQUMsMEJBQTBCLEVBQUUsQ0FBQTtRQUN2QyxNQUFNLElBQUksQ0FBQyx3QkFBd0IsRUFBRSxDQUFBO1FBRXJDLElBQUksQ0FBQywwQkFBMEIsRUFBRSxDQUFBO1FBQ2pDLElBQUksQ0FBQyxTQUFTLENBQUMsZUFBZSxFQUFFLENBQUE7SUFDbEMsQ0FBQztJQUVNLEtBQUssQ0FBQyxjQUFjLENBQ3pCLGdCQUltQyxFQUNuQyxRQUF5QixFQUFFLEVBQzNCLGNBSU0sRUFBRTtRQUVSLE1BQU0sY0FBYyxHQUFHLE1BQU0sSUFBSSxDQUFDLFlBQVksQ0FBQyxnQkFBZ0IsRUFBRSxLQUFLLENBQUMsQ0FBQTtRQUN2RSxnQkFBZ0I7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LE1BQU0sSUFBSSxDQUFDLENBQUUsTUFBb0MsQ0FBQyxVQUFVLENBQUE7SUFDckUsQ0FBQztJQUVPLE1BQU0sQ0FBQyxPQUFPLENBQVUsR0FBVTtRQUN4QyxPQUFPLEdBQUcsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFNLEVBQUUsQ0FBTSxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDO0lBQ3pELENBQUM7SUFFTyxNQUFNLENBQUMsb0JBQW9CLENBQUMsS0FBWTtRQUM5QyxPQUFPLEtBQUssS0FBSyxpQkFBSyxDQUFDLE9BQU8sSUFBSSxLQUFLLEtBQUssaUJBQUssQ0FBQyxTQUFTLENBQUE7SUFDN0QsQ0FBQztDQUNGO0FBaGlCRCxrREFnaUJDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgaXRlcmF0ZSB9IGZyb20gJ2l0ZXJhcmUnXG5pbXBvcnQgeyBBcHBsaWNhdGlvbkNvbmZpZyB9IGZyb20gJy4vYXBwbGljYXRpb24tY29uZmlnJ1xuaW1wb3J0IHtcbiAgQVBQX0ZJTFRFUixcbiAgQVBQX0dVQVJELFxuICBBUFBfSEFORExFUixcbiAgQVBQX0lOVEVSQ0VQVE9SLFxuICBBUFBfUkVTT1VSQ0UsXG4gIEVOSEFOQ0VSX1RPS0VOX1RPX1NVQlRZUEVfTUFQXG59IGZyb20gJy4vY29uc3RhbnRzJ1xuaW1wb3J0IHtcbiAgQ2lyY3VsYXJEZXBlbmRlbmN5RXhjZXB0aW9uLFxuICBJbnZhbGlkTW9kdWxlRXhjZXB0aW9uLFxuICBVbmRlZmluZWRNb2R1bGVFeGNlcHRpb25cbn0gZnJvbSAnLi4vZXJyb3JzJ1xuaW1wb3J0IHtcbiAgRU5IQU5DRVJfS0VZX1RPX1NVQlRZUEVfTUFQLFxuICBFbmhhbmNlclN1YnR5cGUsXG4gIGdldENsYXNzU2NvcGVcbn0gZnJvbSAnLi4vaGVscGVycydcbmltcG9ydCB7XG4gIEluc3RhbmNlV3JhcHBlcixcbiAgSW50ZXJuYWxDb3JlTW9kdWxlRmFjdG9yeSxcbiAgTW9kdWxlLFxuICBDb250YWluZXJJb0Ncbn0gZnJvbSAnLi4vY29yZSdcbmltcG9ydCB7IE1ldGFkYXRhU2Nhbm5lciB9IGZyb20gJy4vbWV0YWRhdGEtc2Nhbm5lcidcbmltcG9ydCB7XG4gIEFwcGxpY2F0aW9uUHJvdmlkZXJXcmFwcGVySW50ZXJmYWNlLFxuICBBY2Nlc3NSZXNvdXJjZUludGVyZmFjZSxcbiAgQ2xhc3NQcm92aWRlcixcbiAgRHluYW1pY01vZHVsZUludGVyZmFjZSxcbiAgRXhjZXB0aW9uRmlsdGVySW50ZXJmYWNlLFxuICBFeGlzdGluZ1Byb3ZpZGVyLFxuICBGYWN0b3J5UHJvdmlkZXIsXG4gIEZvcndhcmRSZWZlcmVuY2VJbnRlcmZhY2UsXG4gIEludGVyY2VwdG9ySW50ZXJmYWNlLFxuICBIYW5kbGVyVHJhbnNmb3JtLFxuICBTY29wZSxcbiAgVHlwZSxcbiAgVmFsdWVQcm92aWRlclxufSBmcm9tICcuLi9jb250cmFjdHMnXG5pbXBvcnQge1xuICBFWENFUFRJT05fRklMVEVSU19NRVRBREFUQSxcbiAgUkVTT1VSQ0VTX01FVEFEQVRBLFxuICBJTlRFUkNFUFRPUlNfTUVUQURBVEEsXG4gIE1PRFVMRV9NRVRBREFUQSxcbiAgSEFORExFUl9NRVRBREFUQSxcbiAgUk9VVEVfQVJHU19NRVRBREFUQVxufSBmcm9tICcuLi9oZWxwZXJzJ1xuaW1wb3J0IHsgaXNGdW5jdGlvbiwgaXNOaWwsIGlzVW5kZWZpbmVkLCByYW5kb21TdHJpbmdHZW5lcmF0b3IgfSBmcm9tICcuLi91dGlscydcbmltcG9ydCB7IENvbnRyb2xsZXJUeXBlLCBJbmplY3RhYmxlVHlwZSwgUHJvdmlkZXJUeXBlIH0gZnJvbSAnLi4vdHlwZXMnXG5pbXBvcnQgeyBHcmFwaEluc3BlY3RvciB9IGZyb20gJy4uL2luc3BlY3RvcidcbmltcG9ydCB7IENhbkFjdGl2YXRlIH0gZnJvbSAnLi4vY29udHJhY3RzL2Nhbi1hY3RpdmF0ZSdcblxuZXhwb3J0IGNsYXNzIERlcGVuZGVuY2llc1NjYW5uZXIge1xuICBwcml2YXRlIHJlYWRvbmx5IGFwcGxpY2F0aW9uUHJvdmlkZXJzQXBwbHlNYXA6IEFwcGxpY2F0aW9uUHJvdmlkZXJXcmFwcGVySW50ZXJmYWNlW10gPVxuICAgIFtdXG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSByZWFkb25seSBjb250YWluZXI6IENvbnRhaW5lcklvQyxcbiAgICBwcml2YXRlIHJlYWRvbmx5IG1ldGFkYXRhU2Nhbm5lcjogTWV0YWRhdGFTY2FubmVyLFxuICAgIHByaXZhdGUgcmVhZG9ubHkgZ3JhcGhJbnNwZWN0b3I6IEdyYXBoSW5zcGVjdG9yLFxuICAgIHByaXZhdGUgcmVhZG9ubHkgYXBwbGljYXRpb25Db25maWcgPSBuZXcgQXBwbGljYXRpb25Db25maWcoKVxuICApIHsgfVxuXG4gIHB1YmxpYyBhc3luYyBzY2FuKG1vZHVsZTogVHlwZTxhbnk+KSB7XG4gICAgYXdhaXQgdGhpcy5yZWdpc3RlckNvcmVNb2R1bGUoKVxuICAgIGF3YWl0IHRoaXMuc2NhbkZvck1vZHVsZXMobW9kdWxlKVxuICAgIGF3YWl0IHRoaXMuc2Nhbk1vZHVsZXNGb3JEZXBlbmRlbmNpZXMoKVxuICAgIGF3YWl0IHRoaXMuY2FsY3VsYXRlTW9kdWxlc0Rpc3RhbmNlKClcblxuICAgIHRoaXMuYWRkU2NvcGVkRW5oYW5jZXJzTWV0YWRhdGEoKVxuICAgIHRoaXMuY29udGFpbmVyLmJpbmRHbG9iYWxTY29wZSgpXG4gIH1cblxuICBwdWJsaWMgYXN5bmMgc2NhbkZvck1vZHVsZXMoXG4gICAgbW9kdWxlRGVmaW5pdGlvbjpcbiAgICAgIHwgRm9yd2FyZFJlZmVyZW5jZUludGVyZmFjZVxuICAgICAgfCBUeXBlPHVua25vd24+XG4gICAgICB8IER5bmFtaWNNb2R1bGVJbnRlcmZhY2VcbiAgICAgIHwgUHJvbWlzZTxEeW5hbWljTW9kdWxlSW50ZXJmYWNlPixcbiAgICBzY29wZTogVHlwZTx1bmtub3duPltdID0gW10sXG4gICAgY3R4UmVnaXN0cnk6IChcbiAgICAgIHwgRm9yd2FyZFJlZmVyZW5jZUludGVyZmFjZVxuICAgICAgfCBEeW5hbWljTW9kdWxlSW50ZXJmYWNlXG4gICAgICB8IFR5cGU8dW5rbm93bj5cbiAgICApW10gPSBbXVxuICApOiBQcm9taXNlPE1vZHVsZVtdPiB7XG4gICAgY29uc3QgbW9kdWxlSW5zdGFuY2UgPSBhd2FpdCB0aGlzLmluc2VydE1vZHVsZShtb2R1bGVEZWZpbml0aW9uLCBzY29wZSlcbiAgICBtb2R1bGVEZWZpbml0aW9uID1cbiAgICAgIG1vZHVsZURlZmluaXRpb24gaW5zdGFuY2VvZiBQcm9taXNlXG4gICAgICAgID8gYXdhaXQgbW9kdWxlRGVmaW5pdGlvblxuICAgICAgICA6IG1vZHVsZURlZmluaXRpb25cblxuICAgIGN0eFJlZ2lzdHJ5LnB1c2gobW9kdWxlRGVmaW5pdGlvbilcblxuICAgIGlmICh0aGlzLmlzRm9yd2FyZFJlZmVyZW5jZShtb2R1bGVEZWZpbml0aW9uKSlcbiAgICAgIG1vZHVsZURlZmluaXRpb24gPSAoXG4gICAgICAgIG1vZHVsZURlZmluaXRpb24gYXMgRm9yd2FyZFJlZmVyZW5jZUludGVyZmFjZVxuICAgICAgKS5mb3J3YXJkUmVmKClcblxuICAgIGNvbnN0IG1vZHVsZXMgPSAhdGhpcy5pc0R5bmFtaWNNb2R1bGUoXG4gICAgICBtb2R1bGVEZWZpbml0aW9uIGFzIFR5cGU8YW55PiB8IER5bmFtaWNNb2R1bGVJbnRlcmZhY2VcbiAgICApXG4gICAgICA/IHRoaXMucmVmbGVjdE1ldGFkYXRhKFxuICAgICAgICBtb2R1bGVEZWZpbml0aW9uIGFzIFR5cGU8YW55PixcbiAgICAgICAgTU9EVUxFX01FVEFEQVRBLklNUE9SVFNcbiAgICAgIClcbiAgICAgIDogW1xuICAgICAgICAuLi50aGlzLnJlZmxlY3RNZXRhZGF0YShcbiAgICAgICAgICAobW9kdWxlRGVmaW5pdGlvbiBhcyBEeW5hbWljTW9kdWxlSW50ZXJmYWNlKS5tb2R1bGUsXG4gICAgICAgICAgTU9EVUxFX01FVEFEQVRBLklNUE9SVFNcbiAgICAgICAgKSxcbiAgICAgICAgLi4uKChtb2R1bGVEZWZpbml0aW9uIGFzIER5bmFtaWNNb2R1bGVJbnRlcmZhY2UpLmltcG9ydHMgfHwgW10pXG4gICAgICBdXG5cbiAgICBsZXQgcmVnaXN0ZXJlZE1vZHVsZVJlZnMgPSBbXVxuICAgIGZvciAoY29uc3QgW2luZGV4LCBpbm5lck1vZHVsZV0gb2YgbW9kdWxlcy5lbnRyaWVzKCkpIHtcbiAgICAgIGlmIChpbm5lck1vZHVsZSA9PT0gdW5kZWZpbmVkKVxuICAgICAgICB0aHJvdyBuZXcgVW5kZWZpbmVkTW9kdWxlRXhjZXB0aW9uKG1vZHVsZURlZmluaXRpb24sIGluZGV4LCBzY29wZSlcblxuICAgICAgaWYgKCFpbm5lck1vZHVsZSlcbiAgICAgICAgdGhyb3cgbmV3IEludmFsaWRNb2R1bGVFeGNlcHRpb24obW9kdWxlRGVmaW5pdGlvbiwgaW5kZXgsIHNjb3BlKVxuXG4gICAgICBpZiAoY3R4UmVnaXN0cnkuaW5jbHVkZXMoaW5uZXJNb2R1bGUpKSB7XG4gICAgICAgIGNvbnRpbnVlXG4gICAgICB9XG4gICAgICBjb25zdCBtb2R1bGVSZWZzID0gYXdhaXQgdGhpcy5zY2FuRm9yTW9kdWxlcyhcbiAgICAgICAgaW5uZXJNb2R1bGUsXG4gICAgICAgIFtdLmNvbmNhdChzY29wZSwgbW9kdWxlRGVmaW5pdGlvbiksXG4gICAgICAgIGN0eFJlZ2lzdHJ5XG4gICAgICApXG4gICAgICByZWdpc3RlcmVkTW9kdWxlUmVmcyA9IHJlZ2lzdGVyZWRNb2R1bGVSZWZzLmNvbmNhdChtb2R1bGVSZWZzKVxuICAgIH1cbiAgICBpZiAoIW1vZHVsZUluc3RhbmNlKSB7XG4gICAgICByZXR1cm4gcmVnaXN0ZXJlZE1vZHVsZVJlZnNcbiAgICB9XG4gICAgcmV0dXJuIFttb2R1bGVJbnN0YW5jZV0uY29uY2F0KHJlZ2lzdGVyZWRNb2R1bGVSZWZzKVxuICB9XG5cbiAgcHVibGljIGFzeW5jIGluc2VydE1vZHVsZShcbiAgICBtb2R1bGU6IGFueSxcbiAgICBzY29wZTogVHlwZTx1bmtub3duPltdXG4gICk6IFByb21pc2U8TW9kdWxlIHwgdW5kZWZpbmVkPiB7XG4gICAgaWYgKG1vZHVsZSAmJiBtb2R1bGUuZm9yd2FyZFJlZilcbiAgICAgIHJldHVybiB0aGlzLmNvbnRhaW5lci5hZGRNb2R1bGUobW9kdWxlLmZvcndhcmRSZWYoKSwgc2NvcGUpXG4gICAgcmV0dXJuIHRoaXMuY29udGFpbmVyLmFkZE1vZHVsZShtb2R1bGUsIHNjb3BlKVxuICB9XG5cbiAgcHVibGljIGFzeW5jIHNjYW5Nb2R1bGVzRm9yRGVwZW5kZW5jaWVzKFxuICAgIG1vZHVsZXM6IE1hcDxzdHJpbmcsIE1vZHVsZT4gPSB0aGlzLmNvbnRhaW5lci5nZXRNb2R1bGVzKClcbiAgKSB7XG4gICAgZm9yIChjb25zdCBbdG9rZW4sIHsgbWV0YVR5cGUgfV0gb2YgbW9kdWxlcykge1xuICAgICAgYXdhaXQgdGhpcy5yZWZsZWN0SW1wb3J0cyhtZXRhVHlwZSwgdG9rZW4sIG1ldGFUeXBlLm5hbWUpXG4gICAgICB0aGlzLnJlZmxlY3RQcm92aWRlcnMobWV0YVR5cGUsIHRva2VuKVxuICAgICAgdGhpcy5yZWZsZWN0Q29udHJvbGxlcnMobWV0YVR5cGUsIHRva2VuKVxuICAgICAgdGhpcy5yZWZsZWN0RXhwb3J0cyhtZXRhVHlwZSwgdG9rZW4pXG4gICAgfVxuICB9XG5cbiAgcHVibGljIGFzeW5jIHJlZmxlY3RJbXBvcnRzKFxuICAgIG1vZHVsZTogVHlwZTx1bmtub3duPixcbiAgICB0b2tlbjogc3RyaW5nLFxuICAgIGNvbnRleHQ6IHN0cmluZ1xuICApIHtcbiAgICBjb25zdCBtb2R1bGVzID0gW1xuICAgICAgLi4udGhpcy5yZWZsZWN0TWV0YWRhdGEobW9kdWxlLCBNT0RVTEVfTUVUQURBVEEuSU1QT1JUUyksXG4gICAgICAuLi50aGlzLmNvbnRhaW5lci5nZXREeW5hbWljTWV0YWRhdGFCeVRva2VuKFxuICAgICAgICB0b2tlbixcbiAgICAgICAgTU9EVUxFX01FVEFEQVRBLklNUE9SVFMgYXMgJ2ltcG9ydHMnXG4gICAgICApXG4gICAgXVxuICAgIGZvciAoY29uc3QgcmVsYXRlZCBvZiBtb2R1bGVzKSB7XG4gICAgICBhd2FpdCB0aGlzLmluc2VydEltcG9ydChyZWxhdGVkLCB0b2tlbiwgY29udGV4dClcbiAgICB9XG4gIH1cblxuICBwdWJsaWMgcmVmbGVjdFByb3ZpZGVycyhtb2R1bGU6IFR5cGU8YW55PiwgdG9rZW46IHN0cmluZykge1xuICAgIGNvbnN0IHByb3ZpZGVycyA9IFtcbiAgICAgIC4uLnRoaXMucmVmbGVjdE1ldGFkYXRhKG1vZHVsZSwgTU9EVUxFX01FVEFEQVRBLlBST1ZJREVSUyksXG4gICAgICAuLi50aGlzLmNvbnRhaW5lci5nZXREeW5hbWljTWV0YWRhdGFCeVRva2VuKFxuICAgICAgICB0b2tlbixcbiAgICAgICAgTU9EVUxFX01FVEFEQVRBLlBST1ZJREVSUyBhcyAncHJvdmlkZXJzJ1xuICAgICAgKVxuICAgIF1cbiAgICBwcm92aWRlcnMuZm9yRWFjaChwcm92aWRlciA9PiB7XG4gICAgICB0aGlzLmluc2VydFByb3ZpZGVyKHByb3ZpZGVyLCB0b2tlbilcbiAgICAgIHRoaXMucmVmbGVjdER5bmFtaWNNZXRhZGF0YShwcm92aWRlciwgdG9rZW4pXG4gICAgfSlcbiAgfVxuXG4gIHB1YmxpYyByZWZsZWN0Q29udHJvbGxlcnMobW9kdWxlOiBUeXBlPGFueT4sIHRva2VuOiBzdHJpbmcpIHtcbiAgICBjb25zdCBjb250cm9sbGVycyA9IFtcbiAgICAgIC4uLnRoaXMucmVmbGVjdE1ldGFkYXRhKG1vZHVsZSwgTU9EVUxFX01FVEFEQVRBLkNPTlRST0xMRVJTKSxcbiAgICAgIC4uLnRoaXMuY29udGFpbmVyLmdldER5bmFtaWNNZXRhZGF0YUJ5VG9rZW4oXG4gICAgICAgIHRva2VuLFxuICAgICAgICBNT0RVTEVfTUVUQURBVEEuQ09OVFJPTExFUlMgYXMgJ2NvbnRyb2xsZXJzJ1xuICAgICAgKVxuICAgIF1cbiAgICBjb250cm9sbGVycy5mb3JFYWNoKGl0ZW0gPT4ge1xuICAgICAgdGhpcy5pbnNlcnRDb250cm9sbGVyKGl0ZW0sIHRva2VuKVxuICAgICAgdGhpcy5yZWZsZWN0RHluYW1pY01ldGFkYXRhKGl0ZW0sIHRva2VuKVxuICAgIH0pXG4gIH1cblxuICBwdWJsaWMgcmVmbGVjdER5bmFtaWNNZXRhZGF0YShvYmo6IFR5cGU8SW5qZWN0YWJsZVR5cGU+LCB0b2tlbjogc3RyaW5nKSB7XG4gICAgaWYgKCFvYmogfHwgIW9iai5wcm90b3R5cGUpIHtcbiAgICAgIHJldHVyblxuICAgIH1cbiAgICB0aGlzLnJlZmxlY3RJbmplY3RhYmxlcyhvYmosIHRva2VuLCBSRVNPVVJDRVNfTUVUQURBVEEpXG4gICAgdGhpcy5yZWZsZWN0SW5qZWN0YWJsZXMob2JqLCB0b2tlbiwgSU5URVJDRVBUT1JTX01FVEFEQVRBKVxuICAgIHRoaXMucmVmbGVjdEluamVjdGFibGVzKG9iaiwgdG9rZW4sIEVYQ0VQVElPTl9GSUxURVJTX01FVEFEQVRBKVxuICAgIHRoaXMucmVmbGVjdEluamVjdGFibGVzKG9iaiwgdG9rZW4sIEhBTkRMRVJfTUVUQURBVEEpXG4gICAgdGhpcy5yZWZsZWN0UGFyYW1JbmplY3RhYmxlcyhvYmosIHRva2VuLCBST1VURV9BUkdTX01FVEFEQVRBKVxuICB9XG5cbiAgcHVibGljIHJlZmxlY3RFeHBvcnRzKG1vZHVsZTogVHlwZTx1bmtub3duPiwgdG9rZW46IHN0cmluZykge1xuICAgIGNvbnN0IGV4cG9ydHMgPSBbXG4gICAgICAuLi50aGlzLnJlZmxlY3RNZXRhZGF0YShtb2R1bGUsIE1PRFVMRV9NRVRBREFUQS5FWFBPUlRTKSxcbiAgICAgIC4uLnRoaXMuY29udGFpbmVyLmdldER5bmFtaWNNZXRhZGF0YUJ5VG9rZW4oXG4gICAgICAgIHRva2VuLFxuICAgICAgICBNT0RVTEVfTUVUQURBVEEuRVhQT1JUUyBhcyAnZXhwb3J0cydcbiAgICAgIClcbiAgICBdXG4gICAgZXhwb3J0cy5mb3JFYWNoKGV4cG9ydGVkUHJvdmlkZXIgPT5cbiAgICAgIHRoaXMuaW5zZXJ0RXhwb3J0ZWRQcm92aWRlcihleHBvcnRlZFByb3ZpZGVyLCB0b2tlbilcbiAgICApXG4gIH1cblxuICBwdWJsaWMgcmVmbGVjdEluamVjdGFibGVzKFxuICAgIGNvbXBvbmVudDogVHlwZTxJbmplY3RhYmxlVHlwZT4sXG4gICAgdG9rZW46IHN0cmluZyxcbiAgICBtZXRhZGF0YUtleTogc3RyaW5nXG4gICkge1xuXG4gICAgY29uc3QgY29udHJvbGxlckluamVjdGFibGVzID0gdGhpcy5yZWZsZWN0TWV0YWRhdGEoY29tcG9uZW50LCBtZXRhZGF0YUtleSk7XG5cbiAgICBjb25zdCBtZXRob2RJbmplY3RhYmxlcyA9IHRoaXMubWV0YWRhdGFTY2FubmVyXG4gICAgICAuZ2V0QWxsTWV0aG9kTmFtZXMoY29tcG9uZW50LnByb3RvdHlwZSlcbiAgICAgIC5yZWR1Y2UoKGFjYywgbWV0aG9kKSA9PiB7XG4gICAgICAgIGNvbnN0IG1ldGhvZEluamVjdGFibGUgPVxuICAgICAgICAgIHRoaXMucmVmbGVjdEtleU1ldGFkYXRhKGNvbXBvbmVudCwgbWV0YWRhdGFLZXksIG1ldGhvZCkgfHwgeyBtZXRhZGF0YTogW10gfTtcblxuICAgICAgICBpZiAobWV0aG9kSW5qZWN0YWJsZSkge1xuICAgICAgICAgIGFjYy5wdXNoKG1ldGhvZEluamVjdGFibGUpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGFjYztcbiAgICAgIH0sIFtdKTtcblxuICAgIGNvbnRyb2xsZXJJbmplY3RhYmxlcy5mb3JFYWNoKGluamVjdGFibGUgPT5cbiAgICAgIHRoaXMuaW5zZXJ0SW5qZWN0YWJsZShcbiAgICAgICAgaW5qZWN0YWJsZSxcbiAgICAgICAgdG9rZW4sXG4gICAgICAgIGNvbXBvbmVudCxcbiAgICAgICAgRU5IQU5DRVJfS0VZX1RPX1NVQlRZUEVfTUFQW21ldGFkYXRhS2V5XVxuICAgICAgKVxuICAgICk7XG5cbiAgICBtZXRob2RJbmplY3RhYmxlcy5mb3JFYWNoKG1ldGhvZEluamVjdGFibGUgPT4ge1xuICAgICAgaWYgKG1ldGhvZEluamVjdGFibGUubWV0YWRhdGEpIHtcbiAgICAgICAgbWV0aG9kSW5qZWN0YWJsZS5tZXRhZGF0YS5mb3JFYWNoKGluamVjdGFibGUgPT5cbiAgICAgICAgICB0aGlzLmluc2VydEluamVjdGFibGUoXG4gICAgICAgICAgICBpbmplY3RhYmxlLFxuICAgICAgICAgICAgdG9rZW4sXG4gICAgICAgICAgICBjb21wb25lbnQsXG4gICAgICAgICAgICBFTkhBTkNFUl9LRVlfVE9fU1VCVFlQRV9NQVBbbWV0YWRhdGFLZXldLFxuICAgICAgICAgICAgbWV0aG9kSW5qZWN0YWJsZS5tZXRob2RLZXlcbiAgICAgICAgICApXG4gICAgICAgICk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb25zb2xlLndhcm4oXG4gICAgICAgICAgYE5vIG1ldGFkYXRhIGZvdW5kIGZvciBtZXRob2QgJHttZXRob2RJbmplY3RhYmxlLm1ldGhvZEtleX1gXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfSk7XG5cbiAgfVxuXG4gIHB1YmxpYyByZWZsZWN0UGFyYW1JbmplY3RhYmxlcyhcbiAgICBjb21wb25lbnQ6IFR5cGU8SW5qZWN0YWJsZVR5cGU+LFxuICAgIHRva2VuOiBzdHJpbmcsXG4gICAgbWV0YWRhdGFLZXk6IHN0cmluZ1xuICApIHtcbiAgICBjb25zdCBwYXJhbXNNZXRob2RzID0gdGhpcy5tZXRhZGF0YVNjYW5uZXIuZ2V0QWxsTWV0aG9kTmFtZXMoXG4gICAgICBjb21wb25lbnQucHJvdG90eXBlXG4gICAgKVxuXG4gICAgcGFyYW1zTWV0aG9kcy5mb3JFYWNoKG1ldGhvZEtleSA9PiB7XG4gICAgICBjb25zdCBtZXRhZGF0YTogUmVjb3JkPFxuICAgICAgICBzdHJpbmcsXG4gICAgICAgIHtcbiAgICAgICAgICBpbmRleDogbnVtYmVyXG4gICAgICAgICAgZGF0YTogdW5rbm93blxuICAgICAgICAgIHBpcGVzOiBBcnJheTxUeXBlPEhhbmRsZXJUcmFuc2Zvcm0+IHwgSGFuZGxlclRyYW5zZm9ybT5cbiAgICAgICAgfVxuICAgICAgPiA9IFJlZmxlY3QuZ2V0TWV0YWRhdGEobWV0YWRhdGFLZXksIGNvbXBvbmVudCwgbWV0aG9kS2V5KVxuXG4gICAgICBpZiAoIW1ldGFkYXRhKSB7XG4gICAgICAgIHJldHVyblxuICAgICAgfVxuXG4gICAgICBjb25zdCBwYXJhbXMgPSBPYmplY3QudmFsdWVzKG1ldGFkYXRhKVxuICAgICAgcGFyYW1zXG4gICAgICAgIC5tYXAoaXRlbSA9PiBpdGVtLnBpcGVzKVxuICAgICAgICAuZmxhdCgxKVxuICAgICAgICAuZm9yRWFjaChpbmplY3RhYmxlID0+XG4gICAgICAgICAgdGhpcy5pbnNlcnRJbmplY3RhYmxlKFxuICAgICAgICAgICAgaW5qZWN0YWJsZSxcbiAgICAgICAgICAgIHRva2VuLFxuICAgICAgICAgICAgY29tcG9uZW50LFxuICAgICAgICAgICAgJ3Jlc291cmNlJyxcbiAgICAgICAgICAgIG1ldGhvZEtleVxuICAgICAgICAgIClcbiAgICAgICAgKVxuICAgIH0pXG4gIH1cblxuICBwdWJsaWMgcmVmbGVjdEtleU1ldGFkYXRhKFxuICAgIGNvbXBvbmVudDogVHlwZTxJbmplY3RhYmxlVHlwZT4sXG4gICAga2V5OiBzdHJpbmcsXG4gICAgbWV0aG9kOiBzdHJpbmdcbiAgKSB7XG4gICAgbGV0IHByb3RvdHlwZSA9IGNvbXBvbmVudC5wcm90b3R5cGVcbiAgICBkbyB7XG4gICAgICBjb25zdCBkZXNjcmlwdG9yID0gUmVmbGVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3IocHJvdG90eXBlLCBtZXRob2QpXG4gICAgICBpZiAoIWRlc2NyaXB0b3IpIGNvbnRpbnVlXG5cbiAgICAgIHJldHVybiBSZWZsZWN0LmdldE1ldGFkYXRhKGtleSwgZGVzY3JpcHRvci52YWx1ZSlcbiAgICB9IHdoaWxlIChcbiAgICAgIChwcm90b3R5cGUgPSBSZWZsZWN0LmdldFByb3RvdHlwZU9mKHByb3RvdHlwZSkpICYmXG4gICAgICBwcm90b3R5cGUgIT09IE9iamVjdC5wcm90b3R5cGUgJiZcbiAgICAgIHByb3RvdHlwZVxuICAgIClcbiAgICByZXR1cm4gdW5kZWZpbmVkXG4gIH1cblxuICBwdWJsaWMgYXN5bmMgY2FsY3VsYXRlTW9kdWxlc0Rpc3RhbmNlKCkge1xuICAgIGNvbnN0IG1vZHVsZXNHZW5lcmF0b3IgPSB0aGlzLmNvbnRhaW5lci5nZXRNb2R1bGVzKCkudmFsdWVzKClcblxuICAgIG1vZHVsZXNHZW5lcmF0b3IubmV4dCgpXG5cbiAgICBjb25zdCBtb2R1bGVzU3RhY2sgPSBbXVxuICAgIGNvbnN0IGNhbGN1bGF0ZURpc3RhbmNlID0gKG1vZHVsZVJlZjogTW9kdWxlLCBkaXN0YW5jZSA9IDEpID0+IHtcbiAgICAgIGlmIChtb2R1bGVzU3RhY2suaW5jbHVkZXMobW9kdWxlUmVmKSkgcmV0dXJuXG5cbiAgICAgIG1vZHVsZXNTdGFjay5wdXNoKG1vZHVsZVJlZilcblxuICAgICAgY29uc3QgbW9kdWxlSW1wb3J0cyA9IG1vZHVsZVJlZi5pbXBvcnRzXG4gICAgICBtb2R1bGVJbXBvcnRzLmZvckVhY2goaW1wb3J0ZWRNb2R1bGVSZWYgPT4ge1xuICAgICAgICBpZiAoaW1wb3J0ZWRNb2R1bGVSZWYpIHtcbiAgICAgICAgICBpbXBvcnRlZE1vZHVsZVJlZi5kaXN0YW5jZSA9IGRpc3RhbmNlXG4gICAgICAgICAgY2FsY3VsYXRlRGlzdGFuY2UoaW1wb3J0ZWRNb2R1bGVSZWYsIGRpc3RhbmNlICsgMSlcbiAgICAgICAgfVxuICAgICAgfSlcbiAgICB9XG5cbiAgICBjb25zdCByb290TW9kdWxlID0gbW9kdWxlc0dlbmVyYXRvci5uZXh0KCkudmFsdWUgYXMgTW9kdWxlXG4gICAgY2FsY3VsYXRlRGlzdGFuY2Uocm9vdE1vZHVsZSlcbiAgfVxuXG4gIHB1YmxpYyBhc3luYyBpbnNlcnRJbXBvcnQocmVsYXRlZDogYW55LCB0b2tlbjogc3RyaW5nLCBjb250ZXh0OiBzdHJpbmcpIHtcbiAgICBpZiAoaXNVbmRlZmluZWQocmVsYXRlZCkpIHtcbiAgICAgIHRocm93IG5ldyBDaXJjdWxhckRlcGVuZGVuY3lFeGNlcHRpb24oY29udGV4dClcbiAgICB9XG4gICAgaWYgKHJlbGF0ZWQgJiYgcmVsYXRlZC5mb3J3YXJkUmVmKVxuICAgICAgcmV0dXJuIHRoaXMuY29udGFpbmVyLmFkZEltcG9ydChyZWxhdGVkLmZvcndhcmRSZWYoKSwgdG9rZW4pXG5cbiAgICBhd2FpdCB0aGlzLmNvbnRhaW5lci5hZGRJbXBvcnQocmVsYXRlZCwgdG9rZW4pXG4gIH1cblxuICBwdWJsaWMgaXNDdXN0b21Qcm92aWRlcihcbiAgICBwcm92aWRlcjogUHJvdmlkZXJUeXBlXG4gICk6IHByb3ZpZGVyIGlzXG4gICAgfCBDbGFzc1Byb3ZpZGVyXG4gICAgfCBWYWx1ZVByb3ZpZGVyXG4gICAgfCBGYWN0b3J5UHJvdmlkZXJcbiAgICB8IEV4aXN0aW5nUHJvdmlkZXIge1xuICAgIHJldHVybiBwcm92aWRlciAmJiAhaXNOaWwoKHByb3ZpZGVyIGFzIGFueSkucHJvdmlkZSlcbiAgfVxuXG4gIHB1YmxpYyBpbnNlcnRQcm92aWRlcihwcm92aWRlcjogUHJvdmlkZXJUeXBlLCB0b2tlbjogc3RyaW5nKSB7XG4gICAgY29uc3QgaXNDdXN0b21Qcm92aWRlciA9IHRoaXMuaXNDdXN0b21Qcm92aWRlcihwcm92aWRlcilcbiAgICBpZiAoIWlzQ3VzdG9tUHJvdmlkZXIpXG4gICAgICByZXR1cm4gdGhpcy5jb250YWluZXIuYWRkUHJvdmlkZXIocHJvdmlkZXIgYXMgVHlwZTxhbnk+LCB0b2tlbilcblxuICAgIGNvbnN0IGFwcGx5UHJvdmlkZXJzTWFwID0gdGhpcy5nZXRBcHBseVByb3ZpZGVyc01hcCgpXG4gICAgY29uc3QgcHJvdmlkZXJzS2V5cyA9IE9iamVjdC5rZXlzKGFwcGx5UHJvdmlkZXJzTWFwKVxuICAgIGNvbnN0IHR5cGUgPSAoXG4gICAgICBwcm92aWRlciBhc1xuICAgICAgfCBDbGFzc1Byb3ZpZGVyXG4gICAgICB8IFZhbHVlUHJvdmlkZXJcbiAgICAgIHwgRmFjdG9yeVByb3ZpZGVyXG4gICAgICB8IEV4aXN0aW5nUHJvdmlkZXJcbiAgICApLnByb3ZpZGVcblxuICAgIGlmICghcHJvdmlkZXJzS2V5cy5pbmNsdWRlcyh0eXBlIGFzIHN0cmluZykpXG4gICAgICByZXR1cm4gdGhpcy5jb250YWluZXIuYWRkUHJvdmlkZXIocHJvdmlkZXIgYXMgYW55LCB0b2tlbilcblxuICAgIGNvbnN0IHByb3ZpZGVyVG9rZW4gPSBgJHt0eXBlIGFzIHN0cmluZ30gKFVVSUQ6ICR7cmFuZG9tU3RyaW5nR2VuZXJhdG9yKCl9KWBcblxuICAgIGxldCBzY29wZSA9IChwcm92aWRlciBhcyBDbGFzc1Byb3ZpZGVyIHwgRmFjdG9yeVByb3ZpZGVyKS5zY29wZVxuICAgIGlmIChpc05pbChzY29wZSkgJiYgKHByb3ZpZGVyIGFzIENsYXNzUHJvdmlkZXIpLnVzZUNsYXNzKVxuICAgICAgc2NvcGUgPSBnZXRDbGFzc1Njb3BlKChwcm92aWRlciBhcyBDbGFzc1Byb3ZpZGVyKS51c2VDbGFzcylcblxuICAgIHRoaXMuYXBwbGljYXRpb25Qcm92aWRlcnNBcHBseU1hcC5wdXNoKHtcbiAgICAgIHR5cGUsXG4gICAgICBtb2R1bGVLZXk6IHRva2VuLFxuICAgICAgcHJvdmlkZXJLZXk6IHByb3ZpZGVyVG9rZW4sXG4gICAgICBzY29wZVxuICAgIH0pXG5cbiAgICBjb25zdCBuZXdQcm92aWRlciA9IHtcbiAgICAgIC4uLnByb3ZpZGVyLFxuICAgICAgcHJvdmlkZTogcHJvdmlkZXJUb2tlbixcbiAgICAgIHNjb3BlXG4gICAgfSBhcyBQcm92aWRlclR5cGVcblxuICAgIGNvbnN0IGVuaGFuY2VyU3VidHlwZSA9XG4gICAgICBFTkhBTkNFUl9UT0tFTl9UT19TVUJUWVBFX01BUFtcbiAgICAgIHR5cGUgYXNcbiAgICAgIHwgdHlwZW9mIEFQUF9SRVNPVVJDRVxuICAgICAgfCB0eXBlb2YgQVBQX0hBTkRMRVJcbiAgICAgIHwgdHlwZW9mIEFQUF9GSUxURVJcbiAgICAgIHwgdHlwZW9mIEFQUF9JTlRFUkNFUFRPUlxuICAgICAgXVxuXG4gICAgY29uc3QgZmFjdG9yeU9yQ2xhc3NQcm92aWRlciA9IG5ld1Byb3ZpZGVyIGFzXG4gICAgICB8IEZhY3RvcnlQcm92aWRlclxuICAgICAgfCBDbGFzc1Byb3ZpZGVyXG4gICAgaWYgKERlcGVuZGVuY2llc1NjYW5uZXIuaXNSZXF1ZXN0T3JUcmFuc2llbnQoZmFjdG9yeU9yQ2xhc3NQcm92aWRlci5zY29wZSkpXG4gICAgICByZXR1cm4gdGhpcy5jb250YWluZXIuYWRkSW5qZWN0YWJsZShuZXdQcm92aWRlciwgdG9rZW4sIGVuaGFuY2VyU3VidHlwZSlcblxuICAgIHRoaXMuY29udGFpbmVyLmFkZFByb3ZpZGVyKG5ld1Byb3ZpZGVyLCB0b2tlbiwgZW5oYW5jZXJTdWJ0eXBlKVxuICB9XG5cbiAgcHVibGljIGluc2VydEluamVjdGFibGUoXG4gICAgaW5qZWN0YWJsZTogVHlwZTxJbmplY3RhYmxlVHlwZT4gfCBPYmplY3QsXG4gICAgdG9rZW46IHN0cmluZyxcbiAgICBob3N0OiBUeXBlPEluamVjdGFibGVUeXBlPixcbiAgICBzdWJ0eXBlOiBFbmhhbmNlclN1YnR5cGUsXG4gICAgbWV0aG9kS2V5Pzogc3RyaW5nXG4gICkge1xuICAgIGlmIChpc0Z1bmN0aW9uKGluamVjdGFibGUpKSB7XG4gICAgICBjb25zdCBpbnN0YW5jZVdyYXBwZXIgPSB0aGlzLmNvbnRhaW5lci5hZGRJbmplY3RhYmxlKFxuICAgICAgICBpbmplY3RhYmxlIGFzIFR5cGUsXG4gICAgICAgIHRva2VuLFxuICAgICAgICBzdWJ0eXBlLFxuICAgICAgICBob3N0XG4gICAgICApIGFzIHVua25vd24gYXMgSW5zdGFuY2VXcmFwcGVyXG5cbiAgICAgIHRoaXMuZ3JhcGhJbnNwZWN0b3IuaW5zZXJ0RW5oYW5jZXJNZXRhZGF0YUNhY2hlKHtcbiAgICAgICAgbW9kdWxlVG9rZW46IHRva2VuLFxuICAgICAgICBjbGFzc1JlZjogaG9zdCxcbiAgICAgICAgZW5oYW5jZXJJbnN0YW5jZVdyYXBwZXI6IGluc3Rh