UNPKG

ngx-material-timepicker-decon

Version:
310 lines 34.7 kB
/** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ import { ChangeDetectionStrategy, Component, ElementRef, EventEmitter, HostListener, Input, Output, ViewChild } from '@angular/core'; import { TimeUnit } from '../../models/time-unit.enum'; /** @type {?} */ const CLOCK_HAND_STYLES = { small: { height: '75px', top: 'calc(50% - 75px)' }, large: { height: '103px', top: 'calc(50% - 103px)' } }; export class NgxMaterialTimepickerFaceComponent { constructor() { this.timeUnit = TimeUnit; this.innerClockFaceSize = 85; this.timeChange = new EventEmitter(); this.timeSelected = new EventEmitter(); } /** * @return {?} */ ngAfterViewInit() { this.setClockHandPosition(); this.addTouchEvents(); } /** * @param {?} changes * @return {?} */ ngOnChanges(changes) { /** @type {?} */ const faceTimeChanges = changes['faceTime']; /** @type {?} */ const selectedTimeChanges = changes['selectedTime']; if ((faceTimeChanges && faceTimeChanges.currentValue) && (selectedTimeChanges && selectedTimeChanges.currentValue)) { /* Set time according to passed an input value */ this.selectedTime = this.faceTime.find(time => time.time === this.selectedTime.time); } if (selectedTimeChanges && selectedTimeChanges.currentValue) { this.setClockHandPosition(); } if (faceTimeChanges && faceTimeChanges.currentValue) { // To avoid an error ExpressionChangedAfterItHasBeenCheckedError setTimeout(() => this.selectAvailableTime()); } } /** * @param {?} _ * @param {?} time * @return {?} */ trackByTime(_, time) { return time.time; } /** * @param {?} e * @return {?} */ onMousedown(e) { e.preventDefault(); this.isStarted = true; } /** * @param {?} e * @return {?} */ selectTime(e) { if (!this.isStarted && (e instanceof MouseEvent && e.type !== 'click')) { return; } /** @type {?} */ const clockFaceCords = this.clockFace.nativeElement.getBoundingClientRect(); /* Get x0 and y0 of the circle */ /** @type {?} */ const centerX = clockFaceCords.left + clockFaceCords.width / 2; /** @type {?} */ const centerY = clockFaceCords.top + clockFaceCords.height / 2; /* Counting the arctangent and convert it to from radian to deg */ /** @type {?} */ const arctangent = Math.atan(Math.abs(e.clientX - centerX) / Math.abs(e.clientY - centerY)) * 180 / Math.PI; /* Get angle according to quadrant */ /** @type {?} */ const circleAngle = countAngleByCords(centerX, centerY, e.clientX, e.clientY, arctangent); /* Check if selected time from the inner clock face (24 hours format only) */ /** @type {?} */ const isInnerClockChosen = this.format && this.isInnerClockFace(centerX, centerY, e.clientX, e.clientY); /* Round angle according to angle step */ /** @type {?} */ const angleStep = this.unit === TimeUnit.MINUTE ? (6 * (this.minutesGap || 1)) : 30; /** @type {?} */ const roundedAngle = isInnerClockChosen ? roundAngle(circleAngle, angleStep) + 360 : roundAngle(circleAngle, angleStep); /** @type {?} */ const angle = roundedAngle === 0 ? 360 : roundedAngle; /** @type {?} */ const selectedTime = this.faceTime.find(val => val.angle === angle); if (selectedTime && !selectedTime.disabled) { this.timeChange.next(selectedTime); /* To let know whether user ended interaction with clock face */ if (!this.isStarted) { this.timeSelected.next(selectedTime.time); } } } /** * @param {?} e * @return {?} */ onMouseup(e) { e.preventDefault(); this.isStarted = false; } /** * @param {?} hour * @return {?} */ isHourSelected(hour) { return (hour === this.selectedTime.time) && !this.isClockFaceDisabled; } /** * @param {?} minute * @return {?} */ isMinuteSelected(minute) { return ((this.selectedTime.time === minute) && (minute % (this.minutesGap || 5) === 0)) && !this.isClockFaceDisabled; } /** * @return {?} */ ngOnDestroy() { this.removeTouchEvents(); } /** * @private * @return {?} */ addTouchEvents() { this.touchStartHandler = this.onMousedown.bind(this); this.touchEndHandler = this.onMouseup.bind(this); this.clockFace.nativeElement.addEventListener('touchstart', this.touchStartHandler); this.clockFace.nativeElement.addEventListener('touchend', this.touchEndHandler); } /** * @private * @return {?} */ removeTouchEvents() { this.clockFace.nativeElement.removeEventListener('touchstart', this.touchStartHandler); this.clockFace.nativeElement.removeEventListener('touchend', this.touchEndHandler); } /** * @private * @return {?} */ setClockHandPosition() { if (this.format === 24) { if (this.selectedTime.time > 12 || this.selectedTime.time === 0) { this.decreaseClockHand(); } else { this.increaseClockHand(); } } this.clockHand.nativeElement.style.transform = `rotate(${this.selectedTime.angle}deg)`; } /** * @private * @return {?} */ selectAvailableTime() { /** @type {?} */ const currentTime = this.faceTime.find(time => this.selectedTime.time === time.time); this.isClockFaceDisabled = this.faceTime.every(time => time.disabled); if ((currentTime && currentTime.disabled) && !this.isClockFaceDisabled) { /** @type {?} */ const availableTime = this.faceTime.find(time => !time.disabled); this.timeChange.next(availableTime); } } /** * @private * @param {?} x0 * @param {?} y0 * @param {?} x * @param {?} y * @return {?} */ isInnerClockFace(x0, y0, x, y) { /* Detect whether time from the inner clock face or not (24 format only) */ return Math.sqrt(Math.pow(x - x0, 2) + Math.pow(y - y0, 2)) < this.innerClockFaceSize; } /** * @private * @return {?} */ decreaseClockHand() { this.clockHand.nativeElement.style.height = CLOCK_HAND_STYLES.small.height; this.clockHand.nativeElement.style.top = CLOCK_HAND_STYLES.small.top; } /** * @private * @return {?} */ increaseClockHand() { this.clockHand.nativeElement.style.height = CLOCK_HAND_STYLES.large.height; this.clockHand.nativeElement.style.top = CLOCK_HAND_STYLES.large.top; } } NgxMaterialTimepickerFaceComponent.decorators = [ { type: Component, args: [{ selector: 'ngx-material-timepicker-face', template: "<div class=\"clock-face\" #clockFace>\n <div *ngIf=\"unit !== timeUnit.MINUTE;else minutesFace\" class=\"clock-face__container\">\n <div class=\"clock-face__number clock-face__number--outer\"\n [style.transform]=\"'rotateZ('+ time.angle +'deg) translateX(-50%)' | styleSanitizer\"\n *ngFor=\"let time of faceTime.slice(0, 12); trackBy: trackByTime\">\n\t\t\t<span [style.transform]=\"'rotateZ(-'+ time.angle +'deg)' | styleSanitizer\"\n [ngClass]=\"{'active': isHourSelected(time.time), 'disabled': time.disabled}\">{{time.time}}</span>\n </div>\n <div class=\"clock-face__inner\" *ngIf=\"faceTime.length > 12\"\n [style.top]=\"'calc(50% - ' + innerClockFaceSize + 'px)'\">\n <div class=\"clock-face__number clock-face__number--inner\"\n [style.transform]=\"'rotateZ('+ time.angle +'deg) translateX(-50%)' | styleSanitizer\"\n [style.height.px]=\"innerClockFaceSize\"\n *ngFor=\"let time of faceTime.slice(12, 24); trackBy: trackByTime\">\n\t\t\t<span [style.transform]=\"'rotateZ(-'+ time.angle +'deg)' | styleSanitizer\"\n [ngClass]=\"{'active': isHourSelected(time.time), 'disabled': time.disabled}\">\n {{time.time === 0 ? '00' : time.time}}</span>\n </div>\n </div>\n </div>\n\n <span class=\"clock-face__clock-hand\" [ngClass]=\"{'clock-face__clock-hand_minute': unit === timeUnit.MINUTE}\"\n #clockHand [hidden]=\"isClockFaceDisabled\"></span>\n</div>\n<ng-template #minutesFace>\n <div class=\"clock-face__container\">\n <div class=\"clock-face__number clock-face__number--outer\"\n [style.transform]=\"'rotateZ('+ time.angle +'deg) translateX(-50%)' | styleSanitizer\"\n *ngFor=\"let time of faceTime; trackBy: trackByTime\">\n\t<span [style.transform]=\"'rotateZ(-'+ time.angle +'deg)' | styleSanitizer\"\n [ngClass]=\"{'active': isMinuteSelected(time.time), 'disabled': time.disabled}\">\n\t{{time.time === 0 ? '00' : time.time | minutesFormatter: minutesGap}}</span>\n </div>\n </div>\n</ng-template>\n", changeDetection: ChangeDetectionStrategy.OnPush, styles: [".clock-face{width:290px;height:290px;border-radius:50%;position:relative;display:flex;justify-content:center;padding:20px;box-sizing:border-box;background-color:#f0f0f0}@supports (background-color:var(--clock-face-background-color)){.clock-face{background-color:var(--clock-face-background-color)}}.clock-face__inner{position:absolute}.clock-face__container{margin-left:-2px}.clock-face__number{position:absolute;-webkit-transform-origin:0 100%;transform-origin:0 100%;width:50px;text-align:center;z-index:2}.clock-face__number--outer{height:calc(290px / 2 - 20px)}.clock-face__number--outer>span{font-size:16px;color:#6c6c6c}@supports (color:var(--clock-face-time-inactive-color)){.clock-face__number--outer>span{color:var(--clock-face-time-inactive-color)}}.clock-face__number--inner>span{font-size:14px;color:#929292}@supports (color:var(--clock-face-inner-time-inactive-color)){.clock-face__number--inner>span{color:var(--clock-face-inner-time-inactive-color)}}.clock-face__number>span{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;width:30px;height:30px;display:flex;justify-content:center;align-items:center;margin:auto;border-radius:50%;font-weight:500;font-family:Roboto,sans-serif}@supports (font-family:var(--primary-font-family)){.clock-face__number>span{font-family:var(--primary-font-family)}}.clock-face__number>span.active{background-color:#00bfff;color:#fff}@supports (background-color:var(--clock-hand-color)){.clock-face__number>span.active{background-color:var(--clock-hand-color);color:var(--clock-face-time-active-color)}}.clock-face__number>span.disabled{color:#c5c5c5}@supports (color:var(--clock-face-time-disabled-color)){.clock-face__number>span.disabled{color:var(--clock-face-time-disabled-color)}}.clock-face__clock-hand{height:103px;width:2px;-webkit-transform-origin:0 100%;transform-origin:0 100%;position:absolute;top:calc(50% - 103px);z-index:1;background-color:#00bfff}@supports (background-color:var(--clock-hand-color)){.clock-face__clock-hand{background-color:var(--clock-hand-color)}}.clock-face__clock-hand:after{content:'';width:7px;height:7px;border-radius:50%;background-color:inherit;position:absolute;bottom:-3px;left:-3.5px}.clock-face__clock-hand_minute:before{content:'';width:7px;height:7px;background-color:#fff;border-radius:50%;position:absolute;top:-8px;left:calc(50% - 8px);box-sizing:content-box;border:4px solid #00bfff}@supports (border-color:var(--clock-hand-color)){.clock-face__clock-hand_minute:before{border-color:var(--clock-hand-color)}}@media (max-device-width:1023px) and (orientation:landscape){.clock-face{width:225px;height:225px;padding:5px}.clock-face__number--outer{height:calc(225px / 2 - 5px)}.clock-face__clock-hand_minute:before{top:0}}"] }] } ]; NgxMaterialTimepickerFaceComponent.propDecorators = { faceTime: [{ type: Input }], selectedTime: [{ type: Input }], unit: [{ type: Input }], format: [{ type: Input }], minutesGap: [{ type: Input }], timeChange: [{ type: Output }], timeSelected: [{ type: Output }], clockFace: [{ type: ViewChild, args: ['clockFace',] }], clockHand: [{ type: ViewChild, args: ['clockHand',] }], onMousedown: [{ type: HostListener, args: ['mousedown', ['$event'],] }], selectTime: [{ type: HostListener, args: ['click', ['$event'],] }, { type: HostListener, args: ['touchmove', ['$event.changedTouches[0]'],] }, { type: HostListener, args: ['touchend', ['$event.changedTouches[0]'],] }, { type: HostListener, args: ['mousemove', ['$event'],] }], onMouseup: [{ type: HostListener, args: ['mouseup', ['$event'],] }] }; if (false) { /** @type {?} */ NgxMaterialTimepickerFaceComponent.prototype.timeUnit; /** @type {?} */ NgxMaterialTimepickerFaceComponent.prototype.isClockFaceDisabled; /** @type {?} */ NgxMaterialTimepickerFaceComponent.prototype.innerClockFaceSize; /** @type {?} */ NgxMaterialTimepickerFaceComponent.prototype.faceTime; /** @type {?} */ NgxMaterialTimepickerFaceComponent.prototype.selectedTime; /** @type {?} */ NgxMaterialTimepickerFaceComponent.prototype.unit; /** @type {?} */ NgxMaterialTimepickerFaceComponent.prototype.format; /** @type {?} */ NgxMaterialTimepickerFaceComponent.prototype.minutesGap; /** @type {?} */ NgxMaterialTimepickerFaceComponent.prototype.timeChange; /** @type {?} */ NgxMaterialTimepickerFaceComponent.prototype.timeSelected; /** @type {?} */ NgxMaterialTimepickerFaceComponent.prototype.clockFace; /** @type {?} */ NgxMaterialTimepickerFaceComponent.prototype.clockHand; /** * @type {?} * @private */ NgxMaterialTimepickerFaceComponent.prototype.isStarted; /** * @type {?} * @private */ NgxMaterialTimepickerFaceComponent.prototype.touchStartHandler; /** * @type {?} * @private */ NgxMaterialTimepickerFaceComponent.prototype.touchEndHandler; } /** * @param {?} angle * @param {?} step * @return {?} */ function roundAngle(angle, step) { return Math.round(angle / step) * step; } /** * @param {?} x0 * @param {?} y0 * @param {?} x * @param {?} y * @param {?} currentAngle * @return {?} */ function countAngleByCords(x0, y0, x, y, currentAngle) { if (y > y0 && x >= x0) { // II quarter return 180 - currentAngle; } else if (y > y0 && x < x0) { // III quarter return 180 + currentAngle; } else if (y < y0 && x < x0) { // IV quarter return 360 - currentAngle; } else { // I quarter return currentAngle; } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmd4LW1hdGVyaWFsLXRpbWVwaWNrZXItZmFjZS5jb21wb25lbnQuanMiLCJzb3VyY2VSb290Ijoibmc6Ly9uZ3gtbWF0ZXJpYWwtdGltZXBpY2tlci1kZWNvbi8iLCJzb3VyY2VzIjpbInNyYy9hcHAvbWF0ZXJpYWwtdGltZXBpY2tlci9jb21wb25lbnRzL3RpbWVwaWNrZXItZmFjZS9uZ3gtbWF0ZXJpYWwtdGltZXBpY2tlci1mYWNlLmNvbXBvbmVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7O0FBQUEsT0FBTyxFQUVILHVCQUF1QixFQUN2QixTQUFTLEVBQ1QsVUFBVSxFQUNWLFlBQVksRUFDWixZQUFZLEVBQ1osS0FBSyxFQUdMLE1BQU0sRUFFTixTQUFTLEVBQ1osTUFBTSxlQUFlLENBQUM7QUFFdkIsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLDZCQUE2QixDQUFDOztNQUVqRCxpQkFBaUIsR0FBRztJQUN0QixLQUFLLEVBQUU7UUFDSCxNQUFNLEVBQUUsTUFBTTtRQUNkLEdBQUcsRUFBRSxrQkFBa0I7S0FDMUI7SUFDRCxLQUFLLEVBQUU7UUFDSCxNQUFNLEVBQUUsT0FBTztRQUNmLEdBQUcsRUFBRSxtQkFBbUI7S0FDM0I7Q0FDSjtBQVFELE1BQU0sT0FBTyxrQ0FBa0M7SUFOL0M7UUFRSSxhQUFRLEdBQUcsUUFBUSxDQUFDO1FBR3BCLHVCQUFrQixHQUFHLEVBQUUsQ0FBQztRQVFkLGVBQVUsR0FBRyxJQUFJLFlBQVksRUFBaUIsQ0FBQztRQUMvQyxpQkFBWSxHQUFHLElBQUksWUFBWSxFQUFVLENBQUM7SUF1SnhELENBQUM7Ozs7SUE5SUcsZUFBZTtRQUNYLElBQUksQ0FBQyxvQkFBb0IsRUFBRSxDQUFDO1FBQzVCLElBQUksQ0FBQyxjQUFjLEVBQUUsQ0FBQztJQUMxQixDQUFDOzs7OztJQUVELFdBQVcsQ0FBQyxPQUFzQjs7Y0FDeEIsZUFBZSxHQUFHLE9BQU8sQ0FBQyxVQUFVLENBQUM7O2NBQ3JDLG1CQUFtQixHQUFHLE9BQU8s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RUFBRSxDQUFTLEVBQUUsQ0FBUyxFQUFFLFlBQW9CO0lBQ3pGLElBQUksQ0FBQyxHQUFHLEVBQUUsSUFBSSxDQUFDLElBQUksRUFBRSxFQUFFLEVBQUMsYUFBYTtRQUNqQyxPQUFPLEdBQUcsR0FBRyxZQUFZLENBQUM7S0FDN0I7U0FBTSxJQUFJLENBQUMsR0FBRyxFQUFFLElBQUksQ0FBQyxHQUFHLEVBQUUsRUFBRSxFQUFDLGNBQWM7UUFDeEMsT0FBTyxHQUFHLEdBQUcsWUFBWSxDQUFDO0tBQzdCO1NBQU0sSUFBSSxDQUFDLEdBQUcsRUFBRSxJQUFJLENBQUMsR0FBRyxFQUFFLEVBQUUsRUFBQyxhQUFhO1FBQ3ZDLE9BQU8sR0FBRyxHQUFHLFlBQVksQ0FBQztLQUM3QjtTQUFNLEVBQUMsWUFBWTtRQUNoQixPQUFPLFlBQVksQ0FBQztLQUN2QjtBQUNMLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICAgIEFmdGVyVmlld0luaXQsXG4gICAgQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3ksXG4gICAgQ29tcG9uZW50LFxuICAgIEVsZW1lbnRSZWYsXG4gICAgRXZlbnRFbWl0dGVyLFxuICAgIEhvc3RMaXN0ZW5lcixcbiAgICBJbnB1dCxcbiAgICBPbkNoYW5nZXMsXG4gICAgT25EZXN0cm95LFxuICAgIE91dHB1dCxcbiAgICBTaW1wbGVDaGFuZ2VzLFxuICAgIFZpZXdDaGlsZFxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IENsb2NrRmFjZVRpbWUgfSBmcm9tICcuLi8uLi9tb2RlbHMvY2xvY2stZmFjZS10aW1lLmludGVyZmFjZSc7XG5pbXBvcnQgeyBUaW1lVW5pdCB9IGZyb20gJy4uLy4uL21vZGVscy90aW1lLXVuaXQuZW51bSc7XG5cbmNvbnN0IENMT0NLX0hBTkRfU1RZTEVTID0ge1xuICAgIHNtYWxsOiB7XG4gICAgICAgIGhlaWdodDogJzc1cHgnLFxuICAgICAgICB0b3A6ICdjYWxjKDUwJSAtIDc1cHgpJ1xuICAgIH0sXG4gICAgbGFyZ2U6IHtcbiAgICAgICAgaGVpZ2h0OiAnMTAzcHgnLFxuICAgICAgICB0b3A6ICdjYWxjKDUwJSAtIDEwM3B4KSdcbiAgICB9XG59O1xuXG5AQ29tcG9uZW50KHtcbiAgICBzZWxlY3RvcjogJ25neC1tYXRlcmlhbC10aW1lcGlja2VyLWZhY2UnLFxuICAgIHRlbXBsYXRlVXJsOiAnLi9uZ3gtbWF0ZXJpYWwtdGltZXBpY2tlci1mYWNlLmNvbXBvbmVudC5odG1sJyxcbiAgICBzdHlsZVVybHM6IFsnLi9uZ3gtbWF0ZXJpYWwtdGltZXBpY2tlci1mYWNlLmNvbXBvbmVudC5zY3NzJ10sXG4gICAgY2hhbmdlRGV0ZWN0aW9uOiBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneS5PblB1c2hcbn0pXG5leHBvcnQgY2xhc3MgTmd4TWF0ZXJpYWxUaW1lcGlja2VyRmFjZUNvbXBvbmVudCBpbXBsZW1lbnRzIEFmdGVyVmlld0luaXQsIE9uQ2hhbmdlcywgT25EZXN0cm95IHtcblxuICAgIHRpbWVVbml0ID0gVGltZVVuaXQ7XG5cbiAgICBpc0Nsb2NrRmFjZURpc2FibGVkOiBib29sZWFuO1xuICAgIGlubmVyQ2xvY2tGYWNlU2l6ZSA9IDg1O1xuXG4gICAgQElucHV0KCkgZmFjZVRpbWU6IENsb2NrRmFjZVRpbWVbXTtcbiAgICBASW5wdXQoKSBzZWxlY3RlZFRpbWU6IENsb2NrRmFjZVRpbWU7XG4gICAgQElucHV0KCkgdW5pdDogVGltZVVuaXQ7XG4gICAgQElucHV0KCkgZm9ybWF0OiBudW1iZXI7XG4gICAgQElucHV0KCkgbWludXRlc0dhcDogbnVtYmVyO1xuXG4gICAgQE91dHB1dCgpIHRpbWVDaGFuZ2UgPSBuZXcgRXZlbnRFbWl0dGVyPENsb2NrRmFjZVRpbWU+KCk7XG4gICAgQE91dHB1dCgpIHRpbWVTZWxlY3RlZCA9IG5ldyBFdmVudEVtaXR0ZXI8bnVtYmVyPigpO1xuXG4gICAgQFZpZXdDaGlsZCgnY2xvY2tGYWNlJykgY2xvY2tGYWNlOiBFbGVtZW50UmVmO1xuICAgIEBWaWV3Q2hpbGQoJ2Nsb2NrSGFuZCcpIGNsb2NrSGFuZDogRWxlbWVudFJlZjtcblxuICAgIHByaXZhdGUgaXNTdGFydGVkOiBib29sZWFuO1xuICAgIHByaXZhdGUgdG91Y2hTdGFydEhhbmRsZXI6ICgpID0+IGFueTtcbiAgICBwcml2YXRlIHRvdWNoRW5kSGFuZGxlcjogKCkgPT4gYW55O1xuXG4gICAgbmdBZnRlclZpZXdJbml0KCkge1xuICAgICAgICB0aGlzLnNldENsb2NrSGFuZFBvc2l0aW9uKCk7XG4gICAgICAgIHRoaXMuYWRkVG91Y2hFdmVudHMoKTtcbiAgICB9XG5cbiAgICBuZ09uQ2hhbmdlcyhjaGFuZ2VzOiBTaW1wbGVDaGFuZ2VzKSB7XG4gICAgICAgIGNvbnN0IGZhY2VUaW1lQ2hhbmdlcyA9IGNoYW5nZXNbJ2ZhY2VUaW1lJ107XG4gICAgICAgIGNvbnN0IHNlbGVjdGVkVGltZUNoYW5nZXMgPSBjaGFuZ2VzWydzZWxlY3RlZFRpbWUnXTtcblxuICAgICAgICBpZiAoKGZhY2VUaW1lQ2hhbmdlcyAmJiBmYWNlVGltZUNoYW5nZXMuY3VycmVudFZhbHVlKVxuICAgICAgICAgICAgJiYgKHNlbGVjdGVkVGltZUNoYW5nZXMgJiYgc2VsZWN0ZWRUaW1lQ2hhbmdlcy5jdXJyZW50VmFsdWUpKSB7XG4gICAgICAgICAgICAvKiBTZXQgdGltZSBhY2NvcmRpbmcgdG8gcGFzc2VkIGFuIGlucHV0IHZhbHVlICovXG4gICAgICAgICAgICB0aGlzLnNlbGVjdGVkVGltZSA9IHRoaXMuZmFjZVRpbWUuZmluZCh0aW1lID0+IHRpbWUudGltZSA9PT0gdGhpcy5zZWxlY3RlZFRpbWUudGltZSk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHNlbGVjdGVkVGltZUNoYW5nZXMgJiYgc2VsZWN0ZWRUaW1lQ2hhbmdlcy5jdXJyZW50VmFsdWUpIHtcbiAgICAgICAgICAgIHRoaXMuc2V0Q2xvY2tIYW5kUG9zaXRpb24oKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoZmFjZVRpbWVDaGFuZ2VzICYmIGZhY2VUaW1lQ2hhbmdlcy5jdXJyZW50VmFsdWUpIHtcbiAgICAgICAgICAgIC8vIFRvIGF2b2lkIGFuIGVycm9yIEV4cHJlc3Npb25DaGFuZ2VkQWZ0ZXJJdEhhc0JlZW5DaGVja2VkRXJyb3JcbiAgICAgICAgICAgIHNldFRpbWVvdXQoKCkgPT4gdGhpcy5zZWxlY3RBdmFpbGFibGVUaW1lKCkpO1xuICAgICAgICB9XG4gICAgfVxuXG5cbiAgICB0cmFja0J5VGltZShfLCB0aW1lOiBDbG9ja0ZhY2VUaW1lKTogc3RyaW5nIHwgbnVtYmVyIHtcbiAgICAgICAgcmV0dXJuIHRpbWUudGltZTtcbiAgICB9XG5cbiAgICBASG9zdExpc3RlbmVyKCdtb3VzZWRvd24nLCBbJyRldmVudCddKVxuICAgIG9uTW91c2Vkb3duKGU6IE1vdXNlRXZlbnQgfCBUb3VjaEV2ZW50KSB7XG4gICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgdGhpcy5pc1N0YXJ0ZWQgPSB0cnVlO1xuICAgIH1cblxuICAgIEBIb3N0TGlzdGVuZXIoJ2NsaWNrJywgWyckZXZlbnQnXSlcbiAgICBASG9zdExpc3RlbmVyKCd0b3VjaG1vdmUnLCBbJyRldmVudC5jaGFuZ2VkVG91Y2hlc1swXSddKVxuICAgIEBIb3N0TGlzdGVuZXIoJ3RvdWNoZW5kJywgWyckZXZlbnQuY2hhbmdlZFRvdWNoZXNbMF0nXSlcbiAgICBASG9zdExpc3RlbmVyKCdtb3VzZW1vdmUnLCBbJyRldmVudCddKVxuICAgIHNlbGVjdFRpbWUoZTogTW91c2VFdmVudCB8IFRvdWNoKTogdm9pZCB7XG5cbiAgICAgICAgaWYgKCF0aGlzLmlzU3RhcnRlZCAmJiAoZSBpbnN0YW5jZW9mIE1vdXNlRXZlbnQgJiYgZS50eXBlICE9PSAnY2xpY2snKSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IGNsb2NrRmFjZUNvcmRzID0gdGhpcy5jbG9ja0ZhY2UubmF0aXZlRWxlbWVudC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcblxuICAgICAgICAvKiBHZXQgeDAgYW5kIHkwIG9mIHRoZSBjaXJjbGUgKi9cbiAgICAgICAgY29uc3QgY2VudGVyWCA9IGNsb2NrRmFjZUNvcmRzLmxlZnQgKyBjbG9ja0ZhY2VDb3Jkcy53aWR0aCAvIDI7XG4gICAgICAgIGNvbnN0IGNlbnRlclkgPSBjbG9ja0ZhY2VDb3Jkcy50b3AgKyBjbG9ja0ZhY2VDb3Jkcy5oZWlnaHQgLyAyO1xuICAgICAgICAvKiBDb3VudGluZyB0aGUgYXJjdGFuZ2VudCBhbmQgY29udmVydCBpdCB0byBmcm9tIHJhZGlhbiB0byBkZWcgKi9cbiAgICAgICAgY29uc3QgYXJjdGFuZ2VudCA9IE1hdGguYXRhbihNYXRoLmFicyhlLmNsaWVudFggLSBjZW50ZXJYKSAvIE1hdGguYWJzKGUuY2xpZW50WSAtIGNlbnRlclkpKSAqIDE4MCAvIE1hdGguUEk7XG4gICAgICAgIC8qIEdldCBhbmdsZSBhY2NvcmRpbmcgdG8gcXVhZHJhbnQgKi9cbiAgICAgICAgY29uc3QgY2lyY2xlQW5nbGUgPSBjb3VudEFuZ2xlQnlDb3JkcyhjZW50ZXJYLCBjZW50ZXJZLCBlLmNsaWVudFgsIGUuY2xpZW50WSwgYXJjdGFuZ2VudCk7XG4gICAgICAgIC8qIENoZWNrIGlmIHNlbGVjdGVkIHRpbWUgZnJvbSB0aGUgaW5uZXIgY2xvY2sgZmFjZSAoMjQgaG91cnMgZm9ybWF0IG9ubHkpICovXG4gICAgICAgIGNvbnN0IGlzSW5uZXJDbG9ja0Nob3NlbiA9IHRoaXMuZm9ybWF0ICYmIHRoaXMuaXNJbm5lckNsb2NrRmFjZShjZW50ZXJYLCBjZW50ZXJZLCBlLmNsaWVudFgsIGUuY2xpZW50WSk7XG4gICAgICAgIC8qIFJvdW5kIGFuZ2xlIGFjY29yZGluZyB0byBhbmdsZSBzdGVwICovXG4gICAgICAgIGNvbnN0IGFuZ2xlU3RlcCA9IHRoaXMudW5pdCA9PT0gVGltZVVuaXQuTUlOVVRFID8gKDYgKiAodGhpcy5taW51dGVzR2FwIHx8IDEpKSA6IDMwO1xuICAgICAgICBjb25zdCByb3VuZGVkQW5nbGUgPSBpc0lubmVyQ2xvY2tDaG9zZW5cbiAgICAgICAgICAgID8gcm91bmRBbmdsZShjaXJjbGVBbmdsZSwgYW5nbGVTdGVwKSArIDM2MFxuICAgICAgICAgICAgOiByb3VuZEFuZ2xlKGNpcmNsZUFuZ2xlLCBhbmdsZVN0ZXApO1xuICAgICAgICBjb25zdCBhbmdsZSA9IHJvdW5kZWRBbmdsZSA9PT0gMCA/IDM2MCA6IHJvdW5kZWRBbmdsZTtcblxuICAgICAgICBjb25zdCBzZWxlY3RlZFRpbWUgPSB0aGlzLmZhY2VUaW1lLmZpbmQodmFsID0+IHZhbC5hbmdsZSA9PT0gYW5nbGUpO1xuXG4gICAgICAgIGlmIChzZWxlY3RlZFRpbWUgJiYgIXNlbGVjdGVkVGltZS5kaXNhYmxlZCkge1xuICAgICAgICAgICAgdGhpcy50aW1lQ2hhbmdlLm5leHQoc2VsZWN0ZWRUaW1lKTtcblxuICAgICAgICAgICAgLyogVG8gbGV0IGtub3cgd2hldGhlciB1c2VyIGVuZGVkIGludGVyYWN0aW9uIHdpdGggY2xvY2sgZmFjZSAqL1xuICAgICAgICAgICAgaWYgKCF0aGlzLmlzU3RhcnRlZCkge1xuICAgICAgICAgICAgICAgIHRoaXMudGltZVNlbGVjdGVkLm5leHQoc2VsZWN0ZWRUaW1lLnRpbWUpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICB9XG5cbiAgICBASG9zdExpc3RlbmVyKCdtb3VzZXVwJywgWyckZXZlbnQnXSlcbiAgICBvbk1vdXNldXAoZTogTW91c2VFdmVudCB8IFRvdWNoRXZlbnQpIHtcbiAgICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICB0aGlzLmlzU3RhcnRlZCA9IGZhbHNlO1xuICAgIH1cblxuICAgIGlzSG91clNlbGVjdGVkKGhvdXI6IG51bWJlcik6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gKGhvdXIgPT09IHRoaXMuc2VsZWN0ZWRUaW1lLnRpbWUpICYmICF0aGlzLmlzQ2xvY2tGYWNlRGlzYWJsZWQ7XG4gICAgfVxuXG4gICAgaXNNaW51dGVTZWxlY3RlZChtaW51dGU6IG51bWJlcik6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gKCh0aGlzLnNlbGVjdGVkVGltZS50aW1lID09PSBtaW51dGUpICYmIChtaW51dGUgJSAodGhpcy5taW51dGVzR2FwIHx8IDUpID09PSAwKSkgJiYgIXRoaXMuaXNDbG9ja0ZhY2VEaXNhYmxlZDtcbiAgICB9XG5cbiAgICBuZ09uRGVzdHJveSgpIHtcbiAgICAgICAgdGhpcy5yZW1vdmVUb3VjaEV2ZW50cygpO1xuICAgIH1cblxuICAgIHByaXZhdGUgYWRkVG91Y2hFdmVudHMoKTogdm9pZCB7XG4gICAgICAgIHRoaXMudG91Y2hTdGFydEhhbmRsZXIgPSB0aGlzLm9uTW91c2Vkb3duLmJpbmQodGhpcyk7XG4gICAgICAgIHRoaXMudG91Y2hFbmRIYW5kbGVyID0gdGhpcy5vbk1vdXNldXAuYmluZCh0aGlzKTtcblxuICAgICAgICB0aGlzLmNsb2NrRmFjZS5uYXRpdmVFbGVtZW50LmFkZEV2ZW50TGlzdGVuZXIoJ3RvdWNoc3RhcnQnLCB0aGlzLnRvdWNoU3RhcnRIYW5kbGVyKTtcbiAgICAgICAgdGhpcy5jbG9ja0ZhY2UubmF0aXZlRWxlbWVudC5hZGRFdmVudExpc3RlbmVyKCd0b3VjaGVuZCcsIHRoaXMudG91Y2hFbmRIYW5kbGVyKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIHJlbW92ZVRvdWNoRXZlbnRzKCk6IHZvaWQge1xuICAgICAgICB0aGlzLmNsb2NrRmFjZS5uYXRpdmVFbGVtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoJ3RvdWNoc3RhcnQnLCB0aGlzLnRvdWNoU3RhcnRIYW5kbGVyKTtcbiAgICAgICAgdGhpcy5jbG9ja0ZhY2UubmF0aXZlRWxlbWVudC5yZW1vdmVFdmVudExpc3RlbmVyKCd0b3VjaGVuZCcsIHRoaXMudG91Y2hFbmRIYW5kbGVyKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIHNldENsb2NrSGFuZFBvc2l0aW9uKCk6IHZvaWQge1xuICAgICAgICBpZiAodGhpcy5mb3JtYXQgPT09IDI0KSB7XG4gICAgICAgICAgICBpZiAodGhpcy5zZWxlY3RlZFRpbWUudGltZSA+IDEyIHx8IHRoaXMuc2VsZWN0ZWRUaW1lLnRpbWUgPT09IDApIHtcbiAgICAgICAgICAgICAgICB0aGlzLmRlY3JlYXNlQ2xvY2tIYW5kKCk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHRoaXMuaW5jcmVhc2VDbG9ja0hhbmQoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuY2xvY2tIYW5kLm5hdGl2ZUVsZW1lbnQuc3R5bGUudHJhbnNmb3JtID0gYHJvdGF0ZSgke3RoaXMuc2VsZWN0ZWRUaW1lLmFuZ2xlfWRlZylgO1xuICAgIH1cblxuICAgIHByaXZhdGUgc2VsZWN0QXZhaWxhYmxlVGltZSgpOiB2b2lkIHtcbiAgICAgICAgY29uc3QgY3VycmVudFRpbWUgPSB0aGlzLmZhY2VUaW1lLmZpbmQodGltZSA9PiB0aGlzLnNlbGVjdGVkVGltZS50aW1lID09PSB0aW1lLnRpbWUpO1xuICAgICAgICB0aGlzLmlzQ2xvY2tGYWNlRGlzYWJsZWQgPSB0aGlzLmZhY2VUaW1lLmV2ZXJ5KHRpbWUgPT4gdGltZS5kaXNhYmxlZCk7XG5cbiAgICAgICAgaWYgKChjdXJyZW50VGltZSAmJiBjdXJyZW50VGltZS5kaXNhYmxlZCkgJiYgIXRoaXMuaXNDbG9ja0ZhY2VEaXNhYmxlZCkge1xuICAgICAgICAgICAgY29uc3QgYXZhaWxhYmxlVGltZSA9IHRoaXMuZmFjZVRpbWUuZmluZCh0aW1lID0+ICF0aW1lLmRpc2FibGVkKTtcblxuICAgICAgICAgICAgdGhpcy50aW1lQ2hhbmdlLm5leHQoYXZhaWxhYmxlVGltZSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwcml2YXRlIGlzSW5uZXJDbG9ja0ZhY2UoeDA6IG51bWJlciwgeTA6IG51bWJlciwgeDogbnVtYmVyLCB5OiBudW1iZXIpOiBib29sZWFuIHtcbiAgICAgICAgLyogRGV0ZWN0IHdoZXRoZXIgdGltZSBmcm9tIHRoZSBpbm5lciBjbG9jayBmYWNlIG9yIG5vdCAoMjQgZm9ybWF0IG9ubHkpICovXG4gICAgICAgIHJldHVybiBNYXRoLnNxcnQoTWF0aC5wb3coeCAtIHgwLCAyKSArIE1hdGgucG93KHkgLSB5MCwgMikpIDwgdGhpcy5pbm5lckNsb2NrRmFjZVNpemU7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBkZWNyZWFzZUNsb2NrSGFuZCgpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5jbG9ja0hhbmQubmF0aXZlRWxlbWVudC5zdHlsZS5oZWlnaHQgPSBDTE9DS19IQU5EX1NUWUxFUy5zbWFsbC5oZWlnaHQ7XG4gICAgICAgIHRoaXMuY2xvY2tIYW5kLm5hdGl2ZUVsZW1lbnQuc3R5bGUudG9wID0gQ0xPQ0tfSEFORF9TVFlMRVMuc21hbGwudG9wO1xuICAgIH1cblxuICAgIHByaXZhdGUgaW5jcmVhc2VDbG9ja0hhbmQoKTogdm9pZCB7XG4gICAgICAgIHRoaXMuY2xvY2tIYW5kLm5hdGl2ZUVsZW1lbnQuc3R5bGUuaGVpZ2h0ID0gQ0xPQ0tfSEFORF9TVFlMRVMubGFyZ2UuaGVpZ2h0O1xuICAgICAgICB0aGlzLmNsb2NrSGFuZC5uYXRpdmVFbGVtZW50LnN0eWxlLnRvcCA9IENMT0NLX0hBTkRfU1RZTEVTLmxhcmdlLnRvcDtcbiAgICB9XG59XG5cbmZ1bmN0aW9uIHJvdW5kQW5nbGUoYW5nbGU6IG51bWJlciwgc3RlcDogbnVtYmVyKTogbnVtYmVyIHtcbiAgICByZXR1cm4gTWF0aC5yb3VuZChhbmdsZSAvIHN0ZXApICogc3RlcDtcbn1cblxuZnVuY3Rpb24gY291bnRBbmdsZUJ5Q29yZHMoeDA6IG51bWJlciwgeTA6IG51bWJlciwgeDogbnVtYmVyLCB5OiBudW1iZXIsIGN1cnJlbnRBbmdsZTogbnVtYmVyKTogbnVtYmVyIHtcbiAgICBpZiAoeSA+IHkwICYmIHggPj0geDApIHsvLyBJSSBxdWFydGVyXG4gICAgICAgIHJldHVybiAxODAgLSBjdXJyZW50QW5nbGU7XG4gICAgfSBlbHNlIGlmICh5ID4geTAgJiYgeCA8IHgwKSB7Ly8gSUlJIHF1YXJ0ZXJcbiAgICAgICAgcmV0dXJuIDE4MCArIGN1cnJlbnRBbmdsZTtcbiAgICB9IGVsc2UgaWYgKHkgPCB5MCAmJiB4IDwgeDApIHsvLyBJViBxdWFydGVyXG4gICAgICAgIHJldHVybiAzNjAgLSBjdXJyZW50QW5nbGU7XG4gICAgfSBlbHNlIHsvLyBJIHF1YXJ0ZXJcbiAgICAgICAgcmV0dXJuIGN1cnJlbnRBbmdsZTtcbiAgICB9XG59XG4iXX0=