UNPKG

@dotglitch/ngx-common

Version:

Angular components and utilities that are commonly used.

383 lines 58.7 kB
import { Input, ViewContainerRef, isDevMode, EventEmitter, Optional, ViewChild, Component, Inject, Output } from '@angular/core'; import { NgComponentOutlet, NgTemplateOutlet } from '@angular/common'; import { MAT_DIALOG_DATA, } from '@angular/material/dialog'; import { debounceTime } from 'rxjs'; import { LazyLoaderService } from './lazy-loader.service'; import { stringToSlug } from '../../utils'; import * as i0 from "@angular/core"; import * as i1 from "./lazy-loader.service"; import * as i2 from "@angular/cdk/dialog"; export class LazyLoaderComponent { /** * The id of the component that will be lazy loaded */ set id(data) { this.originalId = data; const id = stringToSlug(data); // Check if there is a change to the loaded component's id // if it's updated, we destroy and rehydrate the entire container if (this.initialized && this._id != id) { this._id = id; this.ngAfterViewInit(); } else { this._id = id; } } ; set group(data) { this.originalGroup = data; const group = stringToSlug(data); if (typeof group != "string" || !group) return; // If the group was updated, retry to bootstrap something into the container. if (this.initialized && this._group != group) { this._group = group; this.ngAfterViewInit(); return; } this._group = group; } get group() { return this._group; } /** * A map of inputs to bind to the child. * Supports change detection. (May fail on deep JSON changes) * * ```html * <lazy-loader component="MyLazyComponent" * [inputs]="{ * prop1: true, * prop2: false, * complex: { * a: true, * b: 0 * } * }" * > * </lazy-loader> * ``` */ set inputs(data) { if (data == undefined) return; let previous = this._inputs; this._inputs = data; if (data == undefined) console.trace(data); if (this.targetComponentFactory) { const { inputs } = this.targetComponentFactory.ɵcmp; const currentKeys = Object.keys(inputs); const oldKeys = Object.keys(previous).filter(key => currentKeys.includes(key)); const newKeys = Object.keys(data).filter(key => currentKeys.includes(key)); const removed = oldKeys.filter(key => !newKeys.includes(key)); // ? perhaps set to null or undefined instead removed.forEach(k => this.targetComponentInstance[k] = null); this.bindInputs(); } } /** * A map of outputs to bind from the child. * Should support change detection. * ```html * <lazy-loader component="MyLazyComponent" * [outputs]="{ * prop3: onOutputFire * }" * > * </lazy-loader> * ``` */ set outputs(data) { let previous = this._outputs; this._outputs = data; if (this.targetComponentFactory) { const { inputs } = this.targetComponentFactory.ɵcmp; const currentKeys = Object.keys(inputs); const removed = Object.keys(previous).filter(key => !currentKeys.includes(key)); removed.forEach(k => { // Unsubscribe from observable this.outputSubscriptions[k]?.unsubscribe(); delete this.targetComponentInstance[k]; }); this.bindOutputs(); } } constructor(service, viewContainerRef, dialog, dialogArguments) { this.service = service; this.viewContainerRef = viewContainerRef; this.dialog = dialog; this.dialogArguments = dialogArguments; this._group = "default"; this.outputSubscriptions = {}; /** * Emits errors encountered when loading components */ this.componentLoadError = new EventEmitter(); /** * Emits when the component is fully constructed * and had it's inputs and outputs bound * > before `OnInit` * * Returns the active class instance of the lazy-loaded component */ this.componentLoaded = new EventEmitter(); // Force 500ms delay before revealing the spinner this.clearEmitter = new EventEmitter(); this.clearLoader$ = this.clearEmitter.pipe(debounceTime(300)); this.showEmitter = new EventEmitter(); this.showLoader$ = this.showEmitter.pipe(debounceTime(1)); this.subscriptions = [ this.clearLoader$.subscribe(() => { this.isClearingLoader = true; setTimeout(() => { this.renderSpinner = false; }, 300); }), this.showLoader$.subscribe(() => { this.isClearingLoader = false; this.renderSpinner = true; }) ]; this.renderSpinner = true; // whether we render the DOM for the spinner this.isClearingLoader = false; // should the spinner start fading out this.initialized = false; this.config = LazyLoaderService.config; this.err = LazyLoaderService.config.logger.err; this.warn = LazyLoaderService.config.logger.warn; this.log = LazyLoaderService.config.logger.log; // First, check for dialog arguments if (this.dialogArguments) { this.inputs = this.dialogArguments.inputs || this.dialogArguments.data; this.outputs = this.dialogArguments.outputs; this.id = this.dialogArguments.id; this.group = this.dialogArguments.group; } } async ngAfterViewInit() { this.ngOnDestroy(false); this.isClearingLoader = false; this.renderSpinner = true; this.initialized = true; if (!this._id) { this.warn("No component was specified!"); return this.loadDefault(); } try { const _entry = this.service.resolveRegistrationEntry(this.originalId, this.originalGroup); if (!_entry || !_entry.entry) { this.err(`Failed to find Component '${this._id}' in group '${this._group}' in registry!`); return this.loadDefault(); } const { entry, matchGroups } = _entry; this._matchGroups = matchGroups; // Download the "module" (the standalone component) const bundle = this.targetModule = await entry.load(); // Check if there is some corruption on the bundle. if (!bundle || typeof bundle != 'object') { this.err(`Failed to load component/module for '${this._id}'! Parsed resource is invalid.`); return this.loadError(); } const modules = Object.keys(bundle) .map(k => { const entry = bundle[k]; // Strictly check for exported modules or standalone components if (typeof entry == "function" && typeof entry["ɵfac"] == "function") return entry; return null; }) .filter(e => e != null) .filter(entry => { entry['_isModule'] = !!entry['ɵmod']; // module entry['_isComponent'] = !!entry['ɵcmp']; // component return (entry['_isModule'] || entry['_isComponent']); }); if (modules.length == 0) { this.err(`Component/Module loaded for '${this._id}' has no exported components or modules!`); return this.loadError(); } const component = this.targetComponentFactory = this.service.resolveComponent(this._id, "default", modules); if (!component) { this.err(`Component '${this._id}' is invalid or corrupted!`); return this.loadError(); } // const componentRef = this.targetComponentContainerRef = createComponent(component as any, { // environmentInjector: this.appRef.injector, // elementInjector: this.injector, // hostElement: this.viewContainerRef.element.nativeElement, // // projectableNodes: // }); // // this.targetRef = this.targetContainer.insert(this.targetComponentContainerRef.hostView); // this.appRef.attachView(componentRef.hostView); // Bootstrap the component into the container const componentRef = this.targetComponentContainerRef = this.targetContainer.createComponent(component); this.targetRef = this.targetContainer.insert(this.targetComponentContainerRef.hostView); const instance = this.targetComponentInstance = componentRef['instance']; this.bindInputs(); this.bindOutputs(); this.componentLoaded.next(instance); this.instance = instance; // Look for an observable called isLoading$ that will make us show/hide // the same distractor that is used on basic loading const isLoading$ = instance['ngxShowDistractor$']; if (isLoading$ && typeof isLoading$.subscribe == "function") { this.distractorSubscription = isLoading$.subscribe(loading => { loading ? this.showEmitter.emit() : this.clearEmitter.emit(); }); } else { this.clearEmitter.emit(); } const name = Object.keys(bundle)[0]; this.log(`Loaded '${name}'`); this.clearEmitter.emit(); return componentRef; } catch (ex) { if (isDevMode()) { console.warn("Component DDD " + this._id + " threw an error on mount!"); console.warn("This will cause you to see a 404 panel."); console.error(ex); } // Network errors throw a toast and return an error component if (ex && !isDevMode()) { console.error("Uncaught error when loading component"); throw ex; } return this.loadDefault(); } } ngOnDestroy(clearAll = true) { // unsubscribe from all subscriptions Object.entries(this.outputSubscriptions).forEach(([key, sub]) => { sub.unsubscribe(); }); this.outputSubscriptions = {}; // Clear all things if (clearAll) { Object.entries(this.subscriptions).forEach(([key, sub]) => { sub.unsubscribe(); }); } this.distractorSubscription?.unsubscribe(); // Clear target container this.targetRef?.destroy(); this.targetComponentContainerRef?.destroy(); this.targetContainer?.clear(); // Wipe the rest of the state clean this.targetRef = null; this.targetComponentContainerRef = null; } /** * Bind the input values to the child component. */ bindInputs() { if (!this._inputs || !this.targetComponentInstance) return; // Merge match groups if (typeof this._matchGroups == "object") { Object.entries(this._matchGroups).forEach(([key, val]) => { if (typeof this._inputs[key] == 'undefined') this._inputs[key] = val; }); } // forward-bind inputs const { inputs } = this.targetComponentFactory.ɵcmp; // Returns a list of entries that need to be set // This makes it so that unnecessary setters are not invoked. const updated = Object.entries(inputs).filter(([parentKey, childKey]) => { return this.targetComponentInstance[childKey] != this._inputs[parentKey]; }); updated.forEach(([parentKey, childKey]) => { if (this._inputs.hasOwnProperty(parentKey)) { // Angular 19.2+ if (Array.isArray(childKey)) { this.targetComponentInstance[childKey[0]] = this._inputs[parentKey]; } else { this.targetComponentInstance[childKey] = this._inputs[parentKey]; } } }); } /** * Bind the output handlers to the loaded child component */ bindOutputs() { if (!this._outputs || !this.targetComponentInstance) return; const { outputs } = this.targetComponentFactory.ɵcmp; // Get a list of unregistered outputs const newOutputs = Object.entries(outputs).filter(([parentKey, childKey]) => { return !this.outputSubscriptions[parentKey]; }); // Reverse bind via subscription newOutputs.forEach(([parentKey, childKey]) => { if (this._outputs.hasOwnProperty(parentKey)) { const target = this.targetComponentInstance[childKey]; const outputs = this._outputs; // Angular folks, stop making this so difficult. const ctx = this.viewContainerRef['_hostLView'][8]; const sub = target.subscribe(outputs[parentKey].bind(ctx)); // Subscription this.outputSubscriptions[parentKey] = sub; } }); } /** * Load the "Default" component (404) screen normally. * This is shown when the component id isn't in the * registry or otherwise doesn't match * * This */ loadDefault() { if (this.config.notFoundComponent) this.targetContainer.createComponent(this.config.notFoundComponent); this.clearEmitter.emit(); } /** * Load the "Error" component. * This is shown when we are able to resolve the component * in the registry, but have some issue boostrapping the * component into the viewContainer */ loadError() { if (this.config.errorComponent) this.targetContainer.createComponent(this.config.errorComponent); this.clearEmitter.emit(); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: LazyLoaderComponent, deps: [{ token: i1.LazyLoaderService }, { token: i0.ViewContainerRef, optional: true }, { token: i2.DialogRef, optional: true }, { token: MAT_DIALOG_DATA, optional: true }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.1.2", type: LazyLoaderComponent, isStandalone: true, selector: "ngx-lazy-loader", inputs: { id: ["component", "id"], group: "group", inputs: "inputs", outputs: "outputs" }, outputs: { componentLoadError: "componentLoadError", componentLoaded: "componentLoaded" }, viewQueries: [{ propertyName: "targetContainer", first: true, predicate: ["content"], descendants: true, read: ViewContainerRef }], ngImport: i0, template: "<ng-container #content></ng-container>\n\n@if (renderSpinner) {\n <div\n class=\"ngx-lazy-loader-distractor\"\n [class.destroying]=\"isClearingLoader\"\n >\n @if (config.loaderDistractorComponent) {\n <ng-container\n [ngComponentOutlet]=\"config.loaderDistractorComponent\"\n />\n }\n @if (config.loaderDistractorTemplate) {\n <ng-container\n [ngTemplateOutlet]=\"config.loaderDistractorTemplate\"\n [ngTemplateOutletContext]=\"{ '$implicit': inputs }\"\n />\n }\n </div>\n}\n", styles: [":host{display:contents;contain:content;z-index:1;position:relative}.ngx-lazy-loader-distractor{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;flex-direction:column;background-color:var(--background-color, #212121);opacity:1;transition:opacity .3s ease;z-index:999999;animation:fade-in .3s ease}.ngx-lazy-loader-distractor.destroying{opacity:0;pointer-events:none}@keyframes fade-in{0%{opacity:0;pointer-events:none}to{opacity:1;pointer-events:all}}\n"], dependencies: [{ kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: LazyLoaderComponent, decorators: [{ type: Component, args: [{ selector: 'ngx-lazy-loader', imports: [NgComponentOutlet, NgTemplateOutlet], standalone: true, template: "<ng-container #content></ng-container>\n\n@if (renderSpinner) {\n <div\n class=\"ngx-lazy-loader-distractor\"\n [class.destroying]=\"isClearingLoader\"\n >\n @if (config.loaderDistractorComponent) {\n <ng-container\n [ngComponentOutlet]=\"config.loaderDistractorComponent\"\n />\n }\n @if (config.loaderDistractorTemplate) {\n <ng-container\n [ngTemplateOutlet]=\"config.loaderDistractorTemplate\"\n [ngTemplateOutletContext]=\"{ '$implicit': inputs }\"\n />\n }\n </div>\n}\n", styles: [":host{display:contents;contain:content;z-index:1;position:relative}.ngx-lazy-loader-distractor{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;flex-direction:column;background-color:var(--background-color, #212121);opacity:1;transition:opacity .3s ease;z-index:999999;animation:fade-in .3s ease}.ngx-lazy-loader-distractor.destroying{opacity:0;pointer-events:none}@keyframes fade-in{0%{opacity:0;pointer-events:none}to{opacity:1;pointer-events:all}}\n"] }] }], ctorParameters: () => [{ type: i1.LazyLoaderService }, { type: i0.ViewContainerRef, decorators: [{ type: Optional }] }, { type: i2.DialogRef, decorators: [{ type: Optional }] }, { type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [MAT_DIALOG_DATA] }] }], propDecorators: { targetContainer: [{ type: ViewChild, args: ["content", { read: ViewContainerRef }] }], id: [{ type: Input, args: ["component"] }], group: [{ type: Input, args: ["group"] }], inputs: [{ type: Input, args: ["inputs"] }], outputs: [{ type: Input, args: ["outputs"] }], componentLoadError: [{ type: Output }], componentLoaded: [{ type: Output }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGF6eS1sb2FkZXIuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vcGFja2FnZXMvY29tbW9uL3NyYy9jb21wb25lbnRzL2xhenktbG9hZGVyL2xhenktbG9hZGVyLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uL3BhY2thZ2VzL2NvbW1vbi9zcmMvY29tcG9uZW50cy9sYXp5LWxvYWRlci9sYXp5LWxvYWRlci5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsS0FBSyxFQUFFLGdCQUFnQixFQUFFLFNBQVMsRUFBZ0IsWUFBWSxFQUFFLFFBQVEsRUFBRSxTQUFTLEVBQUUsU0FBUyxFQUFFLE1BQU0sRUFBRSxNQUFNLEVBQW1DLE1BQU0sZUFBZSxDQUFDO0FBQ2hMLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQ3RFLE9BQU8sRUFBRSxlQUFlLEdBQUcsTUFBTSwwQkFBMEIsQ0FBQztBQUU1RCxPQUFPLEVBQW1CLFlBQVksRUFBZ0IsTUFBTSxNQUFNLENBQUM7QUFDbkUsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFDMUQsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGFBQWEsQ0FBQzs7OztBQVczQyxNQUFNLE9BQU8sbUJBQW1CO0lBaUI1Qjs7T0FFRztJQUNILElBQXdCLEVBQUUsQ0FBQyxJQUFZO1FBQ25DLElBQUksQ0FBQyxVQUFVLEdBQUcsSUFBSSxDQUFDO1FBQ3ZCLE1BQU0sRUFBRSxHQUFHLFlBQVksQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUU5QiwwREFBMEQ7UUFDMUQsaUVBQWlFO1FBQ2pFLElBQUksSUFBSSxDQUFDLFdBQVcsSUFBSSxJQUFJLENBQUMsR0FBRyxJQUFJLEVBQUUsRUFBRSxDQUFDO1lBQ3JDLElBQUksQ0FBQyxHQUFHLEdBQUcsRUFBRSxDQUFDO1lB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QU07Z0JBU0csZUFBZTtzQkFBeEIsTUFBTSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IElucHV0LCBWaWV3Q29udGFpbmVyUmVmLCBpc0Rldk1vZGUsIENvbXBvbmVudFJlZiwgRXZlbnRFbWl0dGVyLCBPcHRpb25hbCwgVmlld0NoaWxkLCBDb21wb25lbnQsIEluamVjdCwgT3V0cHV0LCBOZ01vZHVsZSwgQWZ0ZXJWaWV3SW5pdCwgT25Jbml0IH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBOZ0NvbXBvbmVudE91dGxldCwgTmdUZW1wbGF0ZU91dGxldCB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XG5pbXBvcnQgeyBNQVRfRElBTE9HX0RBVEEsIH0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvZGlhbG9nJztcbmltcG9ydCB7IERpYWxvZ1JlZiB9IGZyb20gJ0Bhbmd1bGFyL2Nkay9kaWFsb2cnO1xuaW1wb3J0IHsgQmVoYXZpb3JTdWJqZWN0LCBkZWJvdW5jZVRpbWUsIFN1YnNjcmlwdGlvbiB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgTGF6eUxvYWRlclNlcnZpY2UgfSBmcm9tICcuL2xhenktbG9hZGVyLnNlcnZpY2UnO1xuaW1wb3J0IHsgc3RyaW5nVG9TbHVnIH0gZnJvbSAnLi4vLi4vdXRpbHMnO1xuaW1wb3J0IHsgQ29tcGlsZWRCdW5kbGUsIE5neExhenlMb2FkZXJDb25maWcgfSBmcm9tICcuL3R5cGVzJztcblxuXG5AQ29tcG9uZW50KHtcbiAgICBzZWxlY3RvcjogJ25neC1sYXp5LWxvYWRlcicsXG4gICAgdGVtcGxhdGVVcmw6ICcuL2xhenktbG9hZGVyLmNvbXBvbmVudC5odG1sJyxcbiAgICBzdHlsZVVybHM6IFsgJy4vbGF6eS1sb2FkZXIuY29tcG9uZW50LnNjc3MnIF0sXG4gICAgaW1wb3J0czogWyBOZ0NvbXBvbmVudE91dGxldCwgTmdUZW1wbGF0ZU91dGxldCBdLFxuICAgIHN0YW5kYWxvbmU6IHRydWVcbn0pXG5leHBvcnQgY2xhc3MgTGF6eUxvYWRlckNvbXBvbmVudCBpbXBsZW1lbnRzIEFmdGVyVmlld0luaXQge1xuICAgIEBWaWV3Q2hpbGQoXCJjb250ZW50XCIsIHsgcmVhZDogVmlld0NvbnRhaW5lclJlZiB9KSB0YXJnZXRDb250YWluZXI6IFZpZXdDb250YWluZXJSZWY7XG5cbiAgICAvKipcbiAgICAgKiAhIEhlcmUgYmUgZHJhZ29ucy5cbiAgICAgKiBPbmx5IHRoZSBicmF2ZXN0IG9mIEFkdmVudHVyZXJzIGNhbiBzdXJ2aXZlIHRoZSBiYXR0bGVzIGJlbG93LFxuICAgICAqIGFuZCB0aGV5IG11c3QgYmUgdHJhaW5lZCBhbmQgcmVhZHkgZm9yIHRoZSBncnVlbGxpbmcgam91cm5leSBhaGVhZC5cbiAgICAgKiBNYW55IGEgc291bCBoYXMgdHJpZWQgdG8gYmVzdCB0aGVzZSBEcmFnb25zLCB5ZXQgb25seSBvbmUgaGFzXG4gICAgICogc3VjY2VlZGVkIHNpbmNlIG91ciBmb3VuZGluZy5cbiAgICAgKlxuICAgICAqIFRMO0RSIC0tIERvbid0IG1lc3Mgd2l0aCB0aGlzIHVubGVzcyB5b3Uga25vdyB3aGF0IHlvdSdyZSBkb2luZy5cbiAgICAgKiAgICAgVGhpcyBpcyBjZW50cmFsIHRvIGEgdG9uIG9mIG1vdmluZyBwYXJ0cyAtLSBicmVha2luZyBpdCB3aWxsXG4gICAgICogICAgIGNhdXNlIG1vcmUgY29sbGF0ZXJhbCBkYW1hZ2UgdGhhbiB5b3UgbWF5IHJlYWxpemUuXG4gICAgICovXG5cbiAgICBwcml2YXRlIF9pZDogc3RyaW5nO1xuICAgIHByaXZhdGUgb3JpZ2luYWxJZDogc3RyaW5nO1xuICAgIC8qKlxuICAgICAqIFRoZSBpZCBvZiB0aGUgY29tcG9uZW50IHRoYXQgd2lsbCBiZSBsYXp5IGxvYWRlZFxuICAgICAqL1xuICAgIEBJbnB1dChcImNvbXBvbmVudFwiKSBzZXQgaWQoZGF0YTogc3RyaW5nKSB7XG4gICAgICAgIHRoaXMub3JpZ2luYWxJZCA9IGRhdGE7XG4gICAgICAgIGNvbnN0IGlkID0gc3RyaW5nVG9TbHVnKGRhdGEpO1xuXG4gICAgICAgIC8vIENoZWNrIGlmIHRoZXJlIGlzIGEgY2hhbmdlIHRvIHRoZSBsb2FkZWQgY29tcG9uZW50J3MgaWRcbiAgICAgICAgLy8gaWYgaXQncyB1cGRhdGVkLCB3ZSBkZXN0cm95IGFuZCByZWh5ZHJhdGUgdGhlIGVudGlyZSBjb250YWluZXJcbiAgICAgICAgaWYgKHRoaXMuaW5pdGlhbGl6ZWQgJiYgdGhpcy5faWQgIT0gaWQpIHtcbiAgICAgICAgICAgIHRoaXMuX2lkID0gaWQ7XG4gICAgICAgICAgICB0aGlzLm5nQWZ0ZXJWaWV3SW5pdCgpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5faWQgPSBpZDtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICBwcml2YXRlIF9ncm91cCA9IFwiZGVmYXVsdFwiO1xuICAgIHByaXZhdGUgb3JpZ2luYWxHcm91cDogc3RyaW5nO1xuICAgIEBJbnB1dChcImdyb3VwXCIpIHNldCBncm91cChkYXRhOiBzdHJpbmcpIHtcbiAgICAgICAgdGhpcy5vcmlnaW5hbEdyb3VwID0gZGF0YTtcbiAgICAgICAgY29uc3QgZ3JvdXAgPSBzdHJpbmdUb1NsdWcoZGF0YSk7XG5cbiAgICAgICAgaWYgKHR5cGVvZiBncm91cCAhPSBcInN0cmluZ1wiIHx8ICFncm91cCkgcmV0dXJuO1xuXG4gICAgICAgIC8vIElmIHRoZSBncm91cCB3YXMgdXBkYXRlZCwgcmV0cnkgdG8gYm9vdHN0cmFwIHNvbWV0aGluZyBpbnRvIHRoZSBjb250YWluZXIuXG4gICAgICAgIGlmICh0aGlzLmluaXRpYWxpemVkICYmIHRoaXMuX2dyb3VwICE9IGdyb3VwKSB7XG4gICAgICAgICAgICB0aGlzLl9ncm91cCA9IGdyb3VwO1xuXG4gICAgICAgICAgICB0aGlzLm5nQWZ0ZXJWaWV3SW5pdCgpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5fZ3JvdXAgPSBncm91cDtcbiAgICB9XG4gICAgZ2V0IGdyb3VwKCkgeyByZXR1cm4gdGhpcy5fZ3JvdXAgfVxuXG4gICAgcHJpdmF0ZSBfbWF0Y2hHcm91cHM6IHsgW2tleTogc3RyaW5nXTogc3RyaW5nIH07XG4gICAgcHJpdmF0ZSBfaW5wdXRzOiB7IFtrZXk6IHN0cmluZ106IGFueTsgfTtcbiAgICAvKipcbiAgICAgKiBBIG1hcCBvZiBpbnB1dHMgdG8gYmluZCB0byB0aGUgY2hpbGQuXG4gICAgICogU3VwcG9ydHMgY2hhbmdlIGRldGVjdGlvbi4gKE1heSBmYWlsIG9uIGRlZXAgSlNPTiBjaGFuZ2VzKVxuICAgICAqXG4gICAgICogYGBgaHRtbFxuICAgICAqIDxsYXp5LWxvYWRlciBjb21wb25lbnQ9XCJNeUxhenlDb21wb25lbnRcIlxuICAgICAqICAgICAgIFtpbnB1dHNdPVwie1xuICAgICAqICAgICAgICAgIHByb3AxOiB0cnVlLFxuICAgICAqICAgICAgICAgIHByb3AyOiBmYWxzZSxcbiAgICAgKiAgICAgICAgICBjb21wbGV4OiB7XG4gICAgICogICAgICAgICAgICAgIGE6IHRydWUsXG4gICAgICogICAgICAgICAgICAgIGI6IDBcbiAgICAgKiAgICAgICAgICB9XG4gICAgICogICAgICAgfVwiXG4gICAgICogPlxuICAgICAqIDwvbGF6eS1sb2FkZXI+XG4gICAgICogYGBgXG4gICAgICovXG4gICAgQElucHV0KFwiaW5wdXRzXCIpIHNldCBpbnB1dHMoZGF0YTogeyBba2V5OiBzdHJpbmddOiBhbnk7IH0pIHtcbiAgICAgICAgaWYgKGRhdGEgPT0gdW5kZWZpbmVkKSByZXR1cm47XG5cbiAgICAgICAgbGV0IHByZXZpb3VzID0gdGhpcy5faW5wdXRzO1xuICAgICAgICB0aGlzLl9pbnB1dHMgPSBkYXRhO1xuICAgICAgICBpZiAoZGF0YSA9PSB1bmRlZmluZWQpXG4gICAgICAgICAgICBjb25zb2xlLnRyYWNlKGRhdGEpO1xuXG4gICAgICAgIGlmICh0aGlzLnRhcmdldENvbXBvbmVudEZhY3RvcnkpIHtcbiAgICAgICAgICAgIGNvbnN0IHsgaW5wdXRzIH0gPSB0aGlzLnRhcmdldENvbXBvbmVudEZhY3RvcnkuybVjbXA7XG5cbiAgICAgICAgICAgIGNvbnN0IGN1cnJlbnRLZXlzID0gT2JqZWN0LmtleXMoaW5wdXRzKTtcblxuICAgICAgICAgICAgY29uc3Qgb2xkS2V5cyA9IE9iamVjdC5rZXlzKHByZXZpb3VzKS5maWx0ZXIoa2V5ID0+IGN1cnJlbnRLZXlzLmluY2x1ZGVzKGtleSkpO1xuICAgICAgICAgICAgY29uc3QgbmV3S2V5cyA9IE9iamVjdC5rZXlzKGRhdGEpLmZpbHRlcihrZXkgPT4gY3VycmVudEtleXMuaW5jbHVkZXMoa2V5KSk7XG5cbiAgICAgICAgICAgIGNvbnN0IHJlbW92ZWQgPSBvbGRLZXlzLmZpbHRlcihrZXkgPT4gIW5ld0tleXMuaW5jbHVkZXMoa2V5KSk7XG5cbiAgICAgICAgICAgIC8vID8gcGVyaGFwcyBzZXQgdG8gbnVsbCBvciB1bmRlZmluZWQgaW5zdGVhZFxuICAgICAgICAgICAgcmVtb3ZlZC5mb3JFYWNoKGsgPT4gdGhpcy50YXJnZXRDb21wb25lbnRJbnN0YW5jZVtrXSA9IG51bGwpO1xuXG4gICAgICAgICAgICB0aGlzLmJpbmRJbnB1dHMoKTtcbiAgICAgICAgfVxuICAgIH1cblxuXG4gICAgcHJpdmF0ZSBvdXRwdXRTdWJzY3JpcHRpb25zOiB7IFtrZXk6IHN0cmluZ106IFN1YnNjcmlwdGlvbjsgfSA9IHt9O1xuICAgIHByaXZhdGUgX291dHB1dHM6IHsgW2tleTogc3RyaW5nXTogRnVuY3Rpb247IH07XG4gICAgLyoqXG4gICAgICogQSBtYXAgb2Ygb3V0cHV0cyB0byBiaW5kIGZyb20gdGhlIGNoaWxkLlxuICAgICAqIFNob3VsZCBzdXBwb3J0IGNoYW5nZSBkZXRlY3Rpb24uXG4gICAgICogYGBgaHRtbFxuICAgICAqIDxsYXp5LWxvYWRlciBjb21wb25lbnQ9XCJNeUxhenlDb21wb25lbnRcIlxuICAgICAqICAgICAgIFtvdXRwdXRzXT1cIntcbiAgICAgKiAgICAgICAgICAgcHJvcDM6IG9uT3V0cHV0RmlyZVxuICAgICAqICAgICAgIH1cIlxuICAgICAqID5cbiAgICAgKiA8L2xhenktbG9hZGVyPlxuICAgICAqIGBgYFxuICAgICAqL1xuICAgIEBJbnB1dChcIm91dHB1dHNcIikgc2V0IG91dHB1dHMoZGF0YTogeyBba2V5OiBzdHJpbmddOiBGdW5jdGlvbjsgfSkge1xuICAgICAgICBsZXQgcHJldmlvdXMgPSB0aGlzLl9vdXRwdXRzO1xuICAgICAgICB0aGlzLl9vdXRwdXRzID0gZGF0YTtcblxuICAgICAgICBpZiAodGhpcy50YXJnZXRDb21wb25lbnRGYWN0b3J5KSB7XG4gICAgICAgICAgICBjb25zdCB7IGlucHV0cyB9ID0gdGhpcy50YXJnZXRDb21wb25lbnRGYWN0b3J5Lsm1Y21wO1xuXG4gICAgICAgICAgICBjb25zdCBjdXJyZW50S2V5cyA9IE9iamVjdC5rZXlzKGlucHV0cyk7XG4gICAgICAgICAgICBjb25zdCByZW1vdmVkID0gT2JqZWN0LmtleXMocHJldmlvdXMpLmZpbHRlcihrZXkgPT4gIWN1cnJlbnRLZXlzLmluY2x1ZGVzKGtleSkpO1xuXG4gICAgICAgICAgICByZW1vdmVkLmZvckVhY2goayA9PiB7XG4gICAgICAgICAgICAgICAgLy8gVW5zdWJzY3JpYmUgZnJvbSBvYnNlcnZhYmxlXG4gICAgICAgICAgICAgICAgdGhpcy5vdXRwdXRTdWJzY3JpcHRpb25zW2tdPy51bnN1YnNjcmliZSgpO1xuICAgICAgICAgICAgICAgIGRlbGV0ZSB0aGlzLnRhcmdldENvbXBvbmVudEluc3RhbmNlW2tdO1xuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIHRoaXMuYmluZE91dHB1dHMoKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEVtaXRzIGVycm9ycyBlbmNvdW50ZXJlZCB3aGVuIGxvYWRpbmcgY29tcG9uZW50c1xuICAgICAqL1xuICAgIEBPdXRwdXQoKSBjb21wb25lbnRMb2FkRXJyb3IgPSBuZXcgRXZlbnRFbWl0dGVyKCk7XG5cbiAgICAvKipcbiAgICAgKiBFbWl0cyB3aGVuIHRoZSBjb21wb25lbnQgaXMgZnVsbHkgY29uc3RydWN0ZWRcbiAgICAgKiBhbmQgaGFkIGl0J3MgaW5wdXRzIGFuZCBvdXRwdXRzIGJvdW5kXG4gICAgICogPiBiZWZvcmUgYE9uSW5pdGBcbiAgICAgKlxuICAgICAqIFJldHVybnMgdGhlIGFjdGl2ZSBjbGFzcyBpbnN0YW5jZSBvZiB0aGUgbGF6eS1sb2FkZWQgY29tcG9uZW50XG4gICAgICovXG4gICAgQE91dHB1dCgpIGNvbXBvbmVudExvYWRlZCA9IG5ldyBFdmVudEVtaXR0ZXIoKTtcblxuXG4gICAgLyoqXG4gICAgICogVGhpcyBpcyBhbiBpbnN0YW5jZSBvZiB0aGUgY29tcG9uZW50IHRoYXQgaXMgY3VycmVudGx5IGxvYWRlZC5cbiAgICAgKi9cbiAgICBwdWJsaWMgaW5zdGFuY2U6IGFueTtcblxuXG4gICAgLyoqXG4gICAgICogQ29udGFpbmVyIHRoYXQgcHJvdmlkZXMgdGhlIGNvbXBvbmVudCBkYXRhXG4gICAgICovXG4gICAgcHJpdmF0ZSB0YXJnZXRNb2R1bGU6IENvbXBpbGVkQnVuZGxlO1xuXG4gICAgLyoqXG4gICAgICogQ29tcG9uZW50IGRlZmluaXRpb25cbiAgICAgKi9cbiAgICBwcml2YXRlIHRhcmdldENvbXBvbmVudEZhY3Rvcnk6IGFueTtcblxuICAgIC8qKlxuICAgICAqIEFjdGl2ZSBjb21wb25lbnQgY29udGFpbmVyIHJlZmVyZW5jZVxuICAgICAqL1xuICAgIHByaXZhdGUgdGFyZ2V0Q29tcG9uZW50Q29udGFpbmVyUmVmOiBDb21wb25lbnRSZWY8YW55PjtcbiAgICBwcml2YXRlIHRhcmdldFJlZjogYW55O1xuICAgIC8qKlxuICAgICAqIFJlZmVyZW5jZSB0byB0aGUgY29tcG9uZW50IGNsYXNzIGluc3RhbmNlXG4gICAgICovXG4gICAgcHJpdmF0ZSB0YXJnZXRDb21wb25lbnRJbnN0YW5jZTogYW55O1xuXG4gICAgLyoqXG4gICAgICogU3Vic2NyaXB0aW9uIHdpdGggdHJ1ZS9mYWxzZSBzdGF0ZSBvbiB3aGV0aGVyIHRoZSBkaXN0cmFjdG9yIHNob3VsZCBiZVxuICAgICAqL1xuICAgIHByaXZhdGUgZGlzdHJhY3RvclN1YnNjcmlwdGlvbjogU3Vic2NyaXB0aW9uO1xuXG4gICAgcHVibGljIGNvbmZpZzogTmd4TGF6eUxvYWRlckNvbmZpZztcbiAgICBwcml2YXRlIGVycjtcbiAgICBwcml2YXRlIHdhcm47XG4gICAgcHJpdmF0ZSBsb2c7XG5cbiAgICAvLyBGb3JjZSA1MDBtcyBkZWxheSBiZWZvcmUgcmV2ZWFsaW5nIHRoZSBzcGlubmVyXG4gICAgcHJpdmF0ZSBjbGVhckVtaXR0ZXIgPSBuZXcgRXZlbnRFbWl0dGVyKCk7XG4gICAgcHJpdmF0ZSBjbGVhckxvYWRlciQgPSB0aGlzLmNsZWFyRW1pdHRlci5waXBlKGRlYm91bmNlVGltZSgzMDApKTtcblxuICAgIHByaXZhdGUgc2hvd0VtaXR0ZXIgPSBuZXcgRXZlbnRFbWl0dGVyKCk7XG4gICAgcHJpdmF0ZSBzaG93TG9hZGVyJCA9IHRoaXMuc2hvd0VtaXR0ZXIucGlwZShkZWJvdW5jZVRpbWUoMSkpO1xuXG4gICAgcHJpdmF0ZSBzdWJzY3JpcHRpb25zID0gW1xuICAgICAgICB0aGlzLmNsZWFyTG9hZGVyJC5zdWJzY3JpYmUoKCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5pc0NsZWFyaW5nTG9hZGVyID0gdHJ1ZTtcblxuICAgICAgICAgICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgICAgICAgICAgdGhpcy5yZW5kZXJTcGlubmVyID0gZmFsc2U7XG4gICAgICAgICAgICB9LCAzMDApXG4gICAgICAgIH0pLFxuICAgICAgICB0aGlzLnNob3dMb2FkZXIkLnN1YnNjcmliZSgoKSA9PiB7XG4gICAgICAgICAgICB0aGlzLmlzQ2xlYXJpbmdMb2FkZXIgPSBmYWxzZTtcbiAgICAgICAgICAgIHRoaXMucmVuZGVyU3Bpbm5lciA9IHRydWU7XG4gICAgICAgIH0pXG4gICAgXTtcblxuICAgIHB1YmxpYyByZW5kZXJTcGlubmVyID0gdHJ1ZTsgLy8gd2hldGhlciB3ZSByZW5kZXIgdGhlIERPTSBmb3IgdGhlIHNwaW5uZXJcbiAgICBwdWJsaWMgaXNDbGVhcmluZ0xvYWRlciA9IGZhbHNlOyAvLyBzaG91bGQgdGhlIHNwaW5uZXIgc3RhcnQgZmFkaW5nIG91dFxuXG4gICAgY29uc3RydWN0b3IoXG4gICAgICAgIHByaXZhdGUgc2VydmljZTogTGF6eUxvYWRlclNlcnZpY2UsXG4gICAgICAgIEBPcHRpb25hbCgpIHByaXZhdGUgdmlld0NvbnRhaW5lclJlZjogVmlld0NvbnRhaW5lclJlZixcbiAgICAgICAgQE9wdGlvbmFsKCkgcHVibGljIGRpYWxvZzogRGlhbG9nUmVmLFxuICAgICAgICBAT3B0aW9uYWwoKSBASW5qZWN0KE1BVF9ESUFMT0dfREFUQSkgcHVibGljIGRpYWxvZ0FyZ3VtZW50c1xuICAgICkge1xuICAgICAgICB0aGlzLmNvbmZpZyA9IExhenlMb2FkZXJTZXJ2aWNlLmNvbmZpZztcbiAgICAgICAgdGhpcy5lcnIgPSBMYXp5TG9hZGVyU2VydmljZS5jb25maWcubG9nZ2VyLmVycjtcbiAgICAgICAgdGhpcy53YXJuID0gTGF6eUxvYWRlclNlcnZpY2UuY29uZmlnLmxvZ2dlci53YXJuO1xuICAgICAgICB0aGlzLmxvZyA9IExhenlMb2FkZXJTZXJ2aWNlLmNvbmZpZy5sb2dnZXIubG9nO1xuXG4gICAgICAgIC8vIEZpcnN0LCBjaGVjayBmb3IgZGlhbG9nIGFyZ3VtZW50c1xuICAgICAgICBpZiAodGhpcy5kaWFsb2dBcmd1bWVudHMpIHtcbiAgICAgICAgICAgIHRoaXMuaW5wdXRzID0gdGhpcy5kaWFsb2dBcmd1bWVudHMuaW5wdXRzIHx8IHRoaXMuZGlhbG9nQXJndW1lbnRzLmRhdGE7XG4gICAgICAgICAgICB0aGlzLm91dHB1dHMgPSB0aGlzLmRpYWxvZ0FyZ3VtZW50cy5vdXRwdXRzO1xuICAgICAgICAgICAgdGhpcy5pZCA9IHRoaXMuZGlhbG9nQXJndW1lbnRzLmlkO1xuICAgICAgICAgICAgdGhpcy5ncm91cCA9IHRoaXMuZGlhbG9nQXJndW1lbnRzLmdyb3VwO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBpbml0aWFsaXplZCA9IGZhbHNlO1xuICAgIGFzeW5jIG5nQWZ0ZXJWaWV3SW5pdCgpIHtcbiAgICAgICAgdGhpcy5uZ09uRGVzdHJveShmYWxzZSk7XG4gICAgICAgIHRoaXMuaXNDbGVhcmluZ0xvYWRlciA9IGZhbHNlO1xuICAgICAgICB0aGlzLnJlbmRlclNwaW5uZXIgPSB0cnVlO1xuICAgICAgICB0aGlzLmluaXRpYWxpemVkID0gdHJ1ZTtcblxuICAgICAgICBpZiAoIXRoaXMuX2lkKSB7XG4gICAgICAgICAgICB0aGlzLndhcm4oXCJObyBjb21wb25lbnQgd2FzIHNwZWNpZmllZCFcIik7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5sb2FkRGVmYXVsdCgpO1xuICAgICAgICB9XG5cbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGNvbnN0IF9lbnRyeSA9IHRoaXMuc2VydmljZS5yZXNvbHZlUmVnaXN0cmF0aW9uRW50cnkodGhpcy5vcmlnaW5hbElkLCB0aGlzLm9yaWdpbmFsR3JvdXApO1xuICAgICAgICAgICAgaWYgKCFfZW50cnkgfHwgIV9lbnRyeS5lbnRyeSkge1xuICAgICAgICAgICAgICAgIHRoaXMuZXJyKGBGYWlsZWQgdG8gZmluZCBDb21wb25lbnQgJyR7dGhpcy5faWR9JyBpbiBncm91cCAnJHt0aGlzLl9ncm91cH0nIGluIHJlZ2lzdHJ5IWApO1xuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLmxvYWREZWZhdWx0KCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGNvbnN0IHsgZW50cnksIG1hdGNoR3JvdXBzIH0gPSBfZW50cnk7XG4gICAgICAgICAgICB0aGlzLl9tYXRjaEdyb3VwcyA9IG1hdGNoR3JvdXBzO1xuXG4gICAgICAgICAgICAvLyBEb3dubG9hZCB0aGUgXCJtb2R1bGVcIiAodGhlIHN0YW5kYWxvbmUgY29tcG9uZW50KVxuICAgICAgICAgICAgY29uc3QgYnVuZGxlOiBDb21waWxlZEJ1bmRsZSA9IHRoaXMudGFyZ2V0TW9kdWxlID0gYXdhaXQgZW50cnkubG9hZCgpO1xuXG5cbiAgICAgICAgICAgIC8vIENoZWNrIGlmIHRoZXJlIGlzIHNvbWUgY29ycnVwdGlvbiBvbiB0aGUgYnVuZGxlLlxuICAgICAgICAgICAgaWYgKCFidW5kbGUgfHwgdHlwZW9mIGJ1bmRsZSAhPSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgICAgIHRoaXMuZXJyKGBGYWlsZWQgdG8gbG9hZCBjb21wb25lbnQvbW9kdWxlIGZvciAnJHt0aGlzLl9pZH0nISBQYXJzZWQgcmVzb3VyY2UgaXMgaW52YWxpZC5gKTtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5sb2FkRXJyb3IoKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgY29uc3QgbW9kdWxlcyA9IE9iamVjdC5rZXlzKGJ1bmRsZSlcbiAgICAgICAgICAgICAgICAubWFwKGsgPT4ge1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBlbnRyeSA9IGJ1bmRsZVtrXTtcblxuICAgICAgICAgICAgICAgICAgICAvLyBTdHJpY3RseSBjaGVjayBmb3IgZXhwb3J0ZWQgbW9kdWxlcyBvciBzdGFuZGFsb25lIGNvbXBvbmVudHNcbiAgICAgICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBlbnRyeSA9PSBcImZ1bmN0aW9uXCIgJiYgdHlwZW9mIGVudHJ5W1wiybVmYWNcIl0gPT0gXCJmdW5jdGlvblwiKVxuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGVudHJ5O1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgIC5maWx0ZXIoZSA9PiBlICE9IG51bGwpXG4gICAgICAgICAgICAgICAgLmZpbHRlcihlbnRyeSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGVudHJ5WydfaXNNb2R1bGUnXSA9ICEhZW50cnlbJ8m1bW9kJ107IC8vIG1vZHVsZVxuICAgICAgICAgICAgICAgICAgICBlbnRyeVsnX2lzQ29tcG9uZW50J10gPSAhIWVudHJ5WyfJtWNtcCddOyAvLyBjb21wb25lbnRcblxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gKGVudHJ5WydfaXNNb2R1bGUnXSB8fCBlbnRyeVsnX2lzQ29tcG9uZW50J10pO1xuICAgICAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICBpZiAobW9kdWxlcy5sZW5ndGggPT0gMCkge1xuICAgICAgICAgICAgICAgIHRoaXMuZXJyKGBDb21wb25lbnQvTW9kdWxlIGxvYWRlZCBmb3IgJyR7dGhpcy5faWR9JyBoYXMgbm8gZXhwb3J0ZWQgY29tcG9uZW50cyBvciBtb2R1bGVzIWApO1xuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLmxvYWRFcnJvcigpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBjb25zdCBjb21wb25lbnQgPSB0aGlzLnRhcmdldENvbXBvbmVudEZhY3RvcnkgPSB0aGlzLnNlcnZpY2UucmVzb2x2ZUNvbXBvbmVudCh0aGlzLl9pZCwgXCJkZWZhdWx0XCIsIG1vZHVsZXMpO1xuXG4gICAgICAgICAgICBpZiAoIWNvbXBvbmVudCkge1xuICAgICAgICAgICAgICAgIHRoaXMuZXJyKGBDb21wb25lbnQgJyR7dGhpcy5faWR9JyBpcyBpbnZhbGlkIG9yIGNvcnJ1cHRlZCFgKTtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5sb2FkRXJyb3IoKTtcbiAgICAgICAgICAgIH1cblxuXG4gICAgICAgICAgICAvLyBjb25zdCBjb21wb25lbnRSZWYgPSB0aGlzLnRhcmdldENvbXBvbmVudENvbnRhaW5lclJlZiA9IGNyZWF0ZUNvbXBvbmVudChjb21wb25lbnQgYXMgYW55LCB7XG4gICAgICAgICAgICAvLyAgICAgZW52aXJvbm1lbnRJbmplY3RvcjogdGhpcy5hcHBSZWYuaW5qZWN0b3IsXG4gICAgICAgICAgICAvLyAgICAgZWxlbWVudEluamVjdG9yOiB0aGlzLmluamVjdG9yLFxuICAgICAgICAgICAgLy8gICAgIGhvc3RFbGVtZW50OiB0aGlzLnZpZXdDb250YWluZXJSZWYuZWxlbWVudC5uYXRpdmVFbGVtZW50LFxuICAgICAgICAgICAgLy8gICAgIC8vIHByb2plY3RhYmxlTm9kZXM6XG4gICAgICAgICAgICAvLyB9KTtcbiAgICAgICAgICAgIC8vIC8vIHRoaXMudGFyZ2V0UmVmID0gdGhpcy50YXJnZXRDb250YWluZXIuaW5zZXJ0KHRoaXMudGFyZ2V0Q29tcG9uZW50Q29udGFpbmVyUmVmLmhvc3RWaWV3KTtcbiAgICAgICAgICAgIC8vIHRoaXMuYXBwUmVmLmF0dGFjaFZpZXcoY29tcG9uZW50UmVmLmhvc3RWaWV3KTtcblxuICAgICAgICAgICAgLy8gQm9vdHN0cmFwIHRoZSBjb21wb25lbnQgaW50byB0aGUgY29udGFpbmVyXG4gICAgICAgICAgICBjb25zdCBjb21wb25lbnRSZWYgPSB0aGlzLnRhcmdldENvbXBvbmVudENvbnRhaW5lclJlZiA9IHRoaXMudGFyZ2V0Q29udGFpbmVyLmNyZW