ngx-material-timepicker
Version:
Handy material design timepicker for angular
408 lines • 35.9 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} */
var AnimationState = {
ENTER: 'enter',
LEAVE: 'leave',
};
export { AnimationState };
/** @type {?} */
var ESCAPE = 27;
var NgxMaterialTimepickerComponent = /** @class */ (function () {
function NgxMaterialTimepickerComponent(timepickerService, eventService) {
var _this = this;
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(function (e) { return e.keyCode === ESCAPE && _this.isEsc; })))
.subscribe(function () { return _this.close(); }));
}
Object.defineProperty(NgxMaterialTimepickerComponent.prototype, "minutesGap", {
get: /**
* @return {?}
*/
function () {
return this._minutesGap;
},
set: /**
* @param {?} gap
* @return {?}
*/
function (gap) {
if (gap == null) {
return;
}
gap = Math.floor(gap);
this._minutesGap = gap <= 59 ? gap : 1;
},
enumerable: true,
configurable: true
});
Object.defineProperty(NgxMaterialTimepickerComponent.prototype, "defaultTime", {
set: /**
* @param {?} time
* @return {?}
*/
function (time) {
this.setDefaultTime(time);
},
enumerable: true,
configurable: true
});
Object.defineProperty(NgxMaterialTimepickerComponent.prototype, "minTime", {
get: /**
* @return {?}
*/
function () {
return this.timepickerInput && this.timepickerInput.min;
},
enumerable: true,
configurable: true
});
Object.defineProperty(NgxMaterialTimepickerComponent.prototype, "maxTime", {
get: /**
* @return {?}
*/
function () {
return this.timepickerInput && this.timepickerInput.max;
},
enumerable: true,
configurable: true
});
Object.defineProperty(NgxMaterialTimepickerComponent.prototype, "disabled", {
get: /**
* @return {?}
*/
function () {
return this.timepickerInput && this.timepickerInput.disabled;
},
enumerable: true,
configurable: true
});
Object.defineProperty(NgxMaterialTimepickerComponent.prototype, "format", {
get: /**
* @return {?}
*/
function () {
return this.timepickerInput && this.timepickerInput.format;
},
enumerable: true,
configurable: true
});
/**
* @return {?}
*/
NgxMaterialTimepickerComponent.prototype.ngOnInit = /**
* @return {?}
*/
function () {
var _this = this;
this.subscriptions.push(this.timepickerService.selectedHour
.subscribe(function (hour) { return _this.selectedHour = hour; }));
this.subscriptions.push(this.timepickerService.selectedMinute
.subscribe(function (minute) { return _this.selectedMinute = minute; }));
this.subscriptions.push(this.timepickerService.selectedPeriod
.subscribe(function (period) { return _this.selectedPeriod = period; }));
};
/***
* Register an input with this timepicker.
* input - The timepicker input to register with this timepicker
*/
/**
*
* Register an input with this timepicker.
* input - The timepicker input to register with this timepicker
* @param {?} input
* @return {?}
*/
NgxMaterialTimepickerComponent.prototype.registerInput = /**
*
* Register an input with this timepicker.
* input - The timepicker input to register with this timepicker
* @param {?} input
* @return {?}
*/
function (input) {
if (this.timepickerInput) {
throw Error('A Timepicker can only be associated with a single input.');
}
this.timepickerInput = input;
};
/**
* @param {?} hour
* @return {?}
*/
NgxMaterialTimepickerComponent.prototype.onHourChange = /**
* @param {?} hour
* @return {?}
*/
function (hour) {
this.timepickerService.hour = hour;
};
/**
* @param {?} hour
* @return {?}
*/
NgxMaterialTimepickerComponent.prototype.onHourSelected = /**
* @param {?} hour
* @return {?}
*/
function (hour) {
this.changeTimeUnit(TimeUnit.MINUTE);
this.hourSelected.next(hour);
};
/**
* @param {?} minute
* @return {?}
*/
NgxMaterialTimepickerComponent.prototype.onMinuteChange = /**
* @param {?} minute
* @return {?}
*/
function (minute) {
this.timepickerService.minute = minute;
};
/**
* @param {?} period
* @return {?}
*/
NgxMaterialTimepickerComponent.prototype.changePeriod = /**
* @param {?} period
* @return {?}
*/
function (period) {
this.timepickerService.period = period;
};
/**
* @param {?} unit
* @return {?}
*/
NgxMaterialTimepickerComponent.prototype.changeTimeUnit = /**
* @param {?} unit
* @return {?}
*/
function (unit) {
this.activeTimeUnit = unit;
};
/**
* @return {?}
*/
NgxMaterialTimepickerComponent.prototype.setTime = /**
* @return {?}
*/
function () {
this.timeSet.next(this.timepickerService.getFullTime(this.format));
this.close();
};
/**
* @param {?} time
* @return {?}
*/
NgxMaterialTimepickerComponent.prototype.setDefaultTime = /**
* @param {?} time
* @return {?}
*/
function (time) {
this.timepickerService.setDefaultTimeIfAvailable(time, (/** @type {?} */ (this.minTime)), (/** @type {?} */ (this.maxTime)), this.format, this.minutesGap);
};
/**
* @return {?}
*/
NgxMaterialTimepickerComponent.prototype.open = /**
* @return {?}
*/
function () {
this.isOpened = true;
if (!this.disableAnimation) {
this.animationState = AnimationState.ENTER;
}
this.opened.next();
};
/**
* @return {?}
*/
NgxMaterialTimepickerComponent.prototype.close = /**
* @return {?}
*/
function () {
if (this.disableAnimation) {
this.closeTimepicker();
return;
}
this.animationState = AnimationState.LEAVE;
};
/**
* @param {?} event
* @return {?}
*/
NgxMaterialTimepickerComponent.prototype.animationDone = /**
* @param {?} event
* @return {?}
*/
function (event) {
if (event.phaseName === 'done' && event.toState === AnimationState.LEAVE) {
this.closeTimepicker();
}
};
/**
* @param {?} e
* @return {?}
*/
NgxMaterialTimepickerComponent.prototype.onKeydown = /**
* @param {?} e
* @return {?}
*/
function (e) {
this.eventService.dispatchEvent(e);
e.stopPropagation();
};
/**
* @return {?}
*/
NgxMaterialTimepickerComponent.prototype.ngOnDestroy = /**
* @return {?}
*/
function () {
this.subscriptions.forEach(function (subscription) { return subscription.unsubscribe(); });
};
/**
* @private
* @return {?}
*/
NgxMaterialTimepickerComponent.prototype.closeTimepicker = /**
* @private
* @return {?}
*/
function () {
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 = function () { return [
{ 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'],] }]
};
return NgxMaterialTimepickerComponent;
}());
export { NgxMaterialTimepickerComponent };
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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmd4LW1hdGVyaWFsLXRpbWVwaWNrZXIuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6Im5nOi8vbmd4LW1hdGVyaWFsLXRpbWVwaWNrZXIvIiwic291cmNlcyI6WyJzcmMvYXBwL21hdGVyaWFsLXRpbWVwaWNrZXIvbmd4LW1hdGVyaWFsLXRpbWVwaWNrZXIuY29tcG9uZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7QUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFFLFVBQVUsRUFBRSxZQUFZLEVBQUUsWUFBWSxFQUFFLEtBQUssRUFBcUIsTUFBTSxFQUFFLFdBQVcsRUFBRSxTQUFTLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFHNUksT0FBTyxFQUFFLEtBQUssRUFBZ0IsTUFBTSxNQUFNLENBQUM7QUFDM0MsT0FBTyxFQUFFLDRCQUE0QixFQUFFLE1BQU0sNENBQTRDLENBQUM7QUFDMUYsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQ25ELE9BQU8sRUFBRSxPQUFPLEVBQWtCLEtBQUssRUFBRSxVQUFVLEVBQUUsT0FBTyxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDMUYsT0FBTyxFQUFFLGlDQUFpQyxFQUFFLE1BQU0sa0RBQWtELENBQUM7QUFDckcsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLGdCQUFnQixDQUFDOzs7SUFLcEMsT0FBUSxPQUFPO0lBQ2YsT0FBUSxPQUFPOzs7O0lBSWIsTUFBTSxHQUFHLEVBQUU7QUFFakI7SUFtRUksd0NBQW9CLGlCQUErQyxFQUMvQyxZQUErQztRQURuRSxpQkFPQztRQVBtQixzQkFBaUIsR0FBakIsaUJBQWlCLENBQThCO1FBQy9DLGlCQUFZLEdBQVosWUFBWSxDQUFtQztRQTVDbkUsYUFBUSxHQUFHLFFBQVEsQ0FBQztRQUNwQixtQkFBYyxHQUFHLFFBQVEsQ0FBQyxJQUFJLENBQUM7UUFFL0IsYUFBUSxHQUFHLEtBQUssQ0FBQztRQU1ILFVBQUssR0FBRyxJQUFJLENBQUM7UUF1QmpC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QTBHeEIsWUFBWSxTQUFDLFNBQVMsRUFBRSxDQUFDLFFBQVEsQ0FBQzs7SUFldkMscUNBQUM7Q0FBQSxBQXRMRCxJQXNMQztTQXBLWSw4QkFBOEI7OztJQUV2QyxzREFBNEI7O0lBQzVCLHdEQUE4Qjs7SUFDOUIsd0RBQTJCOztJQUUzQixrREFBb0I7O0lBQ3BCLHdEQUErQjs7SUFFL0Isa0RBQWlCOztJQUNqQix3REFBK0I7O0lBRS9CLHVEQUEwQzs7SUFDMUMsMERBQTZDOztJQUM3Qyx3REFBMkM7O0lBQzNDLCtDQUEyQjs7SUFDM0IsNkRBQXNDOztJQUN0Qyw2REFBc0M7O0lBQ3RDLDBEQUFtQzs7SUFvQm5DLGlEQUErQzs7SUFDL0MsZ0RBQTRDOztJQUM1QyxnREFBNEM7O0lBQzVDLHNEQUFvRDs7SUFFcEQsNkRBQTJEOzs7OztJQUUzRCxxREFBNEI7Ozs7O0lBQzVCLHlEQUE2Qzs7Ozs7SUFDN0MsdURBQTJDOzs7OztJQUUvQiwyREFBdUQ7Ozs7O0lBQ3ZELHNEQUF1RCIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBvbmVudCwgRWxlbWVudFJlZiwgRXZlbnRFbWl0dGVyLCBIb3N0TGlzdGVuZXIsIElucHV0LCBPbkRlc3Ryb3ksIE9uSW5pdCwgT3V0cHV0LCBUZW1wbGF0ZVJlZiwgVmlld0NoaWxkIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBDbG9ja0ZhY2VUaW1lIH0gZnJvbSAnLi9tb2RlbHMvY2xvY2stZmFjZS10aW1lLmludGVyZmFjZSc7XG5pbXBvcnQgeyBUaW1lUGVyaW9kIH0gZnJvbSAnLi9tb2RlbHMvdGltZS1wZXJpb2QuZW51bSc7XG5pbXBvcnQgeyBtZXJnZSwgU3Vic2NyaXB0aW9uIH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyBOZ3hNYXRlcmlhbFRpbWVwaWNrZXJTZXJ2aWNlIH0gZnJvbSAnLi9zZXJ2aWNlcy9uZ3gtbWF0ZXJpYWwtdGltZXBpY2tlci5zZXJ2aWNlJztcbmltcG9ydCB7IFRpbWVVbml0IH0gZnJvbSAnLi9tb2RlbHMvdGltZS11bml0LmVudW0nO1xuaW1wb3J0IHsgYW5pbWF0ZSwgQW5pbWF0aW9uRXZlbnQsIHN0eWxlLCB0cmFuc2l0aW9uLCB0cmlnZ2VyIH0gZnJvbSAnQGFuZ3VsYXIvYW5pbWF0aW9ucyc7XG5pbXBvcnQgeyBOZ3hNYXRlcmlhbFRpbWVwaWNrZXJFdmVudFNlcnZpY2UgfSBmcm9tICcuL3NlcnZpY2VzL25neC1tYXRlcmlhbC10aW1lcGlja2VyLWV2ZW50LnNlcnZpY2UnO1xuaW1wb3J0IHsgZmlsdGVyIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuaW1wb3J0IHsgVGltZXBpY2tlckRpcmVjdGl2ZSB9IGZyb20gJy4vZGlyZWN0aXZlcy9uZ3gtdGltZXBpY2tlci5kaXJlY3RpdmUnO1xuaW1wb3J0IHsgRGF0ZVRpbWUgfSBmcm9tICdsdXhvbic7XG5cbmV4cG9ydCBlbnVtIEFuaW1hdGlvblN0YXRlIHtcbiAgICBFTlRFUiA9ICdlbnRlcicsXG4gICAgTEVBVkUgPSAnbGVhdmUnXG59XG5cblxuY29uc3QgRVNDQVBFID0gMjc7XG5cbkBDb21wb25lbnQoe1xuICAgIHNlbGVjdG9yOiAnbmd4LW1hdGVyaWFsLXRpbWVwaWNrZXInLFxuICAgIHRlbXBsYXRlVXJsOiAnLi9uZ3gtbWF0ZXJpYWwtdGltZXBpY2tlci5jb21wb25lbnQuaHRtbCcsXG4gICAgc3R5bGVVcmxzOiBbJy4vbmd4LW1hdGVyaWFsLXRpbWVwaWNrZXIuY29tcG9uZW50LnNjc3MnXSxcbiAgICBhbmltYXRpb25zOiBbXG4gICAgICAgIHRyaWdnZXIoJ3RpbWVwaWNrZXInLCBbXG4gICAgICAgICAgICB0cmFuc2l0aW9uKGAqID0+ICR7QW5pbWF0aW9uU3RhdGUuRU5URVJ9YCwgW1xuICAgICAgICAgICAgICAgIHN0eWxlKHt0cmFuc2Zvcm06ICd0cmFuc2xhdGVZKC0zMCUpJ30pLFxuICAgICAgICAgICAgICAgIGFuaW1hdGUoJzAuMnMgZWFzZS1vdXQnLCBzdHlsZSh7dHJhbnNmb3JtOiAndHJhbnNsYXRlWSgwKSd9KSlcbiAgICAgICAgICAgIF0pLFxuICAgICAgICAgICAgdHJhbnNpdGlvbihgJHtBbmltYXRpb25TdGF0ZS5FTlRFUn0gPT4gJHtBbmltYXRpb25TdGF0ZS5MRUFWRX1gLCBbXG4gICAgICAgICAgICAgICAgc3R5bGUoe3RyYW5zZm9ybTogJ3RyYW5zbGF0ZVkoMCknLCBvcGFjaXR5OiAxfSksXG4gICAgICAgICAgICAgICAgYW5pbWF0ZSgnMC4ycyBlYXNlLW91dCcsIHN0eWxlKHt0cmFuc2Zvcm06ICd0cmFuc2xhdGVZKC0zMCUpJywgb3BhY2l0eTogMH0pKVxuICAgICAgICAgICAgXSlcbiAgICAgICAgXSlcbiAgICBdLFxuICAgIHByb3ZpZGVyczogW05neE1hdGVyaWFsVGltZXBpY2tlclNlcnZpY2VdXG59KVxuZXhwb3J0IGNsYXNzIE5neE1hdGVyaWFsVGltZXBpY2tlckNvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCwgT25EZXN0cm95IHtcblxuICAgIHNlbGVjdGVkSG91cjogQ2xvY2tGYWNlVGltZTtcbiAgICBzZWxlY3RlZE1pbnV0ZTogQ2xvY2tGYWNlVGltZTtcbiAgICBzZWxlY3RlZFBlcmlvZDogVGltZVBlcmlvZDtcblxuICAgIHRpbWVVbml0ID0gVGltZVVuaXQ7XG4gICAgYWN0aXZlVGltZVVuaXQgPSBUaW1lVW5pdC5IT1VSO1xuXG4gICAgaXNPcGVuZWQgPSBmYWxzZTtcbiAgICBhbmltYXRpb25TdGF0ZTogQW5pbWF0aW9uU3RhdGU7XG5cbiAgICBASW5wdXQoKSBjYW5jZWxCdG5UbXBsOiBUZW1wbGF0ZVJlZjxOb2RlPjtcbiAgICBASW5wdXQoKSBlZGl0YWJsZUhpbnRUbXBsOiBUZW1wbGF0ZVJlZjxOb2RlPjtcbiAgICBASW5wdXQoKSBjb25maXJtQnRuVG1wbDogVGVtcGxhdGVSZWY8Tm9kZT47XG4gICAgQElucHV0KCdFU0MnKSBpc0VzYyA9IHRydWU7XG4gICAgQElucHV0KCkgZW5hYmxlS2V5Ym9hcmRJbnB1dDogYm9vbGVhbjtcbiAgICBASW5wdXQoKSBwcmV2ZW50T3ZlcmxheUNsaWNrOiBib29sZWFuO1xuICAgIEBJbnB1dCgpIGRpc2FibGVBbmltYXRpb246IGJvb2xlYW47XG5cbiAgICBASW5wdXQoKVxuICAgIHNldCBtaW51dGVzR2FwKGdhcDogbnVtYmVyKSB7XG4gICAgICAgIGlmIChnYXAgPT0gbnVsbCkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGdhcCA9IE1hdGguZmxvb3IoZ2FwKTtcbiAgICAgICAgdGhpcy5fbWludXRlc0dhcCA9IGdhcCA8PSA1OSA/IGdhcCA6IDE7XG4gICAgfVxuXG4gICAgZ2V0IG1pbnV0ZXNHYXAoKTogbnVtYmVyIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX21pbnV0ZXNHYXA7XG4gICAgfVxuXG4gICAgQElucHV0KClcbiAgICBzZXQgZGVmYXVsdFRpbWUodGltZTogc3RyaW5nKSB7XG4gICAgICAgIHRoaXMuc2V0RGVmYXVsdFRpbWUodGltZSk7XG4gICAgfVxuXG4gICAgQE91dHB1dCgpIHRpbWVTZXQgPSBuZXcgRXZlbnRFbWl0dGVyPHN0cmluZz4oKTtcbiAgICBAT3V0cHV0KCkgb3BlbmVkID0gbmV3IEV2ZW50RW1pdHRlcjxudWxsPigpO1xuICAgIEBPdXRwdXQoKSBjbG9zZWQgPSBuZXcgRXZlbnRFbWl0dGVyPG51bGw+KCk7XG4gICAgQE91dHB1dCgpIGhvdXJTZWxlY3RlZCA9IG5ldyBFdmVudEVtaXR0ZXI8bnVtYmVyPigpO1xuXG4gICAgQFZpZXdDaGlsZCgndGltZXBpY2tlcnd3JykgdGltZXBpY2tlckNvbXBvbmVudDogRWxlbWVudFJlZjtcblxuICAgIHByaXZhdGUgX21pbnV0ZXNHYXA6IG51bWJlcjtcbiAgICBwcml2YXRlIHRpbWVwaWNrZXJJbnB1dDogVGltZXBpY2tlckRpcmVjdGl2ZTtcbiAgICBwcml2YXRlIHN1YnNjcmlwdGlvbnM6IFN1YnNjcmlwdGlvbltdID0gW107XG5cbiAgICBjb25zdHJ1Y3Rvcihwcml2YXRlIHRpbWVwaWNrZXJTZXJ2aWNlOiBOZ3hNYXRlcmlhbFRpbWVwaWNrZXJTZXJ2aWNlLFxuICAgICAgICAgICAgICAgIHByaXZhdGUgZXZlbnRTZXJ2aWNlOiBOZ3hNYXRlcmlhbFRpbWVwaWNrZXJFdmVudFNlcnZpY2UpIHtcblxuICAgICAgICB0aGlzLnN1YnNjcmlwdGlvbnMucHVzaChtZXJnZSh0aGlzLmV2ZW50U2VydmljZS5iYWNrZHJvcENsaWNrLFxuICAgICAgICAgICAgdGhpcy5ldmVudFNlcnZpY2Uua2V5ZG93bkV2ZW50LnBpcGUoZmlsdGVyKGUgPT4gZS5rZXlDb2RlID09PSBFU0NBUEUgJiYgdGhpcy5pc0VzYykpKVxuICAgICAgICAgICAgLnN1YnNjcmliZSgoKSA9PiB0aGlzLmNsb3NlKCkpKTtcblxuICAgIH1cblxuICAgIGdldCBtaW5UaW1lKCk6IHN0cmluZyB8IERhdGVUaW1lIHtcbiAgICAgICAgcmV0dXJuIHRoaXMudGltZXBpY2tlcklucHV0ICYmIHRoaXMudGltZXBpY2tlcklucHV0Lm1pbjtcbiAgICB9XG5cbiAgICBnZXQgbWF4VGltZSgpOiBzdHJpbmcgfCBEYXRlVGltZSB7XG4gICAgICAgIHJldHVybiB0aGlzLnRpbWVwaWNrZXJJbnB1dCAmJiB0aGlzLnRpbWVwaWNrZXJJbnB1dC5tYXg7XG4gICAgfVxuXG4gICAgZ2V0IGRpc2FibGVkKCk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gdGhpcy50aW1lcGlja2VySW5wdXQgJiYgdGhpcy50aW1lcGlja2VySW5wdXQuZGlzYWJsZWQ7XG4gICAgfVxuXG4gICAgZ2V0IGZvcm1hdCgpOiBudW1iZXIge1xuICAgICAgICByZXR1cm4gdGhpcy50aW1lcGlja2VySW5wdXQgJiYgdGhpcy50aW1lcGlja2VySW5wdXQuZm9ybWF0O1xuICAgIH1cblxuICAgIG5nT25Jbml0KCkge1xuICAgICAgICB0aGlzLnN1YnNjcmlwdGlvbnMucHVzaCh0aGlzLnRpbWVwaWNrZXJTZXJ2aWNlLnNlbGVjdGVkSG91clxuICAgICAgICAgICAgLnN1YnNjcmliZShob3VyID0+IHRoaXMuc2VsZWN0ZWRIb3VyID0gaG91cikpO1xuXG4gICAgICAgIHRoaXMuc3Vic2NyaXB0aW9ucy5wdXNoKHRoaXMudGltZXBpY2tlclNlcnZpY2Uuc2VsZWN0ZWRNaW51dGVcbiAgICAgICAgICAgIC5zdWJzY3JpYmUobWludXRlID0+IHRoaXMuc2VsZWN0ZWRNaW51dGUgPSBtaW51dGUpKTtcblxuICAgICAgICB0aGlzLnN1YnNjcmlwdGlvbnMucHVzaCh0aGlzLnRpbWVwaWNrZXJTZXJ2aWNlLnNlbGVjdGVkUGVyaW9kXG4gICAgICAgICAgICAuc3Vic2NyaWJlKHBlcmlvZCA9PiB0aGlzLnNlbGVjdGVkUGVyaW9kID0gcGVyaW9kKSk7XG4gICAgfVxuXG4gICAgLyoqKlxuICAgICAqIFJlZ2lzdGVyIGFuIGlucHV0IHdpdGggdGhpcyB0aW1lcGlja2VyLlxuICAgICAqIGlucHV0IC0gVGhlIHRpbWVwaWNrZXIgaW5wdXQgdG8gcmVnaXN0ZXIgd2l0aCB0aGlzIHRpbWVwaWNrZXJcbiAgICAgKi9cbiAgICByZWdpc3RlcklucHV0KGlucHV0OiBUaW1lcGlja2VyRGlyZWN0aXZlKTogdm9pZCB7XG4gICAgICAgIGlmICh0aGlzLnRpbWVwaWNrZXJJbnB1dCkge1xuICAgICAgICAgICAgdGhyb3cgRXJyb3IoJ0EgVGltZXBpY2tlciBjYW4gb25seSBiZSBhc3NvY2lhdGVkIHdpdGggYSBzaW5nbGUgaW5wdXQuJyk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy50aW1lcGlja2VySW5wdXQgPSBpbnB1dDtcbiAgICB9XG5cbiAgICBvbkhvdXJDaGFuZ2UoaG91cjogQ2xvY2tGYWNlVGltZSk6IHZvaWQge1xuICAgICAgICB0aGlzLnRpbWVwaWNrZXJTZXJ2aWNlLmhvdXIgPSBob3VyO1xuICAgIH1cblxuICAgIG9uSG91clNlbGVjdGVkKGhvdXI6IG51bWJlcik6IHZvaWQge1xuICAgICAgICB0aGlzLmNoYW5nZVRpbWVVbml0KFRpbWVVbml0Lk1JTlVURSk7XG4gICAgICAgIHRoaXMuaG91clNlbGVjdGVkLm5leHQoaG91cik7XG4gICAgfVxuXG4gICAgb25NaW51dGVDaGFuZ2UobWludXRlOiBDbG9ja0ZhY2VUaW1lKTogdm9pZCB7XG4gICAgICAgIHRoaXMudGltZXBpY2tlclNlcnZpY2UubWludXRlID0gbWludXRlO1xuICAgIH1cblxuICAgIGNoYW5nZVBlcmlvZChwZXJpb2Q6IFRpbWVQZXJpb2QpOiB2b2lkIHtcbiAgICAgICAgdGhpcy50aW1lcGlja2VyU2VydmljZS5wZXJpb2QgPSBwZXJpb2Q7XG4gICAgfVxuXG4gICAgY2hhbmdlVGltZVVuaXQodW5pdDogVGltZVVuaXQpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5hY3RpdmVUaW1lVW5pdCA9IHVuaXQ7XG4gICAgfVxuXG4gICAgc2V0VGltZSgpOiB2b2lkIHtcbiAgICAgICAgdGhpcy50aW1lU2V0Lm5leHQodGhpcy50aW1lcGlja2VyU2VydmljZS5nZXRGdWxsVGltZSh0aGlzLmZvcm1hdCkpO1xuICAgICAgICB0aGlzLmNsb3NlKCk7XG4gICAgfVxuXG4gICAgc2V0RGVmYXVsdFRpbWUodGltZTogc3RyaW5nKTogdm9pZCB7XG4gICAgICAgIHRoaXMudGltZXBpY2tlclNlcnZpY2Uuc2V0RGVmYXVsdFRpbWVJZkF2YWlsYWJsZShcbiAgICAgICAgICAgIHRpbWUsIHRoaXMubWluVGltZSBhcyBEYXRlVGltZSwgdGhpcy5tYXhUaW1lIGFzIERhdGVUaW1lLCB0aGlzLmZvcm1hdCwgdGhpcy5taW51dGVzR2FwKTtcbiAgICB9XG5cbiAgICBvcGVuKCk6IHZvaWQge1xuICAgICAgICB0aGlzLmlzT3BlbmVkID0gdHJ1ZTtcbiAgICAgICAgaWYgKCF0aGlzLmRpc2FibGVBbmltYXRpb24pIHtcbiAgICAgICAgICAgIHRoaXMuYW5pbWF0aW9uU3RhdGUgPSBBbmltYXRpb25TdGF0ZS5FTlRFUjtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLm9wZW5lZC5uZXh0KCk7XG4gICAgfVxuXG4gICAgY2xvc2UoKTogdm9pZCB7XG4gICAgICAgIGlmICh0aGlzLmRpc2FibGVBbmltYXRpb24pIHtcbiAgICAgICAgICAgIHRoaXMuY2xvc2VUaW1lcGlja2VyKCk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5hbmltYXRpb25TdGF0ZSA9IEFuaW1hdGlvblN0YXRlLkxFQVZFO1xuICAgIH1cblxuICAgIGFuaW1hdGlvbkRvbmUoZXZlbnQ6IEFuaW1hdGlvbkV2ZW50KTogdm9pZCB7XG4gICAgICAgIGlmIChldmVudC5waGFzZU5hbWUgPT09ICdkb25lJyAmJiBldmVudC50b1N0YXRlID09PSBBbmltYXRpb25TdGF0ZS5MRUFWRSkge1xuICAgICAgICAgICAgdGhpcy5jbG9zZVRpbWVwaWNrZXIoKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIEBIb3N0TGlzdGVuZXIoJ2tleWRvd24nLCBbJyRldmVudCddKVxuICAgIG9uS2V5ZG93bihlOiBLZXlib2FyZEV2ZW50KSB7XG4gICAgICAgIHRoaXMuZXZlbnRTZXJ2aWNlLmRpc3BhdGNoRXZlbnQoZSk7XG4gICAgICAgIGUuc3RvcFByb3BhZ2F0aW9uKCk7XG4gICAgfVxuXG4gICAgbmdPbkRlc3Ryb3koKSB7XG4gICAgICAgIHRoaXMuc3Vic2NyaXB0aW9ucy5mb3JFYWNoKHN1YnNjcmlwdGlvbiA9PiBzdWJzY3JpcHRpb24udW5zdWJzY3JpYmUoKSk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBjbG9zZVRpbWVwaWNrZXIoKTogdm9pZCB7XG4gICAgICAgIHRoaXMuaXNPcGVuZWQgPSBmYWxzZTtcbiAgICAgICAgdGhpcy5hY3RpdmVUaW1lVW5pdCA9IFRpbWVVbml0LkhPVVI7XG4gICAgICAgIHRoaXMuY2xvc2VkLm5leHQoKTtcbiAgICB9XG59XG4iXX0=