ngx-material-timepicker-decon
Version:
Handy material design timepicker for angular DECONied
473 lines • 44.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 };
/** @enum {number} */
var KeyboardTypes = {
'NUMPAD': 0,
'CLOCK': 1,
};
export { KeyboardTypes };
KeyboardTypes[KeyboardTypes['NUMPAD']] = 'NUMPAD';
KeyboardTypes[KeyboardTypes['CLOCK']] = 'CLOCK';
/** @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.keyboardTypes = KeyboardTypes;
this.isEsc = true;
this.keyboardType = KeyboardTypes.NUMPAD;
this.keyboardTypeChanged = new EventEmitter();
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
});
/**
* @return {?}
*/
NgxMaterialTimepickerComponent.blurAll = /**
* @return {?}
*/
function () {
// const tmp = document.createElement('input');
// document.body.appendChild(tmp);
// tmp.focus();
// document.body.removeChild(tmp);
/** @type {?} */
var btn = document.querySelector('.hidden-button');
if (btn) {
btn.focus();
}
};
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; }));
};
/**
* @param {?} type
* @return {?}
*/
NgxMaterialTimepickerComponent.prototype.changeKeyboardType = /**
* @param {?} type
* @return {?}
*/
function (type) {
this.keyboardType = type;
this.keyboardTypeChanged.emit(type);
};
/***
* 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();
};
/**
* @param {?} k
* @return {?}
*/
NgxMaterialTimepickerComponent.prototype.numPadPressed = /**
* @param {?} k
* @return {?}
*/
function (k) {
NgxMaterialTimepickerComponent.blurAll();
this.timepickerService.keyboardClick.emit(new KeyboardEvent('keypress', (/** @type {?} */ ({
ctrlKey: true,
key: k,
charCode: k === 'Backspace' ? 46 : k.charCodeAt(0),
keyCode: k === 'Backspace' ? 46 : k.charCodeAt(0)
}))));
};
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 <button class=\"hidden-button\"></button>\n <button class=\"change-type-button\" *ngIf=\"keyboardType === keyboardTypes.NUMPAD\" (click)=\"changeKeyboardType(keyboardTypes.CLOCK)\">\n <i class=\"decontimepicker-clock\"></i>\n </button>\n <button class=\"change-type-button\" *ngIf=\"keyboardType === keyboardTypes.CLOCK\" (click)=\"changeKeyboardType(keyboardTypes.NUMPAD)\">\n <i class=\"decontimepicker-keypad\"></i>\n </button>\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 *ngIf=\"keyboardType === keyboardTypes.CLOCK\">\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>\n <div *ngIf=\"keyboardType === keyboardTypes.NUMPAD\">\n <timepicker-numpad (keyPressed)=\"numPadPressed($event)\"></timepicker-numpad>\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}@font-face{font-family:decontimepicker;src:url(../assets/icons/decontimepicker.eot);src:url(../assets/icons/decontimepicker.eot?#iefix) format(\"embedded-opentype\"),url(../assets/icons/decontimepicker.woff) format(\"woff\"),url(../assets/icons/decontimepicker.ttf) format(\"truetype\"),url(../assets/icons/decontimepicker.svg#decontimepicker) format(\"svg\");font-weight:400;font-style:normal}[class*=decontimepicker-]:before{display:inline-block;font-family:decontimepicker;font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.decontimepicker-backspace:before{content:'\\0041'}.decontimepicker-clock:before{content:'\\0042'}.decontimepicker-keypad:before{content:'\\0043'}.timepicker-overlay::ng-deep [class*=decontimepicker-]:before{display:inline-block;font-family:decontimepicker;font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.timepicker-overlay::ng-deep .decontimepicker-backspace:before{content:'\\0041'}.timepicker-overlay::ng-deep .decontimepicker-clock:before{content:'\\0042'}.timepicker-overlay::ng-deep .decontimepicker-keypad:before{content:'\\0043'}.simple-keyboard{font-family:HelveticaNeue-Light,Helvetica Neue Light,Helvetica Neue,Helvetica,Arial,Lucida Grande,sans-serif;width:100%;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;box-sizing:border-box;overflow:hidden;touch-action:manipulation}.simple-keyboard .hg-row{display:flex}.simple-keyboard .hg-row:not(:last-child){margin-bottom:5px}.simple-keyboard .hg-row .hg-button-container,.simple-keyboard .hg-row .hg-button:not(:last-child){margin-right:5px}.simple-keyboard .hg-row>div:last-child{margin-right:0}.simple-keyboard .hg-row .hg-button-container{display:flex}.simple-keyboard .hg-button{display:inline-block;flex-grow:1;cursor:pointer}.simple-keyboard .hg-button span{pointer-events:none}.simple-keyboard.hg-theme-default{background-color:rgba(0,0,0,.1);padding:5px;border-radius:5px}.simple-keyboard.hg-theme-default .hg-button{box-shadow:0 0 3px -1px rgba(0,0,0,.3);height:40px;border-radius:5px;box-sizing:border-box;padding:5px;background:#fff;border-bottom:1px solid #b5b5b5;cursor:pointer;display:flex;align-items:center;justify-content:center}.simple-keyboard button.hg-button{border-width:0;outline:0;font-size:inherit}.simple-keyboard.hg-theme-default:not(.hg-touch-events) .hg-button:active{background:#e4e4e4}.simple-keyboard.hg-theme-default.hg-layout-numeric .hg-button{width:33.3%;height:60px;align-items:center;display:flex;justify-content:center}.simple-keyboard.hg-theme-default .hg-button.hg-button-numpadadd,.simple-keyboard.hg-theme-default .hg-button.hg-button-numpadenter{height:85px}.simple-keyboard.hg-theme-default .hg-button.hg-button-numpad0{width:105px}.simple-keyboard.hg-theme-default .hg-button.hg-button-com{max-width:85px}.simple-keyboard.hg-theme-default .hg-button.hg-standardBtn.hg-button-at{max-width:45px}.simple-keyboard.hg-theme-default .hg-button.hg-selectedButton{background:rgba(5,25,70,.53);color:#fff}.simple-keyboard.hg-theme-default .hg-button.hg-standardBtn[data-skbtn=\".com\"]{max-width:82px}.simple-keyboard.hg-theme-default .hg-button.hg-standardBtn[data-skbtn=\"@\"]{max-width:60px}.hidden-button{display:block;visibility:hidden;height:1px;width:1px;overflow:hidden;border:0;position:fixed;top:-1px;left:-1px}.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{color:#fff;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 }],
keyboardType: [{ type: Input }],
keyboardTypeChanged: [{ type: Output }],
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.keyboardTypes;
/** @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.keyboardType;
/** @type {?} */
NgxMaterialTimepickerComponent.prototype.keyboardTypeChanged;
/** @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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmd4LW1hdGVyaWFsLXRpbWVwaWNrZXIuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6Im5nOi8vbmd4LW1hdGVyaWFsLXRpbWVwaWNrZXItZGVjb24vIiwic291cmNlcyI6WyJzcmMvYXBwL21hdGVyaWFsLXRpbWVwaWNrZXIvbmd4LW1hdGVyaWFsLXRpbWVwaWNrZXIuY29tcG9uZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7QUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFFLFVBQVUsRUFBRSxZQUFZLEVBQUUsWUFBWSxFQUFFLEtBQUssRUFBcUIsTUFBTSxFQUFFLFdBQVcsRUFBRSxTQUFTLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFHNUksT0FBTyxFQUFFLEtBQUssRUFBZ0IsTUFBTSxNQUFNLENBQUM7QUFDM0MsT0FBTyxFQUFFLDRCQUE0QixFQUFFLE1BQU0sNENBQTRDLENBQUM7QUFDMUYsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQ25ELE9BQU8sRUFBRSxPQUFPLEVBQWtCLEtBQUssRUFBRSxVQUFVLEVBQUUsT0FBTyxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDMUYsT0FBTyxFQUFFLGlDQUFpQyxFQUFFLE1BQU0sa0RBQWtELENBQUM7QUFDckcsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLGdCQUFnQixDQUFDOzs7SUFLcEMsT0FBUSxPQUFPO0lBQ2YsT0FBUSxPQUFPOzs7OztJQUdmLFdBQVE7SUFDUixVQUFPOzs7NEJBRFAsUUFBUSxLQUFSLFFBQVE7NEJBQ1IsT0FBTyxLQUFQLE9BQU87O0lBR0wsTUFBTSxHQUFHLEVBQUU7QUFFakI7SUF1RUksd0NBQW9CLGlCQUErQyxFQUMvQyxZQUErQztRQURuRSxpQkFPQztRQVBtQixzQkFBaUIsR0FBakIsaUJBQWlCLENBQThCO1FBQy9DLGlCQUFZLEdBQVosWUFBWSxDQUFtQztRQWhEbkUsYUFBUSxHQUFHLFFBQVEsQ0FBQztRQUNwQixtQkFBYyxHQUFHLFFBQVEs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LFNBQUMsU0FBUyxFQUFFLENBQUMsUUFBUSxDQUFDOztJQXlCdkMscUNBQUM7Q0FBQSxBQXBORCxJQW9OQztTQWxNWSw4QkFBOEI7OztJQUV2QyxzREFBNEI7O0lBQzVCLHdEQUE4Qjs7SUFDOUIsd0RBQTJCOztJQUUzQixrREFBb0I7O0lBQ3BCLHdEQUErQjs7SUFFL0Isa0RBQWlCOztJQUNqQix3REFBK0I7O0lBRS9CLHVEQUE4Qjs7SUFFOUIsdURBQTBDOztJQUMxQywwREFBNkM7O0lBQzdDLHdEQUEyQzs7SUFDM0MsK0NBQTJCOztJQUMzQiw2REFBc0M7O0lBQ3RDLDZEQUFzQzs7SUFDdEMsMERBQW1DOztJQUNuQyxzREFBNEQ7O0lBQzVELDZEQUFnRjs7SUFvQmhGLGlEQUErQzs7SUFDL0MsZ0RBQTRDOztJQUM1QyxnREFBNEM7O0lBQzVDLHNEQUFvRDs7SUFFcEQsNkRBQTJEOzs7OztJQUUzRCxxREFBNEI7Ozs7O0lBQzVCLHlEQUE2Qzs7Ozs7SUFDN0MsdURBQTJDOzs7OztJQUUvQiwyREFBdUQ7Ozs7O0lBQ3ZELHNEQUF1RCIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBvbmVudCwgRWxlbWVudFJlZiwgRXZlbnRFbWl0dGVyLCBIb3N0TGlzdGVuZXIsIElucHV0LCBPbkRlc3Ryb3ksIE9uSW5pdCwgT3V0cHV0LCBUZW1wbGF0ZVJlZiwgVmlld0NoaWxkIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBDbG9ja0ZhY2VUaW1lIH0gZnJvbSAnLi9tb2RlbHMvY2xvY2stZmFjZS10aW1lLmludGVyZmFjZSc7XG5pbXBvcnQgeyBUaW1lUGVyaW9kIH0gZnJvbSAnLi9tb2RlbHMvdGltZS1wZXJpb2QuZW51bSc7XG5pbXBvcnQgeyBtZXJnZSwgU3Vic2NyaXB0aW9uIH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyBOZ3hNYXRlcmlhbFRpbWVwaWNrZXJTZXJ2aWNlIH0gZnJvbSAnLi9zZXJ2aWNlcy9uZ3gtbWF0ZXJpYWwtdGltZXBpY2tlci5zZXJ2aWNlJztcbmltcG9ydCB7IFRpbWVVbml0IH0gZnJvbSAnLi9tb2RlbHMvdGltZS11bml0LmVudW0nO1xuaW1wb3J0IHsgYW5pbWF0ZSwgQW5pbWF0aW9uRXZlbnQsIHN0eWxlLCB0cmFuc2l0aW9uLCB0cmlnZ2VyIH0gZnJvbSAnQGFuZ3VsYXIvYW5pbWF0aW9ucyc7XG5pbXBvcnQgeyBOZ3hNYXRlcmlhbFRpbWVwaWNrZXJFdmVudFNlcnZpY2UgfSBmcm9tICcuL3NlcnZpY2VzL25neC1tYXRlcmlhbC10aW1lcGlja2VyLWV2ZW50LnNlcnZpY2UnO1xuaW1wb3J0IHsgZmlsdGVyIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuaW1wb3J0IHsgVGltZXBpY2tlckRpcmVjdGl2ZSB9IGZyb20gJy4vZGlyZWN0aXZlcy9uZ3gtdGltZXBpY2tlci5kaXJlY3RpdmUnO1xuaW1wb3J0IHsgRGF0ZVRpbWUgfSBmcm9tICdsdXhvbic7XG5cbmV4cG9ydCBlbnVtIEFuaW1hdGlvblN0YXRlIHtcbiAgICBFTlRFUiA9ICdlbnRlcicsXG4gICAgTEVBVkUgPSAnbGVhdmUnXG59XG5leHBvcnQgZW51bSBLZXlib2FyZFR5cGVzIHtcbiAgICAnTlVNUEFEJyxcbiAgICAnQ0xPQ0snXG59XG5cbmNvbnN0IEVTQ0FQRSA9IDI3O1xuXG5AQ29tcG9uZW50KHtcbiAgICBzZWxlY3RvcjogJ25neC1tYXRlcmlhbC10aW1lcGlja2VyJyxcbiAgICB0ZW1wbGF0ZVVybDogJy4vbmd4LW1hdGVyaWFsLXRpbWVwaWNrZXIuY29tcG9uZW50Lmh0bWwnLFxuICAgIHN0eWxlVXJsczogWycuL25neC1tYXRlcmlhbC10aW1lcGlja2VyLmNvbXBvbmVudC5zY3NzJ10sXG4gICAgYW5pbWF0aW9uczogW1xuICAgICAgICB0cmlnZ2VyKCd0aW1lcGlja2VyJywgW1xuICAgICAgICAgICAgdHJhbnNpdGlvbihgKiA9PiAke0FuaW1hdGlvblN0YXRlLkVOVEVSfWAsIFtcbiAgICAgICAgICAgICAgICBzdHlsZSh7dHJhbnNmb3JtOiAndHJhbnNsYXRlWSgtMzAlKSd9KSxcbiAgICAgICAgICAgICAgICBhbmltYXRlKCcwLjJzIGVhc2Utb3V0Jywgc3R5bGUoe3RyYW5zZm9ybTogJ3RyYW5zbGF0ZVkoMCknfSkpXG4gICAgICAgICAgICBdKSxcbiAgICAgICAgICAgIHRyYW5zaXRpb24oYCR7QW5pbWF0aW9uU3RhdGUuRU5URVJ9ID0+ICR7QW5pbWF0aW9uU3RhdGUuTEVBVkV9YCwgW1xuICAgICAgICAgICAgICAgIHN0eWxlKHt0cmFuc2Zvcm06ICd0cmFuc2xhdGVZKDApJywgb3BhY2l0eTogMX0pLFxuICAgICAgICAgICAgICAgIGFuaW1hdGUoJzAuMnMgZWFzZS1vdXQnLCBzdHlsZSh7dHJhbnNmb3JtOiAndHJhbnNsYXRlWSgtMzAlKScsIG9wYWNpdHk6IDB9KSlcbiAgICAgICAgICAgIF0pXG4gICAgICAgIF0pXG4gICAgXSxcbiAgICBwcm92aWRlcnM6IFtOZ3hNYXRlcmlhbFRpbWVwaWNrZXJTZXJ2aWNlXVxufSlcbmV4cG9ydCBjbGFzcyBOZ3hNYXRlcmlhbFRpbWVwaWNrZXJDb21wb25lbnQgaW1wbGVtZW50cyBPbkluaXQsIE9uRGVzdHJveSB7XG5cbiAgICBzZWxlY3RlZEhvdXI6IENsb2NrRmFjZVRpbWU7XG4gICAgc2VsZWN0ZWRNaW51dGU6IENsb2NrRmFjZVRpbWU7XG4gICAgc2VsZWN0ZWRQZXJpb2Q6IFRpbWVQZXJpb2Q7XG5cbiAgICB0aW1lVW5pdCA9IFRpbWVVbml0O1xuICAgIGFjdGl2ZVRpbWVVbml0ID0gVGltZVVuaXQuSE9VUjtcblxuICAgIGlzT3BlbmVkID0gZmFsc2U7XG4gICAgYW5pbWF0aW9uU3RhdGU6IEFuaW1hdGlvblN0YXRlO1xuXG4gICAga2V5Ym9hcmRUeXBlcyA9IEtleWJvYXJkVHlwZXM7XG5cbiAgICBASW5wdXQoKSBjYW5jZWxCdG5UbXBsOiBUZW1wbGF0ZVJlZjxOb2RlPjtcbiAgICBASW5wdXQoKSBlZGl0YWJsZUhpbnRUbXBsOiBUZW1wbGF0ZVJlZjxOb2RlPjtcbiAgICBASW5wdXQoKSBjb25maXJtQnRuVG1wbDogVGVtcGxhdGVSZWY8Tm9kZT47XG4gICAgQElucHV0KCdFU0MnKSBpc0VzYyA9IHRydWU7XG4gICAgQElucHV0KCkgZW5hYmxlS2V5Ym9hcmRJbnB1dDogYm9vbGVhbjtcbiAgICBASW5wdXQoKSBwcmV2ZW50T3ZlcmxheUNsaWNrOiBib29sZWFuO1xuICAgIEBJbnB1dCgpIGRpc2FibGVBbmltYXRpb246IGJvb2xlYW47XG4gICAgQElucHV0KCkga2V5Ym9hcmRUeXBlOiBLZXlib2FyZFR5cGVzID0gS2V5Ym9hcmRUeXBlcy5OVU1QQUQ7XG4gICAgQE91dHB1dCgpIGtleWJvYXJkVHlwZUNoYW5nZWQ6IEV2ZW50RW1pdHRlcjxLZXlib2FyZFR5cGVzPiA9IG5ldyBFdmVudEVtaXR0ZXIoKTtcblxuICAgIEBJbnB1dCgpXG4gICAgc2V0IG1pbnV0ZXNHYXAoZ2FwOiBudW1iZXIpIHtcbiAgICAgICAgaWYgKGdhcCA9PSBudWxsKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgZ2FwID0gTWF0aC5mbG9vcihnYXApO1xuICAgICAgICB0aGlzLl9taW51dGVzR2FwID0gZ2FwIDw9IDU5ID8gZ2FwIDogMTtcbiAgICB9XG5cbiAgICBnZXQgbWludXRlc0dhcCgpOiBudW1iZXIge1xuICAgICAgICByZXR1cm4gdGhpcy5fbWludXRlc0dhcDtcbiAgICB9XG5cbiAgICBASW5wdXQoKVxuICAgIHNldCBkZWZhdWx0VGltZSh0aW1lOiBzdHJpbmcpIHtcbiAgICAgICAgdGhpcy5zZXREZWZhdWx0VGltZSh0aW1lKTtcbiAgICB9XG5cbiAgICBAT3V0cHV0KCkgdGltZVNldCA9IG5ldyBFdmVudEVtaXR0ZXI8c3RyaW5nPigpO1xuICAgIEBPdXRwdXQoKSBvcGVuZWQgPSBuZXcgRXZlbnRFbWl0dGVyPG51bGw+KCk7XG4gICAgQE91dHB1dCgpIGNsb3NlZCA9IG5ldyBFdmVudEVtaXR0ZXI8bnVsbD4oKTtcbiAgICBAT3V0cHV0KCkgaG91clNlbGVjdGVkID0gbmV3IEV2ZW50RW1pdHRlcjxudW1iZXI+KCk7XG5cbiAgICBAVmlld0NoaWxkKCd0aW1lcGlja2Vyd3cnKSB0aW1lcGlja2VyQ29tcG9uZW50OiBFbGVtZW50UmVmO1xuXG4gICAgcHJpdmF0ZSBfbWludXRlc0dhcDogbnVtYmVyO1xuICAgIHByaXZhdGUgdGltZXBpY2tlcklucHV0OiBUaW1lcGlja2VyRGlyZWN0aXZlO1xuICAgIHByaXZhdGUgc3Vic2NyaXB0aW9uczogU3Vic2NyaXB0aW9uW10gPSBbXTtcblxuICAgIGNvbnN0cnVjdG9yKHByaXZhdGUgdGltZXBpY2tlclNlcnZpY2U6IE5neE1hdGVyaWFsVGltZXBpY2tlclNlcnZpY2UsXG4gICAgICAgICAgICAgICAgcHJpdmF0ZSBldmVudFNlcnZpY2U6IE5neE1hdGVyaWFsVGltZXBpY2tlckV2ZW50U2VydmljZSkge1xuXG4gICAgICAgIHRoaXMuc3Vic2NyaXB0aW9ucy5wdXNoKG1lcmdlKHRoaXMuZXZlbnRTZXJ2aWNlLmJhY2tkcm9wQ2xpY2ssXG4gICAgICAgICAgICB0aGlzLmV2ZW50U2VydmljZS5rZXlkb3duRXZlbnQucGlwZShmaWx0ZXIoZSA9PiBlLmtleUNvZGUgPT09IEVTQ0FQRSAmJiB0aGlzLmlzRXNjKSkpXG4gICAgICAgICAgICAuc3Vic2NyaWJlKCgpID0+IHRoaXMuY2xvc2UoKSkpO1xuXG4gICAgfVxuXG4gICAgcHVibGljIHN0YXRpYyBibHVyQWxsKCkge1xuICAgICAgICAvLyBjb25zdCB0bXAgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdpbnB1dCcpO1xuICAgICAgICAvLyBkb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKHRtcCk7XG4gICAgICAgIC8vIHRtcC5mb2N1cygpO1xuICAgICAgICAvLyBkb2N1bWVudC5ib2R5LnJlbW92ZUNoaWxkKHRtcCk7XG4gICAgICAgIGNvbnN0IGJ0bjogSFRNTEJ1dHRvbkVsZW1lbnQgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcuaGlkZGVuLWJ1dHRvbicpO1xuICAgICAgICBpZiAoYnRuKSB7XG4gICAgICAgICAgICBidG4uZm9jdXMoKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGdldCBtaW5UaW1lKCk6IHN0cmluZyB8IERhdGVUaW1lIHtcbiAgICAgICAgcmV0dXJuIHRoaXMudGltZXBpY2tlcklucHV0ICYmIHRoaXMudGltZXBpY2tlcklucHV0Lm1pbjtcbiAgICB9XG5cbiAgICBnZXQgbWF4VGltZSgpOiBzdHJpbmcgfCBEYXRlVGltZSB7XG4gICAgICAgIHJldHVybiB0aGlzLnRpbWVwaWNrZXJJbnB1dCAmJiB0aGlzLnRpbWVwaWNrZXJJbnB1dC5tYXg7XG4gICAgfVxuXG4gICAgZ2V0IGRpc2FibGVkKCk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gdGhpcy50aW1lcGlja2VySW5wdXQgJiYgdGhpcy50aW1lcGlja2VySW5wdXQuZGlzYWJsZWQ7XG4gICAgfVxuXG4gICAgZ2V0IGZvcm1hdCgpOiBudW1iZXIge1xuICAgICAgICByZXR1cm4gdGhpcy50aW1lcGlja2VySW5wdXQgJiYgdGhpcy50aW1lcGlja2VySW5wdXQuZm9ybWF0O1xuICAgIH1cblxuICAgIG5nT25Jbml0KCkge1xuICAgICAgICB0aGlzLnN1YnNjcmlwdGlvbnMucHVzaCh0aGlzLnRpbWVwaWNrZXJTZXJ2aWNlLnNlbGVjdGVkSG91clxuICAgICAgICAgICAgLnN1YnNjcmliZShob3VyID0+IHRoaXMuc2VsZWN0ZWRIb3VyID0gaG91cikpO1xuXG4gICAgICAgIHRoaXMuc3Vic2NyaXB0aW9ucy5wdXNoKHRoaXMudGltZXBpY2tlclNlcnZpY2Uuc2VsZWN0ZWRNaW51dGVcbiAgICAgICAgICAgIC5zdWJzY3JpYmUobWludXRlID0+IHRoaXMuc2VsZWN0ZWRNaW51dGUgPSBtaW51dGUpKTtcblxuICAgICAgICB0aGlzLnN1YnNjcmlwdGlvbnMucHVzaCh0aGlzLnRpbWVwaWNrZXJTZXJ2aWNlLnNlbGVjdGVkUGVyaW9kXG4gICAgICAgICAgICAuc3Vic2NyaWJlKHBlcmlvZCA9PiB0aGlzLnNlbGVjdGVkUGVyaW9kID0gcGVyaW9kKSk7XG4gICAgfVxuXG4gICAgY2hhbmdlS2V5Ym9hcmRUeXBlKHR5cGU6IEtleWJvYXJkVHlwZXMpIHtcbiAgICAgICAgdGhpcy5rZXlib2FyZFR5cGUgPSB0eXBlO1xuICAgICAgICB0aGlzLmtleWJvYXJkVHlwZUNoYW5nZWQuZW1pdCh0eXBlKTtcbiAgICB9XG5cbiAgICAvKioqXG4gICAgICogUmVnaXN0ZXIgYW4gaW5wdXQgd2l0aCB0aGlzIHRpbWVwaWNrZXIuXG4gICAgICogaW5wdXQgLSBUaGUgdGltZXBpY2tlciBpbnB1dCB0byByZWdpc3RlciB3aXRoIHRoaXMgdGltZXBpY2tlclxuICAgICAqL1xuICAgIHJlZ2lzdGVySW5wdXQoaW5wdXQ6IFRpbWVwaWNrZXJEaXJlY3RpdmUpOiB2b2lkIHtcbiAgICAgICAgaWYgKHRoaXMudGltZXBpY2tlcklucHV0KSB7XG4gICAgICAgICAgICB0aHJvdyBFcnJvcignQSBUaW1lcGlja2VyIGNhbiBvbmx5IGJlIGFzc29jaWF0ZWQgd2l0aCBhIHNpbmdsZSBpbnB1dC4nKTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLnRpbWVwaWNrZXJJbnB1dCA9IGlucHV0O1xuICAgIH1cblxuICAgIG9uSG91ckNoYW5nZShob3VyOiBDbG9ja0ZhY2VUaW1lKTogdm9pZCB7XG4gICAgICAgIHRoaXMudGltZXBpY2tlclNlcnZpY2UuaG91ciA9IGhvdXI7XG4gICAgfVxuXG4gICAgb25Ib3VyU2VsZWN0ZWQoaG91cjogbnVtYmVyKTogdm9pZCB7XG4gICAgICAgIHRoaXMuY2hhbmdlVGltZVVuaXQoVGltZVVuaXQuTUlOVVRFKTtcbiAgICAgICAgdGhpcy5ob3VyU2VsZWN0ZWQubmV4dChob3VyKTtcbiAgICB9XG5cbiAgICBvbk1pbnV0ZUNoYW5nZShtaW51dGU6IENsb2NrRmFjZVRpbWUpOiB2b2lkIHtcbiAgICAgICAgdGhpcy50aW1lcGlja2VyU2VydmljZS5taW51dGUgPSBtaW51dGU7XG4gICAgfVxuXG4gICAgY2hhbmdlUGVyaW9kKHBlcmlvZDogVGltZVBlcmlvZCk6IHZvaWQge1xuICAgICAgICB0aGlzLnRpbWVwaWNrZXJTZXJ2aWNlLnBlcmlvZCA9IHBlcmlvZDtcbiAgICB9XG5cbiAgICBjaGFuZ2VUaW1lVW5pdCh1bml0OiBUaW1lVW5pdCk6IHZvaWQge1xuICAgICAgICB0aGlzLmFjdGl2ZVRpbWVVbml0ID0gdW5pdDtcbiAgICB9XG5cbiAgICBzZXRUaW1lKCk6IHZvaWQge1xuICAgICAgICB0aGlzLnRpbWVTZXQubmV4dCh0aGlzLnRpbWVwaWNrZXJTZXJ2aWNlLmdldEZ1bGxUaW1lKHRoaXMuZm9ybWF0KSk7XG4gICAgICAgIHRoaXMuY2xvc2UoKTtcbiAgICB9XG5cbiAgICBzZXREZWZhdWx0VGltZSh0aW1lOiBzdHJpbmcpOiB2b2lkIHtcbiAgICAgICAgdGhpcy50aW1lcGlja2VyU2VydmljZS5zZXREZWZhdWx0VGltZUlmQXZhaWxhYmxlKFxuICAgICAgICAgICAgdGltZSwgdGhpcy5taW5UaW1lIGFzIERhdGVUaW1lLCB0aGlzLm1heFRpbWUgYXMgRGF0ZVRpbWUsIHRoaXMuZm9ybWF0LCB0aGlzLm1pbnV0ZXNHYXApO1xuICAgIH1cblxuICAgIG9wZW4oKTogdm9pZCB7XG4gICAgICAgIHRoaXMuaXNPcGVuZWQgPSB0cnVlO1xuICAgICAgICBpZiAoIXRoaXMuZGlzYWJsZUFuaW1hdGlvbikge1xuICAgICAgICAgICAgdGhpcy5hbmltYXRpb25TdGF0ZSA9IEFuaW1hdGlvblN0YXRlLkVOVEVSO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMub3BlbmVkLm5leHQoKTtcbiAgICB9XG5cbiAgICBjbG9zZSgpOiB2b2lkIHtcbiAgICAgICAgaWYgKHRoaXMuZGlzYWJsZUFuaW1hdGlvbikge1xuICAgICAgICAgICAgdGhpcy5jbG9zZVRpbWVwaWNrZXIoKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLmFuaW1hdGlvblN0YXRlID0gQW5pbWF0aW9uU3RhdGUuTEVBVkU7XG4gICAgfVxuXG4gICAgYW5pbWF0aW9uRG9uZShldmVudDogQW5pbWF0aW9uRXZlbnQpOiB2b2lkIHtcbiAgICAgICAgaWYgKGV2ZW50LnBoYXNlTmFtZSA9PT0gJ2RvbmUnICYmIGV2ZW50LnRvU3RhdGUgPT09IEFuaW1hdGlvblN0YXRlLkxFQVZFKSB7XG4gICAgICAgICAgICB0aGlzLmNsb3NlVGltZXBpY2tlcigpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgQEhvc3RMaXN0ZW5lcigna2V5ZG93bicsIFsnJGV2ZW50J10pXG4gICAgb25LZXlkb3duKGU6IEtleWJvYXJkRXZlbnQpIHtcbiAgICAgICAgdGhpcy5ldmVudFNlcnZpY2UuZGlzcGF0Y2hFdmVudChlKTtcbiAgICAgICAgZS5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICB9XG5cbiAgICBuZ09uRGVzdHJveSgpIHtcbiAgICAgICAgdGhpcy5zdWJzY3JpcHRpb25zLmZvckVhY2goc3Vic2NyaXB0aW9uID0+IHN1YnNjcmlwdGlvbi51bnN1YnNjcmliZSgpKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGNsb3NlVGltZXBpY2tlcigpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5pc09wZW5lZCA9IGZhbHNlO1xuICAgICAgICB0aGlzLmFjdGl2ZVRpbWVVbml0ID0gVGltZVVuaXQuSE9VUjtcbiAgICAgICAgdGhpcy5jbG9zZWQubmV4dCgpO1xuICAgIH1cblxuICAgIG51bVBhZFByZXNzZWQoazogc3RyaW5nKSB7XG4gICAgICAgIE5neE1hdGVyaWFsVGltZXBpY2tlckNvbXBvbmVudC5ibHVyQWxsKCk7XG4gICAgICAgIHRoaXMudGltZXBpY2tlclNlcnZpY2Uua2V5Ym9hcmRDbGljay5lbWl0KG5ldyBLZXlib2FyZEV2ZW50KCdrZXlwcmVzcycsIDxhbnk+e1xuICAgICAgICAgICAgY3RybEtleTogdHJ1ZSxcbiAgICAgICAgICAgIGtleTogayxcbiAgICAgICAgICAgIGNoYXJDb2RlOiBrID09PSAnQmFja3NwYWNlJyA/IDQ2IDogay5jaGFyQ29kZUF0KDApLFxuICAgICAgICAgICAga2V5Q29kZTogayA9PT0gJ0JhY2tzcGFjZScgPyA0NiA6IGsuY2hhckNvZGVBdCgwKVxuICAgICAgICB9KSk7XG4gICAgfVxufVxuIl19