@c8y/ngx-components
Version:
Angular modules for Cumulocity IoT applications
402 lines • 62.4 kB
JavaScript
import { Injectable } from '@angular/core';
import { ApplicationAvailability } from '@c8y/client';
import { ApplicationService } from '@c8y/client';
import { cloneDeep, get, uniqBy } from 'lodash-es';
import { coerce, compare } from 'semver';
import { AppStateService } from '../common/ui-state.service';
import { groupBy } from 'lodash-es';
import { PackageType } from './plugins.model';
import { PluginsExportScopes } from '../common/ApplicationOptions';
import { PluginsResolveService } from './plugins-resolve.service';
import * as i0 from "@angular/core";
import * as i1 from "@c8y/client";
import * as i2 from "../common/ui-state.service";
export class PluginsService {
static convertInstalledRemotesToIds(remotes) {
if (!remotes) {
return;
}
const importContextPaths = Object.keys(remotes);
const plugins = [];
importContextPaths.forEach(contextPath => {
const moduleNames = remotes[contextPath] || [];
plugins.push(...moduleNames.map(module => PluginsService.createPluginId(contextPath, module, '', true)));
});
return plugins;
}
static createPluginId(contextPath, plugin, version, useLatest = false) {
const moduleName = typeof plugin === 'string' ? plugin : plugin.module;
if (useLatest) {
return `${contextPath}/${moduleName}`;
}
return `${contextPath}@${version}/${moduleName}`;
}
constructor(applicationService, appStateService) {
this.applicationService = applicationService;
this.appStateService = appStateService;
}
/**
* Fetches a list of available packages.
* @param params Additional query parameters.
* @returns Returns a list of packages.
*/
async listPackages(params = {}) {
const apps = await this.listApplicationsByCurrentTenant(params);
const webApps = apps.filter(app => this.isPackage(app));
const uniqueWebApps = this.removeDuplicates(webApps, 'contextPath');
return uniqueWebApps.sort((a, b) => a.name.localeCompare(b.name));
}
/**
* Checks if an application is a package.
* @param application Application managed object.
* @returns Returns true if the application is a package.
*/
isPackage(application) {
return application.manifest?.isPackage === true;
}
/**
* Updates the remotes field in the application configuration by adding new plugins.
* Important: if the remotes object is not set on the configuration object,
* remotes will not be added. Make sure that this object exists in the application configuration.
* @param application Application managed object.
* @param plugins List of remotes to be added.
* @returns Returns updated application remotes.
*/
async addRemotes(application, plugins) {
const pluginsArray = Array.isArray(plugins) ? plugins : [plugins];
const manifestRemotes = application.manifest?.remotes || {};
const appConfig = application?.config;
const appConfigRemotes = appConfig?.remotes || manifestRemotes;
const appConfigExcludedRemotes = appConfig?.excludedRemotes || {};
// only normal and self optional scoped plugins should be added to remotes
// self scoped plugins will be automatically added
const allPluginsExceptSelfScoped = this.getAllPluginsExceptSelfScoped(pluginsArray, application.contextPath);
const newRemotes = this.addPluginToRemotesConfig(appConfigRemotes, allPluginsExceptSelfScoped);
// should be unproblematic to remove all categories of plugins from excluded remotes
const newExcludedRemotes = this.removePluginsFromRemotesConfig(appConfigExcludedRemotes, plugins);
return await this.updateRemotesInAppConfig(application, newRemotes, newExcludedRemotes);
}
/**
* Updates the remotes field in the application configuration by removing plugins.
* @param application Application managed object.
* @param plugins List of remotes to be removed.
* @returns Returns updated application remotes.
*/
async removeRemotes(application, plugins) {
const pluginsArray = Array.isArray(plugins) ? plugins : [plugins];
const manifestRemotes = application.manifest?.remotes || {};
const appConfig = application?.config;
const appConfigRemotes = appConfig?.remotes || manifestRemotes;
const appConfigExcludedRemotes = appConfig?.excludedRemotes || {};
// app plugins need to be removed from remotes
const newRemotes = this.removePluginsFromRemotesConfig(appConfigRemotes, plugins);
// self scoped plugins need to be added to excluded remotes
// as they would be otherwise automatically added to remotes
const selfScopedPlugins = this.getSelfScopedPlugins(pluginsArray, application.contextPath);
const newExcludedRemotes = this.addPluginToRemotesConfig(appConfigExcludedRemotes, selfScopedPlugins);
return await this.updateRemotesInAppConfig(application, newRemotes, newExcludedRemotes);
}
/**
* Updates the remotes field in the application configuration.
* @param application Application managed object.
* @param plugins List of remotes to be added.
* @returns Returns updated application remotes.
*/
async updateRemotesInAppConfig(application, plugins, excludedRemotes) {
const updatedAppWithConfig = await this.applicationService.updateApplicationConfig(application, {
remotes: plugins,
excludedRemotes: excludedRemotes || {}
});
return updatedAppWithConfig?.config || { remotes: {} };
}
/**
* Fetches the application manifest.
* @param application Application managed object.
* @returns Returns the application manifest.
*/
async getCumulocityJsonFile(application) {
const c8yJson = await this.applicationService.getAppManifest(application);
if (!c8yJson.remotes) {
c8yJson.remotes = {};
}
return c8yJson;
}
/**
* Sets the initial state of remotes in the configuration (when it's missing), based on the list of remotes being in the application manifest.
* @param application Application managed object.
* @returns Returns a list of remotes that has been assigned to the configuration object.
*/
async setInitialRemotes(application) {
try {
const manifest = await this.getCumulocityJsonFile(application);
const manifestRemotes = manifest.remotes;
return await this.updateRemotesInAppConfig(application, manifestRemotes || {}, {});
}
catch (er) {
return undefined;
}
}
async resetRemotes(application) {
return await this.applicationService.updateApplicationConfig(application, {
remotes: undefined,
excludedRemotes: undefined
});
}
sortVersions(source, order) {
const sourceCopy = cloneDeep(source);
if (source.list && source.path) {
const path = sourceCopy.path.join('.');
return sourceCopy.list.sort((a, b) => compare(coerce(get(a, path)), coerce(get(b, path))) * (order === 'asc' ? 1 : -1));
}
else {
return sourceCopy.sort((a, b) => compare(coerce(a), coerce(b)) * (order === 'asc' ? 1 : -1));
}
}
/**
* Extracts a list of exported plugins from the application object.
* @param application Application managed object.
* @param useLatest Set this to true, to not bind the plugin to any version.
* @returns Returns a list of exported plugins.
*/
getMFExports(application, excludedScopes = [
PluginsExportScopes.SELF,
PluginsExportScopes.SELF_OPTIONAL,
PluginsExportScopes.GLOBAL
], useLatest = false) {
const manifest = application.manifest;
if (!manifest || !manifest.exports) {
return [];
}
return this.extendPluginsDetails(application, {
version: manifest.version,
binaryId: undefined
}, useLatest).filter(plugin => !excludedScopes.includes(plugin.scope));
}
/**
* Extracts a list of exports from each available package.
* @param allVersions If set to true, all and not only latest versions are included.
* @param excludedScopes Defines which scopes should not be loaded.
* @returns Returns a list of all exported plugins.
*/
async getAllMFExports(allVersions = false, excludedScopes = [
PluginsExportScopes.SELF,
PluginsExportScopes.SELF_OPTIONAL,
PluginsExportScopes.GLOBAL
]) {
const plugins = new Array();
const packages = await this.listPackages();
for (const pkg of packages) {
if (!pkg?.manifest?.exports) {
continue;
}
if (allVersions && Array.isArray(pkg.applicationVersions)) {
pkg.applicationVersions.forEach(version => {
plugins.push(...this.extendPluginsDetails(pkg, version));
});
}
else {
plugins.push(...this.extendPluginsDetails(pkg, {
version: pkg.manifest.version,
binaryId: undefined
}));
}
}
return plugins.filter(plugin => !excludedScopes.includes(plugin.scope));
}
/**
* Extracts a list of remotes from the application object.
* @param application Application managed object.
* @returns Returns list of remotes.
*/
getMFRemotes(application) {
const manifest = application.manifest || {};
const config = application?.config;
let remotes = config?.remotes || manifest.remotes || {};
const manifestExports = manifest.exports || manifest.manifest?.exports || [];
const selfRemotes = manifestExports
.filter(plugin => plugin.scope === PluginsExportScopes.SELF)
.map(plugin => plugin.module || plugin.name);
if (selfRemotes.length) {
remotes = PluginsResolveService.mergeRemotes([
{ [application.contextPath]: selfRemotes },
remotes
]);
}
remotes = PluginsResolveService.removeRemotes(remotes, config?.excludedRemotes);
return remotes;
}
/**
* Determines the type of a package.
* A package is OFFICIAL if it comes from management tenant and has a label attached called OFFICIAL.
* A package is COMMUNITY if it has a label called COMMUNITY.
* A package is CUSTOM if it does not have any label attached.
* A package is UNKNOWN if it has a label attached but it does not match COMMUNITY or OFFICIAL.
*
* Labels can be used to identify the status of a package. Community packages always need
* a license validation. The label will be shown on the application card to tell a user
* whether they are looking into an official or community package.
*
* @param packageApplication The package application object to check.
* @returns The package type.
*/
getPackageType(packageApplication) {
const label = packageApplication.label || packageApplication.manifest?.label;
if (label === PackageType.ARCHIVED) {
return PackageType.ARCHIVED;
}
if (!label) {
return PackageType.CUSTOM;
}
if (label === PackageType.OFFICIAL && this.isOwnedByManagement(packageApplication)) {
return PackageType.OFFICIAL;
}
if (label === PackageType.COMMUNITY) {
return PackageType.COMMUNITY;
}
return PackageType.UNKNOWN;
}
/**
* Verifies if an application is owned by management tenant.
*
* @param app The application to verify.
* @returns True if owned by management tenant.
*/
isOwnedByManagement(app) {
const appOwner = get(app, 'owner.tenant.id');
return appOwner === 'management';
}
pluginsFromManifest(manifest) {
const plugins = manifest.exports;
const extendedPlugins = plugins
.filter(p => p.scope === PluginsExportScopes.SELF)
.map(p => ({
...p,
id: PluginsService.createPluginId(manifest.contextPath, p, manifest.version),
contextPath: manifest.contextPath,
version: manifest.version,
versioningMatrix: manifest.versioningMatrix,
license: manifest.license,
type: PackageType.CUSTOM
}));
return extendedPlugins;
}
isSelfScopedPlugin(plugin, contextPath) {
return (plugin.scope === PluginsExportScopes.SELF &&
(!contextPath || plugin.contextPath === contextPath));
}
getSelfScopedPlugins(plugins, contextPath) {
return plugins.filter(plugin => this.isSelfScopedPlugin(plugin, contextPath));
}
getAllPluginsExceptSelfScoped(plugins, contextPath) {
return plugins.filter(plugin => !this.isSelfScopedPlugin(plugin, contextPath));
}
removeDuplicates(apps, key) {
const uniqueList = [];
const groupedAppsByKey = groupBy(apps, key);
const groupedApps = Object.keys(groupedAppsByKey).map(key => groupedAppsByKey[key]);
for (const appsGroup of groupedApps) {
if (appsGroup.length < 2) {
uniqueList.push(...appsGroup);
}
else {
const appFromCurrentTenant = appsGroup.find(app => this.isFromCurrentTenant(app));
if (appFromCurrentTenant) {
uniqueList.push(appFromCurrentTenant);
continue;
}
const appNotOwnedByManagement = appsGroup.find(app => !this.isOwnedByManagement(app));
uniqueList.push(appNotOwnedByManagement);
}
}
return uniqueList;
}
isFromCurrentTenant(app) {
return app.owner.tenant.id === this.appStateService.currentTenant.value.name;
}
/**
* Modifies the list of plugins to have additional information such as id.
* @ignore
*/
extendPluginsDetails(application, version, useLatest = false) {
const plugins = application.manifest.exports;
const extendedPlugins = plugins.map(p => ({
...p,
id: PluginsService.createPluginId(application.contextPath, p, version.version, useLatest),
idLatest: PluginsService.createPluginId(application.contextPath, p, version.version, true),
contextPath: application.contextPath,
version: version.version,
versioningMatrix: application.manifest.versioningMatrix,
tags: useLatest ? ['latest'] : version.tags || [],
license: application.manifest.license,
type: this.getPackageType(application),
originApp: application
}));
return extendedPlugins;
}
async listApplicationsByCurrentTenant(params = {}) {
const filter = Object.assign({
type: 'HOSTED',
pageSize: 2000,
withTotalPages: true
}, params);
const sharedFilter = Object.assign({
availability: ApplicationAvailability.SHARED,
type: 'HOSTED',
pageSize: 2000,
withTotalPages: true
}, params);
const tenantName = this.appStateService.currentTenant.value.name;
const [resultAppsOwnedByTenant, resultSharedApps] = await Promise.all([
this.applicationService.listByTenant(tenantName, filter),
this.applicationService.list(sharedFilter)
]);
const { data: appsOwnedByTenant } = resultAppsOwnedByTenant;
const { data: sharedApps } = resultSharedApps;
const webApps = [...appsOwnedByTenant, ...sharedApps];
return uniqBy(webApps, (app) => app.id);
}
addPluginToRemotesConfig(remotesConfig, plugins) {
if (!plugins) {
return;
}
const remotesCopy = cloneDeep(remotesConfig);
const temp = Array.isArray(plugins) ? plugins : [plugins];
temp.forEach(plugin => {
const { contextPath, moduleName } = this.parsePluginId(plugin.id);
if (!contextPath || !moduleName) {
return;
}
remotesCopy[contextPath]?.length >= 0
? remotesCopy[contextPath].push(moduleName)
: (remotesCopy[contextPath] = []).push(moduleName);
remotesCopy[contextPath] = [...new Set(remotesCopy[contextPath])];
});
return remotesCopy;
}
removePluginsFromRemotesConfig(remotesConfig, plugins) {
const remotesCopy = cloneDeep(remotesConfig);
const temp = Array.isArray(plugins) ? plugins : [plugins];
temp.forEach(plugin => {
const { contextPath, moduleName } = this.parsePluginId(plugin.id);
if (!contextPath || !moduleName || !remotesCopy[contextPath]) {
return;
}
remotesCopy[contextPath] = remotesCopy[contextPath].filter(p => p !== moduleName);
remotesCopy[contextPath] = [...new Set(remotesCopy[contextPath])];
if (remotesCopy[contextPath].length === 0) {
delete remotesCopy[contextPath];
}
});
return remotesCopy;
}
parsePluginId(id) {
const [contextPath, moduleName] = id.split('/');
return { contextPath, moduleName };
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: PluginsService, deps: [{ token: i1.ApplicationService }, { token: i2.AppStateService }], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: PluginsService }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: PluginsService, decorators: [{
type: Injectable
}], ctorParameters: () => [{ type: i1.ApplicationService }, { type: i2.AppStateService }] });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGx1Z2lucy5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vY29yZS9wbHVnaW5zL3BsdWdpbnMuc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQzNDLE9BQU8sRUFDTCx1QkFBdUIsRUFLeEIsTUFBTSxhQUFhLENBQUM7QUFDckIsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sYUFBYSxDQUFDO0FBQ2pELE9BQU8sRUFBRSxTQUFTLEVBQUUsR0FBRyxFQUFFLE1BQU0sRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUNuRCxPQUFPLEVBQUUsTUFBTSxFQUFFLE9BQU8sRUFBRSxNQUFNLFFBQVEsQ0FBQztBQUN6QyxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFDN0QsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUNwQyxPQUFPLEVBQXFCLFdBQVcsRUFBaUIsTUFBTSxpQkFBaUIsQ0FBQztBQUNoRixPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSw4QkFBOEIsQ0FBQztBQUNuRSxPQUFPLEVBQUUscUJBQXFCLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQzs7OztBQUdsRSxNQUFNLE9BQU8sY0FBYztJQUN6QixNQUFNLENBQUMsNEJBQTRCLENBQUMsT0FBaUM7UUFDbkUsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDO1lBQ2IsT0FBTztRQUNULENBQUM7UUFDRCxNQUFNLGtCQUFrQixHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDaEQsTUFBTSxPQUFPLEdBQUcsRUFBRSxDQUFDO1FBQ25CLGtCQUFrQixDQUFDLE9BQU8sQ0FBQyxXQUFXLENBQUMsRUFBRTtZQUN2QyxNQUFNLFdBQVcsR0FBRyxPQUFPLENBQUMsV0FBVyxDQUFDLElBQUksRUFBRSxDQUFDO1lBQy9DLE9B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QUNsRSxJQUFJLENBQUMsV0FBVyxJQUFJLENBQUMsVUFBVSxJQUFJLENBQUMsV0FBVyxDQUFDLFdBQVcsQ0FBQyxFQUFFLENBQUM7Z0JBQzdELE9BQU87WUFDVCxDQUFDO1lBQ0QsV0FBVyxDQUFDLFdBQVcsQ0FBQyxHQUFHLFdBQVcsQ0FBQyxXQUFXLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLEtBQUssVUFBVSxDQUFDLENBQUM7WUFDbEYsV0FBVyxDQUFDLFdBQVcsQ0FBQyxHQUFHLENBQUMsR0FBRyxJQUFJLEdBQUcsQ0FBQyxXQUFXLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQ2xFLElBQUksV0FBVyxDQUFDLFdBQVcsQ0FBQyxDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUUsQ0FBQztnQkFDMUMsT0FBTyxXQUFXLENBQUMsV0FBVyxDQUFDLENBQUM7WUFDbEMsQ0FBQztRQUNILENBQUMsQ0FBQyxDQUFDO1FBQ0gsT0FBTyxXQUFXLENBQUM7SUFDckIsQ0FBQztJQUVPLGFBQWEsQ0FBQyxFQUFVO1FBQzlCLE1BQU0sQ0FBQyxXQUFXLEVBQUUsVUFBVSxDQUFDLEdBQUcsRUFBRSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUNoRCxPQUFPLEVBQUUsV0FBVyxFQUFFLFVBQVUsRUFBRSxDQUFDO0lBQ3JDLENBQUM7K0dBL2ZVLGNBQWM7bUhBQWQsY0FBYzs7NEZBQWQsY0FBYztrQkFEMUIsVUFBVSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEluamVjdGFibGUgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7XG4gIEFwcGxpY2F0aW9uQXZhaWxhYmlsaXR5LFxuICBBcHBsaWNhdGlvblJlbW90ZVBsdWdpbnMsXG4gIElBcHBsaWNhdGlvbixcbiAgSUFwcGxpY2F0aW9uVmVyc2lvbixcbiAgSU1hbmlmZXN0XG59IGZyb20gJ0BjOHkvY2xpZW50JztcbmltcG9ydCB7IEFwcGxpY2F0aW9uU2VydmljZSB9IGZyb20gJ0BjOHkvY2xpZW50JztcbmltcG9ydCB7IGNsb25lRGVlcCwgZ2V0LCB1bmlxQnkgfSBmcm9tICdsb2Rhc2gtZXMnO1xuaW1wb3J0IHsgY29lcmNlLCBjb21wYXJlIH0gZnJvbSAnc2VtdmVyJztcbmltcG9ydCB7IEFwcFN0YXRlU2VydmljZSB9IGZyb20gJy4uL2NvbW1vbi91aS1zdGF0ZS5zZXJ2aWNlJztcbmltcG9ydCB7IGdyb3VwQnkgfSBmcm9tICdsb2Rhc2gtZXMnO1xuaW1wb3J0IHsgQXBwbGljYXRpb25QbHVnaW4sIFBhY2thZ2VUeXBlLCBQbHVnaW5zQ29uZmlnIH0gZnJvbSAnLi9wbHVnaW5zLm1vZGVsJztcbmltcG9ydCB7IFBsdWdpbnNFeHBvcnRTY29wZXMgfSBmcm9tICcuLi9jb21tb24vQXBwbGljYXRpb25PcHRpb25zJztcbmltcG9ydCB7IFBsdWdpbnNSZXNvbHZlU2VydmljZSB9IGZyb20gJy4vcGx1Z2lucy1yZXNvbHZlLnNlcnZpY2UnO1xuXG5ASW5qZWN0YWJsZSgpXG5leHBvcnQgY2xhc3MgUGx1Z2luc1NlcnZpY2Uge1xuICBzdGF0aWMgY29udmVydEluc3RhbGxlZFJlbW90ZXNUb0lkcyhyZW1vdGVzOiBBcHBsaWNhdGlvblJlbW90ZVBsdWdpbnMpOiBzdHJpbmdbXSB7XG4gICAgaWYgKCFyZW1vdGVzKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGNvbnN0IGltcG9ydENvbnRleHRQYXRocyA9IE9iamVjdC5rZXlzKHJlbW90ZXMpO1xuICAgIGNvbnN0IHBsdWdpbnMgPSBbXTtcbiAgICBpbXBvcnRDb250ZXh0UGF0aHMuZm9yRWFjaChjb250ZXh0UGF0aCA9PiB7XG4gICAgICBjb25zdCBtb2R1bGVOYW1lcyA9IHJlbW90ZXNbY29udGV4dFBhdGhdIHx8IFtdO1xuICAgICAgcGx1Z2lucy5wdXNoKFxuICAgICAgICAuLi5tb2R1bGVOYW1lcy5tYXAobW9kdWxlID0+IFBsdWdpbnNTZXJ2aWNlLmNyZWF0ZVBsdWdpbklkKGNvbnRleHRQYXRoLCBtb2R1bGUsICcnLCB0cnVlKSlcbiAgICAgICk7XG4gICAgfSk7XG4gICAgcmV0dXJuIHBsdWdpbnM7XG4gIH1cblxuICBzdGF0aWMgY3JlYXRlUGx1Z2luSWQoXG4gICAgY29udGV4dFBhdGg6IHN0cmluZyxcbiAgICBwbHVnaW46IEFwcGxpY2F0aW9uUGx1Z2luIHwgc3RyaW5nLFxuICAgIHZlcnNpb246IHN0cmluZyxcbiAgICB1c2VMYXRlc3QgPSBmYWxzZVxuICApOiBzdHJpbmcge1xuICAgIGNvbnN0IG1vZHVsZU5hbWUgPSB0eXBlb2YgcGx1Z2luID09PSAnc3RyaW5nJyA/IHBsdWdpbiA6IHBsdWdpbi5tb2R1bGU7XG4gICAgaWYgKHVzZUxhdGVzdCkge1xuICAgICAgcmV0dXJuIGAke2NvbnRleHRQYXRofS8ke21vZHVsZU5hbWV9YDtcbiAgICB9XG4gICAgcmV0dXJuIGAke2NvbnRleHRQYXRofUAke3ZlcnNpb259LyR7bW9kdWxlTmFtZX1gO1xuICB9XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSBhcHBsaWNhdGlvblNlcnZpY2U6IEFwcGxpY2F0aW9uU2VydmljZSxcbiAgICBwcml2YXRlIGFwcFN0YXRlU2VydmljZTogQXBwU3RhdGVTZXJ2aWNlXG4gICkge31cblxuICAvKipcbiAgICogRmV0Y2hlcyBhIGxpc3Qgb2YgYXZhaWxhYmxlIHBhY2thZ2VzLlxuICAgKiBAcGFyYW0gcGFyYW1zIEFkZGl0aW9uYWwgcXVlcnkgcGFyYW1ldGVycy5cbiAgICogQHJldHVybnMgUmV0dXJucyBhIGxpc3Qgb2YgcGFja2FnZXMuXG4gICAqL1xuICBhc3luYyBsaXN0UGFja2FnZXMocGFyYW1zOiBhbnkgPSB7fSk6IFByb21pc2U8SUFwcGxpY2F0aW9uW10+IHtcbiAgICBjb25zdCBhcHBzID0gYXdhaXQgdGhpcy5saXN0QXBwbGljYXRpb25zQnlDdXJyZW50VGVuYW50KHBhcmFtcyk7XG4gICAgY29uc3Qgd2ViQXBwcyA9IGFwcHMuZmlsdGVyKGFwcCA9PiB0aGlzLmlzUGFja2FnZShhcHApKTtcbiAgICBjb25zdCB1bmlxdWVXZWJBcHBzID0gdGhpcy5yZW1vdmVEdXBsaWNhdGVzKHdlYkFwcHMsICdjb250ZXh0UGF0aCcpO1xuICAgIHJldHVybiB1bmlxdWVXZWJBcHBzLnNvcnQoKGEsIGIpID0+IGEubmFtZS5sb2NhbGVDb21wYXJlKGIubmFtZSkpO1xuICB9XG5cbiAgLyoqXG4gICAqIENoZWNrcyBpZiBhbiBhcHBsaWNhdGlvbiBpcyBhIHBhY2thZ2UuXG4gICAqIEBwYXJhbSBhcHBsaWNhdGlvbiBBcHBsaWNhdGlvbiBtYW5hZ2VkIG9iamVjdC5cbiAgICogQHJldHVybnMgUmV0dXJucyB0cnVlIGlmIHRoZSBhcHBsaWNhdGlvbiBpcyBhIHBhY2thZ2UuXG4gICAqL1xuICBpc1BhY2thZ2UoYXBwbGljYXRpb246IElBcHBsaWNhdGlvbik6IGJvb2xlYW4ge1xuICAgIHJldHVybiBhcHBsaWNhdGlvbi5tYW5pZmVzdD8uaXNQYWNrYWdlID09PSB0cnVlO1xuICB9XG5cbiAgLyoqXG4gICAqIFVwZGF0ZXMgdGhlIHJlbW90ZXMgZmllbGQgaW4gdGhlIGFwcGxpY2F0aW9uIGNvbmZpZ3VyYXRpb24gYnkgYWRkaW5nIG5ldyBwbHVnaW5zLlxuICAgKiBJbXBvcnRhbnQ6IGlmIHRoZSByZW1vdGVzIG9iamVjdCBpcyBub3Qgc2V0IG9uIHRoZSBjb25maWd1cmF0aW9uIG9iamVjdCxcbiAgICogcmVtb3RlcyB3aWxsIG5vdCBiZSBhZGRlZC4gTWFrZSBzdXJlIHRoYXQgdGhpcyBvYmplY3QgZXhpc3RzIGluIHRoZSBhcHBsaWNhdGlvbiBjb25maWd1cmF0aW9uLlxuICAgKiBAcGFyYW0gYXBwbGljYXRpb24gQXBwbGljYXRpb24gbWFuYWdlZCBvYmplY3QuXG4gICAqIEBwYXJhbSBwbHVnaW5zIExpc3Qgb2YgcmVtb3RlcyB0byBiZSBhZGRlZC5cbiAgICogQHJldHVybnMgUmV0dXJucyB1cGRhdGVkIGFwcGxpY2F0aW9uIHJlbW90ZXMuXG4gICAqL1xuICBhc3luYyBhZGRSZW1vdGVzKFxuICAgIGFwcGxpY2F0aW9uOiBJQXBwbGljYXRpb24sXG4gICAgcGx1Z2luczogQXBwbGljYXRpb25QbHVnaW4gfCBBcHBsaWNhdGlvblBsdWdpbltdXG4gICk6IFByb21pc2U8UGx1Z2luc0NvbmZpZz4ge1xuICAgIGNvbnN0IHBsdWdpbnNBcnJheSA9IEFycmF5LmlzQXJyYXkocGx1Z2lucykgPyBwbHVnaW5zIDogW3BsdWdpbnNdO1xuICAgIGNvbnN0IG1hbmlmZXN0UmVtb3RlcyA9IGFwcGxpY2F0aW9uLm1hbmlmZXN0Py5yZW1vdGVzIHx8IHt9O1xuICAgIGNvbnN0IGFwcENvbmZpZzogUGx1Z2luc0NvbmZpZyB8IHVuZGVmaW5lZCA9IGFwcGxpY2F0aW9uPy5jb25maWcgYXMgUGx1Z2luc0NvbmZpZztcbiAgICBjb25zdCBhcHBDb25maWdSZW1vdGVzID0gYXBwQ29uZmlnPy5yZW1vdGVzIHx8IG1hbmlmZXN0UmVtb3RlcztcbiAgICBjb25zdCBhcHBDb25maWdFeGNsdWRlZFJlbW90ZXMgPSBhcHBDb25maWc/LmV4Y2x1ZGVkUmVtb3RlcyB8fCB7fTtcbiAgICAvLyBvbmx5IG5vcm1hbCBhbmQgc2VsZiBvcHRpb25hbCBzY29wZWQgcGx1Z2lucyBzaG91bGQgYmUgYWRkZWQgdG8gcmVtb3Rlc1xuICAgIC8vIHNlbGYgc2NvcGVkIHBsdWdpbnMgd2lsbCBiZSBhdXRvbWF0aWNhbGx5IGFkZGVkXG4gICAgY29uc3QgYWxsUGx1Z2luc0V4Y2VwdFNlbGZTY29wZWQgPSB0aGlzLmdldEFsbFBsdWdpbnNFeGNlcHRTZWxmU2NvcGVkKFxuICAgICAgcGx1Z2luc0FycmF5LFxuICAgICAgYXBwbGljYXRpb24uY29udGV4dFBhdGhcbiAgICApO1xuICAgIGNvbnN0IG5ld1JlbW90ZXMgPSB0aGlzLmFkZFBsdWdpblRvUmVtb3Rlc0NvbmZpZyhhcHBDb25maWdSZW1vdGVzLCBhbGxQbHVnaW5zRXhjZXB0U2VsZlNjb3BlZCk7XG4gICAgLy8gc2hvdWxkIGJlIHVucHJvYmxlbWF0aWMgdG8gcmVtb3ZlIGFsbCBjYXRlZ29yaWVzIG9mIHBsdWdpbnMgZnJvbSBleGNsdWRlZCByZW1vdGVzXG4gICAgY29uc3QgbmV3RXhjbHVkZWRSZW1vdGVzID0gdGhpcy5yZW1vdmVQbHVnaW5zRnJvbVJlbW90ZXNDb25maWcoXG4gICAgICBhcHBDb25maWdFeGNsdWRlZFJlbW90ZXMsXG4gICAgICBwbHVnaW5zXG4gICAgKTtcbiAgICByZXR1cm4gYXdhaXQgdGhpcy51cGRhdGVSZW1vdGVzSW5BcHBDb25maWcoYXBwbGljYXRpb24sIG5ld1JlbW90ZXMsIG5ld0V4Y2x1ZGVkUmVtb3Rlcyk7XG4gIH1cblxuICAvKipcbiAgICogVXBkYXRlcyB0aGUgcmVtb3RlcyBmaWVsZCBpbiB0aGUgYXBwbGljYXRpb24gY29uZmlndXJhdGlvbiBieSByZW1vdmluZyBwbHVnaW5zLlxuICAgKiBAcGFyYW0gYXBwbGljYXRpb24gQXBwbGljYXRpb24gbWFuYWdlZCBvYmplY3QuXG4gICAqIEBwYXJhbSBwbHVnaW5zIExpc3Qgb2YgcmVtb3RlcyB0byBiZSByZW1vdmVkLlxuICAgKiBAcmV0dXJucyBSZXR1cm5zIHVwZGF0ZWQgYXBwbGljYXRpb24gcmVtb3Rlcy5cbiAgICovXG4gIGFzeW5jIHJlbW92ZVJlbW90ZXMoXG4gICAgYXBwbGljYXRpb246IElBcHBsaWNhdGlvbixcbiAgICBwbHVnaW5zOiBBcHBsaWNhdGlvblBsdWdpbiB8IEFwcGxpY2F0aW9uUGx1Z2luW11cbiAgKTogUHJvbWlzZTxQbHVnaW5zQ29uZmlnPiB7XG4gICAgY29uc3QgcGx1Z2luc0FycmF5ID0gQXJyYXkuaXNBcnJheShwbHVnaW5zKSA/IHBsdWdpbnMgOiBbcGx1Z2luc107XG4gICAgY29uc3QgbWFuaWZlc3RSZW1vdGVzID0gYXBwbGljYXRpb24ubWFuaWZlc3Q/LnJlbW90ZXMgfHwge307XG4gICAgY29uc3QgYXBwQ29uZmlnOiBQbHVnaW5zQ29uZmlnIHwgdW5kZWZpbmVkID0gYXBwbGljYXRpb24/LmNvbmZpZyBhcyBQbHVnaW5zQ29uZmlnO1xuICAgIGNvbnN0IGFwcENvbmZpZ1JlbW90ZXMgPSBhcHBDb25maWc/LnJlbW90ZXMgfHwgbWFuaWZlc3RSZW1vdGVzO1xuICAgIGNvbnN0IGFwcENvbmZpZ0V4Y2x1ZGVkUmVtb3RlcyA9IGFwcENvbmZpZz8uZXhjbHVkZWRSZW1vdGVzIHx8IHt9O1xuICAgIC8vIGFwcCBwbHVnaW5zIG5lZWQgdG8gYmUgcmVtb3ZlZCBmcm9tIHJlbW90ZXNcbiAgICBjb25zdCBuZXdSZW1vdGVzID0gdGhpcy5yZW1vdmVQbHVnaW5zRnJvbVJlbW90ZXNDb25maWcoYXBwQ29uZmlnUmVtb3RlcywgcGx1Z2lucyk7XG4gICAgLy8gc2VsZiBzY29wZWQgcGx1Z2lucyBuZWVkIHRvIGJlIGFkZGVkIHRvIGV4Y2x1ZGVkIHJlbW90ZXNcbiAgICAvLyBhcyB0aGV5IHdvdWxkIGJlIG90aGVyd2lzZSBhdXRvbWF0aWNhbGx5IGFkZGVkIHRvIHJlbW90ZXNcbiAgICBjb25zdCBzZWxmU2NvcGVkUGx1Z2lucyA9IHRoaXMuZ2V0U2VsZlNjb3BlZFBsdWdpbnMocGx1Z2luc0FycmF5LCBhcHBsaWNhdGlvbi5jb250ZXh0UGF0aCk7XG4gICAgY29uc3QgbmV3RXhjbHVkZWRSZW1vdGVzID0gdGhpcy5hZGRQbHVnaW5Ub1JlbW90ZXNDb25maWcoXG4gICAgICBhcHBDb25maWdFeGNsdWRlZFJlbW90ZXMsXG4gICAgICBzZWxmU2NvcGVkUGx1Z2luc1xuICAgICk7XG4gICAgcmV0dXJuIGF3YWl0IHRoaXMudXBkYXRlUmVtb3Rlc0luQXBwQ29uZmlnKGFwcGxpY2F0aW9uLCBuZXdSZW1vdGVzLCBuZXdFeGNsdWRlZFJlbW90ZXMpO1xuICB9XG5cbiAgLyoqXG4gICAqIFVwZGF0ZXMgdGhlIHJlbW90ZXMgZmllbGQgaW4gdGhlIGFwcGxpY2F0aW9uIGNvbmZpZ3VyYXRpb24uXG4gICAqIEBwYXJhbSBhcHBsaWNhdGlvbiBBcHBsaWNhdGlvbiBtYW5hZ2VkIG9iamVjdC5cbiAgICogQHBhcmFtIHBsdWdpbnMgTGlzdCBvZiByZW1vdGVzIHRvIGJlIGFkZGVkLlxuICAgKiBAcmV0dXJucyBSZXR1cm5zIHVwZGF0ZWQgYXBwbGljYXRpb24gcmVtb3Rlcy5cbiAgICovXG4gIGFzeW5jIHVwZGF0ZVJlbW90ZXNJbkFwcENvbmZpZyhcbiAgICBhcHBsaWNhdGlvbjogSUFwcGxpY2F0aW9uLFxuICAgIHBsdWdpbnM6IEFwcGxpY2F0aW9uUmVtb3RlUGx1Z2lucyxcbiAgICBleGNsdWRlZFJlbW90ZXM/OiBBcHBsaWNhdGlvblJlbW90ZVBsdWdpbnNcbiAgKTogUHJvbWlzZTxQbHVnaW5zQ29uZmlnPiB7XG4gICAgY29uc3QgdXBkYXRlZEFwcFdpdGhDb25maWcgPSBhd2FpdCB0aGlzLmFwcGxpY2F0aW9uU2VydmljZS51cGRhdGVBcHBsaWNhdGlvbkNvbmZpZyhcbiAgICAgIGFwcGxpY2F0aW9uLFxuICAgICAge1xuICAgICAgICByZW1vdGVzOiBwbHVnaW5zLFxuICAgICAgICBleGNsdWRlZFJlbW90ZXM6IGV4Y2x1ZGVkUmVtb3RlcyB8fCB7fVxuICAgICAgfSBhcyBQbHVnaW5zQ29uZmlnXG4gICAgKTtcbiAgICByZXR1cm4gdXBkYXRlZEFwcFdpdGhDb25maWc/LmNvbmZpZyB8fCB7IHJlbW90ZXM6IHt9IH07XG4gIH1cblxuICAvKipcbiAgICogRmV0Y2hlcyB0aGUgYXBwbGljYXRpb24gbWFuaWZlc3QuXG4gICAqIEBwYXJhbSBhcHBsaWNhdGlvbiBBcHBsaWNhdGlvbiBtYW5hZ2VkIG9iamVjdC5cbiAgICogQHJldHVybnMgUmV0dXJucyB0aGUgYXBwbGljYXRpb24gbWFuaWZlc3QuXG4gICAqL1xuICBhc3luYyBnZXRDdW11bG9jaXR5SnNvbkZpbGUoYXBwbGljYXRpb246IElBcHBsaWNhdGlvbikge1xuICAgIGNvbnN0IGM4eUpzb24gPSBhd2FpdCB0aGlzLmFwcGxpY2F0aW9uU2VydmljZS5nZXRBcHBNYW5pZmVzdChhcHBsaWNhdGlvbik7XG4gICAgaWYgKCFjOHlKc29uLnJlbW90ZXMpIHtcbiAgICAgIGM4eUpzb24ucmVtb3RlcyA9IHt9O1xuICAgIH1cbiAgICByZXR1cm4gYzh5SnNvbjtcbiAgfVxuXG4gIC8qKlxuICAgKiBTZXRzIHRoZSBpbml0aWFsIHN0YXRlIG9mIHJlbW90ZXMgaW4gdGhlIGNvbmZpZ3VyYXRpb24gKHdoZW4gaXQncyBtaXNzaW5nKSwgYmFzZWQgb24gdGhlIGxpc3Qgb2YgcmVtb3RlcyBiZWluZyBpbiB0aGUgYXBwbGljYXRpb24gbWFuaWZlc3QuXG4gICAqIEBwYXJhbSBhcHBsaWNhdGlvbiAgQXBwbGljYXRpb24gbWFuYWdlZCBvYmplY3QuXG4gICAqIEByZXR1cm5zIFJldHVybnMgYSBsaXN0IG9mIHJlbW90ZXMgdGhhdCBoYXMgYmVlbiBhc3NpZ25lZCB0byB0aGUgY29uZmlndXJhdGlvbiBvYmplY3QuXG4gICAqL1xuICBhc3luYyBzZXRJbml0aWFsUmVtb3RlcyhhcHBsaWNhdGlvbjogSUFwcGxpY2F0aW9uKSB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IG1hbmlmZXN0OiBJTWFuaWZlc3QgPSBhd2FpdCB0aGlzLmdldEN1bXVsb2NpdHlKc29uRmlsZShhcHBsaWNhdGlvbik7XG4gICAgICBjb25zdCBtYW5pZmVzdFJlbW90ZXM6IEFwcGxpY2F0aW9uUmVtb3RlUGx1Z2lucyA9IG1hbmlmZXN0LnJlbW90ZXM7XG5cbiAgICAgIHJldHVybiBhd2FpdCB0aGlzLnVwZGF0ZVJlbW90ZXNJbkFwcENvbmZpZyhhcHBsaWNhdGlvbiwgbWFuaWZlc3RSZW1vdGVzIHx8IHt9LCB7fSk7XG4gICAgfSBjYXRjaCAoZXIpIHtcbiAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfVxuICB9XG5cbiAgYXN5bmMgcmVzZXRSZW1vdGVzKGFwcGxpY2F0aW9uOiBJQXBwbGljYXRpb24pIHtcbiAgICByZXR1cm4gYXdhaXQgdGhpcy5hcHBsaWNhdGlvblNlcnZpY2UudXBkYXRlQXBwbGljYXRpb25Db25maWcoYXBwbGljYXRpb24sIHtcbiAgICAgIHJlbW90ZXM6IHVuZGVmaW5lZCxcbiAgICAgIGV4Y2x1ZGVkUmVtb3RlczogdW5kZWZpbmVkXG4gICAgfSBhcyBQbHVnaW5zQ29uZmlnKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTb3J0cyB2ZXJzaW9ucyBsaXN0IG9yIGxpc3Qgb2Ygb2JqZWN0cyBieSB2ZXJzaW9uIHByb3BlcnR5XG4gICAqIEByZXR1cm5zIGxpc3Qgb2YgdmVyc2lvbnMgYXMgYXJyYXkgb2Ygc3RyaW5ncyBvciBhcnJheSBvZiBvYmplY3RzIHNvcnRlZCBieSB2ZXJzaW9uIHByb3BlcnR5XG4gICAqXG4gICAqIEBwYXJhbSB7eyBsaXN0OiBUW107IHBhdGg6IHN0cmluZ1tdIH0gfCBzdHJpbmdbXX0gc291cmNlIGRhdGEgdG8gc29ydFxuICAgKiBAcGFyYW0geydhc2MnIHwgJ2Rlc2MnfSBvcmRlciBhc2NlbmRpbmcgb3IgZGVzY2VuZGluZyBvcmRlciBvZiBzb3J0aW5nXG4gICAqXG4gICAqICoqRXhhbXBsZSoqXG4gICAqIGBgYHR5cGVzY3JpcHRcbiAgICogY29uc3QgZGF0YSA9IFsnMS41LjAnLCAnMi4wLjAnXTtcbiAgICogY29uc3Qgc29ydGVkRGF0YSA9IHBsdWdpbnNTZXJ2aWNlLnNvcnRWZXJzaW9ucyh2ZXJzaW9ucywgJ2Rlc2MnKTtcbiAgICogLy8gc29ydGVkRGF0YTpcbiAgICogLy8gWycyLjAuMCcsICcxLjUuMCddXG4gICAqIGBgYFxuICAgKlxuICAgKiAqKkV4YW1wbGUqKlxuICAgKiBgYGB0eXBlc2NyaXB0XG4gICAqIGNvbnN0IGRhdGEgPSBbXG4gICAqICB7YXBwOiB7YXBwVmVyc2lvbjogJzEuNS4wJ319LFxuICAgKiAge2FwcDoge2FwcFZlcnNpb246ICcyLjAuMCd9fSxcbiAgICogXTtcbiAgICogY29uc3Qgc29ydGVkRGF0YSA9IHBsdWdpbnNTZXJ2aWNlLnNvcnRWZXJzaW9ucyh7bGlzdDogZGF0YSwgcGF0aDogWydhcHAnLCAnYXBwVmVyc2lvbiddfSwgJ2Rlc2MnKTtcbiAgICogLy8gc29ydGVkRGF0YTpcbiAgICogLy8gW1xuICAgKiAvLyAge2FwcDoge2FwcFZlcnNpb246ICcyLjAuMCd9fSxcbiAgICogLy8gIHthcHA6IHthcHBWZXJzaW9uOiAnMS41LjAnfX1cbiAgICogLy8gXVxuICAgKiBgYGBcbiAgICovXG4gIHNvcnRWZXJzaW9uczxUPihzb3VyY2U6IHsgbGlzdDogVFtdOyBwYXRoOiBzdHJpbmdbXSB9LCBvcmRlcjogJ2FzYycgfCAnZGVzYycpOiBUW107XG4gIHNvcnRWZXJzaW9ucyhzb3VyY2U6IHN0cmluZ1tdLCBvcmRlcjogJ2FzYycgfCAnZGVzYycpOiBzdHJpbmdbXTtcbiAgc29ydFZlcnNpb25zKHNvdXJjZTogYW55LCBvcmRlcjogJ2FzYycgfCAnZGVzYycpOiBhbnkge1xuICAgIGNvbnN0IHNvdXJjZUNvcHkgPSBjbG9uZURlZXAoc291cmNlKTtcbiAgICBpZiAoc291cmNlLmxpc3QgJiYgc291cmNlLnBhdGgpIHtcbiAgICAgIGNvbnN0IHBhdGggPSBzb3VyY2VDb3B5LnBhdGguam9pbignLicpO1xuICAgICAgcmV0dXJuIHNvdXJjZUNvcHkubGlzdC5zb3J0KFxuICAgICAgICAoYSwgYikgPT4gY29tcGFyZShjb2VyY2UoZ2V0KGEsIHBhdGgpKSwgY29lcmNlKGdldChiLCBwYXRoKSkpICogKG9yZGVyID09PSAnYXNjJyA/IDEgOiAtMSlcbiAgICAgICk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybiBzb3VyY2VDb3B5LnNvcnQoKGEsIGIpID0+IGNvbXBhcmUoY29lcmNlKGEpLCBjb2VyY2UoYikpICogKG9yZGVyID09PSAnYXNjJyA/IDEgOiAtMSkpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBFeHRyYWN0cyBhIGxpc3Qgb2YgZXhwb3J0ZWQgcGx1Z2lucyBmcm9tIHRoZSBhcHBsaWNhdGlvbiBvYmplY3QuXG4gICAqIEBwYXJhbSBhcHBsaWNhdGlvbiBBcHBsaWNhdGlvbiBtYW5hZ2VkIG9iamVjdC5cbiAgICogQHBhcmFtIHVzZUxhdGVzdCBTZXQgdGhpcyB0byB0cnVlLCB0byBub3QgYmluZCB0aGUgcGx1Z2luIHRvIGFueSB2ZXJzaW9uLlxuICAgKiBAcmV0dXJucyBSZXR1cm5zIGEgbGlzdCBvZiBleHBvcnRlZCBwbHVnaW5zLlxuICAgKi9cbiAgZ2V0TUZFeHBvcnRzKFxuICAgIGFwcGxpY2F0aW9uOiBJQXBwbGljYXRpb24sXG4gICAgZXhjbHVkZWRTY29wZXMgPSBbXG4gICAgICBQbHVnaW5zRXhwb3J0U2NvcGVzLlNFTEYsXG4gICAgICBQbHVnaW5zRXhwb3J0U2NvcGVzLlNFTEZfT1BUSU9OQUwsXG4gICAgICBQbHVnaW5zRXhwb3J0U2NvcGVzLkdMT0JBTFxuICAgIF0sXG4gICAgdXNlTGF0ZXN0ID0gZmFsc2VcbiAgKTogQXBwbGljYXRpb25QbHVnaW5bXSB7XG4gICAgY29uc3QgbWFuaWZlc3Q6IFBhcnRpYWw8SU1hbmlmZXN0PiA9IGFwcGxpY2F0aW9uLm1hbmlmZXN0O1xuICAgIGlmICghbWFuaWZlc3QgfHwgIW1hbmlmZXN0LmV4cG9ydHMpIHtcbiAgICAgIHJldHVybiBbXTtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMuZXh0ZW5kUGx1Z2luc0RldGFpbHMoXG4gICAgICBhcHBsaWNhdGlvbixcbiAgICAgIHtcbiAgICAgICAgdmVyc2lvbjogbWFuaWZlc3QudmVyc2lvbixcbiAgICAgICAgYmluYXJ5SWQ6IHVuZGVmaW5lZFxuICAgICAgfSxcbiAgICAgIHVzZUxhdGVzdFxuICAgICkuZmlsdGVyKHBsdWdpbiA9PiAhZXhjbHVkZWRTY29wZXMuaW5jbHVkZXMocGx1Z2luLnNjb3BlKSk7XG4gIH1cblxuICAvKipcbiAgICogRXh0cmFjdHMgYSBsaXN0IG9mIGV4cG9ydHMgZnJvbSBlYWNoIGF2YWlsYWJsZSBwYWNrYWdlLlxuICAgKiBAcGFyYW0gYWxsVmVyc2lvbnMgSWYgc2V0IHRvIHRydWUsIGFsbCBhbmQgbm90IG9ubHkgbGF0ZXN0IHZlcnNpb25zIGFyZSBpbmNsdWRlZC5cbiAgICogQHBhcmFtIGV4Y2x1ZGVkU2NvcGVzIERlZmluZXMgd2hpY2ggc2NvcGVzIHNob3VsZCBub3QgYmUgbG9hZGVkLlxuICAgKiBAcmV0dXJucyBSZXR1cm5zIGEgbGlzdCBvZiBhbGwgZXhwb3J0ZWQgcGx1Z2lucy5cbiAgICovXG4gIGFzeW5jIGdldEFsbE1GRXhwb3J0cyhcbiAgICBhbGxWZXJzaW9ucyA9IGZhbHNlLFxuICAgIGV4Y2x1ZGVkU2NvcGVzID0gW1xuICAgICAgUGx1Z2luc0V4cG9ydFNjb3Blcy5TRUxGLFxuICAgICAgUGx1Z2luc0V4cG9ydFNjb3Blcy5TRUxGX09QVElPTkFMLFxuICAgICAgUGx1Z2luc0V4cG9ydFNjb3Blcy5HTE9CQUxcbiAgICBdXG4gICk6IFByb21pc2U8QXBwbGljYXRpb25QbHVnaW5bXT4ge1xuICAgIGNvbnN0IHBsdWdpbnMgPSBuZXcgQXJyYXk8QXBwbGljYXRpb25QbHVnaW4+KCk7XG4gICAgY29uc3QgcGFja2FnZXMgPSBhd2FpdCB0aGlzLmxpc3RQ