@ux-aspects/ux-aspects
Version:
Open source user interface framework for building modern, responsive, mobile big data applications
289 lines • 41.5 kB
JavaScript
import { ChangeDetectionStrategy, Component, EventEmitter, inject, Input, Output, } from '@angular/core';
import { Subject } from 'rxjs';
import { distinctUntilChanged, 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 { DatePickerMode, DateTimePickerService } from './date-time-picker.service';
import { dateComparator, isDateAfter, isDateBefore, timezoneComparator, } from './date-time-picker.utils';
import * as i0 from "@angular/core";
import * as i1 from "../../directives/accessibility/focus-indicator/focus-indicator.directive";
import * as i2 from "./header/header.component";
import * as i3 from "./day-view/day-view.component";
import * as i4 from "./month-view/month-view.component";
import * as i5 from "./year-view/year-view.component";
import * as i6 from "./time-view/time-view.component";
import * as i7 from "@angular/common";
export class DateTimePickerComponent {
/** Defines whether or not the date picker should be visible. */
set showDate(value) {
if (value !== undefined) {
this.datepicker.showDate$.next(value);
}
}
/** Defines whether or not the time picker should be visible. */
set showTime(value) {
if (value !== undefined) {
this.datepicker.showTime$.next(value);
}
}
/** Defines whether or not the time picker should allow the user to choose a timezone. */
set showTimezone(value) {
if (value !== undefined) {
this.datepicker.showTimezone$.next(value);
}
}
/** Defines whether or not the time picker should allow the user to specify seconds. */
set showSeconds(value) {
if (value !== undefined) {
this.datepicker.showSeconds$.next(value);
}
}
/** Defines whether or not the time picker should show an AM/PM button, or time should be represented in 24hr format instead. */
set showMeridian(value) {
if (value !== undefined) {
this.datepicker.showMeridian$.next(value);
}
}
/** Defines whether or not the time picker should allow the user to select the time using spinners. */
set showSpinners(value) {
if (value !== undefined) {
this.datepicker.showSpinners$.next(value);
}
}
/** If defined will override the weekday names displayed. */
set weekdays(value) {
if (value !== undefined) {
this.datepicker.weekdays$.next(value);
}
}
/** Defines the names of the months. */
set months(months) {
if (months !== undefined) {
this.datepicker.months = months;
}
}
/** Defines the short names of each month. */
set monthsShort(months) {
if (months !== undefined) {
this.datepicker.monthsShort = months;
}
}
/** Defines the labels to show in the meridian (AM/PM) selector. */
set meridians(meridians) {
if (meridians !== undefined) {
this.datepicker.meridians = meridians;
}
}
/** Defines the text to be displayed in the button used to set the selected time to the current time. */
set nowBtnText(value) {
if (value !== undefined) {
this.datepicker.nowBtnText$.next(value);
}
}
/** Specify whether or not to show the show now button */
set showNowBtn(value) {
if (value !== undefined) {
this.datepicker.showNowBtn$.next(value);
}
}
/**
* Defines the list of available timezones. The `DateTimePickerTimezone` interface specifies that each timezone should
* be an object with a `name` property that represents the timezone, eg. `GMT+2`, and an `offset` property that represents
* the number of minutes relative to GMT the timezone is.
*/
set timezones(value) {
if (value !== undefined) {
this.datepicker.timezones$.next(value);
}
}
/** Defines the day of the week that should appear in the first column. `WeekDay` is an enumeration available in `@angular/common`. */
set startOfWeek(startOfWeek) {
if (startOfWeek !== undefined) {
this.datepicker.startOfWeek$.next(startOfWeek);
}
}
/** The selected date to be displayed in the component. */
set date(value) {
if (value && !dateComparator(value, this.datepicker.date$.value)) {
if (this._isRangeMode) {
this.datepicker.date$.next(new Date(value));
this.datepicker.selected$.next(new Date(value));
}
else {
this.datepicker.selected$.next(new Date(value));
}
}
if (!value) {
this.datepicker.date$.next(value);
this.datepicker.selected$.next(value);
}
}
/** Will set the selected timezone. */
set timezone(value) {
this.setTimezone(value);
}
/** The earliest selectable date. */
set min(value) {
this.datepicker.min$.next(value);
}
/** The latest selectable date. */
set max(value) {
this.datepicker.max$.next(value);
}
/** 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;
}
/** Determine if the today button is disabled */
get _isTodayDisabled() {
const min = this.datepicker.min$.value;
const max = this.datepicker.max$.value;
if (!min && !max) {
return false;
}
if (min && !max) {
return isDateBefore(new Date(), min);
}
if (!min && max) {
return isDateAfter(new Date(), max);
}
return isDateBefore(new Date(), min) || isDateAfter(new Date(), max);
}
constructor() {
this.datepicker = inject(DateTimePickerService);
this._rangeService = inject(DateRangeService, { optional: true });
this._rangeOptions = inject(DateRangeOptions, { optional: true });
/** Define the aria label for the now button */
this.nowBtnAriaLabel = 'Set date to now';
/** Emits an event when the date is changed using the component. */
this.dateChange = new EventEmitter();
/** If not defined the picker will try to use the user's timezone. If that is not available, it will revert to GMT. */
this.timezoneChange = new EventEmitter();
// expose enum to view
this.DatePickerMode = DatePickerMode;
this._onDestroy = new Subject();
this.datepicker.selected$
.pipe(distinctUntilChanged(dateComparator), takeUntil(this._onDestroy))
.subscribe(date => this.dateChange.emit(date));
}
ngOnInit() {
this.setTimezone(this.datepicker.timezone$.value);
}
ngAfterViewInit() {
setTimeout(() => (this.datepicker.initialised = true));
}
ngOnDestroy() {
this._onDestroy.next();
this._onDestroy.complete();
}
/**
* Change the date to the current date and time
*/
setToNow() {
if (this._isRangeMode) {
const date = new Date();
if (this._isRangeStart && !this._rangeService.showTime) {
this.datepicker.setDate(date.getDate(), date.getMonth(), date.getFullYear(), 0, 0, 0);
}
else if (this._isRangeEnd && !this._rangeService.showTime) {
this.datepicker.setDate(date.getDate(), date.getMonth(), date.getFullYear(), 23, 59, 59);
}
else {
this.datepicker.setDate(date.getDate(), date.getMonth(), date.getFullYear(), this.datepicker.hours, this.datepicker.minutes, this.datepicker.seconds);
}
}
else {
// set the date to the current moment
this.datepicker.setDateToNow();
}
}
_onTimezoneChange(timezone) {
if (!timezoneComparator(this.datepicker.timezone$.value, timezone)) {
this.timezoneChange.emit(timezone);
}
}
/**
* Update the service with the new timezone value, falling back on the default if it is undefined or
* not present in `timezones`.
*/
setTimezone(timezone) {
// if the user does not provide a timezone, set it to the current timezone and emit the change
if (!timezone) {
this.datepicker.timezone$.next(this.datepicker.getDefaultTimezone());
this.timezoneChange.emit(this.datepicker.timezone$.value);
return;
}
// Check if the timezone is available in the timezones list; if not, get the default timezone
if (this.datepicker.isTimezoneAvailable(timezone)) {
this.datepicker.timezone$.next(timezone);
}
else {
// This is probably an unintended state so emit a warning
console.warn(`ux-date-time-picker: specified timezone ${JSON.stringify(timezone)} is not present in the timezones array.`);
// Fall back on the default timezone
const defaultTimezone = this.datepicker.getDefaultTimezone();
if (!this.datepicker.timezone$.value ||
!timezoneComparator(defaultTimezone, this.datepicker.timezone$.value)) {
this.datepicker.timezone$.next(defaultTimezone);
this.timezoneChange.emit(defaultTimezone);
}
}
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: DateTimePickerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.12", type: DateTimePickerComponent, selector: "ux-date-time-picker", inputs: { showDate: "showDate", showTime: "showTime", showTimezone: "showTimezone", showSeconds: "showSeconds", showMeridian: "showMeridian", showSpinners: "showSpinners", weekdays: "weekdays", months: "months", monthsShort: "monthsShort", meridians: "meridians", nowBtnText: "nowBtnText", showNowBtn: "showNowBtn", timezones: "timezones", startOfWeek: "startOfWeek", nowBtnAriaLabel: "nowBtnAriaLabel", date: "date", timezone: "timezone", min: "min", max: "max" }, outputs: { dateChange: "dateChange", timezoneChange: "timezoneChange" }, providers: [DateTimePickerService], ngImport: i0, template: "<div class=\"calendar-container\">\n\n <ux-date-time-picker-header></ux-date-time-picker-header>\n\n @if (datepicker.showDate$ | async) {\n @switch (datepicker.mode$ | async) {\n <!-- Display days in the current month -->\n @case (DatePickerMode.Day) {\n <ux-date-time-picker-day-view></ux-date-time-picker-day-view>\n }\n <!-- Display the months in the current year -->\n @case (DatePickerMode.Month) {\n <ux-date-time-picker-month-view></ux-date-time-picker-month-view>\n }\n <!-- Display a decade -->\n @case (DatePickerMode.Year) {\n <ux-date-time-picker-year-view></ux-date-time-picker-year-view>\n }\n }\n }\n\n <!-- Display a Time Picker -->\n @if (datepicker.showTime$ | async) {\n <ux-date-time-picker-time-view (timezoneChange)=\"_onTimezoneChange($event)\"\n ></ux-date-time-picker-time-view>\n }\n\n</div>\n\n@if (datepicker.showNowBtn$ | async) {\n <button type=\"button\"\n uxFocusIndicator\n class=\"now-button\"\n [attr.aria-label]=\"nowBtnAriaLabel\"\n [disabled]=\"_isTodayDisabled\"\n (click)=\"setToNow()\">\n {{ datepicker.nowBtnText$ | async }}\n </button>\n}", dependencies: [{ kind: "directive", type: i1.FocusIndicatorDirective, selector: "[uxFocusIndicator]", inputs: ["checkChildren", "mouseFocusIndicator", "touchFocusIndicator", "keyboardFocusIndicator", "programmaticFocusIndicator"], outputs: ["indicator"], exportAs: ["ux-focus-indicator"] }, { kind: "component", type: i2.HeaderComponent, selector: "ux-date-time-picker-header" }, { kind: "component", type: i3.DayViewComponent, selector: "ux-date-time-picker-day-view" }, { kind: "component", type: i4.MonthViewComponent, selector: "ux-date-time-picker-month-view" }, { kind: "component", type: i5.YearViewComponent, selector: "ux-date-time-picker-year-view" }, { kind: "component", type: i6.TimeViewComponent, selector: "ux-date-time-picker-time-view", outputs: ["timezoneChange"] }, { kind: "pipe", type: i7.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: DateTimePickerComponent, decorators: [{
type: Component,
args: [{ selector: 'ux-date-time-picker', providers: [DateTimePickerService], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"calendar-container\">\n\n <ux-date-time-picker-header></ux-date-time-picker-header>\n\n @if (datepicker.showDate$ | async) {\n @switch (datepicker.mode$ | async) {\n <!-- Display days in the current month -->\n @case (DatePickerMode.Day) {\n <ux-date-time-picker-day-view></ux-date-time-picker-day-view>\n }\n <!-- Display the months in the current year -->\n @case (DatePickerMode.Month) {\n <ux-date-time-picker-month-view></ux-date-time-picker-month-view>\n }\n <!-- Display a decade -->\n @case (DatePickerMode.Year) {\n <ux-date-time-picker-year-view></ux-date-time-picker-year-view>\n }\n }\n }\n\n <!-- Display a Time Picker -->\n @if (datepicker.showTime$ | async) {\n <ux-date-time-picker-time-view (timezoneChange)=\"_onTimezoneChange($event)\"\n ></ux-date-time-picker-time-view>\n }\n\n</div>\n\n@if (datepicker.showNowBtn$ | async) {\n <button type=\"button\"\n uxFocusIndicator\n class=\"now-button\"\n [attr.aria-label]=\"nowBtnAriaLabel\"\n [disabled]=\"_isTodayDisabled\"\n (click)=\"setToNow()\">\n {{ datepicker.nowBtnText$ | async }}\n </button>\n}" }]
}], ctorParameters: () => [], propDecorators: { showDate: [{
type: Input
}], showTime: [{
type: Input
}], showTimezone: [{
type: Input
}], showSeconds: [{
type: Input
}], showMeridian: [{
type: Input
}], showSpinners: [{
type: Input
}], weekdays: [{
type: Input
}], months: [{
type: Input
}], monthsShort: [{
type: Input
}], meridians: [{
type: Input
}], nowBtnText: [{
type: Input
}], showNowBtn: [{
type: Input
}], timezones: [{
type: Input
}], startOfWeek: [{
type: Input
}], nowBtnAriaLabel: [{
type: Input
}], dateChange: [{
type: Output
}], timezoneChange: [{
type: Output
}], date: [{
type: Input
}], timezone: [{
type: Input
}], min: [{
type: Input
}], max: [{
type: Input
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGF0ZS10aW1lLXBpY2tlci5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvY29tcG9uZW50cy9kYXRlLXRpbWUtcGlja2VyL2RhdGUtdGltZS1waWNrZXIuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vc3JjL2NvbXBvbmVudHMvZGF0ZS10aW1lLXBpY2tlci9kYXRlLXRpbWUtcGlja2VyLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUNBLE9BQU8sRUFFTCx1QkFBdUIsRUFDdkIsU0FBUyxFQUNULFlBQVksRUFDWixNQUFNLEVBQ04sS0FBSyxFQUdMLE1BQU0sR0FDUCxNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQy9CLE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxTQUFTLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUNqRSxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxrREFBa0QsQ0FBQztBQUNwRixPQUFPLEVBQUUsZUFBZSxFQUFFLGdCQUFnQixFQUFFLE1BQU0seUNBQXlDLENBQUM7QUFDNUYsT0FBTyxFQUFFLGNBQWMsRUFBRSxxQkFBcUIsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBQ25GLE9BQU8sRUFDTCxjQUFjLEVBRWQsV0FBVyxFQUNYLFlBQVksRUFDWixrQkFBa0IsR0FDbkIsTUFBTSwwQkFBMEIsQ0FBQzs7Ozs7Ozs7O0FBUWxDLE1BQU0sT0FBTyx1QkFBdUI7SUFPbEMsZ0VBQWdFO0lBQ2hFLElBQWEsUUFBUSxDQUFDLEtBQWM7UUFDbEMsSUFBSSxLQUFLLEtBQUssU0FBUyxFQUFFLENBQUM7WUFDeEIsSUFBSSxDQUFDLFVBQVUsQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQ3hDLENBQUM7SUFDSCxDQUFDO0lBRUQsZ0VBQWdFO0lBQ2hFLElBQWEsUUFBUSxD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QUFRO3NCQURYLEtBQUs7Z0JBT0YsR0FBRztzQkFETixLQUFLO2dCQU9GLEdBQUc7c0JBRE4sS0FBSyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IFdlZWtEYXkgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuaW1wb3J0IHtcbiAgQWZ0ZXJWaWV3SW5pdCxcbiAgQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3ksXG4gIENvbXBvbmVudCxcbiAgRXZlbnRFbWl0dGVyLFxuICBpbmplY3QsXG4gIElucHV0LFxuICBPbkRlc3Ryb3ksXG4gIE9uSW5pdCxcbiAgT3V0cHV0LFxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IFN1YmplY3QgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IGRpc3RpbmN0VW50aWxDaGFuZ2VkLCB0YWtlVW50aWwgfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5pbXBvcnQgeyBEYXRlUmFuZ2VPcHRpb25zIH0gZnJvbSAnLi4vZGF0ZS1yYW5nZS1waWNrZXIvZGF0ZS1yYW5nZS1waWNrZXIuZGlyZWN0aXZlJztcbmltcG9ydCB7IERhdGVSYW5nZVBpY2tlciwgRGF0ZVJhbmdlU2VydmljZSB9IGZyb20gJy4uL2RhdGUtcmFuZ2UtcGlja2VyL2RhdGUtcmFuZ2Uuc2VydmljZSc7XG5pbXBvcnQgeyBEYXRlUGlja2VyTW9kZSwgRGF0ZVRpbWVQaWNrZXJTZXJ2aWNlIH0gZnJvbSAnLi9kYXRlLXRpbWUtcGlja2VyLnNlcnZpY2UnO1xuaW1wb3J0IHtcbiAgZGF0ZUNvbXBhcmF0b3IsXG4gIERhdGVUaW1lUGlja2VyVGltZXpvbmUsXG4gIGlzRGF0ZUFmdGVyLFxuICBpc0RhdGVCZWZvcmUsXG4gIHRpbWV6b25lQ29tcGFyYXRvcixcbn0gZnJvbSAnLi9kYXRlLXRpbWUtcGlja2VyLnV0aWxzJztcblxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAndXgtZGF0ZS10aW1lLXBpY2tlcicsXG4gIHRlbXBsYXRlVXJsOiAnLi9kYXRlLXRpbWUtcGlja2VyLmNvbXBvbmVudC5odG1sJyxcbiAgcHJvdmlkZXJzOiBbRGF0ZVRpbWVQaWNrZXJTZXJ2aWNlXSxcbiAgY2hhbmdlRGV0ZWN0aW9uOiBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneS5PblB1c2gsXG59KVxuZXhwb3J0IGNsYXNzIERhdGVUaW1lUGlja2VyQ29tcG9uZW50IGltcGxlbWVudHMgT25Jbml0LCBBZnRlclZpZXdJbml0LCBPbkRlc3Ryb3kge1xuICByZWFkb25seSBkYXRlcGlja2VyID0gaW5qZWN0KERhdGVUaW1lUGlja2VyU2VydmljZSk7XG5cbiAgcHJpdmF0ZSByZWFkb25seSBfcmFuZ2VTZXJ2aWNlID0gaW5qZWN0KERhdGVSYW5nZVNlcnZpY2UsIHsgb3B0aW9uYWw6IHRydWUgfSk7XG5cbiAgcHJpdmF0ZSByZWFkb25seSBfcmFuZ2VPcHRpb25zID0gaW5qZWN0KERhdGVSYW5nZU9wdGlvbnMsIHsgb3B0aW9uYWw6IHRydWUgfSk7XG5cbiAgLyoqIERlZmluZXMgd2hldGhlciBvciBub3QgdGhlIGRhdGUgcGlja2VyIHNob3VsZCBiZSB2aXNpYmxlLiAqL1xuICBASW5wdXQoKSBzZXQgc2hvd0RhdGUodmFsdWU6IGJvb2xlYW4pIHtcbiAgICBpZiAodmFsdWUgIT09IHVuZGVmaW5lZCkge1xuICAgICAgdGhpcy5kYXRlcGlja2VyLnNob3dEYXRlJC5uZXh0KHZhbHVlKTtcbiAgICB9XG4gIH1cblxuICAvKiogRGVmaW5lcyB3aGV0aGVyIG9yIG5vdCB0aGUgdGltZSBwaWNrZXIgc2hvdWxkIGJlIHZpc2libGUuICovXG4gIEBJbnB1dCgpIHNldCBzaG93VGltZSh2YWx1ZTogYm9vbGVhbikge1xuICAgIGlmICh2YWx1ZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICB0aGlzLmRhdGVwaWNrZXIuc2hvd1RpbWUkLm5leHQodmFsdWUpO1xuICAgIH1cbiAgfVxuXG4gIC8qKiBEZWZpbmVzIHdoZXRoZXIgb3Igbm90IHRoZSB0aW1lIHBpY2tlciBzaG91bGQgYWxsb3cgdGhlIHVzZXIgdG8gY2hvb3NlIGEgdGltZXpvbmUuICovXG4gIEBJbnB1dCgpIHNldCBzaG93VGltZXpvbmUodmFsdWU6IGJvb2xlYW4pIHtcbiAgICBpZiAodmFsdWUgIT09IHVuZGVmaW5lZCkge1xuICAgICAgdGhpcy5kYXRlcGlja2VyLnNob3dUaW1lem9uZSQubmV4dCh2YWx1ZSk7XG4gICAgfVxuICB9XG5cbiAgLyoqIERlZmluZXMgd2hldGhlciBvciBub3QgdGhlIHRpbWUgcGlja2VyIHNob3VsZCBhbGxvdyB0aGUgdXNlciB0byBzcGVjaWZ5IHNlY29uZHMuICovXG4gIEBJbnB1dCgpIHNldCBzaG93U2Vjb25kcyh2YWx1ZTogYm9vbGVhbikge1xuICAgIGlmICh2YWx1ZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICB0aGlzLmRhdGVwaWNrZXIuc2hvd1NlY29uZHMkLm5leHQodmFsdWUpO1xuICAgIH1cbiAgfVxuXG4gIC8qKiBEZWZpbmVzIHdoZXRoZXIgb3Igbm90IHRoZSB0aW1lIHBpY2tlciBzaG91bGQgc2hvdyBhbiBBTS9QTSBidXR0b24sIG9yIHRpbWUgc2hvdWxkIGJlIHJlcHJlc2VudGVkIGluIDI0aHIgZm9ybWF0IGluc3RlYWQuICovXG4gIEBJbnB1dCgpIHNldCBzaG93TWVyaWRpYW4odmFsdWU6IGJvb2xlYW4pIHtcbiAgICBpZiAodmFsdWUgIT09IHVuZGVmaW5lZCkge1xuICAgICAgdGhpcy5kYXRlcGlja2VyLnNob3dNZXJpZGlhbiQubmV4dCh2YWx1ZSk7XG4gICAgfVxuICB9XG5cbiAgLyoqIERlZmluZXMgd2hldGhlciBvciBub3QgdGhlIHRpbWUgcGlja2VyIHNob3VsZCBhbGxvdyB0aGUgdXNlciB0byBzZWxlY3QgdGhlIHRpbWUgdXNpbmcgc3Bpbm5lcnMuICovXG4gIEBJbnB1dCgpIHNldCBzaG93U3Bpbm5lcnModmFsdWU6IGJvb2xlYW4pIHtcbiAgICBpZiAodmFsdWUgIT09IHVuZGVmaW5lZCkge1xuICAgICAgdGhpcy5kYXRlcGlja2VyLnNob3dTcGlubmVycyQubmV4dCh2YWx1ZSk7XG4gICAgfVxuICB9XG5cbiAgLyoqIElmIGRlZmluZWQgd2lsbCBvdmVycmlkZSB0aGUgd2Vla2RheSBuYW1lcyBkaXNwbGF5ZWQuICovXG4gIEBJbnB1dCgpIHNldCB3ZWVrZGF5cyh2YWx1ZTogc3RyaW5nW10pIHtcbiAgICBpZiAodmFsdWUgIT09IHVuZGVmaW5lZCkge1xuICAgICAgdGhpcy5kYXRlcGlja2VyLndlZWtkYXlzJC5uZXh0KHZhbHVlKTtcbiAgICB9XG4gIH1cblxuICAvKiogRGVmaW5lcyB0aGUgbmFtZXMgb2YgdGhlIG1vbnRocy4gKi9cbiAgQElucHV0KCkgc2V0IG1vbnRocyhtb250aHM6IHN0cmluZ1tdKSB7XG4gICAgaWYgKG1vbnRocyAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICB0aGlzLmRhdGVwaWNrZXIubW9udGhzID0gbW9udGhzO1xuICAgIH1cbiAgfVxuXG4gIC8qKiBEZWZpbmVzIHRoZSBzaG9ydCBuYW1lcyBvZiBlYWNoIG1vbnRoLiAqL1xuICBASW5wdXQoKSBzZXQgbW9udGhzU2hvcnQobW9udGhzOiBzdHJpbmdbXSkge1xuICAgIGlmIChtb250aHMgIT09IHVuZGVmaW5lZCkge1xuICAgICAgdGhpcy5kYXRlcGlja2VyLm1vbnRoc1Nob3J0ID0gbW9udGhzO1xuICAgIH1cbiAgfVxuXG4gIC8qKiBEZWZpbmVzIHRoZSBsYWJlbHMgdG8gc2hvdyBpbiB0aGUgbWVyaWRpYW4gKEFNL1BNKSBzZWxlY3Rvci4gKi9cbiAgQElucHV0KCkgc2V0IG1lcmlkaWFucyhtZXJpZGlhbnM6IHN0cmluZ1tdKSB7XG4gICAgaWYgKG1lcmlkaWFucyAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICB0aGlzLmRhdGVwaWNrZXIubWVyaWRpYW5zID0gbWVyaWRpYW5zO1xuICAgIH1cbiAgfVxuXG4gIC8qKiBEZWZpbmVzIHRoZSB0ZXh0IHRvIGJlIGRpc3BsYXllZCBpbiB0aGUgYnV0dG9uIHVzZWQgdG8gc2V0IHRoZSBzZWxlY3RlZCB0aW1lIHRvIHRoZSBjdXJyZW50IHRpbWUuICovXG4gIEBJbnB1dCgpIHNldCBub3dCdG5UZXh0KHZhbHVlOiBzdHJpbmcpIHtcbiAgICBpZiAodmFsdWUgIT09IHVuZGVmaW5lZCkge1xuICAgICAgdGhpcy5kYXRlcGlja2VyLm5vd0J0blRleHQkLm5leHQodmFsdWUpO1xuICAgIH1cbiAgfVxuXG4gIC8qKiBTcGVjaWZ5IHdoZXRoZXIgb3Igbm90IHRvIHNob3cgdGhlIHNob3cgbm93IGJ1dHRvbiAqL1xuICBASW5wdXQoKSBzZXQgc2hvd05vd0J0bih2YWx1ZTogYm9vbGVhbikge1xuICAgIGlmICh2YWx1ZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICB0aGlzLmRhdGVwaWNrZXIuc2hvd05vd0J0biQubmV4dCh2YWx1ZSk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIERlZmluZXMgdGhlIGxpc3Qgb2YgYXZhaWxhYmxlIHRpbWV6b25lcy4gVGhlIGBEYXRlVGltZVBpY2tlclRpbWV6b25lYCBpbnRlcmZhY2Ugc3BlY2lmaWVzIHRoYXQgZWFjaCB0aW1lem9uZSBzaG91bGRcbiAgICogYmUgYW4gb2JqZWN0IHdpdGggYSBgbmFtZWAgcHJvcGVydHkgdGhhdCByZXByZXNlbnRzIHRoZSB0aW1lem9uZSwgZWcuIGBHTVQrMmAsIGFuZCBhbiBgb2Zmc2V0YCBwcm9wZXJ0eSB0aGF0IHJlcHJlc2VudHNcbiAgICogdGhlIG51bWJlciBvZiBtaW51dGVzIHJlbGF0aXZlIHRvIEdNVCB0aGUgdGltZXpvbmUgaXMuXG4gICAqL1xuICBASW5wdXQoKSBzZXQgdGltZXpvbmVzKHZhbHVlOiBEYXRlVGltZVBpY2tlclRpbWV6b25lW10pIHtcbiAgICBpZiAodmFsdWUgIT09IHVuZGVmaW5lZCkge1xuICAgICAgdGhpcy5kYXRlcGlja2VyLnRpbWV6b25lcyQubmV4dCh2YWx1ZSk7XG4gICAgfVxuICB9XG5cbiAgLyoqIERlZmluZXMgdGhlIGRheSBvZiB0aGUgd2VlayB0aGF0IHNob3VsZCBhcHBlYXIgaW4gdGhlIGZpcnN0IGNvbHVtbi4gYFdlZWtEYXlgIGlzIGFuIGVudW1lcmF0aW9uIGF2YWlsYWJsZSBpbiBgQGFuZ3VsYXIvY29tbW9uYC4gKi9cbiAgQElucHV0KCkgc2V0IHN0YXJ0T2ZXZWVrKHN0YXJ0T2ZXZWVrOiBXZWVrRGF5KSB7XG4gICAgaWYgKHN0YXJ0T2ZXZWVrICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIHRoaXMuZGF0ZXBpY2tlci5zdGFydE9mV2VlayQubmV4dChzdGFydE9mV2Vlayk7XG4gICAgfVxuICB9XG5cbiAgLyoqIERlZmluZSB0aGUgYXJpYSBsYWJlbCBmb3IgdGhlIG5vdyBidXR0b24gKi9cbiAgQElucHV0KCkgbm93QnRuQXJpYUxhYmVsOiBzdHJpbmcgPSAnU2V0IGRhdGUgdG8gbm93JztcblxuICAvKiogRW1pdHMgYW4gZXZlbnQgd2hlbiB0aGUgZGF0ZSBpcyBjaGFuZ2VkIHVzaW5nIHRoZSBjb21wb25lbnQuICovXG4gIEBPdXRwdXQoKSBkYXRlQ2hhbmdlOiBFdmVudEVtaXR0ZXI8RGF0ZT4gPSBuZXcgRXZlbnRFbWl0dGVyPERhdGU+KCk7XG5cbiAgLyoqIElmIG5vdCBkZWZpbmVkIHRoZSBwaWNrZXIgd2lsbCB0cnkgdG8gdXNlIHRoZSB1c2VyJ3MgdGltZXpvbmUuIElmIHRoYXQgaXMgbm90IGF2YWlsYWJsZSwgaXQgd2lsbCByZXZlcnQgdG8gR01ULiAqL1xuICBAT3V0cHV0KCkgdGltZXpvbmVDaGFuZ2U6IEV2ZW50RW1pdHRlcjxEYXRlVGltZVBpY2tlclRpbWV6b25lPiA9XG4gICAgbmV3IEV2ZW50RW1pdHRlcjxEYXRlVGltZVBpY2tlclRpbWV6b25lPigpO1xuXG4gIC8qKiBUaGUgc2VsZWN0ZWQgZGF0ZSB0byBiZSBkaXNwbGF5ZWQgaW4gdGhlIGNvbXBvbmVudC4gKi9cbiAgQElucHV0KClcbiAgc2V0IGRhdGUodmFsdWU6IERhdGUpIHtcbiAgICBpZiAodmFsdWUgJiYgIWRhdGVDb21wYXJhdG9yKHZhbHVlLCB0aGlzLmRhdGVwaWNrZXIuZGF0ZSQudmFsdWUpKSB7XG4gICAgICBpZiAodGhpcy5faXNSYW5nZU1vZGUpIHtcbiAgICAgICAgdGhpcy5kYXRlcGlja2VyLmRhdGUkLm5leHQobmV3IERhdGUodmFsdWUpKTtcbiAgICAgICAgdGhpcy5kYXRlcGlja2VyLnNlbGVjdGVkJC5uZXh0KG5ldyBEYXRlKHZhbHVlKSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLmRhdGVwaWNrZXIuc2VsZWN0ZWQkLm5leHQobmV3IERhdGUodmFsdWUpKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAoIXZhbHVlKSB7XG4gICAgICB0aGlzLmRhdGVwaWNrZXIuZGF0ZSQubmV4dCh2YWx1ZSk7XG4gICAgICB0aGlzLmRhdGVwaWNrZXIuc2VsZWN0ZWQkLm5leHQodmFsdWUpO1xuICAgIH1cbiAgfVxuXG4gIC8qKiBXaWxsIHNldCB0aGUgc2VsZWN0ZWQgdGltZXpvbmUuICovXG4gIEBJbnB1dCgpXG4gIHNldCB0aW1lem9uZSh2YWx1ZTogRGF0ZVRpbWVQaWNrZXJUaW1lem9uZSkge1xuICAgIHRoaXMuc2V0VGltZXpvbmUodmFsdWUpO1xuICB9XG5cbiAgLyoqIFRoZSBlYXJsaWVzdCBzZWxlY3RhYmxlIGRhdGUuICovXG4gIEBJbnB1dCgpXG4gIHNldCBtaW4odmFsdWU6IERhdGUpIHtcbiAgICB0aGlzLmRhdGVwaWNrZXIubWluJC5uZXh0KHZhbHVlKTtcbiAgfVxuXG4gIC8qKiBUaGUgbGF0ZXN0IHNlbGVjdGFibGUgZGF0ZS4gKi9cbiAgQElucHV0KClcbiAgc2V0IG1heCh2YWx1ZTogRGF0ZSkge1xuICAgIHRoaXMuZGF0ZXBpY2tlci5tYXgkLm5leHQodmFsdWUpO1xuICB9XG5cbiAgLyoqIERldGVybWluZSBpZiB3ZSBhcmUgaW4gcmFuZ2Ugc2VsZWN0aW9uIG1vZGUgKi9cbiAgZ2V0IF9pc1JhbmdlTW9kZSgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gISF0aGlzLl9yYW5nZU9wdGlvbnM7XG4gIH1cblxuICAvKiogRGV0ZXJtaW5lIGlmIHRoaXMgcGlja2VyIGlzIHRoZSBzdGFydCBwaWNrZXIgKi9cbiAgZ2V0IF9pc1JhbmdlU3RhcnQoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuX2lzUmFuZ2VNb2RlICYmIHRoaXMuX3JhbmdlT3B0aW9ucy5waWNrZXIgPT09IERhdGVSYW5nZVBpY2tlci5TdGFydDtcbiAgfVxuXG4gIC8qKiBEZXRlcm1pbmUgaWYgdGhpcyBwaWNrZXIgaXMgdGhlIGVuZCBwaWNrZXIgKi9cbiAgZ2V0IF9pc1JhbmdlRW5kKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLl9pc1JhbmdlTW9kZSAmJiB0aGlzLl9yYW5nZU9wdGlvbnMucGlja2VyID09PSBEYXRlUmFuZ2VQaWNrZXIuRW5kO1xuICB9XG5cbiAgLyoqIERldGVybWluZSBpZiB0aGUgdG9kYXkgYnV0dG9uIGlzIGRpc2FibGVkICovXG4gIGdldCBfaXNUb2RheURpc2FibGVkKCk6IGJvb2xlYW4ge1xuICAgIGNvbnN0IG1pbiA9IHRoaXMuZGF0ZXBpY2tlci5taW4kLnZhbHVlO1xuICAgIGNvbnN0IG1heCA9IHRoaXMuZGF0ZXBpY2tlci5tYXgkLnZhbHVlO1xuXG4gICAgaWYgKCFtaW4gJiYgIW1heCkge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIGlmIChtaW4gJiYgIW1heCkge1xuICAgICAgcmV0dXJuIGlzRGF0ZUJlZm9yZShuZXcgRGF0ZSgpLCBtaW4pO1xuICAgIH1cblxuICAgIGlmICghbWluICYmIG1heCkge1xuICAgICAgcmV0dXJuIGlzRGF0ZUFmdGVyKG5ldyBEYXRlKCksIG1heCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIGlzRGF0ZUJlZm9yZShuZXcgRGF0ZSgpLCBtaW4pIHx8IGlzRGF0ZUFmdGVyKG5ldyBEYXRlKCksIG1heCk7XG4gIH1cblxuICAvLyBleHBvc2UgZW51bSB0byB2aWV3XG4gIERhdGVQaWNrZXJNb2RlID0gRGF0ZVBpY2tlck1vZGU7XG5cbiAgcHJpdmF0ZSByZWFkb25seSBfb25EZXN0cm95ID0gbmV3IFN1YmplY3Q8dm9pZD4oKTtcblxuICBjb25zdHJ1Y3RvcigpIHtcbiAgICB0aGlzLmRhdGVwaWNrZXIuc2VsZWN0ZWQkXG4gICAgICAucGlwZShkaXN0aW5jdFVudGlsQ2hhbmdlZChkYXRlQ29tcGFyYXRvciksIHRha2VVbnRpbCh0aGlzLl9vbkRlc3Ryb3kpKVxuICAgICAgLnN1YnNjcmliZShkYXRlID0+IHRoaXMuZGF0ZUNoYW5nZS5lbWl0KGRhdGUpKTtcbiAgfVxuXG4gIG5nT25Jbml0KCk6IHZvaWQge1xuICAgIHRoaXMuc2V0VGltZXpvbmUodGhpcy5kYXRlcGlja2VyLnRpbWV6b25lJC52YWx1ZSk7XG4gIH1cblxuICBuZ0FmdGVyVmlld0luaXQoKTogdm9pZCB7XG4gICAgc2V0VGltZW91dCgoKSA9PiAodGhpcy5kYXRlcGlja2VyLmluaXRpYWxpc2VkID0gdHJ1ZSkpO1xuICB9XG5cbiAgbmdPbkRlc3Ryb3koKTogdm9pZCB7XG4gICAgdGhpcy5fb25EZXN0cm95Lm5leHQoKTtcbiAgICB0aGlzLl9vbkRlc3Ryb3kuY29tcGxldGUoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDaGFuZ2UgdGhlIGRhdGUgdG8gdGhlIGN1cnJlbnQgZGF0ZSBhbmQgdGltZVxuICAgKi9cbiAgc2V0VG9Ob3coKTogdm9pZCB7XG4gICAgaWYgKHRoaXMuX2lzUmFuZ2VNb2RlKSB7XG4gICAgICBjb25zdCBkYXRlID0gbmV3IERhdGUoKTtcblxuICAgICAgaWYgKHRoaXMuX2lzUmFuZ2VTdGFydCAmJiAhdGhpcy5fcmFuZ2VTZXJ2aWNlLnNob3dUaW1lKSB7XG4gICAgICAgIHRoaXMuZGF0ZXBpY2tlci5zZXREYXRlKGRhdGUuZ2V0RGF0ZSgpLCBkYXRlLmdldE1vbnRoKCksIGRhdGUuZ2V0RnVsbFllYXIoKSwgMCwgMCwgMCk7XG4gICAgICB9IGVsc2UgaWYgKHRoaXMuX2lzUmFuZ2VFbmQgJiYgIXRoaXMuX3JhbmdlU2VydmljZS5zaG93VGltZSkge1xuICAgICAgICB0aGlzLmRhdGVwaWNrZXIuc2V0RGF0ZShkYXRlLmdldERhdGUoKSwgZGF0ZS5nZXRNb250aCgpLCBkYXRlLmdldEZ1bGxZZWFyKCksIDIzLCA1OSwgNTkpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy5kYXRlcGlja2VyLnNldERhdGUoXG4gICAgICAgICAgZGF0ZS5nZXREYXRlKCksXG4gICAgICAgICAgZGF0ZS5nZXRNb250aCgpLFxuICAgICAgICAgIGRhdGUuZ2V0RnVsbFllYXIoKSxcbiAgICAgICAgICB0aGlzLmRhdGVwaWNrZXIuaG91cnMsXG4gICAgICAgICAgdGhpcy5kYXRlcGlja2VyLm1pbnV0ZXMsXG4gICAgICAgICAgdGhpcy5kYXRlcGlja2VyLnNlY29uZHNcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgLy8gc2V0IHRoZSBkYXRlIHRvIHRoZSBjdXJyZW50IG1vbWVudFxuICAgICAgdGhpcy5kYXRlcGlja2VyLnNldERhdGVUb05vdygpO1xuICAgIH1cbiAgfVxuXG4gIF9vblRpbWV6b25lQ2hhbmdlKHRpbWV6b25lOiBEYXRlVGltZVBpY2tlclRpbWV6b25lKTogdm9pZCB7XG4gICAgaWYgKCF0aW1lem9uZUNvbXBhcmF0b3IodGhpcy5kYXRlcGlja2VyLnRpbWV6b25lJC52YWx1ZSwgdGltZXpvbmUpKSB7XG4gICAgICB0aGlzLnRpbWV6b25lQ2hhbmdlLmVtaXQodGltZXpvbmUpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBVcGRhdGUgdGhlIHNlcnZpY2Ugd2l0aCB0aGUgbmV3IHRpbWV6b25lIHZhbHVlLCBmYWxsaW5nIGJhY2sgb24gdGhlIGRlZmF1bHQgaWYgaXQgaXMgdW5kZWZpbmVkIG9yXG4gICAqIG5vdCBwcmVzZW50IGluIGB0aW1lem9uZXNgLlxuICAgKi9cbiAgcHJpdmF0ZSBzZXRUaW1lem9uZSh0aW1lem9uZTogRGF0ZVRpbWVQaWNrZXJUaW1lem9uZSB8IHVuZGVmaW5lZCk6IHZvaWQge1xuICAgIC8vIGlmIHRoZSB1c2VyIGRvZXMgbm90IHByb3ZpZGUgYSB0aW1lem9uZSwgc2V0IGl0IHRvIHRoZSBjdXJyZW50IHRpbWV6b25lIGFuZCBlbWl0IHRoZSBjaGFuZ2VcbiAgICBpZiAoIXRpbWV6b25lKSB7XG4gICAgICB0aGlzLmRhdGVwaWNrZXIudGltZXpvbmUkLm5leHQodGhpcy5kYXRlcGlja2VyLmdldERlZmF1bHRUaW1lem9uZSgpKTtcbiAgICAgIHRoaXMudGltZXpvbmVDaGFuZ2UuZW1pdCh0aGlzLmRhdGVwaWNrZXIudGltZXpvbmUkLnZhbHVlKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyBDaGVjayBpZiB0aGUgdGltZXpvbmUgaXMgYXZhaWxhYmxlIGluIHRoZSB0aW1lem9uZXMgbGlzdDsgaWYgbm90LCBnZXQgdGhlIGRlZmF1bHQgdGltZXpvbmVcbiAgICBpZiAodGhpcy5kYXRlcGlja2VyLmlzVGltZXpvbmVBdmFpbGFibGUodGltZXpvbmUpKSB7XG4gICAgICB0aGlzLmRhdGVwaWNrZXIudGltZXpvbmUkLm5leHQodGltZXpvbmUpO1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBUaGlzIGlzIHByb2JhYmx5IGFuIHVuaW50ZW5kZWQgc3RhdGUgc28gZW1pdCBhIHdhcm5pbmdcbiAgICAgIGNvbnNvbGUud2FybihcbiAgICAgICAgYHV4LWRhdGUtdGltZS1waWNrZXI6IHNwZWNpZmllZCB0aW1lem9uZSAke0pTT04uc3RyaW5naWZ5KHRpbWV6b25lKX0gaXMgbm90IHByZXNlbnQgaW4gdGhlIHRpbWV6b25lcyBhcnJheS5gXG4gICAgICApO1xuXG4gICAgICAvLyBGYWxsIGJhY2sgb24gdGhlIGRlZmF1bHQgdGltZXpvbmVcbiAgICAgIGNvbnN0IGRlZmF1bHRUaW1lem9uZSA9IHRoaXMuZGF0ZXBpY2tlci5nZXREZWZhdWx0VGltZXpvbmUoKTtcbiAgICAgIGlmIChcbiAgICAgICAgIXRoaXMuZGF0ZXBpY2tlci50aW1lem9uZSQudmFsdWUgfHxcbiAgICAgICAgIXRpbWV6b25lQ29tcGFyYXRvcihkZWZhdWx0VGltZXpvbmUsIHRoaXMuZGF0ZXBpY2tlci50aW1lem9uZSQudmFsdWUpXG4gICAgICApIHtcbiAgICAgICAgdGhpcy5kYXRlcGlja2VyLnRpbWV6b25lJC5uZXh0KGRlZmF1bHRUaW1lem9uZSk7XG4gICAgICAgIHRoaXMudGltZXpvbmVDaGFuZ2UuZW1pdChkZWZhdWx0VGltZXpvbmUpO1xuICAgICAgfVxuICAgIH1cbiAgfVxufVxuIiwiPGRpdiBjbGFzcz1cImNhbGVuZGFyLWNvbnRhaW5lclwiPlxuXG4gIDx1eC1kYXRlLXRpbWUtcGlja2VyLWhlYWRlcj48L3V4LWRhdGUtdGltZS1waWNrZXItaGVhZGVyPlxuXG4gIEBpZiAoZGF0ZXBpY2tlci5zaG93RGF0ZSQgfCBhc3luYykge1xuICAgIEBzd2l0Y2ggKGRhdGVwaWNrZXIubW9kZSQgfCBhc3luYykge1xuICAgICAgPCEtLSBEaXNwbGF5IGRheXMgaW4gdGhlIGN1cnJlbnQgbW9udGggLS0+XG4gICAgICBAY2FzZSAoRGF0ZVBpY2tlck1vZGUuRGF5KSB7XG4gICAgICAgIDx1eC1kYXRlLXRpbWUtcGlja2VyLWRheS12aWV3PjwvdXgtZGF0ZS10aW1lLXBpY2tlci1kYXktdmlldz5cbiAgICAgIH1cbiAgICAgIDwhLS0gRGlzcGxheSB0aGUgbW9udGhzIGluIHRoZSBjdXJyZW50IHllYXIgLS0+XG4gICAgICBAY2FzZSAoRGF0ZVBpY2tlck1vZGUuTW9udGgpIHtcbiAgICAgICAgPHV4LWRhdGUtdGltZS1waWNrZXItbW9udGgtdmlldz48L3V4LWRhdGUtdGltZS1waWNrZXItbW9udGgtdmlldz5cbiAgICAgIH1cbiAgICAgIDwhLS0gRGlzcGxheSBhIGRlY2FkZSAtLT5cbiAgICAgIEBjYXNlIChEYXRlUGlja2VyTW9kZS5ZZWFyKSB7XG4gICAgICAgIDx1eC1kYXRlLXRpbWUtcGlja2VyLXllYXItdmlldz48L3V4LWRhdGUtdGltZS1waWNrZXIteWVhci12aWV3PlxuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIDwhLS0gRGlzcGxheSBhIFRpbWUgUGlja2VyIC0tPlxuICBAaWYgKGRhdGVwaWNrZXIuc2hvd1RpbWUkIHwgYXN5bmMpIHtcbiAgICA8dXgtZGF0ZS10aW1lLXBpY2tlci10aW1lLXZpZXcgKHRpbWV6b25lQ2hhbmdlKT1cIl9vblRpbWV6b25lQ2hhbmdlKCRldmVudClcIlxuICAgID48L3V4LWRhdGUtdGltZS1waWNrZXItdGltZS12aWV3PlxuICB9XG5cbjwvZGl2PlxuXG5AaWYgKGRhdGVwaWNrZXIuc2hvd05vd0J0biQgfCBhc3luYykge1xuICA8YnV0dG9uIHR5cGU9XCJidXR0b25cIlxuICAgIHV4Rm9jdXNJbmRpY2F0b3JcbiAgICBjbGFzcz1cIm5vdy1idXR0b25cIlxuICAgIFthdHRyLmFyaWEtbGFiZWxdPVwibm93QnRuQXJpYUxhYmVsXCJcbiAgICBbZGlzYWJsZWRdPVwiX2lzVG9kYXlEaXNhYmxlZFwiXG4gICAgKGNsaWNrKT1cInNldFRvTm93KClcIj5cbiAgICB7eyBkYXRlcGlja2VyLm5vd0J0blRleHQkIHwgYXN5bmMgfX1cbiAgPC9idXR0b24+XG59Il19