@ux-aspects/ux-aspects
Version:
Open source user interface framework for building modern, responsive, mobile big data applications
302 lines • 48.3 kB
JavaScript
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, forwardRef, inject, Input, Output, ViewEncapsulation, } from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
import * as i0 from "@angular/core";
import * as i1 from "../../directives/accessibility/focus-indicator/default-focus-indicator.directive";
import * as i2 from "../spin-button/spin-button.component";
import * as i3 from "@angular/common";
export const TIME_PICKER_VALUE_ACCESSOR = {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => TimePickerComponent),
multi: true,
};
export class TimePickerComponent {
constructor() {
this._changeDetector = inject(ChangeDetectorRef);
/** Whether the arrow keys can be used to increment or decrement the selected time component. */
this.arrowkeys = true;
/** Whether the mouse scroll wheel can be used to increment or decrement the selected time component. */
this.mousewheel = true;
/** Whether the control is disabled. */
this.disabled = false;
/** Whether the control is readonly. */
this.readOnly = false;
/** Whether to show the meridian (AM/PM) selector. If this is false, the 24-hour clock will be used. */
this.showMeridian = false;
/** Whether to show the hour selector. */
this.showHours = true;
/** Whether to show the minute selector. */
this.showMinutes = true;
/** Whether to show the second selector. */
this.showSeconds = false;
/** Whether to show increment and decrement buttons in the time picker. */
this.showSpinners = true;
/** The number of hours to increment or decrement by when using the spinner buttons, arrow keys, or mouse scroll wheel. */
this.hourStep = 1;
/** The number of minutes to increment or decrement by when using the spinner buttons, arrow keys, or mouse scroll wheel. */
this.minuteStep = 1;
/** The number of seconds to increment or decrement by when using the spinner buttons, arrow keys, or mouse scroll wheel. */
this.secondStep = 1;
/** An array containing the labels to show in the meridian selector. */
this.meridians = ['AM', 'PM'];
/** Emitted when the `value` changes. */
this.valueChange = new EventEmitter();
/** Emitted when the validity of the control changes. */
this.isValid = new EventEmitter();
// eslint-disable-next-line @typescript-eslint/no-empty-function
this.onTouchedCallback = () => { };
// eslint-disable-next-line @typescript-eslint/no-empty-function
this.onChangeCallback = () => { };
this._value = new Date();
this._isValid = true;
}
/** The value to display. */
set value(value) {
this._value = new Date(value);
this.valueChange.emit(this._value);
this.onChangeCallback(this._value);
this.onTouchedCallback();
}
get value() {
return new Date(this._value);
}
get _meridian() {
return this._value.getHours() < 12 ? this.meridians[0] : this.meridians[1];
}
get _valid() {
return this.checkValidity(this._value);
}
get isValidDate() {
return this.value instanceof Date && !isNaN(this.value.getTime());
}
writeValue(value) {
this.value = value;
this._changeDetector.markForCheck();
}
registerOnChange(fn) {
this.onChangeCallback = fn;
}
registerOnTouched(fn) {
this.onTouchedCallback = fn;
}
setDisabledState(isDisabled) {
this.disabled = isDisabled;
this._changeDetector.markForCheck();
}
getMeridianTime(hour) {
return hour > 12 ? hour - 12 : hour;
}
setHour(hour) {
const date = this.value;
date.setHours(hour ? hour : 0);
this.value = date;
}
setMinute(minute) {
const date = this.value;
date.setMinutes(minute ? minute : 0);
this.value = date;
}
setSeconds(seconds) {
const date = this.value;
date.setSeconds(seconds ? seconds : 0);
this.value = date;
}
incrementHour(arrowkey = false) {
if (this.disabled || (arrowkey && !this.arrowkeys)) {
return;
}
this.setHour(this.value.getHours() + this.hourStep);
}
decrementHour(arrowkey = false) {
if (this.disabled || (arrowkey && !this.arrowkeys)) {
return;
}
this.setHour(this.value.getHours() - this.hourStep);
}
incrementMinute(arrowkey = false) {
if (this.disabled || (arrowkey && !this.arrowkeys)) {
return;
}
this.setMinute(this.value.getMinutes() + this.minuteStep);
}
decrementMinute(arrowkey = false) {
if (this.disabled || (arrowkey && !this.arrowkeys)) {
return;
}
this.setMinute(this.value.getMinutes() - this.minuteStep);
}
incrementSecond(arrowkey = false) {
if (this.disabled || (arrowkey && !this.arrowkeys)) {
return;
}
this.setSeconds(this.value.getSeconds() + this.secondStep);
}
decrementSecond(arrowkey = false) {
if (this.disabled || (arrowkey && !this.arrowkeys)) {
return;
}
this.setSeconds(this.value.getSeconds() - this.secondStep);
}
selectMeridian(meridian) {
// get the current time
const hour = this.value.getHours();
// if we have selected AM
if (meridian === this.meridians[0]) {
if (hour >= 12) {
this.setHour(hour - 12);
}
}
// if we have selected PM
if (meridian === this.meridians[1]) {
if (hour < 12) {
this.setHour(hour + 12);
}
}
}
checkValidity(date) {
let valid = true;
// Fix min and max date components in order to compare time only
const min = this.normalizeDate(this.min, date);
const max = this.normalizeDate(this.max, date);
if ((min && date.getTime() < min.getTime()) || (max && date.getTime() > max.getTime())) {
valid = false;
}
// if the valid state has changed then emit the isValid output
if (valid !== this._isValid) {
this._isValid = valid;
this.isValid.emit(valid);
}
return valid;
}
hourChange(value) {
// if the value is empty then emit nothing
if (value && typeof value === 'string' && value.trim() === '') {
return;
}
// convert the string to a number
let hour = typeof value === 'number' ? value : parseInt(value);
// ensure the hours is valid
if (!isNaN(hour)) {
if (hour < 0) {
hour = 0;
}
if (hour > (this.showMeridian ? 12 : 23)) {
hour = this.showMeridian ? 12 : 23;
}
}
const currentHour = this.value.getHours();
// if the value hasn't changed, do nothing
if (hour === currentHour) {
return;
}
hour = isNaN(hour) ? currentHour : hour;
if (this.showMeridian) {
// if the number is invalid then restore it to the previous value
if (this._meridian === this.meridians[0]) {
if (hour >= 12) {
hour -= 12;
}
}
// if we have selected PM
if (this._meridian === this.meridians[1]) {
if (hour < 12) {
hour += 12;
}
}
}
this.setHour(hour);
}
minuteChange(value) {
// convert the string to a number
let minute = typeof value === 'number' ? value : parseInt(value);
const currentMinute = this.value.getMinutes();
// if the value hasn't changed, do nothing
if (minute === currentMinute) {
return;
}
// ensure the hours is valid
if (!isNaN(minute)) {
if (minute < 0) {
minute = 59;
}
if (minute > 59) {
minute = 0;
}
}
// if the number is invalid then restore it to the previous value
this.setMinute(isNaN(minute) ? currentMinute : minute);
}
secondChange(value) {
// convert the string to a number
let second = typeof value === 'number' ? value : parseInt(value);
const currentSecond = this.value.getSeconds();
// if the value hasn't changed, do nothing
if (second === currentSecond) {
return;
}
// ensure the hours is valid
if (!isNaN(second)) {
if (second < 0) {
second = 0;
}
if (second > 59) {
second = 59;
}
}
// if the number is invalid then restore it to the previous value
this.setSeconds(isNaN(second) ? currentSecond : second);
}
/** Normalise a date's year/month/date components. */
normalizeDate(date, reference) {
if (!date) {
return null;
}
const normalized = new Date(date);
normalized.setFullYear(reference.getFullYear());
normalized.setMonth(reference.getMonth());
normalized.setDate(reference.getDate());
return normalized;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: TimePickerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.12", type: TimePickerComponent, selector: "ux-time-picker", inputs: { arrowkeys: "arrowkeys", mousewheel: "mousewheel", disabled: "disabled", readOnly: "readOnly", showMeridian: "showMeridian", showHours: "showHours", showMinutes: "showMinutes", showSeconds: "showSeconds", showSpinners: "showSpinners", hourStep: "hourStep", minuteStep: "minuteStep", secondStep: "secondStep", min: "min", max: "max", meridians: "meridians", value: "value" }, outputs: { valueChange: "valueChange", isValid: "isValid" }, providers: [TIME_PICKER_VALUE_ACCESSOR], ngImport: i0, template: "<div class=\"time-picker\">\n @if (showHours) {\n <div class=\"time-picker-column time-hours-picker\" [class.has-error]=\"!_valid\">\n <ux-spin-button\n type=\"number\"\n class=\"time-spinner\"\n placeholder=\"HH\"\n [maxLength]=\"2\"\n [min]=\"0\"\n [max]=\"showMeridian ? 12 : 23\"\n [value]=\"isValidDate ? (value | date: (showMeridian ? 'h' : 'HH')) : ''\"\n (valueChange)=\"hourChange($event)\"\n [spinners]=\"showSpinners\"\n [disabled]=\"disabled\"\n [readOnly]=\"readOnly\"\n inputAriaLabel=\"hour\"\n incrementAriaLabel=\"Increment the hour\"\n decrementAriaLabel=\"Decrement the hour\"\n (increment)=\"incrementHour()\"\n (decrement)=\"decrementHour()\"\n >\n </ux-spin-button>\n </div>\n }\n\n @if (showMinutes) {\n <div class=\"time-picker-separator\">:</div>\n }\n\n @if (showMinutes) {\n <div class=\"time-picker-column time-minutes-picker\" [class.has-error]=\"!_valid\">\n <ux-spin-button\n type=\"number\"\n class=\"time-spinner\"\n placeholder=\"MM\"\n [maxLength]=\"2\"\n [min]=\"0\"\n [max]=\"59\"\n [value]=\"isValidDate ? (value | date: 'mm') : ''\"\n (valueChange)=\"minuteChange($event)\"\n [spinners]=\"showSpinners\"\n [disabled]=\"disabled\"\n [readOnly]=\"readOnly\"\n inputAriaLabel=\"minute\"\n incrementAriaLabel=\"Increment the minute\"\n decrementAriaLabel=\"Decrement the minute\"\n (increment)=\"incrementMinute()\"\n (decrement)=\"decrementMinute()\"\n >\n </ux-spin-button>\n </div>\n }\n\n @if (showSeconds) {\n <div class=\"time-picker-separator\">:</div>\n }\n\n @if (showSeconds) {\n <div class=\"time-picker-column time-seconds-picker\" [class.has-error]=\"!_valid\">\n <ux-spin-button\n type=\"number\"\n class=\"time-spinner\"\n placeholder=\"SS\"\n [maxLength]=\"2\"\n [min]=\"0\"\n [max]=\"59\"\n [value]=\"isValidDate ? (value | date: 'ss') : ''\"\n (valueChange)=\"secondChange($event)\"\n [spinners]=\"showSpinners\"\n [disabled]=\"disabled\"\n [readOnly]=\"readOnly\"\n inputAriaLabel=\"seconds\"\n incrementAriaLabel=\"Increment the second\"\n decrementAriaLabel=\"Decrement the second\"\n (increment)=\"incrementSecond()\"\n (decrement)=\"decrementSecond()\"\n >\n </ux-spin-button>\n </div>\n }\n</div>\n\n@if (showMeridian) {\n <div class=\"time-picker-meridian\">\n <div class=\"btn-group\" role=\"radiogroup\">\n @for (meridian of meridians; track meridian) {\n <button\n type=\"button\"\n class=\"btn button-toggle-accent\"\n role=\"radio\"\n tabindex=\"0\"\n [disabled]=\"disabled\"\n (click)=\"selectMeridian(meridian)\"\n [class.active]=\"meridian === _meridian\"\n [attr.aria-label]=\"meridian\"\n [attr.aria-checked]=\"meridian === _meridian\"\n [attr.aria-disabled]=\"disabled\"\n >\n {{ meridian }}\n </button>\n }\n </div>\n </div>\n}\n", dependencies: [{ kind: "directive", type: i1.DefaultFocusIndicatorDirective, selector: ".btn:not([uxFocusIndicator]):not([uxMenuNavigationToggle]):not([uxMenuTriggerFor]), a[href]:not([uxFocusIndicator]):not([uxMenuNavigationToggle]):not([uxMenuTriggerFor])" }, { 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: "pipe", type: i3.DatePipe, name: "date" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: TimePickerComponent, decorators: [{
type: Component,
args: [{ selector: 'ux-time-picker', encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, providers: [TIME_PICKER_VALUE_ACCESSOR], template: "<div class=\"time-picker\">\n @if (showHours) {\n <div class=\"time-picker-column time-hours-picker\" [class.has-error]=\"!_valid\">\n <ux-spin-button\n type=\"number\"\n class=\"time-spinner\"\n placeholder=\"HH\"\n [maxLength]=\"2\"\n [min]=\"0\"\n [max]=\"showMeridian ? 12 : 23\"\n [value]=\"isValidDate ? (value | date: (showMeridian ? 'h' : 'HH')) : ''\"\n (valueChange)=\"hourChange($event)\"\n [spinners]=\"showSpinners\"\n [disabled]=\"disabled\"\n [readOnly]=\"readOnly\"\n inputAriaLabel=\"hour\"\n incrementAriaLabel=\"Increment the hour\"\n decrementAriaLabel=\"Decrement the hour\"\n (increment)=\"incrementHour()\"\n (decrement)=\"decrementHour()\"\n >\n </ux-spin-button>\n </div>\n }\n\n @if (showMinutes) {\n <div class=\"time-picker-separator\">:</div>\n }\n\n @if (showMinutes) {\n <div class=\"time-picker-column time-minutes-picker\" [class.has-error]=\"!_valid\">\n <ux-spin-button\n type=\"number\"\n class=\"time-spinner\"\n placeholder=\"MM\"\n [maxLength]=\"2\"\n [min]=\"0\"\n [max]=\"59\"\n [value]=\"isValidDate ? (value | date: 'mm') : ''\"\n (valueChange)=\"minuteChange($event)\"\n [spinners]=\"showSpinners\"\n [disabled]=\"disabled\"\n [readOnly]=\"readOnly\"\n inputAriaLabel=\"minute\"\n incrementAriaLabel=\"Increment the minute\"\n decrementAriaLabel=\"Decrement the minute\"\n (increment)=\"incrementMinute()\"\n (decrement)=\"decrementMinute()\"\n >\n </ux-spin-button>\n </div>\n }\n\n @if (showSeconds) {\n <div class=\"time-picker-separator\">:</div>\n }\n\n @if (showSeconds) {\n <div class=\"time-picker-column time-seconds-picker\" [class.has-error]=\"!_valid\">\n <ux-spin-button\n type=\"number\"\n class=\"time-spinner\"\n placeholder=\"SS\"\n [maxLength]=\"2\"\n [min]=\"0\"\n [max]=\"59\"\n [value]=\"isValidDate ? (value | date: 'ss') : ''\"\n (valueChange)=\"secondChange($event)\"\n [spinners]=\"showSpinners\"\n [disabled]=\"disabled\"\n [readOnly]=\"readOnly\"\n inputAriaLabel=\"seconds\"\n incrementAriaLabel=\"Increment the second\"\n decrementAriaLabel=\"Decrement the second\"\n (increment)=\"incrementSecond()\"\n (decrement)=\"decrementSecond()\"\n >\n </ux-spin-button>\n </div>\n }\n</div>\n\n@if (showMeridian) {\n <div class=\"time-picker-meridian\">\n <div class=\"btn-group\" role=\"radiogroup\">\n @for (meridian of meridians; track meridian) {\n <button\n type=\"button\"\n class=\"btn button-toggle-accent\"\n role=\"radio\"\n tabindex=\"0\"\n [disabled]=\"disabled\"\n (click)=\"selectMeridian(meridian)\"\n [class.active]=\"meridian === _meridian\"\n [attr.aria-label]=\"meridian\"\n [attr.aria-checked]=\"meridian === _meridian\"\n [attr.aria-disabled]=\"disabled\"\n >\n {{ meridian }}\n </button>\n }\n </div>\n </div>\n}\n" }]
}], propDecorators: { arrowkeys: [{
type: Input
}], mousewheel: [{
type: Input
}], disabled: [{
type: Input
}], readOnly: [{
type: Input
}], showMeridian: [{
type: Input
}], showHours: [{
type: Input
}], showMinutes: [{
type: Input
}], showSeconds: [{
type: Input
}], showSpinners: [{
type: Input
}], hourStep: [{
type: Input
}], minuteStep: [{
type: Input
}], secondStep: [{
type: Input
}], min: [{
type: Input
}], max: [{
type: Input
}], meridians: [{
type: Input
}], value: [{
type: Input
}], valueChange: [{
type: Output
}], isValid: [{
type: Output
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGltZS1waWNrZXIuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL2NvbXBvbmVudHMvdGltZS1waWNrZXIvdGltZS1waWNrZXIuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vc3JjL2NvbXBvbmVudHMvdGltZS1waWNrZXIvdGltZS1waWNrZXIuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUNMLHVCQUF1QixFQUN2QixpQkFBaUIsRUFDakIsU0FBUyxFQUNULFlBQVksRUFDWixVQUFVLEVBQ1YsTUFBTSxFQUNOLEtBQUssRUFDTCxNQUFNLEVBQ04saUJBQWlCLEdBQ2xCLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBd0IsaUJBQWlCLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQzs7Ozs7QUFFekUsTUFBTSxDQUFDLE1BQU0sMEJBQTBCLEdBQUc7SUFDeEMsT0FBTyxFQUFFLGlCQUFpQjtJQUMxQixXQUFXLEVBQUUsVUFBVSxDQUFDLEdBQUcsRUFBRSxDQUFDLG1CQUFtQixDQUFDO0lBQ2xELEtBQUssRUFBRSxJQUFJO0NBQ1osQ0FBQztBQVNGLE1BQU0sT0FBTyxtQkFBbUI7SUFQaEM7UUFRbUIsb0JBQWUsR0FBRyxNQUFNLENBQUMsaUJBQWlCLENBQUMsQ0FBQztRQUU3RCxnR0FBZ0c7UUFDdkYsY0FBUyxHQUFZLElBQUksQ0FBQztRQUVuQyx3R0FBd0c7UUFDL0YsZUFBVSxHQUFZLElBQUksQ0FBQztRQUVwQyx1Q0FBdUM7UUFDOUIsYUFBUSxHQUFZLEtBQUssQ0FBQztRQUVuQyx1Q0FBdUM7UUFDOUIsYUFBUSxHQUFZLEtBQUssQ0FBQztRQUVuQyx1R0FBdUc7UUFDOUYsaUJBQVksR0FBWSxLQUFLLENBQUM7UUFFdkMseUNBQXlDO1FBQ2hDLGNBQVMsR0FBWSxJQUFJLENBQUM7UUFFbkMsMkNBQTJDO1FBQ2xDLGdCQUFXLEdBQVksSUFBSSxD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RGV0ZWN0b3JSZWYsXG4gIENvbXBvbmVudCxcbiAgRXZlbnRFbWl0dGVyLFxuICBmb3J3YXJkUmVmLFxuICBpbmplY3QsXG4gIElucHV0LFxuICBPdXRwdXQsXG4gIFZpZXdFbmNhcHN1bGF0aW9uLFxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IENvbnRyb2xWYWx1ZUFjY2Vzc29yLCBOR19WQUxVRV9BQ0NFU1NPUiB9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcblxuZXhwb3J0IGNvbnN0IFRJTUVfUElDS0VSX1ZBTFVFX0FDQ0VTU09SID0ge1xuICBwcm92aWRlOiBOR19WQUxVRV9BQ0NFU1NPUixcbiAgdXNlRXhpc3Rpbmc6IGZvcndhcmRSZWYoKCkgPT4gVGltZVBpY2tlckNvbXBvbmVudCksXG4gIG11bHRpOiB0cnVlLFxufTtcblxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAndXgtdGltZS1waWNrZXInLFxuICB0ZW1wbGF0ZVVybDogJy4vdGltZS1waWNrZXIuY29tcG9uZW50Lmh0bWwnLFxuICBlbmNhcHN1bGF0aW9uOiBWaWV3RW5jYXBzdWxhdGlvbi5Ob25lLFxuICBjaGFuZ2VEZXRlY3Rpb246IENoYW5nZURldGVjdGlvblN0cmF0ZWd5Lk9uUHVzaCxcbiAgcHJvdmlkZXJzOiBbVElNRV9QSUNLRVJfVkFMVUVfQUNDRVNTT1JdLFxufSlcbmV4cG9ydCBjbGFzcyBUaW1lUGlja2VyQ29tcG9uZW50IGltcGxlbWVudHMgQ29udHJvbFZhbHVlQWNjZXNzb3Ige1xuICBwcml2YXRlIHJlYWRvbmx5IF9jaGFuZ2VEZXRlY3RvciA9IGluamVjdChDaGFuZ2VEZXRlY3RvclJlZik7XG5cbiAgLyoqIFdoZXRoZXIgdGhlIGFycm93IGtleXMgY2FuIGJlIHVzZWQgdG8gaW5jcmVtZW50IG9yIGRlY3JlbWVudCB0aGUgc2VsZWN0ZWQgdGltZSBjb21wb25lbnQuICovXG4gIEBJbnB1dCgpIGFycm93a2V5czogYm9vbGVhbiA9IHRydWU7XG5cbiAgLyoqIFdoZXRoZXIgdGhlIG1vdXNlIHNjcm9sbCB3aGVlbCBjYW4gYmUgdXNlZCB0byBpbmNyZW1lbnQgb3IgZGVjcmVtZW50IHRoZSBzZWxlY3RlZCB0aW1lIGNvbXBvbmVudC4gKi9cbiAgQElucHV0KCkgbW91c2V3aGVlbDogYm9vbGVhbiA9IHRydWU7XG5cbiAgLyoqIFdoZXRoZXIgdGhlIGNvbnRyb2wgaXMgZGlzYWJsZWQuICovXG4gIEBJbnB1dCgpIGRpc2FibGVkOiBib29sZWFuID0gZmFsc2U7XG5cbiAgLyoqIFdoZXRoZXIgdGhlIGNvbnRyb2wgaXMgcmVhZG9ubHkuICovXG4gIEBJbnB1dCgpIHJlYWRPbmx5OiBib29sZWFuID0gZmFsc2U7XG5cbiAgLyoqIFdoZXRoZXIgdG8gc2hvdyB0aGUgbWVyaWRpYW4gKEFNL1BNKSBzZWxlY3Rvci4gSWYgdGhpcyBpcyBmYWxzZSwgdGhlIDI0LWhvdXIgY2xvY2sgd2lsbCBiZSB1c2VkLiAqL1xuICBASW5wdXQoKSBzaG93TWVyaWRpYW46IGJvb2xlYW4gPSBmYWxzZTtcblxuICAvKiogV2hldGhlciB0byBzaG93IHRoZSBob3VyIHNlbGVjdG9yLiAqL1xuICBASW5wdXQoKSBzaG93SG91cnM6IGJvb2xlYW4gPSB0cnVlO1xuXG4gIC8qKiBXaGV0aGVyIHRvIHNob3cgdGhlIG1pbnV0ZSBzZWxlY3Rvci4gKi9cbiAgQElucHV0KCkgc2hvd01pbnV0ZXM6IGJvb2xlYW4gPSB0cnVlO1xuXG4gIC8qKiBXaGV0aGVyIHRvIHNob3cgdGhlIHNlY29uZCBzZWxlY3Rvci4gKi9cbiAgQElucHV0KCkgc2hvd1NlY29uZHM6IGJvb2xlYW4gPSBmYWxzZTtcblxuICAvKiogV2hldGhlciB0byBzaG93IGluY3JlbWVudCBhbmQgZGVjcmVtZW50IGJ1dHRvbnMgaW4gdGhlIHRpbWUgcGlja2VyLiAqL1xuICBASW5wdXQoKSBzaG93U3Bpbm5lcnM6IGJvb2xlYW4gPSB0cnVlO1xuXG4gIC8qKiBUaGUgbnVtYmVyIG9mIGhvdXJzIHRvIGluY3JlbWVudCBvciBkZWNyZW1lbnQgYnkgd2hlbiB1c2luZyB0aGUgc3Bpbm5lciBidXR0b25zLCBhcnJvdyBrZXlzLCBvciBtb3VzZSBzY3JvbGwgd2hlZWwuICovXG4gIEBJbnB1dCgpIGhvdXJTdGVwOiBudW1iZXIgPSAxO1xuXG4gIC8qKiBUaGUgbnVtYmVyIG9mIG1pbnV0ZXMgdG8gaW5jcmVtZW50IG9yIGRlY3JlbWVudCBieSB3aGVuIHVzaW5nIHRoZSBzcGlubmVyIGJ1dHRvbnMsIGFycm93IGtleXMsIG9yIG1vdXNlIHNjcm9sbCB3aGVlbC4gKi9cbiAgQElucHV0KCkgbWludXRlU3RlcDogbnVtYmVyID0gMTtcblxuICAvKiogVGhlIG51bWJlciBvZiBzZWNvbmRzIHRvIGluY3JlbWVudCBvciBkZWNyZW1lbnQgYnkgd2hlbiB1c2luZyB0aGUgc3Bpbm5lciBidXR0b25zLCBhcnJvdyBrZXlzLCBvciBtb3VzZSBzY3JvbGwgd2hlZWwuICovXG4gIEBJbnB1dCgpIHNlY29uZFN0ZXA6IG51bWJlciA9IDE7XG5cbiAgLyoqIFRoZSBtaW5pbXVtIHZhbHVlIHRoYXQgdGhlIGNvbXBvbmVudCB3aWxsIGFsbG93LiAqL1xuICBASW5wdXQoKSBtaW46IERhdGU7XG5cbiAgLyoqIFRoZSBtYXhpbXVtIHZhbHVlIHRoYXQgdGhlIGNvbXBvbmVudCB3aWxsIGFsbG93LiAqL1xuICBASW5wdXQoKSBtYXg6IERhdGU7XG5cbiAgLyoqIEFuIGFycmF5IGNvbnRhaW5pbmcgdGhlIGxhYmVscyB0byBzaG93IGluIHRoZSBtZXJpZGlhbiBzZWxlY3Rvci4gKi9cbiAgQElucHV0KCkgbWVyaWRpYW5zOiBzdHJpbmdbXSA9IFsnQU0nLCAnUE0nXTtcblxuICAvKiogVGhlIHZhbHVlIHRvIGRpc3BsYXkuICovXG4gIEBJbnB1dCgpIHNldCB2YWx1ZSh2YWx1ZTogRGF0ZSkge1xuICAgIHRoaXMuX3ZhbHVlID0gbmV3IERhdGUodmFsdWUpO1xuICAgIHRoaXMudmFsdWVDaGFuZ2UuZW1pdCh0aGlzLl92YWx1ZSk7XG5cbiAgICB0aGlzLm9uQ2hhbmdlQ2FsbGJhY2sodGhpcy5fdmFsdWUpO1xuICAgIHRoaXMub25Ub3VjaGVkQ2FsbGJhY2soKTtcbiAgfVxuXG4gIGdldCB2YWx1ZSgpOiBEYXRlIHtcbiAgICByZXR1cm4gbmV3IERhdGUodGhpcy5fdmFsdWUpO1xuICB9XG5cbiAgZ2V0IF9tZXJpZGlhbigpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLl92YWx1ZS5nZXRIb3VycygpIDwgMTIgPyB0aGlzLm1lcmlkaWFuc1swXSA6IHRoaXMubWVyaWRpYW5zWzFdO1xuICB9XG5cbiAgZ2V0IF92YWxpZCgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5jaGVja1ZhbGlkaXR5KHRoaXMuX3ZhbHVlKTtcbiAgfVxuXG4gIC8qKiBFbWl0dGVkIHdoZW4gdGhlIGB2YWx1ZWAgY2hhbmdlcy4gKi9cbiAgQE91dHB1dCgpIHZhbHVlQ2hhbmdlID0gbmV3IEV2ZW50RW1pdHRlcjxEYXRlPigpO1xuXG4gIC8qKiBFbWl0dGVkIHdoZW4gdGhlIHZhbGlkaXR5IG9mIHRoZSBjb250cm9sIGNoYW5nZXMuICovXG4gIEBPdXRwdXQoKSBpc1ZhbGlkID0gbmV3IEV2ZW50RW1pdHRlcjxib29sZWFuPigpO1xuXG4gIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tZW1wdHktZnVuY3Rpb25cbiAgb25Ub3VjaGVkQ2FsbGJhY2s6ICgpID0+IHZvaWQgPSAoKSA9PiB7fTtcbiAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby1lbXB0eS1mdW5jdGlvblxuICBvbkNoYW5nZUNhbGxiYWNrOiAoXzogRGF0ZSkgPT4gdm9pZCA9ICgpID0+IHt9O1xuXG4gIHByaXZhdGUgX3ZhbHVlID0gbmV3IERhdGUoKTtcbiAgcHJpdmF0ZSBfaXNWYWxpZDogYm9vbGVhbiA9IHRydWU7XG5cbiAgcHJvdGVjdGVkIGdldCBpc1ZhbGlkRGF0ZSgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy52YWx1ZSBpbnN0YW5jZW9mIERhdGUgJiYgIWlzTmFOKHRoaXMudmFsdWUuZ2V0VGltZSgpKTtcbiAgfVxuXG4gIHdyaXRlVmFsdWUodmFsdWU6IERhdGUpOiB2b2lkIHtcbiAgICB0aGlzLnZhbHVlID0gdmFsdWU7XG4gICAgdGhpcy5fY2hhbmdlRGV0ZWN0b3IubWFya0ZvckNoZWNrKCk7XG4gIH1cblxuICByZWdpc3Rlck9uQ2hhbmdlKGZuOiAoXzogRGF0ZSkgPT4gdm9pZCk6IHZvaWQge1xuICAgIHRoaXMub25DaGFuZ2VDYWxsYmFjayA9IGZuO1xuICB9XG5cbiAgcmVnaXN0ZXJPblRvdWNoZWQoZm46ICgpID0+IHZvaWQpOiB2b2lkIHtcbiAgICB0aGlzLm9uVG91Y2hlZENhbGxiYWNrID0gZm47XG4gIH1cblxuICBzZXREaXNhYmxlZFN0YXRlKGlzRGlzYWJsZWQ6IGJvb2xlYW4pOiB2b2lkIHtcbiAgICB0aGlzLmRpc2FibGVkID0gaXNEaXNhYmxlZDtcbiAgICB0aGlzLl9jaGFuZ2VEZXRlY3Rvci5tYXJrRm9yQ2hlY2soKTtcbiAgfVxuXG4gIGdldE1lcmlkaWFuVGltZShob3VyOiBudW1iZXIpOiBudW1iZXIge1xuICAgIHJldHVybiBob3VyID4gMTIgPyBob3VyIC0gMTIgOiBob3VyO1xuICB9XG5cbiAgc2V0SG91cihob3VyOiBudW1iZXIpOiB2b2lkIHtcbiAgICBjb25zdCBkYXRlID0gdGhpcy52YWx1ZTtcbiAgICBkYXRlLnNldEhvdXJzKGhvdXIgPyBob3VyIDogMCk7XG5cbiAgICB0aGlzLnZhbHVlID0gZGF0ZTtcbiAgfVxuXG4gIHNldE1pbnV0ZShtaW51dGU6IG51bWJlcik6IHZvaWQge1xuICAgIGNvbnN0IGRhdGUgPSB0aGlzLnZhbHVlO1xuICAgIGRhdGUuc2V0TWludXRlcyhtaW51dGUgPyBtaW51dGUgOiAwKTtcblxuICAgIHRoaXMudmFsdWUgPSBkYXRlO1xuICB9XG5cbiAgc2V0U2Vjb25kcyhzZWNvbmRzOiBudW1iZXIpOiB2b2lkIHtcbiAgICBjb25zdCBkYXRlID0gdGhpcy52YWx1ZTtcbiAgICBkYXRlLnNldFNlY29uZHMoc2Vjb25kcyA/IHNlY29uZHMgOiAwKTtcblxuICAgIHRoaXMudmFsdWUgPSBkYXRlO1xuICB9XG5cbiAgaW5jcmVtZW50SG91cihhcnJvd2tleTogYm9vbGVhbiA9IGZhbHNlKTogdm9pZCB7XG4gICAgaWYgKHRoaXMuZGlzYWJsZWQgfHwgKGFycm93a2V5ICYmICF0aGlzLmFycm93a2V5cykpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB0aGlzLnNldEhvdXIodGhpcy52YWx1ZS5nZXRIb3VycygpICsgdGhpcy5ob3VyU3RlcCk7XG4gIH1cblxuICBkZWNyZW1lbnRIb3VyKGFycm93a2V5OiBib29sZWFuID0gZmFsc2UpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5kaXNhYmxlZCB8fCAoYXJyb3drZXkgJiYgIXRoaXMuYXJyb3drZXlzKSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHRoaXMuc2V0SG91cih0aGlzLnZhbHVlLmdldEhvdXJzKCkgLSB0aGlzLmhvdXJTdGVwKTtcbiAgfVxuXG4gIGluY3JlbWVudE1pbnV0ZShhcnJvd2tleTogYm9vbGVhbiA9IGZhbHNlKTogdm9pZCB7XG4gICAgaWYgKHRoaXMuZGlzYWJsZWQgfHwgKGFycm93a2V5ICYmICF0aGlzLmFycm93a2V5cykpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB0aGlzLnNldE1pbnV0ZSh0aGlzLnZhbHVlLmdldE1pbnV0ZXMoKSArIHRoaXMubWludXRlU3RlcCk7XG4gIH1cblxuICBkZWNyZW1lbnRNaW51dGUoYXJyb3drZXk6IGJvb2xlYW4gPSBmYWxzZSk6IHZvaWQge1xuICAgIGlmICh0aGlzLmRpc2FibGVkIHx8IChhcnJvd2tleSAmJiAhdGhpcy5hcnJvd2tleXMpKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdGhpcy5zZXRNaW51dGUodGhpcy52YWx1ZS5nZXRNaW51dGVzKCkgLSB0aGlzLm1pbnV0ZVN0ZXApO1xuICB9XG5cbiAgaW5jcmVtZW50U2Vjb25kKGFycm93a2V5OiBib29sZWFuID0gZmFsc2UpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5kaXNhYmxlZCB8fCAoYXJyb3drZXkgJiYgIXRoaXMuYXJyb3drZXlzKSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHRoaXMuc2V0U2Vjb25kcyh0aGlzLnZhbHVlLmdldFNlY29uZHMoKSArIHRoaXMuc2Vjb25kU3RlcCk7XG4gIH1cblxuICBkZWNyZW1lbnRTZWNvbmQoYXJyb3drZXk6IGJvb2xlYW4gPSBmYWxzZSk6IHZvaWQge1xuICAgIGlmICh0aGlzLmRpc2FibGVkIHx8IChhcnJvd2tleSAmJiAhdGhpcy5hcnJvd2tleXMpKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdGhpcy5zZXRTZWNvbmRzKHRoaXMudmFsdWUuZ2V0U2Vjb25kcygpIC0gdGhpcy5zZWNvbmRTdGVwKTtcbiAgfVxuXG4gIHNlbGVjdE1lcmlkaWFuKG1lcmlkaWFuOiBzdHJpbmcpOiB2b2lkIHtcbiAgICAvLyBnZXQgdGhlIGN1cnJlbnQgdGltZVxuICAgIGNvbnN0IGhvdXIgPSB0aGlzLnZhbHVlLmdldEhvdXJzKCk7XG5cbiAgICAvLyBpZiB3ZSBoYXZlIHNlbGVjdGVkIEFNXG4gICAgaWYgKG1lcmlkaWFuID09PSB0aGlzLm1lcmlkaWFuc1swXSkge1xuICAgICAgaWYgKGhvdXIgPj0gMTIpIHtcbiAgICAgICAgdGhpcy5zZXRIb3VyKGhvdXIgLSAxMik7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gaWYgd2UgaGF2ZSBzZWxlY3RlZCBQTVxuICAgIGlmIChtZXJpZGlhbiA9PT0gdGhpcy5tZXJpZGlhbnNbMV0pIHtcbiAgICAgIGlmIChob3VyIDwgMTIpIHtcbiAgICAgICAgdGhpcy5zZXRIb3VyKGhvdXIgKyAxMik7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgY2hlY2tWYWxpZGl0eShkYXRlOiBEYXRlKTogYm9vbGVhbiB7XG4gICAgbGV0IHZhbGlkID0gdHJ1ZTtcblxuICAgIC8vIEZpeCBtaW4gYW5kIG1heCBkYXRlIGNvbXBvbmVudHMgaW4gb3JkZXIgdG8gY29tcGFyZSB0aW1lIG9ubHlcbiAgICBjb25zdCBtaW4gPSB0aGlzLm5vcm1hbGl6ZURhdGUodGhpcy5taW4sIGRhdGUpO1xuICAgIGNvbnN0IG1heCA9IHRoaXMubm9ybWFsaXplRGF0ZSh0aGlzLm1heCwgZGF0ZSk7XG5cbiAgICBpZiAoKG1pbiAmJiBkYXRlLmdldFRpbWUoKSA8IG1pbi5nZXRUaW1lKCkpIHx8IChtYXggJiYgZGF0ZS5nZXRUaW1lKCkgPiBtYXguZ2V0VGltZSgpKSkge1xuICAgICAgdmFsaWQgPSBmYWxzZTtcbiAgICB9XG5cbiAgICAvLyBpZiB0aGUgdmFsaWQgc3RhdGUgaGFzIGNoYW5nZWQgdGhlbiBlbWl0IHRoZSBpc1ZhbGlkIG91dHB1dFxuICAgIGlmICh2YWxpZCAhPT0gdGhpcy5faXNWYWxpZCkge1xuICAgICAgdGhpcy5faXNWYWxpZCA9IHZhbGlkO1xuICAgICAgdGhpcy5pc1ZhbGlkLmVtaXQodmFsaWQpO1xuICAgIH1cblxuICAgIHJldHVybiB2YWxpZDtcbiAgfVxuXG4gIGhvdXJDaGFuZ2UodmFsdWU6IHN0cmluZyB8IG51bWJlcik6IHZvaWQge1xuICAgIC8vIGlmIHRoZSB2YWx1ZSBpcyBlbXB0eSB0aGVuIGVtaXQgbm90aGluZ1xuICAgIGlmICh2YWx1ZSAmJiB0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnICYmIHZhbHVlLnRyaW0oKSA9PT0gJycpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyBjb252ZXJ0IHRoZSBzdHJpbmcgdG8gYSBudW1iZXJcbiAgICBsZXQgaG91ciA9IHR5cGVvZiB2YWx1ZSA9PT0gJ251bWJlcicgPyB2YWx1ZSA6IHBhcnNlSW50KHZhbHVlKTtcblxuICAgIC8vIGVuc3VyZSB0aGUgaG91cnMgaXMgdmFsaWRcbiAgICBpZiAoIWlzTmFOKGhvdXIpKSB7XG4gICAgICBpZiAoaG91ciA8IDApIHtcbiAgICAgICAgaG91ciA9IDA7XG4gICAgICB9XG5cbiAgICAgIGlmIChob3VyID4gKHRoaXMuc2hvd01lcmlkaWFuID8gMTIgOiAyMykpIHtcbiAgICAgICAgaG91ciA9IHRoaXMuc2hvd01lcmlkaWFuID8gMTIgOiAyMztcbiAgICAgIH1cbiAgICB9XG5cbiAgICBjb25zdCBjdXJyZW50SG91ciA9IHRoaXMudmFsdWUuZ2V0SG91cnMoKTtcblxuICAgIC8vIGlmIHRoZSB2YWx1ZSBoYXNuJ3QgY2hhbmdlZCwgZG8gbm90aGluZ1xuICAgIGlmIChob3VyID09PSBjdXJyZW50SG91cikge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGhvdXIgPSBpc05hTihob3VyKSA/IGN1cnJlbnRIb3VyIDogaG91cjtcblxuICAgIGlmICh0aGlzLnNob3dNZXJpZGlhbikge1xuICAgICAgLy8gaWYgdGhlIG51bWJlciBpcyBpbnZhbGlkIHRoZW4gcmVzdG9yZSBpdCB0byB0aGUgcHJldmlvdXMgdmFsdWVcbiAgICAgIGlmICh0aGlzLl9tZXJpZGlhbiA9PT0gdGhpcy5tZXJpZGlhbnNbMF0pIHtcbiAgICAgICAgaWYgKGhvdXIgPj0gMTIpIHtcbiAgICAgICAgICBob3VyIC09IDEyO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIC8vIGlmIHdlIGhhdmUgc2VsZWN0ZWQgUE1cbiAgICAgIGlmICh0aGlzLl9tZXJpZGlhbiA9PT0gdGhpcy5tZXJpZGlhbnNbMV0pIHtcbiAgICAgICAgaWYgKGhvdXIgPCAxMikge1xuICAgICAgICAgIGhvdXIgKz0gMTI7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICB0aGlzLnNldEhvdXIoaG91cik7XG4gIH1cblxuICBtaW51dGVDaGFuZ2UodmFsdWU6IHN0cmluZyB8IG51bWJlcik6IHZvaWQge1xuICAgIC8vIGNvbnZlcnQgdGhlIHN0cmluZyB0byBhIG51bWJlclxuICAgIGxldCBtaW51dGUgPSB0eXBlb2YgdmFsdWUgPT09ICdudW1iZXInID8gdmFsdWUgOiBwYXJzZUludCh2YWx1ZSk7XG4gICAgY29uc3QgY3VycmVudE1pbnV0ZSA9IHRoaXMudmFsdWUuZ2V0TWludXRlcygpO1xuXG4gICAgLy8gaWYgdGhlIHZhbHVlIGhhc24ndCBjaGFuZ2VkLCBkbyBub3RoaW5nXG4gICAgaWYgKG1pbnV0ZSA9PT0gY3VycmVudE1pbnV0ZSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIGVuc3VyZSB0aGUgaG91cnMgaXMgdmFsaWRcbiAgICBpZiAoIWlzTmFOKG1pbnV0ZSkpIHtcbiAgICAgIGlmIChtaW51dGUgPCAwKSB7XG4gICAgICAgIG1pbnV0ZSA9IDU5O1xuICAgICAgfVxuXG4gICAgICBpZiAobWludXRlID4gNTkpIHtcbiAgICAgICAgbWludXRlID0gMDtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBpZiB0aGUgbnVtYmVyIGlzIGludmFsaWQgdGhlbiByZXN0b3JlIGl0IHRvIHRoZSBwcmV2aW91cyB2YWx1ZVxuICAgIHRoaXMuc2V0TWludXRlKGlzTmFOKG1pbnV0ZSkgPyBjdXJyZW50TWludXRlIDogbWludXRlKTtcbiAgfVxuXG4gIHNlY29uZENoYW5nZSh2YWx1ZTogc3RyaW5nIHwgbnVtYmVyKTogdm9pZCB7XG4gICAgLy8gY29udmVydCB0aGUgc3RyaW5nIHRvIGEgbnVtYmVyXG4gICAgbGV0IHNlY29uZCA9IHR5cGVvZiB2YWx1ZSA9PT0gJ251bWJlcicgPyB2YWx1ZSA6IHBhcnNlSW50KHZhbHVlKTtcbiAgICBjb25zdCBjdXJyZW50U2Vjb25kID0gdGhpcy52YWx1ZS5nZXRTZWNvbmRzKCk7XG5cbiAgICAvLyBpZiB0aGUgdmFsdWUgaGFzbid0IGNoYW5nZWQsIGRvIG5vdGhpbmdcbiAgICBpZiAoc2Vjb25kID09PSBjdXJyZW50U2Vjb25kKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgLy8gZW5zdXJlIHRoZSBob3VycyBpcyB2YWxpZFxuICAgIGlmICghaXNOYU4oc2Vjb25kKSkge1xuICAgICAgaWYgKHNlY29uZCA8IDApIHtcbiAgICAgICAgc2Vjb25kID0gMDtcbiAgICAgIH1cblxuICAgICAgaWYgKHNlY29uZCA+IDU5KSB7XG4gICAgICAgIHNlY29uZCA9IDU5O1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIGlmIHRoZSBudW1iZXIgaXMgaW52YWxpZCB0aGVuIHJlc3RvcmUgaXQgdG8gdGhlIHByZXZpb3VzIHZhbHVlXG4gICAgdGhpcy5zZXRTZWNvbmRzKGlzTmFOKHNlY29uZCkgPyBjdXJyZW50U2Vjb25kIDogc2Vjb25kKTtcbiAgfVxuXG4gIC8qKiBOb3JtYWxpc2UgYSBkYXRlJ3MgeWVhci9tb250aC9kYXRlIGNvbXBvbmVudHMuICovXG4gIHByaXZhdGUgbm9ybWFsaXplRGF0ZShkYXRlOiBEYXRlLCByZWZlcmVuY2U6IERhdGUpOiBEYXRlIHtcbiAgICBpZiAoIWRhdGUpIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIGNvbnN0IG5vcm1hbGl6ZWQgPSBuZXcgRGF0ZShkYXRlKTtcbiAgICBub3JtYWxpemVkLnNldEZ1bGxZZWFyKHJlZmVyZW5jZS5nZXRGdWxsWWVhcigpKTtcbiAgICBub3JtYWxpemVkLnNldE1vbnRoKHJlZmVyZW5jZS5nZXRNb250aCgpKTtcbiAgICBub3JtYWxpemVkLnNldERhdGUocmVmZXJlbmNlLmdldERhdGUoKSk7XG5cbiAgICByZXR1cm4gbm9ybWFsaXplZDtcbiAgfVxufVxuIiwiPGRpdiBjbGFzcz1cInRpbWUtcGlja2VyXCI+XG4gIEBpZiAoc2hvd0hvdXJzKSB7XG4gICAgPGRpdiBjbGFzcz1cInRpbWUtcGlja2VyLWNvbHVtbiB0aW1lLWhvdXJzLXBpY2tlclwiIFtjbGFzcy5oYXMtZXJyb3JdPVwiIV92YWxpZFwiPlxuICAgICAgPHV4LXNwaW4tYnV0dG9uXG4gICAgICAgIHR5cGU9XCJudW1iZXJcIlxuICAgICAgICBjbGFzcz1cInRpbWUtc3Bpbm5lclwiXG4gICAgICAgIHBsYWNlaG9sZGVyPVwiSEhcIlxuICAgICAgICBbbWF4TGVuZ3RoXT1cIjJcIlxuICAgICAgICBbbWluXT1cIjBcIlxuICAgICAgICBbbWF4XT1cInNob3dNZXJpZGlhbiA/IDEyIDogMjNcIlxuICAgICAgICBbdmFsdWVdPVwiaXNWYWxpZERhdGUgPyAodmFsdWUgfCBkYXRlOiAoc2hvd01lcmlkaWFuID8gJ2gnIDogJ0hIJykpIDogJydcIlxuICAgICAgICAodmFsdWVDaGFuZ2UpPVwiaG91ckNoYW5nZSgkZXZlbnQpXCJcbiAgICAgICAgW3NwaW5uZXJzXT1cInNob3dTcGlubmVyc1wiXG4gICAgICAgIFtkaXNhYmxlZF09XCJkaXNhYmxlZFwiXG4gICAgICAgIFtyZWFkT25seV09XCJyZWFkT25seVwiXG4gICAgICAgIGlucHV0QXJpYUxhYmVsPVwiaG91clwiXG4gICAgICAgIGluY3JlbWVudEFyaWFMYWJlbD1cIkluY3JlbWVudCB0aGUgaG91clwiXG4gICAgICAgIGRlY3JlbWVudEFyaWFMYWJlbD1cIkRlY3JlbWVudCB0aGUgaG91clwiXG4gICAgICAgIChpbmNyZW1lbnQpPVwiaW5jcmVtZW50SG91cigpXCJcbiAgICAgICAgKGRlY3JlbWVudCk9XCJkZWNyZW1lbnRIb3VyKClcIlxuICAgICAgPlxuICAgICAgPC91eC1zcGluLWJ1dHRvbj5cbiAgICA8L2Rpdj5cbiAgfVxuXG4gIEBpZiAoc2hvd01pbnV0ZXMpIHtcbiAgICA8ZGl2IGNsYXNzPVwidGltZS1waWNrZXItc2VwYXJhdG9yXCI+OjwvZGl2PlxuICB9XG5cbiAgQGlmIChzaG93TWludXRlcykge1xuICAgIDxkaXYgY2xhc3M9XCJ0aW1lLXBpY2tlci1jb2x1bW4gdGltZS1taW51dGVzLXBpY2tlclwiIFtjbGFzcy5oYXMtZXJyb3JdPVwiIV92YWxpZFwiPlxuICAgICAgPHV4LXNwaW4tYnV0dG9uXG4gICAgICAgIHR5cGU9XCJudW1iZXJcIlxuICAgICAgICBjbGFzcz1cInRpbWUtc3Bpbm5lclwiXG4gICAgICAgIHBsYWNlaG9sZGVyPVwiTU1cIlxuICAgICAgICBbbWF4TGVuZ3RoXT1cIjJcIlxuICAgICAgICBbbWluXT1cIjBcIlxuICAgICAgICBbbWF4XT1cIjU5XCJcbiAgICAgICAgW3ZhbHVlXT1cImlzVmFsaWREYXRlID8gKHZhbHVlIHwgZGF0ZTogJ21tJykgOiAnJ1wiXG4gICAgICAgICh2YWx1ZUNoYW5nZSk9XCJtaW51dGVDaGFuZ2UoJGV2ZW50KVwiXG4gICAgICAgIFtzcGlubmVyc109XCJzaG93U3Bpbm5lcnNcIlxuICAgICAgICBbZGlzYWJsZWRdPVwiZGlzYWJsZWRcIlxuICAgICAgICBbcmVhZE9ubHldPVwicmVhZE9ubHlcIlxuICAgICAgICBpbnB1dEFyaWFMYWJlbD1cIm1pbnV0ZVwiXG4gICAgICAgIGluY3JlbWVudEFyaWFMYWJlbD1cIkluY3JlbWVudCB0aGUgbWludXRlXCJcbiAgICAgICAgZGVjcmVtZW50QXJpYUxhYmVsPVwiRGVjcmVtZW50IHRoZSBtaW51dGVcIlxuICAgICAgICAoaW5jcmVtZW50KT1cImluY3JlbWVudE1pbnV0ZSgpXCJcbiAgICAgICAgKGRlY3JlbWVudCk9XCJkZWNyZW1lbnRNaW51dGUoKVwiXG4gICAgICA+XG4gICAgICA8L3V4LXNwaW4tYnV0dG9uPlxuICAgIDwvZGl2PlxuICB9XG5cbiAgQGlmIChzaG93U2Vjb25kcykge1xuICAgIDxkaXYgY2xhc3M9XCJ0aW1lLXBpY2tlci1zZXBhcmF0b3JcIj46PC9kaXY+XG4gIH1cblxuICBAaWYgKHNob3dTZWNvbmRzKSB7XG4gICAgPGRpdiBjbGFzcz1cInRpbWUtcGlja2VyLWNvbHVtbiB0aW1lLXNlY29uZHMtcGlja2VyXCIgW2NsYXNzLmhhcy1lcnJvcl09XCIhX3ZhbGlkXCI+XG4gICAgICA8dXgtc3Bpbi1idXR0b25cbiAgICAgICAgdHlwZT1cIm51bWJlclwiXG4gICAgICAgIGNsYXNzPVwidGltZS1zcGlubmVyXCJcbiAgICAgICAgcGxhY2Vob2xkZXI9XCJTU1wiXG4gICAgICAgIFttYXhMZW5ndGhdPVwiMlwiXG4gICAgICAgIFttaW5dPVwiMFwiXG4gICAgICAgIFttYXhdPVwiNTlcIlxuICAgICAgICBbdmFsdWVdPVwiaXNWYWxpZERhdGUgPyAodmFsdWUgfCBkYXRlOiAnc3MnKSA6ICcnXCJcbiAgICAgICAgKHZhbHVlQ2hhbmdlKT1cInNlY29uZENoYW5nZSgkZXZlbnQpXCJcbiAgICAgICAgW3NwaW5uZXJzXT1cInNob3dTcGlubmVyc1wiXG4gICAgICAgIFtkaXNhYmxlZF09XCJkaXNhYmxlZFwiXG4gICAgICAgIFtyZWFkT25seV09XCJyZWFkT25seVwiXG4gICAgICAgIGlucHV0QXJpYUxhYmVsPVwic2Vjb25kc1wiXG4gICAgICAgIGluY3JlbWVudEFyaWFMYWJlbD1cIkluY3JlbWVudCB0aGUgc2Vjb25kXCJcbiAgICAgICAgZGVjcmVtZW50QXJpYUxhYmVsPVwiRGVjcmVtZW50IHRoZSBzZWNvbmRcIlxuICAgICAgICAoaW5jcmVtZW50KT1cImluY3JlbWVudFNlY29uZCgpXCJcbiAgICAgICAgKGRlY3JlbWVudCk9XCJkZWNyZW1lbnRTZWNvbmQoKVwiXG4gICAgICA+XG4gICAgICA8L3V4LXNwaW4tYnV0dG9uPlxuICAgIDwvZGl2PlxuICB9XG48L2Rpdj5cblxuQGlmIChzaG93TWVyaWRpYW4pIHtcbiAgPGRpdiBjbGFzcz1cInRpbWUtcGlja2VyLW1lcmlkaWFuXCI+XG4gICAgPGRpdiBjbGFzcz1cImJ0bi1ncm91cFwiIHJvbGU9XCJyYWRpb2dyb3VwXCI+XG4gICAgICBAZm9yIChtZXJpZGlhbiBvZiBtZXJpZGlhbnM7IHRyYWNrIG1lcmlkaWFuKSB7XG4gICAgICAgIDxidXR0b25cbiAgICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgICBjbGFzcz1cImJ0biBidXR0b24tdG9nZ2xlLWFjY2VudFwiXG4gICAgICAgICAgcm9sZT1cInJhZGlvXCJcbiAgICAgICAgICB0YWJpbmRleD1cIjBcIlxuICAgICAgICAgIFtkaXNhYmxlZF09XCJkaXNhYmxlZFwiXG4gICAgICAgICAgKGNsaWNrKT1cInNlbGVjdE1lcmlkaWFuKG1lcmlkaWFuKVwiXG4gICAgICAgICAgW2NsYXNzLmFjdGl2ZV09XCJtZXJpZGlhbiA9PT0gX21lcmlkaWFuXCJcbiAgICAgICAgICBbYXR0ci5hcmlhLWxhYmVsXT1cIm1lcmlkaWFuXCJcbiAgICAgICAgICBbYXR0ci5hcmlhLWNoZWNrZWRdPVwibWVyaWRpYW4gPT09IF9tZXJpZGlhblwiXG4gICAgICAgICAgW2F0dHIuYXJpYS1kaXNhYmxlZF09XCJkaXNhYmxlZFwiXG4gICAgICAgID5cbiAgICAgICAgICB7eyBtZXJpZGlhbiB9fVxuICAgICAgICA8L2J1dHRvbj5cbiAgICAgIH1cbiAgICA8L2Rpdj5cbiAgPC9kaXY+XG59XG4iXX0=