UNPKG

@ux-aspects/ux-aspects

Version:

Open source user interface framework for building modern, responsive, mobile big data applications

171 lines 36 kB
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, HostListener, inject, Output } from '@angular/core'; import { combineLatest, Subject } from 'rxjs'; import { filter, takeUntil } from 'rxjs/operators'; import { DateRangeOptions } from '../../date-range-picker/date-range-picker.directive'; import { DateRangePicker, DateRangeService } from '../../date-range-picker/date-range.service'; import { DateTimePickerService } from '../date-time-picker.service'; import { compareDays } from '../date-time-picker.utils'; import * as i0 from "@angular/core"; import * as i1 from "@angular/forms"; import * as i2 from "../../spin-button/spin-button.component"; import * as i3 from "../../time-picker/time-picker.component"; import * as i4 from "@angular/common"; export class TimeViewComponent { /** Determine if we are in range selection mode */ get _isRangeMode() { return !!this._rangeOptions; } /** Determine if this picker is the start picker */ get _isRangeStart() { return this._isRangeMode && this._rangeOptions.picker === DateRangePicker.Start; } /** Determine if this picker is the end picker */ get _isRangeEnd() { return this._isRangeMode && this._rangeOptions.picker === DateRangePicker.End; } get _rangeStart() { return this._isRangeMode && this._rangeService ? this._rangeService.start : null; } get _rangeEnd() { return this._isRangeMode && this._rangeService ? this._rangeService.end : null; } constructor() { this.datepicker = inject(DateTimePickerService); this._changeDetector = inject(ChangeDetectorRef); this._rangeService = inject(DateRangeService, { optional: true }); this._rangeOptions = inject(DateRangeOptions, { optional: true }); /** Earliest time permitted on the time picker. */ this.min = null; /** Latest time permitted on the time picker. */ this.max = null; /** Emit when the timezone changes. */ this.timezoneChange = new EventEmitter(); this._onDestroy = new Subject(); // when the date changes we should update the value this.datepicker.date$.pipe(filter(date => date && this.value instanceof Date), takeUntil(this._onDestroy)).subscribe(date => { this.value = new Date(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds()); this._changeDetector.detectChanges(); }); if (!this._isRangeMode) { this.datepicker.selected$.pipe(filter(date => !!date), takeUntil(this._onDestroy)) .subscribe(date => this.value = new Date(date)); } if (this._isRangeMode && this._isRangeStart) { this.value = new Date(); if (!this._rangeStart) { this.value.setHours(0, 0, 0, 0); } else { this.value.setHours(this._rangeStart.getHours(), this._rangeStart.getMinutes(), this._rangeStart.getSeconds()); } } if (this._isRangeMode && this._isRangeEnd) { this.value = new Date(); if (!this._rangeEnd) { this.value.setHours(23, 59, 59, 0); } else { this.value.setHours(this._rangeEnd.getHours(), this._rangeEnd.getMinutes(), this._rangeEnd.getSeconds()); } } } ngOnInit() { // min should only apply if it's on the same day as the selected date combineLatest(this.datepicker.min$, this.datepicker.date$).pipe(takeUntil(this._onDestroy)).subscribe(([min, date]) => { this.min = (min && date && compareDays(date, min)) ? min : null; this._changeDetector.detectChanges(); }); // max should only apply if it's on the same day as the selected date combineLatest(this.datepicker.max$, this.datepicker.date$).pipe(takeUntil(this._onDestroy)).subscribe(([max, date]) => { this.max = (max && date && compareDays(date, max)) ? max : null; this._changeDetector.detectChanges(); }); } ngOnDestroy() { this._onDestroy.next(); this._onDestroy.complete(); } onTimeChange(time) { if (this._isRangeMode) { this.datepicker.hours = time.getHours(); this.datepicker.minutes = time.getMinutes(); this.datepicker.seconds = time.getSeconds(); // update the time in the range picker service if (this._isRangeStart) { this._rangeService.startTime = { hours: time.getHours(), minutes: time.getMinutes(), seconds: time.getSeconds() }; } else { this._rangeService.endTime = { hours: time.getHours(), minutes: time.getMinutes(), seconds: time.getSeconds() }; } // if a date is currently selected we should update it if (this._isRangeStart && this._rangeStart) { const start = new Date(this._rangeStart); start.setHours(time.getHours(), time.getMinutes(), time.getSeconds()); this._rangeService.setStartDate(start); } if (this._isRangeEnd && this._rangeEnd) { const end = new Date(this._rangeEnd); end.setHours(time.getHours(), time.getMinutes(), time.getSeconds()); this._rangeService.setEndDate(end); } return; } // if the selected time is null then do nothing if (!this.datepicker.selected$.value) { return; } // otherwise set the time const date = new Date(this.datepicker.selected$.value); // update the time date.setHours(time.getHours(), time.getMinutes(), time.getSeconds()); // emit the time this.datepicker.selected$.next(date); } selectTimezone(name) { const timezones = this.datepicker.timezones$.value; // find matching timezone const timezone = timezones.find(_timezone => _timezone.name === name); if (timezone) { this.timezoneChange.emit(timezone); } } incrementTimezone() { const timezone = this.datepicker.timezone$.value; const timezones = this.datepicker.timezones$.value; const currentZone = timezones.findIndex(zone => zone.name === timezone.name && zone.offset === timezone.offset); // try to get the previous zone this.timezoneChange.emit(timezones[currentZone + 1] ? timezones[currentZone + 1] : timezones[currentZone]); } decrementTimezone() { const timezone = this.datepicker.timezone$.value; const timezones = this.datepicker.timezones$.value; const currentZone = timezones.findIndex(zone => zone.name === timezone.name && zone.offset === timezone.offset); // try to get the previous zone this.timezoneChange.emit(timezones[currentZone - 1] ? timezones[currentZone - 1] : timezones[currentZone]); } onFocusWithin() { if (this._isRangeMode) { this._rangeService.isChangingTime = true; } } onFocusOut() { if (this._isRangeMode) { this._rangeService.isChangingTime = false; } } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: TimeViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.12", type: TimeViewComponent, selector: "ux-date-time-picker-time-view", outputs: { timezoneChange: "timezoneChange" }, host: { listeners: { "focusin": "onFocusWithin()", "focusout": "onFocusOut()" } }, ngImport: i0, template: "@if (datepicker.showTime$ | async) {\n <ux-time-picker\n [value]=\"value\"\n (valueChange)=\"onTimeChange($event)\"\n [showSeconds]=\"datepicker.showSeconds$ | async\"\n [showMeridian]=\"datepicker.showMeridian$ | async\"\n [showSpinners]=\"datepicker.showSpinners$ | async\"\n [meridians]=\"datepicker.meridians\"\n [min]=\"min\"\n [max]=\"max\">\n </ux-time-picker>\n}\n\n@if (datepicker.showTimezone$ | async) {\n @if (datepicker.showSpinners$ | async) {\n <div class=\"time-zone-picker\">\n <ux-spin-button\n class=\"time-zone-spinner\"\n [value]=\"(datepicker.timezone$ | async)?.name\"\n [readOnly]=\"true\"\n (increment)=\"incrementTimezone()\"\n (decrement)=\"decrementTimezone()\"\n inputAriaLabel=\"Time Zone\"\n incrementAriaLabel=\"Switch to the next time zone\"\n decrementAriaLabel=\"Switch to the previous time zone\">\n </ux-spin-button>\n </div>\n }\n @if ((datepicker.showSpinners$ | async) === false) {\n <div class=\"time-zone-picker\">\n <select class=\"form-control time-zone-select\"\n tabindex=\"0\"\n [ngModel]=\"(datepicker.timezone$ | async)?.name\"\n (ngModelChange)=\"selectTimezone($event)\"\n aria-label=\"Timezone\"\n [attr.aria-valuetext]=\"(datepicker.timezone$ | async)?.name\">\n @for (zone of datepicker.timezones$ | async; track zone) {\n <option\n [selected]=\"zone.name === (datepicker.timezone$ | async)?.name\"\n [value]=\"zone.name\">\n {{ zone?.name }}\n </option>\n }\n </select>\n </div>\n }\n}\n", dependencies: [{ kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i2.SpinButtonComponent, selector: "ux-spin-button", inputs: ["value", "type", "min", "max", "placeholder", "disabled", "spinners", "readOnly", "scrolling", "arrowkeys", "maxLength", "incrementAriaLabel", "inputAriaLabel", "decrementAriaLabel"], outputs: ["valueChange", "increment", "decrement"] }, { kind: "component", type: i3.TimePickerComponent, selector: "ux-time-picker", inputs: ["arrowkeys", "mousewheel", "disabled", "readOnly", "showMeridian", "showHours", "showMinutes", "showSeconds", "showSpinners", "hourStep", "minuteStep", "secondStep", "min", "max", "meridians", "value"], outputs: ["valueChange", "isValid"] }, { kind: "pipe", type: i4.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: TimeViewComponent, decorators: [{ type: Component, args: [{ selector: 'ux-date-time-picker-time-view', changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (datepicker.showTime$ | async) {\n <ux-time-picker\n [value]=\"value\"\n (valueChange)=\"onTimeChange($event)\"\n [showSeconds]=\"datepicker.showSeconds$ | async\"\n [showMeridian]=\"datepicker.showMeridian$ | async\"\n [showSpinners]=\"datepicker.showSpinners$ | async\"\n [meridians]=\"datepicker.meridians\"\n [min]=\"min\"\n [max]=\"max\">\n </ux-time-picker>\n}\n\n@if (datepicker.showTimezone$ | async) {\n @if (datepicker.showSpinners$ | async) {\n <div class=\"time-zone-picker\">\n <ux-spin-button\n class=\"time-zone-spinner\"\n [value]=\"(datepicker.timezone$ | async)?.name\"\n [readOnly]=\"true\"\n (increment)=\"incrementTimezone()\"\n (decrement)=\"decrementTimezone()\"\n inputAriaLabel=\"Time Zone\"\n incrementAriaLabel=\"Switch to the next time zone\"\n decrementAriaLabel=\"Switch to the previous time zone\">\n </ux-spin-button>\n </div>\n }\n @if ((datepicker.showSpinners$ | async) === false) {\n <div class=\"time-zone-picker\">\n <select class=\"form-control time-zone-select\"\n tabindex=\"0\"\n [ngModel]=\"(datepicker.timezone$ | async)?.name\"\n (ngModelChange)=\"selectTimezone($event)\"\n aria-label=\"Timezone\"\n [attr.aria-valuetext]=\"(datepicker.timezone$ | async)?.name\">\n @for (zone of datepicker.timezones$ | async; track zone) {\n <option\n [selected]=\"zone.name === (datepicker.timezone$ | async)?.name\"\n [value]=\"zone.name\">\n {{ zone?.name }}\n </option>\n }\n </select>\n </div>\n }\n}\n" }] }], ctorParameters: () => [], propDecorators: { timezoneChange: [{ type: Output }], onFocusWithin: [{ type: HostListener, args: ['focusin'] }], onFocusOut: [{ type: HostListener, args: ['focusout'] }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGltZS12aWV3LmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9jb21wb25lbnRzL2RhdGUtdGltZS1waWNrZXIvdGltZS12aWV3L3RpbWUtdmlldy5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvY29tcG9uZW50cy9kYXRlLXRpbWUtcGlja2VyL3RpbWUtdmlldy90aW1lLXZpZXcuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLHVCQUF1QixFQUFFLGlCQUFpQixFQUFFLFNBQVMsRUFBRSxZQUFZLEVBQUUsWUFBWSxFQUFFLE1BQU0sRUFBcUIsTUFBTSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ3JKLE9BQU8sRUFBRSxhQUFhLEVBQUUsT0FBTyxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQzlDLE9BQU8sRUFBRSxNQUFNLEVBQUUsU0FBUyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDbkQsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0scURBQXFELENBQUM7QUFDdkYsT0FBTyxFQUFFLGVBQWUsRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLDRDQUE0QyxDQUFDO0FBQy9GLE9BQU8sRUFBRSxxQkFBcUIsRUFBRSxNQUFNLDZCQUE2QixDQUFDO0FBQ3BFLE9BQU8sRUFBRSxXQUFXLEVBQTBCLE1BQU0sMkJBQTJCLENBQUM7Ozs7OztBQU9oRixNQUFNLE9BQU8saUJBQWlCO0lBa0IxQixrREFBa0Q7SUFDbEQsSUFBSSxZQUFZO1FBQ1osT0FBTyxDQUFDLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQztJQUNoQyxDQUFDO0lBRUQsbURBQW1EO0lBQ25ELElBQUksYUFBYTtRQUNiLE9BQU8sSUFBSSxDQUFDLFlBQVksSUFBSSxJQUFJLENBQUMsYUFBYSxDQUFDLE1BQU0sS0FBSyxlQUFlLENBQUMsS0FBSyxDQUFDO0lBQ3BGLENBQUM7SUFFRCxp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QUNMLENBQUM7K0dBNUxRLGlCQUFpQjttR0FBakIsaUJBQWlCLHVNQ2I5Qiw4bkRBK0NBOzs0RkRsQ2EsaUJBQWlCO2tCQUw3QixTQUFTOytCQUNJLCtCQUErQixtQkFFeEIsdUJBQXVCLENBQUMsTUFBTTt3REE0Q3JDLGNBQWM7c0JBQXZCLE1BQU07Z0JBdUlQLGFBQWE7c0JBRFosWUFBWTt1QkFBQyxTQUFTO2dCQVF2QixVQUFVO3NCQURULFlBQVk7dUJBQUMsVUFBVSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENoYW5nZURldGVjdGlvblN0cmF0ZWd5LCBDaGFuZ2VEZXRlY3RvclJlZiwgQ29tcG9uZW50LCBFdmVudEVtaXR0ZXIsIEhvc3RMaXN0ZW5lciwgaW5qZWN0LCBPbkRlc3Ryb3ksIE9uSW5pdCwgT3V0cHV0IH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBjb21iaW5lTGF0ZXN0LCBTdWJqZWN0IH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyBmaWx0ZXIsIHRha2VVbnRpbCB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcbmltcG9ydCB7IERhdGVSYW5nZU9wdGlvbnMgfSBmcm9tICcuLi8uLi9kYXRlLXJhbmdlLXBpY2tlci9kYXRlLXJhbmdlLXBpY2tlci5kaXJlY3RpdmUnO1xuaW1wb3J0IHsgRGF0ZVJhbmdlUGlja2VyLCBEYXRlUmFuZ2VTZXJ2aWNlIH0gZnJvbSAnLi4vLi4vZGF0ZS1yYW5nZS1waWNrZXIvZGF0ZS1yYW5nZS5zZXJ2aWNlJztcbmltcG9ydCB7IERhdGVUaW1lUGlja2VyU2VydmljZSB9IGZyb20gJy4uL2RhdGUtdGltZS1waWNrZXIuc2VydmljZSc7XG5pbXBvcnQgeyBjb21wYXJlRGF5cywgRGF0ZVRpbWVQaWNrZXJUaW1lem9uZSB9IGZyb20gJy4uL2RhdGUtdGltZS1waWNrZXIudXRpbHMnO1xuXG5AQ29tcG9uZW50KHtcbiAgICBzZWxlY3RvcjogJ3V4LWRhdGUtdGltZS1waWNrZXItdGltZS12aWV3JyxcbiAgICB0ZW1wbGF0ZVVybDogJy4vdGltZS12aWV3LmNvbXBvbmVudC5odG1sJyxcbiAgICBjaGFuZ2VEZXRlY3Rpb246IENoYW5nZURldGVjdGlvblN0cmF0ZWd5Lk9uUHVzaFxufSlcbmV4cG9ydCBjbGFzcyBUaW1lVmlld0NvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCwgT25EZXN0cm95IHtcbiAgICByZWFkb25seSBkYXRlcGlja2VyID0gaW5qZWN0KERhdGVUaW1lUGlja2VyU2VydmljZSk7XG5cbiAgICBwcml2YXRlIHJlYWRvbmx5IF9jaGFuZ2VEZXRlY3RvciA9IGluamVjdChDaGFuZ2VEZXRlY3RvclJlZik7XG5cbiAgICBwcml2YXRlIHJlYWRvbmx5IF9yYW5nZVNlcnZpY2UgPSBpbmplY3QoRGF0ZVJhbmdlU2VydmljZSwgeyBvcHRpb25hbDogdHJ1ZSB9KTtcblxuICAgIHByaXZhdGUgcmVhZG9ubHkgX3JhbmdlT3B0aW9ucyA9IGluamVjdChEYXRlUmFuZ2VPcHRpb25zLCB7IG9wdGlvbmFsOiB0cnVlIH0pO1xuXG4gICAgLyoqIERvbnQgYmluZCBkaXJlY3RseSB0byB0aGUgc2VsZWN0ZWQgZGF0ZSBhcyBpZiBpdCdzIG51bGwgd2UgY2FuIGVuZCB1cCBpbiAxOTcwISAqL1xuICAgIHZhbHVlOiBEYXRlO1xuXG4gICAgLyoqIEVhcmxpZXN0IHRpbWUgcGVybWl0dGVkIG9uIHRoZSB0aW1lIHBpY2tlci4gKi9cbiAgICBtaW46IERhdGUgPSBudWxsO1xuXG4gICAgLyoqIExhdGVzdCB0aW1lIHBlcm1pdHRlZCBvbiB0aGUgdGltZSBwaWNrZXIuICovXG4gICAgbWF4OiBEYXRlID0gbnVsbDtcblxuICAgIC8qKiBEZXRlcm1pbmUgaWYgd2UgYXJlIGluIHJhbmdlIHNlbGVjdGlvbiBtb2RlICovXG4gICAgZ2V0IF9pc1JhbmdlTW9kZSgpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuICEhdGhpcy5fcmFuZ2VPcHRpb25zO1xuICAgIH1cblxuICAgIC8qKiBEZXRlcm1pbmUgaWYgdGhpcyBwaWNrZXIgaXMgdGhlIHN0YXJ0IHBpY2tlciAqL1xuICAgIGdldCBfaXNSYW5nZVN0YXJ0KCk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gdGhpcy5faXNSYW5nZU1vZGUgJiYgdGhpcy5fcmFuZ2VPcHRpb25zLnBpY2tlciA9PT0gRGF0ZVJhbmdlUGlja2VyLlN0YXJ0O1xuICAgIH1cblxuICAgIC8qKiBEZXRlcm1pbmUgaWYgdGhpcyBwaWNrZXIgaXMgdGhlIGVuZCBwaWNrZXIgKi9cbiAgICBnZXQgX2lzUmFuZ2VFbmQoKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiB0aGlzLl9pc1JhbmdlTW9kZSAmJiB0aGlzLl9yYW5nZU9wdGlvbnMucGlja2VyID09PSBEYXRlUmFuZ2VQaWNrZXIuRW5kO1xuICAgIH1cblxuICAgIGdldCBfcmFuZ2VTdGFydCgpOiBEYXRlIHwgbnVsbCB7XG4gICAgICAgIHJldHVybiB0aGlzLl9pc1JhbmdlTW9kZSAmJiB0aGlzLl9yYW5nZVNlcnZpY2UgPyB0aGlzLl9yYW5nZVNlcnZpY2Uuc3RhcnQgOiBudWxsO1xuICAgIH1cblxuICAgIGdldCBfcmFuZ2VFbmQoKTogRGF0ZSB8IG51bGwge1xuICAgICAgICByZXR1cm4gdGhpcy5faXNSYW5nZU1vZGUgJiYgdGhpcy5fcmFuZ2VTZXJ2aWNlID8gdGhpcy5fcmFuZ2VTZXJ2aWNlLmVuZCA6IG51bGw7XG4gICAgfVxuXG4gICAgLyoqIEVtaXQgd2hlbiB0aGUgdGltZXpvbmUgY2hhbmdlcy4gKi9cbiAgICBAT3V0cHV0KCkgdGltZXpvbmVDaGFuZ2U6IEV2ZW50RW1pdHRlcjxEYXRlVGltZVBpY2tlclRpbWV6b25lPiA9IG5ldyBFdmVudEVtaXR0ZXI8RGF0ZVRpbWVQaWNrZXJUaW1lem9uZT4oKTtcblxuICAgIHByaXZhdGUgcmVhZG9ubHkgX29uRGVzdHJveSA9IG5ldyBTdWJqZWN0PHZvaWQ+KCk7XG5cbiAgICBjb25zdHJ1Y3RvcigpIHtcblxuICAgICAgICAvLyB3aGVuIHRoZSBkYXRlIGNoYW5nZXMgd2Ugc2hvdWxkIHVwZGF0ZSB0aGUgdmFsdWVcbiAgICAgICAgdGhpcy5kYXRlcGlja2VyLmRhdGUkLnBpcGUoZmlsdGVyKGRhdGUgPT4gZGF0ZSAmJiB0aGlzLnZhbHVlIGluc3RhbmNlb2YgRGF0ZSksIHRha2VVbnRpbCh0aGlzLl9vbkRlc3Ryb3kpKS5zdWJzY3JpYmUoZGF0ZSA9PiB7XG5cbiAgICAgICAgICAgIHRoaXMudmFsdWUgPSBuZXcgRGF0ZShkYXRlLmdldEZ1bGxZZWFyKCksIGRhdGUuZ2V0TW9udGgoKSwgZGF0ZS5nZXREYXRlKCksIGRhdGUuZ2V0SG91cnMoKSwgZGF0ZS5nZXRNaW51dGVzKCksIGRhdGUuZ2V0U2Vjb25kcygpKTtcblxuICAgICAgICAgICAgdGhpcy5fY2hhbmdlRGV0ZWN0b3IuZGV0ZWN0Q2hhbmdlcygpO1xuICAgICAgICB9KTtcblxuICAgICAgICBpZiAoIXRoaXMuX2lzUmFuZ2VNb2RlKSB7XG4gICAgICAgICAgICB0aGlzLmRhdGVwaWNrZXIuc2VsZWN0ZWQkLnBpcGUoZmlsdGVyKGRhdGUgPT4gISFkYXRlKSwgdGFrZVVudGlsKHRoaXMuX29uRGVzdHJveSkpXG4gICAgICAgICAgICAgICAgLnN1YnNjcmliZShkYXRlID0+IHRoaXMudmFsdWUgPSBuZXcgRGF0ZShkYXRlKSk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodGhpcy5faXNSYW5nZU1vZGUgJiYgdGhpcy5faXNSYW5nZVN0YXJ0KSB7XG4gICAgICAgICAgICB0aGlzLnZhbHVlID0gbmV3IERhdGUoKTtcbiAgICAgICAgICAgIGlmICghdGhpcy5fcmFuZ2VTdGFydCkge1xuICAgICAgICAgICAgICAgIHRoaXMudmFsdWUuc2V0SG91cnMoMCwgMCwgMCwgMCk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHRoaXMudmFsdWUuc2V0SG91cnModGhpcy5fcmFuZ2VTdGFydC5nZXRIb3VycygpLCB0aGlzLl9yYW5nZVN0YXJ0LmdldE1pbnV0ZXMoKSwgdGhpcy5fcmFuZ2VTdGFydC5nZXRTZWNvbmRzKCkpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHRoaXMuX2lzUmFuZ2VNb2RlICYmIHRoaXMuX2lzUmFuZ2VFbmQpIHtcbiAgICAgICAgICAgIHRoaXMudmFsdWUgPSBuZXcgRGF0ZSgpO1xuICAgICAgICAgICAgaWYgKCF0aGlzLl9yYW5nZUVuZCkge1xuICAgICAgICAgICAgICAgIHRoaXMudmFsdWUuc2V0SG91cnMoMjMsIDU5LCA1OSwgMCk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHRoaXMudmFsdWUuc2V0SG91cnModGhpcy5fcmFuZ2VFbmQuZ2V0SG91cnMoKSwgdGhpcy5fcmFuZ2VFbmQuZ2V0TWludXRlcygpLCB0aGlzLl9yYW5nZUVuZC5nZXRTZWNvbmRzKCkpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgbmdPbkluaXQoKTogdm9pZCB7XG5cbiAgICAgICAgLy8gbWluIHNob3VsZCBvbmx5IGFwcGx5IGlmIGl0J3Mgb24gdGhlIHNhbWUgZGF5IGFzIHRoZSBzZWxlY3RlZCBkYXRlXG4gICAgICAgIGNvbWJpbmVMYXRlc3QodGhpcy5kYXRlcGlja2VyLm1pbiQsIHRoaXMuZGF0ZXBpY2tlci5kYXRlJCkucGlwZSh0YWtlVW50aWwodGhpcy5fb25EZXN0cm95KSkuc3Vic2NyaWJlKChbbWluLCBkYXRlXSkgPT4ge1xuICAgICAgICAgICAgdGhpcy5taW4gPSAobWluICYmIGRhdGUgJiYgY29tcGFyZURheXMoZGF0ZSwgbWluKSkgPyBtaW4gOiBudWxsO1xuICAgICAgICAgICAgdGhpcy5fY2hhbmdlRGV0ZWN0b3IuZGV0ZWN0Q2hhbmdlcygpO1xuICAgICAgICB9KTtcblxuICAgICAgICAvLyBtYXggc2hvdWxkIG9ubHkgYXBwbHkgaWYgaXQncyBvbiB0aGUgc2FtZSBkYXkgYXMgdGhlIHNlbGVjdGVkIGRhdGVcbiAgICAgICAgY29tYmluZUxhdGVzdCh0aGlzLmRhdGVwaWNrZXIubWF4JCwgdGhpcy5kYXRlcGlja2VyLmRhdGUkKS5waXBlKHRha2VVbnRpbCh0aGlzLl9vbkRlc3Ryb3kpKS5zdWJzY3JpYmUoKFttYXgsIGRhdGVdKSA9PiB7XG4gICAgICAgICAgICB0aGlzLm1heCA9IChtYXggJiYgZGF0ZSAmJiBjb21wYXJlRGF5cyhkYXRlLCBtYXgpKSA/IG1heCA6IG51bGw7XG4gICAgICAgICAgICB0aGlzLl9jaGFuZ2VEZXRlY3Rvci5kZXRlY3RDaGFuZ2VzKCk7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIG5nT25EZXN0cm95KCk6IHZvaWQge1xuICAgICAgICB0aGlzLl9vbkRlc3Ryb3kubmV4dCgpO1xuICAgICAgICB0aGlzLl9vbkRlc3Ryb3kuY29tcGxldGUoKTtcbiAgICB9XG5cbiAgICBvblRpbWVDaGFuZ2UodGltZTogRGF0ZSk6IHZvaWQge1xuXG4gICAgICAgIGlmICh0aGlzLl9pc1JhbmdlTW9kZSkge1xuICAgICAgICAgICAgdGhpcy5kYXRlcGlja2VyLmhvdXJzID0gdGltZS5nZXRIb3VycygpO1xuICAgICAgICAgICAgdGhpcy5kYXRlcGlja2VyLm1pbnV0ZXMgPSB0aW1lLmdldE1pbnV0ZXMoKTtcbiAgICAgICAgICAgIHRoaXMuZGF0ZXBpY2tlci5zZWNvbmRzID0gdGltZS5nZXRTZWNvbmRzKCk7XG5cbiAgICAgICAgICAgIC8vIHVwZGF0ZSB0aGUgdGltZSBpbiB0aGUgcmFuZ2UgcGlja2VyIHNlcnZpY2VcbiAgICAgICAgICAgIGlmICh0aGlzLl9pc1JhbmdlU3RhcnQpIHtcbiAgICAgICAgICAgICAgICB0aGlzLl9yYW5nZVNlcnZpY2Uuc3RhcnRUaW1lID0geyBob3VyczogdGltZS5nZXRIb3VycygpLCBtaW51dGVzOiB0aW1lLmdldE1pbnV0ZXMoKSwgc2Vjb25kczogdGltZS5nZXRTZWNvbmRzKCkgfTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgdGhpcy5fcmFuZ2VTZXJ2aWNlLmVuZFRpbWUgPSB7IGhvdXJzOiB0aW1lLmdldEhvdXJzKCksIG1pbnV0ZXM6IHRpbWUuZ2V0TWludXRlcygpLCBzZWNvbmRzOiB0aW1lLmdldFNlY29uZHMoKSB9O1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBpZiBhIGRhdGUgaXMgY3VycmVudGx5IHNlbGVjdGVkIHdlIHNob3VsZCB1cGRhdGUgaXRcbiAgICAgICAgICAgIGlmICh0aGlzLl9pc1JhbmdlU3RhcnQgJiYgdGhpcy5fcmFuZ2VTdGFydCkge1xuICAgICAgICAgICAgICAgIGNvbnN0IHN0YXJ0ID0gbmV3IERhdGUodGhpcy5fcmFuZ2VTdGFydCk7XG4gICAgICAgICAgICAgICAgc3RhcnQuc2V0SG91cnModGltZS5nZXRIb3VycygpLCB0aW1lLmdldE1pbnV0ZXMoKSwgdGltZS5nZXRTZWNvbmRzKCkpO1xuICAgICAgICAgICAgICAgIHRoaXMuX3JhbmdlU2VydmljZS5zZXRTdGFydERhdGUoc3RhcnQpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAodGhpcy5faXNSYW5nZUVuZCAmJiB0aGlzLl9yYW5nZUVuZCkge1xuICAgICAgICAgICAgICAgIGNvbnN0IGVuZCA9IG5ldyBEYXRlKHRoaXMuX3JhbmdlRW5kKTtcbiAgICAgICAgICAgICAgICBlbmQuc2V0SG91cnModGltZS5nZXRIb3VycygpLCB0aW1lLmdldE1pbnV0ZXMoKSwgdGltZS5nZXRTZWNvbmRzKCkpO1xuICAgICAgICAgICAgICAgIHRoaXMuX3JhbmdlU2VydmljZS5zZXRFbmREYXRlKGVuZCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIGlmIHRoZSBzZWxlY3RlZCB0aW1lIGlzIG51bGwgdGhlbiBkbyBub3RoaW5nXG4gICAgICAgIGlmICghdGhpcy5kYXRlcGlja2VyLnNlbGVjdGVkJC52YWx1ZSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gb3RoZXJ3aXNlIHNldCB0aGUgdGltZVxuICAgICAgICBjb25zdCBkYXRlID0gbmV3IERhdGUodGhpcy5kYXRlcGlja2VyLnNlbGVjdGVkJC52YWx1ZSk7XG5cbiAgICAgICAgLy8gdXBkYXRlIHRoZSB0aW1lXG4gICAgICAgIGRhdGUuc2V0SG91cnModGltZS5nZXRIb3VycygpLCB0aW1lLmdldE1pbnV0ZXMoKSwgdGltZS5nZXRTZWNvbmRzKCkpO1xuXG4gICAgICAgIC8vIGVtaXQgdGhlIHRpbWVcbiAgICAgICAgdGhpcy5kYXRlcGlja2VyLnNlbGVjdGVkJC5uZXh0KGRhdGUpO1xuICAgIH1cblxuICAgIHNlbGVjdFRpbWV6b25lKG5hbWU6IHN0cmluZyk6IHZvaWQge1xuICAgICAgICBjb25zdCB0aW1lem9uZXMgPSB0aGlzLmRhdGVwaWNrZXIudGltZXpvbmVzJC52YWx1ZTtcblxuICAgICAgICAvLyBmaW5kIG1hdGNoaW5nIHRpbWV6b25lXG4gICAgICAgIGNvbnN0IHRpbWV6b25lID0gdGltZXpvbmVzLmZpbmQoX3RpbWV6b25lID0+IF90aW1lem9uZS5uYW1lID09PSBuYW1lKTtcblxuICAgICAgICBpZiAodGltZXpvbmUpIHtcbiAgICAgICAgICAgIHRoaXMudGltZXpvbmVDaGFuZ2UuZW1pdCh0aW1lem9uZSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBpbmNyZW1lbnRUaW1lem9uZSgpOiB2b2lkIHtcbiAgICAgICAgY29uc3QgdGltZXpvbmUgPSB0aGlzLmRhdGVwaWNrZXIudGltZXpvbmUkLnZhbHVlO1xuICAgICAgICBjb25zdCB0aW1lem9uZXMgPSB0aGlzLmRhdGVwaWNrZXIudGltZXpvbmVzJC52YWx1ZTtcblxuICAgICAgICBjb25zdCBjdXJyZW50Wm9uZSA9IHRpbWV6b25lcy5maW5kSW5kZXgoem9uZSA9PiB6b25lLm5hbWUgPT09IHRpbWV6b25lLm5hbWUgJiYgem9uZS5vZmZzZXQgPT09IHRpbWV6b25lLm9mZnNldCk7XG5cbiAgICAgICAgLy8gdHJ5IHRvIGdldCB0aGUgcHJldmlvdXMgem9uZVxuICAgICAgICB0aGlzLnRpbWV6b25lQ2hhbmdlLmVtaXQodGltZXpvbmVzW2N1cnJlbnRab25lICsgMV0gPyB0aW1lem9uZXNbY3VycmVudFpvbmUgKyAxXSA6IHRpbWV6b25lc1tjdXJyZW50Wm9uZV0pO1xuICAgIH1cblxuICAgIGRlY3JlbWVudFRpbWV6b25lKCk6IHZvaWQge1xuICAgICAgICBjb25zdCB0aW1lem9uZSA9IHRoaXMuZGF0ZXBpY2tlci50aW1lem9uZSQudmFsdWU7XG4gICAgICAgIGNvbnN0IHRpbWV6b25lcyA9IHRoaXMuZGF0ZXBpY2tlci50aW1lem9uZXMkLnZhbHVlO1xuXG4gICAgICAgIGNvbnN0IGN1cnJlbnRab25lID0gdGltZXpvbmVzLmZpbmRJbmRleCh6b25lID0+IHpvbmUubmFtZSA9PT0gdGltZXpvbmUubmFtZSAmJiB6b25lLm9mZnNldCA9PT0gdGltZXpvbmUub2Zmc2V0KTtcblxuICAgICAgICAvLyB0cnkgdG8gZ2V0IHRoZSBwcmV2aW91cyB6b25lXG4gICAgICAgIHRoaXMudGltZXpvbmVDaGFuZ2UuZW1pdCh0aW1lem9uZXNbY3VycmVudFpvbmUgLSAxXSA/IHRpbWV6b25lc1tjdXJyZW50Wm9uZSAtIDFdIDogdGltZXpvbmVzW2N1cnJlbnRab25lXSk7XG4gICAgfVxuXG4gICAgQEhvc3RMaXN0ZW5lcignZm9jdXNpbicpXG4gICAgb25Gb2N1c1dpdGhpbigpOiB2b2lkIHtcbiAgICAgICAgaWYgKHRoaXMuX2lzUmFuZ2VNb2RlKSB7XG4gICAgICAgICAgICB0aGlzLl9yYW5nZVNlcnZpY2UuaXNDaGFuZ2luZ1RpbWUgPSB0cnVlO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgQEhvc3RMaXN0ZW5lcignZm9jdXNvdXQnKVxuICAgIG9uRm9jdXNPdXQoKTogdm9pZCB7XG4gICAgICAgIGlmICh0aGlzLl9pc1JhbmdlTW9kZSkge1xuICAgICAgICAgICAgdGhpcy5fcmFuZ2VTZXJ2aWNlLmlzQ2hhbmdpbmdUaW1lID0gZmFsc2U7XG4gICAgICAgIH1cbiAgICB9XG59XG4iLCJAaWYgKGRhdGVwaWNrZXIuc2hvd1RpbWUkIHwgYXN5bmMpIHtcbiAgPHV4LXRpbWUtcGlja2VyXG4gICAgW3ZhbHVlXT1cInZhbHVlXCJcbiAgICAodmFsdWVDaGFuZ2UpPVwib25UaW1lQ2hhbmdlKCRldmVudClcIlxuICAgIFtzaG93U2Vjb25kc109XCJkYXRlcGlja2VyLnNob3dTZWNvbmRzJCB8IGFzeW5jXCJcbiAgICBbc2hvd01lcmlkaWFuXT1cImRhdGVwaWNrZXIuc2hvd01lcmlkaWFuJCB8IGFzeW5jXCJcbiAgICBbc2hvd1NwaW5uZXJzXT1cImRhdGVwaWNrZXIuc2hvd1NwaW5uZXJzJCB8IGFzeW5jXCJcbiAgICBbbWVyaWRpYW5zXT1cImRhdGVwaWNrZXIubWVyaWRpYW5zXCJcbiAgICBbbWluXT1cIm1pblwiXG4gICAgW21heF09XCJtYXhcIj5cbiAgPC91eC10aW1lLXBpY2tlcj5cbn1cblxuQGlmIChkYXRlcGlja2VyLnNob3dUaW1lem9uZSQgfCBhc3luYykge1xuICBAaWYgKGRhdGVwaWNrZXIuc2hvd1NwaW5uZXJzJCB8IGFzeW5jKSB7XG4gICAgPGRpdiBjbGFzcz1cInRpbWUtem9uZS1waWNrZXJcIj5cbiAgICAgIDx1eC1zcGluLWJ1dHRvblxuICAgICAgICBjbGFzcz1cInRpbWUtem9uZS1zcGlubmVyXCJcbiAgICAgICAgW3ZhbHVlXT1cIihkYXRlcGlja2VyLnRpbWV6b25lJCB8IGFzeW5jKT8ubmFtZVwiXG4gICAgICAgIFtyZWFkT25seV09XCJ0cnVlXCJcbiAgICAgICAgKGluY3JlbWVudCk9XCJpbmNyZW1lbnRUaW1lem9uZSgpXCJcbiAgICAgICAgKGRlY3JlbWVudCk9XCJkZWNyZW1lbnRUaW1lem9uZSgpXCJcbiAgICAgICAgaW5wdXRBcmlhTGFiZWw9XCJUaW1lIFpvbmVcIlxuICAgICAgICBpbmNyZW1lbnRBcmlhTGFiZWw9XCJTd2l0Y2ggdG8gdGhlIG5leHQgdGltZSB6b25lXCJcbiAgICAgICAgZGVjcmVtZW50QXJpYUxhYmVsPVwiU3dpdGNoIHRvIHRoZSBwcmV2aW91cyB0aW1lIHpvbmVcIj5cbiAgICAgIDwvdXgtc3Bpbi1idXR0b24+XG4gICAgPC9kaXY+XG4gIH1cbiAgQGlmICgoZGF0ZXBpY2tlci5zaG93U3Bpbm5lcnMkIHwgYXN5bmMpID09PSBmYWxzZSkge1xuICAgIDxkaXYgY2xhc3M9XCJ0aW1lLXpvbmUtcGlja2VyXCI+XG4gICAgICA8c2VsZWN0IGNsYXNzPVwiZm9ybS1jb250cm9sIHRpbWUtem9uZS1zZWxlY3RcIlxuICAgICAgICB0YWJpbmRleD1cIjBcIlxuICAgICAgICBbbmdNb2RlbF09XCIoZGF0ZXBpY2tlci50aW1lem9uZSQgfCBhc3luYyk/Lm5hbWVcIlxuICAgICAgICAobmdNb2RlbENoYW5nZSk9XCJzZWxlY3RUaW1lem9uZSgkZXZlbnQpXCJcbiAgICAgICAgYXJpYS1sYWJlbD1cIlRpbWV6b25lXCJcbiAgICAgICAgW2F0dHIuYXJpYS12YWx1ZXRleHRdPVwiKGRhdGVwaWNrZXIudGltZXpvbmUkIHwgYXN5bmMpPy5uYW1lXCI+XG4gICAgICAgIEBmb3IgKHpvbmUgb2YgZGF0ZXBpY2tlci50aW1lem9uZXMkIHwgYXN5bmM7IHRyYWNrIHpvbmUpIHtcbiAgICAgICAgICA8b3B0aW9uXG4gICAgICAgICAgICBbc2VsZWN0ZWRdPVwiem9uZS5uYW1lID09PSAoZGF0ZXBpY2tlci50aW1lem9uZSQgfCBhc3luYyk/Lm5hbWVcIlxuICAgICAgICAgICAgW3ZhbHVlXT1cInpvbmUubmFtZVwiPlxuICAgICAgICAgICAge3sgem9uZT8ubmFtZSB9fVxuICAgICAgICAgIDwvb3B0aW9uPlxuICAgICAgICB9XG4gICAgICA8L3NlbGVjdD5cbiAgICA8L2Rpdj5cbiAgfVxufVxuIl19