UNPKG

ngx-material-timepicker

Version:
215 lines 33.9 kB
import * as tslib_1 from "tslib"; import { ChangeDetectionStrategy, Component, ElementRef, EventEmitter, HostListener, Input, Output, ViewChild } from '@angular/core'; import { TimeUnit } from '../../models/time-unit.enum'; const CLOCK_HAND_STYLES = { small: { height: '75px', top: 'calc(50% - 75px)' }, large: { height: '103px', top: 'calc(50% - 103px)' } }; let NgxMaterialTimepickerFaceComponent = class NgxMaterialTimepickerFaceComponent { constructor() { this.timeUnit = TimeUnit; this.innerClockFaceSize = 85; this.timeChange = new EventEmitter(); this.timeSelected = new EventEmitter(); } ngAfterViewInit() { this.setClockHandPosition(); this.addTouchEvents(); } ngOnChanges(changes) { const faceTimeChanges = changes['faceTime']; 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()); } } trackByTime(_, time) { return time.time; } onMousedown(e) { e.preventDefault(); this.isStarted = true; } selectTime(e) { if (!this.isStarted && (e instanceof MouseEvent && e.type !== 'click')) { return; } const clockFaceCords = this.clockFace.nativeElement.getBoundingClientRect(); /* Get x0 and y0 of the circle */ const centerX = clockFaceCords.left + clockFaceCords.width / 2; const centerY = clockFaceCords.top + clockFaceCords.height / 2; /* Counting the arctangent and convert it to from radian to deg */ const arctangent = Math.atan(Math.abs(e.clientX - centerX) / Math.abs(e.clientY - centerY)) * 180 / Math.PI; /* Get angle according to quadrant */ const circleAngle = countAngleByCords(centerX, centerY, e.clientX, e.clientY, arctangent); /* Check if selected time from the inner clock face (24 hours format only) */ const isInnerClockChosen = this.format && this.isInnerClockFace(centerX, centerY, e.clientX, e.clientY); /* Round angle according to angle step */ const angleStep = this.unit === TimeUnit.MINUTE ? (6 * (this.minutesGap || 1)) : 30; const roundedAngle = isInnerClockChosen ? roundAngle(circleAngle, angleStep) + 360 : roundAngle(circleAngle, angleStep); const angle = roundedAngle === 0 ? 360 : roundedAngle; 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); } } } onMouseup(e) { e.preventDefault(); this.isStarted = false; } isHourSelected(hour) { return (hour === this.selectedTime.time) && !this.isClockFaceDisabled; } isMinuteSelected(minute) { return ((this.selectedTime.time === minute) && (minute % (this.minutesGap || 5) === 0)) && !this.isClockFaceDisabled; } ngOnDestroy() { this.removeTouchEvents(); } 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); } removeTouchEvents() { this.clockFace.nativeElement.removeEventListener('touchstart', this.touchStartHandler); this.clockFace.nativeElement.removeEventListener('touchend', this.touchEndHandler); } 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)`; } selectAvailableTime() { 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) { const availableTime = this.faceTime.find(time => !time.disabled); this.timeChange.next(availableTime); } } 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; } decreaseClockHand() { this.clockHand.nativeElement.style.height = CLOCK_HAND_STYLES.small.height; this.clockHand.nativeElement.style.top = CLOCK_HAND_STYLES.small.top; } increaseClockHand() { this.clockHand.nativeElement.style.height = CLOCK_HAND_STYLES.large.height; this.clockHand.nativeElement.style.top = CLOCK_HAND_STYLES.large.top; } }; tslib_1.__decorate([ Input(), tslib_1.__metadata("design:type", Array) ], NgxMaterialTimepickerFaceComponent.prototype, "faceTime", void 0); tslib_1.__decorate([ Input(), tslib_1.__metadata("design:type", Object) ], NgxMaterialTimepickerFaceComponent.prototype, "selectedTime", void 0); tslib_1.__decorate([ Input(), tslib_1.__metadata("design:type", Number) ], NgxMaterialTimepickerFaceComponent.prototype, "unit", void 0); tslib_1.__decorate([ Input(), tslib_1.__metadata("design:type", Number) ], NgxMaterialTimepickerFaceComponent.prototype, "format", void 0); tslib_1.__decorate([ Input(), tslib_1.__metadata("design:type", Number) ], NgxMaterialTimepickerFaceComponent.prototype, "minutesGap", void 0); tslib_1.__decorate([ Output(), tslib_1.__metadata("design:type", Object) ], NgxMaterialTimepickerFaceComponent.prototype, "timeChange", void 0); tslib_1.__decorate([ Output(), tslib_1.__metadata("design:type", Object) ], NgxMaterialTimepickerFaceComponent.prototype, "timeSelected", void 0); tslib_1.__decorate([ ViewChild('clockFace', { static: true }), tslib_1.__metadata("design:type", ElementRef) ], NgxMaterialTimepickerFaceComponent.prototype, "clockFace", void 0); tslib_1.__decorate([ ViewChild('clockHand', { static: true }), tslib_1.__metadata("design:type", ElementRef) ], NgxMaterialTimepickerFaceComponent.prototype, "clockHand", void 0); tslib_1.__decorate([ HostListener('mousedown', ['$event']), tslib_1.__metadata("design:type", Function), tslib_1.__metadata("design:paramtypes", [Object]), tslib_1.__metadata("design:returntype", void 0) ], NgxMaterialTimepickerFaceComponent.prototype, "onMousedown", null); tslib_1.__decorate([ HostListener('click', ['$event']), HostListener('touchmove', ['$event.changedTouches[0]']), HostListener('touchend', ['$event.changedTouches[0]']), HostListener('mousemove', ['$event']), tslib_1.__metadata("design:type", Function), tslib_1.__metadata("design:paramtypes", [Object]), tslib_1.__metadata("design:returntype", void 0) ], NgxMaterialTimepickerFaceComponent.prototype, "selectTime", null); tslib_1.__decorate([ HostListener('mouseup', ['$event']), tslib_1.__metadata("design:type", Function), tslib_1.__metadata("design:paramtypes", [Object]), tslib_1.__metadata("design:returntype", void 0) ], NgxMaterialTimepickerFaceComponent.prototype, "onMouseup", null); NgxMaterialTimepickerFaceComponent = tslib_1.__decorate([ Component({ 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); export { NgxMaterialTimepickerFaceComponent }; function roundAngle(angle, step) { return Math.round(angle / step) * step; } 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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmd4LW1hdGVyaWFsLXRpbWVwaWNrZXItZmFjZS5jb21wb25lbnQuanMiLCJzb3VyY2VSb290Ijoibmc6Ly9uZ3gtbWF0ZXJpYWwtdGltZXBpY2tlci8iLCJzb3VyY2VzIjpbInNyYy9hcHAvbWF0ZXJpYWwtdGltZXBpY2tlci9jb21wb25lbnRzL3RpbWVwaWNrZXItZmFjZS9uZ3gtbWF0ZXJpYWwtdGltZXBpY2tlci1mYWNlLmNvbXBvbmVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUEsT0FBTyxFQUVILHVCQUF1QixFQUN2QixTQUFTLEVBQ1QsVUFBVSxFQUNWLFlBQVksRUFDWixZQUFZLEVBQ1osS0FBSyxFQUdMLE1BQU0sRUFFTixTQUFTLEVBQ1osTUFBTSxlQUFlLENBQUM7QUFFdkIsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLDZCQUE2QixDQUFDO0FBRXZELE1BQU0saUJBQWlCLEdBQUc7SUFDdEIsS0FBSyxFQUFFO1FBQ0gsTUFBTSxFQUFFLE1BQU07UUFDZCxHQUFHLEVBQUUsa0JBQWtCO0tBQzFCO0lBQ0QsS0FBSyxFQUFFO1FBQ0gsTUFBTSxFQUFFLE9BQU87UUFDZixHQUFHLEVBQUUsbUJBQW1CO0tBQzNCO0NBQ0osQ0FBQztBQVFGLElBQWEsa0NBQWtDLEdBQS9DLE1BQWEsa0NBQWtDO0lBTi9DO1FBUUksYUFBUSxHQUFHLFFBQVEsQ0FBQztRQUdwQix1QkFBa0IsR0FBRyxFQUFFLENBQUM7UUFRZCxlQUFVLEdBQUcsSUFBSSxZQUFZLEVBQWlCLENBQUM7UUFDL0MsaUJBQVksR0FBRyxJQUFJLFlBQVksRUFBVSxDQUFDO0lBdUp4RCxDQUFDO0lBOUlHLGVBQWU7UUFDWCxJQUFJLENBQUMsb0JBQW9CLEVBQUUsQ0FBQztRQUM1QixJQUFJLENBQUMsY0FBYyxFQUFFLENBQUM7SUFDMUIsQ0FBQztJQUVELFdBQVcsQ0FBQyxPQUFzQjtRQUM5QixNQUFNLGVBQWUsR0FBRyxPQUFPLENBQUMsVUFBVSxDQUFDLENBQUM7UUFDNUMsTUFB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USxFQUFFLDhCQUE4QjtRQUN4Qyxvb0VBQTREO1FBRTVELGVBQWUsRUFBRSx1QkFBdUIsQ0FBQyxNQUFNOztLQUNsRCxDQUFDO0dBQ1csa0NBQWtDLENBcUs5QztTQXJLWSxrQ0FBa0M7QUF1Sy9DLFNBQVMsVUFBVSxDQUFDLEtBQWEsRUFBRSxJQUFZO0lBQzNDLE9BQU8sSUFBSSxDQUFDLEtBQUssQ0FBQyxLQUFLLEdBQUcsSUFBSSxDQUFDLEdBQUcsSUFBSSxDQUFDO0FBQzNDLENBQUM7QUFFRCxTQUFTLGlCQUFpQixDQUFDLEVBQVUsRUFBRSxFQUFVLEVBQUUsQ0FBUyxFQUFFLENBQVMsRUFBRSxZQUFvQjtJQUN6RixJQUFJLENBQUMsR0FBRyxFQUFFLElBQUksQ0FBQyxJQUFJLEVBQUUsRUFBRSxFQUFDLGFBQWE7UUFDakMsT0FBTyxHQUFHLEdBQUcsWUFBWSxDQUFDO0tBQzdCO1NBQU0sSUFBSSxDQUFDLEdBQUcsRUFBRSxJQUFJLENBQUMsR0FBRyxFQUFFLEVBQUUsRUFBQyxjQUFjO1FBQ3hDLE9BQU8sR0FBRyxHQUFHLFlBQVksQ0FBQztLQUM3QjtTQUFNLElBQUksQ0FBQyxHQUFHLEVBQUUsSUFBSSxDQUFDLEdBQUcsRUFBRSxFQUFFLEVBQUMsYUFBYTtRQUN2QyxPQUFPLEdBQUcsR0FBRyxZQUFZLENBQUM7S0FDN0I7U0FBTSxFQUFDLFlBQVk7UUFDaEIsT0FBTyxZQUFZLENBQUM7S0FDdkI7QUFDTCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgICBBZnRlclZpZXdJbml0LFxuICAgIENoYW5nZURldGVjdGlvblN0cmF0ZWd5LFxuICAgIENvbXBvbmVudCxcbiAgICBFbGVtZW50UmVmLFxuICAgIEV2ZW50RW1pdHRlcixcbiAgICBIb3N0TGlzdGVuZXIsXG4gICAgSW5wdXQsXG4gICAgT25DaGFuZ2VzLFxuICAgIE9uRGVzdHJveSxcbiAgICBPdXRwdXQsXG4gICAgU2ltcGxlQ2hhbmdlcyxcbiAgICBWaWV3Q2hpbGRcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBDbG9ja0ZhY2VUaW1lIH0gZnJvbSAnLi4vLi4vbW9kZWxzL2Nsb2NrLWZhY2UtdGltZS5pbnRlcmZhY2UnO1xuaW1wb3J0IHsgVGltZVVuaXQgfSBmcm9tICcuLi8uLi9tb2RlbHMvdGltZS11bml0LmVudW0nO1xuXG5jb25zdCBDTE9DS19IQU5EX1NUWUxFUyA9IHtcbiAgICBzbWFsbDoge1xuICAgICAgICBoZWlnaHQ6ICc3NXB4JyxcbiAgICAgICAgdG9wOiAnY2FsYyg1MCUgLSA3NXB4KSdcbiAgICB9LFxuICAgIGxhcmdlOiB7XG4gICAgICAgIGhlaWdodDogJzEwM3B4JyxcbiAgICAgICAgdG9wOiAnY2FsYyg1MCUgLSAxMDNweCknXG4gICAgfVxufTtcblxuQENvbXBvbmVudCh7XG4gICAgc2VsZWN0b3I6ICduZ3gtbWF0ZXJpYWwtdGltZXBpY2tlci1mYWNlJyxcbiAgICB0ZW1wbGF0ZVVybDogJy4vbmd4LW1hdGVyaWFsLXRpbWVwaWNrZXItZmFjZS5jb21wb25lbnQuaHRtbCcsXG4gICAgc3R5bGVVcmxzOiBbJy4vbmd4LW1hdGVyaWFsLXRpbWVwaWNrZXItZmFjZS5jb21wb25lbnQuc2NzcyddLFxuICAgIGNoYW5nZURldGVjdGlvbjogQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3kuT25QdXNoXG59KVxuZXhwb3J0IGNsYXNzIE5neE1hdGVyaWFsVGltZXBpY2tlckZhY2VDb21wb25lbnQgaW1wbGVtZW50cyBBZnRlclZpZXdJbml0LCBPbkNoYW5nZXMsIE9uRGVzdHJveSB7XG5cbiAgICB0aW1lVW5pdCA9IFRpbWVVbml0O1xuXG4gICAgaXNDbG9ja0ZhY2VEaXNhYmxlZDogYm9vbGVhbjtcbiAgICBpbm5lckNsb2NrRmFjZVNpemUgPSA4NTtcblxuICAgIEBJbnB1dCgpIGZhY2VUaW1lOiBDbG9ja0ZhY2VUaW1lW107XG4gICAgQElucHV0KCkgc2VsZWN0ZWRUaW1lOiBDbG9ja0ZhY2VUaW1lO1xuICAgIEBJbnB1dCgpIHVuaXQ6IFRpbWVVbml0O1xuICAgIEBJbnB1dCgpIGZvcm1hdDogbnVtYmVyO1xuICAgIEBJbnB1dCgpIG1pbnV0ZXNHYXA6IG51bWJlcjtcblxuICAgIEBPdXRwdXQoKSB0aW1lQ2hhbmdlID0gbmV3IEV2ZW50RW1pdHRlcjxDbG9ja0ZhY2VUaW1lPigpO1xuICAgIEBPdXRwdXQoKSB0aW1lU2VsZWN0ZWQgPSBuZXcgRXZlbnRFbWl0dGVyPG51bWJlcj4oKTtcblxuICAgIEBWaWV3Q2hpbGQoJ2Nsb2NrRmFjZScsIHtzdGF0aWM6IHRydWV9KSBjbG9ja0ZhY2U6IEVsZW1lbnRSZWY7XG4gICAgQFZpZXdDaGlsZCgnY2xvY2tIYW5kJywge3N0YXRpYzogdHJ1ZX0pIGNsb2NrSGFuZDogRWxlbWVudFJlZjtcblxuICAgIHByaXZhdGUgaXNTdGFydGVkOiBib29sZWFuO1xuICAgIHByaXZhdGUgdG91Y2hTdGFydEhhbmRsZXI6ICgpID0+IGFueTtcbiAgICBwcml2YXRlIHRvdWNoRW5kSGFuZGxlcjogKCkgPT4gYW55O1xuXG4gICAgbmdBZnRlclZpZXdJbml0KCkge1xuICAgICAgICB0aGlzLnNldENsb2NrSGFuZFBvc2l0aW9uKCk7XG4gICAgICAgIHRoaXMuYWRkVG91Y2hFdmVudHMoKTtcbiAgICB9XG5cbiAgICBuZ09uQ2hhbmdlcyhjaGFuZ2VzOiBTaW1wbGVDaGFuZ2VzKSB7XG4gICAgICAgIGNvbnN0IGZhY2VUaW1lQ2hhbmdlcyA9IGNoYW5nZXNbJ2ZhY2VUaW1lJ107XG4gICAgICAgIGNvbnN0IHNlbGVjdGVkVGltZUNoYW5nZXMgPSBjaGFuZ2VzWydzZWxlY3RlZFRpbWUnXTtcblxuICAgICAgICBpZiAoKGZhY2VUaW1lQ2hhbmdlcyAmJiBmYWNlVGltZUNoYW5nZXMuY3VycmVudFZhbHVlKVxuICAgICAgICAgICAgJiYgKHNlbGVjdGVkVGltZUNoYW5nZXMgJiYgc2VsZWN0ZWRUaW1lQ2hhbmdlcy5jdXJyZW50VmFsdWUpKSB7XG4gICAgICAgICAgICAvKiBTZXQgdGltZSBhY2NvcmRpbmcgdG8gcGFzc2VkIGFuIGlucHV0IHZhbHVlICovXG4gICAgICAgICAgICB0aGlzLnNlbGVjdGVkVGltZSA9IHRoaXMuZmFjZVRpbWUuZmluZCh0aW1lID0+IHRpbWUudGltZSA9PT0gdGhpcy5zZWxlY3RlZFRpbWUudGltZSk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHNlbGVjdGVkVGltZUNoYW5nZXMgJiYgc2VsZWN0ZWRUaW1lQ2hhbmdlcy5jdXJyZW50VmFsdWUpIHtcbiAgICAgICAgICAgIHRoaXMuc2V0Q2xvY2tIYW5kUG9zaXRpb24oKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoZmFjZVRpbWVDaGFuZ2VzICYmIGZhY2VUaW1lQ2hhbmdlcy5jdXJyZW50VmFsdWUpIHtcbiAgICAgICAgICAgIC8vIFRvIGF2b2lkIGFuIGVycm9yIEV4cHJlc3Npb25DaGFuZ2VkQWZ0ZXJJdEhhc0JlZW5DaGVja2VkRXJyb3JcbiAgICAgICAgICAgIHNldFRpbWVvdXQoKCkgPT4gdGhpcy5zZWxlY3RBdmFpbGFibGVUaW1lKCkpO1xuICAgICAgICB9XG4gICAgfVxuXG5cbiAgICB0cmFja0J5VGltZShfLCB0aW1lOiBDbG9ja0ZhY2VUaW1lKTogc3RyaW5nIHwgbnVtYmVyIHtcbiAgICAgICAgcmV0dXJuIHRpbWUudGltZTtcbiAgICB9XG5cbiAgICBASG9zdExpc3RlbmVyKCdtb3VzZWRvd24nLCBbJyRldmVudCddKVxuICAgIG9uTW91c2Vkb3duKGU6IE1vdXNlRXZlbnQgfCBUb3VjaEV2ZW50KSB7XG4gICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgdGhpcy5pc1N0YXJ0ZWQgPSB0cnVlO1xuICAgIH1cblxuICAgIEBIb3N0TGlzdGVuZXIoJ2NsaWNrJywgWyckZXZlbnQnXSlcbiAgICBASG9zdExpc3RlbmVyKCd0b3VjaG1vdmUnLCBbJyRldmVudC5jaGFuZ2VkVG91Y2hlc1swXSddKVxuICAgIEBIb3N0TGlzdGVuZXIoJ3RvdWNoZW5kJywgWyckZXZlbnQuY2hhbmdlZFRvdWNoZXNbMF0nXSlcbiAgICBASG9zdExpc3RlbmVyKCdtb3VzZW1vdmUnLCBbJyRldmVudCddKVxuICAgIHNlbGVjdFRpbWUoZTogTW91c2VFdmVudCB8IFRvdWNoKTogdm9pZCB7XG5cbiAgICAgICAgaWYgKCF0aGlzLmlzU3RhcnRlZCAmJiAoZSBpbnN0YW5jZW9mIE1vdXNlRXZlbnQgJiYgZS50eXBlICE9PSAnY2xpY2snKSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IGNsb2NrRmFjZUNvcmRzID0gdGhpcy5jbG9ja0ZhY2UubmF0aXZlRWxlbWVudC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcblxuICAgICAgICAvKiBHZXQgeDAgYW5kIHkwIG9mIHRoZSBjaXJjbGUgKi9cbiAgICAgICAgY29uc3QgY2VudGVyWCA9IGNsb2NrRmFjZUNvcmRzLmxlZnQgKyBjbG9ja0ZhY2VDb3Jkcy53aWR0aCAvIDI7XG4gICAgICAgIGNvbnN0IGNlbnRlclkgPSBjbG9ja0ZhY2VDb3Jkcy50b3AgKyBjbG9ja0ZhY2VDb3Jkcy5oZWlnaHQgLyAyO1xuICAgICAgICAvKiBDb3VudGluZyB0aGUgYXJjdGFuZ2VudCBhbmQgY29udmVydCBpdCB0byBmcm9tIHJhZGlhbiB0byBkZWcgKi9cbiAgICAgICAgY29uc3QgYXJjdGFuZ2VudCA9IE1hdGguYXRhbihNYXRoLmFicyhlLmNsaWVudFggLSBjZW50ZXJYKSAvIE1hdGguYWJzKGUuY2xpZW50WSAtIGNlbnRlclkpKSAqIDE4MCAvIE1hdGguUEk7XG4gICAgICAgIC8qIEdldCBhbmdsZSBhY2NvcmRpbmcgdG8gcXVhZHJhbnQgKi9cbiAgICAgICAgY29uc3QgY2lyY2xlQW5nbGUgPSBjb3VudEFuZ2xlQnlDb3JkcyhjZW50ZXJYLCBjZW50ZXJZLCBlLmNsaWVudFgsIGUuY2xpZW50WSwgYXJjdGFuZ2VudCk7XG4gICAgICAgIC8qIENoZWNrIGlmIHNlbGVjdGVkIHRpbWUgZnJvbSB0aGUgaW5uZXIgY2xvY2sgZmFjZSAoMjQgaG91cnMgZm9ybWF0IG9ubHkpICovXG4gICAgICAgIGNvbnN0IGlzSW5uZXJDbG9ja0Nob3NlbiA9IHRoaXMuZm9ybWF0ICYmIHRoaXMuaXNJbm5lckNsb2NrRmFjZShjZW50ZXJYLCBjZW50ZXJZLCBlLmNsaWVudFgsIGUuY2xpZW50WSk7XG4gICAgICAgIC8qIFJvdW5kIGFuZ2xlIGFjY29yZGluZyB0byBhbmdsZSBzdGVwICovXG4gICAgICAgIGNvbnN0IGFuZ2xlU3RlcCA9IHRoaXMudW5pdCA9PT0gVGltZVVuaXQuTUlOVVRFID8gKDYgKiAodGhpcy5taW51dGVzR2FwIHx8IDEpKSA6IDMwO1xuICAgICAgICBjb25zdCByb3VuZGVkQW5nbGUgPSBpc0lubmVyQ2xvY2tDaG9zZW5cbiAgICAgICAgICAgID8gcm91bmRBbmdsZShjaXJjbGVBbmdsZSwgYW5nbGVTdGVwKSArIDM2MFxuICAgICAgICAgICAgOiByb3VuZEFuZ2xlKGNpcmNsZUFuZ2xlLCBhbmdsZVN0ZXApO1xuICAgICAgICBjb25zdCBhbmdsZSA9IHJvdW5kZWRBbmdsZSA9PT0gMCA/IDM2MCA6IHJvdW5kZWRBbmdsZTtcblxuICAgICAgICBjb25zdCBzZWxlY3RlZFRpbWUgPSB0aGlzLmZhY2VUaW1lLmZpbmQodmFsID0+IHZhbC5hbmdsZSA9PT0gYW5nbGUpO1xuXG4gICAgICAgIGlmIChzZWxlY3RlZFRpbWUgJiYgIXNlbGVjdGVkVGltZS5kaXNhYmxlZCkge1xuICAgICAgICAgICAgdGhpcy50aW1lQ2hhbmdlLm5leHQoc2VsZWN0ZWRUaW1lKTtcblxuICAgICAgICAgICAgLyogVG8gbGV0IGtub3cgd2hldGhlciB1c2VyIGVuZGVkIGludGVyYWN0aW9uIHdpdGggY2xvY2sgZmFjZSAqL1xuICAgICAgICAgICAgaWYgKCF0aGlzLmlzU3RhcnRlZCkge1xuICAgICAgICAgICAgICAgIHRoaXMudGltZVNlbGVjdGVkLm5leHQoc2VsZWN0ZWRUaW1lLnRpbWUpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICB9XG5cbiAgICBASG9zdExpc3RlbmVyKCdtb3VzZXVwJywgWyckZXZlbnQnXSlcbiAgICBvbk1vdXNldXAoZTogTW91c2VFdmVudCB8IFRvdWNoRXZlbnQpIHtcbiAgICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICB0aGlzLmlzU3RhcnRlZCA9IGZhbHNlO1xuICAgIH1cblxuICAgIGlzSG91clNlbGVjdGVkKGhvdXI6IG51bWJlcik6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gKGhvdXIgPT09IHRoaXMuc2VsZWN0ZWRUaW1lLnRpbWUpICYmICF0aGlzLmlzQ2xvY2tGYWNlRGlzYWJsZWQ7XG4gICAgfVxuXG4gICAgaXNNaW51dGVTZWxlY3RlZChtaW51dGU6IG51bWJlcik6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gKCh0aGlzLnNlbGVjdGVkVGltZS50aW1lID09PSBtaW51dGUpICYmIChtaW51dGUgJSAodGhpcy5taW51dGVzR2FwIHx8IDUpID09PSAwKSkgJiYgIXRoaXMuaXNDbG9ja0ZhY2VEaXNhYmxlZDtcbiAgICB9XG5cbiAgICBuZ09uRGVzdHJveSgpIHtcbiAgICAgICAgdGhpcy5yZW1vdmVUb3VjaEV2ZW50cygpO1xuICAgIH1cblxuICAgIHByaXZhdGUgYWRkVG91Y2hFdmVudHMoKTogdm9pZCB7XG4gICAgICAgIHRoaXMudG91Y2hTdGFydEhhbmRsZXIgPSB0aGlzLm9uTW91c2Vkb3duLmJpbmQodGhpcyk7XG4gICAgICAgIHRoaXMudG91Y2hFbmRIYW5kbGVyID0gdGhpcy5vbk1vdXNldXAuYmluZCh0aGlzKTtcblxuICAgICAgICB0aGlzLmNsb2NrRmFjZS5uYXRpdmVFbGVtZW50LmFkZEV2ZW50TGlzdGVuZXIoJ3RvdWNoc3RhcnQnLCB0aGlzLnRvdWNoU3RhcnRIYW5kbGVyKTtcbiAgICAgICAgdGhpcy5jbG9ja0ZhY2UubmF0aXZlRWxlbWVudC5hZGRFdmVudExpc3RlbmVyKCd0b3VjaGVuZCcsIHRoaXMudG91Y2hFbmRIYW5kbGVyKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIHJlbW92ZVRvdWNoRXZlbnRzKCk6IHZvaWQge1xuICAgICAgICB0aGlzLmNsb2NrRmFjZS5uYXRpdmVFbGVtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoJ3RvdWNoc3RhcnQnLCB0aGlzLnRvdWNoU3RhcnRIYW5kbGVyKTtcbiAgICAgICAgdGhpcy5jbG9ja0ZhY2UubmF0aXZlRWxlbWVudC5yZW1vdmVFdmVudExpc3RlbmVyKCd0b3VjaGVuZCcsIHRoaXMudG91Y2hFbmRIYW5kbGVyKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIHNldENsb2NrSGFuZFBvc2l0aW9uKCk6IHZvaWQge1xuICAgICAgICBpZiAodGhpcy5mb3JtYXQgPT09IDI0KSB7XG4gICAgICAgICAgICBpZiAodGhpcy5zZWxlY3RlZFRpbWUudGltZSA+IDEyIHx8IHRoaXMuc2VsZWN0ZWRUaW1lLnRpbWUgPT09IDApIHtcbiAgICAgICAgICAgICAgICB0aGlzLmRlY3JlYXNlQ2xvY2tIYW5kKCk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHRoaXMuaW5jcmVhc2VDbG9ja0hhbmQoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuY2xvY2tIYW5kLm5hdGl2ZUVsZW1lbnQuc3R5bGUudHJhbnNmb3JtID0gYHJvdGF0ZSgke3RoaXMuc2VsZWN0ZWRUaW1lLmFuZ2xlfWRlZylgO1xuICAgIH1cblxuICAgIHByaXZhdGUgc2VsZWN0QXZhaWxhYmxlVGltZSgpOiB2b2lkIHtcbiAgICAgICAgY29uc3QgY3VycmVudFRpbWUgPSB0aGlzLmZhY2VUaW1lLmZpbmQodGltZSA9PiB0aGlzLnNlbGVjdGVkVGltZS50aW1lID09PSB0aW1lLnRpbWUpO1xuICAgICAgICB0aGlzLmlzQ2xvY2tGYWNlRGlzYWJsZWQgPSB0aGlzLmZhY2VUaW1lLmV2ZXJ5KHRpbWUgPT4gdGltZS5kaXNhYmxlZCk7XG5cbiAgICAgICAgaWYgKChjdXJyZW50VGltZSAmJiBjdXJyZW50VGltZS5kaXNhYmxlZCkgJiYgIXRoaXMuaXNDbG9ja0ZhY2VEaXNhYmxlZCkge1xuICAgICAgICAgICAgY29uc3QgYXZhaWxhYmxlVGltZSA9IHRoaXMuZmFjZVRpbWUuZmluZCh0aW1lID0+ICF0aW1lLmRpc2FibGVkKTtcblxuICAgICAgICAgICAgdGhpcy50aW1lQ2hhbmdlLm5leHQoYXZhaWxhYmxlVGltZSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwcml2YXRlIGlzSW5uZXJDbG9ja0ZhY2UoeDA6IG51bWJlciwgeTA6IG51bWJlciwgeDogbnVtYmVyLCB5OiBudW1iZXIpOiBib29sZWFuIHtcbiAgICAgICAgLyogRGV0ZWN0IHdoZXRoZXIgdGltZSBmcm9tIHRoZSBpbm5lciBjbG9jayBmYWNlIG9yIG5vdCAoMjQgZm9ybWF0IG9ubHkpICovXG4gICAgICAgIHJldHVybiBNYXRoLnNxcnQoTWF0aC5wb3coeCAtIHgwLCAyKSArIE1hdGgucG93KHkgLSB5MCwgMikpIDwgdGhpcy5pbm5lckNsb2NrRmFjZVNpemU7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBkZWNyZWFzZUNsb2NrSGFuZCgpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5jbG9ja0hhbmQubmF0aXZlRWxlbWVudC5zdHlsZS5oZWlnaHQgPSBDTE9DS19IQU5EX1NUWUxFUy5zbWFsbC5oZWlnaHQ7XG4gICAgICAgIHRoaXMuY2xvY2tIYW5kLm5hdGl2ZUVsZW1lbnQuc3R5bGUudG9wID0gQ0xPQ0tfSEFORF9TVFlMRVMuc21hbGwudG9wO1xuICAgIH1cblxuICAgIHByaXZhdGUgaW5jcmVhc2VDbG9ja0hhbmQoKTogdm9pZCB7XG4gICAgICAgIHRoaXMuY2xvY2tIYW5kLm5hdGl2ZUVsZW1lbnQuc3R5bGUuaGVpZ2h0ID0gQ0xPQ0tfSEFORF9TVFlMRVMubGFyZ2UuaGVpZ2h0O1xuICAgICAgICB0aGlzLmNsb2NrSGFuZC5uYXRpdmVFbGVtZW50LnN0eWxlLnRvcCA9IENMT0NLX0hBTkRfU1RZTEVTLmxhcmdlLnRvcDtcbiAgICB9XG59XG5cbmZ1bmN0aW9uIHJvdW5kQW5nbGUoYW5nbGU6IG51bWJlciwgc3RlcDogbnVtYmVyKTogbnVtYmVyIHtcbiAgICByZXR1cm4gTWF0aC5yb3VuZChhbmdsZSAvIHN0ZXApICogc3RlcDtcbn1cblxuZnVuY3Rpb24gY291bnRBbmdsZUJ5Q29yZHMoeDA6IG51bWJlciwgeTA6IG51bWJlciwgeDogbnVtYmVyLCB5OiBudW1iZXIsIGN1cnJlbnRBbmdsZTogbnVtYmVyKTogbnVtYmVyIHtcbiAgICBpZiAoeSA+IHkwICYmIHggPj0geDApIHsvLyBJSSBxdWFydGVyXG4gICAgICAgIHJldHVybiAxODAgLSBjdXJyZW50QW5nbGU7XG4gICAgfSBlbHNlIGlmICh5ID4geTAgJiYgeCA8IHgwKSB7Ly8gSUlJIHF1YXJ0ZXJcbiAgICAgICAgcmV0dXJuIDE4MCArIGN1cnJlbnRBbmdsZTtcbiAgICB9IGVsc2UgaWYgKHkgPCB5MCAmJiB4IDwgeDApIHsvLyBJViBxdWFydGVyXG4gICAgICAgIHJldHVybiAzNjAgLSBjdXJyZW50QW5nbGU7XG4gICAgfSBlbHNlIHsvLyBJIHF1YXJ0ZXJcbiAgICAgICAgcmV0dXJuIGN1cnJlbnRBbmdsZTtcbiAgICB9XG59XG4iXX0=