gentics-ui-core
Version:
This is the common core framework for the Gentics CMS and Mesh UI, and other Angular applications.
358 lines • 57.9 kB
JavaScript
import { Component, ElementRef, EventEmitter, HostBinding, Input, Optional, Output, ViewChild } from '@angular/core';
import { NEVER, of as observableOf } from 'rxjs';
import { concat } from 'rxjs/operators';
import { coerceToBoolean } from '../../common/coerce-to-boolean';
import { defaultStrings } from './date-time-picker-default-strings';
import { DateTimePickerFormatProvider } from './date-time-picker-format-provider.service';
import { momentjs } from '../../common/momentjs.import';
import { rome } from '../../common/rome.import';
import * as i0 from "@angular/core";
import * as i1 from "./date-time-picker-format-provider.service";
import * as i2 from "../select/select.component";
import * as i3 from "../input/input.component";
import * as i4 from "@angular/common";
import * as i5 from "@angular/forms";
import * as i6 from "../select/option.component";
// http://ecma-international.org/ecma-262/5.1/#sec-15.9.1.1
const MAX_DATE_MILLISECONDS = 8640000000000000;
/**
* The controls (calendar view, year & time inputs) powering the `DateTimePicker` component. Can be used as a stand-alone component.
*/
export class DateTimePickerControls {
constructor(defaultFormatProvider) {
this.defaultFormatProvider = defaultFormatProvider;
/**
* Emits the unix timestamp of the current value on changes.
*/
this.change = new EventEmitter();
this.dateOrder = 'mdy';
this.years = [];
this._selectYear = false;
this._disabled = false;
this._displayTime = false;
this._displaySeconds = false;
this._compact = false;
/** @internal */
this.value = momentjs();
/** @internal */
this.time = {
h: 0,
m: 0,
s: 0
};
}
/**
* If true, the year may be selected from a Select control
*/
set selectYear(val) {
this._selectYear = coerceToBoolean(val);
}
get selectYear() { return this._selectYear; }
/**
* Set to `true` to disable the input field and not show the date picker on click.
*/
set disabled(val) {
this._disabled = coerceToBoolean(val);
}
get disabled() { return this._disabled; }
/**
* Set to `false` to omit the time picker part of the component. Defaults to `true`
*/
set displayTime(val) {
this._displayTime = coerceToBoolean(val);
}
get displayTime() { return this._displayTime; }
/**
* Set to `false` to omit the seconds of the time picker part. Defaults to `true`
*/
set displaySeconds(val) {
this._displaySeconds = coerceToBoolean(val);
}
get displaySeconds() { return this._displaySeconds; }
/**
* When `true`, the controls use the "compact" (small screen) styling for all screen sizes. Defaults to `false`
*/
set compact(val) {
this._compact = coerceToBoolean(val);
}
get compact() { return this._compact; }
ngOnInit() {
if (this.defaultFormatProvider == null) {
this.defaultFormatProvider = new DateTimePickerFormatProvider();
}
if (this.formatProvider == null) {
this.formatProvider = this.defaultFormatProvider;
}
this.value = momentjs.unix(Number(this.timestamp));
this.setupProviderChangeHook();
this.min = this.min instanceof Date ? this.min : new Date(-MAX_DATE_MILLISECONDS);
this.max = this.max instanceof Date ? this.max : new Date(MAX_DATE_MILLISECONDS);
// We don't want a date select which is stupidly long
const MAX_YEAR_RANGE = 500;
let minYear = this.min.getFullYear();
let maxYear = this.max.getFullYear();
const thisYear = new Date().getFullYear();
if (MAX_YEAR_RANGE < maxYear - minYear) {
minYear = thisYear - Math.floor(MAX_YEAR_RANGE / 2);
maxYear = thisYear + Math.floor(MAX_YEAR_RANGE / 2);
}
for (let year = minYear; year <= maxYear; year++) {
this.years.push(year);
}
}
ngOnChanges(changes) {
if (changes['timestamp']) {
this.value = momentjs.unix(Number(this.timestamp));
this.updateTimeObject(this.value);
if (this.cal) {
this.cal.setValue(this.value);
}
}
if (changes['min']) {
const currentValue = changes['min'].currentValue;
if (currentValue && !(changes['min'].currentValue instanceof Date)) {
throw new Error(`min must be a Date object. Got ${typeof changes['min'].currentValue}`);
}
}
if (changes['max']) {
const currentValue = changes['max'].currentValue;
if (currentValue && !(changes['max'].currentValue instanceof Date)) {
throw new Error(`max must be a Date object. Got ${typeof changes['max'].currentValue}`);
}
}
if (changes['formatProvider'] && !changes['formatProvider'].firstChange) {
this.setupProviderChangeHook();
}
}
/**
* Initialize the Rome widget instance.
*/
ngAfterViewInit() {
let calendarEl = this.calendarContainer.nativeElement;
this.cal = rome(calendarEl, this.getRomeConfig())
.on('data', () => {
this.value = this.cal.getMoment();
this.change.emit(this.value.unix());
});
}
ngOnDestroy() {
if (this.cal) {
this.cal.off('data');
this.cal.destroy();
this.cal = undefined;
}
if (this.subscription) {
this.subscription.unsubscribe();
}
}
getRomeConfig() {
const romeConfig = {
appendTo: this.calendarContainer.nativeElement,
time: false,
initialValue: this.value
};
if (this.min) {
romeConfig.min = this.min;
}
if (this.max) {
romeConfig.max = this.max;
}
if (this.value != null) {
romeConfig.weekdayFormat = this.value.localeData().weekdaysMin();
romeConfig.weekStart = this.value.localeData().firstDayOfWeek();
}
return romeConfig;
}
setupProviderChangeHook() {
// Unsubscribe from the old subscription
if (this.subscription != null) {
this.subscription.unsubscribe();
}
// Update strings and date format when format provider emits a change
this.subscription = observableOf(1)
.pipe(concat(this.formatProvider.changed$ || NEVER))
.subscribe(() => {
this.value.locale(this.getMomentLocale());
this.updateTimeObject(this.value);
// When the locale changes, re-initialize the calendar to update the
// weekdays as these are only updated when initialized.
if (this.cal != null) {
this.cal.options(this.getRomeConfig());
this.cal.show();
}
this.determineDateOrder();
});
}
/**
* Update the this.value in accordance with the input of one of the
* time fields (h, m, s).
*/
updateTime(unit, value) {
const newValue = this.updateByUnits(this.value.clone(), unit, value);
if (newValue.isBefore(this.min) || newValue.isAfter(this.max)) {
// the new year is out of the allowed range
return;
}
this.updateByUnits(this.value, unit, value);
this.updateTimeObject(this.value);
this.updateCalendar(this.value);
}
/**
* Handler for the incrementing the time values when up or down arrows are pressed.
*/
timeKeyHandler(unit, e) {
// UP arrow key
if (e.keyCode === 38) {
e.preventDefault();
this.incrementTime(unit);
}
// DOWN arrow key
if (e.keyCode === 40) {
e.preventDefault();
this.decrementTime(unit);
}
}
incrementTime(unit) {
this.addToTime(unit, 1);
}
decrementTime(unit) {
this.addToTime(unit, -1);
}
formatWith(formatString) {
return this.value.format(formatString);
}
getUnixTimestamp() {
return this.value.unix();
}
setYear(year) {
const newValue = this.value.clone().year(year);
if (newValue.isBefore(this.min) || newValue.isAfter(this.max)) {
// the new year is out of the allowed range
return;
}
this.value.year(year);
this.updateCalendar(this.value);
}
updateByUnits(moment, unit, value) {
switch (unit) {
case 'hours':
moment.hour(value);
break;
case 'minutes':
moment.minute(value);
break;
case 'seconds':
moment.second(value);
break;
default:
}
return moment;
}
/**
* Create a momentjs locale from the (possibly localized) strings.
* @internal
*/
getMomentLocale() {
const localeStrings = this.formatProvider.strings;
const momentLocales = DateTimePickerControls.momentLocales;
for (let [strings, locale] of momentLocales) {
if (strings === localeStrings) {
return locale;
}
}
const newLocale = momentjs.locale('x-gtx-date-picker-' + momentLocales.length, {
months: localeStrings.months,
monthsShort: localeStrings.monthsShort ||
(localeStrings.months &&
localeStrings.months.map(month => month.substr(0, 3))),
weekdays: localeStrings.weekdays,
weekdaysMin: localeStrings.weekdaysMin ||
(localeStrings.weekdays &&
localeStrings.weekdays.map(weekday => weekday.substr(0, 2)))
});
momentLocales.push([localeStrings, newLocale]);
return newLocale;
}
determineDateOrder() {
// Stringify 1999-08-22 with the dateProvider to determine the date order (D-M-Y, M-D-Y or Y-M-D).
const time = this.formatProvider.format(momentjs(935272800000), false, false);
const yearPos = time.indexOf('99');
const monthPos = time.indexOf('8');
const dayPos = time.indexOf('22');
if (dayPos < monthPos && monthPos < yearPos) {
this.dateOrder = 'dmy';
}
else if (monthPos < dayPos) {
this.dateOrder = 'mdy';
}
else {
this.dateOrder = 'ymd';
}
}
/**
* Increment or decrement the value and update the time object.
*/
addToTime(unit, increment) {
const newValue = this.value.clone().add(increment, unit);
if (newValue.isBefore(this.min) || newValue.isAfter(this.max)) {
// the new time is out of the allowed range
return;
}
this.value.add(increment, unit);
this.updateTimeObject(this.value);
this.updateCalendar(this.value);
}
/**
* Update the time object based on the value of this.value.
*/
updateTimeObject(date) {
this.time.h = date.hour();
this.time.m = date.minute();
this.time.s = date.second();
}
/**
* Update the Rome calendar widget with the current value.
*/
updateCalendar(value) {
if (this.cal) {
this.cal.setValue(value);
this.change.emit(value.unix());
}
}
}
DateTimePickerControls.momentLocales = [[defaultStrings, 'en']];
/** @nocollapse */ DateTimePickerControls.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: DateTimePickerControls, deps: [{ token: i1.DateTimePickerFormatProvider, optional: true }], target: i0.ɵɵFactoryTarget.Component });
/** @nocollapse */ DateTimePickerControls.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.8", type: DateTimePickerControls, selector: "gtx-date-time-picker-controls", inputs: { timestamp: "timestamp", formatProvider: "formatProvider", min: "min", max: "max", selectYear: "selectYear", disabled: "disabled", displayTime: "displayTime", displaySeconds: "displaySeconds", compact: "compact" }, outputs: { change: "change" }, host: { properties: { "class.compact": "this._compact" } }, viewQueries: [{ propertyName: "calendarContainer", first: true, predicate: ["calendarContainer"], descendants: true, static: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"controls-header\">\n <div class=\"day\">{{ formatWith('dddd') }}</div>\n <div class=\"year\" *ngIf=\"!selectYear && dateOrder === 'ymd'\">{{ formatWith('YYYY') }}</div>\n <div class=\"month\" *ngIf=\"dateOrder !== 'dmy'\">{{ formatWith('MMM') }}</div>\n <div class=\"date\">{{ formatWith('D') }}</div>\n <div class=\"month\" *ngIf=\"dateOrder === 'dmy'\">{{ formatWith('MMM') }}</div>\n <div class=\"year\" *ngIf=\"!selectYear && dateOrder !== 'ymd'\">{{ formatWith('YYYY') }}</div>\n <div *ngIf=\"selectYear\" class=\"year-selector\">\n <gtx-select (change)=\"setYear($event)\" [ngModel]=\"value.year()\">\n <gtx-option *ngFor=\"let year of years\" [value]=\"year\">{{ year }}</gtx-option>\n </gtx-select>\n </div>\n</div>\n<div class=\"controls-content\">\n <div #calendarContainer class=\"calendar-container\"></div>\n <div class=\"time-picker\" *ngIf=\"displayTime\">\n <div class=\"row\">\n <div class=\"column hours\" [ngClass]=\"displaySeconds ? 'small-4' : 'small-6'\">\n <button class=\"increment-button\" (click)=\"incrementTime('hours')\"><i class=\"material-icons\">arrow_drop_up</i></button>\n <gtx-input [(ngModel)]=\"time.h\"\n [label]=\"formatProvider.strings.hours\"\n (blur)=\"updateTime('hours', time.h)\"\n (keydown)=\"timeKeyHandler('hours', $event)\"\n type=\"number\"\n min=\"0\"\n max=\"23\"></gtx-input>\n <button class=\"increment-button\" (click)=\"decrementTime('hours')\"><i class=\"material-icons\">arrow_drop_down</i></button>\n </div>\n <div class=\"column minutes\" [ngClass]=\"displaySeconds ? 'small-4' : 'small-6'\">\n <button class=\"increment-button\" (click)=\"incrementTime('minutes')\"><i class=\"material-icons\">arrow_drop_up</i></button>\n <gtx-input [(ngModel)]=\"time.m\"\n [label]=\"formatProvider.strings.minutes\"\n (blur)=\"updateTime('minutes', time.m)\"\n (keydown)=\"timeKeyHandler('minutes', $event)\"\n type=\"number\"\n min=\"0\"\n max=\"59\"></gtx-input>\n <button class=\"increment-button\" (click)=\"decrementTime('minutes')\"><i class=\"material-icons\">arrow_drop_down</i></button>\n </div>\n <div class=\"column seconds small-4\" *ngIf=\"displaySeconds\">\n <button class=\"increment-button\" (click)=\"incrementTime('seconds')\"><i class=\"material-icons\">arrow_drop_up</i></button>\n <gtx-input [(ngModel)]=\"time.s\"\n [label]=\"formatProvider.strings.seconds\"\n (blur)=\"updateTime('seconds', time.s)\"\n (keydown)=\"timeKeyHandler('seconds', $event)\"\n type=\"number\"\n min=\"0\"\n max=\"59\"></gtx-input>\n <button class=\"increment-button\" (click)=\"decrementTime('seconds')\"><i class=\"material-icons\">arrow_drop_down</i></button>\n </div>\n </div>\n </div>\n</div>\n", components: [{ type: i2.Select, selector: "gtx-select", inputs: ["autofocus", "clearable", "disabled", "multiple", "required", "value", "placeholder", "label"], outputs: ["blur", "focus", "change"] }, { type: i3.InputField, selector: "gtx-input", inputs: ["autocomplete", "autofocus", "disabled", "id", "label", "max", "min", "maxlength", "name", "pattern", "placeholder", "readonly", "required", "step", "type", "value"], outputs: ["blur", "focus", "change"] }], directives: [{ type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i5.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i5.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { type: i4.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i6.SelectOption, selector: "gtx-option", inputs: ["icon", "value", "disabled"] }, { type: i4.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: DateTimePickerControls, decorators: [{
type: Component,
args: [{ selector: 'gtx-date-time-picker-controls', template: "<div class=\"controls-header\">\n <div class=\"day\">{{ formatWith('dddd') }}</div>\n <div class=\"year\" *ngIf=\"!selectYear && dateOrder === 'ymd'\">{{ formatWith('YYYY') }}</div>\n <div class=\"month\" *ngIf=\"dateOrder !== 'dmy'\">{{ formatWith('MMM') }}</div>\n <div class=\"date\">{{ formatWith('D') }}</div>\n <div class=\"month\" *ngIf=\"dateOrder === 'dmy'\">{{ formatWith('MMM') }}</div>\n <div class=\"year\" *ngIf=\"!selectYear && dateOrder !== 'ymd'\">{{ formatWith('YYYY') }}</div>\n <div *ngIf=\"selectYear\" class=\"year-selector\">\n <gtx-select (change)=\"setYear($event)\" [ngModel]=\"value.year()\">\n <gtx-option *ngFor=\"let year of years\" [value]=\"year\">{{ year }}</gtx-option>\n </gtx-select>\n </div>\n</div>\n<div class=\"controls-content\">\n <div #calendarContainer class=\"calendar-container\"></div>\n <div class=\"time-picker\" *ngIf=\"displayTime\">\n <div class=\"row\">\n <div class=\"column hours\" [ngClass]=\"displaySeconds ? 'small-4' : 'small-6'\">\n <button class=\"increment-button\" (click)=\"incrementTime('hours')\"><i class=\"material-icons\">arrow_drop_up</i></button>\n <gtx-input [(ngModel)]=\"time.h\"\n [label]=\"formatProvider.strings.hours\"\n (blur)=\"updateTime('hours', time.h)\"\n (keydown)=\"timeKeyHandler('hours', $event)\"\n type=\"number\"\n min=\"0\"\n max=\"23\"></gtx-input>\n <button class=\"increment-button\" (click)=\"decrementTime('hours')\"><i class=\"material-icons\">arrow_drop_down</i></button>\n </div>\n <div class=\"column minutes\" [ngClass]=\"displaySeconds ? 'small-4' : 'small-6'\">\n <button class=\"increment-button\" (click)=\"incrementTime('minutes')\"><i class=\"material-icons\">arrow_drop_up</i></button>\n <gtx-input [(ngModel)]=\"time.m\"\n [label]=\"formatProvider.strings.minutes\"\n (blur)=\"updateTime('minutes', time.m)\"\n (keydown)=\"timeKeyHandler('minutes', $event)\"\n type=\"number\"\n min=\"0\"\n max=\"59\"></gtx-input>\n <button class=\"increment-button\" (click)=\"decrementTime('minutes')\"><i class=\"material-icons\">arrow_drop_down</i></button>\n </div>\n <div class=\"column seconds small-4\" *ngIf=\"displaySeconds\">\n <button class=\"increment-button\" (click)=\"incrementTime('seconds')\"><i class=\"material-icons\">arrow_drop_up</i></button>\n <gtx-input [(ngModel)]=\"time.s\"\n [label]=\"formatProvider.strings.seconds\"\n (blur)=\"updateTime('seconds', time.s)\"\n (keydown)=\"timeKeyHandler('seconds', $event)\"\n type=\"number\"\n min=\"0\"\n max=\"59\"></gtx-input>\n <button class=\"increment-button\" (click)=\"decrementTime('seconds')\"><i class=\"material-icons\">arrow_drop_down</i></button>\n </div>\n </div>\n </div>\n</div>\n" }]
}], ctorParameters: function () { return [{ type: i1.DateTimePickerFormatProvider, decorators: [{
type: Optional
}] }]; }, propDecorators: { timestamp: [{
type: Input
}], formatProvider: [{
type: Input
}], min: [{
type: Input
}], max: [{
type: Input
}], selectYear: [{
type: Input
}], disabled: [{
type: Input
}], displayTime: [{
type: Input
}], displaySeconds: [{
type: Input
}], compact: [{
type: Input
}], change: [{
type: Output
}], calendarContainer: [{
type: ViewChild,
args: ['calendarContainer', { static: true }]
}], _compact: [{
type: HostBinding,
args: ['class.compact']
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGF0ZS10aW1lLXBpY2tlci1jb250cm9scy5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvY29tcG9uZW50cy9kYXRlLXRpbWUtcGlja2VyL2RhdGUtdGltZS1waWNrZXItY29udHJvbHMuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vc3JjL2NvbXBvbmVudHMvZGF0ZS10aW1lLXBpY2tlci9kYXRlLXRpbWUtcGlja2VyLWNvbnRyb2xzLnRwbC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFDSCxTQUFTLEVBQ1QsVUFBVSxFQUNWLFlBQVksRUFDWixXQUFXLEVBQ1gsS0FBSyxFQUVMLFFBQVEsRUFDUixNQUFNLEVBRU4sU0FBUyxFQUNaLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBQyxLQUFLLEVBQUUsRUFBRSxJQUFJLFlBQVksRUFBZSxNQUFNLE1BQU0sQ0FBQztBQUM3RCxPQUFPLEVBQUMsTUFBTSxFQUFDLE1BQU0sZ0JBQWdCLENBQUM7QUFFdEMsT0FBTyxFQUFDLGVBQWUsRUFBQyxNQUFNLGdDQUFnQyxDQUFDO0FBQy9ELE9BQU8sRUFBQyxjQUFjLEVBQUMsTUFBTSxvQ0FBb0MsQ0FBQztBQUNsRSxPQUFPLEVBQUMsNEJBQTRCLEVBQUMsTUFBTSw0Q0FBNEMsQ0FBQztBQUV4RixPQUFPLEVBQUMsUUFBUSxFQUFTLE1BQU0sOEJBQThCLENBQUM7QUFDOUQsT0FBTyxFQUFDLElBQUksRUFBQyxNQUFNLDBCQUEwQixDQUFDOzs7Ozs7OztBQUU5QywyREFBMkQ7QUFDM0QsTUFBTSxxQkFBcUIsR0FBRyxnQkFBZ0IsQ0FBQztBQUkvQzs7R0FFRztBQUtILE1BQU0sT0FBTyxzQkFBc0I7SUFvRy9CLFlBQWdDLHFCQUFtRDtRQUFuRCwwQkFBcUIsR0FBckIscUJBQXFCLENBQThCO1FBcENuRjs7V0FFRztRQUNPLFdBQU0sR0FBRyxJQUFJLFlBQVksRUFBVSxD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QmEsc0JBQXNCO2tCQUpsQyxTQUFTOytCQUNJLCtCQUErQjs7MEJBdUc1QixRQUFROzRDQTdGWixTQUFTO3NCQUFqQixLQUFLO2dCQUtHLGNBQWM7c0JBQXRCLEtBQUs7Z0JBS0csR0FBRztzQkFBWCxLQUFLO2dCQUtHLEdBQUc7c0JBQVgsS0FBSztnQkFLTyxVQUFVO3NCQUF0QixLQUFLO2dCQVFPLFFBQVE7c0JBQXBCLEtBQUs7Z0JBUU8sV0FBVztzQkFBdkIsS0FBSztnQkFRTyxjQUFjO3NCQUExQixLQUFLO2dCQVFPLE9BQU87c0JBQW5CLEtBQUs7Z0JBUUksTUFBTTtzQkFBZixNQUFNO2dCQUdQLGlCQUFpQjtzQkFEaEIsU0FBUzt1QkFBQyxtQkFBbUIsRUFBRSxFQUFFLE1BQU0sRUFBRSxJQUFJLEVBQUU7Z0JBWWhELFFBQVE7c0JBRFAsV0FBVzt1QkFBQyxlQUFlIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgICBDb21wb25lbnQsXG4gICAgRWxlbWVudFJlZixcbiAgICBFdmVudEVtaXR0ZXIsXG4gICAgSG9zdEJpbmRpbmcsXG4gICAgSW5wdXQsXG4gICAgT25EZXN0cm95LFxuICAgIE9wdGlvbmFsLFxuICAgIE91dHB1dCxcbiAgICBTaW1wbGVDaGFuZ2VzLFxuICAgIFZpZXdDaGlsZFxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7TkVWRVIsIG9mIGFzIG9ic2VydmFibGVPZiwgU3Vic2NyaXB0aW9ufSBmcm9tICdyeGpzJztcbmltcG9ydCB7Y29uY2F0fSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5cbmltcG9ydCB7Y29lcmNlVG9Cb29sZWFufSBmcm9tICcuLi8uLi9jb21tb24vY29lcmNlLXRvLWJvb2xlYW4nO1xuaW1wb3J0IHtkZWZhdWx0U3RyaW5nc30gZnJvbSAnLi9kYXRlLXRpbWUtcGlja2VyLWRlZmF1bHQtc3RyaW5ncyc7XG5pbXBvcnQge0RhdGVUaW1lUGlja2VyRm9ybWF0UHJvdmlkZXJ9IGZyb20gJy4vZGF0ZS10aW1lLXBpY2tlci1mb3JtYXQtcHJvdmlkZXIuc2VydmljZSc7XG5pbXBvcnQge0RhdGVUaW1lUGlja2VyU3RyaW5nc30gZnJvbSAnLi9kYXRlLXRpbWUtcGlja2VyLXN0cmluZ3MnO1xuaW1wb3J0IHttb21lbnRqcywgTW9tZW50fSBmcm9tICcuLi8uLi9jb21tb24vbW9tZW50anMuaW1wb3J0JztcbmltcG9ydCB7cm9tZX0gZnJvbSAnLi4vLi4vY29tbW9uL3JvbWUuaW1wb3J0JzsgXG5cbi8vIGh0dHA6Ly9lY21hLWludGVybmF0aW9uYWwub3JnL2VjbWEtMjYyLzUuMS8jc2VjLTE1LjkuMS4xXG5jb25zdCBNQVhfREFURV9NSUxMSVNFQ09ORFMgPSA4NjQwMDAwMDAwMDAwMDAwO1xuXG5leHBvcnQgdHlwZSBUaW1lVW5pdCA9ICdob3VycycgfCAnbWludXRlcycgfCAnc2Vjb25kcyc7XG5cbi8qKlxuICogVGhlIGNvbnRyb2xzIChjYWxlbmRhciB2aWV3LCB5ZWFyICYgdGltZSBpbnB1dHMpIHBvd2VyaW5nIHRoZSBgRGF0ZVRpbWVQaWNrZXJgIGNvbXBvbmVudC4gQ2FuIGJlIHVzZWQgYXMgYSBzdGFuZC1hbG9uZSBjb21wb25lbnQuXG4gKi9cbkBDb21wb25lbnQoe1xuICAgIHNlbGVjdG9yOiAnZ3R4LWRhdGUtdGltZS1waWNrZXItY29udHJvbHMnLFxuICAgIHRlbXBsYXRlVXJsOiAnLi9kYXRlLXRpbWUtcGlja2VyLWNvbnRyb2xzLnRwbC5odG1sJ1xufSlcbmV4cG9ydCBjbGFzcyBEYXRlVGltZVBpY2tlckNvbnRyb2xzIGltcGxlbWVudHMgT25EZXN0cm95IHtcblxuICAgIHByaXZhdGUgc3RhdGljIG1vbWVudExvY2FsZXM6IFtEYXRlVGltZVBpY2tlclN0cmluZ3MsIHN0cmluZ11bXSA9IFtbZGVmYXVsdFN0cmluZ3MsICdlbiddXTtcblxuICAgIC8qKlxuICAgICAqIFRoZSBkYXRlL3RpbWUgdmFsdWUgYXMgYSB1bml4IHRpbWVzdGFtcCAoaW4gc2Vjb25kcylcbiAgICAgKi9cbiAgICBASW5wdXQoKSB0aW1lc3RhbXA6IG51bWJlcjtcblxuICAgIC8qKlxuICAgICAqIFNldCB0byBvdmVyd3JpdGUgdGV4dHMgYW5kIGRhdGUgZm9ybWF0dGluZyBpbiB0aGUgbW9kYWwuXG4gICAgICovXG4gICAgQElucHV0KCkgZm9ybWF0UHJvdmlkZXI6IERhdGVUaW1lUGlja2VyRm9ybWF0UHJvdmlkZXI7XG5cbiAgICAvKipcbiAgICAgKiBUaGUgbWluaW11bSBkYXRlIGFsbG93YWJsZS4gRS5nLiBgbmV3IERhdGUoMjAxNSwgMiwgMTIpYFxuICAgICAqL1xuICAgIEBJbnB1dCgpIG1pbjogRGF0ZTtcblxuICAgIC8qKlxuICAgICAqIFRoZSBtYXhpbXVtIGRhdGUgYWxsb3dhYmxlLiBFLmcuIGBuZXcgRGF0ZSgyMDMxLCAxLCAzMClgXG4gICAgICovXG4gICAgQElucHV0KCkgbWF4OiBEYXRlO1xuXG4gICAgLyoqXG4gICAgICogSWYgdHJ1ZSwgdGhlIHllYXIgbWF5IGJlIHNlbGVjdGVkIGZyb20gYSBTZWxlY3QgY29udHJvbFxuICAgICAqL1xuICAgIEBJbnB1dCgpIHNldCBzZWxlY3RZZWFyKHZhbDogYW55KSB7XG4gICAgICAgIHRoaXMuX3NlbGVjdFllYXIgPSBjb2VyY2VUb0Jvb2xlYW4odmFsKTtcbiAgICB9XG4gICAgZ2V0IHNlbGVjdFllYXIoKTogYW55IHsgcmV0dXJuIHRoaXMuX3NlbGVjdFllYXI7IH1cblxuICAgIC8qKlxuICAgICAqIFNldCB0byBgdHJ1ZWAgdG8gZGlzYWJsZSB0aGUgaW5wdXQgZmllbGQgYW5kIG5vdCBzaG93IHRoZSBkYXRlIHBpY2tlciBvbiBjbGljay5cbiAgICAgKi9cbiAgICBASW5wdXQoKSBzZXQgZGlzYWJsZWQodmFsOiBhbnkpIHtcbiAgICAgICAgdGhpcy5fZGlzYWJsZWQgPSBjb2VyY2VUb0Jvb2xlYW4odmFsKTtcbiAgICB9XG4gICAgZ2V0IGRpc2FibGVkKCk6IGFueSB7IHJldHVybiB0aGlzLl9kaXNhYmxlZDsgfVxuXG4gICAgLyoqXG4gICAgICogU2V0IHRvIGBmYWxzZWAgdG8gb21pdCB0aGUgdGltZSBwaWNrZXIgcGFydCBvZiB0aGUgY29tcG9uZW50LiBEZWZhdWx0cyB0byBgdHJ1ZWBcbiAgICAgKi9cbiAgICBASW5wdXQoKSBzZXQgZGlzcGxheVRpbWUodmFsOiBhbnkpIHtcbiAgICAgICAgdGhpcy5fZGlzcGxheVRpbWUgPSBjb2VyY2VUb0Jvb2xlYW4odmFsKTtcbiAgICB9XG4gICAgZ2V0IGRpc3BsYXlUaW1lKCk6IGFueSB7IHJldHVybiB0aGlzLl9kaXNwbGF5VGltZTsgfVxuXG4gICAgLyoqXG4gICAgICogU2V0IHRvIGBmYWxzZWAgdG8gb21pdCB0aGUgc2Vjb25kcyBvZiB0aGUgdGltZSBwaWNrZXIgcGFydC4gRGVmYXVsdHMgdG8gYHRydWVgXG4gICAgICovXG4gICAgQElucHV0KCkgc2V0IGRpc3BsYXlTZWNvbmRzKHZhbDogYW55KSB7XG4gICAgICAgIHRoaXMuX2Rpc3BsYXlTZWNvbmRzID0gY29lcmNlVG9Cb29sZWFuKHZhbCk7XG4gICAgfVxuICAgIGdldCBkaXNwbGF5U2Vjb25kcygpOiBhbnkgeyByZXR1cm4gdGhpcy5fZGlzcGxheVNlY29uZHM7IH1cblxuICAgIC8qKlxuICAgICAqIFdoZW4gYHRydWVgLCB0aGUgY29udHJvbHMgdXNlIHRoZSBcImNvbXBhY3RcIiAoc21hbGwgc2NyZWVuKSBzdHlsaW5nIGZvciBhbGwgc2NyZWVuIHNpemVzLiBEZWZhdWx0cyB0byBgZmFsc2VgXG4gICAgICovXG4gICAgQElucHV0KCkgc2V0IGNvbXBhY3QodmFsOiBhbnkpIHtcbiAgICAgICAgdGhpcy5fY29tcGFjdCA9IGNvZXJjZVRvQm9vbGVhbih2YWwpO1xuICAgIH1cbiAgICBnZXQgY29tcGFjdCgpOiBhbnkgeyByZXR1cm4gdGhpcy5fY29tcGFjdDsgfVxuXG4gICAgLyoqXG4gICAgICogRW1pdHMgdGhlIHVuaXggdGltZXN0YW1wIG9mIHRoZSBjdXJyZW50IHZhbHVlIG9uIGNoYW5nZXMuXG4gICAgICovXG4gICAgQE91dHB1dCgpIGNoYW5nZSA9IG5ldyBFdmVudEVtaXR0ZXI8bnVtYmVyPigpO1xuXG4gICAgQFZpZXdDaGlsZCgnY2FsZW5kYXJDb250YWluZXInLCB7IHN0YXRpYzogdHJ1ZSB9KVxuICAgIGNhbGVuZGFyQ29udGFpbmVyOiBFbGVtZW50UmVmO1xuXG4gICAgZGF0ZU9yZGVyOiAnZG15JyB8ICd5bWQnIHwgJ21keScgPSAnbWR5JztcblxuICAgIHllYXJzOiBudW1iZXJbXSA9IFtdO1xuXG4gICAgX3NlbGVjdFllYXI6IGJvb2xlYW4gPSBmYWxzZTtcbiAgICBfZGlzYWJsZWQ6IGJvb2xlYW4gPSBmYWxzZTtcbiAgICBfZGlzcGxheVRpbWU6IGJvb2xlYW4gPSBmYWxzZTtcbiAgICBfZGlzcGxheVNlY29uZHM6IGJvb2xlYW4gPSBmYWxzZTtcbiAgICBASG9zdEJpbmRpbmcoJ2NsYXNzLmNvbXBhY3QnKVxuICAgIF9jb21wYWN0OiBib29sZWFuID0gZmFsc2U7XG5cbiAgICAvKiogQGludGVybmFsICovXG4gICAgdmFsdWUgPSBtb21lbnRqcygpO1xuXG4gICAgLyoqIEBpbnRlcm5hbCAqL1xuICAgIHRpbWU6IGFueSA9IHtcbiAgICAgICAgaDogMCxcbiAgICAgICAgbTogMCxcbiAgICAgICAgczogMFxuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBjYWwgaXMgYW4gaW5zdGFuY2Ugb2YgYSBSb21lIGNhbGVuZGFyLCBmb3IgdGhlIEFQSSBzZWUgaHR0cHM6Ly9naXRodWIuY29tL2JldmFjcXVhL3JvbWUjcm9tZS1hcGlcbiAgICAgKi9cbiAgICBwcml2YXRlIGNhbDogYW55O1xuXG4gICAgcHJpdmF0ZSBzdWJzY3JpcHRpb246IFN1YnNjcmlwdGlvbjtcblxuICAgIGNvbnN0cnVjdG9yKEBPcHRpb25hbCgpIHByaXZhdGUgZGVmYXVsdEZvcm1hdFByb3ZpZGVyOiBEYXRlVGltZVBpY2tlckZvcm1hdFByb3ZpZGVyKSB7fVxuXG4gICAgbmdPbkluaXQoKTogdm9pZCB7XG4gICAgICAgIGlmICh0aGlzLmRlZmF1bHRGb3JtYXRQcm92aWRlciA9PSBudWxsKSB7XG4gICAgICAgICAgICB0aGlzLmRlZmF1bHRGb3JtYXRQcm92aWRlciA9IG5ldyBEYXRlVGltZVBpY2tlckZvcm1hdFByb3ZpZGVyKCk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHRoaXMuZm9ybWF0UHJvdmlkZXIgPT0gbnVsbCkge1xuICAgICAgICAgICAgdGhpcy5mb3JtYXRQcm92aWRlciA9IHRoaXMuZGVmYXVsdEZvcm1hdFByb3ZpZGVyO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy52YWx1ZSA9IG1vbWVudGpzLnVuaXgoTnVtYmVyKHRoaXMudGltZXN0YW1wKSk7XG4gICAgICAgIHRoaXMuc2V0dXBQcm92aWRlckNoYW5nZUhvb2soKTtcblxuICAgICAgICB0aGlzLm1pbiA9IHRoaXMubWluIGluc3RhbmNlb2YgRGF0ZSA/IHRoaXMubWluIDogbmV3IERhdGUoLU1BWF9EQVRFX01JTExJU0VDT05EUyk7XG4gICAgICAgIHRoaXMubWF4ID0gdGhpcy5tYXggaW5zdGFuY2VvZiBEYXRlID8gdGhpcy5tYXggOiBuZXcgRGF0ZShNQVhfREFURV9NSUxMSVNFQ09ORFMpO1xuICAgICAgICAvLyBXZSBkb24ndCB3YW50IGEgZGF0ZSBzZWxlY3Qgd2hpY2ggaXMgc3R1cGlkbHkgbG9uZ1xuICAgICAgICBjb25zdCBNQVhfWUVBUl9SQU5HRSA9IDUwMDtcblxuICAgICAgICBsZXQgbWluWWVhciA9IHRoaXMubWluLmdldEZ1bGxZZWFyKCk7XG4gICAgICAgIGxldCBtYXhZZWFyID0gdGhpcy5tYXguZ2V0RnVsbFllYXIoKTtcbiAgICAgICAgY29uc3QgdGhpc1llYXIgPSBuZXcgRGF0ZSgpLmdldEZ1bGxZZWFyKCk7XG4gICAgICAgIGlmIChNQVhfWUVBUl9SQU5HRSA8IG1heFllYXIgLSBtaW5ZZWFyKSB7XG4gICAgICAgICAgICBtaW5ZZWFyID0gdGhpc1llYXIgLSBNYXRoLmZsb29yKE1BWF9ZRUFSX1JBTkdFIC8gMik7XG4gICAgICAgICAgICBtYXhZZWFyID0gdGhpc1llYXIgKyBNYXRoLmZsb29yKE1BWF9ZRUFSX1JBTkdFIC8gMik7XG4gICAgICAgIH1cblxuICAgICAgICBmb3IgKGxldCB5ZWFyID0gbWluWWVhcjsgeWVhciA8PSBtYXhZZWFyOyB5ZWFyICsrKSB7XG4gICAgICAgICAgICB0aGlzLnllYXJzLnB1c2goeWVhcik7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBuZ09uQ2hhbmdlcyhjaGFuZ2VzOiBTaW1wbGVDaGFuZ2VzKTogdm9pZCB7XG4gICAgICAgIGlmIChjaGFuZ2VzWyd0aW1lc3RhbXAnXSkge1xuICAgICAgICAgICAgdGhpcy52YWx1ZSA9IG1vbWVudGpzLnVuaXgoTnVtYmVyKHRoaXMudGltZXN0YW1wKSk7XG4gICAgICAgICAgICB0aGlzLnVwZGF0ZVRpbWVPYmplY3QodGhpcy52YWx1ZSk7XG4gICAgICAgICAgICBpZiAodGhpcy5jYWwpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmNhbC5zZXRWYWx1ZSh0aGlzLnZhbHVlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBpZiAoY2hhbmdlc1snbWluJ10pIHtcbiAgICAgICAgICAgIGNvbnN0IGN1cnJlbnRWYWx1ZSA9IGNoYW5nZXNbJ21pbiddLmN1cnJlbnRWYWx1ZTtcbiAgICAgICAgICAgIGlmIChjdXJyZW50VmFsdWUgJiYgIShjaGFuZ2VzWydtaW4nXS5jdXJyZW50VmFsdWUgaW5zdGFuY2VvZiBEYXRlKSkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgbWluIG11c3QgYmUgYSBEYXRlIG9iamVjdC4gR290ICR7dHlwZW9mIGNoYW5nZXNbJ21pbiddLmN1cnJlbnRWYWx1ZX1gKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBpZiAoY2hhbmdlc1snbWF4J10pIHtcbiAgICAgICAgICAgIGNvbnN0IGN1cnJlbnRWYWx1ZSA9IGNoYW5nZXNbJ21heCddLmN1cnJlbnRWYWx1ZTtcbiAgICAgICAgICAgIGlmIChjdXJyZW50VmFsdWUgJiYgIShjaGFuZ2VzWydtYXgnXS5jdXJyZW50VmFsdWUgaW5zdGFuY2VvZiBEYXRlKSkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgbWF4IG11c3QgYmUgYSBEYXRlIG9iamVjdC4gR290ICR7dHlwZW9mIGNoYW5nZXNbJ21heCddLmN1cnJlbnRWYWx1ZX1gKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBpZiAoY2hhbmdlc1snZm9ybWF0UHJvdmlkZXInXSAmJiAhY2hhbmdlc1snZm9ybWF0UHJvdmlkZXInXS5maXJzdENoYW5nZSkge1xuICAgICAgICAgICAgdGhpcy5zZXR1cFByb3ZpZGVyQ2hhbmdlSG9vaygpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogSW5pdGlhbGl6ZSB0aGUgUm9tZSB3aWRnZXQgaW5zdGFuY2UuXG4gICAgICovXG4gICAgbmdBZnRlclZpZXdJbml0KCk6IHZvaWQge1xuICAgICAgICBsZXQgY2FsZW5kYXJFbDogRWxlbWVudCA9IHRoaXMuY2FsZW5kYXJDb250YWluZXIubmF0aXZlRWxlbWVudDtcblxuICAgICAgICB0aGlzLmNhbCA9IHJvbWUoY2FsZW5kYXJFbCwgdGhpcy5nZXRSb21lQ29uZmlnKCkpXG4gICAgICAgICAgICAub24oJ2RhdGEnLCAoKSA9PiB7XG4gICAgICAgICAgICAgICAgdGhpcy52YWx1ZSA9IHRoaXMuY2FsLmdldE1vbWVudCgpO1xuICAgICAgICAgICAgICAgIHRoaXMuY2hhbmdlLmVtaXQodGhpcy52YWx1ZS51bml4KCkpO1xuICAgICAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgbmdPbkRlc3Ryb3koKTogdm9pZCB7XG4gICAgICAgIGlmICh0aGlzLmNhbCkge1xuICAgICAgICAgICAgdGhpcy5jYWwub2ZmKCdkYXRhJyk7XG4gICAgICAgICAgICB0aGlzLmNhbC5kZXN0cm95KCk7XG4gICAgICAgICAgICB0aGlzLmNhbCA9IHVuZGVmaW5lZDtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh0aGlzLnN1YnNjcmlwdGlvbikge1xuICAgICAgICAgICAgdGhpcy5zdWJzY3JpcHRpb24udW5zdWJzY3JpYmUoKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGdldFJvbWVDb25maWcoKSB7XG4gICAgICAgIGNvbnN0IHJvbWVDb25maWc6IGFueSA9IHtcbiAgICAgICAgICAgIGFwcGVuZFRvOiB0aGlzLmNhbGVuZGFyQ29udGFpbmVyLm5hdGl2ZUVsZW1lbnQsXG4gICAgICAgICAgICB0aW1lOiBmYWxzZSxcbiAgICAgICAgICAgIGluaXRpYWxWYWx1ZTogdGhpcy52YWx1ZVxuICAgICAgICB9O1xuICAgICAgICBpZiAodGhpcy5taW4pIHtcbiAgICAgICAgICAgIHJvbWVDb25maWcubWluID0gdGhpcy5taW47XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHRoaXMubWF4KSB7XG4gICAgICAgICAgICByb21lQ29uZmlnLm1heCA9IHRoaXMubWF4O1xuICAgICAgICB9XG4gICAgICAgIGlmICh0aGlzLnZhbHVlICE9IG51bGwpIHtcbiAgICAgICAgICAgIHJvbWVDb25maWcud2Vla2RheUZvcm1hdCA9IHRoaXMudmFsdWUubG9jYWxlRGF0YSgpLndlZWtkYXlzTWluKCk7XG4gICAgICAgICAgICByb21lQ29uZmlnLndlZWtTdGFydCA9IHRoaXMudmFsdWUubG9jYWxlRGF0YSgpLmZpcnN0RGF5T2ZXZWVrKCk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gcm9tZUNvbmZpZztcbiAgICB9XG5cbiAgICBzZXR1cFByb3ZpZGVyQ2hhbmdlSG9vaygpIHtcbiAgICAgICAgLy8gVW5zdWJzY3JpYmUgZnJvbSB0aGUgb2xkIHN1YnNjcmlwdGlvblxuICAgICAgICBpZiAodGhpcy5zdWJzY3JpcHRpb24gIT0gbnVsbCkge1xuICAgICAgICAgICAgdGhpcy5zdWJzY3JpcHRpb24udW5zdWJzY3JpYmUoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFVwZGF0ZSBzdHJpbmdzIGFuZCBkYXRlIGZvcm1hdCB3aGVuIGZvcm1hdCBwcm92aWRlciBlbWl0cyBhIGNoYW5nZVxuICAgICAgICB0aGlzLnN1YnNjcmlwdGlvbiA9IG9ic2VydmFibGVPZigxKVxuICAgICAgICAgICAgLnBpcGUoY29uY2F0KHRoaXMuZm9ybWF0UHJvdmlkZXIuY2hhbmdlZCQgfHwgTkVWRVIpKVxuICAgICAgICAgICAgLnN1YnNjcmliZSgoKSA9PiB7XG4gICAgICAgICAgICAgICAgdGhpcy52YWx1ZS5sb2NhbGUodGhpcy5nZXRNb21lbnRMb2NhbGUoKSk7XG4gICAgICAgICAgICAgICAgdGhpcy51cGRhdGVUaW1lT2JqZWN0KHRoaXMudmFsdWUpO1xuICAgICAgICAgICAgICAgIC8vIFdoZW4gdGhlIGxvY2FsZSBjaGFuZ2VzLCByZS1pbml0aWFsaXplIHRoZSBjYWxlbmRhciB0byB1cGRhdGUgdGhlXG4gICAgICAgICAgICAgICAgLy8gd2Vla2RheXMgYXMgdGhlc2UgYXJlIG9ubHkgdXBkYXRlZCB3aGVuIGluaXRpYWxpemVkLlxuICAgICAgICAgICAgICAgIGlmICh0aGlzLmNhbCAhPSBudWxsKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuY2FsLm9wdGlvbnModGhpcy5nZXRSb21lQ29uZmlnKCkpO1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmNhbC5zaG93KCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHRoaXMuZGV0ZXJtaW5lRGF0ZU9yZGVyKCk7XG4gICAgICAgICAgICB9KTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBVcGRhdGUgdGhlIHRoaXMudmFsdWUgaW4gYWNjb3JkYW5jZSB3aXRoIHRoZSBpbnB1dCBvZiBvbmUgb2YgdGhlXG4gICAgICogdGltZSBmaWVsZHMgKGgsIG0sIHMpLlxuICAgICAqL1xuICAgIHVwZGF0ZVRpbWUodW5pdDogVGltZVVuaXQsIHZhbHVlOiBudW1iZXIpOiB2b2lkIHtcbiAgICAgICAgY29uc3QgbmV3VmFsdWUgPSB0aGlzLnVwZGF0ZUJ5VW5pdHModGhpcy52YWx1ZS5jbG9uZSgpLCB1bml0LCB2YWx1ZSk7XG4gICAgICAgIGlmIChuZXdWYWx1ZS5pc0JlZm9yZSh0aGlzLm1pbikgfHwgbmV3VmFsdWUuaXNBZnRlcih0aGlzLm1heCkpIHtcbiAgICAgICAgICAgIC8vIHRoZSBuZXcgeWVhciBpcyBvdXQgb2YgdGhlIGFsbG93ZWQgcmFuZ2VcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMudXBkYXRlQnlVbml0cyh0aGlzLnZhbHVlLCB1bml0LCB2YWx1ZSk7XG4gICAgICAgIHRoaXMudXBkYXRlVGltZU9iamVjdCh0aGlzLnZhbHVlKTtcbiAgICAgICAgdGhpcy51cGRhdGVDYWxlbmRhcih0aGlzLnZhbHVlKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBIYW5kbGVyIGZvciB0aGUgaW5jcmVtZW50aW5nIHRoZSB0aW1lIHZhbHVlcyB3aGVuIHVwIG9yIGRvd24gYXJyb3dzIGFyZSBwcmVzc2VkLlxuICAgICAqL1xuICAgIHRpbWVLZXlIYW5kbGVyKHVuaXQ6IFRpbWVVbml0LCBlOiBLZXlib2FyZEV2ZW50KTogdm9pZCB7XG4gICAgICAgIC8vIFVQIGFycm93IGtleVxuICAgICAgICBpZiAoZS5rZXlDb2RlID09PSAzOCkge1xuICAgICAgICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICAgICAgdGhpcy5pbmNyZW1lbnRUaW1lKHVuaXQpO1xuICAgICAgICB9XG4gICAgICAgIC8vIERPV04gYXJyb3cga2V5XG4gICAgICAgIGlmIChlLmtleUNvZGUgPT09IDQwKSB7XG4gICAgICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICAgICB0aGlzLmRlY3JlbWVudFRpbWUodW5pdCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBpbmNyZW1lbnRUaW1lKHVuaXQ6IFRpbWVVbml0KTogdm9pZCB7XG4gICAgICAgIHRoaXMuYWRkVG9UaW1lKHVuaXQsIDEpO1xuICAgIH1cblxuICAgIGRlY3JlbWVudFRpbWUodW5pdDogVGltZVVuaXQpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5hZGRUb1RpbWUodW5pdCwgLTEpO1xuICAgIH1cblxuICAgIGZvcm1hdFdpdGgoZm9ybWF0U3RyaW5nOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgICAgICByZXR1cm4gdGhpcy52YWx1ZS5mb3JtYXQoZm9ybWF0U3RyaW5nKTtcbiAgICB9XG5cbiAgICBnZXRVbml4VGltZXN0YW1wKCk6IG51bWJlciB7XG4gICAgICAgIHJldHVybiB0aGlzLnZhbHVlLnVuaXgoKTtcbiAgICB9XG5cbiAgICBzZXRZZWFyKHllYXI6IG51bWJlcik6IHZvaWQge1xuICAgICAgICBjb25zdCBuZXdWYWx1ZSA9IHRoaXMudmFsdWUuY2xvbmUoKS55ZWFyKHllYXIpO1xuICAgICAgICBpZiAobmV3VmFsdWUuaXNCZWZvcmUodGhpcy5taW4pIHx8IG5ld1ZhbHVlLmlzQWZ0ZXIodGhpcy5tYXgpKSB7XG4gICAgICAgICAgICAvLyB0aGUgbmV3IHllYXIgaXMgb3V0IG9mIHRoZSBhbGxvd2VkIHJhbmdlXG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy52YWx1ZS55ZWFyKHllYXIpO1xuICAgICAgICB0aGlzLnVwZGF0ZUNhbGVuZGFyKHRoaXMudmFsdWUpO1xuICAgIH1cblxuICAgIHByaXZhdGUgdXBkYXRlQnlVbml0cyhtb21lbnQ6IE1vbWVudCwgdW5pdDogVGltZVVuaXQsIHZhbHVlOiBudW1iZXIpOiBNb21lbnQge1xuICAgICAgICBzd2l0Y2ggKHVuaXQpIHtcbiAgICAgICAgICAgIGNhc2UgJ2hvdXJzJzpcbiAgICAgICAgICAgICAgICBtb21lbnQuaG91cih2YWx1ZSk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlICdtaW51dGVzJzpcbiAgICAgICAgICAgICAgICBtb21lbnQubWludXRlKHZhbHVlKTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgJ3NlY29uZHMnOlxuICAgICAgICAgICAgICAgIG1vbWVudC5zZWNvbmQodmFsdWUpO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gbW9tZW50O1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENyZWF0ZSBhIG1vbWVudGpzIGxvY2FsZSBmcm9tIHRoZSAocG9zc2libHkgbG9jYWxpemVkKSBzdHJpbmdzLlxuICAgICAqIEBpbnRlcm5hbFxuICAgICAqL1xuICAgIHByaXZhdGUgZ2V0TW9tZW50TG9jYWxlKCk6IHN0cmluZyB7XG4gICAgICAgIGNvbnN0IGxvY2FsZVN0cmluZ3MgPSB0aGlzLmZvcm1hdFByb3ZpZGVyLnN0cmluZ3M7XG4gICAgICAgIGNvbnN0IG1vbWVudExvY2FsZXMgPSBE