@alauda-fe/common
Version:
Alauda frontend team common codes.
347 lines • 50.9 kB
JavaScript
import { __decorate, __metadata } from "tslib";
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, HostBinding, Input, Output, TemplateRef, } from '@angular/core';
import { Observable, Subject, combineLatest, merge, of, pipe, BehaviorSubject, catchError, filter, map, switchMap, tap, withLatestFrom, } from 'rxjs';
import { DATE_TIME_FORMAT_X_AXIS, } from '../chart/public-api';
import { ObservableInput, publishRef } from '../core/public-api';
import { CommonChartService } from './common-chart.service';
import { PICKER_TIME_RANGES } from './helpers';
import { checkInterval, fillNullChartData, hasNoData } from './utils';
import * as i0 from "@angular/core";
import * as i1 from "./common-chart.service";
export class MetricChartComponent {
get overflow() {
return !this.tooltipAppendToBody && 'unset';
}
get xAccessor() {
return (d) => d.x * 1000;
}
constructor(service, cdr) {
this.service = service;
this.cdr = cdr;
this.chartType = 'area';
this.tooltipAppendToBody = true;
this.gridOffsetTop = 0;
this.barType = 'standard';
this.legendSelectAllOperation = false;
this.hideLegend = false;
this.mode = 'default';
this.tooltipTranslation = true;
this.yPlotLinesHide = false;
this.mouseUpEvent = new EventEmitter();
this.markClickEvent = new EventEmitter();
this.refreshEvent = new EventEmitter();
this.dataCompleted = new EventEmitter();
this.reload$ = new BehaviorSubject(null);
this._chartStatus$$ = new Subject();
this._status = {};
this.status$ = merge(this.chartStatus$, this._chartStatus$$).pipe(map(status => ({
...this._status,
...status,
})), tap(status => (this._status = status)), publishRef());
this.dateAxisLabelFormats = DATE_TIME_FORMAT_X_AXIS;
this.dateXAxisLabelFormats = '%H:%M';
this.yAccessor$ = this.percent$.pipe(tap(percent => {
if (percent) {
this.unit = '%';
}
}), map(percent => (d) => {
// prometheus 可能出现 Infinity情况,处理为 null
if (!Number.isFinite(d.y) || String(d.y).includes('Inf')) {
return null;
}
return percent && d.y ? +d.y * 100 : d.y === null ? d.y : +d.y;
}));
this._cacheTime = {
start: PICKER_TIME_RANGES[1].startTime(),
end: PICKER_TIME_RANGES[1].endTime(),
step: PICKER_TIME_RANGES[1].step,
};
this.defaultSeries$ = combineLatest([
this.metricApiParams$,
this.indicator$,
this.reload$,
]).pipe(tap(([, indicator]) => {
this.handleTimeParams();
this.handleDateAxisLabelFormats(this.chartParams);
this.handelChartStatus({
loading: !!indicator?.length,
failed: false,
noData: !indicator?.length,
});
}), switchMap(([_, indicator]) => indicator?.length && this.chartParams
? this.service.requestChartData(this.chartParams, indicator).pipe(catchError(() => {
this.handelChartStatus({ loading: false, failed: true });
return of(null);
}))
: of(null)));
}
ngOnInit() {
if (this.metricApiParams) {
this._cacheTime = this.metricApiParams;
}
this.series$ = (this.isCustomSeries ? this.customSeries$ : this.defaultSeries$).pipe(this.handleMetricDataPipe());
}
handleTimeParams() {
let timeParams = this.metricApiParams;
if (timeParams) {
if (checkInterval(this.metricApiParams, this._cacheTime)) {
this._cacheTime = this.metricApiParams;
}
else {
timeParams = this._cacheTime;
}
this.chartParams = {
...this.metricApiParams,
...timeParams,
};
}
}
handleMetricDataPipe() {
return pipe(tap(() => {
if (this.isCustomSeries) {
this.handleTimeParams();
}
}), filter((res) => !!this.chartParams && (!!res || !this.indicator?.length)), map((res) => {
const format = this.dataFormat || this.service.handelChartData;
// `fillNullChartData` prometheus 存在某个时间点未采集到数据的情况,这里为区分 未采集到数据为0的情况,这里前端根据时间段自动填充数据
// 后端 需要和 Prometheus API 保持兼容,还是在前端做处理填充
return format(res, this.indicator || [], this.dependOnData)?.map(item => ({
...item,
unit: this.unit,
values: fillNullChartData(this.chartParams, item.values, this.stepLine),
}));
}), tap(res => {
this.handleDateAxisLabelFormats(this.chartParams);
this.handelChartStatus({
loading: false,
noData: hasNoData(res),
});
this.cdr.markForCheck();
}), map(res => res?.length
? res
: [
{
values: fillNullChartData(this.chartParams, [], this.stepLine),
},
]), withLatestFrom(this.adaptUnit$), map(([res, _adaptUnit]) => {
if (_adaptUnit && !this.noData) {
const { base, unit } = this.service.adaptChartUnit(res, _adaptUnit);
this.unit = `unit_${unit}`;
if (typeof _adaptUnit === 'object') {
const { defaultPrefix = true, prefix } = _adaptUnit;
this.unit = defaultPrefix
? `unit_${unit}`
: `${prefix || ''}${unit}`;
}
return res.map((item) => ({
...item,
unit: this.unit,
values: item.values.map(d => ({
...d,
y: d.y ? d.y / base : d.y,
})),
}));
}
return res.map(item => ({ ...item, unit: this.unit }));
}), tap(() => {
this.dataCompleted.next();
}), publishRef());
}
refresh() {
this.reload$.next(null);
this.refreshEvent.next(null);
}
handelChartStatus(status) {
this._chartStatus$$.next({
...status,
});
}
handleDateAxisLabelFormats(params) {
if (params) {
const diff = params.end - params.start;
const m1 = 24 * 60 * 60;
const m3 = 3 * m1;
const m7 = 7 * m1;
const M_D_FORMAT = 'MM-DD';
const format = diff >= m7
? M_D_FORMAT
: diff < m7 && (diff >= m3 || diff > m1)
? `${M_D_FORMAT} ${DATE_TIME_FORMAT_X_AXIS}`
: DATE_TIME_FORMAT_X_AXIS;
this.dateAxisLabelFormats = format;
// https://d3js.org.cn/document/d3-time-format/#api-reference
this.dateXAxisLabelFormats =
diff >= m7
? '%m-%d'
: diff < m7 && (diff >= m3 || diff > m1)
? `%m-%d %H:%M`
: '%H:%M';
this.cdr.detectChanges();
}
}
static { this.ɵfac = function MetricChartComponent_Factory(t) { return new (t || MetricChartComponent)(i0.ɵɵdirectiveInject(i1.CommonChartService), i0.ɵɵdirectiveInject(i0.ChangeDetectorRef)); }; }
static { this.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: MetricChartComponent, selectors: [["acl-metric-chart"]], hostVars: 2, hostBindings: function MetricChartComponent_HostBindings(rf, ctx) { if (rf & 2) {
i0.ɵɵstyleProp("overflow", ctx.overflow);
} }, inputs: { contextCallbackFunction: "contextCallbackFunction", backgroundColor: "backgroundColor", hideHeader: "hideHeader", title: "title", hideTitle: "hideTitle", chartType: "chartType", titleDescription: "titleDescription", titleDescriptionContext: "titleDescriptionContext", unit: "unit", tooltipAppendToBody: "tooltipAppendToBody", indicator: "indicator", gridOffsetTop: "gridOffsetTop", yAxisMinStep: "yAxisMinStep", rotated: "rotated", barType: "barType", metricApiParams: "metricApiParams", tooltipPointNameTemplate: "tooltipPointNameTemplate", tooltipPointTemplate: "tooltipPointTemplate", legendTemplate: "legendTemplate", legendSelectAllOperation: "legendSelectAllOperation", legendSelectAllName: "legendSelectAllName", tooltipHide: "tooltipHide", tooltipPointFormat: "tooltipPointFormat", tooltipPointTemplateContext: "tooltipPointTemplateContext", tooltipColumnLayout: "tooltipColumnLayout", hideLegend: "hideLegend", tooltipAutoSort: "tooltipAutoSort", tooltipSortMethod: "tooltipSortMethod", hideTooltipUnit: "hideTooltipUnit", leftOperation: "leftOperation", leftOperationContext: "leftOperationContext", rightOperation: "rightOperation", mode: "mode", adaptUnit: "adaptUnit", percent: "percent", dependOnData: "dependOnData", customNoDataTitle: "customNoDataTitle", dataFormat: "dataFormat", customSeries: "customSeries", isCustomSeries: "isCustomSeries", chartStatus: "chartStatus", tooltipTranslation: "tooltipTranslation", xPlotLines: "xPlotLines", xPlotEmpty: "xPlotEmpty", yPlotLines: "yPlotLines", yPlotLinesTooltip: "yPlotLinesTooltip", yPlotLinesTooltipContext: "yPlotLinesTooltipContext", yPlotLinesHide: "yPlotLinesHide", enableZoom: "enableZoom", stepLine: "stepLine", tooltipTitleTemplate: "tooltipTitleTemplate", yAccessor: "yAccessor", curveType: "curveType" }, outputs: { mouseUpEvent: "mouseUpEvent", markClickEvent: "markClickEvent", refreshEvent: "refreshEvent", dataCompleted: "dataCompleted" }, decls: 4, vars: 51, consts: [[3, "mouseUpEvent", "markClickEvent", "refreshEvent", "contextCallbackFunction", "unit", "hideHeader", "customNoDataTitle", "chartStatus", "backgroundColor", "series", "curveType", "tooltipAppendToBody", "mode", "gridOffsetTop", "title", "chartType", "hideTitle", "tooltipHide", "tooltipSortMethod", "titleDescription", "titleDescriptionContext", "hideLegend", "dateAxisLabelFormats", "enableZoom", "stepLine", "rotated", "rightOperation", "leftOperation", "leftOperationContext", "legendTemplate", "legendSelectAllOperation", "legendSelectAllName", "yAccessor", "xAccessor", "yAxisMinStep", "hideTooltipUnit", "tooltipTitleTemplate", "tooltipAutoSort", "tooltipTranslation", "tooltipPointNameTemplate", "tooltipPointTemplate", "tooltipPointTemplateContext", "xPlotLines", "xPlotEmpty", "yPlotLinesHide", "yPlotLines"]], template: function MetricChartComponent_Template(rf, ctx) { if (rf & 1) {
i0.ɵɵelementStart(0, "acl-view-zchart", 0);
i0.ɵɵpipe(1, "async");
i0.ɵɵpipe(2, "async");
i0.ɵɵpipe(3, "async");
i0.ɵɵlistener("mouseUpEvent", function MetricChartComponent_Template_acl_view_zchart_mouseUpEvent_0_listener($event) { return ctx.mouseUpEvent.next($event); })("markClickEvent", function MetricChartComponent_Template_acl_view_zchart_markClickEvent_0_listener($event) { return ctx.markClickEvent.next($event); })("refreshEvent", function MetricChartComponent_Template_acl_view_zchart_refreshEvent_0_listener() { return ctx.refresh(); });
i0.ɵɵelementEnd();
} if (rf & 2) {
i0.ɵɵclassProp("overflow-display", !ctx.tooltipAppendToBody);
i0.ɵɵproperty("contextCallbackFunction", ctx.contextCallbackFunction)("unit", ctx.unit)("hideHeader", ctx.hideHeader)("customNoDataTitle", ctx.customNoDataTitle)("chartStatus", i0.ɵɵpipeBind1(1, 45, ctx.status$))("backgroundColor", ctx.backgroundColor)("series", i0.ɵɵpipeBind1(2, 47, ctx.series$))("curveType", ctx.curveType)("tooltipAppendToBody", ctx.tooltipAppendToBody)("mode", ctx.mode)("gridOffsetTop", ctx.gridOffsetTop)("title", ctx.title)("chartType", ctx.chartType)("hideTitle", ctx.hideTitle)("tooltipHide", ctx.tooltipHide)("tooltipSortMethod", ctx.tooltipSortMethod)("titleDescription", ctx.titleDescription)("titleDescriptionContext", ctx.titleDescriptionContext)("hideLegend", ctx.dependOnData && ctx.noData || ctx.hideLegend)("dateAxisLabelFormats", ctx.dateAxisLabelFormats)("enableZoom", ctx.enableZoom)("stepLine", ctx.stepLine)("rotated", ctx.rotated)("rightOperation", ctx.rightOperation)("leftOperation", ctx.leftOperation)("leftOperationContext", ctx.leftOperationContext)("legendTemplate", ctx.legendTemplate)("legendSelectAllOperation", ctx.legendSelectAllOperation)("legendSelectAllName", ctx.legendSelectAllName)("yAccessor", ctx.yAccessor || i0.ɵɵpipeBind1(3, 49, ctx.yAccessor$))("xAccessor", ctx.xAccessor)("yAxisMinStep", ctx.yAxisMinStep)("hideTooltipUnit", ctx.hideTooltipUnit)("tooltipTitleTemplate", ctx.tooltipTitleTemplate)("tooltipAutoSort", ctx.tooltipAutoSort)("tooltipTranslation", ctx.tooltipTranslation)("tooltipPointNameTemplate", ctx.tooltipPointNameTemplate)("tooltipPointTemplate", ctx.tooltipPointTemplate)("tooltipPointTemplateContext", ctx.tooltipPointTemplateContext)("xPlotLines", ctx.xPlotLines)("xPlotEmpty", ctx.xPlotEmpty)("yPlotLinesHide", ctx.yPlotLinesHide)("yPlotLines", ctx.yPlotLines);
} }, styles: ["[_nghost-%COMP%]{flex:1;display:flex;height:100%;overflow:hidden}[_nghost-%COMP%] .overflow-display[_ngcontent-%COMP%]{overflow:unset}"], changeDetection: 0 }); }
}
__decorate([
ObservableInput(),
__metadata("design:type", Observable)
], MetricChartComponent.prototype, "unit$", void 0);
__decorate([
ObservableInput(),
__metadata("design:type", Observable)
], MetricChartComponent.prototype, "indicator$", void 0);
__decorate([
ObservableInput(),
__metadata("design:type", Observable)
], MetricChartComponent.prototype, "metricApiParams$", void 0);
__decorate([
ObservableInput(),
__metadata("design:type", Observable)
], MetricChartComponent.prototype, "adaptUnit$", void 0);
__decorate([
ObservableInput(),
__metadata("design:type", Observable)
], MetricChartComponent.prototype, "percent$", void 0);
__decorate([
ObservableInput(),
__metadata("design:type", Observable)
], MetricChartComponent.prototype, "customSeries$", void 0);
__decorate([
ObservableInput(),
__metadata("design:type", Observable)
], MetricChartComponent.prototype, "chartStatus$", void 0);
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MetricChartComponent, [{
type: Component,
args: [{ selector: 'acl-metric-chart', changeDetection: ChangeDetectionStrategy.OnPush, template: "<acl-view-zchart\n [class.overflow-display]=\"!tooltipAppendToBody\"\n [contextCallbackFunction]=\"contextCallbackFunction\"\n [unit]=\"unit\"\n [hideHeader]=\"hideHeader\"\n [customNoDataTitle]=\"customNoDataTitle\"\n [chartStatus]=\"status$ | async\"\n [backgroundColor]=\"backgroundColor\"\n [series]=\"series$ | async\"\n [curveType]=\"curveType\"\n [tooltipAppendToBody]=\"tooltipAppendToBody\"\n [mode]=\"mode\"\n [gridOffsetTop]=\"gridOffsetTop\"\n [title]=\"title\"\n [chartType]=\"chartType\"\n [hideTitle]=\"hideTitle\"\n [tooltipHide]=\"tooltipHide\"\n [tooltipSortMethod]=\"tooltipSortMethod\"\n [titleDescription]=\"titleDescription\"\n [titleDescriptionContext]=\"titleDescriptionContext\"\n [hideLegend]=\"(dependOnData && noData) || hideLegend\"\n [dateAxisLabelFormats]=\"dateAxisLabelFormats\"\n [enableZoom]=\"enableZoom\"\n [stepLine]=\"stepLine\"\n [rotated]=\"rotated\"\n [rightOperation]=\"rightOperation\"\n [leftOperation]=\"leftOperation\"\n [leftOperationContext]=\"leftOperationContext\"\n [legendTemplate]=\"legendTemplate\"\n [legendSelectAllOperation]=\"legendSelectAllOperation\"\n [legendSelectAllName]=\"legendSelectAllName\"\n [yAccessor]=\"yAccessor || (yAccessor$ | async)\"\n [xAccessor]=\"xAccessor\"\n [yAxisMinStep]=\"yAxisMinStep\"\n [hideTooltipUnit]=\"hideTooltipUnit\"\n [tooltipTitleTemplate]=\"tooltipTitleTemplate\"\n [tooltipAutoSort]=\"tooltipAutoSort\"\n [tooltipTranslation]=\"tooltipTranslation\"\n [tooltipPointNameTemplate]=\"tooltipPointNameTemplate\"\n [tooltipPointTemplate]=\"tooltipPointTemplate\"\n [tooltipPointTemplateContext]=\"tooltipPointTemplateContext\"\n [xPlotLines]=\"xPlotLines\"\n [xPlotEmpty]=\"xPlotEmpty\"\n [yPlotLinesHide]=\"yPlotLinesHide\"\n [yPlotLines]=\"yPlotLines\"\n (mouseUpEvent)=\"mouseUpEvent.next($event)\"\n (markClickEvent)=\"markClickEvent.next($event)\"\n (refreshEvent)=\"refresh()\"\n>\n</acl-view-zchart>\n<!-- [tooltipPointFormat]=\"tooltipPointFormat\" -->\n", styles: [":host{flex:1;display:flex;height:100%;overflow:hidden}:host .overflow-display{overflow:unset}\n"] }]
}], () => [{ type: i1.CommonChartService }, { type: i0.ChangeDetectorRef }], { contextCallbackFunction: [{
type: Input
}], backgroundColor: [{
type: Input
}], hideHeader: [{
type: Input
}], title: [{
type: Input
}], hideTitle: [{
type: Input
}], chartType: [{
type: Input
}], titleDescription: [{
type: Input
}], titleDescriptionContext: [{
type: Input
}], unit: [{
type: Input
}], tooltipAppendToBody: [{
type: Input
}], overflow: [{
type: HostBinding,
args: ['style.overflow']
}], unit$: [], indicator: [{
type: Input
}], gridOffsetTop: [{
type: Input
}], yAxisMinStep: [{
type: Input
}], rotated: [{
type: Input
}], barType: [{
type: Input
}], indicator$: [], metricApiParams: [{
type: Input
}], metricApiParams$: [], tooltipPointNameTemplate: [{
type: Input
}], tooltipPointTemplate: [{
type: Input
}], legendTemplate: [{
type: Input
}], legendSelectAllOperation: [{
type: Input
}], legendSelectAllName: [{
type: Input
}], tooltipHide: [{
type: Input
}], tooltipPointFormat: [{
type: Input
}], tooltipPointTemplateContext: [{
type: Input
}], tooltipColumnLayout: [{
type: Input
}], hideLegend: [{
type: Input
}], tooltipAutoSort: [{
type: Input
}], tooltipSortMethod: [{
type: Input
}], hideTooltipUnit: [{
type: Input
}], leftOperation: [{
type: Input
}], leftOperationContext: [{
type: Input
}], rightOperation: [{
type: Input
}], mode: [{
type: Input
}], adaptUnit: [{
type: Input
}], adaptUnit$: [], percent: [{
type: Input
}], percent$: [], dependOnData: [{
type: Input
}], customNoDataTitle: [{
type: Input
}], dataFormat: [{
type: Input
}], customSeries: [{
type: Input
}], customSeries$: [], isCustomSeries: [{
type: Input
}], chartStatus: [{
type: Input
}], chartStatus$: [], tooltipTranslation: [{
type: Input
}], xPlotLines: [{
type: Input
}], xPlotEmpty: [{
type: Input
}], yPlotLines: [{
type: Input
}], yPlotLinesTooltip: [{
type: Input
}], yPlotLinesTooltipContext: [{
type: Input
}], yPlotLinesHide: [{
type: Input
}], enableZoom: [{
type: Input
}], stepLine: [{
type: Input
}], tooltipTitleTemplate: [{
type: Input
}], yAccessor: [{
type: Input
}], curveType: [{
type: Input
}], mouseUpEvent: [{
type: Output
}], markClickEvent: [{
type: Output
}], refreshEvent: [{
type: Output
}], dataCompleted: [{
type: Output
}] }); })();
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MetricChartComponent, { className: "MetricChartComponent" }); })();
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWV0cmljLWNoYXJ0LmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL2xpYnMvY29tbW9uL3NyYy9tZXRyaWMtY2hhcnQvbWV0cmljLWNoYXJ0LmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uL2xpYnMvY29tbW9uL3NyYy9tZXRyaWMtY2hhcnQvbWV0cmljLWNoYXJ0LmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFDQSxPQUFPLEVBQ0wsdUJBQXVCLEVBQ3ZCLGlCQUFpQixFQUNqQixTQUFTLEVBQ1QsWUFBWSxFQUNaLFdBQVcsRUFDWCxLQUFLLEVBRUwsTUFBTSxFQUNOLFdBQVcsR0FDWixNQUFNLGVBQWUsQ0FBQztBQUV2QixPQUFPLEVBQ0wsVUFBVSxFQUNWLE9BQU8sRUFDUCxhQUFhLEVBQ2IsS0FBSyxFQUNMLEVBQUUsRUFDRixJQUFJLEVBQ0osZUFBZSxFQUNmLFVBQVUsRUFDVixNQUFNLEVBQ04sR0FBRyxFQUNILFNBQVMsRUFDVCxHQUFHLEVBQ0gsY0FBYyxHQUNmLE1BQU0sTUFBTSxDQUFDO0FBR2QsT0FBTyxFQUdMLHVCQUF1QixHQUN4QixNQUFNLHFCQUFxQixDQUFDO0FBQzdCLE9BQU8sRUFBYSxlQUFlLEVBQUUsVUFBVSxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFRNUUsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDNUQsT0FBTyxFQUFtQixrQkFBa0IsRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUVoRSxPQUFPLEVBQUUsYUFBYSxFQUFFLGlCQUFpQixFQUFFLFNBQVMsRUFBRSxNQUFNLFNBQVMsQ0FBQzs7O0FBUXRFLE1BQU0sT0FBTyxvQkFBb0I7SUFxQi9CLElBQ0ksUUFBUTtRQUNWLE9BQU8sQ0FBQyxJQUFJLENBQUMsbUJBQW1CLElBQUksT0FBTyxDQUFDO0lBQzlDLENBQUM7SUE0SUQsSUFBSSxTQUFTO1FBQ1gsT0FBTyxD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QUFtQjtrQkFBM0IsS0FBSztZQUVHLFVBQVU7a0JBQWxCLEtBQUs7WUFFRyxlQUFlO2tCQUF2QixLQUFLO1lBRUcsaUJBQWlCO2tCQUF6QixLQUFLO1lBRUcsZUFBZTtrQkFBdkIsS0FBSztZQUVHLGFBQWE7a0JBQXJCLEtBQUs7WUFFRyxvQkFBb0I7a0JBQTVCLEtBQUs7WUFFRyxjQUFjO2tCQUF0QixLQUFLO1lBRUcsSUFBSTtrQkFBWixLQUFLO1lBR04sU0FBUztrQkFEUixLQUFLO1lBSU4sVUFBVSxNQUdWLE9BQU87a0JBRE4sS0FBSztZQUlOLFFBQVEsTUFFQyxZQUFZO2tCQUFwQixLQUFLO1lBRUcsaUJBQWlCO2tCQUF6QixLQUFLO1lBRUcsVUFBVTtrQkFBbEIsS0FBSztZQUtHLFlBQVk7a0JBQXBCLEtBQUs7WUFDYSxhQUFhLE1BRXZCLGNBQWM7a0JBQXRCLEtBQUs7WUFJRyxXQUFXO2tCQUFuQixLQUFLO1lBRU4sWUFBWSxNQUVILGtCQUFrQjtrQkFBMUIsS0FBSztZQUVHLFVBQVU7a0JBQWxCLEtBQUs7WUFFRyxVQUFVO2tCQUFsQixLQUFLO1lBRUcsVUFBVTtrQkFBbEIsS0FBSztZQUVHLGlCQUFpQjtrQkFBekIsS0FBSztZQUVHLHdCQUF3QjtrQkFBaEMsS0FBSztZQUVHLGNBQWM7a0JBQXRCLEtBQUs7WUFFRyxVQUFVO2tCQUFsQixLQUFLO1lBRUcsUUFBUTtrQkFBaEIsS0FBSztZQUVHLG9CQUFvQjtrQkFBNUIsS0FBSztZQUVHLFNBQVM7a0JBQWpCLEtBQUs7WUFFRyxTQUFTO2tCQUFqQixLQUFLO1lBRUksWUFBWTtrQkFBckIsTUFBTTtZQUVHLGNBQWM7a0JBQXZCLE1BQU07WUFFRyxZQUFZO2tCQUFyQixNQUFNO1lBRUcsYUFBYTtrQkFBdEIsTUFBTTs7a0ZBL0lJLG9CQUFvQiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IFRvb2x0aXBDb250ZXh0IH0gZnJvbSAnQGFsYXVkYS9jaGFydCc7XG5pbXBvcnQge1xuICBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneSxcbiAgQ2hhbmdlRGV0ZWN0b3JSZWYsXG4gIENvbXBvbmVudCxcbiAgRXZlbnRFbWl0dGVyLFxuICBIb3N0QmluZGluZyxcbiAgSW5wdXQsXG4gIE9uSW5pdCxcbiAgT3V0cHV0LFxuICBUZW1wbGF0ZVJlZixcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBDdXJ2ZUZhY3RvcnksIEN1cnZlRmFjdG9yeUxpbmVPbmx5IH0gZnJvbSAnZDMnO1xuaW1wb3J0IHtcbiAgT2JzZXJ2YWJsZSxcbiAgU3ViamVjdCxcbiAgY29tYmluZUxhdGVzdCxcbiAgbWVyZ2UsXG4gIG9mLFxuICBwaXBlLFxuICBCZWhhdmlvclN1YmplY3QsXG4gIGNhdGNoRXJyb3IsXG4gIGZpbHRlcixcbiAgbWFwLFxuICBzd2l0Y2hNYXAsXG4gIHRhcCxcbiAgd2l0aExhdGVzdEZyb20sXG59IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgQ2hhcnQsIFRvb2x0aXBWYWx1ZSB9IGZyb20gJ3p6LWNoYXJ0JztcblxuaW1wb3J0IHtcbiAgQXJlYVBvc2l0aW9uLFxuICBDb250ZXh0SXRlbSxcbiAgREFURV9USU1FX0ZPUk1BVF9YX0FYSVMsXG59IGZyb20gJy4uL2NoYXJ0L3B1YmxpYy1hcGknO1xuaW1wb3J0IHsgU3RyaW5nTWFwLCBPYnNlcnZhYmxlSW5wdXQsIHB1Ymxpc2hSZWYgfSBmcm9tICcuLi9jb3JlL3B1YmxpYy1hcGknO1xuaW1wb3J0IHtcbiAgQ2hhcnREYXRhLFxuICBDaGFydERhdGFJdGVtLFxuICBDaGFydFN0YXR1cyxcbiAgWFBsb3RMaW5lcyxcbn0gZnJvbSAnLi4vdmlldy1jaGFydC9wdWJsaWMtYXBpJztcblxuaW1wb3J0IHsgQ29tbW9uQ2hhcnRTZXJ2aWNlIH0gZnJvbSAnLi9jb21tb24tY2hhcnQuc2VydmljZSc7XG5pbXBvcnQgeyBNYXRjaFVuaXRQYXJhbXMsIFBJQ0tFUl9USU1FX1JBTkdFUyB9IGZyb20gJy4vaGVscGVycyc7XG5pbXBvcnQgeyBJbmRpY2F0b3IsIE1ldHJpY0FwaVBhcmFtcywgTWV0cmljUmVzdWx0IH0gZnJvbSAnLi90eXBlcyc7XG5pbXBvcnQgeyBjaGVja0ludGVydmFsLCBmaWxsTnVsbENoYXJ0RGF0YSwgaGFzTm9EYXRhIH0gZnJvbSAnLi91dGlscyc7XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ2FjbC1tZXRyaWMtY2hhcnQnLFxuICB0ZW1wbGF0ZVVybDogJy4vbWV0cmljLWNoYXJ0LmNvbXBvbmVudC5odG1sJyxcbiAgc3R5bGVVcmxzOiBbJy4vbWV0cmljLWNoYXJ0LmNvbXBvbmVudC5zY3NzJ10sXG4gIGNoYW5nZURldGVjdGlvbjogQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3kuT25QdXNoLFxufSlcbmV4cG9ydCBjbGFzcyBNZXRyaWNDaGFydENvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCB7XG4gIEBJbnB1dCgpIGNvbnRleHRDYWxsYmFja0Z1bmN0aW9uOiAoY29udGV4dDogQ2hhcnQpID0+IHZvaWQ7XG5cbiAgQElucHV0KCkgYmFja2dyb3VuZENvbG9yOiBzdHJpbmc7XG5cbiAgQElucHV0KCkgaGlkZUhlYWRlcjogYm9vbGVhbjtcblxuICBASW5wdXQoKSB0aXRsZTogc3RyaW5nIHwgVGVtcGxhdGVSZWY8dW5rbm93bj47XG5cbiAgQElucHV0KCkgaGlkZVRpdGxlOiBib29sZWFuO1xuXG4gIEBJbnB1dCgpIGNoYXJ0VHlwZTogJ2xpbmUnIHwgJ2FyZWEnIHwgJ2JhcicgfCAncG9pbnQnIHwgJ3N0YXQnID0gJ2FyZWEnO1xuXG4gIEBJbnB1dCgpIHRpdGxlRGVzY3JpcHRpb246IHN0cmluZyB8IFRlbXBsYXRlUmVmPHVua25vd24+O1xuXG4gIEBJbnB1dCgpIHRpdGxlRGVzY3JpcHRpb25Db250ZXh0OiBTdHJpbmdNYXA7XG5cbiAgQElucHV0KCkgdW5pdDogc3RyaW5nO1xuXG4gIEBJbnB1dCgpIHRvb2x0aXBBcHBlbmRUb0JvZHkgPSB0cnVlO1xuXG4gIEBIb3N0QmluZGluZygnc3R5bGUub3ZlcmZsb3cnKVxuICBnZXQgb3ZlcmZsb3coKSB7XG4gICAgcmV0dXJuICF0aGlzLnRvb2x0aXBBcHBlbmRUb0JvZHkgJiYgJ3Vuc2V0JztcbiAgfVxuXG4gIEBPYnNlcnZhYmxlSW5wdXQoKVxuICB1bml0JCE6IE9ic2VydmFibGU8c3RyaW5nPjtcblxuICBASW5wdXQoKSBpbmRpY2F0b3I6IEluZGljYXRvcltdO1xuXG4gIEBJbnB1dCgpIGdyaWRPZmZzZXRUb3AgPSAwO1xuXG4gIEBJbnB1dCgpIHlBeGlzTWluU3RlcD86IG51bWJlcjtcblxuICBASW5wdXQoKSByb3RhdGVkOiBib29sZWFuO1xuXG4gIEBJbnB1dCgpIGJhclR5cGU6ICdzdGFuZGFyZCcgfCAnc3RhY2tlZCcgPSAnc3RhbmRhcmQnO1xuXG4gIEBPYnNlcnZhYmxlSW5wdXQoKVxuICBpbmRpY2F0b3IkITogT2JzZXJ2YWJsZTxJbmRpY2F0b3JbXT47XG5cbiAgQElucHV0KCkgbWV0cmljQXBpUGFyYW1zOiBNZXRyaWNBcGlQYXJhbXM7XG5cbiAgQE9ic2VydmFibGVJbnB1dCgpXG4gIG1ldHJpY0FwaVBhcmFtcyQhOiBPYnNlcnZhYmxlPE1ldHJpY0FwaVBhcmFtcz47XG5cbiAgQElucHV0KCkgdG9vbHRpcFBvaW50TmFtZVRlbXBsYXRlOiBUZW1wbGF0ZVJlZjx1bmtub3duPjtcblxuICBASW5wdXQoKSB0b29sdGlwUG9pbnRUZW1wbGF0ZTogVGVtcGxhdGVSZWY8dW5rbm93bj47XG5cbiAgQElucHV0KCkgbGVnZW5kVGVtcGxhdGU6IFRlbXBsYXRlUmVmPHVua25vd24+IHwgc3RyaW5nO1xuXG4gIEBJbnB1dCgpIGxlZ2VuZFNlbGVjdEFsbE9wZXJhdGlvbiA9IGZhbHNlO1xuXG4gIEBJbnB1dCgpIGxlZ2VuZFNlbGVjdEFsbE5hbWU6IHN0cmluZztcblxuICBASW5wdXQoKSB0b29sdGlwSGlkZTogYm9vbGVhbjtcblxuICBASW5wdXQoKSB0b29sdGlwUG9pbnRGb3JtYXQ6IChkOiBDb250ZXh0SXRlbSkgPT4gbnVtYmVyIHwgc3RyaW5nO1xuXG4gIEBJbnB1dCgpIHRvb2x0aXBQb2ludFRlbXBsYXRlQ29udGV4dDogeyBba2V5OiBzdHJpbmddOiBhbnkgfTtcblxuICBASW5wdXQoKSB0b29sdGlwQ29sdW1uTGF5b3V0OiBib29sZWFuO1xuXG4gIEBJbnB1dCgpIGhpZGVMZWdlbmQgPSBmYWxzZTtcblxuICBASW5wdXQoKSB0b29sdGlwQXV0b1NvcnQ6IGJvb2xlYW47XG5cbiAgQElucHV0KCkgdG9vbHRpcFNvcnRNZXRob2Q6IChhOiBUb29sdGlwVmFsdWUsIGI6IFRvb2x0aXBWYWx1ZSkgPT4gbnVtYmVyO1xuXG4gIEBJbnB1dCgpIGhpZGVUb29sdGlwVW5pdDogYm9vbGVhbjtcblxuICBASW5wdXQoKSBsZWZ0T3BlcmF0aW9uOiBUZW1wbGF0ZVJlZjx1bmtub3duPjtcblxuICBASW5wdXQoKSBsZWZ0T3BlcmF0aW9uQ29udGV4dDogU3RyaW5nTWFwO1xuXG4gIEBJbnB1dCgpIHJpZ2h0T3BlcmF0aW9uOiBUZW1wbGF0ZVJlZjx1bmtub3duPjtcblxuICBASW5wdXQoKSBtb2RlOiAnY2FyZCcgfCAnZGVmYXVsdCcgPSAnZGVmYXVsdCc7XG5cbiAgQElucHV0KClcbiAgYWRhcHRVbml0OiBib29sZWFuIHwgTWF0Y2hVbml0UGFyYW1zO1xuXG4gIEBPYnNlcnZhYmxlSW5wdXQoKVxuICBhZGFwdFVuaXQkITogT2JzZXJ2YWJsZTxib29sZWFuIHwgTWF0Y2hVbml0UGFyYW1zPjtcblxuICBASW5wdXQoKVxuICBwZXJjZW50OiBib29sZWFuO1xuXG4gIEBPYnNlcnZhYmxlSW5wdXQoKVxuICBwZXJjZW50JCE6IE9ic2VydmFibGU8Ym9vbGVhbj47XG5cbiAgQElucHV0KCkgZGVwZW5kT25EYXRhOiBib29sZWFuO1xuXG4gIEBJbnB1dCgpIGN1c3RvbU5vRGF0YVRpdGxlOiBUZW1wbGF0ZVJlZjx1bmtub3duPiB8IHN0cmluZztcblxuICBASW5wdXQoKSBkYXRhRm9ybWF0OiAoXG4gICAgZDogTWV0cmljUmVzdWx0W10sXG4gICAgaW5kaWNhdG9yOiBJbmRpY2F0b3JbXSxcbiAgKSA9PiBDaGFydERhdGFbXTtcblxuICBASW5wdXQoKSBjdXN0b21TZXJpZXMhOiBNZXRyaWNSZXN1bHRbXTtcbiAgQE9ic2VydmFibGVJbnB1dCgpIGN1c3RvbVNlcmllcyQhOiBPYnNlcnZhYmxlPE1ldHJpY1Jlc3VsdFtdPjtcblxuICBASW5wdXQoKSBpc0N1c3RvbVNlcmllczogYm9vbGVhbjtcblxuICBzZXJpZXMkOiBPYnNlcnZhYmxlPENoYXJ0RGF0YVtdPjtcblxuICBASW5wdXQoKSBjaGFydFN0YXR1czogQ2hhcnRTdGF0dXM7XG4gIEBPYnNlcnZhYmxlSW5wdXQoKVxuICBjaGFydFN0YXR1cyQhOiBPYnNlcnZhYmxlPENoYXJ0U3RhdHVzPjtcblxuICBASW5wdXQoKSB0b29sdGlwVHJhbnNsYXRpb24gPSB0cnVlO1xuXG4gIEBJbnB1dCgpIHhQbG90TGluZXM6IFhQbG90TGluZXM7XG5cbiAgQElucHV0KCkgeFBsb3RFbXB0eTogYm9vbGVhbjtcblxuICBASW5wdXQoKSB5UGxvdExpbmVzOiBUb29sdGlwQ29udGV4dDtcblxuICBASW5wdXQoKSB5UGxvdExpbmVzVG9vbHRpcDogVGVtcGxhdGVSZWY8dW5rbm93bj47XG5cbiAgQElucHV0KCkgeVBsb3RMaW5lc1Rvb2x0aXBDb250ZXh0OiBTdHJpbmdNYXA7XG5cbiAgQElucHV0KCkgeVBsb3RMaW5lc0hpZGUgPSBmYWxzZTtcblxuICBASW5wdXQoKSBlbmFibGVab29tOiBib29sZWFuO1xuXG4gIEBJbnB1dCgpIHN0ZXBMaW5lOiBib29sZWFuO1xuXG4gIEBJbnB1dCgpIHRvb2x0aXBUaXRsZVRlbXBsYXRlOiBUZW1wbGF0ZVJlZjx1bmtub3duPjtcblxuICBASW5wdXQoKSB5QWNjZXNzb3I6IChkOiBDaGFydERhdGFJdGVtKSA9PiBudW1iZXI7XG5cbiAgQElucHV0KCkgY3VydmVUeXBlOiBDdXJ2ZUZhY3RvcnkgfCBDdXJ2ZUZhY3RvcnlMaW5lT25seTtcblxuICBAT3V0cHV0KCkgbW91c2VVcEV2ZW50ID0gbmV3IEV2ZW50RW1pdHRlcjxBcmVhUG9zaXRpb24+KCk7XG5cbiAgQE91dHB1dCgpIG1hcmtDbGlja0V2ZW50ID0gbmV3IEV2ZW50RW1pdHRlcjxUb29sdGlwQ29udGV4dD4oKTtcblxuICBAT3V0cHV0KCkgcmVmcmVzaEV2ZW50ID0gbmV3IEV2ZW50RW1pdHRlcigpO1xuXG4gIEBPdXRwdXQoKSBkYXRhQ29tcGxldGVkID0gbmV3IEV2ZW50RW1pdHRlcjx2b2lkPigpO1xuXG4gIHJlbG9hZCQgPSBuZXcgQmVoYXZpb3JTdWJqZWN0KG51bGwpO1xuXG4gIF9jaGFydFN0YXR1cyQkID0gbmV3IFN1YmplY3Q8Q2hhcnRTdGF0dXM+KCk7XG4gIF9zdGF0dXM6IENoYXJ0U3RhdHVzID0ge307XG4gIHN0YXR1cyQgPSBtZXJnZSh0aGlzLmNoYXJ0U3RhdHVzJCwgdGhpcy5fY2hhcnRTdGF0dXMkJCkucGlwZShcbiAgICBtYXAoc3RhdHVzID0+ICh7XG4gICAgICAuLi50aGlzLl9zdGF0dXMsXG4gICAgICAuLi5zdGF0dXMsXG4gICAgfSkpLFxuICAgIHRhcChzdGF0dXMgPT4gKHRoaXMuX3N0YXR1cyA9IHN0YXR1cykpLFxuICAgIHB1Ymxpc2hSZWYoKSxcbiAgKTtcblxuICBub0RhdGE6IGJvb2xlYW47XG5cbiAgZGF0ZUF4aXNMYWJlbEZvcm1hdHMgPSBEQVRFX1RJTUVfRk9STUFUX1hfQVhJUztcblxuICBkYXRlWEF4aXNMYWJlbEZvcm1hdHMgPSAnJUg6JU0nO1xuXG4gIGdldCB4QWNjZXNzb3IoKSB7XG4gICAgcmV0dXJuIChkOiBDaGFydERhdGFJdGVtPHsgeDogbnVtYmVyOyB5OiBudW1iZXIgfT4pID0+IGQueCAqIDEwMDA7XG4gIH1cblxuICB5QWNjZXNzb3IkID0gdGhpcy5wZXJjZW50JC5waXBlKFxuICAgIHRhcChwZXJjZW50ID0+IHtcbiAgICAgIGlmIChwZXJjZW50KSB7XG4gICAgICAgIHRoaXMudW5pdCA9ICclJztcbiAgICAgIH1cbiAgICB9KSxcbiAgICBtYXAocGVyY2VudCA9PiAoZDogQ2hhcnREYXRhSXRlbTx7IHg6IG51bWJlcjsgeTogbnVtYmVyIH0+KSA9PiB7XG4gICAgICAvLyBwcm9tZXRoZXVzIOWPr+iDveWHuueOsCBJbmZpbml0eeaDheWGte+8jOWkhOeQhuS4uiBudWxsXG4gICAgICBpZiAoIU51bWJlci5pc0Zpbml0ZShkLnkpIHx8IFN0cmluZyhkLnkpLmluY2x1ZGVzKCdJbmYnKSkge1xuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgIH1cbiAgICAgIHJldHVybiBwZXJjZW50ICYmIGQueSA/ICtkLnkgKiAxMDAgOiBkLnkgPT09IG51bGwgPyBkLnkgOiArZC55O1xuICAgIH0pLFxuICApO1xuXG4gIF9jYWNoZVRpbWU6IE1ldHJpY0FwaVBhcmFtcyA9IHtcbiAgICBzdGFydDogUElDS0VSX1RJTUVfUkFOR0VTWzFdLnN0YXJ0VGltZSgpLFxuICAgIGVuZDogUElDS0VSX1RJTUVfUkFOR0VTWzFdLmVuZFRpbWUoKSxcbiAgICBzdGVwOiBQSUNLRVJfVElNRV9SQU5HRVNbMV0uc3RlcCxcbiAgfTtcblxuICBwcml2YXRlIGNoYXJ0UGFyYW1zOiBNZXRyaWNBcGlQYXJhbXM7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSByZWFkb25seSBzZXJ2aWNlOiBDb21tb25DaGFydFNlcnZpY2UsXG4gICAgcHJpdmF0ZSByZWFkb25seSBjZHI6IENoYW5nZURldGVjdG9yUmVmLFxuICApIHt9XG5cbiAgbmdPbkluaXQoKSB7XG4gICAgaWYgKHRoaXMubWV0cmljQXBpUGFyYW1zKSB7XG4gICAgICB0aGlzLl9jYWNoZVRpbWUgPSB0aGlzLm1ldHJpY0FwaVBhcmFtcztcbiAgICB9XG5cbiAgICB0aGlzLnNlcmllcyQgPSAoXG4gICAgICB0aGlzLmlzQ3VzdG9tU2VyaWVzID8gdGhpcy5jdXN0b21TZXJpZXMkIDogdGhpcy5kZWZhdWx0U2VyaWVzJFxuICAgICkucGlwZSh0aGlzLmhhbmRsZU1ldHJpY0RhdGFQaXBlKCkpO1xuICB9XG5cbiAgZGVmYXVsdFNlcmllcyQ6IE9ic2VydmFibGU8TWV0cmljUmVzdWx0W10+ID0gY29tYmluZUxhdGVzdChbXG4gICAgdGhpcy5tZXRyaWNBcGlQYXJhbXMkLFxuICAgIHRoaXMuaW5kaWNhdG9yJCxcbiAgICB0aGlzLnJlbG9hZCQsXG4gIF0pLnBpcGUoXG4gICAgdGFwKChbLCBpbmRpY2F0b3JdKSA9PiB7XG4gICAgICB0aGlzLmhhbmRsZVRpbWVQYXJhbXMoKTtcbiAgICAgIHRoaXMuaGFuZGxlRGF0ZUF4aXNMYWJlbEZvcm1hdHModGhpcy5jaGFydFBhcmFtcyk7XG4gICAgICB0aGlzLmhhbmRlbENoYXJ0U3RhdHVzKHtcbiAgICAgICAgbG9hZGluZzogISFpbmRpY2F0b3I/Lmxlbmd0aCxcbiAgICAgICAgZmFpbGVkOiBmYWxzZSxcbiAgICAgICAgbm9EYXRhOiAhaW5kaWNhdG9yPy5sZW5ndGgsXG4gICAgICB9KTtcbiAgICB9KSxcbiAgICBzd2l0Y2hNYXAoKFtfLCBpbmRpY2F0b3JdKSA9PlxuICAgICAgaW5kaWNhdG9yPy5sZW5ndGggJiYgdGhpcy5jaGFydFBhcmFtc1xuICAgICAgICA/IHRoaXMuc2VydmljZS5yZXF1ZXN0Q2hhcnREYXRhKHRoaXMuY2hhcnRQYXJhbXMsIGluZGljYXRvcikucGlwZShcbiAgICAgICAgICAgIGNhdGNoRXJyb3IoKCkgPT4ge1xuICAgICAgICAgICAgICB0aGlzLmhhbmRlbENoYXJ0U3RhdHVzKHsgbG9hZGluZzogZmFsc2UsIGZhaWxlZDogdHJ1ZSB9KTtcbiAgICAgICAgICAgICAgcmV0dXJuIG9mKG51bGwpO1xuICAgICAgICAgICAgfSksXG4gICAgICAgICAgKVxuICAgICAgICA6IG9mKG51bGwpLFxuICAgICksXG4gICk7XG5cbiAgaGFuZGxlVGltZVBhcmFtcygpIHtcbiAgICBsZXQgdGltZVBhcmFtcyA9IHRoaXMubWV0cmljQXBpUGFyYW1zO1xuICAgIGlmICh0aW1lUGFyYW1zKSB7XG4gICAgICBpZiAoY2hlY2tJbnRlcnZhbCh0aGlzLm1ldHJpY0FwaVBhcmFtcywgdGhpcy5fY2FjaGVUaW1lKSkge1xuICAgICAgICB0aGlzLl9jYWNoZVRpbWUgPSB0aGlzLm1ldHJpY0FwaVBhcmFtcztcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRpbWVQYXJhbXMgPSB0aGlzLl9jYWNoZVRpbWU7XG4gICAgICB9XG4gICAgICB0aGlzLmNoYXJ0UGFyYW1zID0ge1xuICAgICAgICAuLi50aGlzLm1ldHJpY0FwaVBhcmFtcyxcbiAgICAgICAgLi4udGltZVBhcmFtcyxcbiAgICAgIH07XG4gICAgfVxuICB9XG5cbiAgaGFuZGxlTWV0cmljRGF0YVBpcGUoKSB7XG4gICAgcmV0dXJuIHBpcGUoXG4gICAgICB0YXAoKCkgPT4ge1xuICAgICAgICBpZiAodGhpcy5pc0N1c3RvbVNlcmllcykge1xuICAgICAgICAgIHRoaXMuaGFuZGxlVGltZVBhcmFtcygpO1xuICAgICAgICB9XG4gICAgICB9KSxcbiAgICAgIGZpbHRlcihcbiAgICAgICAgKHJlczogTWV0cmljUmVzdWx0W10pID0+XG4gICAgICAgICAgISF0aGlzLmNoYXJ0UGFyYW1zICYmICghIXJlcyB8fCAhdGhpcy5pbmRpY2F0b3I/Lmxlbmd0aCksXG4gICAgICApLFxuICAgICAgbWFwKChyZXM6IE1ldHJpY1Jlc3VsdFtdKSA9PiB7XG4gICAgICAgIGNvbnN0IGZvcm1hdCA9IHRoaXMuZGF0YUZvcm1hdCB8fCB0aGlzLnNlcnZpY2UuaGFuZGVsQ2hhcnREYXRhO1xuICAgICAgICAvLyBgZmlsbE51bGxDaGFydERhdGFgIHByb21ldGhldXMg5a2Y5Zyo5p+Q5Liq5pe26Ze054K55pyq6YeH6ZuG5Yiw5pWw5o2u55qE5oOF5Ya177yM6L+Z6YeM5Li65Yy65YiGIOacqumHh+mbhuWIsOaVsOaNruS4ujDnmoTmg4XlhrXvvIzov5nph4zliY3nq6/moLnmja7ml7bpl7TmrrXoh6rliqjloavlhYXmlbDmja5cbiAgICAgICAgLy8g5ZCO56uvIOmcgOimgeWSjCBQcm9tZXRoZXVzIEFQSSDkv53mjIHlhbzlrrnvvIzov5jmmK/lnKjliY3nq6/lgZrlpITnkIbloavlhYVcbiAgICAgICAgcmV0dXJuIGZvcm1hdChyZXMsIHRoaXMuaW5kaWNhdG9yIHx8IFtdLCB0aGlzLmRlcGVuZE9uRGF0YSk/Lm1hcChcbiAgICAgICAgICBpdGVtID0+ICh7XG4gICAgICAgICAgICAuLi5pdGVtLFxuICAgICAgICAgICAgdW5pdDogdGhpcy51bml0LFxuICAgICAgICAgICAgdmFsdWVzOiBmaWxsTnVsbENoYXJ0RGF0YShcbiAgICAgICAgICAgICAgdGhpcy5jaGFydFBhcmFtcyxcbiAgICAgICAgICAgICAgaXRlbS52YWx1ZXMgYXMgQXJyYXk8Q2hhcnREYXRhSXRlbTx7IHg6IG51bWJlcjsgeTogbnVtYmVyIH0+PixcbiAgICAgICAgICAgICAgdGhpcy5zdGVwTGluZSxcbiAgICAgICAgICAgICksXG4gICAgICAgICAgfSksXG4gICAgICAgICk7XG4gICAgICB9KSxcbiAgICAgIHRhcChyZXMgPT4ge1xuICAgICAgICB0aGlzLmhhbmRsZURhdGVBeGlzTGFiZWxGb3JtYXRzKHRoaXMuY2hhcnRQYXJhbXMpO1xuICAgICAgICB0aGlzLmhhbmRlbENoYXJ0U3RhdHVzKHtcbiAgICAgICAgICBsb2FkaW5nOiBmYWxzZSxcbiAgICAgICAgICBub0RhdGE6IGhhc05vRGF0YShyZXMpLFxuICAgICAgICB9KTtcbiAgICAgICAgdGhpcy5jZHIubWFya0ZvckNoZWNrKCk7XG4gICAgICB9KSxcbiAgICAgIG1hcChyZXMgPT5cbiAgICAgICAgcmVzPy5sZW5ndGhcbiAgICAgICAgICA/IHJlc1xuICAgICAgICAgIDogW1xuICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgdmFsdWVzOiBmaWxsTnVsbENoYXJ0RGF0YSh0aGlzLmNoYXJ0UGFyYW1zLCBbXSwgdGhpcy5zdGVwTGluZSksXG4gICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBdLFxuICAgICAgKSxcbiAgICAgIHdpdGhMYXRlc3RGcm9tKHRoaXMuYWRhcHRVbml0JCksXG4gICAgICBtYXAoKFtyZXMsIF9hZGFwdFVuaXRdKSA9PiB7XG4gICAgICAgIGlmIChfYWRhcHRVbml0ICYmICF0aGlzLm5vRGF0YSkge1xuICAgICAgICAgIGNvbnN0IHsgYmFzZSwgdW5pdCB9ID0gdGhpcy5zZXJ2aWNlLmFkYXB0Q2hhcnRVbml0KHJlcywgX2FkYXB0VW5pdCk7XG4gICAgICAgICAgdGhpcy51bml0ID0gYHVuaXRfJHt1bml0fWA7XG4gICAgICAgICAgaWYgKHR5cGVvZiBfYWRhcHRVbml0ID09PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgY29uc3QgeyBkZWZhdWx0UHJlZml4ID0gdHJ1ZSwgcHJlZml4IH0gPSBfYWRhcHRVbml0O1xuICAgICAgICAgICAgdGhpcy51bml0ID0gZGVmYXVsdFByZWZpeFxuICAgICAgICAgICAgICA/IGB1bml0XyR7dW5pdH1gXG4gICAgICAgICAgICAgIDogYCR7cHJlZml4IHx8ICcnfSR7dW5pdH1gO1xuICAgICAgICAgIH1cbiAgICAgICAgICByZXR1cm4gKHJlcyBhcyBDaGFydERhdGFbXSkubWFwKChpdGVtOiBDaGFydERhdGEpID0+ICh7XG4gICAgICAgICAgICAuLi5pdGVtLFxuICAgICAgICAgICAgdW5pdDogdGhpcy51bml0LFxuICAgICAgICAgICAgdmFsdWVzOiBpdGVtLnZhbHVlcy5tYXAoZCA9PiAoe1xuICAgICAgICAgICAgICAuLi5kLFxuICAgICAgICAgICAgICB5OiBkLnkgPyBkLnkgLyBiYXNlIDogZC55LFxuICAgICAgICAgICAgfSkpLFxuICAgICAgICAgIH0pKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gcmVzLm1hcChpdGVtID0+ICh7IC4uLml0ZW0sIHVuaXQ6IHRoaXMudW5pdCB9KSkgYXMgQ2hhcnREYXRhW107XG4gICAgICB9KSxcbiAgICAgIHRhcCgoKSA9PiB7XG4gICAgICAgIHRoaXMuZGF0YUNvbXBsZXRlZC5uZXh0KCk7XG4gICAgICB9KSxcbiAgICAgIHB1Ymxpc2hSZWYoKSxcbiAgICApO1xuICB9XG5cbiAgcmVmcmVzaCgpIHtcbiAgICB0aGlzLnJlbG9hZCQubmV4dChudWxsKTtcbiAgICB0aGlzLnJlZnJlc2hFdmVudC5uZXh0KG51bGwpO1xuICB9XG5cbiAgcHJpdmF0ZSBoYW5kZWxDaGFydFN0YXR1cyhzdGF0dXM6IENoYXJ0U3RhdHVzKSB7XG4gICAgdGhpcy5fY2hhcnRTdGF0dXMkJC5uZXh0KHtcbiAgICAgIC4uLnN0YXR1cyxcbiAgICB9KTtcbiAgfVxuXG4gIHByaXZhdGUgaGFuZGxlRGF0ZUF4aXNMYWJlbEZvcm1hdHMocGFyYW1zOiBNZXRyaWNBcGlQYXJhbXMpIHtcbiAgICBpZiAocGFyYW1zKSB7XG4gICAgICBjb25zdCBkaWZmID0gcGFyYW1zLmVuZCAtIHBhcmFtcy5zdGFydDtcbiAgICAgIGNvbnN0IG0xID0gMjQgKiA2MCAqIDYwO1xuICAgICAgY29uc3QgbTMgPSAzICogbTE7XG4gICAgICBjb25zdCBtNyA9IDcgKiBtMTtcbiAgICAgIGNvbnN0IE1fRF9GT1JNQVQgPSAnTU0tREQnO1xuICAgICAgY29uc3QgZm9ybWF0ID1cbiAgICAgICAgZGlmZiA+PSBtN1xuICAgICAgICAgID8gTV9EX0ZPUk1BVFxuICAgICAgICAgIDogZGlmZiA8IG03ICYmIChkaWZmID49IG0zIHx8IGRpZmYgPiBtMSlcbiAgICAgICAgICA/IGAke01fRF9GT1JNQVR9ICR7REFURV9USU1FX0ZPUk1BVF9YX0FYSVN9YFxuICAgICAgICAgIDogREFURV9USU1FX0ZPUk1BVF9YX0FYSVM7XG4gICAgICB0aGlzLmRhdGVBeGlzTGFiZWxGb3JtYXRzID0gZm9ybWF0O1xuICAgICAgLy8gaHR0cHM6Ly9kM2pzLm9yZy5jbi9kb2N1bWVudC9kMy10aW1lLWZvcm1hdC8jYXBpLXJlZmVyZW5jZVxuICAgICAgdGhpcy5kYXRlWEF4aXNMYWJlbEZvcm1hdHMgPVxuICAgICAgICBkaWZmID49IG03XG4gICAgICAgICAgPyAnJW0tJWQnXG4gICAgICAgICAgOiBkaWZmIDwgbTcgJiYgKGRpZmYgPj0gbTMgfHwgZGlmZiA+IG0xKVxuICAgICAgICAgID8gYCVtLSVkICVIOiVNYFxuICAgICAgICAgIDogJyVIOiVNJztcbiAgICAgIHRoaXMuY2RyLmRldGVjdENoYW5nZXMoKTtcbiAgICB9XG4gIH1cbn1cbiIsIjxhY2wtdmlldy16Y2hhcnRcbiAgW2NsYXNzLm92ZXJmbG93LWRpc3BsYXldPVwiIXRvb2x0aXBBcHBlbmRUb0JvZHlcIlxuICBbY29udGV4dENhbGxiYWNrRnVuY3Rpb25dPVwiY29udGV4dENhbGxiYWNrRnVuY3Rpb25cIlxuICBbdW5pdF09XCJ1bml0XCJcbiAgW2hpZGVIZWFkZXJdPVwiaGlkZUhlYWRlclwiXG4gIFtjdXN0b21Ob0RhdGFUaXRsZV09XCJjdXN0b21Ob0RhdGFUaXRsZVwiXG4gIFtjaGFydFN0YXR1c109XCJzdGF0dXMkIHwgYXN5bmNcIlxuICBbYmFja2dyb3VuZENvbG9yXT1cImJhY2tncm91bmRDb2xvclwiXG4gIFtzZXJpZXNdPVwic2VyaWVzJCB8IGFzeW5jXCJcbiAgW2N1cnZlVHlwZV09XCJjdXJ2ZVR5cGVcIlxuICBbdG9vbHRpcEFwcGVuZFRvQm9keV09XCJ0b29sdGlwQXBwZW5kVG9Cb2R5XCJcbiAgW21vZGVdPVwibW9kZVwiXG4gIFtncmlkT2Zmc2V0VG9wXT1cImdyaWRPZmZzZXRUb3BcIlxuICBbdGl0bGVdPVwidGl0bGVcIlxuICBbY2hhcnRUeXBlXT1cImNoYXJ0VHlwZVwiXG4gIFtoaWRlVGl0bGVdPVwiaGlkZVRpdGxlXCJcbiAgW3Rvb2x0aXBIaWRlXT1cInRvb2x0aXBIaWRlXCJcbiAgW3Rvb2x0aXBTb3J0TWV0aG9kXT1cInRvb2x0aXBTb3J0TWV0aG9kXCJcbiAgW3RpdGxlRGVzY3JpcHRpb25dPVwidGl0bGVEZXNjcmlwdGlvblwiXG4gIFt0aXRsZURlc2NyaXB0aW9uQ29udGV4dF09XCJ0aXRsZURlc2NyaXB0aW9uQ29udGV4dFwiXG4gIFtoaWRlTGVnZW5kXT1cIihkZXBlbmRPbkRhdGEgJiYgbm9EYXRhKSB8fCBoaWRlTGVnZW5kXCJcbiAgW2RhdGVBeGlzTGFiZWxGb3JtYXRzXT1cImRhdGVBeGlzTGFiZWxGb3JtYXRzXCJcbiAgW2VuYWJsZVpvb21dPVwiZW5hYmxlWm9vbVwiXG4gIFtzdGVwTGluZV09XCJzdGVwTGluZVwiXG4gIFtyb3RhdGVkXT1cInJvdGF0ZWRcIlxuICBbcmlnaHRPcGVyYXRpb25dPVwicmlnaHRPcGVyYXRpb25cIlxuICBbbGVmdE9wZXJhdGlvbl09XCJsZWZ0T3BlcmF0aW9uXCJcbiAgW2xlZnRPcGVyYXRpb25Db250ZXh0XT1cImxlZnRPcGVyYXRpb25Db250ZXh0XCJcbiAgW2xlZ2VuZFRlbXBsYXRlXT1cImxlZ2VuZFRlbXBsYXRlXCJcbiAgW2xlZ2VuZFNlbGVjdEFsbE9wZXJhdGlvbl09XCJsZWdlbmRTZWxlY3RBbGxPcGVyYXRpb25cIlxuICBbbGVnZW5kU2VsZWN0QWxsTmFtZV09XCJsZWdlbmRTZWxlY3RBbGxOYW1lXCJcbiAgW3lBY2Nlc3Nvcl09XCJ5QWNjZXNzb3IgfHwgKHlBY2Nlc3NvciQgfCBhc3luYylcIlxuICBbeEFjY2Vzc29yXT1cInhBY2Nlc3NvclwiXG4gIFt5QXhpc01pblN0ZXBdPVwieUF4aXNNaW5TdGVwXCJcbiAgW2hpZGVUb29sdGlwVW5pdF09XCJoaWRlVG9vbHRpcFVuaXRcIlxuICBbdG9vbHRpcFRpdGxlVGVtcGxhdGVdPVwidG9vbHRpcFRpdGxlVGVtcGxhdGVcIlxuICBbdG9vbHRpcEF1dG9Tb3J0XT1cInRvb2x0aXBBdXRvU29ydFwiXG4gIFt0b29sdGlwVHJhbnNsYXRpb25dPVwidG9vbHRpcFRyYW5zbGF0aW9