@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
149 lines • 26.4 kB
JavaScript
// © 2022 SolarWinds Worldwide, LLC. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import { ApplicationRef, ComponentFactoryResolver, Injectable, Injector, Optional, RendererFactory2, } from "@angular/core";
import { NavigationEnd, Router } from "@angular/router";
import cloneDeep from "lodash/cloneDeep";
import isFunction from "lodash/isFunction";
import { EMPTY, Observable, of, Subject } from "rxjs";
import { catchError, filter, switchMap, takeUntil } from "rxjs/operators";
import { LoggerService, uuid } from "@nova-ui/bits";
import { WidgetTypesService } from "../../services/widget-types.service";
import { ConfiguratorComponent } from "../components/configurator/configurator.component";
import * as i0 from "@angular/core";
import * as i1 from "../../services/widget-types.service";
import * as i2 from "@nova-ui/bits";
import * as i3 from "@angular/router";
export class ConfiguratorService {
constructor(componentFactoryResolver, widgetTypesService, injector, appRef, logger, rendererFactory, router) {
this.componentFactoryResolver = componentFactoryResolver;
this.widgetTypesService = widgetTypesService;
this.injector = injector;
this.appRef = appRef;
this.logger = logger;
this.router = router;
this.close$ = new Subject();
this.handleSubmit = (confSource, trySubmit) => (source) => source.pipe(this.trySubmit(trySubmit, confSource), this.updateDashboard(confSource.dashboardComponent));
this.trySubmit = (trySubmit, confSource) => (source) => source.pipe(
// eslint-disable-next-line import/no-deprecated
switchMap((widget) => {
if (widget && isFunction(trySubmit)) {
return trySubmit(widget, confSource).pipe(catchError((err) => {
this.logger.error(err);
this.componentRef.instance.handleSubmitError();
return EMPTY;
}));
}
else {
return of(widget);
}
}));
this.updateDashboard = (dashboardComponent) => (source) => new Observable((observer) => source.subscribe((widget) => {
if (widget) {
widget.id = widget.id || uuid();
let widgetToSet;
const dashboardWidget = dashboardComponent.dashboard.widgets[widget.id];
if (dashboardWidget) {
widgetToSet = {
...widget,
pizzagna: {
...this.widgetTypesService.getWidgetType(widget.type, widget.version).widget,
configuration: widget.pizzagna.configuration,
},
};
}
else {
widgetToSet = widget;
}
// first we remove the widget so that we can recreate it from scratch
dashboardComponent.removeWidget(widgetToSet.id, false /* this is set to preserve the widget location */);
// then we wait for the removal to take effect and we create the widget again
setTimeout(() => {
dashboardComponent.updateWidget(widgetToSet);
});
}
this.close();
observer.next();
}));
this.renderer = rendererFactory.createRenderer(null, null);
}
open(configurator) {
const source = {
dashboardComponent: configurator.dashboardComponent,
previewPizzagnaComponent: configurator.previewPizzagnaComponent,
widget: cloneDeep(configurator.widget),
};
this.componentRef = this.appendComponentToBody();
const component = this.componentRef.instance;
// TODO: Handle the case when portalBundle is undefined
// @ts-ignore
component.formPortal = configurator.portalBundle.portal;
// TODO: Handle the case when widget is undefined
// @ts-ignore
component.previewWidget = cloneDeep(configurator.widget);
if (configurator.portalBundle?.attached) {
component.formPortalAttached
.pipe(takeUntil(this.close$))
.subscribe((e) => {
if (configurator?.portalBundle?.attached) {
configurator?.portalBundle?.attached(e);
}
});
}
component.changeDetector.detectChanges();
return (component.result
.asObservable()
// TODO: Handle the case when trySubmit is undefined
// @ts-ignore
.pipe(this.handleSubmit(source, configurator.trySubmit)));
}
close() {
if (!this.renderer) {
return;
}
this.close$.next();
this.renderer.removeChild(document.body, this.componentRef.hostView
.rootNodes[0]);
this.appRef.detachView(this.componentRef.hostView);
this.componentRef.destroy();
this.renderer.removeStyle(document.body, "overflow");
}
appendComponentToBody() {
const factory = this.componentFactoryResolver.resolveComponentFactory(ConfiguratorComponent);
const componentRef = factory.create(this.injector);
this.appRef.attachView(componentRef.hostView);
this.renderer.appendChild(document.body, componentRef.hostView
.rootNodes[0]);
this.renderer.setStyle(document.body, "overflow", "hidden");
if (this.router) {
this.router.events
.pipe(filter((event) => event instanceof NavigationEnd), takeUntil(this.close$))
.subscribe(() => this.close());
}
return componentRef;
}
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ConfiguratorService, deps: [{ token: i0.ComponentFactoryResolver }, { token: i1.WidgetTypesService }, { token: i0.Injector }, { token: i0.ApplicationRef }, { token: i2.LoggerService }, { token: i0.RendererFactory2 }, { token: i3.Router, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
/** @nocollapse */ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ConfiguratorService }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ConfiguratorService, decorators: [{
type: Injectable
}], ctorParameters: () => [{ type: i0.ComponentFactoryResolver }, { type: i1.WidgetTypesService }, { type: i0.Injector }, { type: i0.ApplicationRef }, { type: i2.LoggerService }, { type: i0.RendererFactory2 }, { type: i3.Router, decorators: [{
type: Optional
}] }] });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uZmlndXJhdG9yLnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvbGliL2NvbmZpZ3VyYXRvci9zZXJ2aWNlcy9jb25maWd1cmF0b3Iuc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSx5REFBeUQ7QUFDekQsRUFBRTtBQUNGLCtFQUErRTtBQUMvRSw0RUFBNEU7QUFDNUUsOEVBQThFO0FBQzlFLCtFQUErRTtBQUMvRSw4RUFBOEU7QUFDOUUsNERBQTREO0FBQzVELEVBQUU7QUFDRiw2RUFBNkU7QUFDN0UsdURBQXVEO0FBQ3ZELEVBQUU7QUFDRiw2RUFBNkU7QUFDN0UsNEVBQTRFO0FBQzVFLCtFQUErRTtBQUMvRSwwRUFBMEU7QUFDMUUsaUZBQWlGO0FBQ2pGLDZFQUE2RTtBQUM3RSxpQkFBaUI7QUFFakIsT0FBTyxFQUNILGNBQWMsRUFDZCx3QkFBd0IsRUFHeEIsVUFBVSxFQUNWLFFBQVEsRUFDUixRQUFRLEVBRVIsZ0JBQWdCLEdBQ25CLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDeEQsT0FBTyxTQUFTLE1BQU0sa0JBQWtCLENBQUM7QUFDekMsT0FBTyxVQUFVLE1BQU0sbUJBQW1CLENBQUM7QUFDM0MsT0FBTyxFQUFFLEtBQUssRUFBRSxVQUFVLEVBQUUsRUFBRSxFQUFFLE9BQU8sRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUN0RCxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sRUFBRSxTQUFTLEVBQUUsU0FBUyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFFMUUsT0FBTyxFQUFFLGFBQWEsRUFBRSxJQUFJLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFNcEQsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0scUNBQXFDLENBQUM7QUFDekUsT0FBTyxFQUFFLHFCQUFxQixFQUFFLE1BQU0sbURBQW1E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USxDQUFDLElBQUksRUFDWixZQUFZLENBQUMsUUFBaUM7YUFDMUMsU0FBUyxDQUFDLENBQUMsQ0FBZ0IsQ0FDbkMsQ0FBQztRQUNGLElBQUksQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxJQUFJLEVBQUUsVUFBVSxFQUFFLFFBQVEsQ0FBQyxDQUFDO1FBQzVELElBQUksSUFBSSxDQUFDLE1BQU0sRUFBRTtZQUNiLElBQUksQ0FBQyxNQUFNLENBQUMsTUFBTTtpQkFDYixJQUFJLENBQ0QsTUFBTSxDQUFDLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxLQUFLLFlBQVksYUFBYSxDQUFDLEVBQ2pELFNBQVMsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQ3pCO2lCQUNBLFNBQVMsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsS0FBSyxFQUFFLENBQUMsQ0FBQztTQUN0QztRQUNELE9BQU8sWUFBWSxDQUFDO0lBQ3hCLENBQUM7a0lBdEtRLG1CQUFtQjtzSUFBbkIsbUJBQW1COzs0RkFBbkIsbUJBQW1CO2tCQUQvQixVQUFVOzswQkFhRixRQUFRIiwic291cmNlc0NvbnRlbnQiOlsiLy8gwqkgMjAyMiBTb2xhcldpbmRzIFdvcmxkd2lkZSwgTExDLiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuLy9cbi8vIFBlcm1pc3Npb24gaXMgaGVyZWJ5IGdyYW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkgcGVyc29uIG9idGFpbmluZyBhIGNvcHlcbi8vICBvZiB0aGlzIHNvZnR3YXJlIGFuZCBhc3NvY2lhdGVkIGRvY3VtZW50YXRpb24gZmlsZXMgKHRoZSBcIlNvZnR3YXJlXCIpLCB0b1xuLy8gIGRlYWwgaW4gdGhlIFNvZnR3YXJlIHdpdGhvdXQgcmVzdHJpY3Rpb24sIGluY2x1ZGluZyB3aXRob3V0IGxpbWl0YXRpb24gdGhlXG4vLyAgcmlnaHRzIHRvIHVzZSwgY29weSwgbW9kaWZ5LCBtZXJnZSwgcHVibGlzaCwgZGlzdHJpYnV0ZSwgc3VibGljZW5zZSwgYW5kL29yXG4vLyAgc2VsbCBjb3BpZXMgb2YgdGhlIFNvZnR3YXJlLCBhbmQgdG8gcGVybWl0IHBlcnNvbnMgdG8gd2hvbSB0aGUgU29mdHdhcmUgaXNcbi8vICBmdXJuaXNoZWQgdG8gZG8gc28sIHN1YmplY3QgdG8gdGhlIGZvbGxvd2luZyBjb25kaXRpb25zOlxuLy9cbi8vIFRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlIGFuZCB0aGlzIHBlcm1pc3Npb24gbm90aWNlIHNoYWxsIGJlIGluY2x1ZGVkIGluXG4vLyAgYWxsIGNvcGllcyBvciBzdWJzdGFudGlhbCBwb3J0aW9ucyBvZiB0aGUgU29mdHdhcmUuXG4vL1xuLy8gVEhFIFNPRlRXQVJFIElTIFBST1ZJREVEIFwiQVMgSVNcIiwgV0lUSE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCwgRVhQUkVTUyBPUlxuLy8gIElNUExJRUQsIElOQ0xVRElORyBCVVQgTk9UIExJTUlURUQgVE8gVEhFIFdBUlJBTlRJRVMgT0YgTUVSQ0hBTlRBQklMSVRZLFxuLy8gIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFIEFORCBOT05JTkZSSU5HRU1FTlQuIElOIE5PIEVWRU5UIFNIQUxMIFRIRVxuLy8gIEFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERFUlMgQkUgTElBQkxFIEZPUiBBTlkgQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVJcbi8vICBMSUFCSUxJVFksIFdIRVRIRVIgSU4gQU4gQUNUSU9OIE9GIENPTlRSQUNULCBUT1JUIE9SIE9USEVSV0lTRSwgQVJJU0lORyBGUk9NLFxuLy8gIE9VVCBPRiBPUiBJTiBDT05ORUNUSU9OIFdJVEggVEhFIFNPRlRXQVJFIE9SIFRIRSBVU0UgT1IgT1RIRVIgREVBTElOR1MgSU5cbi8vICBUSEUgU09GVFdBUkUuXG5cbmltcG9ydCB7XG4gICAgQXBwbGljYXRpb25SZWYsXG4gICAgQ29tcG9uZW50RmFjdG9yeVJlc29sdmVyLFxuICAgIENvbXBvbmVudFJlZixcbiAgICBFbWJlZGRlZFZpZXdSZWYsXG4gICAgSW5qZWN0YWJsZSxcbiAgICBJbmplY3RvcixcbiAgICBPcHRpb25hbCxcbiAgICBSZW5kZXJlcjIsXG4gICAgUmVuZGVyZXJGYWN0b3J5Mixcbn0gZnJvbSBcIkBhbmd1bGFyL2NvcmVcIjtcbmltcG9ydCB7IE5hdmlnYXRpb25FbmQsIFJvdXRlciB9IGZyb20gXCJAYW5ndWxhci9yb3V0ZXJcIjtcbmltcG9ydCBjbG9uZURlZXAgZnJvbSBcImxvZGFzaC9jbG9uZURlZXBcIjtcbmltcG9ydCBpc0Z1bmN0aW9uIGZyb20gXCJsb2Rhc2gvaXNGdW5jdGlvblwiO1xuaW1wb3J0IHsgRU1QVFksIE9ic2VydmFibGUsIG9mLCBTdWJqZWN0IH0gZnJvbSBcInJ4anNcIjtcbmltcG9ydCB7IGNhdGNoRXJyb3IsIGZpbHRlciwgc3dpdGNoTWFwLCB0YWtlVW50aWwgfSBmcm9tIFwicnhqcy9vcGVyYXRvcnNcIjtcblxuaW1wb3J0IHsgTG9nZ2VyU2VydmljZSwgdXVpZCB9IGZyb20gXCJAbm92YS11aS9iaXRzXCI7XG5cbmltcG9ydCB7IElDb25maWd1cmF0b3IsIElDb25maWd1cmF0b3JTb3VyY2UgfSBmcm9tIFwiLi90eXBlc1wiO1xuaW1wb3J0IHsgRGFzaGJvYXJkQ29tcG9uZW50IH0gZnJvbSBcIi4uLy4uL2NvbXBvbmVudHMvZGFzaGJvYXJkL2Rhc2hib2FyZC5jb21wb25lbnRcIjtcbmltcG9ydCB7IElXaWRnZXQgfSBmcm9tIFwiLi4vLi4vY29tcG9uZW50cy93aWRnZXQvdHlwZXNcIjtcbmltcG9ydCB7IFdpZGdldFVwZGF0ZU9wZXJhdGlvbiB9IGZyb20gXCIuLi8uLi9jb25maWd1cmF0b3Ivc2VydmljZXMvdHlwZXNcIjtcbmltcG9ydCB7IFdpZGdldFR5cGVzU2VydmljZSB9IGZyb20gXCIuLi8uLi9zZXJ2aWNlcy93aWRnZXQtdHlwZXMuc2VydmljZVwiO1xuaW1wb3J0IHsgQ29uZmlndXJhdG9yQ29tcG9uZW50IH0gZnJvbSBcIi4uL2NvbXBvbmVudHMvY29uZmlndXJhdG9yL2NvbmZpZ3VyYXRvci5jb21wb25lbnRcIjtcblxuQEluamVjdGFibGUoKVxuZXhwb3J0IGNsYXNzIENvbmZpZ3VyYXRvclNlcnZpY2Uge1xuICAgIHByaXZhdGUgcmVuZGVyZXI6IFJlbmRlcmVyMjtcbiAgICBwcml2YXRlIGNvbXBvbmVudFJlZjogQ29tcG9uZW50UmVmPENvbmZpZ3VyYXRvckNvbXBvbmVudD47XG4gICAgcHJpdmF0ZSBjbG9zZSQ6IFN1YmplY3Q8dm9pZD4gPSBuZXcgU3ViamVjdDx2b2lkPigpO1xuXG4gICAgY29uc3RydWN0b3IoXG4gICAgICAgIHByaXZhdGUgY29tcG9uZW50RmFjdG9yeVJlc29sdmVyOiBDb21wb25lbnRGYWN0b3J5UmVzb2x2ZXIsXG4gICAgICAgIHByaXZhdGUgd2lkZ2V0VHlwZXNTZXJ2aWNlOiBXaWRnZXRUeXBlc1NlcnZpY2UsXG4gICAgICAgIHByaXZhdGUgaW5qZWN0b3I6IEluamVjdG9yLFxuICAgICAgICBwcml2YXRlIGFwcFJlZjogQXBwbGljYXRpb25SZWYsXG4gICAgICAgIHByaXZhdGUgbG9nZ2VyOiBMb2dnZXJTZXJ2aWNlLFxuICAgICAgICByZW5kZXJlckZhY3Rvcnk6IFJlbmRlcmVyRmFjdG9yeTIsXG4gICAgICAgIEBPcHRpb25hbCgpIHByaXZhdGUgcm91dGVyOiBSb3V0ZXJcbiAgICApIHtcbiAgICAgICAgdGhpcy5yZW5kZXJlciA9IHJlbmRlcmVyRmFjdG9yeS5jcmVhdGVSZW5kZXJlcihudWxsLCBudWxsKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgb3Blbihjb25maWd1cmF0b3I6IElDb25maWd1cmF0b3IpOiBPYnNlcnZhYmxlPHZvaWQ+IHtcbiAgICAgICAgY29uc3Qgc291cmNlOiBJQ29uZmlndXJhdG9yU291cmNlID0ge1xuICAgICAgICAgICAgZGFzaGJvYXJkQ29tcG9uZW50OiBjb25maWd1cmF0b3IuZGFzaGJvYXJkQ29tcG9uZW50LFxuICAgICAgICAgICAgcHJldmlld1BpenphZ25hQ29tcG9uZW50OiBjb25maWd1cmF0b3IucHJldmlld1BpenphZ25hQ29tcG9uZW50LFxuICAgICAgICAgICAgd2lkZ2V0OiBjbG9uZURlZXAoY29uZmlndXJhdG9yLndpZGdldCksXG4gICAgICAgIH07XG5cbiAgICAgICAgdGhpcy5jb21wb25lbnRSZWYgPSB0aGlzLmFwcGVuZENvbXBvbmVudFRvQm9keSgpO1xuICAgICAgICBjb25zdCBjb21wb25lbnQ6IENvbmZpZ3VyYXRvckNvbXBvbmVudCA9IHRoaXMuY29tcG9uZW50UmVmLmluc3RhbmNlO1xuXG4gICAgICAgIC8vIFRPRE86IEhhbmRsZSB0aGUgY2FzZSB3aGVuIHBvcnRhbEJ1bmRsZSBpcyB1bmRlZmluZWRcbiAgICAgICAgLy8gQHRzLWlnbm9yZVxuICAgICAgICBjb21wb25lbnQuZm9ybVBvcnRhbCA9IGNvbmZpZ3VyYXRvci5wb3J0YWxCdW5kbGUucG9ydGFsO1xuICAgICAgICAvLyBUT0RPOiBIYW5kbGUgdGhlIGNhc2Ugd2hlbiB3aWRnZXQgaXMgdW5kZWZpbmVkXG4gICAgICAgIC8vIEB0cy1pZ25vcmVcbiAgICAgICAgY29tcG9uZW50LnByZXZpZXdXaWRnZXQgPSBjbG9uZURlZXAoY29uZmlndXJhdG9yLndpZGdldCk7XG4gICAgICAgIGlmIChjb25maWd1cmF0b3IucG9ydGFsQnVuZGxlPy5hdHRhY2hlZCkge1xuICAgICAgICAgICAgY29tcG9uZW50LmZvcm1Qb3J0YWxBdHRhY2hlZFxuICAgICAgICAgICAgICAgIC5waXBlKHRha2VVbnRpbCh0aGlzLmNsb3NlJCkpXG4gICAgICAgICAgICAgICAgLnN1YnNjcmliZSgoZSkgPT4ge1xuICAgICAgICAgICAgICAgICAgICBpZiAoY29uZmlndXJhdG9yPy5wb3J0YWxCdW5kbGU/LmF0dGFjaGVkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25maWd1cmF0b3I/LnBvcnRhbEJ1bmRsZT8uYXR0YWNoZWQoZSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbXBvbmVudC5jaGFuZ2VEZXRlY3Rvci5kZXRlY3RDaGFuZ2VzKCk7XG5cbiAgICAgICAgcmV0dXJuIChcbiAgICAgICAgICAgIGNvbXBvbmVudC5yZXN1bHRcbiAgICAgICAgICAgICAgICAuYXNPYnNlcnZhYmxlKClcbiAgICAgICAgICAgICAgICAvLyBUT0RPOiBIYW5kbGUgdGhlIGNhc2Ugd2hlbiB0cnlTdWJtaXQgaXMgdW5kZWZpbmVkXG4gICAgICAgICAgICAgICAgLy8gQHRzLWlnbm9yZVxuICAgICAgICAgICAgICAgIC5waXBlKHRoaXMuaGFuZGxlU3VibWl0KHNvdXJjZSwgY29uZmlndXJhdG9yLnRyeVN1Ym1pdCkpXG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgcHVibGljIGNsb3NlKCk6IHZvaWQge1xuICAgICAgICBpZiAoIXRoaXMucmVuZGVyZXIpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuY2xvc2UkLm5leHQoKTtcbiAgICAgICAgdGhpcy5yZW5kZXJlci5yZW1vdmVDaGlsZChcbiAgICAgICAgICAgIGRvY3VtZW50LmJvZHksXG4gICAgICAgICAgICAodGhpcy5jb21wb25lbnRSZWYuaG9zdFZpZXcgYXMgRW1iZWRkZWRWaWV3UmVmPGFueT4pXG4gICAgICAgICAgICAgICAgLnJvb3ROb2Rlc1swXSBhcyBIVE1MRWxlbWVudFxuICAgICAgICApO1xuICAgICAgICB0aGlzLmFwcFJlZi5kZXRhY2hWaWV3KHRoaXMuY29tcG9uZW50UmVmLmhvc3RWaWV3KTtcbiAgICAgICAgdGhpcy5jb21wb25lbnRSZWYuZGVzdHJveSgpO1xuXG4gICAgICAgIHRoaXMucmVuZGVyZXIucmVtb3ZlU3R5bGUoZG9jdW1lbnQuYm9keSwgXCJvdmVyZmxvd1wiKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgaGFuZGxlU3VibWl0ID1cbiAgICAgICAgKGNvbmZTb3VyY2U6IElDb25maWd1cmF0b3JTb3VyY2UsIHRyeVN1Ym1pdDogV2lkZ2V0VXBkYXRlT3BlcmF0aW9uKSA9PlxuICAgICAgICAoc291cmNlOiBPYnNlcnZhYmxlPElXaWRnZXQ+KTogT2JzZXJ2YWJsZTx2b2lkPiA9PlxuICAgICAgICAgICAgc291cmNlLnBpcGUoXG4gICAgICAgICAgICAgICAgdGhpcy50cnlTdWJtaXQodHJ5U3VibWl0LCBjb25mU291cmNlKSxcbiAgICAgICAgICAgICAgICB0aGlzLnVwZGF0ZURhc2hib2FyZChjb25mU291cmNlLmRhc2hib2FyZENvbXBvbmVudClcbiAgICAgICAgICAgICk7XG5cbiAgICBwcml2YXRlIHRyeVN1Ym1pdCA9XG4gICAgICAgICh0cnlTdWJtaXQ6IFdpZGdldFVwZGF0ZU9wZXJhdGlvbiwgY29uZlNvdXJjZTogSUNvbmZpZ3VyYXRvcikgPT5cbiAgICAgICAgKHNvdXJjZTogT2JzZXJ2YWJsZTxJV2lkZ2V0PikgPT5cbiAgICAgICAgICAgIHNvdXJjZS5waXBlKFxuICAgICAgICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBpbXBvcnQvbm8tZGVwcmVjYXRlZFxuICAgICAgICAgICAgICAgIHN3aXRjaE1hcCgod2lkZ2V0OiBJV2lkZ2V0KSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGlmICh3aWRnZXQgJiYgaXNGdW5jdGlvbih0cnlTdWJtaXQpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gdHJ5U3VibWl0KHdpZGdldCwgY29uZlNvdXJjZSkucGlwZShcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYXRjaEVycm9yKChlcnI6IGFueSkgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmxvZ2dlci5lcnJvcihlcnIpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmNvbXBvbmVudFJlZi5pbnN0YW5jZS5oYW5kbGVTdWJtaXRFcnJvcigpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gRU1QVFk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gb2Yod2lkZ2V0KTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICApO1xuXG4gICAgcHJpdmF0ZSB1cGRhdGVEYXNoYm9hcmQgPVxuICAgICAgICAoZGFzaGJvYXJkQ29tcG9uZW50OiBEYXNoYm9hcmRDb21wb25lbnQpID0+XG4gICAgICAgIChzb3VyY2U6IE9ic2VydmFibGU8SVdpZGdldD4pID0+XG4gICAgICAgICAgICBuZXcgT2JzZXJ2YWJsZTx2b2lkPigob2JzZXJ2ZXIpID0+XG4gICAgICAgICAgICAgICAgc291cmNlLnN1YnNjcmliZSgod2lkZ2V0OiBJV2lkZ2V0KSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGlmICh3aWRnZXQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHdpZGdldC5pZCA9IHdpZGdldC5pZCB8fCB1dWlkKCk7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIGxldCB3aWRnZXRUb1NldDogSVdpZGdldDtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IGRhc2hib2FyZFdpZGdldCA9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZGFzaGJvYXJkQ29tcG9uZW50LmRhc2hib2FyZC53aWRnZXRzW3dpZGdldC5pZF07XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoZGFzaGJvYXJkV2lkZ2V0KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgd2lkZ2V0VG9TZXQgPSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC4uLndpZGdldCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGl6emFnbmE6IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC4uLnRoaXMud2lkZ2V0VHlwZXNTZXJ2aWNlLmdldFdpZGdldFR5cGUoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd2lkZ2V0LnR5cGUsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd2lkZ2V0LnZlcnNpb25cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkud2lkZ2V0LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uZmlndXJhdGlvbjpcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3aWRnZXQucGl6emFnbmEuY29uZmlndXJhdGlvbixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB3aWRnZXRUb1NldCA9IHdpZGdldDtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gZmlyc3Qgd2UgcmVtb3ZlIHRoZSB3aWRnZXQgc28gdGhhdCB3ZSBjYW4gcmVjcmVhdGUgaXQgZnJvbSBzY3JhdGNoXG4gICAgICAgICAgICAgICAgICAgICAgICBkYXNoYm9hcmRDb21wb25lbnQucmVtb3ZlV2lkZ2V0KFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdpZGdldFRvU2V0LmlkLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZhbHNlIC8qIHRoaXMgaXMgc2V0IHRvIHByZXNlcnZlIHRoZSB3aWRnZXQgbG9jYXRpb24gKi9cbiAgICAgICAgICAgICAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHRoZW4gd2Ugd2FpdCBmb3IgdGhlIHJlbW92YWwgdG8gdGFrZSBlZmZlY3QgYW5kIHdlIGNyZWF0ZSB0aGUgd2lkZ2V0IGFnYWluXG4gICAgICAgICAgICAgICAgICAgICAgICBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXNoYm9hcmRDb21wb25lbnQudXBkYXRlV2lkZ2V0KHdpZGdldFRvU2V0KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgdGhpcy5jbG9zZSgpO1xuICAgICAgICAgICAgICAgICAgICBvYnNlcnZlci5uZXh0KCk7XG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICk7XG5cbiAgICBwcml2YXRlIGFwcGVuZENvbXBvbmVudFRvQm9keSgpOiBDb21wb25lbnRSZWY8Q29uZmlndXJhdG9yQ29tcG9uZW50PiB7XG4gICAgICAgIGNvbnN0IGZhY3RvcnkgPSB0aGlzLmNvbXBvbmVudEZhY3RvcnlSZXNvbHZlci5yZXNvbHZlQ29tcG9uZW50RmFjdG9yeShcbiAgICAgICAgICAgIENvbmZpZ3VyYXRvckNvbXBvbmVudFxuICAgICAgICApO1xuICAgICAgICBjb25zdCBjb21wb25lbnRSZWY6IENvbXBvbmVudFJlZjxDb25maWd1cmF0b3JDb21wb25lbnQ+ID1cbiAgICAgICAgICAgIGZhY3RvcnkuY3JlYXRlKHRoaXMuaW5qZWN0b3IpO1xuXG4gICAgICAgIHRoaXMuYXBwUmVmLmF0dGFjaFZpZXcoY29tcG9uZW50UmVmLmhvc3RWaWV3KTtcbiAgICAgICAgdGhpcy5yZW5kZXJlci5hcHBlbmRDaGlsZChcbiAgICAgICAgICAgIGRvY3VtZW50LmJvZHksXG4gICAgICAgICAgICAoY29tcG9uZW50UmVmLmhvc3RWaWV3IGFzIEVtYmVkZGVkVmlld1JlZjxhbnk+KVxuICAgICAgICAgICAgICAgIC5yb290Tm9kZXNbMF0gYXMgSFRNTEVsZW1lbnRcbiAgICAgICAgKTtcbiAgICAgICAgdGhpcy5yZW5kZXJlci5zZXRTdHlsZShkb2N1bWVudC5ib2R5LCBcIm92ZXJmbG93XCIsIFwiaGlkZGVuXCIpO1xuICAgICAgICBpZiAodGhpcy5yb3V0ZXIpIHtcbiAgICAgICAgICAgIHRoaXMucm91dGVyLmV2ZW50c1xuICAgICAgICAgICAgICAgIC5waXBlKFxuICAgICAgICAgICAgICAgICAgICBmaWx0ZXIoKGV2ZW50KSA9PiBldmVudCBpbnN0YW5jZW9mIE5hdmlnYXRpb25FbmQpLFxuICAgICAgICAgICAgICAgICAgICB0YWtlVW50aWwodGhpcy5jbG9zZSQpXG4gICAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgICAgIC5zdWJzY3JpYmUoKCkgPT4gdGhpcy5jbG9zZSgpKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gY29tcG9uZW50UmVmO1xuICAgIH1cbn1cbiJdfQ==