@versatiledatakit/data-pipelines
Version:
Data Pipelines help Data Engineers develop, deploy, run, and manage data processing workloads (called 'Data Job')
381 lines • 55.2 kB
JavaScript
/*
* Copyright 2023-2025 Broadcom
* SPDX-License-Identifier: Apache-2.0
*/
import { DatePipe } from '@angular/common';
import { Component, EventEmitter, Input, Output } from '@angular/core';
import { Chart, registerables } from 'chart.js';
import ChartDataLabels from 'chartjs-plugin-datalabels';
import zoomPlugin from 'chartjs-plugin-zoom';
import 'chartjs-adapter-date-fns';
import { CollectionsUtil } from '@versatiledatakit/shared';
import { DateUtil } from '../../../../../shared/utils';
import { DATA_PIPELINES_DATE_TIME_FORMAT } from '../../../../../model';
import { DataJobExecutionToGridDataJobExecution } from '../model';
import * as i0 from "@angular/core";
import * as i1 from "@angular/common";
function ExecutionDurationChartComponent_button_3_Template(rf, ctx) { if (rf & 1) {
const _r3 = i0.ɵɵgetCurrentView();
i0.ɵɵelementStart(0, "button", 5);
i0.ɵɵlistener("click", function ExecutionDurationChartComponent_button_3_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r3); const ctx_r2 = i0.ɵɵnextContext(); return ctx_r2.resetZoom(); });
i0.ɵɵtext(1, " Reset Zoom ");
i0.ɵɵelementEnd();
} }
function ExecutionDurationChartComponent_span_4_Template(rf, ctx) { if (rf & 1) {
i0.ɵɵelementStart(0, "span", 6);
i0.ɵɵtext(1, "Click and drag to zoom");
i0.ɵɵelementEnd();
} }
export class ExecutionDurationChartComponent {
constructor(datePipe) {
this.datePipe = datePipe;
this.jobExecutions = [];
/**
* ** Flag that indicates if duration chart is zoomed or not.
*/
this.chartZoomed = false;
/**
* ** Emits event whenever focus on execution changes.
*
* - Value could be either executionId or null.
*/
this.executionIdFocused = new EventEmitter();
/**
* ** Event Emitter that emits events on every user zoom period change in duration chart or reset zoom.
*/
this.zoomPeriodChanged = new EventEmitter();
/**
* ** Zoom selection reference with from and to values.
* @private
*/
this._zoomPeriod = {
from: null,
to: null
};
Chart.register(...registerables, ChartDataLabels, zoomPlugin);
}
resetZoom() {
this._zoomPeriod = {
from: null,
to: null
};
this.zoomPeriodChanged.next(this._zoomPeriod);
}
/**
* @inheritDoc
*/
ngOnChanges(changes) {
if (!changes['jobExecutions'].firstChange) {
this._updateChart();
}
}
/**
* @inheritDoc
*/
ngOnInit() {
this._initChart();
}
_initChart() {
const chartData = this._getChartData();
const unit = this._getTimeScaleUnit(chartData);
const [min, max] = this._getMinMaxExecutionTupleAdjusted(chartData, unit);
const data = {
labels: this._getChartLabels(),
datasets: [
{
data: chartData,
fill: false,
pointRadius: 3,
pointBorderColor: (context) => DataJobExecutionToGridDataJobExecution.resolveColor(context.raw?.status),
pointBackgroundColor: (context) => DataJobExecutionToGridDataJobExecution.resolveColor(context.raw?.status),
pointBorderWidth: 3,
parsing: {
xAxisKey: 'startTime',
yAxisKey: 'duration'
}
}
]
};
this.chart = new Chart('durationChart', {
type: 'line',
data,
options: {
// callback listen for hover events in duration chart and process events
onHover: (event, activeElements) => {
this._emitFocussedExecutionId(activeElements);
},
showLine: false,
scales: {
x: {
type: 'time',
time: {
unit
},
min,
max
},
y: {
title: {
display: true,
text: `Duration ${this._getDurationUnit().name}`
}
}
},
maintainAspectRatio: false,
plugins: {
zoom: {
zoom: {
drag: {
enabled: true
},
mode: 'x',
onZoomComplete: (context) => {
const from = new Date(Math.floor(context.chart.scales['x'].min));
const to = new Date(Math.ceil(context.chart.scales['x'].max));
if (this._zoomPeriod.from === from && this._zoomPeriod.to === to) {
return;
}
this._zoomPeriod = {
from,
to
};
this.zoomPeriodChanged.next(this._zoomPeriod);
}
}
},
datalabels: {
display: false
},
legend: {
display: false
},
tooltip: {
callbacks: {
label: (context) => {
const rawValues = context.raw;
// eslint-disable-next-line @typescript-eslint/restrict-plus-operands
return (`Duration: ${context.parsed.y} | ${rawValues.status}` +
(rawValues.endTime
? ` | End: ${this.datePipe.transform(rawValues.endTime, DATA_PIPELINES_DATE_TIME_FORMAT, 'UTC')}`
: ''));
}
}
}
}
}
});
}
_updateChart() {
const chartLabels = this._getChartLabels();
const chartData = this._getChartData();
const unit = this._getTimeScaleUnit(chartData);
const [min, max] = this._getMinMaxExecutionTupleAdjusted(chartData, unit);
this.chart.data.labels = chartLabels;
this.chart.data.datasets[0].data = chartData;
this.chart.options.scales['x'] = {
type: 'time',
time: {
unit
},
min,
max
};
this.chart.update();
}
_getChartLabels() {
return this.jobExecutions.map((execution) => DateUtil.normalizeToUTC(execution.startTime).getTime());
}
_getChartData() {
const divider = this._getDurationUnit().divider;
return this.jobExecutions
.map((execution) => {
return {
startTime: DateUtil.normalizeToUTC(execution.startTime).getTime(),
duration: Math.round((this._getJobDurationSeconds(execution) / divider) * 100) / 100,
endTime: execution.endTime ? execution.endTime : undefined,
status: execution.status,
opId: execution.opId,
id: execution.id
};
})
.sort((ex1, ex2) => ex1.startTime - ex2.startTime);
}
_getTimeScaleUnit(chartData) {
const [min, max] = this._getMinMaxExecutionTuple(chartData);
if (CollectionsUtil.isNil(min) || CollectionsUtil.isNil(max)) {
return 'day';
}
const _min = CollectionsUtil.isNumber(min) ? min : new Date(min).getTime();
const _max = CollectionsUtil.isNumber(max) ? max : new Date(max).getTime();
const diff = _max - _min;
if (diff > this._getTimeUnitMilliseconds('year') + this._getTimeUnitMilliseconds('second')) {
return 'year';
}
if (diff > this._getTimeUnitMilliseconds('month') + this._getTimeUnitMilliseconds('second')) {
return 'month';
}
if (diff > 2 * this._getTimeUnitMilliseconds('week')) {
return 'week';
}
if (diff > this._getTimeUnitMilliseconds('day') + this._getTimeUnitMilliseconds('second')) {
return 'day';
}
if (diff > this._getTimeUnitMilliseconds('hour') + this._getTimeUnitMilliseconds('second')) {
return 'hour';
}
if (diff > this._getTimeUnitMilliseconds('minute') + this._getTimeUnitMilliseconds('millisecond')) {
return 'minute';
}
if (diff > this._getTimeUnitMilliseconds('second') + this._getTimeUnitMilliseconds('millisecond')) {
return 'second';
}
return 'millisecond';
}
_getDurationUnit() {
const maxDurationSeconds = this._getMaxDurationSeconds();
if (maxDurationSeconds > 60) {
return maxDurationSeconds > 3600 ? { name: 'hours', divider: 3600 } : { name: 'minutes', divider: 60 };
}
else {
return { name: 'seconds', divider: 1 };
}
}
_getMaxDurationSeconds() {
return this.jobExecutions
.map((execution) => this._getJobDurationSeconds(execution))
.sort((v1, v2) => v1 - v2)
.pop();
}
_getJobDurationSeconds(execution) {
const endTime = execution.endTime ? new Date(execution.endTime).getTime() : Date.now();
const delta = endTime - new Date(execution.startTime).getTime();
return delta / 1000;
}
_emitFocussedExecutionId(activeElements) {
if (activeElements.length > 0) {
const element = activeElements[0].element;
const executionId = element?.$context?.raw?.id ?? null;
// if event emits that element is focussed and that value is same as previous skip processing
if (this._focusedExecutionId === executionId) {
return;
}
// when element is focused for the first time, save executionId in component context
this._focusedExecutionId = executionId;
// emit executionId to parent component
this.executionIdFocused.next(executionId);
}
else {
// if event emits that no element is focussed and that value is same as previous skip processing
if (!this._focusedExecutionId) {
return;
}
// when focused element lose focus clear executionId from component context
this._focusedExecutionId = null;
// emit null value to parent component
this.executionIdFocused.next(null);
}
}
_getMinMaxExecutionTuple(chartData) {
if (chartData.length === 0) {
if (CollectionsUtil.isDate(this._zoomPeriod.from) && CollectionsUtil.isDate(this._zoomPeriod.to)) {
return [this._zoomPeriod.from.getTime(), this._zoomPeriod.to.getTime()];
}
return [null, null];
}
if (chartData.length === 1) {
if (CollectionsUtil.isDate(this._zoomPeriod.from) && CollectionsUtil.isDate(this._zoomPeriod.to)) {
if (this._zoomPeriod.to.getTime() - this._zoomPeriod.from.getTime() > 5 * this._getTimeUnitMilliseconds('minute')) {
return [this._zoomPeriod.from.getTime(), this._zoomPeriod.to.getTime()];
}
}
return [chartData[0].startTime, chartData[0].startTime];
}
return [chartData[0].startTime, chartData[chartData.length - 1].startTime];
}
_getMinMaxExecutionTupleAdjusted(chartData, unit) {
const [min, max] = this._getMinMaxExecutionTuple(chartData);
let adjustment;
switch (unit) {
case 'millisecond':
adjustment = 10 * this._getTimeUnitMilliseconds('millisecond');
break;
case 'second':
adjustment = 5 * this._getTimeUnitMilliseconds('second');
break;
case 'minute':
adjustment = 5 * this._getTimeUnitMilliseconds('minute');
break;
case 'hour':
adjustment = 2 * this._getTimeUnitMilliseconds('hour');
break;
case 'day':
adjustment = 15 * this._getTimeUnitMilliseconds('hour');
break;
case 'week':
adjustment = 3 * this._getTimeUnitMilliseconds('day');
break;
case 'month':
adjustment = this._getTimeUnitMilliseconds('month');
break;
case 'year':
adjustment = this._getTimeUnitMilliseconds('year');
break;
default:
console.error(
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
`Taurus DataPipelines ExecutionDurationChartComponent unsupported time format unit ${unit}`);
}
return [min - adjustment, max + adjustment];
}
_getTimeUnitMilliseconds(unit) {
switch (unit) {
case 'millisecond':
return 1;
case 'second':
return 1000;
case 'minute':
return 1000 * 60;
case 'hour':
return 1000 * 60 * 60;
case 'day':
return 1000 * 60 * 60 * 24;
case 'week':
return 1000 * 60 * 60 * 24 * 7;
case 'month':
return 1000 * 60 * 60 * 24 * 31;
case 'year':
return 1000 * 60 * 60 * 24 * 365;
default:
console.error(
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
`Taurus DataPipelines ExecutionDurationChartComponent unsupported time format unit ${unit}`);
return 0;
}
}
}
ExecutionDurationChartComponent.ɵfac = function ExecutionDurationChartComponent_Factory(t) { return new (t || ExecutionDurationChartComponent)(i0.ɵɵdirectiveInject(i1.DatePipe)); };
ExecutionDurationChartComponent.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ExecutionDurationChartComponent, selectors: [["lib-execution-duration-chart"]], inputs: { jobExecutions: "jobExecutions", chartZoomed: "chartZoomed" }, outputs: { executionIdFocused: "executionIdFocused", zoomPeriodChanged: "zoomPeriodChanged" }, features: [i0.ɵɵProvidersFeature([DatePipe]), i0.ɵɵNgOnChangesFeature], decls: 5, vars: 2, consts: [[1, "card", 2, "height", "230px", "padding", "20px", "margin-top", "0"], [1, "duration-chart"], ["id", "durationChart", "data-cy", "data-pipelines-job-executions-duration-chart"], ["class", "btn btn-sm btn-link reset-zoom", 3, "click", 4, "ngIf"], ["class", "zoom-tooltip", 4, "ngIf"], [1, "btn", "btn-sm", "btn-link", "reset-zoom", 3, "click"], [1, "zoom-tooltip"]], template: function ExecutionDurationChartComponent_Template(rf, ctx) { if (rf & 1) {
i0.ɵɵelementStart(0, "div", 0)(1, "div", 1);
i0.ɵɵelement(2, "canvas", 2);
i0.ɵɵtemplate(3, ExecutionDurationChartComponent_button_3_Template, 2, 0, "button", 3);
i0.ɵɵtemplate(4, ExecutionDurationChartComponent_span_4_Template, 2, 0, "span", 4);
i0.ɵɵelementEnd()();
} if (rf & 2) {
i0.ɵɵadvance(3);
i0.ɵɵproperty("ngIf", ctx.chartZoomed);
i0.ɵɵadvance(1);
i0.ɵɵproperty("ngIf", !ctx.chartZoomed);
} }, directives: [i1.NgIf], styles: ["div.duration-chart[_ngcontent-%COMP%]{height:200px;position:relative}div.duration-chart[_ngcontent-%COMP%] button.reset-zoom[_ngcontent-%COMP%]{position:absolute;top:-1rem;left:3rem}div.duration-chart[_ngcontent-%COMP%] span.zoom-tooltip[_ngcontent-%COMP%]{position:absolute;top:-.8rem;opacity:.5;left:2.5rem}"] });
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ExecutionDurationChartComponent, [{
type: Component,
args: [{ selector: 'lib-execution-duration-chart', providers: [DatePipe], template: "<!--\n ~ Copyright 2023-2025 Broadcom\n ~ SPDX-License-Identifier: Apache-2.0\n -->\n\n<div class=\"card\" style=\"height: 230px; padding: 20px; margin-top: 0\">\n <div class=\"duration-chart\">\n <canvas\n id=\"durationChart\"\n data-cy=\"data-pipelines-job-executions-duration-chart\"\n ></canvas>\n <button\n *ngIf=\"chartZoomed\"\n class=\"btn btn-sm btn-link reset-zoom\"\n (click)=\"resetZoom()\"\n >\n Reset Zoom\n </button>\n <span *ngIf=\"!chartZoomed\" class=\"zoom-tooltip\"\n >Click and drag to zoom</span\n >\n </div>\n</div>\n", styles: ["/*!\n * Copyright 2023-2025 Broadcom\n * SPDX-License-Identifier: Apache-2.0\n */div.duration-chart{height:200px;position:relative}div.duration-chart button.reset-zoom{position:absolute;top:-1rem;left:3rem}div.duration-chart span.zoom-tooltip{position:absolute;top:-.8rem;opacity:.5;left:2.5rem}\n"] }]
}], function () { return [{ type: i1.DatePipe }]; }, { jobExecutions: [{
type: Input
}], chartZoomed: [{
type: Input
}], executionIdFocused: [{
type: Output
}], zoomPeriodChanged: [{
type: Output
}] }); })();
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXhlY3V0aW9uLWR1cmF0aW9uLWNoYXJ0LmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2RhdGEtcGlwZWxpbmVzL3NyYy9saWIvY29tcG9uZW50cy9kYXRhLWpvYi9wYWdlcy9leGVjdXRpb25zL2V4ZWN1dGlvbi1kdXJhdGlvbi1jaGFydC9leGVjdXRpb24tZHVyYXRpb24tY2hhcnQuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvZGF0YS1waXBlbGluZXMvc3JjL2xpYi9jb21wb25lbnRzL2RhdGEtam9iL3BhZ2VzL2V4ZWN1dGlvbnMvZXhlY3V0aW9uLWR1cmF0aW9uLWNoYXJ0L2V4ZWN1dGlvbi1kdXJhdGlvbi1jaGFydC5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7O0dBR0c7QUFFSCxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDM0MsT0FBTyxFQUFFLFNBQVMsRUFBRSxZQUFZLEVBQUUsS0FBSyxFQUFxQixNQUFNLEVBQWlCLE1BQU0sZUFBZSxDQUFDO0FBRXpHLE9BQU8sRUFBaUIsS0FBSyxFQUFhLGFBQWEsRUFBOEIsTUFBTSxVQUFVLENBQUM7QUFDdEcsT0FBTyxlQUFlLE1BQU0sMkJBQTJCLENBQUM7QUFDeEQsT0FBTyxVQUFVLE1BQU0scUJBQXFCLENBQUM7QUFDN0MsT0FBTywwQkFBMEIsQ0FBQztBQUVsQyxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFFM0QsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLDZCQUE2QixDQUFDO0FBRXZELE9BQU8sRUFBRSwrQkFBK0IsRUFBMEIsTUFBTSxzQkFBc0IsQ0FBQztBQUUvRixPQUFPLEVBQUUsc0NBQXNDLEVBQXdCLE1BQU0sVUFBVSxDQUFDOzs7OztJQ1JoRixpQ0FJQztJQURH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T0FBTyxDQUFDLENBQUM7U0FDaEI7SUFDTCxDQUFDOzs4R0F6WVEsK0JBQStCO2tGQUEvQiwrQkFBK0IseVBBRjdCLENBQUMsUUFBUSxDQUFDO1FDbEN6Qiw4QkFBc0UsYUFBQTtRQUU5RCw0QkFHVTtRQUNWLHNGQU1TO1FBQ1Qsa0ZBRUM7UUFDTCxpQkFBTSxFQUFBOztRQVRHLGVBQWlCO1FBQWpCLHNDQUFpQjtRQU1mLGVBQWtCO1FBQWxCLHVDQUFrQjs7dUZEdUJwQiwrQkFBK0I7Y0FOM0MsU0FBUzsyQkFDSSw4QkFBOEIsYUFHN0IsQ0FBQyxRQUFRLENBQUM7MkRBR1osYUFBYTtrQkFBckIsS0FBSztZQUtHLFdBQVc7a0JBQW5CLEtBQUs7WUFPSSxrQkFBa0I7a0JBQTNCLE1BQU07WUFLRyxpQkFBaUI7a0JBQTFCLE1BQU0iLCJzb3VyY2VzQ29udGVudCI6WyIvKlxuICogQ29weXJpZ2h0IDIwMjMtMjAyNSBCcm9hZGNvbVxuICogU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjBcbiAqL1xuXG5pbXBvcnQgeyBEYXRlUGlwZSB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XG5pbXBvcnQgeyBDb21wb25lbnQsIEV2ZW50RW1pdHRlciwgSW5wdXQsIE9uQ2hhbmdlcywgT25Jbml0LCBPdXRwdXQsIFNpbXBsZUNoYW5nZXMgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcblxuaW1wb3J0IHsgQWN0aXZlRWxlbWVudCwgQ2hhcnQsIENoYXJ0RGF0YSwgcmVnaXN0ZXJhYmxlcywgU2NhdHRlckRhdGFQb2ludCwgVGltZVVuaXQgfSBmcm9tICdjaGFydC5qcyc7XG5pbXBvcnQgQ2hhcnREYXRhTGFiZWxzIGZyb20gJ2NoYXJ0anMtcGx1Z2luLWRhdGFsYWJlbHMnO1xuaW1wb3J0IHpvb21QbHVnaW4gZnJvbSAnY2hhcnRqcy1wbHVnaW4tem9vbSc7XG5pbXBvcnQgJ2NoYXJ0anMtYWRhcHRlci1kYXRlLWZucyc7XG5cbmltcG9ydCB7IENvbGxlY3Rpb25zVXRpbCB9IGZyb20gJ0B2ZXJzYXRpbGVkYXRha2l0L3NoYXJlZCc7XG5cbmltcG9ydCB7IERhdGVVdGlsIH0gZnJvbSAnLi4vLi4vLi4vLi4vLi4vc2hhcmVkL3V0aWxzJztcblxuaW1wb3J0IHsgREFUQV9QSVBFTElORVNfREFURV9USU1FX0ZPUk1BVCwgRGF0YUpvYkV4ZWN1dGlvblN0YXR1cyB9IGZyb20gJy4uLy4uLy4uLy4uLy4uL21vZGVsJztcblxuaW1wb3J0IHsgRGF0YUpvYkV4ZWN1dGlvblRvR3JpZERhdGFKb2JFeGVjdXRpb24sIEdyaWREYXRhSm9iRXhlY3V0aW9uIH0gZnJvbSAnLi4vbW9kZWwnO1xuXG50eXBlIEN1c3RvbUNoYXJ0RGF0YSA9IFBhcnRpYWw8U2NhdHRlckRhdGFQb2ludD4gJiB7XG4gICAgc3RhcnRUaW1lOiBudW1iZXI7XG4gICAgZHVyYXRpb246IG51bWJlcjtcbiAgICBlbmRUaW1lOiBzdHJpbmc7XG4gICAgc3RhdHVzOiBEYXRhSm9iRXhlY3V0aW9uU3RhdHVzO1xuICAgIG9wSWQ6IHN0cmluZztcbiAgICBpZDogc3RyaW5nO1xufTtcblxuaW50ZXJmYWNlIFpvb21QZXJpb2Qge1xuICAgIGZyb206IERhdGU7XG4gICAgdG86IERhdGU7XG59XG5cbkBDb21wb25lbnQoe1xuICAgIHNlbGVjdG9yOiAnbGliLWV4ZWN1dGlvbi1kdXJhdGlvbi1jaGFydCcsXG4gICAgdGVtcGxhdGVVcmw6ICcuL2V4ZWN1dGlvbi1kdXJhdGlvbi1jaGFydC5jb21wb25lbnQuaHRtbCcsXG4gICAgc3R5bGVVcmxzOiBbJy4vZXhlY3V0aW9uLWR1cmF0aW9uLWNoYXJ0LmNvbXBvbmVudC5zY3NzJ10sXG4gICAgcHJvdmlkZXJzOiBbRGF0ZVBpcGVdXG59KVxuZXhwb3J0IGNsYXNzIEV4ZWN1dGlvbkR1cmF0aW9uQ2hhcnRDb21wb25lbnQgaW1wbGVtZW50cyBPbkluaXQsIE9uQ2hhbmdlcyB7XG4gICAgQElucHV0KCkgam9iRXhlY3V0aW9uczogR3JpZERhdGFKb2JFeGVjdXRpb25bXSA9IFtdO1xuXG4gICAgLyoqXG4gICAgICogKiogRmxhZyB0aGF0IGluZGljYXRlcyBpZiBkdXJhdGlvbiBjaGFydCBpcyB6b29tZWQgb3Igbm90LlxuICAgICAqL1xuICAgIEBJbnB1dCgpIGNoYXJ0Wm9vbWVkID0gZmFsc2U7XG5cbiAgICAvKipcbiAgICAgKiAqKiBFbWl0cyBldmVudCB3aGVuZXZlciBmb2N1cyBvbiBleGVjdXRpb24gY2hhbmdlcy5cbiAgICAgKlxuICAgICAqICAgICAgLSBWYWx1ZSBjb3VsZCBiZSBlaXRoZXIgZXhlY3V0aW9uSWQgb3IgbnVsbC5cbiAgICAgKi9cbiAgICBAT3V0cHV0KCkgZXhlY3V0aW9uSWRGb2N1c2VkID0gbmV3IEV2ZW50RW1pdHRlcjxDdXN0b21DaGFydERhdGFbJ2lkJ10+KCk7XG5cbiAgICAvKipcbiAgICAgKiAqKiBFdmVudCBFbWl0dGVyIHRoYXQgZW1pdHMgZXZlbnRzIG9uIGV2ZXJ5IHVzZXIgem9vbSBwZXJpb2QgY2hhbmdlIGluIGR1cmF0aW9uIGNoYXJ0IG9yIHJlc2V0IHpvb20uXG4gICAgICovXG4gICAgQE91dHB1dCgpIHpvb21QZXJpb2RDaGFuZ2VkOiBFdmVudEVtaXR0ZXI8Wm9vbVBlcmlvZD4gPSBuZXcgRXZlbnRFbWl0dGVyPFpvb21QZXJpb2Q+KCk7XG5cbiAgICAvKipcbiAgICAgKiAqKiBSZWZlcmVuY2UgdG8gRHVyYXRpb24gY2hhcnQgaW5zdGFuY2UuXG4gICAgICovXG4gICAgY2hhcnQ6IENoYXJ0PCdsaW5lJywgQ3VzdG9tQ2hhcnREYXRhW10sIG51bWJlcj47XG5cbiAgICAvKipcbiAgICAgKiAqKiBDdXJyZW50bHkgZm9jdXNzZWQgZXhlY3V0aW9uIGlkLCBpdCBjb3VsZCBiZSBlaXRoZXIgc3RyaW5nIGlmIHRoZXJlIGlzIGZvY3Vzc2VkIGV4ZWN1dGlvbiBvciBudWxsIGlmIG5vdGhpbmcgaXMgZm9jdXNzZWQuXG4gICAgICogQHByaXZhdGVcbiAgICAgKi9cbiAgICBwcml2YXRlIF9mb2N1c2VkRXhlY3V0aW9uSWQ6IEN1c3RvbUNoYXJ0RGF0YVsnaWQnXTtcblxuICAgIC8qKlxuICAgICAqICoqIFpvb20gc2VsZWN0aW9uIHJlZmVyZW5jZSB3aXRoIGZyb20gYW5kIHRvIHZhbHVlcy5cbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqL1xuICAgIHByaXZhdGUgX3pvb21QZXJpb2Q6IFpvb21QZXJpb2QgPSB7XG4gICAgICAgIGZyb206IG51bGwsXG4gICAgICAgIHRvOiBudWxsXG4gICAgfTtcblxuICAgIGNvbnN0cnVjdG9yKHByaXZhdGUgcmVhZG9ubHkgZGF0ZVBpcGU6IERhdGVQaXBlKSB7XG4gICAgICAgIENoYXJ0LnJlZ2lzdGVyKC4uLnJlZ2lzdGVyYWJsZXMsIENoYXJ0RGF0YUxhYmVscywgem9vbVBsdWdpbik7XG4gICAgfVxuXG4gICAgcmVzZXRab29tKCkge1xuICAgICAgICB0aGlzLl96b29tUGVyaW9kID0ge1xuICAgICAgICAgICAgZnJvbTogbnVsbCxcbiAgICAgICAgICAgIHRvOiBudWxsXG4gICAgICAgIH07XG5cbiAgICAgICAgdGhpcy56b29tUGVyaW9kQ2hhbmdlZC5uZXh0KHRoaXMuX3pvb21QZXJpb2QpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEBpbmhlcml0RG9jXG4gICAgICovXG4gICAgbmdPbkNoYW5nZXMoY2hhbmdlczogU2ltcGxlQ2hhbmdlcyk6IHZvaWQge1xuICAgICAgICBpZiAoIWNoYW5nZXNbJ2pvYkV4ZWN1dGlvbnMnXS5maXJzdENoYW5nZSkge1xuICAgICAgICAgICAgdGhpcy5fdXBkYXRlQ2hhcnQoKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEBpbmhlcml0RG9jXG4gICAgICovXG4gICAgbmdPbkluaXQoKTogdm9pZCB7XG4gICAgICAgIHRoaXMuX2luaXRDaGFydCgpO1xuICAgIH1cblxuICAgIHByaXZhdGUgX2luaXRDaGFydCgpOiB2b2lkIHtcbiAgICAgICAgY29uc3QgY2hhcnREYXRhOiBDdXN0b21DaGFydERhdGFbXSA9IHRoaXMuX2dldENoYXJ0RGF0YSgpO1xuICAgICAgICBjb25zdCB1bml0OiBUaW1lVW5pdCA9IHRoaXMuX2dldFRpbWVTY2FsZVVuaXQoY2hhcnREYXRhKTtcbiAgICAgICAgY29uc3QgW21pbiwgbWF4XSA9IHRoaXMuX2dldE1pbk1heEV4ZWN1dGlvblR1cGxlQWRqdXN0ZWQoY2hhcnREYXRhLCB1bml0KTtcblxuICAgICAgICBjb25zdCBkYXRhOiBDaGFydERhdGE8J2xpbmUnLCBDdXN0b21DaGFydERhdGFbXSwgbnVtYmVyPiA9IHtcbiAgICAgICAgICAgIGxhYmVsczogdGhpcy5fZ2V0Q2hhcnRMYWJlbHMoKSxcbiAgICAgICAgICAgIGRhdGFzZXRzOiBbXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICBkYXRhOiBjaGFydERhdGEsXG4gICAgICAgICAgICAgICAgICAgIGZpbGw6IGZhbHNlLFxuICAgICAgICAgICAgICAgICAgICBwb2ludFJhZGl1czogMyxcbiAgICAgICAgICAgICAgICAgICAgcG9pbnRCb3JkZXJDb2xvcjogKGNvbnRleHQpID0+XG4gICAgICAgICAgICAgICAgICAgICAgICBEYXRhSm9iRXhlY3V0aW9uVG9HcmlkRGF0YUpvYkV4ZWN1dGlvbi5yZXNvbHZlQ29sb3IoKGNvbnRleHQucmF3IGFzIHsgc3RhdHVzOiBzdHJpbmcgfSk/LnN0YXR1cyksXG4gICAgICAgICAgICAgICAgICAgIHBvaW50QmFja2dyb3VuZENvbG9yOiAoY29udGV4dCkgPT5cbiAgICAgICAgICAgICAgICAgICAgICAgIERhdGFKb2JFeGVjdXRpb25Ub0dyaWREYXRhSm9iRXhlY3V0aW9uLnJlc29sdmVDb2xvcigoY29udGV4dC5yYXcgYXMgeyBzdGF0dXM6IHN0cmluZyB9KT8uc3RhdHVzKSxcbiAgICAgICAgICAgICAgICAgICAgcG9pbnRCb3JkZXJXaWR0aDogMyxcbiAgICAgICAgICAgICAgICAgICAgcGFyc2luZzoge1xuICAgICAgICAgICAgICAgICAgICAgICAgeEF4aXNLZXk6ICdzdGFydFRpbWUnLFxuICAgICAgICAgICAgICAgICAgICAgICAgeUF4aXNLZXk6ICdkdXJhdGlvbidcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIF1cbiAgICAgICAgfTtcblxuICAgICAgICB0aGlzLmNoYXJ0ID0gbmV3IENoYXJ0PCdsaW5lJywgQ3VzdG9tQ2hhcnREYXRhW10sIG51bWJlcj4oJ2R1cmF0aW9uQ2hhcnQnLCB7XG4gICAgICAgICAgICB0eXBlOiAnbGluZScsXG4gICAgICAgICAgICBkYXRhLFxuICAgICAgICAgICAgb3B0aW9uczoge1xuICAgICAgICAgICAgICAgIC8vIGNhbGxiYWNrIGxpc3RlbiBmb3IgaG92ZXIgZXZlbnRzIGluIGR1cmF0aW9uIGNoYXJ0IGFuZCBwcm9jZXNzIGV2ZW50c1xuICAgICAgICAgICAgICAgIG9uSG92ZXI6IChldmVudCwgYWN0aXZlRWxlbWVudHMpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5fZW1pdEZvY3Vzc2VkRXhlY3V0aW9uSWQoYWN0aXZlRWxlbWVudHMpO1xuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgc2hvd0xpbmU6IGZhbHNlLFxuICAgICAgICAgICAgICAgIHNjYWxlczoge1xuICAgICAgICAgICAgICAgICAgICB4OiB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0eXBlOiAndGltZScsXG4gICAgICAgICAgICAgICAgICAgICAgICB0aW1lOiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdW5pdFxuICAgICAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgICAgIG1pbixcbiAgICAgICAgICAgICAgICAgICAgICAgIG1heFxuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICB5OiB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aXRsZToge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpc3BsYXk6IHRydWUsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGV4dDogYER1cmF0aW9uICR7dGhpcy5fZ2V0RHVyYXRpb25Vbml0KCkubmFtZX1gXG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIG1haW50YWluQXNwZWN0UmF0aW86IGZhbHNlLFxuICAgICAgICAgICAgICAgIHBsdWdpbnM6IHtcbiAgICAgICAgICAgICAgICAgICAgem9vbToge1xuICAgICAgICAgICAgICAgICAgICAgICAgem9vbToge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRyYWc6IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZW5hYmxlZDogdHJ1ZVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kZTogJ3gnLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9uWm9vbUNvbXBsZXRlOiAoY29udGV4dCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBmcm9tID0gbmV3IERhdGUoTWF0aC5mbG9vcihjb250ZXh0LmNoYXJ0LnNjYWxlc1sneCddLm1pbikpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCB0byA9IG5ldyBEYXRlKE1hdGguY2VpbChjb250ZXh0LmNoYXJ0LnNjYWxlc1sneCddLm1heCkpO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICh0aGlzLl96b29tUGVyaW9kLmZyb20gPT09IGZyb20gJiYgdGhpcy5fem9vbVBlcmlvZC50byA9PT0gdG8pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuX3pvb21QZXJpb2QgPSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmcm9tLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG9cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnpvb21QZXJpb2RDaGFuZ2VkLm5leHQodGhpcy5fem9vbVBlcmlvZCk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICBkYXRhbGFiZWxzOiB7XG4gICAgICAgICAgICAgICAgICAgICAgICBkaXNwbGF5OiBmYWxzZVxuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICBsZWdlbmQ6IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGRpc3BsYXk6IGZhbHNlXG4gICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgIHRvb2x0aXA6IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNhbGxiYWNrczoge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsOiAoY29udGV4dCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCByYXdWYWx1ZXMgPSBjb250ZXh0LnJhdyBhcyBDdXN0b21DaGFydERhdGE7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9yZXN0cmljdC1wbHVzLW9wZXJhbmRzXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiAoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgRHVyYXRpb246ICR7Y29udGV4dC5wYXJzZWQueX0gfCAke3Jhd1ZhbHVlcy5zdGF0dXN9YCArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAocmF3VmFsdWVzLmVuZFRpbWVcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA/IGAgfCBFbmQ6ICR7dGhpcy5kYXRlUGlwZS50cmFuc2Zvcm0ocmF3VmFsdWVzLmVuZFRpbWUsIERBVEFfUElQRUxJTkVTX0RBVEVfVElNRV9GT1JNQVQsICdVVEMnKX1gXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgOiAnJylcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIHByaXZhdGUgX3VwZGF0ZUNoYXJ0KCk6IHZvaWQge1xuICAgICAgICBjb25zdCBjaGFydExhYmVsczogbnVtYmVyW10gPSB0aGlzLl9nZXRDaGFydExhYmVscygpO1xuICAgICAgICBjb25zdCBjaGFydERhdGE6IEN1c3RvbUNoYXJ0RGF0YVtdID0gdGhpcy5fZ2V0Q2hhcnREYXRhKCk7XG4gICAgICAgIGNvbnN0IHVuaXQ6IFRpbWVVbml0ID0gdGhpcy5fZ2V0VGltZVNjYWxlVW5pdChjaGFydERhdGEpO1xuICAgICAgICBjb25zdCBbbWluLCBtYXhdID0gdGhpcy5fZ2V0TWluTWF4RXhlY3V0aW9uVHVwbGVBZGp1c3RlZChjaGFydERhdGEsIHVuaXQpO1xuXG4gICAgICAgIHRoaXMuY2hhcnQuZGF0YS5sYWJlbHMgPSBjaGFydExhYmVscztcbiAgICAgICAgdGhpcy5jaGFydC5kYXRhLmRhdGFzZXRzWzBdLmRhdGEgPSBjaGFydERhdGE7XG5cbiAgICAgICAgdGhpcy5jaGFydC5vcHRpb25zLnNjYWxlc1sneCddID0ge1xuICAgICAgICAgICAgdHlwZTogJ3RpbWUnLFxuICAgICAgICAgICAgdGltZToge1xuICAgICAgICAgICAgICAgIHVuaXRcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBtaW4sXG4gICAgICAgICAgICBtYXhcbiAgICAgICAgfTtcblxuICAgICAgICB0aGlzLmNoYXJ0LnVwZGF0ZSgpO1xuICAgIH1cblxuICAgIHByaXZhdGUgX2dldENoYXJ0TGFiZWxzKCk6IG51bWJlcltdIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuam9iRXhlY3V0aW9ucy5tYXAoKGV4ZWN1dGlvbikgPT4gRGF0ZVV0aWwubm9ybWFsaXplVG9VVEMoZXhlY3V0aW9uLnN0YXJ0VGltZSkuZ2V0VGltZSgpKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIF9nZXRDaGFydERhdGEoKTogQ3VzdG9tQ2hhcnREYXRhW10ge1xuICAgICAgICBjb25zdCBkaXZpZGVyID0gdGhpcy5fZ2V0RHVyYXRpb25Vbml0KCkuZGl2aWRlcjtcblxuICAgICAgICByZXR1cm4gdGhpcy5qb2JFeGVjdXRpb25zXG4gICAgICAgICAgICAubWFwKChleGVjdXRpb24pID0+IHtcbiAgICAgICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgICAgICBzdGFydFRpbWU6IERhdGVVdGlsLm5vcm1hbGl6ZVRvVVRDKGV4ZWN1dGlvbi5zdGFydFRpbWUpLmdldFRpbWUoKSxcbiAgICAgICAgICAgICAgICAgICAgZHVyYXRpb246IE1hdGgucm91bmQoKHRoaXMuX2dldEpvYkR1cmF0aW9uU2Vjb25kcyhleGVjdXRpb24pIC8gZGl2aWRlcikgKiAxMDApIC8gMTAwLFxuICAgICAgICAgICAgICAgICAgICBlbmRUaW1lOiBleGVjdXRpb24uZW5kVGltZSA/IGV4ZWN1dGlvbi5lbmRUaW1lIDogdW5kZWZpbmVkLFxuICAgICAgICAgICAgICAgICAgICBzdGF0dXM6IGV4ZWN1dGlvbi5zdGF0dXMsXG4gICAgICAgICAgICAgICAgICAgIG9wSWQ6IGV4ZWN1dGlvbi5vcElkLFxuICAgICAgICAgICAgICAgICAgICBpZDogZXhlY3V0aW9uLmlkXG4gICAgICAgICAgICAgICAgfSBhcyBDdXN0b21DaGFydERhdGE7XG4gICAgICAgICAgICB9KVxuICAgICAgICAgICAgLnNvcnQoKGV4MSwgZXgyKSA9PiBleDEuc3RhcnRUaW1lIC0gZXgyLnN0YXJ0VGltZSk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBfZ2V0VGltZVNjYWxlVW5pdChjaGFydERhdGE6IEN1c3RvbUNoYXJ0RGF0YVtdKTogVGltZVVuaXQge1xuICAgICAgICBjb25zdCBbbWluLCBtYXhdID0gdGhpcy5fZ2V0TWluTWF4RXhlY3V0aW9uVHVwbGUoY2hhcnREYXRhKTtcblxuICAgICAgICBpZiAoQ29sbGVjdGlvbnNVdGlsLmlzTmlsKG1pbikgfHwgQ29sbGVjdGlvbnNVdGlsLmlzTmlsKG1heCkpIHtcbiAgICAgICAgICAgIHJldHVybiAnZGF5JztcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IF9taW4gPSBDb2xsZWN0aW9uc1V0aWwuaXNOdW1iZXIobWluKSA/IG1pbiA6IG5ldyBEYXRlKG1pbikuZ2V0VGltZSgpO1xuICAgICAgICBjb25zdCBfbWF4ID0gQ29sbGVjdGlvbnNVdGlsLmlzTnVtYmVyKG1heCkgPyBtYXggOiBuZXcgRGF0ZShtYXgpLmdldFRpbWUoKTtcbiAgICAgICAgY29uc3QgZGlmZiA9IF9tYXggLSBfbWluO1xuXG4gICAgICAgIGlmIChkaWZmID4gdGhpcy5fZ2V0VGltZVVuaXRNaWxsaXNlY29uZHMoJ3llYXInKSArIHRoaXMuX2dldFRpbWVVbml0TWlsbGlzZWNvbmRzKCdzZWNvbmQnKSkge1xuICAgICAgICAgICAgcmV0dXJuICd5ZWFyJztcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChkaWZmID4gdGhpcy5fZ2V0VGltZVVuaXRNaWxsaXNlY29uZHMoJ21vbnRoJykgKyB0aGlzLl9nZXRUaW1lVW5pdE1pbGxpc2Vjb25kcygnc2Vjb25kJykpIHtcbiAgICAgICAgICAgIHJldHVybiAnbW9udGgnO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGRpZmYgPiAyICogdGhpcy5fZ2V0VGltZVVuaXRNaWxsaXNlY29uZHMoJ3dlZWsnKSkge1xuICAgICAgICAgICAgcmV0dXJuICd3ZWVrJztcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChkaWZmID4gdGhpcy5fZ2V0VGltZVVuaXRNaWxsaXNlY29uZHMoJ2RheScpICsgdGhpcy5fZ2V0VGltZVVuaXRNaWxsaXNlY29uZHMoJ3NlY29uZCcpKSB7XG4gICAgICAgICAgICByZXR1cm4gJ2RheSc7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoZGlmZiA+IHRoaXMuX2dldFRpbWVVbml0TWlsbGlzZWNvbmRzKCdob3VyJykgKyB0aGlzLl9nZXRUaW1lVW5pdE1pbGxpc2Vjb25kcygnc2Vjb25kJykpIHtcbiAgICAgICAgICAgIHJldHVybiAnaG91cic7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoZGlmZiA+IHRoaXMuX2dldFRpbWVVbml0TWlsbGlzZWNvbmRzKCdtaW51dGUnKSArIHRoaXMuX2dldFRpbWVVbml0TWlsbGlzZWNvbmRzKCdtaWxsaXNlY29uZCcpKSB7XG4gICAgICAgICAgICByZXR1cm4gJ21pbnV0ZSc7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoZGlmZiA+IHRoaXMuX2dldFRpbWVVbml0TWlsbGlzZWNvbmRzKCdzZWNvbmQnKSArIHRoaXMuX2dldFRpbWVVbml0TWlsbGlzZWNvbmRzKCdtaWxsaXNlY29uZCcpKSB7XG4gICAgICAgICAgICByZXR1cm4gJ3NlY29uZCc7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gJ21pbGxpc2Vjb25kJztcbiAgICB9XG5cbiAgICBwcml2YXRlIF9nZXREdXJhdGlvblVuaXQoKTogeyBuYW1lOiBzdHJpbmc7IGRpdmlkZXI6IG51bWJlciB9IHtcbiAgICAgICAgY29uc3QgbWF4RHVyYXRpb25TZWNvbmRzID0gdGhpcy5fZ2V0TWF4RHVyYXRpb25TZWNvbmRzKCk7XG5cbiAgICAgICAgaWYgKG1heER1cmF0aW9uU2Vjb25kcyA+IDYwKSB7XG4gICAgICAgICAgICByZXR1cm4gbWF4RHVyYXRpb25TZWNvbmRzID4gMzYwMCA/IHsgbmFtZTogJ2hvdXJzJywgZGl2aWRlcjogMzYwMCB9IDogeyBuYW1lOiAnbWludXRlcycsIGRpdmlkZXI6IDYwIH07XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICByZXR1cm4geyBuYW1lOiAnc2Vjb25kcycsIGRpdmlkZXI6IDEgfTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByaXZhdGUgX2dldE1heER1cmF0aW9uU2Vjb25kcygpOiBudW1iZXIge1xuICAgICAgICByZXR1cm4gdGhpcy5qb2JFeGVjdXRpb25zXG4gICAgICAgICAgICAubWFwKChleGVjdXRpb24pID0+IHRoaXMuX2dldEpvYkR1cmF0aW9uU2Vjb25kcyhleGVjdXRpb24pKVxuICAgICAgICAgICAgLnNvcnQoKHYxLCB2MikgPT4gdjEgLSB2MilcbiAgICAgICAgICAgIC5wb3AoKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIF9nZXRKb2JEdXJhdGlvblNlY29uZHMoZXhlY3V0aW9uOiBHcmlkRGF0YUpvYkV4ZWN1dGlvbik6IG51bWJlciB7XG4gICAgICAgIGNvbnN0IGVuZFRpbWUgPSBleGVjdXRpb24uZW5kVGltZSA/IG5ldyBEYXRlKGV4ZWN1dGlvbi5lbmRUaW1lKS5nZXRUaW1lKCkgOiBEYXRlLm5vdygpO1xuICAgICAgICBjb25zdCBkZWx0YSA9IGVuZFRpbWUgLSBuZXcgRGF0ZShleGVjdXRpb24uc3RhcnRUaW1lKS5nZXRUaW1lKCk7XG5cbiAgICAgICAgcmV0dXJuIGRlbHRhIC8gMTAwMDtcbiAgICB9XG5cbiAgICBwcml2YXRlIF9lbWl0Rm9jdXNzZWRFeGVjdXRpb25JZChhY3RpdmVFbGVtZW50czogQWN0aXZlRWxlbWVudFtdKTogdm9pZCB7XG4gICAgICAgIGlmIChhY3RpdmVFbGVtZW50cy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICBjb25zdCBlbGVtZW50OiB7ICRjb250ZXh0PzogeyByYXc/OiBDdXN0b21DaGFydERhdGEgfSB9ID0gYWN0aXZlRWxlbWVudHNbMF0uZWxlbWVudCBhcyB1bmtub3duO1xuICAgICAgICAgICAgY29uc3QgZXhlY3V0aW9uSWQgPSBlbGVtZW50Py4kY29udGV4dD8ucmF3Py5pZCA/PyBudWxsO1xuXG4gICAgICAgICAgICAvLyBpZiBldmVudCBlbWl0cyB0aGF0IGVsZW1lbnQgaXMgZm9jdXNzZWQgYW5kIHRoYXQgdmFsdWUgaXMgc2FtZSBhcyBwcmV2aW91cyBza2lwIHByb2Nlc3NpbmdcbiAgICAgICAgICAgIGlmICh0aGlzLl9mb2N1c2VkRXhlY3V0aW9uSWQgPT09IGV4ZWN1dGlvbklkKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyB3aGVuIGVsZW1lbnQgaXMgZm9jdXNlZCBmb3IgdGhlIGZpcnN0IHRpbWUsIHNhdmUgZXhlY3V0aW9uSWQgaW4gY29tcG9uZW50IGNvbnRleHRcbiAgICAgICAgICAgIHRoaXMuX2ZvY3VzZWRFeGVjdXRpb25JZCA9IGV4ZWN1dGlvbklkO1xuICAgICAgICAgICAgLy8gZW1pdCBleGVjdXRpb25JZCB0byBwYXJlbnQgY29tcG9uZW50XG4gICAgICAgICAgICB0aGlzLmV4ZWN1dGlvbklkRm9jdXNlZC5uZXh0KGV4ZWN1dGlvbklkKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIC8vIGlmIGV2ZW50IGVtaXRzIHRoYXQgbm8gZWxlbWVudCBpcyBmb2N1c3NlZCBhbmQgdGhhdCB2YWx1ZSBpcyBzYW1lIGFzIHByZXZpb3VzIHNraXAgcHJvY2Vzc2luZ1xuICAgICAgICAgICAgaWYgKCF0aGlzLl9mb2N1c2VkRXhlY3V0aW9uSWQpIHtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIHdoZW4gZm9jdXNlZCBlbGVtZW50IGxvc2UgZm9jdXMgY2xlYXIgZXhlY3V0aW9uSWQgZnJvbSBjb21wb25lbnQgY29udGV4dFxuICAgICAgICAgICAgdGhpcy5fZm9jdXNlZEV4ZWN1dGlvbklkID0gbnVsbDtcbiAgICAgICAgICAgIC8vIGVtaXQgbnVsbCB2YWx1ZSB0byBwYXJlbnQgY29tcG9uZW50XG4gICAgICAgICAgICB0aGlzLmV4ZWN1dGlvbklkRm9jdXNlZC5uZXh0KG51bGwpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBfZ2V0TWluTWF4RXhlY3V0aW9uVHVwbGUoY2hhcnREYXRhOiBDdXN0b21DaGFydERhdGFbXSk6IFtudW1iZXIsIG51bWJlcl0ge1xuICAgICAgICBpZiAoY2hhcnREYXRhLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgICAgaWYgKENvbGxlY3Rpb25zVXRpbC5pc0RhdGUodGhpcy5fem9vbVBlcmlvZC5mcm9tKSAmJiBDb2xsZWN0aW9uc1V0aWwuaXNEYXRlKHRoaXMuX3pvb21QZXJpb2QudG8pKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIFt0aGlzLl96b29tUGVyaW9kLmZyb20uZ2V0VGltZSgpLCB0aGlzLl96b29tUGVyaW9kLnRvLmdldFRpbWUoKV07XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiBbbnVsbCwgbnVsbF07XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoY2hhcnREYXRhLmxlbmd0aCA9PT0gMSkge1