UNPKG

@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
/* * 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