UNPKG

@nova-ui/dashboards

Version:

Nova Dashboards is a framework designed to provide feature developers with a common solution for presenting data coming from various sources within a single view, as well as a set of predefined widget visualizations that are 100% configuration-driven and

306 lines 49.4 kB
import { Directive, EventEmitter, Injector, Input, Output, Renderer2, SimpleChange, } from "@angular/core"; import isArray from "lodash/isArray"; import values from "lodash/values"; import xor from "lodash/xor"; import { ReplaySubject, Subject } from "rxjs"; import { takeUntil } from "rxjs/operators"; import { LoggerService } from "@nova-ui/bits"; import { ProviderRegistryService } from "../../../services/provider-registry.service"; import { ComponentPortalService } from "../../services/component-portal.service"; import * as i0 from "@angular/core"; import * as i1 from "@nova-ui/bits"; import * as i2 from "../../services/component-portal.service"; import * as i3 from "../../../services/provider-registry.service"; export class ComponentPortalDirective { constructor(injector, logger, portalService, renderer, providerRegistry) { this.injector = injector; this.logger = logger; this.portalService = portalService; this.renderer = renderer; this.providerRegistry = providerRegistry; this.output = new EventEmitter(); this.propertiesChanges = new ReplaySubject(); this.providerInstances = {}; this.destroy$ = new Subject(); } ngOnInit() { this.logger.debug("Portal created:", this.componentId); this.recreatePortal(); } ngAfterViewInit() { Object.keys(this.providerInstances).forEach((key) => { const provider = this.providerInstances[key]; if (provider.ngAfterViewInit) { provider.ngAfterViewInit(); } }); } ngOnChanges(changes) { let recreated = false; const providersChange = changes.providers; if (providersChange && !providersChange.isFirstChange()) { if (this.checkForProviderChanges(providersChange)) { this.logger.debug("Portal recreated (provider change):", this.componentId); this.recreatePortal(); recreated = true; // we want to prevent multiple recreations within one ngOnChanges cycle } else { this.updateProviderConfigurations(providersChange); } } if (changes.componentType && !changes.componentType.isFirstChange() && !recreated) { this.logger.debug("Portal recreated (component change):", this.componentId); this.recreatePortal(); } if (changes.properties) { this.propertiesChanges.next(changes.properties); } } ngOnDestroy() { this.logger.debug("Portal destroyed:", this.componentId); this.destroyProviders(); this.listenerUnsubscriber?.(); this.destroy$.next(); this.destroy$.complete(); } attached(componentRef) { this.component = componentRef.instance; // ctrl+shift+click on a pizzagna to get a dump of its properties // this will propagate through the parent components, so it should dump the parent pizzagnas as well this.listenerUnsubscriber = this.renderer.listen(componentRef.location.nativeElement, "click", (event) => { // event.metaKey is a CMD key for Mac if ((event.ctrlKey || event.metaKey) && event.shiftKey && event.button === 0) { console.log("==================== PIZZAGNA DUMP ========================="); console.log("componentId:", this.componentId); console.log("component:", this.component); console.log("componentType:", this.componentType); console.log("properties:", this.properties); console.log("providers:", this.providers); console.log("providerInstances:", this.providerInstances); console.log("============================================================"); } }); for (const key of Object.keys(this.providerInstances)) { const provider = this.providerInstances[key]; if (provider.setComponent) { // setting componentId separately because "componentId" is used as another input, // at the moment of setting the component here, 'this.component' doesn't have 'componentId' property, // because 'changesSubscription' has not received any changes. it leads to the issue // when providers do not know the ID until component property changed provider.setComponent(this.component, this.componentId); } if (provider.setProviders) { provider.setProviders(this.providerInstances, this.componentId); } } this.subscribeToOutputs(); this.changesSubscription = this.propertiesChanges .pipe(takeUntil(this.destroy$)) .subscribe((change) => this.applyPropertiesChange(change)); } recreatePortal() { if (this.changesSubscription) { this.changesSubscription.unsubscribe(); this.changesSubscription = undefined; this.propertiesChanges = new ReplaySubject(); } let injector = this.injector; this.destroyProviders(); if (this.providers) { injector = this.updateProviders(injector); } this.portal = this.portalService.createComponentPortal(this.componentType, injector); // apply initial property values to the freshly (re)created component if (this.properties) { // eslint-disable-next-line @typescript-eslint/no-unused-vars for (const key of Object.keys(this.properties)) { this.propertiesChanges.next(new SimpleChange(undefined, this.properties, true)); } } } updateProviders(injector) { const providerKeys = Object.keys(this.providers); const registeredProviders = providerKeys.reduce((acc, next) => { // for cases when providerId is just empty string, null or undefined (for example adding a tile doesn't provide a DS to it) if (this.providers[next].providerId) { acc[next] = this.providerRegistry.getProvider(this.providers[next].providerId); } return acc; }, {}); const portalInjector = this.portalService.createInjector({ injector: injector, providers: values(registeredProviders), }); this.providerInstances = providerKeys.reduce((acc, next) => { const registeredProvider = registeredProviders[next]; const providerConfig = this.providers[next]; if (registeredProvider) { // TODO: Why do we pass null to the injectFlags parameter? // TODO: How to retrieve info about the provider options to inject?InjectOptions const injections = portalInjector.get(registeredProvider.provide, null); const providerInstance = isArray(injections) ? injections.find((v) => v instanceof registeredProvider.useClass) : injections; if (!providerInstance) { throw new Error("Provider '" + next + "' does not exist."); } if (providerInstance.updateConfiguration && providerConfig.properties) { providerInstance.updateConfiguration({ providerKey: next, ...(providerConfig.properties || {}), }); } providerInstance.providerKey = next; acc[next] = providerInstance; } else if (providerConfig.providerId) { this.logger.error("There's no registered provider for id", next); } return acc; }, this.providerInstances); for (const key of Object.keys(this.providerInstances)) { const pi = this.providerInstances[key]; if (pi.ngOnInit) { pi.ngOnInit(); } } return portalInjector; } updateProviderConfigurations(providersChange) { for (const providerKey of Object.keys(this.providers)) { // for cases when providerId is just empty string, null or undefined (for example adding a tile doesn't provide a DS to it) if (!this.providers[providerKey].providerId) { return; } const providerInstance = this.providerInstances[providerKey]; if (!providerInstance) { throw new Error("Provider '" + providerKey + "' does not exist."); } const previousValue = providersChange.previousValue[providerKey]; const currentValue = providersChange.currentValue[providerKey]; const previousProperties = previousValue && previousValue.properties; const currentProperties = currentValue && currentValue.properties; if (previousProperties !== currentProperties && providerInstance.updateConfiguration) { providerInstance.updateConfiguration({ providerKey, ...currentProperties, }); } } } subscribeToOutputs() { if (!this.outputs) { return; } for (const output of this.outputs.filter((o) => this.component[o] instanceof EventEmitter)) { this.component[output] .pipe(takeUntil(this.destroy$)) .subscribe(($event) => { this.output.emit({ id: output, payload: $event, }); }); } } checkForProviderChanges(change) { const previousKeys = change.previousValue ? Object.keys(change.previousValue) : []; const currentKeys = change.currentValue ? Object.keys(change.currentValue) : []; if (previousKeys.length !== currentKeys.length || xor(previousKeys, currentKeys).length > 0) { return true; } const previousIds = Object.keys(change.previousValue).map((key) => change.previousValue[key].providerId); const currentIds = Object.keys(change.currentValue).map((key) => change.currentValue[key].providerId); if (xor(previousIds, currentIds).length > 0) { return true; } return false; } destroyProviders() { if (this.providerInstances) { for (const piKey of Object.keys(this.providerInstances)) { const providerInstance = this.providerInstances[piKey]; if (providerInstance.ngOnDestroy) { providerInstance.ngOnDestroy(); } delete this.providerInstances[piKey]; } } } /** * There was a change in component properties, so we need to handle that here * * @param change a change of the `properties` input */ applyPropertiesChange(change) { let properties = change.currentValue; if (!properties) { return; } // we add componentId to the mix, so components will be able to use it properties = { ...properties, componentId: this.componentId, }; const changes = {}; let changeHappened = false; for (const key of Object.keys(properties)) { const previousValue = this.component[key]; // reference based change detection in action here! if (properties[key] !== previousValue) { changeHappened = true; this.component[key] = properties[key]; // we're simulating angular by calling ngOnChanges manually if (this.component.ngOnChanges) { changes[key] = new SimpleChange(previousValue, properties[key], change.isFirstChange()); } } } if (changeHappened) { if (this.component.ngOnChanges) { this.component.ngOnChanges(changes); } const changeDetector = this.component.changeDetector; if (changeDetector) { changeDetector.markForCheck(); } else { this.logger.warn(`Property 'changeDetector' is missing on component '${this.componentType}',` + ` so dynamic refresh of given component might not work.`); } } } /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ComponentPortalDirective, deps: [{ token: i0.Injector }, { token: i1.LoggerService }, { token: i2.ComponentPortalService }, { token: i0.Renderer2 }, { token: i3.ProviderRegistryService }], target: i0.ɵɵFactoryTarget.Directive }); } /** @nocollapse */ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: ComponentPortalDirective, selector: "[nuiComponentPortal]", inputs: { componentId: "componentId", componentType: "componentType", properties: "properties", providers: "providers", outputs: "outputs" }, outputs: { output: "output" }, exportAs: ["nuiComponentPortal"], usesOnChanges: true, ngImport: i0 }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ComponentPortalDirective, decorators: [{ type: Directive, args: [{ selector: "[nuiComponentPortal]", exportAs: "nuiComponentPortal", }] }], ctorParameters: () => [{ type: i0.Injector }, { type: i1.LoggerService }, { type: i2.ComponentPortalService }, { type: i0.Renderer2 }, { type: i3.ProviderRegistryService }], propDecorators: { componentId: [{ type: Input }], componentType: [{ type: Input }], properties: [{ type: Input }], providers: [{ type: Input }], outputs: [{ type: Input }], output: [{ type: Output }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29tcG9uZW50LXBvcnRhbC5kaXJlY3RpdmUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvbGliL3BpenphZ25hL2RpcmVjdGl2ZXMvY29tcG9uZW50LXBvcnRhbC9jb21wb25lbnQtcG9ydGFsLmRpcmVjdGl2ZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFxQkEsT0FBTyxFQUdILFNBQVMsRUFDVCxZQUFZLEVBQ1osUUFBUSxFQUNSLEtBQUssRUFJTCxNQUFNLEVBQ04sU0FBUyxFQUNULFlBQVksR0FHZixNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLE9BQU8sTUFBTSxnQkFBZ0IsQ0FBQztBQUNyQyxPQUFPLE1BQU0sTUFBTSxlQUFlLENBQUM7QUFDbkMsT0FBTyxHQUFHLE1BQU0sWUFBWSxDQUFDO0FBQzdCLE9BQU8sRUFBRSxhQUFhLEVBQUUsT0FBTyxFQUFnQixNQUFNLE1BQU0sQ0FBQztBQUM1RCxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFFM0MsT0FBTyxFQUFVLGFBQWEsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUV0RCxPQUFPLEVBQUUsdUJBQXVCLEVBQUUsTUFBTSw2Q0FBNkMsQ0FBQztBQUV0RixPQUFPLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSx5Q0FBeUMsQ0FBQzs7Ozs7QUFNakYsTUFBTSxPQUFPLHdCQUF3QjtJQW1CakMsWUFDWSxRQUFrQixFQUNsQixNQUFxQixFQUNyQixhQUFxQyxFQUNyQyxRQUFtQixFQUNuQixnQkFBeUM7UUFKekMsYUFBUSxHQUFSLFFBQVEsQ0FBVTtRQUNsQixXQUFNLEdBQU4sTUFBTSxDQUFlO1FBQ3JCLGtCQUFhLEdBQWIsYUFBYSxDQUF3QjtRQUNyQyxhQUFRLEdBQVIsUUFBUSxDQUFXO1FBQ25CLHFCQUFnQixHQUFoQixnQkFBZ0IsQ0FBeUI7UUFmcEMsV0FBTSxHQUFHLElBQUksWUFBWSxFQUFVLENBQUM7UUFJN0Msc0JBQWlCLEdBQUcsSUFBSSxhQUFhLEVBQWdCLENBQUM7UUFDdEQsc0JBQWlCLEdBQXdCLEVBQUUsQ0FBQztRQUNuQyxhQUFRLEdBQUcsSUFBSSxPQUFPLEVBQVEsQ0FBQztJQVU3QyxDQUFDO0lBRUcsUUFBUTtRQUNYLElBQUksQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLGlCQUFpQixFQUFFLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQztRQUN2RCxJQUFJLENBQUMsY0FBYyxFQUFFLENBQUM7SUFDMUIsQ0FBQztJQUVNLGVBQWU7UUFDbEIsTUFBTSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsaUJBQWlCLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxHQUFHLEVBQUUsRUFBRTtZQUNoRCxNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsaUJBQWlCLENBQUMsR0FBRyxDQUFDLENBQUM7WUFDN0MsSUFBSSxRQUFRLENBQUMsZUFBZSxFQUFFO2dCQUMxQixRQUFRLENBQUMsZUFBZSxFQUFFLENBQUM7YUFDOUI7UUFDTCxDQUFDLENBQUMsQ0FBQztJQUNQLENBQUM7SUFFTSxXQUFXLENBQUMsT0FBc0I7UUFDckMsSUFBSSxTQUFTLEdBQUcsS0FBSyxDQUFDO1FBQ3RCLE1BQU0sZUFBZSxHQUFHLE9BQU8sQ0FBQyxTQUFTLENBQUM7UUFFMUMsSUFBSSxlQUFlLElBQUksQ0FBQyxlQUFlLENBQUMsYUFBYSxFQUFFLEVBQUU7WUFDckQsSUFBSSxJQUFJLENBQUMsdUJBQXVCLENBQUMsZUFBZSxDQUFDLEVBQUU7Z0JBQy9DLElBQUksQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUNiLHFDQUFxQyxFQUNyQyxJQUFJLENBQUMsV0FBVyxDQUNuQixDQUFDO2dCQUNGLElBQUksQ0FBQyxjQUFjLEVBQUUsQ0FBQztnQkFDdEIsU0FBUyxHQUFHLElBQUksQ0FBQyxDQUFDLHVFQUF1RTthQUM1RjtpQkFBTTtnQkFDSCxJQUFJLENBQUMsNEJBQTRCLENBQUMsZUFBZSxDQUFDLENBQUM7YUFDdEQ7U0FDSjtRQUVELElBQ0ksT0FBTyxDQUFDLGFBQWE7WUFDckIsQ0FBQyxPQUFPLENBQUMsYUFBYSxDQUFDLGFBQWEsRUFBRTtZQUN0QyxDQUFDLFNBQVMsRUFDWjtZQUNFLElBQUksQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUNiLHNDQUFzQyxFQUN0QyxJQUFJLENBQUMsV0FBVyxDQUNuQixDQUFDO1lBQ0YsSUFBSSxDQUFDLGNBQWMsRUFBRSxDQUFDO1NBQ3pCO1FBRUQsSUFBSSxPQUFPLENBQUMsVUFBVSxFQUFFO1lBQ3BCLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLFVBQVUsQ0FBQyxDQUFDO1NBQ25EO0lBQ0wsQ0FBQztJQUVNLFdBQVc7UUFDZCxJQUFJLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxtQkFBbUIsRUFBRSxJQUFJLENBQUMsV0FBVyxDQUFDLENBQUM7UUFFekQsSUFBSSxDQUFDLGdCQUFnQixFQUFFLENBQUM7UUFDeEIsSUFBSSxDQUFDLG9CQUFvQixFQUFFLEVBQUUsQ0FBQztRQUU5QixJQUFJLENBQUMsUUFBUSxDQUFDLElBQUksRUFBRSxDQUFDO1FBQ3JCLElBQUksQ0FBQyxRQUFRLENBQUMsUUFBUSxFQUFFLENBQUM7SUFDN0IsQ0FBQztJQUVNLFFBQVEsQ0FBQyxZQUErQjtRQUMzQyxJQUFJLENBQUMsU0FBUyxHQUFHLFlBQVksQ0FBQyxRQUFRLENBQUM7UUFFdkMsaUVBQWlFO1FBQ2pFLG9HQUFvRztRQUNwRyxJQUFJLENBQUMsb0JBQW9CLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQzVDLFlBQVksQ0FBQyxRQUFRLENBQUMsYUFBYSxFQUNuQyxPQUFPLEVBQ1AsQ0FBQyxLQUFpQixFQUFFLEVBQUU7WUFDbEIscUNBQXFDO1lBQ3JDLElBQ0ksQ0FBQyxLQUFLLENBQUMsT0FBTyxJQUFJLEtBQUssQ0FBQyxPQUFPLENBQUM7Z0JBQ2hDLEtBQUssQ0FBQyxRQUFRO2dCQUNkLEtBQUssQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUNwQjtnQkFDRSxPQUFPLENBQUMsR0FBRyxDQUNQLDhEQUE4RCxDQUNqRSxDQUFDO2dCQUNGLE9BQU8sQ0FBQyxHQUFHLENBQUMsY0FBYyxFQUFFLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQztnQkFDOUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxZQUFZLEVBQUUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDO2dCQUMxQyxPQUFPLENBQUMsR0FBRyxDQUFDLGdCQUFnQixFQUFFLElBQUksQ0FBQyxhQUFhLENBQUMsQ0FBQztnQkFDbEQsT0FBTyxDQUFDLEdBQUcsQ0FBQyxhQUFhLEVBQUUsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFDO2dCQUM1QyxPQUFPLENBQUMsR0FBRyxDQUFDLFlBQVksRUFBRSxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUM7Z0JBQzFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsb0JBQW9CLEVBQUUsSUFBSSxDQUFDLGlCQUFpQixDQUFDLENBQUM7Z0JBQzFELE9BQU8sQ0FBQyxHQUFHLENBQ1AsOERBQThELENBQ2pFLENBQUM7YUFDTDtRQUNMLENBQUMsQ0FDSixDQUFDO1FBRUYsS0FBSyxNQUFNLEdBQUcsSUFBSSxNQUFNLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxFQUFFO1lBQ25ELE1BQU0sUUFBUSxHQUFHLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxHQUFHLENBQUMsQ0FBQztZQUM3QyxJQUFJLFFBQVEsQ0FBQyxZQUFZLEVBQUU7Z0JBQ3ZCLGlGQUFpRjtnQkFDakYscUdBQXFHO2dCQUNyRyxvRkFBb0Y7Z0JBQ3BGLHFFQUFxRTtnQkFDckUsUUFBUSxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQzthQUMzRDtZQUNELElBQUksUUFBUSxDQUFDLFlBQVksRUFBRTtnQkFDdkIsUUFBUSxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsaUJBQWlCLEVBQUUsSUFBSSxDQUFDLFdBQVcsQ0FBQyxDQUFDO2FBQ25FO1NBQ0o7UUFFRCxJQUFJLENBQUMsa0JBQWtCLEVBQUUsQ0FBQztRQUUxQixJQUFJLENBQUMsbUJBQW1CLEdBQUcsSUFBSSxDQUFDLGlCQUFpQjthQUM1QyxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQzthQUM5QixTQUFTLENBQUMsQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDO0lBQ25FLENBQUM7SUFFTyxjQUFjO1FBQ2xCLElBQUksSUFBSSxDQUFDLG1CQUFtQixFQUFFO1lBQzFCLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxXQUFXLEVBQUUsQ0FBQztZQUN2QyxJQUFJLENBQUMsbUJBQW1CLEdBQUcsU0FBUyxDQUFDO1lBQ3JDLElBQUksQ0FBQyxpQkFBaUIsR0FBRyxJQUFJLGFBQWEsRUFBZ0IsQ0FBQztTQUM5RDtRQUVELElBQUksUUFBUSxHQUFHLElBQUksQ0FBQyxRQUFRLENBQUM7UUFFN0IsSUFBSSxDQUFDLGdCQUFnQixFQUFFLENBQUM7UUFFeEIsSUFBSSxJQUFJLENBQUMsU0FBUyxFQUFFO1lBQ2hCLFFBQVEsR0FBRyxJQUFJLENBQUMsZUFBZSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1NBQzdDO1FBRUQsSUFBSSxDQUFDLE1BQU0sR0FBRyxJQUFJLENBQUMsYUFBYSxDQUFDLHFCQUFxQixDQUNsRCxJQUFJLENBQUMsYUFBYSxFQUNsQixRQUFRLENBQ1gsQ0FBQztRQUVGLHFFQUFxRTtRQUNyRSxJQUFJLElBQUksQ0FBQyxVQUFVLEVBQUU7WUFDakIsNkRBQTZEO1lBQzdELEtBQUssTUFBTSxHQUFHLElBQUksTUFBTSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLEVBQUU7Z0JBQzVDLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxJQUFJLENBQ3ZCLElBQUksWUFBWSxDQUFDLFNBQVMsRUFBRSxJQUFJLENBQUMsVUFBVSxFQUFFLElBQUksQ0FBQyxDQUNyRCxDQUFDO2FBQ0w7U0FDSjtJQUNMLENBQUM7SUFFTyxlQUFlLENBQUMsUUFBa0I7UUFDdEMsTUFBTSxZQUFZLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUM7UUFDakQsTUFBTSxtQkFBbUIsR0FBRyxZQUFZLENBQUMsTUFBTSxDQUFDLENBQUMsR0FBRyxFQUFFLElBQUksRUFBRSxFQUFFO1lBQzFELDJIQUEySDtZQUMzSCxJQUFJLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLENBQUMsVUFBVSxFQUFFO2dCQUNqQyxHQUFHLENBQUMsSUFBSSxDQUFDLEdBQUcsSUFBSSxDQUFDLGdCQUFnQixDQUFDLFdBQVcsQ0FDekMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxVQUFVLENBQ2xDLENBQUM7YUFDTDtZQUNELE9BQU8sR0FBRyxDQUFDO1FBQ2YsQ0FBQyxFQUFFLEVBQW9DLENBQUMsQ0FBQztRQUV6QyxNQUFNLGNBQWMsR0FBRyxJQUFJLENBQUMsYUFBYSxDQUFDLGNBQWMsQ0FBQztZQUNyRCxRQUFRLEVBQUUsUUFBUTtZQUNsQixTQUFTLEVBQUUsTUFBTSxDQUFDLG1CQUFtQixDQUFDO1NBQ3pDLENBQUMsQ0FBQztRQUVILElBQUksQ0FBQyxpQkFBaUIsR0FBRyxZQUFZLENBQUMsTUFBTSxDQUFDLENBQUMsR0FBRyxFQUFFLElBQUksRUFBRSxFQUFFO1lBQ3ZELE1BQU0sa0JBQWtCLEdBQUcsbUJBQW1CLENBQUMsSUFBSSxDQUFRLENBQUM7WUFDNUQsTUFBTSxjQUFjLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsQ0FBQztZQUM1QyxJQUFJLGtCQUFrQixFQUFFO2dCQUNwQiwwREFBMEQ7Z0JBQzFELGdGQUFnRjtnQkFDaEYsTUFBTSxVQUFVLEdBQUcsY0FBYyxDQUFDLEdBQUcsQ0FDakMsa0JBQWtCLENBQUMsT0FBTyxFQUMxQixJQUFJLENBQ1AsQ0FBQztnQkFDRixNQUFNLGdCQUFnQixHQUFHLE9BQU8sQ0FBQyxVQUFVLENBQUM7b0JBQ3hDLENBQUMsQ0FBRSxVQUFrQixDQUFDLElBQUksQ0FDcEIsQ0FBQyxDQUFNLEVBQUUsRUFBRSxDQUFDLENBQUMsWUFBWSxrQkFBa0IsQ0FBQyxRQUFRLENBQ3ZEO29CQUNILENBQUMsQ0FBQyxVQUFVLENBQUM7Z0JBRWpCLElBQUksQ0FBQyxnQkFBZ0IsRUFBRTtvQkFDbkIsTUFBTSxJQUFJLEtBQUssQ0FBQyxZQUFZLEdBQUcsSUFBSSxHQUFHLG1CQUFtQixDQUFDLENBQUM7aUJBQzlEO2dCQUNELElBQ0ksZ0JBQWdCLENBQUMsbUJBQW1CO29CQUNwQyxjQUFjLENBQUMsVUFBVSxFQUMzQjtvQkFDRSxnQkFBZ0IsQ0FBQyxtQkFBbUIsQ0FBQzt3QkFDakMsV0FBVyxFQUFFLElBQUk7d0JBQ2pCLEdBQUcsQ0FBQyxjQUFjLENBQUMsVUFBVSxJQUFJLEVBQUUsQ0FBQztxQkFDdkMsQ0FBQyxDQUFDO2lCQUNOO2dCQUNELGdCQUFnQixDQUFDLFdBQVcsR0FBRyxJQUFJLENBQUM7Z0JBRXBDLEdBQUcsQ0FBQyxJQUFJLENBQUMsR0FBRyxnQkFBZ0IsQ0FBQzthQUNoQztpQkFBTSxJQUFJLGNBQWMsQ0FBQyxVQUFVLEVBQUU7Z0JBQ2xDLElBQUksQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUNiLHVDQUF1QyxFQUN2QyxJQUFJLENBQ1AsQ0FBQzthQUNMO1lBQ0QsT0FBTyxHQUFHLENBQUM7UUFDZixDQUFDLEVBQUUsSUFBSSxDQUFDLGlCQUFpQixDQUFDLENBQUM7UUFFM0IsS0FBSyxNQUFNLEdBQUcsSUFBSSxNQUFNLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxFQUFFO1lBQ25ELE1BQU0sRUFBRSxHQUFHLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxHQUFHLENBQUMsQ0FBQztZQUN2QyxJQUFJLEVBQUUsQ0FBQyxRQUFRLEVBQUU7Z0JBQ2IsRUFBRSxDQUFDLFFBQVEsRUFBRSxDQUFDO2FBQ2pCO1NBQ0o7UUFFRCxPQUFPLGNBQWMsQ0FBQztJQUMxQixDQUFDO0lBRU8sNEJBQTRCLENBQUMsZUFBNkI7UUFDOUQsS0FBSyxNQUFNLFdBQVcsSUFBSSxNQUFNLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsRUFBRTtZQUNuRCwySEFBMkg7WUFDM0gsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsV0FBVyxDQUFDLENBQUMsVUFBVSxFQUFFO2dCQUN6QyxPQUFPO2FBQ1Y7WUFDRCxNQUFNLGdCQUFnQixHQUFHLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxXQUFXLENBQUMsQ0FBQztZQUM3RCxJQUFJLENBQUMsZ0JBQWdCLEVBQUU7Z0JBQ25CLE1BQU0sSUFBSSxLQUFLLENBQ1gsWUFBWSxHQUFHLFdBQVcsR0FBRyxtQkFBbUIsQ0FDbkQsQ0FBQzthQUNMO1lBRUQsTUFBTSxhQUFhLEdBQUcsZUFBZSxDQUFDLGFBQWEsQ0FBQyxXQUFXLENBQUMsQ0FBQztZQUNqRSxNQUFNLFlBQVksR0FBRyxlQUFlLENBQUMsWUFBWSxDQUFDLFdBQVcsQ0FBQyxDQUFDO1lBRS9ELE1BQU0sa0JBQWtCLEdBQ3BCLGFBQWEsSUFBSSxhQUFhLENBQUMsVUFBVSxDQUFDO1lBQzlDLE1BQU0saUJBQWlCLEdBQUcsWUFBWSxJQUFJLFlBQVksQ0FBQyxVQUFVLENBQUM7WUFFbEUsSUFDSSxrQkFBa0IsS0FBSyxpQkFBaUI7Z0JBQ3hDLGdCQUFnQixDQUFDLG1CQUFtQixFQUN0QztnQkFDRyxnQkFBa0MsQ0FBQyxtQkFBbUIsQ0FBQztvQkFDcEQsV0FBVztvQkFDWCxHQUFHLGlCQUFpQjtpQkFDdkIsQ0FBQyxDQUFDO2FBQ047U0FDSjtJQUNMLENBQUM7SUFFTyxrQkFBa0I7UUFDdEIsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUU7WUFDZixPQUFPO1NBQ1Y7UUFFRCxLQUFLLE1BQU0sTUFBTSxJQUFJLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUNwQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsWUFBWSxZQUFZLENBQ25ELEVBQUU7WUFDQyxJQUFJLENBQUMsU0FBUyxDQUFDLE1BQU0sQ0FBQztpQkFDakIsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUM7aUJBQzlCLFNBQVMsQ0FBQyxDQUFDLE1BQVcsRUFBRSxFQUFFO2dCQUN2QixJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQztvQkFDYixFQUFFLEVBQUUsTUFBTTtvQkFDVixPQUFPLEVBQUUsTUFBTTtpQkFDbEIsQ0FBQyxDQUFDO1lBQ1AsQ0FBQyxDQUFDLENBQUM7U0FDVjtJQUNMLENBQUM7SUFFTyx1QkFBdUIsQ0FBQyxNQUFvQjtRQUNoRCxNQUFNLFlBQVksR0FBRyxNQUFNLENBQUMsYUFBYTtZQUNyQyxDQUFDLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsYUFBYSxDQUFDO1lBQ25DLENBQUMsQ0FBQyxFQUFFLENBQUM7UUFDVCxNQUFNLFdBQVcsR0FBRyxNQUFNLENBQUMsWUFBWTtZQUNuQyxDQUFDLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsWUFBWSxDQUFDO1lBQ2xDLENBQUMsQ0FBQyxFQUFFLENBQUM7UUFDVCxJQUNJLFlBQVksQ0FBQyxNQUFNLEtBQUssV0FBVyxDQUFDLE1BQU07WUFDMUMsR0FBRyxDQUFDLFlBQVksRUFBRSxXQUFXLENBQUMsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUMzQztZQUNFLE9BQU8sSUFBSSxDQUFDO1NBQ2Y7UUFFRCxNQUFNLFdBQVcsR0FBRyxNQUFNLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxhQUFhLENBQUMsQ0FBQyxHQUFHLENBQ3JELENBQUMsR0FBVyxFQUFFLEVBQUUsQ0FBQyxNQUFNLENBQUMsYUFBYSxDQUFDLEdBQUcsQ0FBQyxDQUFDLFVBQVUsQ0FDeEQsQ0FBQztRQUNGLE1BQU0sVUFBVSxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLFlBQVksQ0FBQyxDQUFDLEdBQUcsQ0FDbkQsQ0FBQyxHQUFXLEVBQUUsRUFBRSxDQUFDLE1BQU0sQ0FBQyxZQUFZLENBQUMsR0FBRyxDQUFDLENBQUMsVUFBVSxDQUN2RCxDQUFDO1FBQ0YsSUFBSSxHQUFHLENBQUMsV0FBVyxFQUFFLFVBQVUsQ0FBQyxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUU7WUFDekMsT0FBTyxJQUFJLENBQUM7U0FDZjtRQUVELE9BQU8sS0FBSyxDQUFDO0lBQ2pCLENBQUM7SUFFTyxnQkFBZ0I7UUFDcEIsSUFBSSxJQUFJLENBQUMsaUJBQWlCLEVBQUU7WUFDeEIsS0FBSyxNQUFNLEtBQUssSUFBSSxNQUFNLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxFQUFFO2dCQUNyRCxNQUFNLGdCQUFnQixHQUFHLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxLQUFLLENBQUMsQ0FBQztnQkFDdkQsSUFBSSxnQkFBZ0IsQ0FBQyxXQUFXLEVBQUU7b0JBQzlCLGdCQUFnQixDQUFDLFdBQVcsRUFBRSxDQUFDO2lCQUNsQztnQkFDRCxPQUFPLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxLQUFLLENBQUMsQ0FBQzthQUN4QztTQUNKO0lBQ0wsQ0FBQztJQUVEOzs7O09BSUc7SUFDSyxxQkFBcUIsQ0FBQyxNQUFvQjtRQUM5QyxJQUFJLFVBQVUsR0FBRyxNQUFNLENBQUMsWUFBWSxDQUFDO1FBQ3JDLElBQUksQ0FBQyxVQUFVLEVBQUU7WUFDYixPQUFPO1NBQ1Y7UUFFRCxzRUFBc0U7UUFDdEUsVUFBVSxHQUFHO1lBQ1QsR0FBRyxVQUFVO1lBQ2IsV0FBVyxFQUFFLElBQUksQ0FBQyxXQUFXO1NBQ2hDLENBQUM7UUFFRixNQUFNLE9BQU8sR0FBa0IsRUFBRSxDQUFDO1FBQ2xDLElBQUksY0FBYyxHQUFHLEtBQUssQ0FBQztRQUMzQixLQUFLLE1BQU0sR0FBRyxJQUFJLE1BQU0sQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLEVBQUU7WUFDdkMsTUFBTSxhQUFhLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxHQUFHLENBQUMsQ0FBQztZQUUxQyxtREFBbUQ7WUFDbkQsSUFBSSxVQUFVLENBQUMsR0FBRyxDQUFDLEtBQUssYUFBYSxFQUFFO2dCQUNuQyxjQUFjLEdBQUcsSUFBSSxDQUFDO2dCQUN0QixJQUFJLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxHQUFHLFVBQVUsQ0FBQyxHQUFHLENBQUMsQ0FBQztnQkFDdEMsMkRBQTJEO2dCQUMzRCxJQUFJLElBQUksQ0FBQyxTQUFTLENBQUMsV0FBVyxFQUFFO29CQUM1QixPQUFPLENBQUMsR0FBRyxDQUFDLEdBQUcsSUFBSSxZQUFZLENBQzNCLGFBQWEsRUFDYixVQUFVLENBQUMsR0FBRyxDQUFDLEVBQ2YsTUFBTSxDQUFDLGFBQWEsRUFBRSxDQUN6QixDQUFDO2lCQUNMO2FBQ0o7U0FDSjtRQUVELElBQUksY0FBYyxFQUFFO1lBQ2hCLElBQUksSUFBSSxDQUFDLFNBQVMsQ0FBQyxXQUFXLEVBQUU7Z0JBQzVCLElBQUksQ0FBQyxTQUFTLENBQUMsV0FBVyxDQUFDLE9BQU8sQ0FBQyxDQUFDO2FBQ3ZDO1lBQ0QsTUFBTSxjQUFjLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxjQUFjLENBQUM7WUFDckQsSUFBSSxjQUFjLEVBQUU7Z0JBQ2hCLGNBQWMsQ0FBQyxZQUFZLEVBQUUsQ0FBQzthQUNqQztpQkFBTTtnQkFDSCxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FDWixzREFBc0QsSUFBSSxDQUFDLGFBQWEsSUFBSTtvQkFDeEUsd0RBQXdELENBQy9ELENBQUM7YUFDTDtTQUNKO0lBQ0wsQ0FBQztrSUF4WFEsd0JBQXdCO3NIQUF4Qix3QkFBd0I7OzRGQUF4Qix3QkFBd0I7a0JBSnBDLFNBQVM7bUJBQUM7b0JBQ1AsUUFBUSxFQUFFLHNCQUFzQjtvQkFDaEMsUUFBUSxFQUFFLG9CQUFvQjtpQkFDakM7NE1BSW1CLFdBQVc7c0JBQTFCLEtBQUs7Z0JBQ1UsYUFBYTtzQkFBNUIsS0FBSztnQkFDVSxVQUFVO3NCQUF6QixLQUFLO2dCQUNVLFNBQVM7c0JBQXhCLEtBQUs7Z0JBQ1UsT0FBTztzQkFBdEIsS0FBSztnQkFFVyxNQUFNO3NCQUF0QixNQUFNIiwic291cmNlc0NvbnRlbnQiOlsiLy8gwqkgMjAyMiBTb2xhcldpbmRzIFdvcmxkd2lkZSwgTExDLiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuLy9cbi8vIFBlcm1pc3Npb24gaXMgaGVyZWJ5IGdyYW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkgcGVyc29uIG9idGFpbmluZyBhIGNvcHlcbi8vICBvZiB0aGlzIHNvZnR3YXJlIGFuZCBhc3NvY2lhdGVkIGRvY3VtZW50YXRpb24gZmlsZXMgKHRoZSBcIlNvZnR3YXJlXCIpLCB0b1xuLy8gIGRlYWwgaW4gdGhlIFNvZnR3YXJlIHdpdGhvdXQgcmVzdHJpY3Rpb24sIGluY2x1ZGluZyB3aXRob3V0IGxpbWl0YXRpb24gdGhlXG4vLyAgcmlnaHRzIHRvIHVzZSwgY29weSwgbW9kaWZ5LCBtZXJnZSwgcHVibGlzaCwgZGlzdHJpYnV0ZSwgc3VibGljZW5zZSwgYW5kL29yXG4vLyAgc2VsbCBjb3BpZXMgb2YgdGhlIFNvZnR3YXJlLCBhbmQgdG8gcGVybWl0IHBlcnNvbnMgdG8gd2hvbSB0aGUgU29mdHdhcmUgaXNcbi8vICBmdXJuaXNoZWQgdG8gZG8gc28sIHN1YmplY3QgdG8gdGhlIGZvbGxvd2luZyBjb25kaXRpb25zOlxuLy9cbi8vIFRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlIGFuZCB0aGlzIHBlcm1pc3Npb24gbm90aWNlIHNoYWxsIGJlIGluY2x1ZGVkIGluXG4vLyAgYWxsIGNvcGllcyBvciBzdWJzdGFudGlhbCBwb3J0aW9ucyBvZiB0aGUgU29mdHdhcmUuXG4vL1xuLy8gVEhFIFNPRlRXQVJFIElTIFBST1ZJREVEIFwiQVMgSVNcIiwgV0lUSE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCwgRVhQUkVTUyBPUlxuLy8gIElNUExJRUQsIElOQ0xVRElORyBCVVQgTk9UIExJTUlURUQgVE8gVEhFIFdBUlJBTlRJRVMgT0YgTUVSQ0hBTlRBQklMSVRZLFxuLy8gIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFIEFORCBOT05JTkZSSU5HRU1FTlQuIElOIE5PIEVWRU5UIFNIQUxMIFRIRVxuLy8gIEFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERFUlMgQkUgTElBQkxFIEZPUiBBTlkgQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVJcbi8vICBMSUFCSUxJVFksIFdIRVRIRVIgSU4gQU4gQUNUSU9OIE9GIENPTlRSQUNULCBUT1JUIE9SIE9USEVSV0lTRSwgQVJJU0lORyBGUk9NLFxuLy8gIE9VVCBPRiBPUiBJTiBDT05ORUNUSU9OIFdJVEggVEhFIFNPRlRXQVJFIE9SIFRIRSBVU0UgT1IgT1RIRVIgREVBTElOR1MgSU5cbi8vICBUSEUgU09GVFdBUkUuXG5cbmltcG9ydCB7IFBvcnRhbCB9IGZyb20gXCJAYW5ndWxhci9jZGsvcG9ydGFsXCI7XG5pbXBvcnQge1xuICAgIEFmdGVyVmlld0luaXQsXG4gICAgQ29tcG9uZW50UmVmLFxuICAgIERpcmVjdGl2ZSxcbiAgICBFdmVudEVtaXR0ZXIsXG4gICAgSW5qZWN0b3IsXG4gICAgSW5wdXQsXG4gICAgT25DaGFuZ2VzLFxuICAgIE9uRGVzdHJveSxcbiAgICBPbkluaXQsXG4gICAgT3V0cHV0LFxuICAgIFJlbmRlcmVyMixcbiAgICBTaW1wbGVDaGFuZ2UsXG4gICAgU2ltcGxlQ2hhbmdlcyxcbiAgICBTdGF0aWNQcm92aWRlcixcbn0gZnJvbSBcIkBhbmd1bGFyL2NvcmVcIjtcbmltcG9ydCBpc0FycmF5IGZyb20gXCJsb2Rhc2gvaXNBcnJheVwiO1xuaW1wb3J0IHZhbHVlcyBmcm9tIFwibG9kYXNoL3ZhbHVlc1wiO1xuaW1wb3J0IHhvciBmcm9tIFwibG9kYXNoL3hvclwiO1xuaW1wb3J0IHsgUmVwbGF5U3ViamVjdCwgU3ViamVjdCwgU3Vic2NyaXB0aW9uIH0gZnJvbSBcInJ4anNcIjtcbmltcG9ydCB7IHRha2VVbnRpbCB9IGZyb20gXCJyeGpzL29wZXJhdG9yc1wiO1xuXG5pbXBvcnQgeyBJRXZlbnQsIExvZ2dlclNlcnZpY2UgfSBmcm9tIFwiQG5vdmEtdWkvYml0c1wiO1xuXG5pbXBvcnQgeyBQcm92aWRlclJlZ2lzdHJ5U2VydmljZSB9IGZyb20gXCIuLi8uLi8uLi9zZXJ2aWNlcy9wcm92aWRlci1yZWdpc3RyeS5zZXJ2aWNlXCI7XG5pbXBvcnQgeyBJQ29uZmlndXJhYmxlLCBJUHJvdmlkZXJDb25maWd1cmF0aW9uIH0gZnJvbSBcIi4uLy4uLy4uL3R5cGVzXCI7XG5pbXBvcnQgeyBDb21wb25lbnRQb3J0YWxTZXJ2aWNlIH0gZnJvbSBcIi4uLy4uL3NlcnZpY2VzL2NvbXBvbmVudC1wb3J0YWwuc2VydmljZVwiO1xuXG5ARGlyZWN0aXZlKHtcbiAgICBzZWxlY3RvcjogXCJbbnVpQ29tcG9uZW50UG9ydGFsXVwiLFxuICAgIGV4cG9ydEFzOiBcIm51aUNvbXBvbmVudFBvcnRhbFwiLFxufSlcbmV4cG9ydCBjbGFzcyBDb21wb25lbnRQb3J0YWxEaXJlY3RpdmVcbiAgICBpbXBsZW1lbnRzIE9uSW5pdCwgQWZ0ZXJWaWV3SW5pdCwgT25EZXN0cm95LCBPbkNoYW5nZXNcbntcbiAgICBASW5wdXQoKSBwdWJsaWMgY29tcG9uZW50SWQ6IHN0cmluZztcbiAgICBASW5wdXQoKSBwdWJsaWMgY29tcG9uZW50VHlwZTogc3RyaW5nIHwgRnVuY3Rpb247XG4gICAgQElucHV0KCkgcHVibGljIHByb3BlcnRpZXM6IFJlY29yZDxzdHJpbmcsIGFueT47XG4gICAgQElucHV0KCkgcHVibGljIHByb3ZpZGVyczogUmVjb3JkPHN0cmluZywgSVByb3ZpZGVyQ29uZmlndXJhdGlvbj47XG4gICAgQElucHV0KCkgcHVibGljIG91dHB1dHM6IHN0cmluZ1tdO1xuXG4gICAgQE91dHB1dCgpIHB1YmxpYyBvdXRwdXQgPSBuZXcgRXZlbnRFbWl0dGVyPElFdmVudD4oKTtcblxuICAgIHB1YmxpYyBwb3J0YWw6IFBvcnRhbDxhbnk+O1xuICAgIHByaXZhdGUgY29tcG9uZW50OiBhbnk7XG4gICAgcHJpdmF0ZSBwcm9wZXJ0aWVzQ2hhbmdlcyA9IG5ldyBSZXBsYXlTdWJqZWN0PFNpbXBsZUNoYW5nZT4oKTtcbiAgICBwcml2YXRlIHByb3ZpZGVySW5zdGFuY2VzOiBSZWNvcmQ8c3RyaW5nLCBhbnk+ID0ge307XG4gICAgcHJpdmF0ZSByZWFkb25seSBkZXN0cm95JCA9IG5ldyBTdWJqZWN0PHZvaWQ+KCk7XG4gICAgcHJpdmF0ZSBjaGFuZ2VzU3Vic2NyaXB0aW9uPzogU3Vic2NyaXB0aW9uO1xuICAgIHByaXZhdGUgbGlzdGVuZXJVbnN1YnNjcmliZXI/OiAoKSA9PiB2b2lkO1xuXG4gICAgY29uc3RydWN0b3IoXG4gICAgICAgIHByaXZhdGUgaW5qZWN0b3I6IEluamVjdG9yLFxuICAgICAgICBwcml2YXRlIGxvZ2dlcjogTG9nZ2VyU2VydmljZSxcbiAgICAgICAgcHJpdmF0ZSBwb3J0YWxTZXJ2aWNlOiBDb21wb25lbnRQb3J0YWxTZXJ2aWNlLFxuICAgICAgICBwcml2YXRlIHJlbmRlcmVyOiBSZW5kZXJlcjIsXG4gICAgICAgIHByaXZhdGUgcHJvdmlkZXJSZWdpc3RyeTogUHJvdmlkZXJSZWdpc3RyeVNlcnZpY2VcbiAgICApIHt9XG5cbiAgICBwdWJsaWMgbmdPbkluaXQoKTogdm9pZCB7XG4gICAgICAgIHRoaXMubG9nZ2VyLmRlYnVnKFwiUG9ydGFsIGNyZWF0ZWQ6XCIsIHRoaXMuY29tcG9uZW50SWQpO1xuICAgICAgICB0aGlzLnJlY3JlYXRlUG9ydGFsKCk7XG4gICAgfVxuXG4gICAgcHVibGljIG5nQWZ0ZXJWaWV3SW5pdCgpOiB2b2lkIHtcbiAgICAgICAgT2JqZWN0LmtleXModGhpcy5wcm92aWRlckluc3RhbmNlcykuZm9yRWFjaCgoa2V5KSA9PiB7XG4gICAgICAgICAgICBjb25zdCBwcm92aWRlciA9IHRoaXMucHJvdmlkZXJJbnN0YW5jZXNba2V5XTtcbiAgICAgICAgICAgIGlmIChwcm92aWRlci5uZ0FmdGVyVmlld0luaXQpIHtcbiAgICAgICAgICAgICAgICBwcm92aWRlci5uZ0FmdGVyVmlld0luaXQoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgcHVibGljIG5nT25DaGFuZ2VzKGNoYW5nZXM6IFNpbXBsZUNoYW5nZXMpOiB2b2lkIHtcbiAgICAgICAgbGV0IHJlY3JlYXRlZCA9IGZhbHNlO1xuICAgICAgICBjb25zdCBwcm92aWRlcnNDaGFuZ2UgPSBjaGFuZ2VzLnByb3ZpZGVycztcblxuICAgICAgICBpZiAocHJvdmlkZXJzQ2hhbmdlICYmICFwcm92aWRlcnNDaGFuZ2UuaXNGaXJzdENoYW5nZSgpKSB7XG4gICAgICAgICAgICBpZiAodGhpcy5jaGVja0ZvclByb3ZpZGVyQ2hhbmdlcyhwcm92aWRlcnNDaGFuZ2UpKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5sb2dnZXIuZGVidWcoXG4gICAgICAgICAgICAgICAgICAgIFwiUG9ydGFsIHJlY3JlYXRlZCAocHJvdmlkZXIgY2hhbmdlKTpcIixcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5jb21wb25lbnRJZFxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgdGhpcy5yZWNyZWF0ZVBvcnRhbCgpO1xuICAgICAgICAgICAgICAgIHJlY3JlYXRlZCA9IHRydWU7IC8vIHdlIHdhbnQgdG8gcHJldmVudCBtdWx0aXBsZSByZWNyZWF0aW9ucyB3aXRoaW4gb25lIG5nT25DaGFuZ2VzIGN5Y2xlXG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHRoaXMudXBkYXRlUHJvdmlkZXJDb25maWd1cmF0aW9ucyhwcm92aWRlcnNDaGFuZ2UpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgaWYgKFxuICAgICAgICAgICAgY2hhbmdlcy5jb21wb25lbnRUeXBlICYmXG4gICAgICAgICAgICAhY2hhbmdlcy5jb21wb25lbnRUeXBlLmlzRmlyc3RDaGFuZ2UoKSAmJlxuICAgICAgICAgICAgIXJlY3JlYXRlZFxuICAgICAgICApIHtcbiAgICAgICAgICAgIHRoaXMubG9nZ2VyLmRlYnVnKFxuICAgICAgICAgICAgICAgIFwiUG9ydGFsIHJlY3JlYXRlZCAoY29tcG9uZW50IGNoYW5nZSk6XCIsXG4gICAgICAgICAgICAgICAgdGhpcy5jb21wb25lbnRJZFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIHRoaXMucmVjcmVhdGVQb3J0YWwoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChjaGFuZ2VzLnByb3BlcnRpZXMpIHtcbiAgICAgICAgICAgIHRoaXMucHJvcGVydGllc0NoYW5nZXMubmV4dChjaGFuZ2VzLnByb3BlcnRpZXMpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHVibGljIG5nT25EZXN0cm95KCk6IHZvaWQge1xuICAgICAgICB0aGlzLmxvZ2dlci5kZWJ1ZyhcIlBvcnRhbCBkZXN0cm95ZWQ6XCIsIHRoaXMuY29tcG9uZW50SWQpO1xuXG4gICAgICAgIHRoaXMuZGVzdHJveVByb3ZpZGVycygpO1xuICAgICAgICB0aGlzLmxpc3RlbmVyVW5zdWJzY3JpYmVyPy4oKTtcblxuICAgICAgICB0aGlzLmRlc3Ryb3kkLm5leHQoKTtcbiAgICAgICAgdGhpcy5kZXN0cm95JC5jb21wbGV0ZSgpO1xuICAgIH1cblxuICAgIHB1YmxpYyBhdHRhY2hlZChjb21wb25lbnRSZWY6IENvbXBvbmVudFJlZjxhbnk+KTogdm9pZCB7XG4gICAgICAgIHRoaXMuY29tcG9uZW50ID0gY29tcG9uZW50UmVmLmluc3RhbmNlO1xuXG4gICAgICAgIC8vIGN0cmwrc2hpZnQrY2xpY2sgb24gYSBwaXp6YWduYSB0byBnZXQgYSBkdW1wIG9mIGl0cyBwcm9wZXJ0aWVzXG4gICAgICAgIC8vIHRoaXMgd2lsbCBwcm9wYWdhdGUgdGhyb3VnaCB0aGUgcGFyZW50IGNvbXBvbmVudHMsIHNvIGl0IHNob3VsZCBkdW1wIHRoZSBwYXJlbnQgcGl6emFnbmFzIGFzIHdlbGxcbiAgICAgICAgdGhpcy5saXN0ZW5lclVuc3Vic2NyaWJlciA9IHRoaXMucmVuZGVyZXIubGlzdGVuKFxuICAgICAgICAgICAgY29tcG9uZW50UmVmLmxvY2F0aW9uLm5hdGl2ZUVsZW1lbnQsXG4gICAgICAgICAgICBcImNsaWNrXCIsXG4gICAgICAgICAgICAoZXZlbnQ6IE1vdXNlRXZlbnQpID0+IHtcbiAgICAgICAgICAgICAgICAvLyBldmVudC5tZXRhS2V5IGlzIGEgQ01EIGtleSBmb3IgTWFjXG4gICAgICAgICAgICAgICAgaWYgKFxuICAgICAgICAgICAgICAgICAgICAoZXZlbnQuY3RybEtleSB8fCBldmVudC5tZXRhS2V5KSAmJlxuICAgICAgICAgICAgICAgICAgICBldmVudC5zaGlmdEtleSAmJlxuICAgICAgICAgICAgICAgICAgICBldmVudC5idXR0b24gPT09IDBcbiAgICAgICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2coXG4gICAgICAgICAgICAgICAgICAgICAgICBcIj09PT09PT09PT09PT09PT09PT09IFBJWlpBR05BIERVTVAgPT09PT09PT09PT09PT09PT09PT09PT09PVwiXG4gICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKFwiY29tcG9uZW50SWQ6XCIsIHRoaXMuY29tcG9uZW50SWQpO1xuICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhcImNvbXBvbmVudDpcIiwgdGhpcy5jb21wb25lbnQpO1xuICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhcImNvbXBvbmVudFR5cGU6XCIsIHRoaXMuY29tcG9uZW50VHlwZSk7XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKFwicHJvcGVydGllczpcIiwgdGhpcy5wcm9wZXJ0aWVzKTtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2coXCJwcm92aWRlcnM6XCIsIHRoaXMucHJvdmlkZXJzKTtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2coXCJwcm92aWRlckluc3RhbmNlczpcIiwgdGhpcy5wcm92aWRlckluc3RhbmNlcyk7XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKFxuICAgICAgICAgICAgICAgICAgICAgICAgXCI9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cIlxuICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgKTtcblxuICAgICAgICBmb3IgKGNvbnN0IGtleSBvZiBPYmplY3Qua2V5cyh0aGlzLnByb3ZpZGVySW5zdGFuY2VzKSkge1xuICAgICAgICAgICAgY29uc3QgcHJvdmlkZXIgPSB0aGlzLnByb3ZpZGVySW5zdGFuY2VzW2tleV07XG4gICAgICAgICAgICBpZiAocHJvdmlkZXIuc2V0Q29tcG9uZW50KSB7XG4gICAgICAgICAgICAgICAgLy8gc2V0dGluZyBjb21wb25lbnRJZCBzZXBhcmF0ZWx5IGJlY2F1c2UgXCJjb21wb25lbnRJZFwiIGlzIHVzZWQgYXMgYW5vdGhlciBpbnB1dCxcbiAgICAgICAgICAgICAgICAvLyBhdCB0aGUgbW9tZW50IG9mIHNldHRpbmcgdGhlIGNvbXBvbmVudCBoZXJlLCAndGhpcy5jb21wb25lbnQnIGRvZXNuJ3QgaGF2ZSAnY29tcG9uZW50SWQnIHByb3BlcnR5LFxuICAgICAgICAgICAgICAgIC8vIGJlY2F1c2UgJ2NoYW5nZXNTdWJzY3JpcHRpb24nIGhhcyBub3QgcmVjZWl2ZWQgYW55IGNoYW5nZXMuIGl0IGxlYWRzIHRvIHRoZSBpc3N1ZVxuICAgICAgICAgICAgICAgIC8vIHdoZW4gcHJvdmlkZXJzIGRvIG5vdCBrbm93IHRoZSBJRCB1bnRpbCBjb21wb25lbnQgcHJvcGVydHkgY2hhbmdlZFxuICAgICAgICAgICAgICAgIHByb3ZpZGVyLnNldENvbXBvbmVudCh0aGlzLmNvbXBvbmVudCwgdGhpcy5jb21wb25lbnRJZCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAocHJvdmlkZXIuc2V0UHJvdmlkZXJzKSB7XG4gICAgICAgICAgICAgICAgcHJvdmlkZXIuc2V0UHJvdmlkZXJzKHRoaXMucHJvdmlkZXJJbnN0YW5jZXMsIHRoaXMuY29tcG9uZW50SWQpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5zdWJzY3JpYmVUb091dHB1dHMoKTtcblxuICAgICAgICB0aGlzLmNoYW5nZXNTdWJzY3JpcHRpb24gPSB0aGlzLnByb3BlcnRpZXNDaGFuZ2VzXG4gICAgICAgICAgICAucGlwZSh0YWtlVW50aWwodGhpcy5kZXN0cm95JCkpXG4gICAgICAgICAgICAuc3Vic2NyaWJlKChjaGFuZ2UpID0+IHRoaXMuYXBwbHlQcm9wZXJ0aWVzQ2hhbmdlKGNoYW5nZSkpO1xuICAgIH1cblxuICAgIHByaXZhdGUgcmVjcmVhdGVQb3J0YWwoKSB7XG4gICAgICAgIGlmICh0aGlzLmNoYW5nZXNTdWJzY3JpcHRpb24pIHtcbiAgICAgICAgICAgIHRoaXMuY2hhbmdlc1N1YnNjcmlwdGlvbi51bnN1YnNjcmliZSgpO1xuICAgICAgICAgICAgdGhpcy5jaGFuZ2VzU3Vic2NyaXB0aW9uID0gdW5kZWZpbmVkO1xuICAgICAgICAgICAgdGhpcy5wcm9wZXJ0aWVzQ2hhbmdlcyA9IG5ldyBSZXBsYXlTdWJqZWN0PFNpbXBsZUNoYW5nZT4oKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGxldCBpbmplY3RvciA9IHRoaXMuaW5qZWN0b3I7XG5cbiAgICAgICAgdGhpcy5kZXN0cm95UHJvdmlkZXJzKCk7XG5cbiAgICAgICAgaWYgKHRoaXMucHJvdmlkZXJzKSB7XG4gICAgICAgICAgICBpbmplY3RvciA9IHRoaXMudXBkYXRlUHJvdmlkZXJzKGluamVjdG9yKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMucG9ydGFsID0gdGhpcy5wb3J0YWxTZXJ2aWNlLmNyZWF0ZUNvbXBvbmVudFBvcnRhbChcbiAgICAgICAgICAgIHRoaXMuY29tcG9uZW50VHlwZSxcbiAgICAgICAgICAgIGluamVjdG9yXG4gICAgICAgICk7XG5cbiAgICAgICAgLy8gYXBwbHkgaW5pdGlhbCBwcm9wZXJ0eSB2YWx1ZXMgdG8gdGhlIGZyZXNobHkgKHJlKWNyZWF0ZWQgY29tcG9uZW50XG4gICAgICAgIGlmICh0aGlzLnByb3BlcnRpZXMpIHtcbiAgICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdW51c2VkLXZhcnNcbiAgICAgICAgICAgIGZvciAoY29uc3Qga2V5IG9mIE9iamVjdC5rZXlzKHRoaXMucHJvcGVydGllcykpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnByb3BlcnRpZXNDaGFuZ2VzLm5leHQoXG4gICAgICAgICAgICAgICAgICAgIG5ldyBTaW1wbGVDaGFuZ2UodW5kZWZpbmVkLCB0aGlzLnByb3BlcnRpZXMsIHRydWUpXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByaXZhdGUgdXBkYXRlUHJvdmlkZXJzKGluamVjdG9yOiBJbmplY3Rvcikge1xuICAgICAgICBjb25zdCBwcm92aWRlcktleXMgPSBPYmplY3Qua2V5cyh0aGlzLnByb3ZpZGVycyk7XG4gICAgICAgIGNvbnN0IHJlZ2lzdGVyZWRQcm92aWRlcnMgPSBwcm92aWRlcktleXMucmVkdWNlKChhY2MsIG5leHQpID0+IHtcbiAgICAgICAgICAgIC8vIGZvciBjYXNlcyB3aGVuIHByb3ZpZGVySWQgaXMganVzdCBlbXB0eSBzdHJpbmcsIG51bGwgb3IgdW5kZWZpbmVkIChmb3IgZXhhbXBsZSBhZGRpbmcgYSB0aWxlIGRvZXNuJ3QgcHJvdmlkZSBhIERTIHRvIGl0KVxuICAgICAgICAgICAgaWYgKHRoaXMucHJvdmlkZXJzW25leHRdLnByb3ZpZGVySWQpIHtcbiAgICAgICAgICAgICAgICBhY2NbbmV4dF0gPSB0aGlzLnByb3ZpZGVyUmVnaXN0cnkuZ2V0UHJvdmlkZXIoXG4gICAgICAgICAgICAgICAgICAgIHRoaXMucHJvdmlkZXJzW25leHRdLnByb3ZpZGVySWRcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIGFjYztcbiAgICAgICAgfSwge30gYXMgUmVjb3JkPHN0cmluZywgU3RhdGljUHJvdmlkZXI+KTtcblxuICAgICAgICBjb25zdCBwb3J0YWxJbmplY3RvciA9IHRoaXMucG9ydGFsU2VydmljZS5jcmVhdGVJbmplY3Rvcih7XG4gICAgICAgICAgICBpbmplY3RvcjogaW5qZWN0b3IsXG4gICAgICAgICAgICBwcm92aWRlcnM6IHZhbHVlcyhyZWdpc3RlcmVkUHJvdmlkZXJzKSxcbiAgICAgICAgfSk7XG5cbiAgICAgICAgdGhpcy5wcm92aWRlckluc3RhbmNlcyA9IHByb3ZpZGVyS2V5cy5yZWR1Y2UoKGFjYywgbmV4dCkgPT4ge1xuICAgICAgICAgICAgY29uc3QgcmVnaXN0ZXJlZFByb3ZpZGVyID0gcmVnaXN0ZXJlZFByb3ZpZGVyc1tuZXh0XSBhcyBhbnk7XG4gICAgICAgICAgICBjb25zdCBwcm92aWRlckNvbmZpZyA9IHRoaXMucHJvdmlkZXJzW25leHRdO1xuICAgICAgICAgICAgaWYgKHJlZ2lzdGVyZWRQcm92aWRlcikge1xuICAgICAgICAgICAgICAgIC8vIFRPRE86IFdoeSBkbyB3ZSBwYXNzIG51bGwgdG8gdGhlIGluamVjdEZsYWdzIHBhcmFtZXRlcj9cbiAgICAgICAgICAgICAgICAvLyBUT0RPOiBIb3cgdG8gcmV0cmlldmUgaW5mbyBhYm91dCB0aGUgcHJvdmlkZXIgb3B0aW9ucyB0byBpbmplY3Q/SW5qZWN0T3B0aW9uc1xuICAgICAgICAgICAgICAgIGNvbnN0IGluamVjdGlvbnMgPSBwb3J0YWxJbmplY3Rvci5nZXQoXG4gICAgICAgICAgICAgICAgICAgIHJlZ2lzdGVyZWRQcm92aWRlci5wcm92aWRlLFxuICAgICAgICAgICAgICAgICAgICBudWxsXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICBjb25zdCBwcm92aWRlckluc3RhbmNlID0gaXNBcnJheShpbmplY3Rpb25zKVxuICAgICAgICAgICAgICAgICAgICA/IChpbmplY3Rpb25zIGFzIGFueSkuZmluZChcbiAgICAgICAgICAgICAgICAgICAgICAgICAgKHY6IGFueSkgPT4gdiBpbnN0YW5jZW9mIHJlZ2lzdGVyZWRQcm92aWRlci51c2VDbGFzc1xuICAgICAgICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgICAgICAgICAgOiBpbmplY3Rpb25zO1xuXG4gICAgICAgICAgICAgICAgaWYgKCFwcm92aWRlckluc3RhbmNlKSB7XG4gICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIlByb3ZpZGVyICdcIiArIG5leHQgKyBcIicgZG9lcyBub3QgZXhpc3QuXCIpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAgICAgICAgIHByb3ZpZGVySW5zdGFuY2UudXBkYXRlQ29uZmlndXJhdGlvbiAmJlxuICAgICAgICAgICAgICAgICAgICBwcm92aWRlckNvbmZpZy5wcm9wZXJ0aWVzXG4gICAgICAgICAgICAgICAgKSB7XG4gICAgICAgICAgICAgICAgICAgIHByb3ZpZGVySW5zdGFuY2UudXBkYXRlQ29uZmlndXJhdGlvbih7XG4gICAgICAgICAgICAgICAgICAgICAgICBwcm92aWRlcktleTogbmV4dCxcbiAgICAgICAgICAgICAgICAgICAgICAgIC4uLihwcm92aWRlckNvbmZpZy5wcm9wZXJ0aWVzIHx8IHt9KSxcbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHByb3ZpZGVySW5zdGFuY2UucHJvdmlkZXJLZXkgPSBuZXh0O1xuXG4gICAgICAgICAgICAgICAgYWNjW25leHRdID0gcHJvdmlkZXJJbnN0YW5jZTtcbiAgICAgICAgICAgIH0gZWxzZSBpZiAocHJvdmlkZXJDb25maWcucHJvdmlkZXJJZCkge1xuICAgICAgICAgICAgICAgIHRoaXMubG9nZ2VyLmVycm9yKFxuICAgICAgICAgICAgICAgICAgICBcIlRoZXJlJ3Mgbm8gcmVnaXN0ZXJlZCBwcm92aWRlciBmb3IgaWRcIixcbiAgICAgICAgICAgICAgICAgICAgbmV4dFxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gYWNjO1xuICAgICAgICB9LCB0aGlzLnByb3ZpZGVySW5zdGFuY2VzKTtcblxuICAgICAgICBmb3IgKGNvbnN0IGtleSBvZiBPYmplY3Qua2V5cyh0aGlzLnByb3ZpZGVySW5zdGFuY2VzKSkge1xuICAgICAgICAgICAgY29uc3QgcGkgPSB0aGlzLnByb3ZpZGVySW5zdGFuY2VzW2tleV07XG4gICAgICAgICAgICBpZiAocGkubmdPbkluaXQpIHtcbiAgICAgICAgICAgICAgICBwaS5uZ09uSW5pdCgpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHBvcnRhbEluamVjdG9yO1xuICAgIH1cblxuICAgIHByaXZhdGUgdXBkYXRlUHJvdmlkZXJDb25maWd1cmF0aW9ucyhwcm92aWRlcnNDaGFuZ2U6IFNpbXBsZUNoYW5nZSkge1xuICAgICAgICBmb3IgKGNvbnN0IHByb3ZpZGVyS2V5IG9mIE9iamVjdC5rZXlzKHRoaXMucHJvdmlkZXJzKSkge1xuICAgICAgICAgICAgLy8gZm9yIGNhc2VzIHdoZW4gcHJvdmlkZXJJZCBpcyBqdXN0IGVtcHR5IHN0cmluZywgbnVsbCBvciB1bmRlZmluZWQgKGZvciBleGFtcGxlIGFkZGluZyBhIHRpbGUgZG9lc24ndCBwcm92aWRlIGEgRFMgdG8gaXQpXG4gICAgICAgICAgICBpZiAoIXRoaXMucHJvdmlkZXJzW3Byb3ZpZGVyS2V5XS5wcm92aWRlcklkKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY29uc3QgcHJvdmlkZXJJbnN0YW5jZSA9IHRoaXMucHJvdmlkZXJJbnN0YW5jZXNbcHJvdmlkZXJLZXldO1xuICAgICAgICAgICAgaWYgKCFwcm92aWRlckluc3RhbmNlKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgICAgICAgICAgICBcIlByb3ZpZGVyICdcIiArIHByb3ZpZGVyS2V5ICsgXCInIGRvZXMgbm90IGV4aXN0LlwiXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgY29uc3QgcHJldmlvdXNWYWx1ZSA9IHByb3ZpZGVyc0NoYW5nZS5wcmV2aW91c1ZhbHVlW3Byb3ZpZGVyS2V5XTtcbiAgICAgICAgICAgIGNvbnN0IGN1cnJlbnRWYWx1ZSA9IHByb3ZpZGVyc0NoYW5nZS5jdXJyZW50VmFsdWVbcHJvdmlkZXJLZXldO1xuXG4gICAgICAgICAgICBjb25zdCBwcmV2aW91c1Byb3BlcnRpZXMgPVxuICAgICAgICAgICAgICAgIHByZXZpb3VzVmFsdWUgJiYgcHJldmlvdXNWYWx1ZS5wcm9wZXJ0aWVzO1xuICAgICAgICAgICAgY29uc3QgY3VycmVudFByb3BlcnRpZXMgPSBjdXJyZW50VmFsdWUgJiYgY3VycmVudFZhbHVlLnByb3BlcnRpZXM7XG5cbiAgICAgICAgICAgIGlmIChcbiAgICAgICAgICAgICAgICBwcmV2aW91c1Byb3BlcnRpZXMgIT09IGN1cnJlbnRQcm9wZXJ0aWVzICYmXG4gICAgICAgICAgICAgICAgcHJvdmlkZXJJbnN0YW5jZS51cGRhdGVDb25maWd1cmF0aW9uXG4gICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgICAocHJvdmlkZXJJbnN0YW5jZSBhcyBJQ29uZmlndXJhYmxlKS51cGRhdGVDb25maWd1cmF0aW9uKHtcbiAgICAgICAgICAgICAgICAgICAgcHJvdmlkZXJLZXksXG4gICAgICAgICAgICAgICAgICAgIC4uLmN1cnJlbnRQcm9wZXJ0aWVzLFxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBzdWJzY3JpYmVUb091dHB1dHMoKSB7XG4gICAgICAgIGlmICghdGhpcy5vdXRwdXRzKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBmb3IgKGNvbnN0IG91dHB1dCBvZiB0aGlzLm91dHB1dHMuZmlsdGVyKFxuICAgICAgICAgICAgKG8pID0+IHRoaXMuY29tcG9uZW50W29dIGluc3RhbmNlb2YgRXZlbnRFbWl0dGVyXG4gICAgICAgICkpIHtcbiAgICAgICAgICAgIHRoaXMuY29tcG9uZW50W291dHB1dF1cbiAgICAgICAgICAgICAgICAucGlwZSh0YWtlVW50aWwodGhpcy5kZXN0cm95JCkpXG4gICAgICAgICAgICAgICAgLnN1YnNjcmliZSgoJGV2ZW50OiBhbnkpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5vdXRwdXQuZW1pdCh7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZDogb3V0cHV0LFxuICAgICAgICAgICAgICAgICAgICAgICAgcGF5bG9hZDogJGV2ZW50LFxuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByaXZhdGUgY2hlY2tGb3JQcm92aWRlckNoYW5nZXMoY2hhbmdlOiBTaW1wbGVDaGFuZ2UpOiBib29sZWFuIHtcbiAgICAgICAgY29uc3QgcHJldmlvdXNLZXlzID0gY2hhbmdlLnByZXZpb3VzVmFsdWVcbiAgICAgICAgICAgID8gT2JqZWN0LmtleXMoY2hhbmdlLnByZXZpb3VzVmFsdWUpXG4gICAgICAgICAgICA6IFtdO1xuICAgICAgICBjb25zdCBjdXJyZW50S2V5cyA9IGNoYW5nZS5jdXJyZW50VmFsdWVcbiAgICAgICAgICAgID8gT2JqZWN0LmtleXMoY2hhbmdlLmN1cnJlbnRWYWx1ZSlcbiAgICAgICAgICAgIDogW107XG4gICAgICAgIGlmIChcbiAgICAgICAgICAgIHByZXZpb3VzS2V5cy5sZW5ndGggIT09IGN1cnJlbnRLZXlzLmxlbmd0aCB8fFxuICAgICAgICAgICAgeG9yKHByZXZpb3VzS2V5cywgY3VycmVudEtleXMpLmxlbmd0aCA+IDBcbiAgICAgICAgKSB7XG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IHByZXZpb3VzSWRzID0gT2JqZWN0LmtleXMoY2hhbmdlLnByZXZpb3VzVmFsdWUpLm1hcChcbiAgICAgICAgICAgIChrZXk6IHN0cmluZykgPT4gY2hhbmdlLnByZXZpb3VzVmFsdWVba2V5XS5wcm92aWRlcklkXG4gICAgICAgICk7XG4gICAgICAgIGNvbnN0IGN1cnJlbnRJZHMgPSBPYmplY3Qua2V5cyhjaGFuZ2UuY3VycmVudFZhbHVlKS5tYXAoXG4gICAgICAgICAgICAoa2V5OiBzdHJpbmcpID0+IGNoYW5nZS5jdXJyZW50VmFsdWVba2V5XS5wcm92aWRlcklkXG4gICAgICAgICk7XG4gICAgICAgIGlmICh4b3IocHJldmlvdXNJZHMsIGN1cnJlbnRJZHMpLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIHByaXZhdGUgZGVzdHJveVByb3ZpZGVycygpIHtcbiAgICAgICAgaWYgKHRoaXMucHJvdmlkZXJJbnN0YW5jZXMpIHtcbiAgICAgICAgICAgIGZvciAoY29uc3QgcGlLZXkgb2YgT2JqZWN0LmtleXModGhpcy5wcm92aWRlckluc3RhbmNlcykpIHtcbiAgICAgICAgICAgICAgICBjb25zdCBwcm92aWRlckluc3RhbmNlID0gdGhpcy5wcm92aWRlckluc3RhbmNlc1twaUtleV07XG4gICAgICAgICAgICAgICAgaWYgKHByb3ZpZGVySW5zdGFuY2UubmdPbkRlc3Ryb3kpIHtcbiAgICAgICAgICAgICAgICAgICAgcHJvdmlkZXJJbnN0YW5jZS5uZ09uRGVzdHJveSgpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBkZWxldGUgdGhpcy5wcm92aWRlckluc3RhbmNlc1twaUtleV07XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBUaGVyZSB3YXMgYSBjaGFuZ2UgaW4gY29tcG9uZW50IHByb3BlcnRpZXMsIHNvIHdlIG5lZWQgdG8gaGFuZGxlIHRoYXQgaGVyZVxuICAgICAqXG4gICAgICogQHBhcmFtIGNoYW5nZSBhIGNoYW5nZSBvZiB0aGUgYHByb3BlcnRpZXNgIGlucHV0XG4gICAgICovXG4gICAgcHJpdmF0ZSBhcHBseVByb3BlcnRpZXNDaGFuZ2UoY2hhbmdlOiBTaW1wbGVDaGFuZ2UpIHtcbiAgICAgICAgbGV0IHByb3BlcnRpZXMgPSBjaGFuZ2UuY3VycmVudFZhbHVlO1xuICAgICAgICBpZiAoIXByb3BlcnRpZXMpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIHdlIGFkZCBjb21wb25lbnRJZCB0byB0aGUgbWl4LCBzbyBjb21wb25lbnRzIHdpbGwgYmUgYWJsZSB0byB1c2UgaXRcbiAgICAgICAgcHJvcGVydGllcyA9IHtcbiAgICAgICAgICAgIC4uLnByb3BlcnRpZXMsXG4gICAgICAgICAgICBjb21wb25lbnRJZDogdGhpcy5jb21wb25lbnRJZCxcbiAgICAgICAgfTtcblxuICAgICAgICBjb25zdCBjaGFuZ2VzOiBTaW1wbGVDaGFuZ2VzID0ge307XG4gICAgICAgIGxldCBjaGFuZ2VIYXBwZW5lZCA9IGZhbHNlO1xuICAgICAgICBmb3IgKGNvbnN0IGtleSBvZiBPYmplY3Qua2V5cyhwcm9wZXJ0aWVzKSkge1xuICAgICAgICAgICAgY29uc3QgcHJldmlvdXNWYWx1ZSA9IHRoaXMuY29tcG9uZW50W2tleV07XG5cbiAgICAgICAgICAgIC8vIHJlZmVyZW5jZSBiYXNlZCBjaGFuZ2UgZGV0ZWN0aW9uIGluIGFjdGlvbiBoZXJlIVxuICAgICAgICAgICAgaWYgKHByb3BlcnRpZXNba2V5XSAhPT0gcHJldmlvdXNWYWx1ZSkge1xuICAgICAgICAgICAgICAgIGNoYW5nZUhhcHBlbmVkID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICB0aGlzLmNvbXBvbmVudFtrZXldID0gcHJvcGVydGllc1trZXldO1xuICAgICAgICAgICAgICAgIC8vIHdlJ3JlIHNpbXVsYXRpbmcgYW5ndWxhciBieSBjYWxsaW5nIG5nT25DaGFuZ2VzIG1hbnVhbGx5XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuY29tcG9uZW50Lm5nT25DaGFuZ2VzKSB7XG4gICAgICAgICAgICAgICAgICAgIGNoYW5nZXNba2V5XSA9IG5ldyBTaW1wbGVDaGFuZ2UoXG4gICAgICAgICAgICAgICAgICAgICAgICBwcmV2aW91c1ZhbHVlLFxuICAgICAgICAgICAgICAgICAgICAgICAgcHJvcGVydGllc1trZXldLFxuICAgICAgICAgICAgICAgICAgICAgICAgY2hhbmdlLmlzRmlyc3RDaGFuZ2UoKVxuICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChjaGFuZ2VIYXBwZW5lZCkge1xuICAgICAgICAgICAgaWYgKHRoaXMuY29tcG9uZW50Lm5nT25DaGFuZ2VzKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5jb21wb25lbnQubmdPbkNoYW5nZXMoY2hhbmdlcyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjb25zdCBjaGFuZ2VEZXRlY3RvciA9IHRoaXMuY29tcG9uZW50LmNoYW5nZURldGVjdG9yO1xuICAgICAgICAgICAgaWYgKGNoYW5nZURldGVjdG9yKSB7XG4gICAgICAgICAgICAgICAgY2hhbmdlRGV0ZWN0b3IubWFya0ZvckNoZWNrKCk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHRoaXMubG9nZ2VyLndhcm4oXG4gICAgICAgICAgICAgICAgICAgIGBQcm9wZXJ0eSAnY2hhbmdlRGV0ZWN0b3InIGlzIG1pc3Npbmcgb24gY29tcG9uZW50ICcke3RoaXMuY29tcG9uZW50VHlwZX0nLGAgK1xuICAgICAgICAgICAgICAgICAgICAgICAgYCBzbyBkeW5hbWljIHJlZnJlc2ggb2YgZ2l2ZW4gY29tcG9uZW50IG1pZ2h0IG5vdCB3b3JrLmBcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxufVxuIl19