UNPKG

@c8y/ngx-components

Version:

Angular modules for Cumulocity IoT applications

193 lines 39.6 kB
import { Injectable } from '@angular/core'; import { from, interval, merge } from 'rxjs'; import { buffer, map, mergeMap, tap, throttleTime } from 'rxjs/operators'; import { AlarmRealtimeService, EventRealtimeService, MeasurementRealtimeService } from '@c8y/ngx-components'; import { EchartsOptionsService } from './echarts-options.service'; import * as i0 from "@angular/core"; import * as i1 from "@c8y/ngx-components"; import * as i2 from "./echarts-options.service"; export class ChartRealtimeService { constructor(measurementRealtime, alarmRealtimeService, eventRealtimeService, echartsOptionsService) { this.measurementRealtime = measurementRealtime; this.alarmRealtimeService = alarmRealtimeService; this.eventRealtimeService = eventRealtimeService; this.echartsOptionsService = echartsOptionsService; this.INTERVAL = 1000; this.MIN_REALTIME_TIMEOUT = 250; this.MAX_REALTIME_TIMEOUT = 5_000; this.lastMeasurements = new Map(); } startRealtime(echartsInstance, datapoints, timeRange, datapointOutOfSyncCallback, timeRangeChangedCallback, alarmOrEventConfig = [], displayOptions) { this.echartsInstance = echartsInstance; this.currentTimeRange = { dateFrom: new Date(timeRange.dateFrom), dateTo: new Date(timeRange.dateTo) }; const activeAlarmsOrEvents = alarmOrEventConfig.filter(alarmOrEvent => alarmOrEvent.__active && !alarmOrEvent.__hidden); const uniqueAlarmOrEventTargets = Array.from(new Set(activeAlarmsOrEvents.map(aOrE => aOrE.__target.id))); const allAlarmsAndEvents$ = from(uniqueAlarmOrEventTargets).pipe(mergeMap(targetId => { const alarmsRealtime$ = this.alarmRealtimeService.onAll$(targetId); const eventsRealtime$ = this.eventRealtimeService.onAll$(targetId); return merge(alarmsRealtime$, eventsRealtime$).pipe(map(realtimeMessage => realtimeMessage.data)); })); const measurementsForDatapoints = datapoints.map(dp => { const source$ = this.measurementRealtime.onCreateOfSpecificMeasurement$(dp.fragment, dp.series, dp.__target?.id); return source$.pipe(map((measurement) => ({ datapoint: dp, measurement }))); }); const updateThrottleTime = this.getRealtimeUpdateThrottleTime(timeRange); const measurement$ = merge(...measurementsForDatapoints); const bufferReset$ = merge(measurement$.pipe(throttleTime(updateThrottleTime)), interval(this.INTERVAL).pipe(tap(() => { this.currentTimeRange = { dateFrom: new Date((this.currentTimeRange?.dateFrom?.valueOf() || 0) + this.INTERVAL), dateTo: new Date((this.currentTimeRange?.dateTo?.valueOf() || 0) + this.INTERVAL) }; timeRangeChangedCallback(this.currentTimeRange); }), throttleTime(updateThrottleTime))).pipe(throttleTime(this.MIN_REALTIME_TIMEOUT)); this.realtimeSubscriptionMeasurements = measurement$ .pipe(buffer(bufferReset$)) .subscribe(measurements => { this.updateChartInstance(measurements, null, displayOptions, datapointOutOfSyncCallback); // Store the last measurements measurements.forEach(measurement => { this.lastMeasurements.set(measurement.datapoint.fragment, measurement); }); }); this.realtimeSubscriptionAlarmsEvents = allAlarmsAndEvents$ .pipe(map(alarmOrEvent => { const foundAlarmOrEvent = activeAlarmsOrEvents.find(aOrE => { return aOrE.filters.type === alarmOrEvent.type; }); if (foundAlarmOrEvent) { alarmOrEvent['color'] = foundAlarmOrEvent.color; alarmOrEvent['selectedDatapoint'] = foundAlarmOrEvent.selectedDatapoint; } if (foundAlarmOrEvent) { const fragment = alarmOrEvent['selectedDatapoint'].fragment; if (this.lastMeasurements.has(fragment)) { const lastMeasurement = this.lastMeasurements.get(fragment); this.updateChartInstance([lastMeasurement], alarmOrEvent, displayOptions, datapointOutOfSyncCallback); } } return foundAlarmOrEvent ? alarmOrEvent : null; })) .subscribe(); } stopRealtime() { this.realtimeSubscriptionMeasurements?.unsubscribe(); this.realtimeSubscriptionAlarmsEvents?.unsubscribe(); } removeValuesBeforeTimeRange(series) { const firstValidValueByDateIndex = series.data.findIndex(([dateString, _]) => { return new Date(dateString) >= (this.currentTimeRange?.dateFrom || new Date()); }); if (firstValidValueByDateIndex > 1) { // we need one value before dateFrom for chart lines to be extended to the left edge of the graph series.data = series.data.slice(firstValidValueByDateIndex - 1); } return series.data; } getRealtimeUpdateThrottleTime(timeRange) { const timeRangeInMs = new Date(timeRange.dateTo).valueOf() - new Date(timeRange.dateFrom).valueOf(); const calculatedThrottleTime = Math.round(timeRangeInMs / 1000); if (calculatedThrottleTime < this.MIN_REALTIME_TIMEOUT) { return this.MIN_REALTIME_TIMEOUT; } else if (calculatedThrottleTime > this.MAX_REALTIME_TIMEOUT) { return this.MAX_REALTIME_TIMEOUT; } return calculatedThrottleTime; } updateChartInstance(receivedMeasurements, alarmOrEvent, displayOptions, datapointOutOfSyncCallback) { const isEvent = (item) => !('severity' in item); const isAlarm = (item) => 'severity' in item; const seriesDataToUpdate = new Map(); receivedMeasurements.forEach(({ datapoint, measurement }) => { if (!seriesDataToUpdate.has(datapoint)) { seriesDataToUpdate.set(datapoint, []); } seriesDataToUpdate.get(datapoint)?.push(measurement); }); let allDataSeries = this.echartsInstance?.getOption()['series']; seriesDataToUpdate.forEach((measurements, datapoint) => { const newValues = measurements.map(m => [ m.time, m[datapoint.fragment][datapoint.series].value ]); const datapointId = datapoint.__target?.id + datapoint.fragment + datapoint.series; const seriesMatchingDatapoint = allDataSeries.find(s => s['datapointId'] === datapointId); if (!seriesMatchingDatapoint) { return; } const seriesDataToUpdate = seriesMatchingDatapoint['data']; seriesDataToUpdate.push(...newValues); seriesMatchingDatapoint['data'] = this.removeValuesBeforeTimeRange(seriesMatchingDatapoint); if (alarmOrEvent) { const renderType = datapoint.renderType || 'min'; const dp = { ...datapoint, values: seriesMatchingDatapoint['data'] }; if (isEvent(alarmOrEvent)) { // if event series with the same id already exists, return const eventExists = allDataSeries.some(series => series['data'].some(data => data[0] === alarmOrEvent.creationTime)); if (eventExists) { return; } const newEventSeries = this.echartsOptionsService.getAlarmOrEventSeries(dp, renderType, false, [alarmOrEvent], 'event', displayOptions, alarmOrEvent.creationTime, null, true); allDataSeries.push(...newEventSeries); } else if (isAlarm(alarmOrEvent)) { const alarmExists = allDataSeries.some((series) => { const seriesData = series['data']; return seriesData.some((data) => data[0] === alarmOrEvent.creationTime); }); if (alarmExists) { const alarmSeries = allDataSeries.filter((series) => { const seriesData = series['data']; return seriesData.some((data) => data[0] === alarmOrEvent.creationTime); }); // remove all matching alarm series which are in the array alarmSeries.forEach(series => { allDataSeries = allDataSeries.filter(s => s['id'] !== series['id']); }); const newAlarmSeries = this.echartsOptionsService.getAlarmOrEventSeries(dp, renderType, false, [alarmOrEvent], 'alarm', displayOptions, alarmOrEvent.creationTime, null, true); allDataSeries.push(...newAlarmSeries); } else { const newAlarmSeries = this.echartsOptionsService.getAlarmOrEventSeries(dp, renderType, false, [alarmOrEvent], 'alarm', displayOptions, alarmOrEvent.id, null, true); allDataSeries.push(...newAlarmSeries); } } } this.checkForValuesAfterTimeRange(seriesMatchingDatapoint['data'], datapoint, datapointOutOfSyncCallback); }); this.echartsInstance?.setOption({ dataZoom: [ { type: 'inside', startValue: this.currentTimeRange?.dateFrom.valueOf(), endValue: this.currentTimeRange?.dateTo.valueOf() } ], xAxis: { max: this.currentTimeRange?.dateTo }, series: allDataSeries }); } checkForValuesAfterTimeRange(data, datapoint, datapointOutOfSyncCallback) { const now = new Date(); const valueAfterNowExists = data.some(([dateString, _]) => { return new Date(dateString).valueOf() > now.valueOf(); }); if (valueAfterNowExists) { datapointOutOfSyncCallback(datapoint); } } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ChartRealtimeService, deps: [{ token: i1.MeasurementRealtimeService }, { token: i1.AlarmRealtimeService }, { token: i1.EventRealtimeService }, { token: i2.EchartsOptionsService }], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ChartRealtimeService }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ChartRealtimeService, decorators: [{ type: Injectable }], ctorParameters: () => [{ type: i1.MeasurementRealtimeService }, { type: i1.AlarmRealtimeService }, { type: i1.EventRealtimeService }, { type: i2.EchartsOptionsService }] }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2hhcnQtcmVhbHRpbWUuc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL2VjaGFydC9zZXJ2aWNlcy9jaGFydC1yZWFsdGltZS5zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDM0MsT0FBTyxFQUFFLElBQUksRUFBRSxRQUFRLEVBQUUsS0FBSyxFQUE0QixNQUFNLE1BQU0sQ0FBQztBQUV2RSxPQUFPLEVBQUUsTUFBTSxFQUFFLEdBQUcsRUFBRSxRQUFRLEVBQUUsR0FBRyxFQUFFLFlBQVksRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBVTFFLE9BQU8sRUFDTCxvQkFBb0IsRUFDcEIsb0JBQW9CLEVBQ3BCLDBCQUEwQixFQUUzQixNQUFNLHFCQUFxQixDQUFDO0FBRTdCLE9BQU8sRUFBRSxxQkFBcUIsRUFBRSxNQUFNLDJCQUEyQixDQUFDOzs7O0FBTWxFLE1BQU0sT0FBTyxvQkFBb0I7SUFVL0IsWUFDVSxtQkFBK0MsRUFDL0Msb0JBQTBDLEVBQzFDLG9CQUEwQyxFQUMxQyxxQkFBNEM7UUFINUMsd0JBQW1CLEdBQW5CLG1CQUFtQixDQUE0QjtRQUMvQyx5QkFBb0IsR0FBcEIsb0JBQW9CLENBQXNCO1FBQzFDLHlCQUFvQixHQUFwQixvQkFBb0IsQ0FBc0I7UUFDMUMsMEJBQXFCLEdBQXJCLHFCQUFxQixDQUF1QjtRQWI5QyxhQUFRLEdBQWlCLElBQUksQ0FBQztRQUM5Qix5QkFBb0IsR0FBaUIsR0FBRyxDQUFDO1FBQ3pDLHlCQUFvQixHQUFpQixLQUFLLENBQUM7UUFLM0MscUJBQWdCLEdBQStDLElBQUksR0FBRyxFQUFFLENBQUM7SUFPOUUsQ0FBQztJQUVKLGFBQWEsQ0FDWCxlQUF3QixFQUN4QixVQUF1QyxFQUN2QyxTQUErQyxFQUMvQywwQkFBbUUsRUFDbkUsd0JBRVMsRUFDVCxxQkFBNkMsRUFBRSxFQUMvQyxjQUEy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QUFNLENBQWtCLEVBQ2hELFNBQVMsRUFDVCwwQkFBMEIsQ0FDM0IsQ0FBQztRQUNKLENBQUMsQ0FBQyxDQUFDO1FBRUgsSUFBSSxDQUFDLGVBQWUsRUFBRSxTQUFTLENBQUM7WUFDOUIsUUFBUSxFQUFFO2dCQUNSO29CQUNFLElBQUksRUFBRSxRQUFRO29CQUNkLFVBQVUsRUFBRSxJQUFJLENBQUMsZ0JBQWdCLEVBQUUsUUFBUSxDQUFDLE9BQU8sRUFBRTtvQkFDckQsUUFBUSxFQUFFLElBQUksQ0FBQyxnQkFBZ0IsRUFBRSxNQUFNLENBQUMsT0FBTyxFQUFFO2lCQUNsRDthQUNGO1lBQ0QsS0FBSyxFQUFFO2dCQUNMLEdBQUcsRUFBRSxJQUFJLENBQUMsZ0JBQWdCLEVBQUUsTUFBTTthQUNuQztZQUNELE1BQU0sRUFBRSxhQUFhO1NBQ3RCLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFTyw0QkFBNEIsQ0FDbEMsSUFBbUIsRUFDbkIsU0FBb0MsRUFDcEMsMEJBQW1FO1FBRW5FLE1BQU0sR0FBRyxHQUFHLElBQUksSUFBSSxFQUFFLENBQUM7UUFDdkIsTUFBTSxtQkFBbUIsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxVQUFVLEVBQUUsQ0FBQyxDQUFjLEVBQUUsRUFBRTtZQUNyRSxPQUFPLElBQUksSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFDLE9BQU8sRUFBRSxHQUFHLEdBQUcsQ0FBQyxPQUFPLEVBQUUsQ0FBQztRQUN4RCxDQUFDLENBQUMsQ0FBQztRQUNILElBQUksbUJBQW1CLEVBQUUsQ0FBQztZQUN4QiwwQkFBMEIsQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUN4QyxDQUFDO0lBQ0gsQ0FBQzsrR0EvU1Usb0JBQW9CO21IQUFwQixvQkFBb0I7OzRGQUFwQixvQkFBb0I7a0JBRGhDLFVBQVUiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJbmplY3RhYmxlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBmcm9tLCBpbnRlcnZhbCwgbWVyZ2UsIE9ic2VydmFibGUsIFN1YnNjcmlwdGlvbiB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgSUFsYXJtLCBJRXZlbnQsIElNZWFzdXJlbWVudCB9IGZyb20gJ0BjOHkvY2xpZW50JztcbmltcG9ydCB7IGJ1ZmZlciwgbWFwLCBtZXJnZU1hcCwgdGFwLCB0aHJvdHRsZVRpbWUgfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5pbXBvcnQge1xuICBBbGFybU9yRXZlbnRFeHRlbmRlZCxcbiAgRGF0YXBvaW50Q2hhcnRSZW5kZXJUeXBlLFxuICBEYXRhcG9pbnRSZWFsdGltZU1lYXN1cmVtZW50cyxcbiAgRGF0YXBvaW50c0dyYXBoS1BJRGV0YWlscyxcbiAgRGF0YXBvaW50c0dyYXBoV2lkZ2V0Q29uZmlnLFxuICBEcFdpdGhWYWx1ZXMsXG4gIFNlcmllc1ZhbHVlXG59IGZyb20gJy4uL21vZGVscyc7XG5pbXBvcnQge1xuICBBbGFybVJlYWx0aW1lU2VydmljZSxcbiAgRXZlbnRSZWFsdGltZVNlcnZpY2UsXG4gIE1lYXN1cmVtZW50UmVhbHRpbWVTZXJ2aWNlLFxuICBSZWFsdGltZU1lc3NhZ2Vcbn0gZnJvbSAnQGM4eS9uZ3gtY29tcG9uZW50cyc7XG5pbXBvcnQgdHlwZSB7IEVDaGFydHMsIFNlcmllc09wdGlvbiB9IGZyb20gJ2VjaGFydHMnO1xuaW1wb3J0IHsgRWNoYXJ0c09wdGlvbnNTZXJ2aWNlIH0gZnJvbSAnLi9lY2hhcnRzLW9wdGlvbnMuc2VydmljZSc7XG5pbXBvcnQgeyBDdXN0b21TZXJpZXNPcHRpb25zIH0gZnJvbSAnLi4vbW9kZWxzL2NoYXJ0Lm1vZGVsJztcblxudHlwZSBNaWxsaXNlY29uZHMgPSBudW1iZXI7XG5cbkBJbmplY3RhYmxlKClcbmV4cG9ydCBjbGFzcyBDaGFydFJlYWx0aW1lU2VydmljZSB7XG4gIHByaXZhdGUgSU5URVJWQUw6IE1pbGxpc2Vjb25kcyA9IDEwMDA7XG4gIHByaXZhdGUgTUlOX1JFQUxUSU1FX1RJTUVPVVQ6IE1pbGxpc2Vjb25kcyA9IDI1MDtcbiAgcHJpdmF0ZSBNQVhfUkVBTFRJTUVfVElNRU9VVDogTWlsbGlzZWNvbmRzID0gNV8wMDA7XG4gIHByaXZhdGUgcmVhbHRpbWVTdWJzY3JpcHRpb25NZWFzdXJlbWVudHMhOiBTdWJzY3JpcHRpb247XG4gIHByaXZhdGUgcmVhbHRpbWVTdWJzY3JpcHRpb25BbGFybXNFdmVudHMhOiBTdWJzY3JpcHRpb247XG4gIHByaXZhdGUgZWNoYXJ0c0luc3RhbmNlOiBFQ2hhcnRzIHwgdW5kZWZpbmVkO1xuICBwcml2YXRlIGN1cnJlbnRUaW1lUmFuZ2U6IHsgZGF0ZUZyb206IERhdGU7IGRhdGVUbzogRGF0ZSB9IHwgdW5kZWZpbmVkO1xuICBwcml2YXRlIGxhc3RNZWFzdXJlbWVudHM6IE1hcDxzdHJpbmcsIERhdGFwb2ludFJlYWx0aW1lTWVhc3VyZW1lbnRzPiA9IG5ldyBNYXAoKTtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIG1lYXN1cmVtZW50UmVhbHRpbWU6IE1lYXN1cmVtZW50UmVhbHRpbWVTZXJ2aWNlLFxuICAgIHByaXZhdGUgYWxhcm1SZWFsdGltZVNlcnZpY2U6IEFsYXJtUmVhbHRpbWVTZXJ2aWNlLFxuICAgIHByaXZhdGUgZXZlbnRSZWFsdGltZVNlcnZpY2U6IEV2ZW50UmVhbHRpbWVTZXJ2aWNlLFxuICAgIHByaXZhdGUgZWNoYXJ0c09wdGlvbnNTZXJ2aWNlOiBFY2hhcnRzT3B0aW9uc1NlcnZpY2VcbiAgKSB7fVxuXG4gIHN0YXJ0UmVhbHRpbWUoXG4gICAgZWNoYXJ0c0luc3RhbmNlOiBFQ2hhcnRzLFxuICAgIGRhdGFwb2ludHM6IERhdGFwb2ludHNHcmFwaEtQSURldGFpbHNbXSxcbiAgICB0aW1lUmFuZ2U6IHsgZGF0ZUZyb206IHN0cmluZzsgZGF0ZVRvOiBzdHJpbmcgfSxcbiAgICBkYXRhcG9pbnRPdXRPZlN5bmNDYWxsYmFjazogKGRwOiBEYXRhcG9pbnRzR3JhcGhLUElEZXRhaWxzKSA9PiB2b2lkLFxuICAgIHRpbWVSYW5nZUNoYW5nZWRDYWxsYmFjazogKFxuICAgICAgdGltZVJhbmdlOiBQaWNrPERhdGFwb2ludHNHcmFwaFdpZGdldENvbmZpZywgJ2RhdGVGcm9tJyB8ICdkYXRlVG8nPlxuICAgICkgPT4gdm9pZCxcbiAgICBhbGFybU9yRXZlbnRDb25maWc6IEFsYXJtT3JFdmVudEV4dGVuZGVkW10gPSBbXSxcbiAgICBkaXNwbGF5T3B0aW9uczogeyBkaXNwbGF5TWFya2VkTGluZTogYm9vbGVhbjsgZGlzcGxheU1hcmtlZFBvaW50OiBib29sZWFuIH1cbiAgKSB7XG4gICAgdGhpcy5lY2hhcnRzSW5zdGFuY2UgPSBlY2hhcnRzSW5zdGFuY2U7XG4gICAgdGhpcy5jdXJyZW50VGltZVJhbmdlID0ge1xuICAgICAgZGF0ZUZyb206IG5ldyBEYXRlKHRpbWVSYW5nZS5kYXRlRnJvbSksXG4gICAgICBkYXRlVG86IG5ldyBEYXRlKHRpbWVSYW5nZS5kYXRlVG8pXG4gICAgfTtcblxuICAgIGNvbnN0IGFjdGl2ZUFsYXJtc09yRXZlbnRzID0gYWxhcm1PckV2ZW50Q29uZmlnLmZpbHRlcihcbiAgICAgIGFsYXJtT3JFdmVudCA9PiBhbGFybU9yRXZlbnQuX19hY3RpdmUgJiYgIWFsYXJtT3JFdmVudC5fX2hpZGRlblxuICAgICk7XG4gICAgY29uc3QgdW5pcXVlQWxhcm1PckV2ZW50VGFyZ2V0cyA9IEFycmF5LmZyb20oXG4gICAgICBuZXcgU2V0KGFjdGl2ZUFsYXJtc09yRXZlbnRzLm1hcChhT3JFID0+IGFPckUuX190YXJnZXQuaWQpKVxuICAgICk7XG5cbiAgICBjb25zdCBhbGxBbGFybXNBbmRFdmVudHMkOiBPYnNlcnZhYmxlPElBbGFybSB8IElFdmVudD4gPSBmcm9tKHVuaXF1ZUFsYXJtT3JFdmVudFRhcmdldHMpLnBpcGUoXG4gICAgICBtZXJnZU1hcCh0YXJnZXRJZCA9PiB7XG4gICAgICAgIGNvbnN0IGFsYXJtc1JlYWx0aW1lJDogT2JzZXJ2YWJsZTxSZWFsdGltZU1lc3NhZ2U8SUFsYXJtPj4gPVxuICAgICAgICAgIHRoaXMuYWxhcm1SZWFsdGltZVNlcnZpY2Uub25BbGwkKHRhcmdldElkKTtcbiAgICAgICAgY29uc3QgZXZlbnRzUmVhbHRpbWUkOiBPYnNlcnZhYmxlPFJlYWx0aW1lTWVzc2FnZTxJRXZlbnQ+PiA9XG4gICAgICAgICAgdGhpcy5ldmVudFJlYWx0aW1lU2VydmljZS5vbkFsbCQodGFyZ2V0SWQpO1xuICAgICAgICByZXR1cm4gbWVyZ2UoYWxhcm1zUmVhbHRpbWUkLCBldmVudHNSZWFsdGltZSQpLnBpcGUoXG4gICAgICAgICAgbWFwKHJlYWx0aW1lTWVzc2FnZSA9PiByZWFsdGltZU1lc3NhZ2UuZGF0YSBhcyBJQWxhcm0gfCBJRXZlbnQpXG4gICAgICAgICk7XG4gICAgICB9KVxuICAgICk7XG5cbiAgICBjb25zdCBtZWFzdXJlbWVudHNGb3JEYXRhcG9pbnRzOiBPYnNlcnZhYmxlPERhdGFwb2ludFJlYWx0aW1lTWVhc3VyZW1lbnRzPltdID0gZGF0YXBvaW50cy5tYXAoXG4gICAgICBkcCA9PiB7XG4gICAgICAgIGNvbnN0IHNvdXJjZSQ6IE9ic2VydmFibGU8SU1lYXN1cmVtZW50PiA9XG4gICAgICAgICAgdGhpcy5tZWFzdXJlbWVudFJlYWx0aW1lLm9uQ3JlYXRlT2ZTcGVjaWZpY01lYXN1cmVtZW50JChcbiAgICAgICAgICAgIGRwLmZyYWdtZW50LFxuICAgICAgICAgICAgZHAuc2VyaWVzLFxuICAgICAgICAgICAgZHAuX190YXJnZXQ/LmlkXG4gICAgICAgICAgKTtcbiAgICAgICAgcmV0dXJuIHNvdXJjZSQucGlwZShtYXAoKG1lYXN1cmVtZW50OiBJTWVhc3VyZW1lbnQpID0+ICh7IGRhdGFwb2ludDogZHAsIG1lYXN1cmVtZW50IH0pKSk7XG4gICAgICB9XG4gICAgKTtcbiAgICBjb25zdCB1cGRhdGVUaHJvdHRsZVRpbWU6IE1pbGxpc2Vjb25kcyA9IHRoaXMuZ2V0UmVhbHRpbWVVcGRhdGVUaHJvdHRsZVRpbWUodGltZVJhbmdlKTtcbiAgICBjb25zdCBtZWFzdXJlbWVudCQgPSBtZXJnZSguLi5tZWFzdXJlbWVudHNGb3JEYXRhcG9pbnRzKTtcbiAgICBjb25zdCBidWZmZXJSZXNldCQgPSBtZXJnZShcbiAgICAgIG1lYXN1cmVtZW50JC5waXBlKHRocm90dGxlVGltZSh1cGRhdGVUaHJvdHRsZVRpbWUpKSxcbiAgICAgIGludGVydmFsKHRoaXMuSU5URVJWQUwpLnBpcGUoXG4gICAgICAgIHRhcCgoKSA9PiB7XG4gICAgICAgICAgdGhpcy5jdXJyZW50VGltZVJhbmdlID0ge1xuICAgICAgICAgICAgZGF0ZUZyb206IG5ldyBEYXRlKCh0aGlzLmN1cnJlbnRUaW1lUmFuZ2U/LmRhdGVGcm9tPy52YWx1ZU9mKCkgfHwgMCkgKyB0aGlzLklOVEVSVkFMKSxcbiAgICAgICAgICAgIGRhdGVUbzogbmV3IERhdGUoKHRoaXMuY3VycmVudFRpbWVSYW5nZT8uZGF0ZVRvPy52YWx1ZU9mKCkgfHwgMCkgKyB0aGlzLklOVEVSVkFMKVxuICAgICAgICAgIH07XG4gICAgICAgICAgdGltZVJhbmdlQ2hhbmdlZENhbGxiYWNrKHRoaXMuY3VycmVudFRpbWVSYW5nZSk7XG4gICAgICAgIH0pLFxuICAgICAgICB0aHJvdHRsZVRpbWUodXBkYXRlVGhyb3R0bGVUaW1lKVxuICAgICAgKVxuICAgICkucGlwZSh0aHJvdHRsZVRpbWUodGhpcy5NSU5fUkVBTFRJTUVfVElNRU9VVCkpO1xuXG4gICAgdGhpcy5yZWFsdGltZVN1YnNjcmlwdGlvbk1lYXN1cmVtZW50cyA9IG1lYXN1cmVtZW50JFxuICAgICAgLnBpcGUoYnVmZmVyKGJ1ZmZlclJlc2V0JCkpXG4gICAgICAuc3Vic2NyaWJlKG1lYXN1cmVtZW50cyA9PiB7XG4gICAgICAgIHRoaXMudXBkYXRlQ2hhcnRJbnN0YW5jZShtZWFzdXJlbWVudHMsIG51bGwsIGRpc3BsYXlPcHRpb25zLCBkYXRhcG9pbnRPdXRPZlN5bmNDYWxsYmFjayk7XG5cbiAgICAgICAgLy8gU3RvcmUgdGhlIGxhc3QgbWVhc3VyZW1lbnRzXG4gICAgICAgIG1lYXN1cmVtZW50cy5mb3JFYWNoKG1lYXN1cmVtZW50ID0+IHtcbiAgICAgICAgICB0aGlzLmxhc3RNZWFzdXJlbWVudHMuc2V0KG1lYXN1cmVtZW50LmRhdGFwb2ludC5mcmFnbWVudCwgbWVhc3VyZW1lbnQpO1xuICAgICAgICB9KTtcbiAgICAgIH0pO1xuXG4gICAgdGhpcy5yZWFsdGltZVN1YnNjcmlwdGlvbkFsYXJtc0V2ZW50cyA9IGFsbEFsYXJtc0FuZEV2ZW50cyRcbiAgICAgIC5waXBlKFxuICAgICAgICBtYXAoYWxhcm1PckV2ZW50ID0+IHtcbiAgICAgICAgICBjb25zdCBmb3VuZEFsYXJtT3JFdmVudCA9IGFjdGl2ZUFsYXJtc09yRXZlbnRzLmZpbmQoYU9yRSA9PiB7XG4gICAgICAgICAgICByZXR1cm4gYU9yRS5maWx0ZXJzLnR5cGUgPT09IGFsYXJtT3JFdmVudC50eXBlO1xuICAgICAgICAgIH0pO1xuICAgICAgICAgIGlmIChmb3VuZEFsYXJtT3JFdmVudCkge1xuICAgICAgICAgICAgYWxhcm1PckV2ZW50Wydjb2xvciddID0gZm91bmRBbGFybU9yRXZlbnQuY29sb3I7XG4gICAgICAgICAgICBhbGFybU9yRXZlbnRbJ3NlbGVjdGVkRGF0YXBvaW50J10gPSBmb3VuZEFsYXJtT3JFdmVudC5zZWxlY3RlZERhdGFwb2ludDtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBpZiAoZm91bmRBbGFybU9yRXZlbnQpIHtcbiAgICAgICAgICAgIGNvbnN0IGZyYWdtZW50ID0gYWxhcm1PckV2ZW50WydzZWxlY3RlZERhdGFwb2ludCddLmZyYWdtZW50O1xuICAgICAgICAgICAgaWYgKHRoaXMubGFzdE1lYXN1cmVtZW50cy5oYXMoZnJhZ21lbnQpKSB7XG4gICAgICAgICAgICAgIGNvbnN0IGxhc3RNZWFzdXJlbWVudCA9IHRoaXMubGFzdE1lYXN1cmVtZW50cy5nZXQoZnJhZ21lbnQpO1xuXG4gICAgICAgICAgICAgIHRoaXMudXBkYXRlQ2hhcnRJbnN0YW5jZShcbiAgICAgICAgICAgICAgICBbbGFzdE1lYXN1cmVtZW50XSxcbiAgICAgICAgICAgICAgICBhbGFybU9yRXZlbnQsXG4gICAgICAgICAgICAgICAgZGlzcGxheU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgZGF0YXBvaW50T3V0T2ZTeW5jQ2FsbGJhY2tcbiAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG5cbiAgICAgICAgICByZXR1cm4gZm91bmRBbGFybU9yRXZlbnQgPyBhbGFybU9yRXZlbnQgOiBudWxsO1xuICAgICAgICB9KVxuICAgICAgKVxuICAgICAgLnN1YnNjcmliZSgpO1xuICB9XG5cbiAgc3RvcFJlYWx0aW1lKCkge1xuICAgIHRoaXMucmVhbHRpbWVTdWJzY3JpcHRpb25NZWFzdXJlbWVudHM/LnVuc3Vic2NyaWJlKCk7XG4gICAgdGhpcy5yZWFsdGltZVN1YnNjcmlwdGlvbkFsYXJtc0V2ZW50cz8udW5zdWJzY3JpYmUoKTtcbiAgfVxuXG4gIHByaXZhdGUgcmVtb3ZlVmFsdWVzQmVmb3JlVGltZVJhbmdlKHNlcmllczogU2VyaWVzT3B0aW9uKTogU2VyaWVzVmFsdWVbXSB7XG4gICAgY29uc3QgZmlyc3RWYWxpZFZhbHVlQnlEYXRlSW5kZXggPSAoc2VyaWVzLmRhdGEgYXMgU2VyaWVzVmFsdWVbXSkuZmluZEluZGV4KFxuICAgICAgKFtkYXRlU3RyaW5nLCBfXSkgPT4ge1xuICAgICAgICByZXR1cm4gbmV3IERhdGUoZGF0ZVN0cmluZykgPj0gKHRoaXMuY3VycmVudFRpbWVSYW5nZT8uZGF0ZUZyb20gfHwgbmV3IERhdGUoKSk7XG4gICAgICB9XG4gICAgKTtcbiAgICBpZiAoZmlyc3RWYWxpZFZhbHVlQnlEYXRlSW5kZXggPiAxKSB7XG4gICAgICAvLyB3ZSBuZWVkIG9uZSB2YWx1ZSBiZWZvcmUgZGF0ZUZyb20gZm9yIGNoYXJ0IGxpbmVzIHRvIGJlIGV4dGVuZGVkIHRvIHRoZSBsZWZ0IGVkZ2Ugb2YgdGhlIGdyYXBoXG4gICAgICBzZXJpZXMuZGF0YSA9IChzZXJpZXMuZGF0YSBhcyBTZXJpZXNWYWx1ZVtdKS5zbGljZShmaXJzdFZhbGlkVmFsdWVCeURhdGVJbmRleCAtIDEpO1xuICAgIH1cbiAgICByZXR1cm4gc2VyaWVzLmRhdGEgYXMgU2VyaWVzVmFsdWVbXTtcbiAgfVxuXG4gIHByaXZhdGUgZ2V0UmVhbHRpbWVVcGRhdGVUaHJvdHRsZVRpbWUodGltZVJhbmdlOiB7XG4gICAgZGF0ZUZyb206IHN0cmluZztcbiAgICBkYXRlVG86IHN0cmluZztcbiAgfSk6IE1pbGxpc2Vjb25kcyB7XG4gICAgY29uc3QgdGltZVJhbmdlSW5NcyA9XG4gICAgICBuZXcgRGF0ZSh0aW1lUmFuZ2UuZGF0ZVRvKS52YWx1ZU9mKCkgLSBuZXcgRGF0ZSh0aW1lUmFuZ2UuZGF0ZUZyb20pLnZhbHVlT2YoKTtcbiAgICBjb25zdCBjYWxjdWxhdGVkVGhyb3R0bGVUaW1lID0gTWF0aC5yb3VuZCh0aW1lUmFuZ2VJbk1zIC8gMTAwMCk7XG4gICAgaWYgKGNhbGN1bGF0ZWRUaHJvdHRsZVRpbWUgPCB0aGlzLk1JTl9SRUFMVElNRV9USU1FT1VUKSB7XG4gICAgICByZXR1cm4gdGhpcy5NSU5fUkVBTFRJTUVfVElNRU9VVDtcbiAgICB9IGVsc2UgaWYgKGNhbGN1bGF0ZWRUaHJvdHRsZVRpbWUgPiB0aGlzLk1BWF9SRUFMVElNRV9USU1FT1VUKSB7XG4gICAgICByZXR1cm4gdGhpcy5NQVhfUkVBTFRJTUVfVElNRU9VVDtcbiAgICB9XG4gICAgcmV0dXJuIGNhbGN1bGF0ZWRUaHJvdHRsZVRpbWU7XG4gIH1cblxuICBwcml2YXRlIHVwZGF0ZUNoYXJ0SW5zdGFuY2UoXG4gICAgcmVjZWl2ZWRNZWFzdXJlbWVudHM6IERhdGFwb2ludFJlYWx0aW1lTWVhc3VyZW1lbnRzW10sXG4gICAgYWxhcm1PckV2ZW50OiBJQWxhcm0gfCBJRXZlbnQgfCBudWxsLFxuICAgIGRpc3BsYXlPcHRpb25zOiB7IGRpc3BsYXlNYXJrZWRMaW5lOiBib29sZWFuOyBkaXNwbGF5TWFya2VkUG9pbnQ6IGJvb2xlYW4gfSxcbiAgICBkYXRhcG9pbnRPdXRPZlN5bmNDYWxsYmFjazogKGRwOiBEYXRhcG9pbnRzR3JhcGhLUElEZXRhaWxzKSA9PiB2b2lkXG4gICkge1xuICAgIGNvbnN0IGlzRXZlbnQgPSAoaXRlbTogSUFsYXJtIHwgSUV2ZW50KTogaXRlbSBpcyBJRXZlbnQgPT4gISgnc2V2ZXJpdHknIGluIGl0ZW0pO1xuICAgIGNvbnN0IGlzQWxhcm0gPSAoaXRlbTogSUFsYXJtIHwgSUV2ZW50KTogaXRlbSBpcyBJQWxhcm0gPT4gJ3NldmVyaXR5JyBpbiBpdGVtO1xuXG4gICAgY29uc3Qgc2VyaWVzRGF0YVRvVXBkYXRlID0gbmV3IE1hcDxEYXRhcG9pbnRzR3JhcGhLUElEZXRhaWxzLCBJTWVhc3VyZW1lbnRbXT4oKTtcblxuICAgIHJlY2VpdmVkTWVhc3VyZW1lbnRzLmZvckVhY2goKHsgZGF0YXBvaW50LCBtZWFzdXJlbWVudCB9KSA9PiB7XG4gICAgICBpZiAoIXNlcmllc0RhdGFUb1VwZGF0ZS5oYXMoZGF0YXBvaW50KSkge1xuICAgICAgICBzZXJpZXNEYXRhVG9VcGRhdGUuc2V0KGRhdGFwb2ludCwgW10pO1xuICAgICAgfVxuICAgICAgc2VyaWVzRGF0YVRvVXBkYXRlLmdldChkYXRhcG9pbnQpPy5wdXNoKG1lYXN1cmVtZW50KTtcbiAgICB9KTtcblxuICAgIGxldCBhbGxEYXRhU2VyaWVzID0gdGhpcy5lY2hhcnRzSW5zdGFuY2U/LmdldE9wdGlvbigpWydzZXJpZXMnXSBhcyBDdXN0b21TZXJpZXNPcHRpb25zW107XG5cbiAgICBzZXJpZXNEYXRhVG9VcGRhdGUuZm9yRWFjaCgobWVhc3VyZW1lbnRzLCBkYXRhcG9pbnQpID0+IHtcbiAgICAgIGNvbnN0IG5ld1ZhbHVlczogU2VyaWVzVmFsdWVbXSA9IG1lYXN1cmVtZW50cy5tYXAobSA9PiBbXG4gICAgICAgIG0udGltZSBhcyBzdHJpbmcsXG4gICAgICAgIG1bZGF0YXBvaW50LmZyYWdtZW50XVtkYXRhcG9pbnQuc2VyaWVzXS52YWx1ZVxuICAgICAgXSk7XG4gICAgICBjb25zdCBkYXRhcG9pbnRJZCA9IGRhdGFwb2ludC5fX3RhcmdldD8uaWQgKyBkYXRhcG9pbnQuZnJhZ21lbnQgKyBkYXRhcG9pbnQuc2VyaWVzO1xuICAgICAgY29uc3Qgc2VyaWVzTWF0Y2hpbmdEYXRhcG9pbnQgPSBhbGxEYXRhU2VyaWVzLmZpbmQocyA9PiBzWydkYXRhcG9pbnRJZCddID09PSBkYXRhcG9pbnRJZCk7XG4gICAgICBpZiAoIXNlcmllc01hdGNoaW5nRGF0YXBvaW50KSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIGNvbnN0IHNlcmllc0RhdGFUb1VwZGF0ZSA9IHNlcmllc01hdGNoaW5nRGF0YXBvaW50WydkYXRhJ10gYXMgU2VyaWVzVmFsdWVbXTtcbiAgICAgIHNlcmllc0RhdGFUb1VwZGF0ZS5wdXNoKC4uLm5ld1ZhbHVlcyk7XG5cbiAgICAgIHNlcmllc01hdGNoaW5nRGF0YXBvaW50WydkYXRhJ10gPSB0aGlzLnJlbW92ZVZhbHVlc0JlZm9yZVRpbWVSYW5nZShzZXJpZXNNYXRjaGluZ0RhdGFwb2ludCk7XG5cbiAgICAgIGlmIChhbGFybU9yRXZlbnQpIHtcbiAgICAgICAgY29uc3QgcmVuZGVyVHlwZTogRGF0YXBvaW50Q2hhcnRSZW5kZXJUeXBlID0gZGF0YXBvaW50LnJlbmRlclR5cGUgfHwgJ21pbic7XG4gICAgICAgIGNvbnN0IGRwOiBEcFdpdGhWYWx1ZXMgPSB7XG4gICAgICAgICAgLi4uZGF0YXBvaW50LFxuICAgICAgICAgIHZhbHVlczogc2VyaWVzTWF0Y2hpbmdEYXRhcG9pbnRbJ2RhdGEnXSBhcyB7XG4gICAgICAgICAgICBbZGF0ZTogc3RyaW5nXTogeyBtaW46IG51bWJlcjsgbWF4OiBudW1iZXIgfVtdO1xuICAgICAgICAgIH1cbiAgICAgICAgfTtcblxuICAgICAgICBpZiAoaXNFdmVudChhbGFybU9yRXZlbnQpKSB7XG4gICAgICAgICAgLy8gaWYgZXZlbnQgc2VyaWVzIHdpdGggdGhlIHNhbWUgaWQgYWxyZWFkeSBleGlzdHMsIHJldHVyblxuICAgICAgICAgIGNvbnN0IGV2ZW50RXhpc3RzID0gYWxsRGF0YVNlcmllcy5zb21lKHNlcmllcyA9PlxuICAgICAgICAgICAgKHNlcmllc1snZGF0YSddIGFzIHN0cmluZ1tdW10pLnNvbWUoXG4gICAgICAgICAgICAgIGRhdGEgPT4gZGF0YVswXSA9PT0gKGFsYXJtT3JFdmVudCBhcyBJRXZlbnQpLmNyZWF0aW9uVGltZVxuICAgICAgICAgICAgKVxuICAgICAgICAgICk7XG4gICAgICAgICAgaWYgKGV2ZW50RXhpc3RzKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgfVxuICAgICAgICAgIGNvbnN0IG5ld0V2ZW50U2VyaWVzID0gdGhpcy5lY2hhcnRzT3B0aW9uc1NlcnZpY2UuZ2V0QWxhcm1PckV2ZW50U2VyaWVzKFxuICAgICAgICAgICAgZHAsXG4gICAgICAgICAgICByZW5kZXJUeXBlLFxuICAgICAgICAgICAgZmFsc2UsXG4gICAgICAgICAgICBbYWxhcm1PckV2ZW50XSxcbiAgICAgICAgICAgICdldmVudCcsXG4gICAgICAgICAgICBkaXNwbGF5T3B0aW9ucyxcbiAgICAgICAgICAgIGFsYXJtT3JFdmVudC5jcmVhdGlvblRpbWUsXG4gICAgICAgICAgICBudWxsLFxuICAgICAgICAgICAgdHJ1ZVxuICAgICAgICAgICk7XG4gICAgICAgICAgYWxsRGF0YVNlcmllcy5wdXNoKC4uLm5ld0V2ZW50U2VyaWVzKTtcbiAgICAgICAgfSBlbHNlIGlmIChpc0FsYXJtKGFsYXJtT3JFdmVudCkpIHtcbiAgICAgICAgICBjb25zdCBhbGFybUV4aXN0cyA9IGFsbERhdGFTZXJpZXMuc29tZSgoc2VyaWVzOiBDdXN0b21TZXJpZXNPcHRpb25zKSA9PiB7XG4gICAgICAgICAgICBjb25zdCBzZXJpZXNEYXRhID0gc2VyaWVzWydkYXRhJ10gYXMgU2VyaWVzVmFsdWVbXTtcbiAgICAgICAgICAgIHJldHVybiBzZXJpZXNEYXRhLnNvbWUoXG4gICAgICAgICAgICAgIChkYXRhOiBTZXJpZXNWYWx1ZSkgPT4gZGF0YVswXSA9PT0gKGFsYXJtT3JFdmVudCBhcyBJRXZlbnQpLmNyZWF0aW9uVGltZVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgICBpZiAoYWxhcm1FeGlzdHMpIHtcbiAgICAgICAgICAgIGNvbnN0IGFsYXJtU2VyaWVzID0gYWxsRGF0YVNlcmllcy5maWx0ZXIoKHNlcmllczogQ3VzdG9tU2VyaWVzT3B0aW9ucykgPT4ge1xuICAgICAgICAgICAgICBjb25zdCBzZXJpZXNEYXRhID0gc2VyaWVzWydkYXRhJ10gYXMgU2VyaWVzVmFsdWVbXTtcbiAgICAgICAgICAgICAgcmV0dXJuIHNlcmllc0RhdGEuc29tZShcbiAgICAgICAgICAgICAgICAoZGF0YTogU2VyaWVzVmFsdWUpID0+IGRhdGFbMF0gPT09IChhbGFybU9yRXZlbnQgYXMgSUFsYXJtKS5jcmVhdGlvblRpbWVcbiAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgLy8gcmVtb3ZlIGFsbCBtYXRjaGluZyBhbGFybSBzZXJpZXMgd2hpY2ggYXJlIGluIHRoZSBhcnJheVxuICAgICAgICAgICAgYWxhcm1TZXJpZXMuZm9yRWFjaChzZXJpZXMgPT4ge1xuICAgICAgICAgICAgICBhbGxEYXRhU2VyaWVzID0gYWxsRGF0YVNlcmllcy5maWx0ZXIocyA9PiBzWydpZCddICE9PSBzZXJpZXNbJ2lkJ10pO1xuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIGNvbnN0IG5ld0FsYXJtU2VyaWVzID0gdGhpcy5lY2hhcnRzT3B0aW9uc1NlcnZpY2UuZ2V0QWxhcm1PckV2ZW50U2VyaWVzKFxuICAgICAgICAgICAgICBkcCxcbiAgICAgICAgICAgICAgcmVuZGVyVHlwZSxcbiAgICAgICAgICAgICAgZmFsc2UsXG4gICAgICAgICAgICAgIFthbGFybU9yRXZlbnRdLFxuICAgICAgICAgICAgICAnYWxhcm0nLFxuICAgICAgICAgICAgICBkaXNwbGF5T3B0aW9ucyxcbiAgICAgICAgICAgICAgKGFsYXJtT3JFdmVudCBhcyBJQWxhcm0pLmNyZWF0aW9uVGltZSxcbiAgICAgICAgICAgICAgbnVsbCxcbiAgICAgICAgICAgICAgdHJ1ZVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIGFsbERhdGFTZXJpZXMucHVzaCguLi5uZXdBbGFybVNlcmllcyk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGNvbnN0IG5ld0FsYXJtU2VyaWVzID0gdGhpcy5lY2hhcnRzT3B0aW9uc1NlcnZpY2UuZ2V0QWxhcm1PckV2ZW50U2VyaWVzKFxuICAgICAgICAgICAgICBkcCxcbiAgICAgICAgICAgICAgcmVuZGVyVHlwZSxcbiAgICAgICAgICAgICAgZmFsc2UsXG4gICAgICAgICAgICAgIFthbGFybU9yRXZlbnRdLFxuICAgICAgICAgICAgICAnYWxhcm0nLFxuICAgICAgICAgICAgICBkaXNwbGF5T3B0aW9ucyxcbiAgICAgICAgICAgICAgKGFsYXJtT3JFdmVudCBhcyBJRXZlbnQpLmlkLFxuICAgICAgICAgICAgICBudWxsLFxuICAgICAgICAgICAgICB0cnVlXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgYWxsRGF0YVNlcmllcy5wdXNoKC4uLm5ld0FsYXJtU2VyaWVzKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgdGhpcy5jaGVja0ZvclZhbHVlc0FmdGVyVGltZVJhbmdlKFxuICAgICAgICBzZXJpZXNNYXRjaGluZ0RhdGFwb2ludFsnZGF0YSddIGFzIFNlcmllc1ZhbHVlW10sXG4gICAgICAgIGRhdGFwb2ludCxcbiAgICAgICAgZGF0YXBvaW50T3V0T2ZTeW5jQ2FsbGJhY2tcbiAgICAgICk7XG4gICAgfSk7XG5cbiAgICB0aGlzLmVjaGFydHNJbnN0YW5jZT8uc2V0T3B0aW9uKHtcbiAgICAgIGRhdGFab29tOiBbXG4gICAgICAgIHtcbiAgICAgICAgICB0eXBlOiAnaW5zaWRlJyxcbiAgICAgICAgICBzdGFydFZhbHVlOiB0aGlzLmN1cnJlbnRUaW1lUmFuZ2U/LmRhdGVGcm9tLnZhbHVlT2YoKSxcbiAgICAgICAgICBlbmRWYWx1ZTogdGhpcy5jdXJyZW50VGltZVJhbmdlPy5kYXRlVG8udmFsdWVPZigpXG4gICAgICAgIH1cbiAgICAgIF0sXG4gICAgICB4QXhpczoge1xuICAgICAgICBtYXg6IHRoaXMuY3VycmVudFRpbWVSYW5nZT8uZGF0ZVRvXG4gICAgICB9LFxuICAgICAgc2VyaWVzOiBhbGxEYXRhU2VyaWVzXG4gICAgfSk7XG4gIH1cblxuICBwcml2YXRlIGNoZWNrRm9yVmFsdWVzQWZ0ZXJUaW1lUmFuZ2UoXG4gICAgZGF0YTogU2VyaWVzVmFsdWVbXSxcbiAgICBkYXRhcG9pbnQ6IERhdGFwb2ludHNHcmFwaEtQSURldGFpbHMsXG4gICAgZGF0YXBvaW50T3V0T2ZTeW5jQ2FsbGJhY2s6IChkcDogRGF0YXBvaW50c0dyYXBoS1BJRGV0YWlscykgPT4gdm9pZFxuICApIHtcbiAgICBjb25zdCBub3cgPSBuZXcgRGF0ZSgpO1xuICAgIGNvbnN0IHZhbHVlQWZ0ZXJOb3dFeGlzdHMgPSBkYXRhLnNvbWUoKFtkYXRlU3RyaW5nLCBfXTogU2VyaWVzVmFsdWUpID0+IHtcbiAgICAgIHJldHVybiBuZXcgRGF0ZShkYXRlU3RyaW5nKS52YWx1ZU9mKCkgPiBub3cudmFsdWVPZigpO1xuICAgIH0pO1xuICAgIGlmICh2YWx1ZUFmdGVyTm93RXhpc3RzKSB7XG4gICAgICBkYXRhcG9pbnRPdXRPZlN5bmNDYWxsYmFjayhkYXRhcG9pbnQpO1xuICAgIH1cbiAgfVxufVxuIl19