UNPKG

@c8y/ngx-components

Version:

Angular modules for Cumulocity IoT applications

428 lines 66.4 kB
import { Injectable } from '@angular/core'; import { ApplicationAvailability, FetchClient } 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, client) { this.applicationService = applicationService; this.appStateService = appStateService; this.client = client; } /** * 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; } async getReadmeFileContent(baseUrl) { return this.getFileContent(baseUrl, 'readme'); } async getChangelogFileContent(baseUrl) { return this.getFileContent(baseUrl, 'changelog'); } async getFileContent(baseUrl, fileType) { const file = await this.getFile(baseUrl, fileType); if (file.status === 200) { return await file.text(); } return ''; } async getFile(baseUrl, fileType) { const options = { method: 'GET', headers: { 'Content-Type': 'text/markdown' } }; const uppercaseFilename = fileType === 'readme' ? 'README.md' : 'CHANGELOG.md'; let result = await this.client.fetch(`${baseUrl}${uppercaseFilename}`, options); if (result && result.status === 404) { result = await this.client.fetch(`${baseUrl}${uppercaseFilename.toLowerCase()}`, options); } return result; } 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 }, { token: i1.FetchClient }], 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 }, { type: i1.FetchClient }] }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGx1Z2lucy5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vY29yZS9wbHVnaW5zL3BsdWdpbnMuc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQzNDLE9BQU8sRUFDTCx1QkFBdUIsRUFFdkIsV0FBVyxFQU1aLE1BQU0sYUFBYSxDQUFDO0FBQ3JCLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUNqRCxPQUFPLEVBQUUsU0FBUyxFQUFFLEdBQUcsRUFBRSxNQUFNLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFDbkQsT0FBTyxFQUFFLE1BQU0sRUFBRSxPQUFPLEVBQUUsTUFBTSxRQUFRLENBQUM7QUFDekMsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBQzdELE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFDcEMsT0FBTyxFQUFxQixXQUFXLEVBQWlCLE1BQU0saUJBQWlCLENBQUM7QUFDaEYsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sOEJBQThCLENBQUM7QUFDbkUsT0FBTyxFQUFFLHFCQUFxQixFQUFFLE1BQU0sMkJBQTJCLENBQUM7Ozs7QUFHbEUsTUFBTSxPQUFPLGNBQWM7SUFDekIsTUFBTSxDQUFDLDRCQUE0QixDQUFDLE9BQWlDO1FBQ25FLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQztZQUNiLE9BQU87UUFDVCxDQUFDO1FBQ0QsTUFBTSxrQkFBa0IsR0FBRyxNQUFNLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ2hELE1BQU0sT0FBTyxHQUFHLEVBQUUsQ0FBQztRQUNuQixrQkFBa0IsQ0FBQyxPQUFPLENBQUMsV0FBVyxDQUFDLEVBQUU7WUFDdkMsTUFBTSxXQUFXLEdBQUcsT0FBTyxDQUFDLFdBQVcsQ0FBQyxJQUFJLEVBQUUsQ0FB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LENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxFQUFFO1lBQ3BCLE1BQU0sRUFBRSxXQUFXLEVBQUUsVUFBVSxFQUFFLEdBQUcsSUFBSSxDQUFDLGFBQWEsQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDLENBQUM7WUFDbEUsSUFBSSxDQUFDLFdBQVcsSUFBSSxDQUFDLFVBQVUsSUFBSSxDQUFDLFdBQVcsQ0FBQyxXQUFXLENBQUMsRUFBRSxDQUFDO2dCQUM3RCxPQUFPO1lBQ1QsQ0FBQztZQUNELFdBQVcsQ0FBQyxXQUFXLENBQUMsR0FBRyxXQUFXLENBQUMsV0FBVyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxLQUFLLFVBQVUsQ0FBQyxDQUFDO1lBQ2xGLFdBQVcsQ0FBQyxXQUFXLENBQUMsR0FBRyxDQUFDLEdBQUcsSUFBSSxHQUFHLENBQUMsV0FBVyxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUNsRSxJQUFJLFdBQVcsQ0FBQyxXQUFXLENBQUMsQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFLENBQUM7Z0JBQzFDLE9BQU8sV0FBVyxDQUFDLFdBQVcsQ0FBQyxDQUFDO1lBQ2xDLENBQUM7UUFDSCxDQUFDLENBQUMsQ0FBQztRQUNILE9BQU8sV0FBVyxDQUFDO0lBQ3JCLENBQUM7SUFFTyxhQUFhLENBQUMsRUFBVTtRQUM5QixNQUFNLENBQUMsV0FBVyxFQUFFLFVBQVUsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDaEQsT0FBTyxFQUFFLFdBQVcsRUFBRSxVQUFVLEVBQUUsQ0FBQztJQUNyQyxDQUFDOytHQXJpQlUsY0FBYzttSEFBZCxjQUFjOzs0RkFBZCxjQUFjO2tCQUQxQixVQUFVIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSW5qZWN0YWJsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHtcbiAgQXBwbGljYXRpb25BdmFpbGFiaWxpdHksXG4gIEFwcGxpY2F0aW9uUmVtb3RlUGx1Z2lucyxcbiAgRmV0Y2hDbGllbnQsXG4gIElBcHBsaWNhdGlvbixcbiAgSUFwcGxpY2F0aW9uVmVyc2lvbixcbiAgSUZldGNoT3B0aW9ucyxcbiAgSUZldGNoUmVzcG9uc2UsXG4gIElNYW5pZmVzdFxufSBmcm9tICdAYzh5L2NsaWVudCc7XG5pbXBvcnQgeyBBcHBsaWNhdGlvblNlcnZpY2UgfSBmcm9tICdAYzh5L2NsaWVudCc7XG5pbXBvcnQgeyBjbG9uZURlZXAsIGdldCwgdW5pcUJ5IH0gZnJvbSAnbG9kYXNoLWVzJztcbmltcG9ydCB7IGNvZXJjZSwgY29tcGFyZSB9IGZyb20gJ3NlbXZlcic7XG5pbXBvcnQgeyBBcHBTdGF0ZVNlcnZpY2UgfSBmcm9tICcuLi9jb21tb24vdWktc3RhdGUuc2VydmljZSc7XG5pbXBvcnQgeyBncm91cEJ5IH0gZnJvbSAnbG9kYXNoLWVzJztcbmltcG9ydCB7IEFwcGxpY2F0aW9uUGx1Z2luLCBQYWNrYWdlVHlwZSwgUGx1Z2luc0NvbmZpZyB9IGZyb20gJy4vcGx1Z2lucy5tb2RlbCc7XG5pbXBvcnQgeyBQbHVnaW5zRXhwb3J0U2NvcGVzIH0gZnJvbSAnLi4vY29tbW9uL0FwcGxpY2F0aW9uT3B0aW9ucyc7XG5pbXBvcnQgeyBQbHVnaW5zUmVzb2x2ZVNlcnZpY2UgfSBmcm9tICcuL3BsdWdpbnMtcmVzb2x2ZS5zZXJ2aWNlJztcblxuQEluamVjdGFibGUoKVxuZXhwb3J0IGNsYXNzIFBsdWdpbnNTZXJ2aWNlIHtcbiAgc3RhdGljIGNvbnZlcnRJbnN0YWxsZWRSZW1vdGVzVG9JZHMocmVtb3RlczogQXBwbGljYXRpb25SZW1vdGVQbHVnaW5zKTogc3RyaW5nW10ge1xuICAgIGlmICghcmVtb3Rlcykge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBjb25zdCBpbXBvcnRDb250ZXh0UGF0aHMgPSBPYmplY3Qua2V5cyhyZW1vdGVzKTtcbiAgICBjb25zdCBwbHVnaW5zID0gW107XG4gICAgaW1wb3J0Q29udGV4dFBhdGhzLmZvckVhY2goY29udGV4dFBhdGggPT4ge1xuICAgICAgY29uc3QgbW9kdWxlTmFtZXMgPSByZW1vdGVzW2NvbnRleHRQYXRoXSB8fCBbXTtcbiAgICAgIHBsdWdpbnMucHVzaChcbiAgICAgICAgLi4ubW9kdWxlTmFtZXMubWFwKG1vZHVsZSA9PiBQbHVnaW5zU2VydmljZS5jcmVhdGVQbHVnaW5JZChjb250ZXh0UGF0aCwgbW9kdWxlLCAnJywgdHJ1ZSkpXG4gICAgICApO1xuICAgIH0pO1xuICAgIHJldHVybiBwbHVnaW5zO1xuICB9XG5cbiAgc3RhdGljIGNyZWF0ZVBsdWdpbklkKFxuICAgIGNvbnRleHRQYXRoOiBzdHJpbmcsXG4gICAgcGx1Z2luOiBBcHBsaWNhdGlvblBsdWdpbiB8IHN0cmluZyxcbiAgICB2ZXJzaW9uOiBzdHJpbmcsXG4gICAgdXNlTGF0ZXN0ID0gZmFsc2VcbiAgKTogc3RyaW5nIHtcbiAgICBjb25zdCBtb2R1bGVOYW1lID0gdHlwZW9mIHBsdWdpbiA9PT0gJ3N0cmluZycgPyBwbHVnaW4gOiBwbHVnaW4ubW9kdWxlO1xuICAgIGlmICh1c2VMYXRlc3QpIHtcbiAgICAgIHJldHVybiBgJHtjb250ZXh0UGF0aH0vJHttb2R1bGVOYW1lfWA7XG4gICAgfVxuICAgIHJldHVybiBgJHtjb250ZXh0UGF0aH1AJHt2ZXJzaW9ufS8ke21vZHVsZU5hbWV9YDtcbiAgfVxuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgYXBwbGljYXRpb25TZXJ2aWNlOiBBcHBsaWNhdGlvblNlcnZpY2UsXG4gICAgcHJpdmF0ZSBhcHBTdGF0ZVNlcnZpY2U6IEFwcFN0YXRlU2VydmljZSxcbiAgICBwcml2YXRlIGNsaWVudDogRmV0Y2hDbGllbnRcbiAgKSB7fVxuXG4gIC8qKlxuICAgKiBGZXRjaGVzIGEgbGlzdCBvZiBhdmFpbGFibGUgcGFja2FnZXMuXG4gICAqIEBwYXJhbSBwYXJhbXMgQWRkaXRpb25hbCBxdWVyeSBwYXJhbWV0ZXJzLlxuICAgKiBAcmV0dXJucyBSZXR1cm5zIGEgbGlzdCBvZiBwYWNrYWdlcy5cbiAgICovXG4gIGFzeW5jIGxpc3RQYWNrYWdlcyhwYXJhbXM6IGFueSA9IHt9KTogUHJvbWlzZTxJQXBwbGljYXRpb25bXT4ge1xuICAgIGNvbnN0IGFwcHMgPSBhd2FpdCB0aGlzLmxpc3RBcHBsaWNhdGlvbnNCeUN1cnJlbnRUZW5hbnQocGFyYW1zKTtcbiAgICBjb25zdCB3ZWJBcHBzID0gYXBwcy5maWx0ZXIoYXBwID0+IHRoaXMuaXNQYWNrYWdlKGFwcCkpO1xuICAgIGNvbnN0IHVuaXF1ZVdlYkFwcHMgPSB0aGlzLnJlbW92ZUR1cGxpY2F0ZXMod2ViQXBwcywgJ2NvbnRleHRQYXRoJyk7XG4gICAgcmV0dXJuIHVuaXF1ZVdlYkFwcHMuc29ydCgoYSwgYikgPT4gYS5uYW1lLmxvY2FsZUNvbXBhcmUoYi5uYW1lKSk7XG4gIH1cblxuICAvKipcbiAgICogQ2hlY2tzIGlmIGFuIGFwcGxpY2F0aW9uIGlzIGEgcGFja2FnZS5cbiAgICogQHBhcmFtIGFwcGxpY2F0aW9uIEFwcGxpY2F0aW9uIG1hbmFnZWQgb2JqZWN0LlxuICAgKiBAcmV0dXJucyBSZXR1cm5zIHRydWUgaWYgdGhlIGFwcGxpY2F0aW9uIGlzIGEgcGFja2FnZS5cbiAgICovXG4gIGlzUGFja2FnZShhcHBsaWNhdGlvbjogSUFwcGxpY2F0aW9uKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIGFwcGxpY2F0aW9uLm1hbmlmZXN0Py5pc1BhY2thZ2UgPT09IHRydWU7XG4gIH1cblxuICAvKipcbiAgICogVXBkYXRlcyB0aGUgcmVtb3RlcyBmaWVsZCBpbiB0aGUgYXBwbGljYXRpb24gY29uZmlndXJhdGlvbiBieSBhZGRpbmcgbmV3IHBsdWdpbnMuXG4gICAqIEltcG9ydGFudDogaWYgdGhlIHJlbW90ZXMgb2JqZWN0IGlzIG5vdCBzZXQgb24gdGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0LFxuICAgKiByZW1vdGVzIHdpbGwgbm90IGJlIGFkZGVkLiBNYWtlIHN1cmUgdGhhdCB0aGlzIG9iamVjdCBleGlzdHMgaW4gdGhlIGFwcGxpY2F0aW9uIGNvbmZpZ3VyYXRpb24uXG4gICAqIEBwYXJhbSBhcHBsaWNhdGlvbiBBcHBsaWNhdGlvbiBtYW5hZ2VkIG9iamVjdC5cbiAgICogQHBhcmFtIHBsdWdpbnMgTGlzdCBvZiByZW1vdGVzIHRvIGJlIGFkZGVkLlxuICAgKiBAcmV0dXJucyBSZXR1cm5zIHVwZGF0ZWQgYXBwbGljYXRpb24gcmVtb3Rlcy5cbiAgICovXG4gIGFzeW5jIGFkZFJlbW90ZXMoXG4gICAgYXBwbGljYXRpb246IElBcHBsaWNhdGlvbixcbiAgICBwbHVnaW5zOiBBcHBsaWNhdGlvblBsdWdpbiB8IEFwcGxpY2F0aW9uUGx1Z2luW11cbiAgKTogUHJvbWlzZTxQbHVnaW5zQ29uZmlnPiB7XG4gICAgY29uc3QgcGx1Z2luc0FycmF5ID0gQXJyYXkuaXNBcnJheShwbHVnaW5zKSA/IHBsdWdpbnMgOiBbcGx1Z2luc107XG4gICAgY29uc3QgbWFuaWZlc3RSZW1vdGVzID0gYXBwbGljYXRpb24ubWFuaWZlc3Q/LnJlbW90ZXMgfHwge307XG4gICAgY29uc3QgYXBwQ29uZmlnOiBQbHVnaW5zQ29uZmlnIHwgdW5kZWZpbmVkID0gYXBwbGljYXRpb24/LmNvbmZpZyBhcyBQbHVnaW5zQ29uZmlnO1xuICAgIGNvbnN0IGFwcENvbmZpZ1JlbW90ZXMgPSBhcHBDb25maWc/LnJlbW90ZXMgfHwgbWFuaWZlc3RSZW1vdGVzO1xuICAgIGNvbnN0IGFwcENvbmZpZ0V4Y2x1ZGVkUmVtb3RlcyA9IGFwcENvbmZpZz8uZXhjbHVkZWRSZW1vdGVzIHx8IHt9O1xuICAgIC8vIG9ubHkgbm9ybWFsIGFuZCBzZWxmIG9wdGlvbmFsIHNjb3BlZCBwbHVnaW5zIHNob3VsZCBiZSBhZGRlZCB0byByZW1vdGVzXG4gICAgLy8gc2VsZiBzY29wZWQgcGx1Z2lucyB3aWxsIGJlIGF1dG9tYXRpY2FsbHkgYWRkZWRcbiAgICBjb25zdCBhbGxQbHVnaW5zRXhjZXB0U2VsZlNjb3BlZCA9IHRoaXMuZ2V0QWxsUGx1Z2luc0V4Y2VwdFNlbGZTY29wZWQoXG4gICAgICBwbHVnaW5zQXJyYXksXG4gICAgICBhcHBsaWNhdGlvbi5jb250ZXh0UGF0aFxuICAgICk7XG4gICAgY29uc3QgbmV3UmVtb3RlcyA9IHRoaXMuYWRkUGx1Z2luVG9SZW1vdGVzQ29uZmlnKGFwcENvbmZpZ1JlbW90ZXMsIGFsbFBsdWdpbnNFeGNlcHRTZWxmU2NvcGVkKTtcbiAgICAvLyBzaG91bGQgYmUgdW5wcm9ibGVtYXRpYyB0byByZW1vdmUgYWxsIGNhdGVnb3JpZXMgb2YgcGx1Z2lucyBmcm9tIGV4Y2x1ZGVkIHJlbW90ZXNcbiAgICBjb25zdCBuZXdFeGNsdWRlZFJlbW90ZXMgPSB0aGlzLnJlbW92ZVBsdWdpbnNGcm9tUmVtb3Rlc0NvbmZpZyhcbiAgICAgIGFwcENvbmZpZ0V4Y2x1ZGVkUmVtb3RlcyxcbiAgICAgIHBsdWdpbnNcbiAgICApO1xuICAgIHJldHVybiBhd2FpdCB0aGlzLnVwZGF0ZVJlbW90ZXNJbkFwcENvbmZpZyhhcHBsaWNhdGlvbiwgbmV3UmVtb3RlcywgbmV3RXhjbHVkZWRSZW1vdGVzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBVcGRhdGVzIHRoZSByZW1vdGVzIGZpZWxkIGluIHRoZSBhcHBsaWNhdGlvbiBjb25maWd1cmF0aW9uIGJ5IHJlbW92aW5nIHBsdWdpbnMuXG4gICAqIEBwYXJhbSBhcHBsaWNhdGlvbiBBcHBsaWNhdGlvbiBtYW5hZ2VkIG9iamVjdC5cbiAgICogQHBhcmFtIHBsdWdpbnMgTGlzdCBvZiByZW1vdGVzIHRvIGJlIHJlbW92ZWQuXG4gICAqIEByZXR1cm5zIFJldHVybnMgdXBkYXRlZCBhcHBsaWNhdGlvbiByZW1vdGVzLlxuICAgKi9cbiAgYXN5bmMgcmVtb3ZlUmVtb3RlcyhcbiAgICBhcHBsaWNhdGlvbjogSUFwcGxpY2F0aW9uLFxuICAgIHBsdWdpbnM6IEFwcGxpY2F0aW9uUGx1Z2luIHwgQXBwbGljYXRpb25QbHVnaW5bXVxuICApOiBQcm9taXNlPFBsdWdpbnNDb25maWc+IHtcbiAgICBjb25zdCBwbHVnaW5zQXJyYXkgPSBBcnJheS5pc0FycmF5KHBsdWdpbnMpID8gcGx1Z2lucyA6IFtwbHVnaW5zXTtcbiAgICBjb25zdCBtYW5pZmVzdFJlbW90ZXMgPSBhcHBsaWNhdGlvbi5tYW5pZmVzdD8ucmVtb3RlcyB8fCB7fTtcbiAgICBjb25zdCBhcHBDb25maWc6IFBsdWdpbnNDb25maWcgfCB1bmRlZmluZWQgPSBhcHBsaWNhdGlvbj8uY29uZmlnIGFzIFBsdWdpbnNDb25maWc7XG4gICAgY29uc3QgYXBwQ29uZmlnUmVtb3RlcyA9IGFwcENvbmZpZz8ucmVtb3RlcyB8fCBtYW5pZmVzdFJlbW90ZXM7XG4gICAgY29uc3QgYXBwQ29uZmlnRXhjbHVkZWRSZW1vdGVzID0gYXBwQ29uZmlnPy5leGNsdWRlZFJlbW90ZXMgfHwge307XG4gICAgLy8gYXBwIHBsdWdpbnMgbmVlZCB0byBiZSByZW1vdmVkIGZyb20gcmVtb3Rlc1xuICAgIGNvbnN0IG5ld1JlbW90ZXMgPSB0aGlzLnJlbW92ZVBsdWdpbnNGcm9tUmVtb3Rlc0NvbmZpZyhhcHBDb25maWdSZW1vdGVzLCBwbHVnaW5zKTtcbiAgICAvLyBzZWxmIHNjb3BlZCBwbHVnaW5zIG5lZWQgdG8gYmUgYWRkZWQgdG8gZXhjbHVkZWQgcmVtb3Rlc1xuICAgIC8vIGFzIHRoZXkgd291bGQgYmUgb3RoZXJ3aXNlIGF1dG9tYXRpY2FsbHkgYWRkZWQgdG8gcmVtb3Rlc1xuICAgIGNvbnN0IHNlbGZTY29wZWRQbHVnaW5zID0gdGhpcy5nZXRTZWxmU2NvcGVkUGx1Z2lucyhwbHVnaW5zQXJyYXksIGFwcGxpY2F0aW9uLmNvbnRleHRQYXRoKTtcbiAgICBjb25zdCBuZXdFeGNsdWRlZFJlbW90ZXMgPSB0aGlzLmFkZFBsdWdpblRvUmVtb3Rlc0NvbmZpZyhcbiAgICAgIGFwcENvbmZpZ0V4Y2x1ZGVkUmVtb3RlcyxcbiAgICAgIHNlbGZTY29wZWRQbHVnaW5zXG4gICAgKTtcbiAgICByZXR1cm4gYXdhaXQgdGhpcy51cGRhdGVSZW1vdGVzSW5BcHBDb25maWcoYXBwbGljYXRpb24sIG5ld1JlbW90ZXMsIG5ld0V4Y2x1ZGVkUmVtb3Rlcyk7XG4gIH1cblxuICAvKipcbiAgICogVXBkYXRlcyB0aGUgcmVtb3RlcyBmaWVsZCBpbiB0aGUgYXBwbGljYXRpb24gY29uZmlndXJhdGlvbi5cbiAgICogQHBhcmFtIGFwcGxpY2F0aW9uIEFwcGxpY2F0aW9uIG1hbmFnZWQgb2JqZWN0LlxuICAgKiBAcGFyYW0gcGx1Z2lucyBMaXN0IG9mIHJlbW90ZXMgdG8gYmUgYWRkZWQuXG4gICAqIEByZXR1cm5zIFJldHVybnMgdXBkYXRlZCBhcHBsaWNhdGlvbiByZW1vdGVzLlxuICAgKi9cbiAgYXN5bmMgdXBkYXRlUmVtb3Rlc0luQXBwQ29uZmlnKFxuICAgIGFwcGxpY2F0aW9uOiBJQXBwbGljYXRpb24sXG4gICAgcGx1Z2luczogQXBwbGljYXRpb25SZW1vdGVQbHVnaW5zLFxuICAgIGV4Y2x1ZGVkUmVtb3Rlcz86IEFwcGxpY2F0aW9uUmVtb3RlUGx1Z2luc1xuICApOiBQcm9taXNlPFBsdWdpbnNDb25maWc+IHtcbiAgICBjb25zdCB1cGRhdGVkQXBwV2l0aENvbmZpZyA9IGF3YWl0IHRoaXMuYXBwbGljYXRpb25TZXJ2aWNlLnVwZGF0ZUFwcGxpY2F0aW9uQ29uZmlnKFxuICAgICAgYXBwbGljYXRpb24sXG4gICAgICB7XG4gICAgICAgIHJlbW90ZXM6IHBsdWdpbnMsXG4gICAgICAgIGV4Y2x1ZGVkUmVtb3RlczogZXhjbHVkZWRSZW1vdGVzIHx8IHt9XG4gICAgICB9IGFzIFBsdWdpbnNDb25maWdcbiAgICApO1xuICAgIHJldHVybiB1cGRhdGVkQXBwV2l0aENvbmZpZz8uY29uZmlnIHx8IHsgcmVtb3Rlczoge30gfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBGZXRjaGVzIHRoZSBhcHBsaWNhdGlvbiBtYW5pZmVzdC5cbiAgICogQHBhcmFtIGFwcGxpY2F0aW9uIEFwcGxpY2F0aW9uIG1hbmFnZWQgb2JqZWN0LlxuICAgKiBAcmV0dXJucyBSZXR1cm5zIHRoZSBhcHBsaWNhdGlvbiBtYW5pZmVzdC5cbiAgICovXG4gIGFzeW5jIGdldEN1bXVsb2NpdHlKc29uRmlsZShhcHBsaWNhdGlvbjogSUFwcGxpY2F0aW9uKSB7XG4gICAgY29uc3QgYzh5SnNvbiA9IGF3YWl0IHRoaXMuYXBwbGljYXRpb25TZXJ2aWNlLmdldEFwcE1hbmlmZXN0KGFwcGxpY2F0aW9uKTtcbiAgICBpZiAoIWM4eUpzb24ucmVtb3Rlcykge1xuICAgICAgYzh5SnNvbi5yZW1vdGVzID0ge307XG4gICAgfVxuICAgIHJldHVybiBjOHlKc29uO1xuICB9XG5cbiAgLyoqXG4gICAqIFNldHMgdGhlIGluaXRpYWwgc3RhdGUgb2YgcmVtb3RlcyBpbiB0aGUgY29uZmlndXJhdGlvbiAod2hlbiBpdCdzIG1pc3NpbmcpLCBiYXNlZCBvbiB0aGUgbGlzdCBvZiByZW1vdGVzIGJlaW5nIGluIHRoZSBhcHBsaWNhdGlvbiBtYW5pZmVzdC5cbiAgICogQHBhcmFtIGFwcGxpY2F0aW9uICBBcHBsaWNhdGlvbiBtYW5hZ2VkIG9iamVjdC5cbiAgICogQHJldHVybnMgUmV0dXJucyBhIGxpc3Qgb2YgcmVtb3RlcyB0aGF0IGhhcyBiZWVuIGFzc2lnbmVkIHRvIHRoZSBjb25maWd1cmF0aW9uIG9iamVjdC5cbiAgICovXG4gIGFzeW5jIHNldEluaXRpYWxSZW1vdGVzKGFwcGxpY2F0aW9uOiBJQXBwbGljYXRpb24pIHtcbiAgICB0cnkge1xuICAgICAgY29uc3QgbWFuaWZlc3Q6IElNYW5pZmVzdCA9IGF3YWl0IHRoaXMuZ2V0Q3VtdWxvY2l0eUpzb25GaWxlKGFwcGxpY2F0aW9uKTtcbiAgICAgIGNvbnN0IG1hbmlmZXN0UmVtb3RlczogQXBwbGljYXRpb25SZW1vdGVQbHVnaW5zID0gbWFuaWZlc3QucmVtb3RlcztcblxuICAgICAgcmV0dXJuIGF3YWl0IHRoaXMudXBkYXRlUmVtb3Rlc0luQXBwQ29uZmlnKGFwcGxpY2F0aW9uLCBtYW5pZmVzdFJlbW90ZXMgfHwge30sIHt9KTtcbiAgICB9IGNhdGNoIChlcikge1xuICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICB9XG4gIH1cblxuICBhc3luYyByZXNldFJlbW90ZXMoYXBwbGljYXRpb246IElBcHBsaWNhdGlvbikge1xuICAgIHJldHVybiBhd2FpdCB0aGlzLmFwcGxpY2F0aW9uU2VydmljZS51cGRhdGVBcHBsaWNhdGlvbkNvbmZpZyhhcHBsaWNhdGlvbiwge1xuICAgICAgcmVtb3RlczogdW5kZWZpbmVkLFxuICAgICAgZXhjbHVkZWRSZW1vdGVzOiB1bmRlZmluZWRcbiAgICB9IGFzIFBsdWdpbnNDb25maWcpO1xuICB9XG5cbiAgLyoqXG4gICAqIFNvcnRzIHZlcnNpb25zIGxpc3Qgb3IgbGlzdCBvZiBvYmplY3RzIGJ5IHZlcnNpb24gcHJvcGVydHlcbiAgICogQHJldHVybnMgbGlzdCBvZiB2ZXJzaW9ucyBhcyBhcnJheSBvZiBzdHJpbmdzIG9yIGFycmF5IG9mIG9iamVjdHMgc29ydGVkIGJ5IHZlcnNpb24gcHJvcGVydHlcbiAgICpcbiAgICogQHBhcmFtIHt7IGxpc3Q6IFRbXTsgcGF0aDogc3RyaW5nW10gfSB8IHN0cmluZ1tdfSBzb3VyY2UgZGF0YSB0byBzb3J0XG4gICAqIEBwYXJhbSB7J2FzYycgfCAnZGVzYyd9IG9yZGVyIGFzY2VuZGluZyBvciBkZXNjZW5kaW5nIG9yZGVyIG9mIHNvcnRpbmdcbiAgICpcbiAgICogKipFeGFtcGxlKipcbiAgICogYGBgdHlwZXNjcmlwdFxuICAgKiBjb25zdCBkYXRhID0gWycxLjUuMCcsICcyLjAuMCddO1xuICAgKiBjb25zdCBzb3J0ZWREYXRhID0gcGx1Z2luc1NlcnZpY2Uuc29ydFZlcnNpb25zKHZlcnNpb25zLCAnZGVzYycpO1xuICAgKiAvLyBzb3J0ZWREYXRhOlxuICAgKiAvLyBbJzIuMC4wJywgJzEuNS4wJ11cbiAgICogYGBgXG4gICAqXG4gICAqICoqRXhhbXBsZSoqXG4gICAqIGBgYHR5cGVzY3JpcHRcbiAgICogY29uc3QgZGF0YSA9IFtcbiAgICogIHthcHA6IHthcHBWZXJzaW9uOiAnMS41LjAnfX0sXG4gICAqICB7YXBwOiB7YXBwVmVyc2lvbjogJzIuMC4wJ319LFxuICAgKiBdO1xuICAgKiBjb25zdCBzb3J0ZWREYXRhID0gcGx1Z2luc1NlcnZpY2Uuc29ydFZlcnNpb25zKHtsaXN0OiBkYXRhLCBwYXRoOiBbJ2FwcCcsICdhcHBWZXJzaW9uJ119LCAnZGVzYycpO1xuICAgKiAvLyBzb3J0ZWREYXRhOlxuICAgKiAvLyBbXG4gICAqIC8vICB7YXBwOiB7YXBwVmVyc2lvbjogJzIuMC4wJ319LFxuICAgKiAvLyAge2FwcDoge2FwcFZlcnNpb246ICcxLjUuMCd9fVxuICAgKiAvLyBdXG4gICAqIGBgYFxuICAgKi9cbiAgc29ydFZlcnNpb25zPFQ+KHNvdXJjZTogeyBsaXN0OiBUW107IHBhdGg6IHN0cmluZ1tdIH0sIG9yZGVyOiAnYXNjJyB8ICdkZXNjJyk6IFRbXTtcbiAgc29ydFZlcnNpb25zKHNvdXJjZTogc3RyaW5nW10sIG9yZGVyOiAnYXNjJyB8ICdkZXNjJyk6IHN0cmluZ1tdO1xuICBzb3J0VmVyc2lvbnMoc291cmNlOiBhbnksIG9yZGVyOiAnYXNjJyB8ICdkZXNj