ngx-material-timepicker
Version:
Handy material design timepicker for angular
322 lines • 32.1 kB
JavaScript
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
import { Component, ElementRef, EventEmitter, HostListener, Input, Output, TemplateRef, ViewChild } from '@angular/core';
import { merge } from 'rxjs';
import { NgxMaterialTimepickerService } from './services/ngx-material-timepicker.service';
import { TimeUnit } from './models/time-unit.enum';
import { animate, style, transition, trigger } from '@angular/animations';
import { NgxMaterialTimepickerEventService } from './services/ngx-material-timepicker-event.service';
import { filter } from 'rxjs/operators';
/** @enum {string} */
const AnimationState = {
ENTER: 'enter',
LEAVE: 'leave',
};
export { AnimationState };
/** @type {?} */
const ESCAPE = 27;
export class NgxMaterialTimepickerComponent {
/**
* @param {?} timepickerService
* @param {?} eventService
*/
constructor(timepickerService, eventService) {
this.timepickerService = timepickerService;
this.eventService = eventService;
this.timeUnit = TimeUnit;
this.activeTimeUnit = TimeUnit.HOUR;
this.isOpened = false;
this.isEsc = true;
this.timeSet = new EventEmitter();
this.opened = new EventEmitter();
this.closed = new EventEmitter();
this.hourSelected = new EventEmitter();
this.subscriptions = [];
this.subscriptions.push(merge(this.eventService.backdropClick, this.eventService.keydownEvent.pipe(filter(e => e.keyCode === ESCAPE && this.isEsc)))
.subscribe(() => this.close()));
}
/**
* @param {?} gap
* @return {?}
*/
set minutesGap(gap) {
if (gap == null) {
return;
}
gap = Math.floor(gap);
this._minutesGap = gap <= 59 ? gap : 1;
}
/**
* @return {?}
*/
get minutesGap() {
return this._minutesGap;
}
/**
* @param {?} time
* @return {?}
*/
set defaultTime(time) {
this.setDefaultTime(time);
}
/**
* @return {?}
*/
get minTime() {
return this.timepickerInput && this.timepickerInput.min;
}
/**
* @return {?}
*/
get maxTime() {
return this.timepickerInput && this.timepickerInput.max;
}
/**
* @return {?}
*/
get disabled() {
return this.timepickerInput && this.timepickerInput.disabled;
}
/**
* @return {?}
*/
get format() {
return this.timepickerInput && this.timepickerInput.format;
}
/**
* @return {?}
*/
ngOnInit() {
this.subscriptions.push(this.timepickerService.selectedHour
.subscribe(hour => this.selectedHour = hour));
this.subscriptions.push(this.timepickerService.selectedMinute
.subscribe(minute => this.selectedMinute = minute));
this.subscriptions.push(this.timepickerService.selectedPeriod
.subscribe(period => this.selectedPeriod = period));
}
/**
*
* Register an input with this timepicker.
* input - The timepicker input to register with this timepicker
* @param {?} input
* @return {?}
*/
registerInput(input) {
if (this.timepickerInput) {
throw Error('A Timepicker can only be associated with a single input.');
}
this.timepickerInput = input;
}
/**
* @param {?} hour
* @return {?}
*/
onHourChange(hour) {
this.timepickerService.hour = hour;
}
/**
* @param {?} hour
* @return {?}
*/
onHourSelected(hour) {
this.changeTimeUnit(TimeUnit.MINUTE);
this.hourSelected.next(hour);
}
/**
* @param {?} minute
* @return {?}
*/
onMinuteChange(minute) {
this.timepickerService.minute = minute;
}
/**
* @param {?} period
* @return {?}
*/
changePeriod(period) {
this.timepickerService.period = period;
}
/**
* @param {?} unit
* @return {?}
*/
changeTimeUnit(unit) {
this.activeTimeUnit = unit;
}
/**
* @return {?}
*/
setTime() {
this.timeSet.next(this.timepickerService.getFullTime(this.format));
this.close();
}
/**
* @param {?} time
* @return {?}
*/
setDefaultTime(time) {
this.timepickerService.setDefaultTimeIfAvailable(time, (/** @type {?} */ (this.minTime)), (/** @type {?} */ (this.maxTime)), this.format, this.minutesGap);
}
/**
* @return {?}
*/
open() {
this.isOpened = true;
if (!this.disableAnimation) {
this.animationState = AnimationState.ENTER;
}
this.opened.next();
}
/**
* @return {?}
*/
close() {
if (this.disableAnimation) {
this.closeTimepicker();
return;
}
this.animationState = AnimationState.LEAVE;
}
/**
* @param {?} event
* @return {?}
*/
animationDone(event) {
if (event.phaseName === 'done' && event.toState === AnimationState.LEAVE) {
this.closeTimepicker();
}
}
/**
* @param {?} e
* @return {?}
*/
onKeydown(e) {
this.eventService.dispatchEvent(e);
e.stopPropagation();
}
/**
* @return {?}
*/
ngOnDestroy() {
this.subscriptions.forEach(subscription => subscription.unsubscribe());
}
/**
* @private
* @return {?}
*/
closeTimepicker() {
this.isOpened = false;
this.activeTimeUnit = TimeUnit.HOUR;
this.closed.next();
}
}
NgxMaterialTimepickerComponent.decorators = [
{ type: Component, args: [{
selector: 'ngx-material-timepicker',
template: "<div class=\"timepicker-backdrop-overlay\" *ngIf=\"isOpened\" [overlay]=\"preventOverlayClick\"></div>\n<div class=\"timepicker-overlay\" *ngIf=\"isOpened\">\n <div class=\"timepicker\" [@timepicker]=\"animationState\" (@timepicker.done)=\"animationDone($event)\">\n <header class=\"timepicker__header\">\n <ngx-material-timepicker-dial [format]=\"format\" [hour]=\"selectedHour?.time\"\n [minute]=\"selectedMinute?.time\"\n [period]=\"selectedPeriod\" [activeTimeUnit]=\"activeTimeUnit\"\n [minTime]=\"minTime\" [maxTime]=\"maxTime\"\n [isEditable]=\"enableKeyboardInput\"\n [editableHintTmpl]=\"editableHintTmpl\"\n [minutesGap]=\"minutesGap\"\n (periodChanged)=\"changePeriod($event)\"\n (timeUnitChanged)=\"changeTimeUnit($event)\"\n (hourChanged)=\"onHourChange($event)\"\n (minuteChanged)=\"onMinuteChange($event)\"\n ></ngx-material-timepicker-dial>\n </header>\n <div class=\"timepicker__main-content\">\n <div class=\"timepicker__body\" [ngSwitch]=\"activeTimeUnit\">\n <div *ngSwitchCase=\"timeUnit.HOUR\">\n <ngx-material-timepicker-24-hours-face *ngIf=\"format === 24;else ampmHours\"\n (hourChange)=\"onHourChange($event)\"\n [selectedHour]=\"selectedHour\"\n [minTime]=\"minTime\"\n [maxTime]=\"maxTime\"\n [format]=\"format\"\n (hourSelected)=\"onHourSelected($event)\"></ngx-material-timepicker-24-hours-face>\n <ng-template #ampmHours>\n <ngx-material-timepicker-12-hours-face\n (hourChange)=\"onHourChange($event)\"\n [selectedHour]=\"selectedHour\"\n [period]=\"selectedPeriod\"\n [minTime]=\"minTime\"\n [maxTime]=\"maxTime\"\n (hourSelected)=\"onHourSelected($event)\"></ngx-material-timepicker-12-hours-face>\n </ng-template>\n </div>\n <ngx-material-timepicker-minutes-face *ngSwitchCase=\"timeUnit.MINUTE\"\n [selectedMinute]=\"selectedMinute\"\n [selectedHour]=\"selectedHour?.time\"\n [minTime]=\"minTime\"\n [maxTime]=\"maxTime\"\n [format]=\"format\"\n [period]=\"selectedPeriod\"\n [minutesGap]=\"minutesGap\"\n (minuteChange)=\"onMinuteChange($event)\"></ngx-material-timepicker-minutes-face>\n </div>\n <div class=\"timepicker__actions\">\n <div (click)=\"close()\">\n <!--suppress HtmlUnknownAttribute -->\n <ng-container *ngTemplateOutlet=\"cancelBtnTmpl ? cancelBtnTmpl : cancelBtnDefault\"></ng-container>\n </div>\n <div (click)=\"setTime()\">\n <!--suppress HtmlUnknownAttribute -->\n <ng-container\n *ngTemplateOutlet=\"confirmBtnTmpl ? confirmBtnTmpl : confirmBtnDefault\"></ng-container>\n </div>\n </div>\n </div>\n </div>\n</div>\n<ng-template #cancelBtnDefault>\n <ngx-material-timepicker-button>Cancel</ngx-material-timepicker-button>\n</ng-template>\n<ng-template #confirmBtnDefault>\n <ngx-material-timepicker-button>Ok</ngx-material-timepicker-button>\n</ng-template>\n",
animations: [
trigger('timepicker', [
transition(`* => ${AnimationState.ENTER}`, [
style({ transform: 'translateY(-30%)' }),
animate('0.2s ease-out', style({ transform: 'translateY(0)' }))
]),
transition(`${AnimationState.ENTER} => ${AnimationState.LEAVE}`, [
style({ transform: 'translateY(0)', opacity: 1 }),
animate('0.2s ease-out', style({ transform: 'translateY(-30%)', opacity: 0 }))
])
])
],
providers: [NgxMaterialTimepickerService],
styles: [":host{--body-background-color:#fff;--primary-font-family:'Roboto',sans-serif;--button-color:deepskyblue;--dial-active-color:#fff;--dial-inactive-color:rgba(255, 255, 255, .5);--dial-background-color:deepskyblue;--clock-face-time-active-color:#fff;--clock-face-time-inactive-color:#6c6c6c;--clock-face-inner-time-inactive-color:#929292;--clock-face-time-disabled-color:#c5c5c5;--clock-face-background-color:#f0f0f0;--clock-hand-color:deepskyblue}.timepicker-backdrop-overlay{position:fixed;top:0;bottom:0;right:0;left:0;background-color:rgba(0,0,0,.3);z-index:999;pointer-events:auto}.timepicker-overlay{position:fixed;top:0;left:0;width:100%;height:100%;display:flex;justify-content:center;align-items:center;z-index:999;pointer-events:none}.timepicker{width:300px;border-radius:2px;box-shadow:rgba(0,0,0,.25) 0 14px 45px,rgba(0,0,0,.22) 0 10px 18px;outline:0;position:static;z-index:999;pointer-events:auto}.timepicker__header{padding:15px 30px;background-color:#00bfff}@supports (background-color:var(--dial-background-color)){.timepicker__header{background-color:var(--dial-background-color)}}.timepicker__body{padding:15px 5px;display:flex;justify-content:center;align-items:center;background-color:#fff}@supports (background-color:var(--body-background-color)){.timepicker__body{background-color:var(--body-background-color)}}.timepicker__actions{display:flex;justify-content:flex-end;padding:15px;background-color:#fff}@supports (background-color:var(--body-background-color)){.timepicker__actions{background-color:var(--body-background-color)}}@media (max-device-width:1023px) and (orientation:landscape){.timepicker{display:flex;width:515px}.timepicker__header{display:flex;align-items:center}.timepicker__main-content{display:flex;flex-direction:column;width:100%}.timepicker__actions{padding:5px;margin-top:-1px}}"]
}] }
];
/** @nocollapse */
NgxMaterialTimepickerComponent.ctorParameters = () => [
{ type: NgxMaterialTimepickerService },
{ type: NgxMaterialTimepickerEventService }
];
NgxMaterialTimepickerComponent.propDecorators = {
cancelBtnTmpl: [{ type: Input }],
editableHintTmpl: [{ type: Input }],
confirmBtnTmpl: [{ type: Input }],
isEsc: [{ type: Input, args: ['ESC',] }],
enableKeyboardInput: [{ type: Input }],
preventOverlayClick: [{ type: Input }],
disableAnimation: [{ type: Input }],
minutesGap: [{ type: Input }],
defaultTime: [{ type: Input }],
timeSet: [{ type: Output }],
opened: [{ type: Output }],
closed: [{ type: Output }],
hourSelected: [{ type: Output }],
timepickerComponent: [{ type: ViewChild, args: ['timepickerww',] }],
onKeydown: [{ type: HostListener, args: ['keydown', ['$event'],] }]
};
if (false) {
/** @type {?} */
NgxMaterialTimepickerComponent.prototype.selectedHour;
/** @type {?} */
NgxMaterialTimepickerComponent.prototype.selectedMinute;
/** @type {?} */
NgxMaterialTimepickerComponent.prototype.selectedPeriod;
/** @type {?} */
NgxMaterialTimepickerComponent.prototype.timeUnit;
/** @type {?} */
NgxMaterialTimepickerComponent.prototype.activeTimeUnit;
/** @type {?} */
NgxMaterialTimepickerComponent.prototype.isOpened;
/** @type {?} */
NgxMaterialTimepickerComponent.prototype.animationState;
/** @type {?} */
NgxMaterialTimepickerComponent.prototype.cancelBtnTmpl;
/** @type {?} */
NgxMaterialTimepickerComponent.prototype.editableHintTmpl;
/** @type {?} */
NgxMaterialTimepickerComponent.prototype.confirmBtnTmpl;
/** @type {?} */
NgxMaterialTimepickerComponent.prototype.isEsc;
/** @type {?} */
NgxMaterialTimepickerComponent.prototype.enableKeyboardInput;
/** @type {?} */
NgxMaterialTimepickerComponent.prototype.preventOverlayClick;
/** @type {?} */
NgxMaterialTimepickerComponent.prototype.disableAnimation;
/** @type {?} */
NgxMaterialTimepickerComponent.prototype.timeSet;
/** @type {?} */
NgxMaterialTimepickerComponent.prototype.opened;
/** @type {?} */
NgxMaterialTimepickerComponent.prototype.closed;
/** @type {?} */
NgxMaterialTimepickerComponent.prototype.hourSelected;
/** @type {?} */
NgxMaterialTimepickerComponent.prototype.timepickerComponent;
/**
* @type {?}
* @private
*/
NgxMaterialTimepickerComponent.prototype._minutesGap;
/**
* @type {?}
* @private
*/
NgxMaterialTimepickerComponent.prototype.timepickerInput;
/**
* @type {?}
* @private
*/
NgxMaterialTimepickerComponent.prototype.subscriptions;
/**
* @type {?}
* @private
*/
NgxMaterialTimepickerComponent.prototype.timepickerService;
/**
* @type {?}
* @private
*/
NgxMaterialTimepickerComponent.prototype.eventService;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmd4LW1hdGVyaWFsLXRpbWVwaWNrZXIuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6Im5nOi8vbmd4LW1hdGVyaWFsLXRpbWVwaWNrZXIvIiwic291cmNlcyI6WyJzcmMvYXBwL21hdGVyaWFsLXRpbWVwaWNrZXIvbmd4LW1hdGVyaWFsLXRpbWVwaWNrZXIuY29tcG9uZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7QUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFFLFVBQVUsRUFBRSxZQUFZLEVBQUUsWUFBWSxFQUFFLEtBQUssRUFBcUIsTUFBTSxFQUFFLFdBQVcsRUFBRSxTQUFTLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFHNUksT0FBTyxFQUFFLEtBQUssRUFBZ0IsTUFBTSxNQUFNLENBQUM7QUFDM0MsT0FBTyxFQUFFLDRCQUE0QixFQUFFLE1BQU0sNENBQTRDLENBQUM7QUFDMUYsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQ25ELE9BQU8sRUFBRSxPQUFPLEVBQWtCLEtBQUssRUFBRSxVQUFVLEVBQUUsT0FBTyxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDMUYsT0FBTyxFQUFFLGlDQUFpQyxFQUFFLE1BQU0sa0RBQWtELENBQUM7QUFDckcsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLGdCQUFnQixDQUFDOzs7SUFLcEMsT0FBUSxPQUFPO0lBQ2YsT0FBUSxPQUFPOzs7O01BSWIsTUFBTSxHQUFHLEVBQUU7QUFvQmpCLE1BQU0sT0FBTyw4QkFBOEI7Ozs7O0lBaUR2QyxZQUFvQixpQkFBK0MsRUFDL0MsWUFBK0M7UUFEL0Msc0JBQWlCLEdBQWpCLGlCQUFpQixDQUE4QjtRQUMvQyxpQkFBWSxHQUFaLFlBQVksQ0FBbUM7UUE1Q25FLGFBQVEsR0FBRyxRQUFRLENBQUM7UUFDcEIsbUJBQWMsR0FBRyxRQUFRLENBQUMsSUFBSSxDQUFDO1FBRS9CLGFBQVEsR0FBRyxLQUFLLENBQUM7UUFNSCxVQUFLLEdBQUcsSUFBSSxDQUFDO1FBdUJqQixZQUFPLEdBQUcsSUFBSSxZQUFZLEVBQVUsQ0FBQztRQUNyQyxXQUFNLEdBQUcsSUFBSSxZQUFZLEVBQVEsQ0FBQztRQUNsQyxXQUFNLEdBQUcsSUFBSSxZQUFZLEVBQVEsQ0FBQztRQUNsQyxpQkFBWSxHQUFHLElBQUksWUFBWSxFQUFVLENBQUM7UUFNNUMsa0JBQWEsR0FBbUIsRUFBRSxDQUFDO1FBS3ZDLElBQUksQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLGFBQWEsRUFDekQsSUFBSSxDQUFDLFlBQVksQ0FBQyxZQUFZLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxPQUFPLEtBQUssTUFBTSxJQUFJLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDO2FBQ3BGLFNBQVMsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsS0FBSyxFQUFFLENBQUMsQ0FBQyxDQUFDO0lBRXhDLENBQUM7Ozs7O0lBcENELElBQ0ksVUFBVSxDQUFDLEdBQVc7UUFDdEIsSUFBSSxHQUFHLElBQUksSUFBSSxFQUFFO1lBQ2IsT0FBTztTQUNWO1FBQ0QsR0FBRyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDdEIsSUFBSSxDQUFDLFdBQVcsR0FBRyxHQUFHLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUMzQyxDQUFDOzs7O0lBRUQsSUFBSSxVQUFVO1FBQ1YsT0FBTyxJQUFJLENBQUMsV0FBVyxDQUFDO0lBQzVCLENBQUM7Ozs7O0lBRUQsSUFDSSxXQUFXLENBQUMsSUFBWTtRQUN4QixJQUFJLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQzlCLENBQUM7Ozs7SUFzQkQsSUFBSSxPQUFPO1FBQ1AsT0FBTyxJQUFJLENBQUMsZUFBZSxJQUFJLElBQUksQ0FBQyxlQUFlLENBQUMsR0FBRyxDQUFDO0lBQzVELENBQUM7Ozs7SUFFRCxJQUFJLE9BQU87UUFDUCxPQUFPLElBQUksQ0FBQyxlQUFlLElBQUksSUFBSSxDQUFDLGVBQWUsQ0FBQyxHQUFHLENBQUM7SUFDNUQsQ0FBQzs7OztJQUVELElBQUksUUFBUTtRQUNSLE9BQU8sSUFBSSxDQUFDLGVBQWUsSUFBSSxJQUFJLENBQUMsZUFBZSxDQUFDLFFBQVEsQ0FBQztJQUNqRSxDQUFDOzs7O0lBRUQsSUFBSSxNQUFNO1FBQ04sT0FBTyxJQUFJLENBQUMsZUFBZSxJQUFJLElBQUksQ0FBQyxlQUFlLENBQUMsTUFBTSxDQUFDO0lBQy9ELENBQUM7Ozs7SUFFRCxRQUFRO1FBQ0osSUFBSSxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLGlCQUFpQixDQUFDLFlBQVk7YUFDdEQsU0FBUyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLFlBQVksR0FBRyxJQUFJLENBQUMsQ0FBQyxDQUFDO1FBRWxELElBQUksQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxjQUFjO2FBQ3hELFNBQVMsQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxjQUFjLEdBQUcsTUFBTSxDQUFDLENBQUMsQ0FBQztRQUV4RCxJQUFJLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsaUJBQWlCLENBQUMsY0FBYzthQUN4RCxTQUFTLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsY0FBYyxHQUFHLE1BQU0sQ0FBQyxDQUFDLENBQUM7SUFDNUQsQ0FBQzs7Ozs7Ozs7SUFNRCxhQUFhLENBQUMsS0FBMEI7UUFDcEMsSUFBSSxJQUFJLENBQUMsZUFBZSxFQUFFO1lBQ3RCLE1BQU0sS0FBSyxDQUFDLDBEQUEwRCxDQUFDLENBQUM7U0FDM0U7UUFDRCxJQUFJLENBQUMsZUFBZSxHQUFHLEtBQUssQ0FBQztJQUNqQyxDQUFDOzs7OztJQUVELFlBQVksQ0FBQyxJQUFtQjtRQUM1QixJQUFJLENBQUMsaUJBQWlCLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQztJQUN2QyxDQUFDOzs7OztJQUVELGNBQWMsQ0FBQyxJQUFZO1FBQ3ZCLElBQUksQ0FBQyxjQUFjLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQ3JDLElBQUksQ0FBQyxZQUFZLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ2pDLENBQUM7Ozs7O0lBRUQsY0FBYyxDQUFDLE1BQXFCO1FBQ2hDLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxNQUFNLEdBQUcsTUFBTSxDQUFDO0lBQzNDLENBQUM7Ozs7O0lBRUQsWUFBWSxDQUFDLE1BQWtCO1FBQzNCLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxNQUFNLEdBQUcsTUFBTSxDQUFDO0lBQzNDLENBQUM7Ozs7O0lBRUQsY0FBYyxDQUFDLElBQWM7UUFDekIsSUFBSSxDQUFDLGNBQWMsR0FBRyxJQUFJLENBQUM7SUFDL0IsQ0FBQzs7OztJQUVELE9BQU87UUFDSCxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsaUJBQWlCLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDO1FBQ25FLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQztJQUNqQixDQUFDOzs7OztJQUVELGNBQWMsQ0FBQyxJQUFZO1FBQ3ZCLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyx5QkFBeUIsQ0FDNUMsSUFBSSxFQUFFLG1CQUFBLElBQUksQ0FBQyxPQUFPLEVBQVksRUFBRSxtQkFBQSxJQUFJLENBQUMsT0FBTyxFQUFZLEVBQUUsSUFBSSxDQUFDLE1BQU0sRUFBRSxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUM7SUFDaEcsQ0FBQzs7OztJQUVELElBQUk7UUFDQSxJQUFJLENBQUMsUUFBUSxHQUFHLElBQUksQ0FBQztRQUNyQixJQUFJLENBQUMsSUFBSSxDQUFDLGdCQUFnQixFQUFFO1lBQ3hCLElBQUksQ0FBQyxjQUFjLEdBQUcsY0FBYyxDQUFDLEtBQUssQ0FBQztTQUM5QztRQUNELElBQUksQ0FBQyxNQUFNLENBQUMsSUFBSSxFQUFFLENBQUM7SUFDdkIsQ0FBQzs7OztJQUVELEtBQUs7UUFDRCxJQUFJLElBQUksQ0FBQyxnQkFBZ0IsRUFBRTtZQUN2QixJQUFJLENBQUMsZUFBZSxFQUFFLENBQUM7WUFDdkIsT0FBTztTQUNWO1FBQ0QsSUFBSSxDQUFDLGNBQWMsR0FBRyxjQUFjLENBQUMsS0FBSyxDQUFDO0lBQy9DLENBQUM7Ozs7O0lBRUQsYUFBYSxDQUFDLEtBQXFCO1FBQy9CLElBQUksS0FBSyxDQUFDLFNBQVMsS0FBSyxNQUFNLElBQUksS0FBSyxDQUFDLE9BQU8sS0FBSyxjQUFjLENBQUMsS0FBSyxFQUFFO1lBQ3RFLElBQUksQ0FBQyxlQUFlLEVBQUUsQ0FBQztTQUMxQjtJQUNMLENBQUM7Ozs7O0lBR0QsU0FBUyxDQUFDLENBQWdCO1FBQ3RCLElBQUksQ0FBQyxZQUFZLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ25DLENBQUMsQ0FBQyxlQUFlLEVBQUUsQ0FBQztJQUN4QixDQUFDOzs7O0lBRUQsV0FBVztRQUNQLElBQUksQ0FBQyxhQUFhLENBQUMsT0FBTyxDQUFDLFlBQVksQ0FBQyxFQUFFLENBQUMsWUFBWSxDQUFDLFdBQVcsRUFBRSxDQUFDLENBQUM7SUFDM0UsQ0FBQzs7Ozs7SUFFTyxlQUFlO1FBQ25CLElBQUksQ0FBQyxRQUFRLEdBQUcsS0FBSyxDQUFDO1FBQ3RCLElBQUksQ0FBQyxjQUFjLEdBQUcsUUFBUSxDQUFDLElBQUksQ0FBQztRQUNwQyxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksRUFBRSxDQUFDO0lBQ3ZCLENBQUM7OztZQXJMSixTQUFTLFNBQUM7Z0JBQ1AsUUFBUSxFQUFFLHlCQUF5QjtnQkFDbkMsODJJQUF1RDtnQkFFdkQsVUFBVSxFQUFFO29CQUNSLE9BQU8sQ0FBQyxZQUFZLEVBQUU7d0JBQ2xCLFVBQVUsQ0FBQyxRQUFRLGNBQWMsQ0FBQyxLQUFLLEVBQUUsRUFBRTs0QkFDdkMsS0FBSyxDQUFDLEVBQUMsU0FBUyxFQUFFLGtCQUFrQixFQUFDLENBQUM7NEJBQ3RDLE9BQU8sQ0FBQyxlQUFlLEVBQUUsS0FBSyxDQUFDLEVBQUMsU0FBUyxFQUFFLGVBQWUsRUFBQyxDQUFDLENBQUM7eUJBQ2hFLENBQUM7d0JBQ0YsVUFBVSxDQUFDLEdBQUcsY0FBYyxDQUFDLEtBQUssT0FBTyxjQUFjLENBQUMsS0FBSyxFQUFFLEVBQUU7NEJBQzdELEtBQUssQ0FBQyxFQUFDLFNBQVMsRUFBRSxlQUFlLEVBQUUsT0FBTyxFQUFFLENBQUMsRUFBQyxDQUFDOzRCQUMvQyxPQUFPLENBQUMsZUFBZSxFQUFFLEtBQUssQ0FBQyxFQUFDLFNBQVMsRUFBRSxrQkFBa0IsRUFBRSxPQUFPLEVBQUUsQ0FBQyxFQUFDLENBQUMsQ0FBQzt5QkFDL0UsQ0FBQztxQkFDTCxDQUFDO2lCQUNMO2dCQUNELFNBQVMsRUFBRSxDQUFDLDRCQUE0QixDQUFDOzthQUM1Qzs7OztZQWpDUSw0QkFBNEI7WUFHNUIsaUNBQWlDOzs7NEJBMkNyQyxLQUFLOytCQUNMLEtBQUs7NkJBQ0wsS0FBSztvQkFDTCxLQUFLLFNBQUMsS0FBSztrQ0FDWCxLQUFLO2tDQUNMLEtBQUs7K0JBQ0wsS0FBSzt5QkFFTCxLQUFLOzBCQWFMLEtBQUs7c0JBS0wsTUFBTTtxQkFDTixNQUFNO3FCQUNOLE1BQU07MkJBQ04sTUFBTTtrQ0FFTixTQUFTLFNBQUMsY0FBYzt3QkEwR3hCLFlBQVksU0FBQyxTQUFTLEVBQUUsQ0FBQyxRQUFRLENBQUM7Ozs7SUFuSm5DLHNEQUE0Qjs7SUFDNUIsd0RBQThCOztJQUM5Qix3REFBMkI7O0lBRTNCLGtEQUFvQjs7SUFDcEIsd0RBQStCOztJQUUvQixrREFBaUI7O0lBQ2pCLHdEQUErQjs7SUFFL0IsdURBQTBDOztJQUMxQywwREFBNkM7O0lBQzdDLHdEQUEyQzs7SUFDM0MsK0NBQTJCOztJQUMzQiw2REFBc0M7O0lBQ3RDLDZEQUFzQzs7SUFDdEMsMERBQW1DOztJQW9CbkMsaURBQStDOztJQUMvQyxnREFBNEM7O0lBQzVDLGdEQUE0Qzs7SUFDNUMsc0RBQW9EOztJQUVwRCw2REFBMkQ7Ozs7O0lBRTNELHFEQUE0Qjs7Ozs7SUFDNUIseURBQTZDOzs7OztJQUM3Qyx1REFBMkM7Ozs7O0lBRS9CLDJEQUF1RDs7Ozs7SUFDdkQsc0RBQXVEIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29tcG9uZW50LCBFbGVtZW50UmVmLCBFdmVudEVtaXR0ZXIsIEhvc3RMaXN0ZW5lciwgSW5wdXQsIE9uRGVzdHJveSwgT25Jbml0LCBPdXRwdXQsIFRlbXBsYXRlUmVmLCBWaWV3Q2hpbGQgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IENsb2NrRmFjZVRpbWUgfSBmcm9tICcuL21vZGVscy9jbG9jay1mYWNlLXRpbWUuaW50ZXJmYWNlJztcbmltcG9ydCB7IFRpbWVQZXJpb2QgfSBmcm9tICcuL21vZGVscy90aW1lLXBlcmlvZC5lbnVtJztcbmltcG9ydCB7IG1lcmdlLCBTdWJzY3JpcHRpb24gfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IE5neE1hdGVyaWFsVGltZXBpY2tlclNlcnZpY2UgfSBmcm9tICcuL3NlcnZpY2VzL25neC1tYXRlcmlhbC10aW1lcGlja2VyLnNlcnZpY2UnO1xuaW1wb3J0IHsgVGltZVVuaXQgfSBmcm9tICcuL21vZGVscy90aW1lLXVuaXQuZW51bSc7XG5pbXBvcnQgeyBhbmltYXRlLCBBbmltYXRpb25FdmVudCwgc3R5bGUsIHRyYW5zaXRpb24sIHRyaWdnZXIgfSBmcm9tICdAYW5ndWxhci9hbmltYXRpb25zJztcbmltcG9ydCB7IE5neE1hdGVyaWFsVGltZXBpY2tlckV2ZW50U2VydmljZSB9IGZyb20gJy4vc2VydmljZXMvbmd4LW1hdGVyaWFsLXRpbWVwaWNrZXItZXZlbnQuc2VydmljZSc7XG5pbXBvcnQgeyBmaWx0ZXIgfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5pbXBvcnQgeyBUaW1lcGlja2VyRGlyZWN0aXZlIH0gZnJvbSAnLi9kaXJlY3RpdmVzL25neC10aW1lcGlja2VyLmRpcmVjdGl2ZSc7XG5pbXBvcnQgeyBEYXRlVGltZSB9IGZyb20gJ2x1eG9uJztcblxuZXhwb3J0IGVudW0gQW5pbWF0aW9uU3RhdGUge1xuICAgIEVOVEVSID0gJ2VudGVyJyxcbiAgICBMRUFWRSA9ICdsZWF2ZSdcbn1cblxuXG5jb25zdCBFU0NBUEUgPSAyNztcblxuQENvbXBvbmVudCh7XG4gICAgc2VsZWN0b3I6ICduZ3gtbWF0ZXJpYWwtdGltZXBpY2tlcicsXG4gICAgdGVtcGxhdGVVcmw6ICcuL25neC1tYXRlcmlhbC10aW1lcGlja2VyLmNvbXBvbmVudC5odG1sJyxcbiAgICBzdHlsZVVybHM6IFsnLi9uZ3gtbWF0ZXJpYWwtdGltZXBpY2tlci5jb21wb25lbnQuc2NzcyddLFxuICAgIGFuaW1hdGlvbnM6IFtcbiAgICAgICAgdHJpZ2dlcigndGltZXBpY2tlcicsIFtcbiAgICAgICAgICAgIHRyYW5zaXRpb24oYCogPT4gJHtBbmltYXRpb25TdGF0ZS5FTlRFUn1gLCBbXG4gICAgICAgICAgICAgICAgc3R5bGUoe3RyYW5zZm9ybTogJ3RyYW5zbGF0ZVkoLTMwJSknfSksXG4gICAgICAgICAgICAgICAgYW5pbWF0ZSgnMC4ycyBlYXNlLW91dCcsIHN0eWxlKHt0cmFuc2Zvcm06ICd0cmFuc2xhdGVZKDApJ30pKVxuICAgICAgICAgICAgXSksXG4gICAgICAgICAgICB0cmFuc2l0aW9uKGAke0FuaW1hdGlvblN0YXRlLkVOVEVSfSA9PiAke0FuaW1hdGlvblN0YXRlLkxFQVZFfWAsIFtcbiAgICAgICAgICAgICAgICBzdHlsZSh7dHJhbnNmb3JtOiAndHJhbnNsYXRlWSgwKScsIG9wYWNpdHk6IDF9KSxcbiAgICAgICAgICAgICAgICBhbmltYXRlKCcwLjJzIGVhc2Utb3V0Jywgc3R5bGUoe3RyYW5zZm9ybTogJ3RyYW5zbGF0ZVkoLTMwJSknLCBvcGFjaXR5OiAwfSkpXG4gICAgICAgICAgICBdKVxuICAgICAgICBdKVxuICAgIF0sXG4gICAgcHJvdmlkZXJzOiBbTmd4TWF0ZXJpYWxUaW1lcGlja2VyU2VydmljZV1cbn0pXG5leHBvcnQgY2xhc3MgTmd4TWF0ZXJpYWxUaW1lcGlja2VyQ29tcG9uZW50IGltcGxlbWVudHMgT25Jbml0LCBPbkRlc3Ryb3kge1xuXG4gICAgc2VsZWN0ZWRIb3VyOiBDbG9ja0ZhY2VUaW1lO1xuICAgIHNlbGVjdGVkTWludXRlOiBDbG9ja0ZhY2VUaW1lO1xuICAgIHNlbGVjdGVkUGVyaW9kOiBUaW1lUGVyaW9kO1xuXG4gICAgdGltZVVuaXQgPSBUaW1lVW5pdDtcbiAgICBhY3RpdmVUaW1lVW5pdCA9IFRpbWVVbml0LkhPVVI7XG5cbiAgICBpc09wZW5lZCA9IGZhbHNlO1xuICAgIGFuaW1hdGlvblN0YXRlOiBBbmltYXRpb25TdGF0ZTtcblxuICAgIEBJbnB1dCgpIGNhbmNlbEJ0blRtcGw6IFRlbXBsYXRlUmVmPE5vZGU+O1xuICAgIEBJbnB1dCgpIGVkaXRhYmxlSGludFRtcGw6IFRlbXBsYXRlUmVmPE5vZGU+O1xuICAgIEBJbnB1dCgpIGNvbmZpcm1CdG5UbXBsOiBUZW1wbGF0ZVJlZjxOb2RlPjtcbiAgICBASW5wdXQoJ0VTQycpIGlzRXNjID0gdHJ1ZTtcbiAgICBASW5wdXQoKSBlbmFibGVLZXlib2FyZElucHV0OiBib29sZWFuO1xuICAgIEBJbnB1dCgpIHByZXZlbnRPdmVybGF5Q2xpY2s6IGJvb2xlYW47XG4gICAgQElucHV0KCkgZGlzYWJsZUFuaW1hdGlvbjogYm9vbGVhbjtcblxuICAgIEBJbnB1dCgpXG4gICAgc2V0IG1pbnV0ZXNHYXAoZ2FwOiBudW1iZXIpIHtcbiAgICAgICAgaWYgKGdhcCA9PSBudWxsKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgZ2FwID0gTWF0aC5mbG9vcihnYXApO1xuICAgICAgICB0aGlzLl9taW51dGVzR2FwID0gZ2FwIDw9IDU5ID8gZ2FwIDogMTtcbiAgICB9XG5cbiAgICBnZXQgbWludXRlc0dhcCgpOiBudW1iZXIge1xuICAgICAgICByZXR1cm4gdGhpcy5fbWludXRlc0dhcDtcbiAgICB9XG5cbiAgICBASW5wdXQoKVxuICAgIHNldCBkZWZhdWx0VGltZSh0aW1lOiBzdHJpbmcpIHtcbiAgICAgICAgdGhpcy5zZXREZWZhdWx0VGltZSh0aW1lKTtcbiAgICB9XG5cbiAgICBAT3V0cHV0KCkgdGltZVNldCA9IG5ldyBFdmVudEVtaXR0ZXI8c3RyaW5nPigpO1xuICAgIEBPdXRwdXQoKSBvcGVuZWQgPSBuZXcgRXZlbnRFbWl0dGVyPG51bGw+KCk7XG4gICAgQE91dHB1dCgpIGNsb3NlZCA9IG5ldyBFdmVudEVtaXR0ZXI8bnVsbD4oKTtcbiAgICBAT3V0cHV0KCkgaG91clNlbGVjdGVkID0gbmV3IEV2ZW50RW1pdHRlcjxudW1iZXI+KCk7XG5cbiAgICBAVmlld0NoaWxkKCd0aW1lcGlja2Vyd3cnKSB0aW1lcGlja2VyQ29tcG9uZW50OiBFbGVtZW50UmVmO1xuXG4gICAgcHJpdmF0ZSBfbWludXRlc0dhcDogbnVtYmVyO1xuICAgIHByaXZhdGUgdGltZXBpY2tlcklucHV0OiBUaW1lcGlja2VyRGlyZWN0aXZlO1xuICAgIHByaXZhdGUgc3Vic2NyaXB0aW9uczogU3Vic2NyaXB0aW9uW10gPSBbXTtcblxuICAgIGNvbnN0cnVjdG9yKHByaXZhdGUgdGltZXBpY2tlclNlcnZpY2U6IE5neE1hdGVyaWFsVGltZXBpY2tlclNlcnZpY2UsXG4gICAgICAgICAgICAgICAgcHJpdmF0ZSBldmVudFNlcnZpY2U6IE5neE1hdGVyaWFsVGltZXBpY2tlckV2ZW50U2VydmljZSkge1xuXG4gICAgICAgIHRoaXMuc3Vic2NyaXB0aW9ucy5wdXNoKG1lcmdlKHRoaXMuZXZlbnRTZXJ2aWNlLmJhY2tkcm9wQ2xpY2ssXG4gICAgICAgICAgICB0aGlzLmV2ZW50U2VydmljZS5rZXlkb3duRXZlbnQucGlwZShmaWx0ZXIoZSA9PiBlLmtleUNvZGUgPT09IEVTQ0FQRSAmJiB0aGlzLmlzRXNjKSkpXG4gICAgICAgICAgICAuc3Vic2NyaWJlKCgpID0+IHRoaXMuY2xvc2UoKSkpO1xuXG4gICAgfVxuXG4gICAgZ2V0IG1pblRpbWUoKTogc3RyaW5nIHwgRGF0ZVRpbWUge1xuICAgICAgICByZXR1cm4gdGhpcy50aW1lcGlja2VySW5wdXQgJiYgdGhpcy50aW1lcGlja2VySW5wdXQubWluO1xuICAgIH1cblxuICAgIGdldCBtYXhUaW1lKCk6IHN0cmluZyB8IERhdGVUaW1lIHtcbiAgICAgICAgcmV0dXJuIHRoaXMudGltZXBpY2tlcklucHV0ICYmIHRoaXMudGltZXBpY2tlcklucHV0Lm1heDtcbiAgICB9XG5cbiAgICBnZXQgZGlzYWJsZWQoKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiB0aGlzLnRpbWVwaWNrZXJJbnB1dCAmJiB0aGlzLnRpbWVwaWNrZXJJbnB1dC5kaXNhYmxlZDtcbiAgICB9XG5cbiAgICBnZXQgZm9ybWF0KCk6IG51bWJlciB7XG4gICAgICAgIHJldHVybiB0aGlzLnRpbWVwaWNrZXJJbnB1dCAmJiB0aGlzLnRpbWVwaWNrZXJJbnB1dC5mb3JtYXQ7XG4gICAgfVxuXG4gICAgbmdPbkluaXQoKSB7XG4gICAgICAgIHRoaXMuc3Vic2NyaXB0aW9ucy5wdXNoKHRoaXMudGltZXBpY2tlclNlcnZpY2Uuc2VsZWN0ZWRIb3VyXG4gICAgICAgICAgICAuc3Vic2NyaWJlKGhvdXIgPT4gdGhpcy5zZWxlY3RlZEhvdXIgPSBob3VyKSk7XG5cbiAgICAgICAgdGhpcy5zdWJzY3JpcHRpb25zLnB1c2godGhpcy50aW1lcGlja2VyU2VydmljZS5zZWxlY3RlZE1pbnV0ZVxuICAgICAgICAgICAgLnN1YnNjcmliZShtaW51dGUgPT4gdGhpcy5zZWxlY3RlZE1pbnV0ZSA9IG1pbnV0ZSkpO1xuXG4gICAgICAgIHRoaXMuc3Vic2NyaXB0aW9ucy5wdXNoKHRoaXMudGltZXBpY2tlclNlcnZpY2Uuc2VsZWN0ZWRQZXJpb2RcbiAgICAgICAgICAgIC5zdWJzY3JpYmUocGVyaW9kID0+IHRoaXMuc2VsZWN0ZWRQZXJpb2QgPSBwZXJpb2QpKTtcbiAgICB9XG5cbiAgICAvKioqXG4gICAgICogUmVnaXN0ZXIgYW4gaW5wdXQgd2l0aCB0aGlzIHRpbWVwaWNrZXIuXG4gICAgICogaW5wdXQgLSBUaGUgdGltZXBpY2tlciBpbnB1dCB0byByZWdpc3RlciB3aXRoIHRoaXMgdGltZXBpY2tlclxuICAgICAqL1xuICAgIHJlZ2lzdGVySW5wdXQoaW5wdXQ6IFRpbWVwaWNrZXJEaXJlY3RpdmUpOiB2b2lkIHtcbiAgICAgICAgaWYgKHRoaXMudGltZXBpY2tlcklucHV0KSB7XG4gICAgICAgICAgICB0aHJvdyBFcnJvcignQSBUaW1lcGlja2VyIGNhbiBvbmx5IGJlIGFzc29jaWF0ZWQgd2l0aCBhIHNpbmdsZSBpbnB1dC4nKTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLnRpbWVwaWNrZXJJbnB1dCA9IGlucHV0O1xuICAgIH1cblxuICAgIG9uSG91ckNoYW5nZShob3VyOiBDbG9ja0ZhY2VUaW1lKTogdm9pZCB7XG4gICAgICAgIHRoaXMudGltZXBpY2tlclNlcnZpY2UuaG91ciA9IGhvdXI7XG4gICAgfVxuXG4gICAgb25Ib3VyU2VsZWN0ZWQoaG91cjogbnVtYmVyKTogdm9pZCB7XG4gICAgICAgIHRoaXMuY2hhbmdlVGltZVVuaXQoVGltZVVuaXQuTUlOVVRFKTtcbiAgICAgICAgdGhpcy5ob3VyU2VsZWN0ZWQubmV4dChob3VyKTtcbiAgICB9XG5cbiAgICBvbk1pbnV0ZUNoYW5nZShtaW51dGU6IENsb2NrRmFjZVRpbWUpOiB2b2lkIHtcbiAgICAgICAgdGhpcy50aW1lcGlja2VyU2VydmljZS5taW51dGUgPSBtaW51dGU7XG4gICAgfVxuXG4gICAgY2hhbmdlUGVyaW9kKHBlcmlvZDogVGltZVBlcmlvZCk6IHZvaWQge1xuICAgICAgICB0aGlzLnRpbWVwaWNrZXJTZXJ2aWNlLnBlcmlvZCA9IHBlcmlvZDtcbiAgICB9XG5cbiAgICBjaGFuZ2VUaW1lVW5pdCh1bml0OiBUaW1lVW5pdCk6IHZvaWQge1xuICAgICAgICB0aGlzLmFjdGl2ZVRpbWVVbml0ID0gdW5pdDtcbiAgICB9XG5cbiAgICBzZXRUaW1lKCk6IHZvaWQge1xuICAgICAgICB0aGlzLnRpbWVTZXQubmV4dCh0aGlzLnRpbWVwaWNrZXJTZXJ2aWNlLmdldEZ1bGxUaW1lKHRoaXMuZm9ybWF0KSk7XG4gICAgICAgIHRoaXMuY2xvc2UoKTtcbiAgICB9XG5cbiAgICBzZXREZWZhdWx0VGltZSh0aW1lOiBzdHJpbmcpOiB2b2lkIHtcbiAgICAgICAgdGhpcy50aW1lcGlja2VyU2VydmljZS5zZXREZWZhdWx0VGltZUlmQXZhaWxhYmxlKFxuICAgICAgICAgICAgdGltZSwgdGhpcy5taW5UaW1lIGFzIERhdGVUaW1lLCB0aGlzLm1heFRpbWUgYXMgRGF0ZVRpbWUsIHRoaXMuZm9ybWF0LCB0aGlzLm1pbnV0ZXNHYXApO1xuICAgIH1cblxuICAgIG9wZW4oKTogdm9pZCB7XG4gICAgICAgIHRoaXMuaXNPcGVuZWQgPSB0cnVlO1xuICAgICAgICBpZiAoIXRoaXMuZGlzYWJsZUFuaW1hdGlvbikge1xuICAgICAgICAgICAgdGhpcy5hbmltYXRpb25TdGF0ZSA9IEFuaW1hdGlvblN0YXRlLkVOVEVSO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMub3BlbmVkLm5leHQoKTtcbiAgICB9XG5cbiAgICBjbG9zZSgpOiB2b2lkIHtcbiAgICAgICAgaWYgKHRoaXMuZGlzYWJsZUFuaW1hdGlvbikge1xuICAgICAgICAgICAgdGhpcy5jbG9zZVRpbWVwaWNrZXIoKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLmFuaW1hdGlvblN0YXRlID0gQW5pbWF0aW9uU3RhdGUuTEVBVkU7XG4gICAgfVxuXG4gICAgYW5pbWF0aW9uRG9uZShldmVudDogQW5pbWF0aW9uRXZlbnQpOiB2b2lkIHtcbiAgICAgICAgaWYgKGV2ZW50LnBoYXNlTmFtZSA9PT0gJ2RvbmUnICYmIGV2ZW50LnRvU3RhdGUgPT09IEFuaW1hdGlvblN0YXRlLkxFQVZFKSB7XG4gICAgICAgICAgICB0aGlzLmNsb3NlVGltZXBpY2tlcigpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgQEhvc3RMaXN0ZW5lcigna2V5ZG93bicsIFsnJGV2ZW50J10pXG4gICAgb25LZXlkb3duKGU6IEtleWJvYXJkRXZlbnQpIHtcbiAgICAgICAgdGhpcy5ldmVudFNlcnZpY2UuZGlzcGF0Y2hFdmVudChlKTtcbiAgICAgICAgZS5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICB9XG5cbiAgICBuZ09uRGVzdHJveSgpIHtcbiAgICAgICAgdGhpcy5zdWJzY3JpcHRpb25zLmZvckVhY2goc3Vic2NyaXB0aW9uID0+IHN1YnNjcmlwdGlvbi51bnN1YnNjcmliZSgpKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGNsb3NlVGltZXBpY2tlcigpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5pc09wZW5lZCA9IGZhbHNlO1xuICAgICAgICB0aGlzLmFjdGl2ZVRpbWVVbml0ID0gVGltZVVuaXQuSE9VUjtcbiAgICAgICAgdGhpcy5jbG9zZWQubmV4dCgpO1xuICAgIH1cbn1cbiJdfQ==