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

180 lines 26 kB
// © 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 { Injectable } from "@angular/core"; import { duration } from "moment/moment"; import { UnitBase, UnitConversionService } from "@nova-ui/bits"; import { LinearScale, TimeIntervalScale, TimeScale, } from "@nova-ui/charts"; import { TimeseriesScaleType, TimeseriesChartPreset, } from "./types"; import { DashboardUnitConversionPipe } from "../../common/pipes/public-api"; import { roundToOptimalDecimals } from "../../functions/round-array-values"; import { timeSeriesDatetimeFormatter } from "../../functions/timeseries-datetime-formatter"; import * as i0 from "@angular/core"; import * as i1 from "@nova-ui/bits"; /** * This service handles scale creation and configuration for the timeseries widget */ export class TimeseriesScalesService { constructor(unitConversionService) { this.unitConversionService = unitConversionService; this.unitConversionPipe = new DashboardUnitConversionPipe(this.unitConversionService); } /** * Creates a scale based on given configuration * * @param scaleConfig */ getScale(scaleConfig, units, widgetConfig) { let scale; switch (scaleConfig.type) { case TimeseriesScaleType.Time: { scale = new TimeScale(); scale.isTimeseriesScale = true; scale.formatters.title = timeSeriesDatetimeFormatter; break; } case TimeseriesScaleType.Linear: { scale = new LinearScale(); scale.isTimeseriesScale = true; scale.formatters.tick = (value, isLabelFormatter) => this.unitConversionPipe.transform(value, scaleConfig.properties?.axisUnits ?? units, UnitBase.Standard); break; } case TimeseriesScaleType.TimeInterval: { scale = new TimeIntervalScale(duration(1, "hour")); break; } } this.updateConfiguration(scale, scaleConfig, widgetConfig); return scale; } /** * Currently only TimeIntervalScale has configuration * * @param scale * @param scaleConfig */ updateConfiguration(scale, scaleConfig, widgetConfig) { switch (scaleConfig.type) { case TimeseriesScaleType.Time: { const interval = scaleConfig.properties?.timeInterval; if (interval?.startDatetime && interval?.endDatetime) { scale.fixDomain([ interval.startDatetime, interval.endDatetime, ]); } break; } case TimeseriesScaleType.TimeInterval: { const interval = scaleConfig.properties?.interval; if (typeof interval === "number") { if (interval <= 0) { throw new Error("Interval value must be greater than zero."); } if (scale instanceof TimeIntervalScale) { scale.interval(duration(interval, "seconds")); } } break; } case TimeseriesScaleType.Linear: { if (scaleConfig.properties?.axisUnits) { scale.scaleUnits = scaleConfig.properties.axisUnits; } if (widgetConfig?.preset === TimeseriesChartPreset.StatusBar) { return; } if (scaleConfig.properties?.axisUnits === "percent" && scale.setFixDomainValues) { scale.setFixDomainValues([0, 25, 50, 75, 100]); } if (scaleConfig.properties?.axisUnits !== "percent" && scaleConfig.properties?.domain && scale.setFixDomainValues) { let domainAdjusted; switch (widgetConfig?.preset) { case TimeseriesChartPreset.StackedBar: domainAdjusted = this.getStackedBarScaleDomain(scaleConfig.properties.domain); break; case TimeseriesChartPreset.StackedArea: domainAdjusted = this.getStackedAreaScaleDomain(scaleConfig.properties.domain.max); break; default: domainAdjusted = this.getLineScaleDomain(scaleConfig.properties.domain); } scale.setFixDomainValues(domainAdjusted); } break; } } } getStackedBarScaleDomain({ min, max, }) { if (max === 0 || max % 4 > 0) { max = max + 4 - (max % 4); } const increment = Math.floor((max - min) / 4); return [ min, min + increment, min + 2 * increment, max - increment, max, ]; } getLineScaleDomain({ min, max, }) { if (min > max) { const tmp = min; min = max; max = tmp; } const extentRange = Math.abs((max - min) / ((max + min) / 2)); // for small domain ranges increase domain so that spikes are not exaggerated if (extentRange < 0.5) { min = min - Math.abs(min) * 0.5; max = max + Math.abs(max) * 0.5; } // handles zero case if (min === 0 && max === 0) { min = -1; max = 1; } // special case for real small number since not using si prefix anymore if (Math.abs(max - min) < 0.04) { max += 0.04; } const point = (max - min) / 4; return roundToOptimalDecimals([ min, min + point, min + 2 * point, max - point, max, ]); } getStackedAreaScaleDomain(max) { const point = max / 4; return [0, point, point * 2, max - point, max]; } /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TimeseriesScalesService, deps: [{ token: i1.UnitConversionService }], target: i0.ɵɵFactoryTarget.Injectable }); } /** @nocollapse */ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TimeseriesScalesService }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TimeseriesScalesService, decorators: [{ type: Injectable }], ctorParameters: () => [{ type: i1.UnitConversionService }] }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGltZXNlcmllcy1zY2FsZXMuc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9saWIvY29tcG9uZW50cy90aW1lc2VyaWVzLXdpZGdldC90aW1lc2VyaWVzLXNjYWxlcy5zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLHlEQUF5RDtBQUN6RCxFQUFFO0FBQ0YsK0VBQStFO0FBQy9FLDRFQUE0RTtBQUM1RSw4RUFBOEU7QUFDOUUsK0VBQStFO0FBQy9FLDhFQUE4RTtBQUM5RSw0REFBNEQ7QUFDNUQsRUFBRTtBQUNGLDZFQUE2RTtBQUM3RSx1REFBdUQ7QUFDdkQsRUFBRTtBQUNGLDZFQUE2RTtBQUM3RSw0RUFBNEU7QUFDNUUsK0VBQStFO0FBQy9FLDBFQUEwRTtBQUMxRSxpRkFBaUY7QUFDakYsNkVBQTZFO0FBQzdFLGlCQUFpQjtBQUVqQixPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQzNDLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFFekMsT0FBTyxFQUFFLFFBQVEsRUFBRSxxQkFBcUIsRUFBYyxNQUFNLGVBQWUsQ0FBQztBQUM1RSxPQUFPLEVBRUgsV0FBVyxFQUNYLGlCQUFpQixFQUNqQixTQUFTLEdBQ1osTUFBTSxpQkFBaUIsQ0FBQztBQUV6QixPQUFPLEVBR0gsbUJBQW1CLEVBQ25CLHFCQUFxQixHQUN4QixNQUFNLFNBQVMsQ0FBQztBQUNqQixPQUFPLEVBQUUsMkJBQTJCLEVBQUUsTUFBTSwrQkFBK0IsQ0FBQztBQUM1RSxPQUFPLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSxvQ0FBb0MsQ0FBQztBQUM1RSxPQUFPLEVBQUUsMkJBQTJCLEVBQUUsTUFBTSwrQ0FBK0MsQ0FBQzs7O0FBRTVGOztHQUVHO0FBRUgsTUFBTSxPQUFPLHVCQUF1QjtJQUdoQyxZQUFvQixxQkFBNEM7UUFBNUMsMEJBQXFCLEdBQXJCLHFCQUFxQixDQUF1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RyxDQUFDLEdBQUcsSUFBSSxFQUFFO1lBQzVCLEdBQUcsSUFBSSxJQUFJLENBQUM7U0FDZjtRQUVELE1BQU0sS0FBSyxHQUFHLENBQUMsR0FBRyxHQUFHLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUM5QixPQUFPLHNCQUFzQixDQUFDO1lBQzFCLEdBQUc7WUFDSCxHQUFHLEdBQUcsS0FBSztZQUNYLEdBQUcsR0FBRyxDQUFDLEdBQUcsS0FBSztZQUNmLEdBQUcsR0FBRyxLQUFLO1lBQ1gsR0FBRztTQUNOLENBQUMsQ0FBQztJQUNQLENBQUM7SUFFTyx5QkFBeUIsQ0FBQyxHQUFXO1FBQ3pDLE1BQU0sS0FBSyxHQUFHLEdBQUcsR0FBRyxDQUFDLENBQUM7UUFDdEIsT0FBTyxDQUFDLENBQUMsRUFBRSxLQUFLLEVBQUUsS0FBSyxHQUFHLENBQUMsRUFBRSxHQUFHLEdBQUcsS0FBSyxFQUFFLEdBQUcsQ0FBQyxDQUFDO0lBQ25ELENBQUM7a0lBdk1RLHVCQUF1QjtzSUFBdkIsdUJBQXVCOzs0RkFBdkIsdUJBQXVCO2tCQURuQyxVQUFVIiwic291cmNlc0NvbnRlbnQiOlsiLy8gwqkgMjAyMiBTb2xhcldpbmRzIFdvcmxkd2lkZSwgTExDLiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuLy9cbi8vIFBlcm1pc3Npb24gaXMgaGVyZWJ5IGdyYW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkgcGVyc29uIG9idGFpbmluZyBhIGNvcHlcbi8vICBvZiB0aGlzIHNvZnR3YXJlIGFuZCBhc3NvY2lhdGVkIGRvY3VtZW50YXRpb24gZmlsZXMgKHRoZSBcIlNvZnR3YXJlXCIpLCB0b1xuLy8gIGRlYWwgaW4gdGhlIFNvZnR3YXJlIHdpdGhvdXQgcmVzdHJpY3Rpb24sIGluY2x1ZGluZyB3aXRob3V0IGxpbWl0YXRpb24gdGhlXG4vLyAgcmlnaHRzIHRvIHVzZSwgY29weSwgbW9kaWZ5LCBtZXJnZSwgcHVibGlzaCwgZGlzdHJpYnV0ZSwgc3VibGljZW5zZSwgYW5kL29yXG4vLyAgc2VsbCBjb3BpZXMgb2YgdGhlIFNvZnR3YXJlLCBhbmQgdG8gcGVybWl0IHBlcnNvbnMgdG8gd2hvbSB0aGUgU29mdHdhcmUgaXNcbi8vICBmdXJuaXNoZWQgdG8gZG8gc28sIHN1YmplY3QgdG8gdGhlIGZvbGxvd2luZyBjb25kaXRpb25zOlxuLy9cbi8vIFRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlIGFuZCB0aGlzIHBlcm1pc3Npb24gbm90aWNlIHNoYWxsIGJlIGluY2x1ZGVkIGluXG4vLyAgYWxsIGNvcGllcyBvciBzdWJzdGFudGlhbCBwb3J0aW9ucyBvZiB0aGUgU29mdHdhcmUuXG4vL1xuLy8gVEhFIFNPRlRXQVJFIElTIFBST1ZJREVEIFwiQVMgSVNcIiwgV0lUSE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCwgRVhQUkVTUyBPUlxuLy8gIElNUExJRUQsIElOQ0xVRElORyBCVVQgTk9UIExJTUlURUQgVE8gVEhFIFdBUlJBTlRJRVMgT0YgTUVSQ0hBTlRBQklMSVRZLFxuLy8gIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFIEFORCBOT05JTkZSSU5HRU1FTlQuIElOIE5PIEVWRU5UIFNIQUxMIFRIRVxuLy8gIEFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERFUlMgQkUgTElBQkxFIEZPUiBBTlkgQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVJcbi8vICBMSUFCSUxJVFksIFdIRVRIRVIgSU4gQU4gQUNUSU9OIE9GIENPTlRSQUNULCBUT1JUIE9SIE9USEVSV0lTRSwgQVJJU0lORyBGUk9NLFxuLy8gIE9VVCBPRiBPUiBJTiBDT05ORUNUSU9OIFdJVEggVEhFIFNPRlRXQVJFIE9SIFRIRSBVU0UgT1IgT1RIRVIgREVBTElOR1MgSU5cbi8vICBUSEUgU09GVFdBUkUuXG5cbmltcG9ydCB7IEluamVjdGFibGUgfSBmcm9tIFwiQGFuZ3VsYXIvY29yZVwiO1xuaW1wb3J0IHsgZHVyYXRpb24gfSBmcm9tIFwibW9tZW50L21vbWVudFwiO1xuXG5pbXBvcnQgeyBVbml0QmFzZSwgVW5pdENvbnZlcnNpb25TZXJ2aWNlLCBVbml0T3B0aW9uIH0gZnJvbSBcIkBub3ZhLXVpL2JpdHNcIjtcbmltcG9ydCB7XG4gICAgSVNjYWxlLFxuICAgIExpbmVhclNjYWxlLFxuICAgIFRpbWVJbnRlcnZhbFNjYWxlLFxuICAgIFRpbWVTY2FsZSxcbn0gZnJvbSBcIkBub3ZhLXVpL2NoYXJ0c1wiO1xuXG5pbXBvcnQge1xuICAgIElUaW1lc2VyaWVzU2NhbGVDb25maWcsXG4gICAgSVRpbWVzZXJpZXNXaWRnZXRDb25maWcsXG4gICAgVGltZXNlcmllc1NjYWxlVHlwZSxcbiAgICBUaW1lc2VyaWVzQ2hhcnRQcmVzZXQsXG59IGZyb20gXCIuL3R5cGVzXCI7XG5pbXBvcnQgeyBEYXNoYm9hcmRVbml0Q29udmVyc2lvblBpcGUgfSBmcm9tIFwiLi4vLi4vY29tbW9uL3BpcGVzL3B1YmxpYy1hcGlcIjtcbmltcG9ydCB7IHJvdW5kVG9PcHRpbWFsRGVjaW1hbHMgfSBmcm9tIFwiLi4vLi4vZnVuY3Rpb25zL3JvdW5kLWFycmF5LXZhbHVlc1wiO1xuaW1wb3J0IHsgdGltZVNlcmllc0RhdGV0aW1lRm9ybWF0dGVyIH0gZnJvbSBcIi4uLy4uL2Z1bmN0aW9ucy90aW1lc2VyaWVzLWRhdGV0aW1lLWZvcm1hdHRlclwiO1xuXG4vKipcbiAqIFRoaXMgc2VydmljZSBoYW5kbGVzIHNjYWxlIGNyZWF0aW9uIGFuZCBjb25maWd1cmF0aW9uIGZvciB0aGUgdGltZXNlcmllcyB3aWRnZXRcbiAqL1xuQEluamVjdGFibGUoKVxuZXhwb3J0IGNsYXNzIFRpbWVzZXJpZXNTY2FsZXNTZXJ2aWNlIHtcbiAgICBwcml2YXRlIHVuaXRDb252ZXJzaW9uUGlwZTogRGFzaGJvYXJkVW5pdENvbnZlcnNpb25QaXBlO1xuXG4gICAgY29uc3RydWN0b3IocHJpdmF0ZSB1bml0Q29udmVyc2lvblNlcnZpY2U6IFVuaXRDb252ZXJzaW9uU2VydmljZSkge1xuICAgICAgICB0aGlzLnVuaXRDb252ZXJzaW9uUGlwZSA9IG5ldyBEYXNoYm9hcmRVbml0Q29udmVyc2lvblBpcGUoXG4gICAgICAgICAgICB0aGlzLnVuaXRDb252ZXJzaW9uU2VydmljZVxuICAgICAgICApO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENyZWF0ZXMgYSBzY2FsZSBiYXNlZCBvbiBnaXZlbiBjb25maWd1cmF0aW9uXG4gICAgICpcbiAgICAgKiBAcGFyYW0gc2NhbGVDb25maWdcbiAgICAgKi9cbiAgICBwdWJsaWMgZ2V0U2NhbGUoXG4gICAgICAgIHNjYWxlQ29uZmlnOiBJVGltZXNlcmllc1NjYWxlQ29uZmlnLFxuICAgICAgICB1bml0czogVW5pdE9wdGlvbixcbiAgICAgICAgd2lkZ2V0Q29uZmlnPzogSVRpbWVzZXJpZXNXaWRnZXRDb25maWdcbiAgICApOiBJU2NhbGU8YW55PiB7XG4gICAgICAgIGxldCBzY2FsZTogSVNjYWxlPGFueT47XG5cbiAgICAgICAgc3dpdGNoIChzY2FsZUNvbmZpZy50eXBlKSB7XG4gICAgICAgICAgICBjYXNlIFRpbWVzZXJpZXNTY2FsZVR5cGUuVGltZToge1xuICAgICAgICAgICAgICAgIHNjYWxlID0gbmV3IFRpbWVTY2FsZSgpO1xuICAgICAgICAgICAgICAgIHNjYWxlLmlzVGltZXNlcmllc1NjYWxlID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICBzY2FsZS5mb3JtYXR0ZXJzLnRpdGxlID0gdGltZVNlcmllc0RhdGV0aW1lRm9ybWF0dGVyO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY2FzZSBUaW1lc2VyaWVzU2NhbGVUeXBlLkxpbmVhcjoge1xuICAgICAgICAgICAgICAgIHNjYWxlID0gbmV3IExpbmVhclNjYWxlKCk7XG4gICAgICAgICAgICAgICAgc2NhbGUuaXNUaW1lc2VyaWVzU2NhbGUgPSB0cnVlO1xuICAgICAgICAgICAgICAgIHNjYWxlLmZvcm1hdHRlcnMudGljayA9IChcbiAgICAgICAgICAgICAgICAgICAgdmFsdWU6IHN0cmluZyB8IG51bWJlciB8IHVuZGVmaW5lZCxcbiAgICAgICAgICAgICAgICAgICAgaXNMYWJlbEZvcm1hdHRlcj86IGJvb2xlYW5cbiAgICAgICAgICAgICAgICApID0+XG4gICAgICAgICAgICAgICAgICAgIHRoaXMudW5pdENvbnZlcnNpb25QaXBlLnRyYW5zZm9ybShcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlLFxuICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGVDb25maWcucHJvcGVydGllcz8uYXhpc1VuaXRzID8/IHVuaXRzLFxuICAgICAgICAgICAgICAgICAgICAgICAgVW5pdEJhc2UuU3RhbmRhcmRcbiAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNhc2UgVGltZXNlcmllc1NjYWxlVHlwZS5UaW1lSW50ZXJ2YWw6IHtcbiAgICAgICAgICAgICAgICBzY2FsZSA9IG5ldyBUaW1lSW50ZXJ2YWxTY2FsZShkdXJhdGlvbigxLCBcImhvdXJcIikpO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy51cGRhdGVDb25maWd1cmF0aW9uKHNjYWxlLCBzY2FsZUNvbmZpZywgd2lkZ2V0Q29uZmlnKTtcblxuICAgICAgICByZXR1cm4gc2NhbGU7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ3VycmVudGx5IG9ubHkgVGltZUludGVydmFsU2NhbGUgaGFzIGNvbmZpZ3VyYXRpb25cbiAgICAgKlxuICAgICAqIEBwYXJhbSBzY2FsZVxuICAgICAqIEBwYXJhbSBzY2FsZUNvbmZpZ1xuICAgICAqL1xuICAgIHB1YmxpYyB1cGRhdGVDb25maWd1cmF0aW9uKFxuICAgICAgICBzY2FsZTogSVNjYWxlPGFueT4sXG4gICAgICAgIHNjYWxlQ29uZmlnOiBJVGltZXNlcmllc1NjYWxlQ29uZmlnLFxuICAgICAgICB3aWRnZXRDb25maWc/OiBJVGltZXNlcmllc1dpZGdldENvbmZpZ1xuICAgICk6IHZvaWQge1xuICAgICAgICBzd2l0Y2ggKHNjYWxlQ29uZmlnLnR5cGUpIHtcbiAgICAgICAgICAgIGNhc2UgVGltZXNlcmllc1NjYWxlVHlwZS5UaW1lOiB7XG4gICAgICAgICAgICAgICAgY29uc3QgaW50ZXJ2YWwgPSBzY2FsZUNvbmZpZy5wcm9wZXJ0aWVzPy50aW1lSW50ZXJ2YWw7XG4gICAgICAgICAgICAgICAgaWYgKGludGVydmFsPy5zdGFydERhdGV0aW1lICYmIGludGVydmFsPy5lbmREYXRldGltZSkge1xuICAgICAgICAgICAgICAgICAgICBzY2FsZS5maXhEb21haW4oW1xuICAgICAgICAgICAgICAgICAgICAgICAgaW50ZXJ2YWwuc3RhcnREYXRldGltZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGludGVydmFsLmVuZERhdGV0aW1lLFxuICAgICAgICAgICAgICAgICAgICBdKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjYXNlIFRpbWVzZXJpZXNTY2FsZVR5cGUuVGltZUludGVydmFsOiB7XG4gICAgICAgICAgICAgICAgY29uc3QgaW50ZXJ2YWwgPSBzY2FsZUNvbmZpZy5wcm9wZXJ0aWVzPy5pbnRlcnZhbDtcbiAgICAgICAgICAgICAgICBpZiAodHlwZW9mIGludGVydmFsID09PSBcIm51bWJlclwiKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChpbnRlcnZhbCA8PSAwKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgXCJJbnRlcnZhbCB2YWx1ZSBtdXN0IGJlIGdyZWF0ZXIgdGhhbiB6ZXJvLlwiXG4gICAgICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGlmIChzY2FsZSBpbnN0YW5jZW9mIFRpbWVJbnRlcnZhbFNjYWxlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBzY2FsZS5pbnRlcnZhbChkdXJhdGlvbihpbnRlcnZhbCwgXCJzZWNvbmRzXCIpKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNhc2UgVGltZXNlcmllc1NjYWxlVHlwZS5MaW5lYXI6IHtcbiAgICAgICAgICAgICAgICBpZiAoc2NhbGVDb25maWcucHJvcGVydGllcz8uYXhpc1VuaXRzKSB7XG4gICAgICAgICAgICAgICAgICAgIHNjYWxlLnNjYWxlVW5pdHMgPSBzY2FsZUNvbmZpZy5wcm9wZXJ0aWVzLmF4aXNVbml0cztcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBpZiAod2lkZ2V0Q29uZmlnPy5wcmVzZXQgPT09IFRpbWVzZXJpZXNDaGFydFByZXNldC5TdGF0dXNCYXIpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGlmIChcbiAgICAgICAgICAgICAgICAgICAgc2NhbGVDb25maWcucHJvcGVydGllcz8uYXhpc1VuaXRzID09PSBcInBlcmNlbnRcIiAmJlxuICAgICAgICAgICAgICAgICAgICBzY2FsZS5zZXRGaXhEb21haW5WYWx1ZXNcbiAgICAgICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgICAgICAgc2NhbGUuc2V0Rml4RG9tYWluVmFsdWVzKFswLCAyNSwgNTAsIDc1LCAxMDBdKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKFxuICAgICAgICAgICAgICAgICAgICBzY2FsZUNvbmZpZy5wcm9wZXJ0aWVzPy5heGlzVW5pdHMgIT09IFwicGVyY2VudFwiICYmXG4gICAgICAgICAgICAgICAgICAgIHNjYWxlQ29uZmlnLnByb3BlcnRpZXM/LmRvbWFpbiAmJlxuICAgICAgICAgICAgICAgICAgICBzY2FsZS5zZXRGaXhEb21haW5WYWx1ZXNcbiAgICAgICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgICAgICAgbGV0IGRvbWFpbkFkanVzdGVkO1xuICAgICAgICAgICAgICAgICAgICBzd2l0Y2ggKHdpZGdldENvbmZpZz8ucHJlc2V0KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjYXNlIFRpbWVzZXJpZXNDaGFydFByZXNldC5TdGFja2VkQmFyOlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRvbWFpbkFkanVzdGVkID0gdGhpcy5nZXRTdGFja2VkQmFyU2NhbGVEb21haW4oXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNjYWxlQ29uZmlnLnByb3BlcnRpZXMuZG9tYWluXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgICAgIGNhc2UgVGltZXNlcmllc0NoYXJ0UHJlc2V0LlN0YWNrZWRBcmVhOlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRvbWFpbkFkanVzdGVkID0gdGhpcy5nZXRTdGFja2VkQXJlYVNjYWxlRG9tYWluKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzY2FsZUNvbmZpZy5wcm9wZXJ0aWVzLmRvbWFpbi5tYXhcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgICAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkb21haW5BZGp1c3RlZCA9IHRoaXMuZ2V0TGluZVNjYWxlRG9tYWluKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzY2FsZUNvbmZpZy5wcm9wZXJ0aWVzLmRvbWFpblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICBzY2FsZS5zZXRGaXhEb21haW5WYWx1ZXMoZG9tYWluQWRqdXN0ZWQpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByaXZhdGUgZ2V0U3RhY2tlZEJhclNjYWxlRG9tYWluKHtcbiAgICAgICAgbWluLFxuICAgICAgICBtYXgsXG4gICAgfToge1xuICAgICAgICBtaW46IG51bWJlcjtcbiAgICAgICAgbWF4OiBudW1iZXI7XG4gICAgfSk6IG51bWJlcltdIHtcbiAgICAgICAgaWYgKG1heCA9PT0gMCB8fCBtYXggJSA0ID4gMCkge1xuICAgICAgICAgICAgbWF4ID0gbWF4ICsgNCAtIChtYXggJSA0KTtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBpbmNyZW1lbnQgPSBNYXRoLmZsb29yKChtYXggLSBtaW4pIC8gNCk7XG4gICAgICAgIHJldHVybiBbXG4gICAgICAgICAgICBtaW4sXG4gICAgICAgICAgICBtaW4gKyBpbmNyZW1lbnQsXG4gICAgICAgICAgICBtaW4gKyAyICogaW5jcmVtZW50LFxuICAgICAgICAgICAgbWF4IC0gaW5jcmVtZW50LFxuICAgICAgICAgICAgbWF4LFxuICAgICAgICBdO1xuICAgIH1cblxuICAgIHByaXZhdGUgZ2V0TGluZVNjYWxlRG9tYWluKHtcbiAgICAgICAgbWluLFxuICAgICAgICBtYXgsXG4gICAgfToge1xuICAgICAgICBtaW46IG51bWJlcjtcbiAgICAgICAgbWF4OiBudW1iZXI7XG4gICAgfSk6IG51bWJlcltdIHtcbiAgICAgICAgaWYgKG1pbiA+IG1heCkge1xuICAgICAgICAgICAgY29uc3QgdG1wID0gbWluO1xuICAgICAgICAgICAgbWluID0gbWF4O1xuICAgICAgICAgICAgbWF4ID0gdG1wO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgZXh0ZW50UmFuZ2UgPSBNYXRoLmFicygobWF4IC0gbWluKSAvICgobWF4ICsgbWluKSAvIDIpKTtcblxuICAgICAgICAvLyBmb3Igc21hbGwgZG9tYWluIHJhbmdlcyBpbmNyZWFzZSBkb21haW4gc28gdGhhdCBzcGlrZXMgYXJlIG5vdCBleGFnZ2VyYXRlZFxuICAgICAgICBpZiAoZXh0ZW50UmFuZ2UgPCAwLjUpIHtcbiAgICAgICAgICAgIG1pbiA9IG1pbiAtIE1hdGguYWJzKG1pbikgKiAwLjU7XG4gICAgICAgICAgICBtYXggPSBtYXggKyBNYXRoLmFicyhtYXgpICogMC41O1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gaGFuZGxlcyB6ZXJvIGNhc2VcbiAgICAgICAgaWYgKG1pbiA9PT0gMCAmJiBtYXggPT09IDApIHtcbiAgICAgICAgICAgIG1pbiA9IC0xO1xuICAgICAgICAgICAgbWF4ID0gMTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIHNwZWNpYWwgY2FzZSBmb3IgcmVhbCBzbWFsbCBudW1iZXIgc2luY2Ugbm90IHVzaW5nIHNpIHByZWZpeCBhbnltb3JlXG4gICAgICAgIGlmIChNYXRoLmFicyhtYXggLSBtaW4pIDwgMC4wNCkge1xuICAgICAgICAgICAgbWF4ICs9IDAuMDQ7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBwb2ludCA9IChtYXggLSBtaW4pIC8gNDtcbiAgICAgICAgcmV0dXJuIHJvdW5kVG9PcHRpbWFsRGVjaW1hbHMoW1xuICAgICAgICAgICAgbWluLFxuICAgICAgICAgICAgbWluICsgcG9pbnQsXG4gICAgICAgICAgICBtaW4gKyAyICogcG9pbnQsXG4gICAgICAgICAgICBtYXggLSBwb2ludCxcbiAgICAgICAgICAgIG1heCxcbiAgICAgICAgXSk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBnZXRTdGFja2VkQXJlYVNjYWxlRG9tYWluKG1heDogbnVtYmVyKTogbnVtYmVyW10ge1xuICAgICAgICBjb25zdCBwb2ludCA9IG1heCAvIDQ7XG4gICAgICAgIHJldHVybiBbMCwgcG9pbnQsIHBvaW50ICogMiwgbWF4IC0gcG9pbnQsIG1heF07XG4gICAgfVxufVxuIl19