@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
175 lines • 28.2 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 { Directive, Inject, Input, } from "@angular/core";
import { Subject } from "rxjs";
import { takeUntil } from "rxjs/operators";
import { EventBus } from "@nova-ui/bits";
import { CHART_METRIC_REMOVE } from "../../../services/types";
import { PIZZAGNA_EVENT_BUS, WellKnownDataSourceFeatures, } from "../../../types";
import { metricsSeriesMeasurementsMinMax } from "../timeseries-helpers";
import { TimeseriesScalesService } from "../timeseries-scales.service";
import { TimeseriesChartPreset, } from "../types";
import * as i0 from "@angular/core";
import * as i1 from "@nova-ui/bits";
import * as i2 from "../timeseries-scales.service";
// eslint-disable-next-line @angular-eslint/directive-class-suffix
export class TimeseriesChartComponent {
get seriesInteractive() {
return (this.configuration?.interaction === "series" ||
this.dataSource?.features?.getFeatureConfig(WellKnownDataSourceFeatures.Interactivity)?.enabled ||
false);
}
constructor(eventBus, timeseriesScalesService, dataSource) {
this.eventBus = eventBus;
this.timeseriesScalesService = timeseriesScalesService;
this.dataSource = dataSource;
this.widgetData = {};
this.configuration = {};
this.scales = {};
this.destroy$ = new Subject();
this.buildChart$ = new Subject();
this.resetChart = false;
this.chartBuilt = false;
this.buildChart$.pipe(takeUntil(this.destroy$)).subscribe(() => {
this.chartBuilt = true;
});
}
ngOnInit() {
// save original data
if (this.configuration.preset === TimeseriesChartPreset.Line &&
this.widgetData &&
this.widgetData.series) {
this.widgetData.series.forEach((serie) => (serie.rawData = serie.data));
}
}
ngOnChanges(changes) {
let shouldUpdateChart = false;
let shouldRebuildChart = false;
if (changes.configuration) {
const configurationCurrent = changes.configuration.currentValue;
const configurationPrevious = changes.configuration.previousValue;
if (configurationCurrent?.preset !== configurationPrevious?.preset) {
shouldRebuildChart = true;
}
if (configurationCurrent?.scales !== configurationPrevious?.scales) {
const scaleKeys = Object.keys(configurationCurrent?.scales);
for (const scaleKey of scaleKeys) {
const scaleConfigCurrent = configurationCurrent?.scales?.[scaleKey];
const scaleConfigPrevious = configurationPrevious?.scales?.[scaleKey];
if (!scaleConfigCurrent) {
continue;
}
if (scaleConfigCurrent?.type !==
scaleConfigPrevious?.type ||
scaleConfigCurrent?.properties?.axisUnits !==
scaleConfigPrevious?.properties?.axisUnits) {
this.scales[scaleKey] =
this.timeseriesScalesService.getScale(scaleConfigCurrent, configurationCurrent.units, this.configuration);
shouldUpdateChart = true;
}
else if (scaleConfigCurrent?.properties !==
scaleConfigPrevious?.properties) {
this.timeseriesScalesService.updateConfiguration(this.scales[scaleKey], scaleConfigCurrent, this.configuration);
shouldUpdateChart = true;
}
}
}
}
if (shouldRebuildChart || !this.chartBuilt) {
this.buildChart();
}
if (changes.widgetData && !changes.widgetData.isFirstChange()) {
if (this.widgetData?.series?.length === 0) {
this.resetChart = true;
}
if (this.widgetData && this.widgetData.series) {
if (this.resetChart && this.widgetData?.series?.length > 0) {
this.resetChart = false;
this.buildChart();
}
this.applyPreviousTransformer(changes.widgetData.previousValue);
shouldUpdateChart = true;
}
}
if (shouldUpdateChart) {
this.updateChartData();
}
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
this.buildChart$.complete();
}
applyPreviousTransformer(previousData) {
// save original data and transform it
this.widgetData.series.forEach((serie) => {
serie.rawData = serie.data;
serie.transformer = previousData?.series.find((prevSerie) => prevSerie.id === serie.id)?.transformer;
this.transformSeriesData(serie);
});
}
transformSeriesData(serie) {
if (serie.transformer && serie.rawData && serie.rawData.length > 0) {
try {
const hasPercentile = serie.metricUnits === "percent";
serie.data = serie.transformer(serie.rawData, hasPercentile);
this.updateYAxisDomain();
}
catch (e) {
serie.transformer = undefined;
serie.data = serie.rawData;
console.error(e.message);
}
}
}
updateYAxisDomain() {
const scaleKeys = ["y", "yRight"];
for (const scaleKey of scaleKeys) {
const scaleConfig = this.configuration.scales?.[scaleKey];
if (scaleConfig?.properties) {
scaleConfig.properties.domain = {
...metricsSeriesMeasurementsMinMax(this.widgetData.series, scaleConfig?.properties?.axisUnits),
};
this.timeseriesScalesService.updateConfiguration(this.scales[scaleKey], scaleConfig, this.configuration);
}
}
}
removeMetric(metricId) {
this.eventBus.next(CHART_METRIC_REMOVE, {
payload: {
metricId: metricId,
groupUniqueId: this.configuration.groupUniqueId,
},
});
}
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TimeseriesChartComponent, deps: "invalid", target: i0.ɵɵFactoryTarget.Directive }); }
/** @nocollapse */ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: TimeseriesChartComponent, inputs: { widgetData: "widgetData", configuration: "configuration" }, usesOnChanges: true, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TimeseriesChartComponent, decorators: [{
type: Directive
}], ctorParameters: () => [{ type: i1.EventBus, decorators: [{
type: Inject,
args: [PIZZAGNA_EVENT_BUS]
}] }, { type: i2.TimeseriesScalesService }, { type: undefined }], propDecorators: { widgetData: [{
type: Input
}], configuration: [{
type: Input
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGltZXNlcmllcy1jaGFydC5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvbGliL2NvbXBvbmVudHMvdGltZXNlcmllcy13aWRnZXQvY2hhcnQtcHJlc2V0cy90aW1lc2VyaWVzLWNoYXJ0LmNvbXBvbmVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSx5REFBeUQ7QUFDekQsRUFBRTtBQUNGLCtFQUErRTtBQUMvRSw0RUFBNEU7QUFDNUUsOEVBQThFO0FBQzlFLCtFQUErRTtBQUMvRSw4RUFBOEU7QUFDOUUsNERBQTREO0FBQzVELEVBQUU7QUFDRiw2RUFBNkU7QUFDN0UsdURBQXVEO0FBQ3ZELEVBQUU7QUFDRiw2RUFBNkU7QUFDN0UsNEVBQTRFO0FBQzVFLCtFQUErRTtBQUMvRSwwRUFBMEU7QUFDMUUsaUZBQWlGO0FBQ2pGLDZFQUE2RTtBQUM3RSxpQkFBaUI7QUFFakIsT0FBTyxFQUNILFNBQVMsRUFDVCxNQUFNLEVBQ04sS0FBSyxHQUtSLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDL0IsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBRTNDLE9BQU8sRUFBRSxRQUFRLEVBQXVCLE1BQU0sZUFBZSxDQUFDO0FBRzlELE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQzlELE9BQU8sRUFDSCxrQkFBa0IsRUFDbEIsMkJBQTJCLEdBQzlCLE1BQU0sZ0JBQWdCLENBQUM7QUFDeEIsT0FBTyxFQUFFLCtCQUErQixFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFDeEUsT0FBTyxFQUFFLHVCQUF1QixFQUFFLE1BQU0sOEJBQThCLENBQUM7QUFDdkUsT0FBTyxFQU1ILHFCQUFxQixHQUN4QixNQUFNLFVBQVUsQ0FBQzs7OztBQUdsQixrRUFBa0U7QUFDbEUsTUFBTSxPQUFnQix3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O29HQXRCZCxVQUFVO3NCQUF6QixLQUFLO2dCQUVVLGFBQWE7c0JBQTVCLEtBQUsiLCJzb3VyY2VzQ29udGVudCI6WyIvLyDCqSAyMDIyIFNvbGFyV2luZHMgV29ybGR3aWRlLCBMTEMuIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4vL1xuLy8gUGVybWlzc2lvbiBpcyBoZXJlYnkgZ3JhbnRlZCwgZnJlZSBvZiBjaGFyZ2UsIHRvIGFueSBwZXJzb24gb2J0YWluaW5nIGEgY29weVxuLy8gIG9mIHRoaXMgc29mdHdhcmUgYW5kIGFzc29jaWF0ZWQgZG9jdW1lbnRhdGlvbiBmaWxlcyAodGhlIFwiU29mdHdhcmVcIiksIHRvXG4vLyAgZGVhbCBpbiB0aGUgU29mdHdhcmUgd2l0aG91dCByZXN0cmljdGlvbiwgaW5jbHVkaW5nIHdpdGhvdXQgbGltaXRhdGlvbiB0aGVcbi8vICByaWdodHMgdG8gdXNlLCBjb3B5LCBtb2RpZnksIG1lcmdlLCBwdWJsaXNoLCBkaXN0cmlidXRlLCBzdWJsaWNlbnNlLCBhbmQvb3Jcbi8vICBzZWxsIGNvcGllcyBvZiB0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJtaXQgcGVyc29ucyB0byB3aG9tIHRoZSBTb2Z0d2FyZSBpc1xuLy8gIGZ1cm5pc2hlZCB0byBkbyBzbywgc3ViamVjdCB0byB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6XG4vL1xuLy8gVGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMgcGVybWlzc2lvbiBub3RpY2Ugc2hhbGwgYmUgaW5jbHVkZWQgaW5cbi8vICBhbGwgY29waWVzIG9yIHN1YnN0YW50aWFsIHBvcnRpb25zIG9mIHRoZSBTb2Z0d2FyZS5cbi8vXG4vLyBUSEUgU09GVFdBUkUgSVMgUFJPVklERUQgXCJBUyBJU1wiLCBXSVRIT1VUIFdBUlJBTlRZIE9GIEFOWSBLSU5ELCBFWFBSRVNTIE9SXG4vLyAgSU1QTElFRCwgSU5DTFVESU5HIEJVVCBOT1QgTElNSVRFRCBUTyBUSEUgV0FSUkFOVElFUyBPRiBNRVJDSEFOVEFCSUxJVFksXG4vLyAgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UgQU5EIE5PTklORlJJTkdFTUVOVC4gSU4gTk8gRVZFTlQgU0hBTEwgVEhFXG4vLyAgQVVUSE9SUyBPUiBDT1BZUklHSFQgSE9MREVSUyBCRSBMSUFCTEUgRk9SIEFOWSBDTEFJTSwgREFNQUdFUyBPUiBPVEhFUlxuLy8gIExJQUJJTElUWSwgV0hFVEhFUiBJTiBBTiBBQ1RJT04gT0YgQ09OVFJBQ1QsIFRPUlQgT1IgT1RIRVJXSVNFLCBBUklTSU5HIEZST00sXG4vLyAgT1VUIE9GIE9SIElOIENPTk5FQ1RJT04gV0lUSCBUSEUgU09GVFdBUkUgT1IgVEhFIFVTRSBPUiBPVEhFUiBERUFMSU5HUyBJTlxuLy8gIFRIRSBTT0ZUV0FSRS5cblxuaW1wb3J0IHtcbiAgICBEaXJlY3RpdmUsXG4gICAgSW5qZWN0LFxuICAgIElucHV0LFxuICAgIE9uQ2hhbmdlcyxcbiAgICBPbkRlc3Ryb3ksXG4gICAgT25Jbml0LFxuICAgIFNpbXBsZUNoYW5nZXMsXG59IGZyb20gXCJAYW5ndWxhci9jb3JlXCI7XG5pbXBvcnQgeyBTdWJqZWN0IH0gZnJvbSBcInJ4anNcIjtcbmltcG9ydCB7IHRha2VVbnRpbCB9IGZyb20gXCJyeGpzL29wZXJhdG9yc1wiO1xuXG5pbXBvcnQgeyBFdmVudEJ1cywgSURhdGFTb3VyY2UsIElFdmVudCB9IGZyb20gXCJAbm92YS11aS9iaXRzXCI7XG5pbXBvcnQgeyBJWFlTY2FsZXMgfSBmcm9tIFwiQG5vdmEtdWkvY2hhcnRzXCI7XG5cbmltcG9ydCB7IENIQVJUX01FVFJJQ19SRU1PVkUgfSBmcm9tIFwiLi4vLi4vLi4vc2VydmljZXMvdHlwZXNcIjtcbmltcG9ydCB7XG4gICAgUElaWkFHTkFfRVZFTlRfQlVTLFxuICAgIFdlbGxLbm93bkRhdGFTb3VyY2VGZWF0dXJlcyxcbn0gZnJvbSBcIi4uLy4uLy4uL3R5cGVzXCI7XG5pbXBvcnQgeyBtZXRyaWNzU2VyaWVzTWVhc3VyZW1lbnRzTWluTWF4IH0gZnJvbSBcIi4uL3RpbWVzZXJpZXMtaGVscGVyc1wiO1xuaW1wb3J0IHsgVGltZXNlcmllc1NjYWxlc1NlcnZpY2UgfSBmcm9tIFwiLi4vdGltZXNlcmllcy1zY2FsZXMuc2VydmljZVwiO1xuaW1wb3J0IHtcbiAgICBJVGltZXNlcmllc091dHB1dCxcbiAgICBJVGltZXNlcmllc1NjYWxlc0NvbmZpZyxcbiAgICBJVGltZXNlcmllc1dpZGdldENvbmZpZyxcbiAgICBJVGltZXNlcmllc1dpZGdldERhdGEsXG4gICAgSVRpbWVzZXJpZXNXaWRnZXRTZXJpZXNEYXRhLFxuICAgIFRpbWVzZXJpZXNDaGFydFByZXNldCxcbn0gZnJvbSBcIi4uL3R5cGVzXCI7XG5cbkBEaXJlY3RpdmUoKVxuLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEBhbmd1bGFyLWVzbGludC9kaXJlY3RpdmUtY2xhc3Mtc3VmZml4XG5leHBvcnQgYWJzdHJhY3QgY2xhc3MgVGltZXNlcmllc0NoYXJ0Q29tcG9uZW50PFQgPSBJVGltZXNlcmllc1dpZGdldFNlcmllc0RhdGE+XG4gICAgaW1wbGVtZW50cyBPbkNoYW5nZXMsIE9uRGVzdHJveSwgT25Jbml0XG57XG4gICAgQElucHV0KCkgcHVibGljIHdpZGdldERhdGE6IElUaW1lc2VyaWVzT3V0cHV0PFQ+ID1cbiAgICAgICAge30gYXMgSVRpbWVzZXJpZXNPdXRwdXQ8VD47XG4gICAgQElucHV0KCkgcHVibGljIGNvbmZpZ3VyYXRpb246IElUaW1lc2VyaWVzV2lkZ2V0Q29uZmlnID1cbiAgICAgICAge30gYXMgSVRpbWVzZXJpZXNXaWRnZXRDb25maWc7XG5cbiAgICBwcm90ZWN0ZWQgc2NhbGVzOiBJWFlTY2FsZXMgPSB7fSBhcyBJWFlTY2FsZXM7XG4gICAgcHJvdGVjdGVkIGRlc3Ryb3kkID0gbmV3IFN1YmplY3Q8dm9pZD4oKTtcbiAgICBwcm90ZWN0ZWQgYnVpbGRDaGFydCQgPSBuZXcgU3ViamVjdDx2b2lkPigpO1xuICAgIHByb3RlY3RlZCByZXNldENoYXJ0ID0gZmFsc2U7XG4gICAgcHJvdGVjdGVkIGNoYXJ0QnVpbHQgPSBmYWxzZTtcblxuICAgIHB1YmxpYyBnZXQgc2VyaWVzSW50ZXJhY3RpdmUoKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiAoXG4gICAgICAgICAgICB0aGlzLmNvbmZpZ3VyYXRpb24/LmludGVyYWN0aW9uID09PSBcInNlcmllc1wiIHx8XG4gICAgICAgICAgICB0aGlzLmRhdGFTb3VyY2U/LmZlYXR1cmVzPy5nZXRGZWF0dXJlQ29uZmlnKFxuICAgICAgICAgICAgICAgIFdlbGxLbm93bkRhdGFTb3VyY2VGZWF0dXJlcy5JbnRlcmFjdGl2aXR5XG4gICAgICAgICAgICApPy5lbmFibGVkIHx8XG4gICAgICAgICAgICBmYWxzZVxuICAgICAgICApO1xuICAgIH1cblxuICAgIHByb3RlY3RlZCBjb25zdHJ1Y3RvcihcbiAgICAgICAgQEluamVjdChQSVpaQUdOQV9FVkVOVF9CVVMpIHByb3RlY3RlZCBldmVudEJ1czogRXZlbnRCdXM8SUV2ZW50PixcbiAgICAgICAgcHVibGljIHRpbWVzZXJpZXNTY2FsZXNTZXJ2aWNlOiBUaW1lc2VyaWVzU2NhbGVzU2VydmljZSxcbiAgICAgICAgcHVibGljIGRhdGFTb3VyY2U6IElEYXRhU291cmNlXG4gICAgKSB7XG4gICAgICAgIHRoaXMuYnVpbGRDaGFydCQucGlwZSh0YWtlVW50aWwodGhpcy5kZXN0cm95JCkpLnN1YnNjcmliZSgoKSA9PiB7XG4gICAgICAgICAgICB0aGlzLmNoYXJ0QnVpbHQgPSB0cnVlO1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBwdWJsaWMgbmdPbkluaXQoKTogdm9pZCB7XG4gICAgICAgIC8vIHNhdmUgb3JpZ2luYWwgZGF0YVxuICAgICAgICBpZiAoXG4gICAgICAgICAgICB0aGlzLmNvbmZpZ3VyYXRpb24ucHJlc2V0ID09PSBUaW1lc2VyaWVzQ2hhcnRQcmVzZXQuTGluZSAmJlxuICAgICAgICAgICAgdGhpcy53aWRnZXREYXRhICYmXG4gICAgICAgICAgICB0aGlzLndpZGdldERhdGEuc2VyaWVzXG4gICAgICAgICkge1xuICAgICAgICAgICAgdGhpcy53aWRnZXREYXRhLnNlcmllcy5mb3JFYWNoKFxuICAgICAgICAgICAgICAgIChzZXJpZSkgPT4gKHNlcmllLnJhd0RhdGEgPSBzZXJpZS5kYXRhKVxuICAgICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHB1YmxpYyBuZ09uQ2hhbmdlcyhjaGFuZ2VzOiBTaW1wbGVDaGFuZ2VzKTogdm9pZCB7XG4gICAgICAgIGxldCBzaG91bGRVcGRhdGVDaGFydCA9IGZhbHNlO1xuICAgICAgICBsZXQgc2hvdWxkUmVidWlsZENoYXJ0ID0gZmFsc2U7XG5cbiAgICAgICAgaWYgKGNoYW5nZXMuY29uZmlndXJhdGlvbikge1xuICAgICAgICAgICAgY29uc3QgY29uZmlndXJhdGlvbkN1cnJlbnQ6IElUaW1lc2VyaWVzV2lkZ2V0Q29uZmlnID1cbiAgICAgICAgICAgICAgICBjaGFuZ2VzLmNvbmZpZ3VyYXRpb24uY3VycmVudFZhbHVlO1xuICAgICAgICAgICAgY29uc3QgY29uZmlndXJhdGlvblByZXZpb3VzOiBJVGltZXNlcmllc1dpZGdldENvbmZpZyA9XG4gICAgICAgICAgICAgICAgY2hhbmdlcy5jb25maWd1cmF0aW9uLnByZXZpb3VzVmFsdWU7XG5cbiAgICAgICAgICAgIGlmIChcbiAgICAgICAgICAgICAgICBjb25maWd1cmF0aW9uQ3VycmVudD8ucHJlc2V0ICE9PSBjb25maWd1cmF0aW9uUHJldmlvdXM/LnByZXNldFxuICAgICAgICAgICAgKSB7XG4gICAgICAgICAgICAgICAgc2hvdWxkUmVidWlsZENoYXJ0ID0gdHJ1ZTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKFxuICAgICAgICAgICAgICAgIGNvbmZpZ3VyYXRpb25DdXJyZW50Py5zY2FsZXMgIT09IGNvbmZpZ3VyYXRpb25QcmV2aW91cz8uc2NhbGVzXG4gICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgICBjb25zdCBzY2FsZUtleXMgPSBPYmplY3Qua2V5cyhcbiAgICAgICAgICAgICAgICAgICAgY29uZmlndXJhdGlvbkN1cnJlbnQ/LnNjYWxlc1xuICAgICAgICAgICAgICAgICkgYXMgQXJyYXk8a2V5b2YgSVRpbWVzZXJpZXNTY2FsZXNDb25maWc+O1xuXG4gICAgICAgICAgICAgICAgZm9yIChjb25zdCBzY2FsZUtleSBvZiBzY2FsZUtleXMpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc3Qgc2NhbGVDb25maWdDdXJyZW50ID1cbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbmZpZ3VyYXRpb25DdXJyZW50Py5zY2FsZXM/LltzY2FsZUtleV07XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IHNjYWxlQ29uZmlnUHJldmlvdXMgPVxuICAgICAgICAgICAgICAgICAgICAgICAgY29uZmlndXJhdGlvblByZXZpb3VzPy5zY2FsZXM/LltzY2FsZUtleV07XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKCFzY2FsZUNvbmZpZ0N1cnJlbnQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKFxuICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGVDb25maWdDdXJyZW50Py50eXBlICE9PVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNjYWxlQ29uZmlnUHJldmlvdXM/LnR5cGUgfHxcbiAgICAgICAgICAgICAgICAgICAgICAgIHNjYWxlQ29uZmlnQ3VycmVudD8ucHJvcGVydGllcz8uYXhpc1VuaXRzICE9PVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNjYWxlQ29uZmlnUHJldmlvdXM/LnByb3BlcnRpZXM/LmF4aXNVbml0c1xuICAgICAgICAgICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuc2NhbGVzW3NjYWxlS2V5XSA9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy50aW1lc2VyaWVzU2NhbGVzU2VydmljZS5nZXRTY2FsZShcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGVDb25maWdDdXJyZW50LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25maWd1cmF0aW9uQ3VycmVudC51bml0cyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5jb25maWd1cmF0aW9uXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgc2hvdWxkVXBkYXRlQ2hhcnQgPSB0cnVlO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKFxuICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGVDb25maWdDdXJyZW50Py5wcm9wZXJ0aWVzICE9PVxuICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGVDb25maWdQcmV2aW91cz8ucHJvcGVydGllc1xuICAgICAgICAgICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMudGltZXNlcmllc1NjYWxlc1NlcnZpY2UudXBkYXRlQ29uZmlndXJhdGlvbihcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnNjYWxlc1tzY2FsZUtleV0sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGVDb25maWdDdXJyZW50LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuY29uZmlndXJhdGlvblxuICAgICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNob3VsZFVwZGF0ZUNoYXJ0ID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChzaG91bGRSZWJ1aWxkQ2hhcnQgfHwgIXRoaXMuY2hhcnRCdWlsdCkge1xuICAgICAgICAgICAgdGhpcy5idWlsZENoYXJ0KCk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoY2hhbmdlcy53aWRnZXREYXRhICYmICFjaGFuZ2VzLndpZGdldERhdGEuaXNGaXJzdENoYW5nZSgpKSB7XG4gICAgICAgICAgICBpZiAodGhpcy53aWRnZXREYXRhPy5zZXJpZXM/Lmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgICAgICAgIHRoaXMucmVzZXRDaGFydCA9IHRydWU7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmICh0aGlzLndpZGdldERhdGEgJiYgdGhpcy53aWRnZXREYXRhLnNlcmllcykge1xuICAgICAgICAgICAgICAgIGlmICh0aGlzLnJlc2V0Q2hhcnQgJiYgdGhpcy53aWRnZXREYXRhPy5zZXJpZXM/Lmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5yZXNldENoYXJ0ID0gZmFsc2U7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuYnVpbGRDaGFydCgpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB0aGlzLmFwcGx5UHJldmlvdXNUcmFuc2Zvcm1lcihjaGFuZ2VzLndpZGdldERhdGEucHJldmlvdXNWYWx1ZSk7XG5cbiAgICAgICAgICAgICAgICBzaG91bGRVcGRhdGVDaGFydCA9IHRydWU7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoc2hvdWxkVXBkYXRlQ2hhcnQpIHtcbiAgICAgICAgICAgIHRoaXMudXBkYXRlQ2hhcnREYXRhKCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwdWJsaWMgbmdPbkRlc3Ryb3koKTogdm9pZCB7XG4gICAgICAgIHRoaXMuZGVzdHJveSQubmV4dCgpO1xuICAgICAgICB0aGlzLmRlc3Ryb3kkLmNvbXBsZXRlKCk7XG4gICAgICAgIHRoaXMuYnVpbGRDaGFydCQuY29tcGxldGUoKTtcbiAgICB9XG5cbiAgICBwcm90ZWN0ZWQgYXBwbHlQcmV2aW91c1RyYW5zZm9ybWVyKHByZXZpb3VzRGF0YTogYW55KTogdm9pZCB7XG4gICAgICAgIC8vIHNhdmUgb3JpZ2luYWwgZGF0YSBhbmQgdHJhbnNmb3JtIGl0XG4gICAgICAgIHRoaXMud2lkZ2V0RGF0YS5zZXJpZXMuZm9yRWFjaCgoc2VyaWUpID0+IHtcbiAgICAgICAgICAgIHNlcmllLnJhd0RhdGEgPSBzZXJpZS5kYXRhO1xuICAgICAgICAgICAgc2VyaWUudHJhbnNmb3JtZXIgPSBwcmV2aW91c0RhdGE/LnNlcmllcy5maW5kKFxuICAgICAgICAgICAgICAgIChwcmV2U2VyaWU6IElUaW1lc2VyaWVzV2lkZ2V0RGF0YSkgPT4gcHJldlNlcmllLmlkID09PSBzZXJpZS5pZFxuICAgICAgICAgICAgKT8udHJhbnNmb3JtZXI7XG4gICAgICAgICAgICB0aGlzLnRyYW5zZm9ybVNlcmllc0RhdGEoc2VyaWUpO1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBwcm90ZWN0ZWQgdHJhbnNmb3JtU2VyaWVzRGF0YShzZXJpZTogSVRpbWVzZXJpZXNXaWRnZXREYXRhPFQ+KTogdm9pZCB7XG4gICAgICAgIGlmIChzZXJpZS50cmFuc2Zvcm1lciAmJiBzZXJpZS5yYXdEYXRhICYmIHNlcmllLnJhd0RhdGEubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICBjb25zdCBoYXNQZXJjZW50aWxlID0gc2VyaWUubWV0cmljVW5pdHMgPT09IFwicGVyY2VudFwiO1xuICAgICAgICAgICAgICAgIHNlcmllLmRhdGEgPSBzZXJpZS50cmFuc2Zvcm1lcihzZXJpZS5yYXdEYXRhLCBoYXNQZXJjZW50aWxlKTtcbiAgICAgICAgICAgICAgICB0aGlzLnVwZGF0ZVlBeGlzRG9tYWluKCk7XG4gICAgICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICAgICAgc2VyaWUudHJhbnNmb3JtZXIgPSB1bmRlZmluZWQ7XG4gICAgICAgICAgICAgICAgc2VyaWUuZGF0YSA9IHNlcmllLnJhd0RhdGE7XG4gICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihlLm1lc3NhZ2UpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHVibGljIHVwZGF0ZVlBeGlzRG9tYWluKCk6IHZvaWQge1xuICAgICAgICBjb25zdCBzY2FsZUtleXMgPSBbXCJ5XCIsIFwieVJpZ2h0XCJdIGFzIEFycmF5PFxuICAgICAgICAgICAga2V5b2YgSVRpbWVzZXJpZXNTY2FsZXNDb25maWdcbiAgICAgICAgPjtcbiAgICAgICAgZm9yIChjb25zdCBzY2FsZUtleSBvZiBzY2FsZUtleXMpIHtcbiAgICAgICAgICAgIGNvbnN0IHNjYWxlQ29uZmlnID0gdGhpcy5jb25maWd1cmF0aW9uLnNjYWxlcz8uW3NjYWxlS2V5XTtcbiAgICAgICAgICAgIGlmIChzY2FsZUNvbmZpZz8ucHJvcGVydGllcykge1xuICAgICAgICAgICAgICAgIHNjYWxlQ29uZmlnLnByb3BlcnRpZXMuZG9tYWluID0ge1xuICAgICAgICAgICAgICAgICAgICAuLi5tZXRyaWNzU2VyaWVzTWVhc3VyZW1lbnRzTWluTWF4KFxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy53aWRnZXREYXRhLnNlcmllcyxcbiAgICAgICAgICAgICAgICAgICAgICAgIHNjYWxlQ29uZmlnPy5wcm9wZXJ0aWVzPy5heGlzVW5pdHNcbiAgICAgICAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgIHRoaXMudGltZXNlcmllc1NjYWxlc1NlcnZpY2UudXBkYXRlQ29uZmlndXJhdGlvbihcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5zY2FsZXNbc2NhbGVLZXldLFxuICAgICAgICAgICAgICAgICAgICBzY2FsZUNvbmZpZyxcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5jb25maWd1cmF0aW9uXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cblxuICAgIHB1YmxpYyByZW1vdmVNZXRyaWMobWV0cmljSWQ6IHN0cmluZyk6IHZvaWQge1xuICAgICAgICB0aGlzLmV2ZW50QnVzLm5leHQoQ0hBUlRfTUVUUklDX1JFTU9WRSwge1xuICAgICAgICAgICAgcGF5bG9hZDoge1xuICAgICAgICAgICAgICAgIG1ldHJpY0lkOiBtZXRyaWNJZCxcbiAgICAgICAgICAgICAgICBncm91cFVuaXF1ZUlkOiB0aGlzLmNvbmZpZ3VyYXRpb24uZ3JvdXBVbmlxdWVJZCxcbiAgICAgICAgICAgIH0sXG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIC8qKiBVcGRhdGVzIGNoYXJ0IGRhdGEuICovXG4gICAgcHJvdGVjdGVkIGFic3RyYWN0IHVwZGF0ZUNoYXJ0RGF0YSgpOiB2b2lkO1xuXG4gICAgcHJvdGVjdGVkIGFic3RyYWN0IGJ1aWxkQ2hhcnQoKTogdm9pZDtcbn1cbiJdfQ==