ngx-bootstrap
Version:
Native Angular Bootstrap Components
480 lines (476 loc) • 43 kB
JavaScript
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, forwardRef, Input, Output, ViewEncapsulation } from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
import { TimepickerActions } from './reducer/timepicker.actions';
import { TimepickerStore } from './reducer/timepicker.store';
import { getControlsValue } from './timepicker-controls.util';
import { TimepickerConfig } from './timepicker.config';
import { isValidDate, padNumber, parseTime, isInputValid, isHourInputValid, isMinuteInputValid, isSecondInputValid, isInputLimitValid } from './timepicker.utils';
export const /** @type {?} */ TIMEPICKER_CONTROL_VALUE_ACCESSOR = {
provide: NG_VALUE_ACCESSOR,
/* tslint:disable-next-line: no-use-before-declare */
useExisting: forwardRef(() => TimepickerComponent),
multi: true
};
export class TimepickerComponent {
/**
* @param {?} _config
* @param {?} _cd
* @param {?} _store
* @param {?} _timepickerActions
*/
constructor(_config, _cd, _store, _timepickerActions) {
this._store = _store;
this._timepickerActions = _timepickerActions;
/**
* emits true if value is a valid date
*/
this.isValid = new EventEmitter();
// min\max validation for input fields
this.invalidHours = false;
this.invalidMinutes = false;
this.invalidSeconds = false;
// control value accessor methods
// tslint:disable-next-line:no-any
this.onChange = Function.prototype;
// tslint:disable-next-line:no-any
this.onTouched = Function.prototype;
Object.assign(this, _config);
this.timepickerSub = _store
.select(state => state.value)
.subscribe((value) => {
// update UI values if date changed
this._renderTime(value);
this.onChange(value);
this._store.dispatch(this._timepickerActions.updateControls(getControlsValue(this)));
});
_store
.select(state => state.controls)
.subscribe((controlsState) => {
this.isValid.emit(isInputValid(this.hours, this.minutes, this.seconds, this.isPM()));
Object.assign(this, controlsState);
_cd.markForCheck();
});
}
/**
* @deprecated - please use `isEditable` instead
* @return {?}
*/
get isSpinnersVisible() {
return this.showSpinners && !this.readonlyInput;
}
/**
* @return {?}
*/
get isEditable() {
return !(this.readonlyInput || this.disabled);
}
/**
* @return {?}
*/
resetValidation() {
this.invalidHours = false;
this.invalidMinutes = false;
this.invalidSeconds = false;
}
/**
* @return {?}
*/
isPM() {
return this.showMeridian && this.meridian === this.meridians[1];
}
/**
* @param {?} $event
* @return {?}
*/
prevDef($event) {
$event.preventDefault();
}
/**
* @param {?} $event
* @return {?}
*/
wheelSign($event) {
return Math.sign($event.deltaY) * -1;
}
/**
* @param {?} changes
* @return {?}
*/
ngOnChanges(changes) {
this._store.dispatch(this._timepickerActions.updateControls(getControlsValue(this)));
}
/**
* @param {?} step
* @param {?=} source
* @return {?}
*/
changeHours(step, source = '') {
this.resetValidation();
this._store.dispatch(this._timepickerActions.changeHours({ step, source }));
}
/**
* @param {?} step
* @param {?=} source
* @return {?}
*/
changeMinutes(step, source = '') {
this.resetValidation();
this._store.dispatch(this._timepickerActions.changeMinutes({ step, source }));
}
/**
* @param {?} step
* @param {?=} source
* @return {?}
*/
changeSeconds(step, source = '') {
this.resetValidation();
this._store.dispatch(this._timepickerActions.changeSeconds({ step, source }));
}
/**
* @param {?} hours
* @return {?}
*/
updateHours(hours) {
this.resetValidation();
this.hours = hours;
const /** @type {?} */ isValid = isHourInputValid(this.hours, this.isPM()) && this.isValidLimit();
if (!isValid) {
this.invalidHours = true;
this.isValid.emit(false);
this.onChange(null);
return;
}
this._updateTime();
}
/**
* @param {?} minutes
* @return {?}
*/
updateMinutes(minutes) {
this.resetValidation();
this.minutes = minutes;
const /** @type {?} */ isValid = isMinuteInputValid(this.minutes) && this.isValidLimit();
if (!isValid) {
this.invalidMinutes = true;
this.isValid.emit(false);
this.onChange(null);
return;
}
this._updateTime();
}
/**
* @param {?} seconds
* @return {?}
*/
updateSeconds(seconds) {
this.resetValidation();
this.seconds = seconds;
const /** @type {?} */ isValid = isSecondInputValid(this.seconds) && this.isValidLimit();
if (!isValid) {
this.invalidSeconds = true;
this.isValid.emit(false);
this.onChange(null);
return;
}
this._updateTime();
}
/**
* @return {?}
*/
isValidLimit() {
return isInputLimitValid({
hour: this.hours,
minute: this.minutes,
seconds: this.seconds,
isPM: this.isPM()
}, this.max, this.min);
}
/**
* @return {?}
*/
_updateTime() {
const /** @type {?} */ _seconds = this.showSeconds ? this.seconds : void 0;
const /** @type {?} */ _minutes = this.showMinutes ? this.minutes : void 0;
if (!isInputValid(this.hours, _minutes, _seconds, this.isPM())) {
this.isValid.emit(false);
this.onChange(null);
return;
}
this._store.dispatch(this._timepickerActions.setTime({
hour: this.hours,
minute: this.minutes,
seconds: this.seconds,
isPM: this.isPM()
}));
}
/**
* @return {?}
*/
toggleMeridian() {
if (!this.showMeridian || !this.isEditable) {
return;
}
const /** @type {?} */ _hoursPerDayHalf = 12;
this._store.dispatch(this._timepickerActions.changeHours({
step: _hoursPerDayHalf,
source: ''
}));
}
/**
* Write a new value to the element.
* @param {?} obj
* @return {?}
*/
writeValue(obj) {
if (isValidDate(obj)) {
this._store.dispatch(this._timepickerActions.writeValue(parseTime(obj)));
}
else if (obj == null) {
this._store.dispatch(this._timepickerActions.writeValue(null));
}
}
/**
* Set the function to be called when the control receives a change event.
* @param {?} fn
* @return {?}
*/
registerOnChange(fn) {
this.onChange = fn;
}
/**
* Set the function to be called when the control receives a touch event.
* @param {?} fn
* @return {?}
*/
registerOnTouched(fn) {
this.onTouched = fn;
}
/**
* This function is called when the control status changes to or from "disabled".
* Depending on the value, it will enable or disable the appropriate DOM element.
*
* @param {?} isDisabled
* @return {?}
*/
setDisabledState(isDisabled) {
this.disabled = isDisabled;
}
/**
* @return {?}
*/
ngOnDestroy() {
this.timepickerSub.unsubscribe();
}
/**
* @param {?} value
* @return {?}
*/
_renderTime(value) {
if (!isValidDate(value)) {
this.hours = '';
this.minutes = '';
this.seconds = '';
this.meridian = this.meridians[0];
return;
}
const /** @type {?} */ _value = parseTime(value);
const /** @type {?} */ _hoursPerDayHalf = 12;
let /** @type {?} */ _hours = _value.getHours();
if (this.showMeridian) {
this.meridian = this.meridians[_hours >= _hoursPerDayHalf ? 1 : 0];
_hours = _hours % _hoursPerDayHalf;
// should be 12 PM, not 00 PM
if (_hours === 0) {
_hours = _hoursPerDayHalf;
}
}
this.hours = padNumber(_hours);
this.minutes = padNumber(_value.getMinutes());
this.seconds = padNumber(_value.getUTCSeconds());
}
}
TimepickerComponent.decorators = [
{ type: Component, args: [{
selector: 'timepicker',
changeDetection: ChangeDetectionStrategy.OnPush,
providers: [TIMEPICKER_CONTROL_VALUE_ACCESSOR, TimepickerStore],
template: "<table>\n <tbody>\n <tr class=\"text-center\" [hidden]=\"!showSpinners\">\n <!-- increment hours button-->\n <td>\n <a class=\"btn btn-link\" [class.disabled]=\"!canIncrementHours || !isEditable\"\n (click)=\"changeHours(hourStep)\"\n ><span class=\"bs-chevron bs-chevron-up\"></span></a>\n </td>\n <!-- divider -->\n <td *ngIf=\"showMinutes\"> </td>\n <!-- increment minutes button -->\n <td *ngIf=\"showMinutes\">\n <a class=\"btn btn-link\" [class.disabled]=\"!canIncrementMinutes || !isEditable\"\n (click)=\"changeMinutes(minuteStep)\"\n ><span class=\"bs-chevron bs-chevron-up\"></span></a>\n </td>\n <!-- divider -->\n <td *ngIf=\"showSeconds\"> </td>\n <!-- increment seconds button -->\n <td *ngIf=\"showSeconds\">\n <a class=\"btn btn-link\" [class.disabled]=\"!canIncrementSeconds || !isEditable\"\n (click)=\"changeSeconds(secondsStep)\">\n <span class=\"bs-chevron bs-chevron-up\"></span>\n </a>\n </td>\n <!-- space between -->\n <td *ngIf=\"showMeridian\"> </td>\n <!-- meridian placeholder-->\n <td *ngIf=\"showMeridian\"></td>\n </tr>\n <tr>\n <!-- hours -->\n <td class=\"form-group\" [class.has-error]=\"invalidHours\">\n <input type=\"text\" [class.is-invalid]=\"invalidHours\"\n class=\"form-control text-center bs-timepicker-field\"\n placeholder=\"HH\"\n maxlength=\"2\"\n [readonly]=\"readonlyInput\"\n [disabled]=\"disabled\"\n [value]=\"hours\"\n (wheel)=\"prevDef($event);changeHours(hourStep * wheelSign($event), 'wheel')\"\n (keydown.ArrowUp)=\"changeHours(hourStep, 'key')\"\n (keydown.ArrowDown)=\"changeHours(-hourStep, 'key')\"\n (change)=\"updateHours($event.target.value)\"></td>\n <!-- divider -->\n <td *ngIf=\"showMinutes\"> : </td>\n <!-- minutes -->\n <td class=\"form-group\" *ngIf=\"showMinutes\" [class.has-error]=\"invalidMinutes\">\n <input type=\"text\" [class.is-invalid]=\"invalidMinutes\"\n class=\"form-control text-center bs-timepicker-field\"\n placeholder=\"MM\"\n maxlength=\"2\"\n [readonly]=\"readonlyInput\"\n [disabled]=\"disabled\"\n [value]=\"minutes\"\n (wheel)=\"prevDef($event);changeMinutes(minuteStep * wheelSign($event), 'wheel')\"\n (keydown.ArrowUp)=\"changeMinutes(minuteStep, 'key')\"\n (keydown.ArrowDown)=\"changeMinutes(-minuteStep, 'key')\"\n (change)=\"updateMinutes($event.target.value)\">\n </td>\n <!-- divider -->\n <td *ngIf=\"showSeconds\"> : </td>\n <!-- seconds -->\n <td class=\"form-group\" *ngIf=\"showSeconds\" [class.has-error]=\"invalidSeconds\">\n <input type=\"text\" [class.is-invalid]=\"invalidSeconds\"\n class=\"form-control text-center bs-timepicker-field\"\n placeholder=\"SS\"\n maxlength=\"2\"\n [readonly]=\"readonlyInput\"\n [disabled]=\"disabled\"\n [value]=\"seconds\"\n (wheel)=\"prevDef($event);changeSeconds(secondsStep * wheelSign($event), 'wheel')\"\n (keydown.ArrowUp)=\"changeSeconds(secondsStep, 'key')\"\n (keydown.ArrowDown)=\"changeSeconds(-secondsStep, 'key')\"\n (change)=\"updateSeconds($event.target.value)\">\n </td>\n <!-- space between -->\n <td *ngIf=\"showMeridian\"> </td>\n <!-- meridian -->\n <td *ngIf=\"showMeridian\">\n <button type=\"button\" class=\"btn btn-default text-center\"\n [disabled]=\"!isEditable || !canToggleMeridian\"\n [class.disabled]=\"!isEditable || !canToggleMeridian\"\n (click)=\"toggleMeridian()\"\n >{{ meridian }}\n </button>\n </td>\n </tr>\n <tr class=\"text-center\" [hidden]=\"!showSpinners\">\n <!-- decrement hours button-->\n <td>\n <a class=\"btn btn-link\" [class.disabled]=\"!canDecrementHours || !isEditable\"\n (click)=\"changeHours(-hourStep)\">\n <span class=\"bs-chevron bs-chevron-down\"></span>\n </a>\n </td>\n <!-- divider -->\n <td *ngIf=\"showMinutes\"> </td>\n <!-- decrement minutes button-->\n <td *ngIf=\"showMinutes\">\n <a class=\"btn btn-link\" [class.disabled]=\"!canDecrementMinutes || !isEditable\"\n (click)=\"changeMinutes(-minuteStep)\">\n <span class=\"bs-chevron bs-chevron-down\"></span>\n </a>\n </td>\n <!-- divider -->\n <td *ngIf=\"showSeconds\"> </td>\n <!-- decrement seconds button-->\n <td *ngIf=\"showSeconds\">\n <a class=\"btn btn-link\" [class.disabled]=\"!canDecrementSeconds || !isEditable\"\n (click)=\"changeSeconds(-secondsStep)\">\n <span class=\"bs-chevron bs-chevron-down\"></span>\n </a>\n </td>\n <!-- space between -->\n <td *ngIf=\"showMeridian\"> </td>\n <!-- meridian placeholder-->\n <td *ngIf=\"showMeridian\"></td>\n </tr>\n </tbody>\n</table>\n",
encapsulation: ViewEncapsulation.None,
styles: [`
.bs-chevron {
border-style: solid;
display: block;
width: 9px;
height: 9px;
position: relative;
border-width: 3px 0px 0 3px;
}
.bs-chevron-up {
-webkit-transform: rotate(45deg);
transform: rotate(45deg);
top: 2px;
}
.bs-chevron-down {
-webkit-transform: rotate(-135deg);
transform: rotate(-135deg);
top: -2px;
}
.bs-timepicker-field {
width: 50px;
}
`]
}] }
];
/** @nocollapse */
TimepickerComponent.ctorParameters = () => [
{ type: TimepickerConfig, },
{ type: ChangeDetectorRef, },
{ type: TimepickerStore, },
{ type: TimepickerActions, },
];
TimepickerComponent.propDecorators = {
"hourStep": [{ type: Input },],
"minuteStep": [{ type: Input },],
"secondsStep": [{ type: Input },],
"readonlyInput": [{ type: Input },],
"disabled": [{ type: Input },],
"mousewheel": [{ type: Input },],
"arrowkeys": [{ type: Input },],
"showSpinners": [{ type: Input },],
"showMeridian": [{ type: Input },],
"showMinutes": [{ type: Input },],
"showSeconds": [{ type: Input },],
"meridians": [{ type: Input },],
"min": [{ type: Input },],
"max": [{ type: Input },],
"isValid": [{ type: Output },],
};
function TimepickerComponent_tsickle_Closure_declarations() {
/** @type {!Array<{type: !Function, args: (undefined|!Array>)}>} */
TimepickerComponent.decorators;
/**
* @nocollapse
* @type {function(): !Array<(null|{type: ?, decorators: (undefined|!Array<{type: !Function, args: (undefined|!Array<?>)}>)})>}
*/
TimepickerComponent.ctorParameters;
/** @type {!Object<string,!Array<{type: !Function, args: (undefined|!Array<?>)}>>} */
TimepickerComponent.propDecorators;
/**
* hours change step
* @type {?}
*/
TimepickerComponent.prototype.hourStep;
/**
* hours change step
* @type {?}
*/
TimepickerComponent.prototype.minuteStep;
/**
* seconds change step
* @type {?}
*/
TimepickerComponent.prototype.secondsStep;
/**
* if true hours and minutes fields will be readonly
* @type {?}
*/
TimepickerComponent.prototype.readonlyInput;
/**
* if true hours and minutes fields will be disabled
* @type {?}
*/
TimepickerComponent.prototype.disabled;
/**
* if true scroll inside hours and minutes inputs will change time
* @type {?}
*/
TimepickerComponent.prototype.mousewheel;
/**
* if true the values of hours and minutes can be changed using the up/down arrow keys on the keyboard
* @type {?}
*/
TimepickerComponent.prototype.arrowkeys;
/**
* if true spinner arrows above and below the inputs will be shown
* @type {?}
*/
TimepickerComponent.prototype.showSpinners;
/**
* if true meridian button will be shown
* @type {?}
*/
TimepickerComponent.prototype.showMeridian;
/**
* show minutes in timepicker
* @type {?}
*/
TimepickerComponent.prototype.showMinutes;
/**
* show seconds in timepicker
* @type {?}
*/
TimepickerComponent.prototype.showSeconds;
/**
* meridian labels based on locale
* @type {?}
*/
TimepickerComponent.prototype.meridians;
/**
* minimum time user can select
* @type {?}
*/
TimepickerComponent.prototype.min;
/**
* maximum time user can select
* @type {?}
*/
TimepickerComponent.prototype.max;
/**
* emits true if value is a valid date
* @type {?}
*/
TimepickerComponent.prototype.isValid;
/** @type {?} */
TimepickerComponent.prototype.hours;
/** @type {?} */
TimepickerComponent.prototype.minutes;
/** @type {?} */
TimepickerComponent.prototype.seconds;
/** @type {?} */
TimepickerComponent.prototype.meridian;
/** @type {?} */
TimepickerComponent.prototype.invalidHours;
/** @type {?} */
TimepickerComponent.prototype.invalidMinutes;
/** @type {?} */
TimepickerComponent.prototype.invalidSeconds;
/** @type {?} */
TimepickerComponent.prototype.canIncrementHours;
/** @type {?} */
TimepickerComponent.prototype.canIncrementMinutes;
/** @type {?} */
TimepickerComponent.prototype.canIncrementSeconds;
/** @type {?} */
TimepickerComponent.prototype.canDecrementHours;
/** @type {?} */
TimepickerComponent.prototype.canDecrementMinutes;
/** @type {?} */
TimepickerComponent.prototype.canDecrementSeconds;
/** @type {?} */
TimepickerComponent.prototype.canToggleMeridian;
/** @type {?} */
TimepickerComponent.prototype.onChange;
/** @type {?} */
TimepickerComponent.prototype.onTouched;
/** @type {?} */
TimepickerComponent.prototype.timepickerSub;
/** @type {?} */
TimepickerComponent.prototype._store;
/** @type {?} */
TimepickerComponent.prototype._timepickerActions;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGltZXBpY2tlci5jb21wb25lbnQuanMiLCJzb3VyY2VSb290Ijoibmc6Ly9uZ3gtYm9vdHN0cmFwL3RpbWVwaWNrZXIvIiwic291cmNlcyI6WyJ0aW1lcGlja2VyLmNvbXBvbmVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7O0FBQ0EsT0FBTyxFQUNMLHVCQUF1QixFQUN2QixpQkFBaUIsRUFDakIsU0FBUyxFQUNULFlBQVksRUFDWixVQUFVLEVBQ1YsS0FBSyxFQUdMLE1BQU0sRUFDUyxpQkFBaUIsRUFDakMsTUFBTSxlQUFlLENBQUM7QUFFdkIsT0FBTyxFQUF3QixpQkFBaUIsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBRXpFLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLDhCQUE4QixDQUFDO0FBQ2pFLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUM3RCxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUM5RCxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQVF2RCxPQUFPLEVBQ0wsV0FBVyxFQUNYLFNBQVMsRUFDVCxTQUFTLEVBQ1QsWUFBWSxFQUNaLGdCQUFnQixFQUNoQixrQkFBa0IsRUFDbEIsa0JBQWtCLEVBQ2xCLGlCQUFpQixFQUNsQixNQUFNLG9CQUFvQixDQUFDO0FBTTVCLE1BQU0sQ0FBQyx1QkFBTSxpQ0FBaUMsR0FBOEI7SUFDMUUsT0FBTyxFQUFFLGlCQUFpQjs7SUFFMUIsV0FBVyxFQUFFLFVBQVUsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxtQkFBbUIsQ0FBQztJQUNsRCxLQUFLLEVBQUUsSUFBSTtDQUNaLENBQUM7QUFtQ0YsTUFBTTs7Ozs7OztJQTZFSixZQUNFLE9BQXlCLEVBQ3pCLEdBQXNCLEVBQ2QsUUFDQTtRQURBLFdBQU0sR0FBTixNQUFNO1FBQ04sdUJBQWtCLEdBQWxCLGtCQUFrQjs7Ozt1QkE3Q1IsSUFBSSxZQUFZLEVBQVc7OzRCQWtC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QkFFTCxLQUFLO3lCQUVMLEtBQUs7MkJBRUwsS0FBSzswQkFFTCxLQUFLOzZCQUVMLEtBQUs7NkJBRUwsS0FBSzs0QkFFTCxLQUFLOzRCQUVMLEtBQUs7MEJBRUwsS0FBSztvQkFFTCxLQUFLO29CQUVMLEtBQUs7d0JBR0wsTUFBTSIsInNvdXJjZXNDb250ZW50IjpbIi8qIHRzbGludDpkaXNhYmxlOm5vLWZvcndhcmQtcmVmIG1heC1maWxlLWxpbmUtY291bnQgKi9cbmltcG9ydCB7XG4gIENoYW5nZURldGVjdGlvblN0cmF0ZWd5LFxuICBDaGFuZ2VEZXRlY3RvclJlZixcbiAgQ29tcG9uZW50LFxuICBFdmVudEVtaXR0ZXIsXG4gIGZvcndhcmRSZWYsXG4gIElucHV0LFxuICBPbkNoYW5nZXMsXG4gIE9uRGVzdHJveSxcbiAgT3V0cHV0LFxuICBTaW1wbGVDaGFuZ2VzLCBWaWV3RW5jYXBzdWxhdGlvblxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcblxuaW1wb3J0IHsgQ29udHJvbFZhbHVlQWNjZXNzb3IsIE5HX1ZBTFVFX0FDQ0VTU09SIH0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xuXG5pbXBvcnQgeyBUaW1lcGlja2VyQWN0aW9ucyB9IGZyb20gJy4vcmVkdWNlci90aW1lcGlja2VyLmFjdGlvbnMnO1xuaW1wb3J0IHsgVGltZXBpY2tlclN0b3JlIH0gZnJvbSAnLi9yZWR1Y2VyL3RpbWVwaWNrZXIuc3RvcmUnO1xuaW1wb3J0IHsgZ2V0Q29udHJvbHNWYWx1ZSB9IGZyb20gJy4vdGltZXBpY2tlci1jb250cm9scy51dGlsJztcbmltcG9ydCB7IFRpbWVwaWNrZXJDb25maWcgfSBmcm9tICcuL3RpbWVwaWNrZXIuY29uZmlnJztcblxuaW1wb3J0IHtcbiAgVGltZUNoYW5nZVNvdXJjZSxcbiAgVGltZXBpY2tlckNvbXBvbmVudFN0YXRlLFxuICBUaW1lcGlja2VyQ29udHJvbHNcbn0gZnJvbSAnLi90aW1lcGlja2VyLm1vZGVscyc7XG5cbmltcG9ydCB7XG4gIGlzVmFsaWREYXRlLFxuICBwYWROdW1iZXIsXG4gIHBhcnNlVGltZSxcbiAgaXNJbnB1dFZhbGlkLFxuICBpc0hvdXJJbnB1dFZhbGlkLFxuICBpc01pbnV0ZUlucHV0VmFsaWQsXG4gIGlzU2Vjb25kSW5wdXRWYWxpZCxcbiAgaXNJbnB1dExpbWl0VmFsaWRcbn0gZnJvbSAnLi90aW1lcGlja2VyLnV0aWxzJztcblxuaW1wb3J0IHsgU3Vic2NyaXB0aW9uIH0gZnJvbSAncnhqcyc7XG5cbmltcG9ydCB7IENvbnRyb2xWYWx1ZUFjY2Vzc29yTW9kZWwgfSBmcm9tICcuL21vZGVscyc7XG5cbmV4cG9ydCBjb25zdCBUSU1FUElDS0VSX0NPTlRST0xfVkFMVUVfQUNDRVNTT1I6IENvbnRyb2xWYWx1ZUFjY2Vzc29yTW9kZWwgPSB7XG4gIHByb3ZpZGU6IE5HX1ZBTFVFX0FDQ0VTU09SLFxuICAvKiB0c2xpbnQ6ZGlzYWJsZS1uZXh0LWxpbmU6IG5vLXVzZS1iZWZvcmUtZGVjbGFyZSAqL1xuICB1c2VFeGlzdGluZzogZm9yd2FyZFJlZigoKSA9PiBUaW1lcGlja2VyQ29tcG9uZW50KSxcbiAgbXVsdGk6IHRydWVcbn07XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ3RpbWVwaWNrZXInLFxuICBjaGFuZ2VEZXRlY3Rpb246IENoYW5nZURldGVjdGlvblN0cmF0ZWd5Lk9uUHVzaCxcbiAgcHJvdmlkZXJzOiBbVElNRVBJQ0tFUl9DT05UUk9MX1ZBTFVFX0FDQ0VTU09SLCBUaW1lcGlja2VyU3RvcmVdLFxuICB0ZW1wbGF0ZVVybDogJy4vdGltZXBpY2tlci5jb21wb25lbnQuaHRtbCcsXG4gIHN0eWxlczogW2BcbiAgICAuYnMtY2hldnJvbiB7XG4gICAgICBib3JkZXItc3R5bGU6IHNvbGlkO1xuICAgICAgZGlzcGxheTogYmxvY2s7XG4gICAgICB3aWR0aDogOXB4O1xuICAgICAgaGVpZ2h0OiA5cHg7XG4gICAgICBwb3NpdGlvbjogcmVsYXRpdmU7XG4gICAgICBib3JkZXItd2lkdGg6IDNweCAwcHggMCAzcHg7XG4gICAgfVxuXG4gICAgLmJzLWNoZXZyb24tdXAge1xuICAgICAgLXdlYmtpdC10cmFuc2Zvcm06IHJvdGF0ZSg0NWRlZyk7XG4gICAgICB0cmFuc2Zvcm06IHJvdGF0ZSg0NWRlZyk7XG4gICAgICB0b3A6IDJweDtcbiAgICB9XG5cbiAgICAuYnMtY2hldnJvbi1kb3duIHtcbiAgICAgIC13ZWJraXQtdHJhbnNmb3JtOiByb3RhdGUoLTEzNWRlZyk7XG4gICAgICB0cmFuc2Zvcm06IHJvdGF0ZSgtMTM1ZGVnKTtcbiAgICAgIHRvcDogLTJweDtcbiAgICB9XG5cbiAgICAuYnMtdGltZXBpY2tlci1maWVsZCB7XG4gICAgICB3aWR0aDogNTBweDtcbiAgICB9XG4gIGBdLFxuICBlbmNhcHN1bGF0aW9uOiBWaWV3RW5jYXBzdWxhdGlvbi5Ob25lXG59KVxuZXhwb3J0IGNsYXNzIFRpbWVwaWNrZXJDb21wb25lbnRcbiAgaW1wbGVtZW50cyBDb250cm9sVmFsdWVBY2Nlc3NvcixcbiAgICBUaW1lcGlja2VyQ29tcG9uZW50U3RhdGUsXG4gICAgVGltZXBpY2tlckNvbnRyb2xzLFxuICAgIE9uQ2hhbmdlcyxcbiAgICBPbkRlc3Ryb3kge1xuICAvKiogaG91cnMgY2hhbmdlIHN0ZXAgKi9cbiAgQElucHV0KCkgaG91clN0ZXA6IG51bWJlcjtcbiAgLyoqIGhvdXJzIGNoYW5nZSBzdGVwICovXG4gIEBJbnB1dCgpIG1pbnV0ZVN0ZXA6IG51bWJlcjtcbiAgLyoqIHNlY29uZHMgY2hhbmdlIHN0ZXAgKi9cbiAgQElucHV0KCkgc2Vjb25kc1N0ZXA6IG51bWJlcjtcbiAgLyoqIGlmIHRydWUgaG91cnMgYW5kIG1pbnV0ZXMgZmllbGRzIHdpbGwgYmUgcmVhZG9ubHkgKi9cbiAgQElucHV0KCkgcmVhZG9ubHlJbnB1dDogYm9vbGVhbjtcbiAgLyoqIGlmIHRydWUgaG91cnMgYW5kIG1pbnV0ZXMgZmllbGRzIHdpbGwgYmUgZGlzYWJsZWQgKi9cbiAgQElucHV0KCkgZGlzYWJsZWQ6IGJvb2xlYW47XG4gIC8qKiBpZiB0cnVlIHNjcm9sbCBpbnNpZGUgaG91cnMgYW5kIG1pbnV0ZXMgaW5wdXRzIHdpbGwgY2hhbmdlIHRpbWUgKi9cbiAgQElucHV0KCkgbW91c2V3aGVlbDogYm9vbGVhbjtcbiAgLyoqIGlmIHRydWUgdGhlIHZhbHVlcyBvZiBob3VycyBhbmQgbWludXRlcyBjYW4gYmUgY2hhbmdlZCB1c2luZyB0aGUgdXAvZG93biBhcnJvdyBrZXlzIG9uIHRoZSBrZXlib2FyZCAqL1xuICBASW5wdXQoKSBhcnJvd2tleXM6IGJvb2xlYW47XG4gIC8qKiBpZiB0cnVlIHNwaW5uZXIgYXJyb3dzIGFib3ZlIGFuZCBiZWxvdyB0aGUgaW5wdXRzIHdpbGwgYmUgc2hvd24gKi9cbiAgQElucHV0KCkgc2hvd1NwaW5uZXJzOiBib29sZWFuO1xuICAvKiogaWYgdHJ1ZSBtZXJpZGlhbiBidXR0b24gd2lsbCBiZSBzaG93biAqL1xuICBASW5wdXQoKSBzaG93TWVyaWRpYW46IGJvb2xlYW47XG4gIC8qKiBzaG93IG1pbnV0ZXMgaW4gdGltZXBpY2tlciAqL1xuICBASW5wdXQoKSBzaG93TWludXRlczogYm9vbGVhbjtcbiAgLyoqIHNob3cgc2Vjb25kcyBpbiB0aW1lcGlja2VyICovXG4gIEBJbnB1dCgpIHNob3dTZWNvbmRzOiBib29sZWFuO1xuICAvKiogbWVyaWRpYW4gbGFiZWxzIGJhc2VkIG9uIGxvY2FsZSAqL1xuICBASW5wdXQoKSBtZXJpZGlhbnM6IHN0cmluZ1tdO1xuICAvKiogbWluaW11bSB0aW1lIHVzZXIgY2FuIHNlbGVjdCAqL1xuICBASW5wdXQoKSBtaW46IERhdGU7XG4gIC8qKiBtYXhpbXVtIHRpbWUgdXNlciBjYW4gc2VsZWN0ICovXG4gIEBJbnB1dCgpIG1heDogRGF0ZTtcblxuICAvKiogZW1pdHMgdHJ1ZSBpZiB2YWx1ZSBpcyBhIHZhbGlkIGRhdGUgKi9cbiAgQE91dHB1dCgpIGlzVmFsaWQgPSBuZXcgRXZlbnRFbWl0dGVyPGJvb2xlYW4+KCk7XG5cbiAgLy8gdWkgdmFyaWFibGVzXG4gIGhvdXJzOiBzdHJpbmc7XG4gIG1pbnV0ZXM6IHN0cmluZztcbiAgc2Vjb25kczogc3RyaW5nO1xuICBtZXJpZGlhbjogc3RyaW5nO1xuXG4gIC8qKiBAZGVwcmVjYXRlZCAtIHBsZWFzZSB1c2UgYGlzRWRpdGFibGVgIGluc3RlYWQgKi9cbiAgZ2V0IGlzU3Bpbm5lcnNWaXNpYmxlKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLnNob3dTcGlubmVycyAmJiAhdGhpcy5yZWFkb25seUlucHV0O1xuICB9XG5cbiAgZ2V0IGlzRWRpdGFibGUoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuICEodGhpcy5yZWFkb25seUlucHV0IHx8IHRoaXMuZGlzYWJsZWQpO1xuICB9XG5cbiAgLy8gbWluXFxtYXggdmFsaWRhdGlvbiBmb3IgaW5wdXQgZmllbGRzXG4gIGludmFsaWRIb3VycyA9IGZhbHNlO1xuICBpbnZhbGlkTWludXRlcyA9IGZhbHNlO1xuICBpbnZhbGlkU2Vjb25kcyA9IGZhbHNlO1xuXG4gIC8vIHRpbWUgcGlja2VyIGNvbnRyb2xzIHN0YXRlXG4gIGNhbkluY3JlbWVudEhvdXJzOiBib29sZWFuO1xuICBjYW5JbmNyZW1lbnRNaW51dGVzOiBib29sZWFuO1xuICBjYW5JbmNyZW1lbnRTZWNvbmRzOiBib29sZWFuO1xuXG4gIGNhbkRlY3JlbWVudEhvdXJzOiBib29sZWFuO1xuICBjYW5EZWNyZW1lbnRNaW51dGVzOiBib29sZWFuO1xuICBjYW5EZWNyZW1lbnRTZWNvbmRzOiBib29sZWFuO1xuXG4gIGNhblRvZ2dsZU1lcmlkaWFuOiBib29sZWFuO1xuXG4gIC8vIGNvbnRyb2wgdmFsdWUgYWNjZXNzb3IgbWV0aG9kc1xuICAvLyB0c2xpbnQ6ZGlzYWJsZS1uZXh0LWxpbmU6bm8tYW55XG4gIG9uQ2hhbmdlID0gRnVuY3Rpb24ucHJvdG90eXBlO1xuICAvLyB0c2xpbnQ6ZGlzYWJsZS1uZXh0LWxpbmU6bm8tYW55XG4gIG9uVG91Y2hlZCA9IEZ1bmN0aW9uLnByb3RvdHlwZTtcblxuICB0aW1lcGlja2VyU3ViOiBTdWJzY3JpcHRpb247XG5cbiAgY29uc3RydWN0b3IoXG4gICAgX2NvbmZpZzogVGltZXBpY2tlckNvbmZpZyxcbiAgICBfY2Q6IENoYW5nZURldGVjdG9yUmVmLFxuICAgIHByaXZhdGUgX3N0b3JlOiBUaW1lcGlja2VyU3RvcmUsXG4gICAgcHJpdmF0ZSBfdGltZXBpY2tlckFjdGlvbnM6IFRpbWVwaWNrZXJBY3Rpb25zXG4gICkge1xuICAgIE9iamVjdC5hc3NpZ24odGhpcywgX2NvbmZpZyk7XG5cbiAgICB0aGlzLnRpbWVwaWNrZXJTdWIgPSBfc3RvcmVcbiAgICAgIC5zZWxlY3Qoc3RhdGUgPT4gc3RhdGUudmFsdWUpXG4gICAgICAuc3Vic2NyaWJlKCh2YWx1ZTogRGF0ZSkgPT4ge1xuICAgICAgICAvLyB1cGRhdGUgVUkgdmFsdWVzIGlmIGRhdGUgY2hhbmdlZFxuICAgICAgICB0aGlzLl9yZW5kZXJUaW1lKHZhbHVlKTtcbiAgICAgICAgdGhpcy5vbkNoYW5nZSh2YWx1ZSk7XG5cbiAgICAgICAgdGhpcy5fc3RvcmUuZGlzcGF0Y2goXG4gICAgICAgICAgdGhpcy5fdGltZXBpY2tlckFjdGlvbnMudXBkYXRlQ29udHJvbHMoZ2V0Q29udHJvbHNWYWx1ZSh0aGlzKSlcbiAgICAgICAgKTtcbiAgICAgIH0pO1xuXG4gICAgX3N0b3JlXG4gICAgICAuc2VsZWN0KHN0YXRlID0+IHN0YXRlLmNvbnRyb2xzKVxuICAgICAgLnN1YnNjcmliZSgoY29udHJvbHNTdGF0ZTogVGltZXBpY2tlckNvbnRyb2xzKSA9PiB7XG4gICAgICAgIHRoaXMuaXNWYWxpZC5lbWl0KGlzSW5wdXRWYWxpZCh0aGlzLmhvdXJzLCB0aGlzLm1pbnV0ZXMsIHRoaXMuc2Vjb25kcywgdGhpcy5pc1BNKCkpKTtcbiAgICAgICAgT2JqZWN0LmFzc2lnbih0aGlzLCBjb250cm9sc1N0YXRlKTtcbiAgICAgICAgX2NkLm1hcmtGb3JDaGVjaygpO1xuICAgICAgfSk7XG4gIH1cblxuICByZXNldFZhbGlkYXRpb24oKTogdm9pZCB7XG4gICAgdGhpcy5pbnZhbGlkSG91cnMgPSBmYWxzZTtcbiAgICB0aGlzLmludmFsaWRNaW51dGVzID0gZmFsc2U7XG4gICAgdGhpcy5pbnZhbGlkU2Vjb25kcyA9IGZhbHNlO1xuICB9XG5cbiAgaXNQTSgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5zaG93TWVyaWRpYW4gJiYgdGhpcy5tZXJpZGlhbiA9PT0gdGhpcy5tZXJpZGlhbnNbMV07XG4gIH1cblxuICBwcmV2RGVmKCRldmVudDogRXZlbnQpIHtcbiAgICAkZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgfVxuXG4gIHdoZWVsU2lnbigkZXZlbnQ6IFdoZWVsRXZlbnRJbml0KTogbnVtYmVyIHtcbiAgICByZXR1cm4gTWF0aC5zaWduKCRldmVudC5kZWx0YVkpICogLTE7XG4gIH1cblxuICBuZ09uQ2hhbmdlcyhjaGFuZ2VzOiBTaW1wbGVDaGFuZ2VzKTogdm9pZCB7XG4gICAgdGhpcy5fc3RvcmUuZGlzcGF0Y2goXG4gICAgICB0aGlzLl90aW1lcGlja2VyQWN0aW9ucy51cGRhdGVDb250cm9scyhnZXRDb250cm9sc1ZhbHVlKHRoaXMpKVxuICAgICk7XG4gIH1cblxuICBjaGFuZ2VIb3VycyhzdGVwOiBudW1iZXIsIHNvdXJjZTogVGltZUNoYW5nZVNvdXJjZSA9ICcnKTogdm9pZCB7XG4gICAgdGhpcy5yZXNldFZhbGlkYXRpb24oKTtcbiAgICB0aGlzLl9zdG9yZS5kaXNwYXRjaCh0aGlzLl90aW1lcGlja2VyQWN0aW9ucy5jaGFuZ2VIb3Vycyh7IHN0ZXAsIHNvdXJjZSB9KSk7XG4gIH1cblxuICBjaGFuZ2VNaW51dGVzKHN0ZXA6IG51bWJlciwgc291cmNlOiBUaW1lQ2hhbmdlU291cmNlID0gJycpOiB2b2lkIHtcbiAgICB0aGlzLnJlc2V0VmFsaWRhdGlvbigpO1xuICAgIHRoaXMuX3N0b3JlLmRpc3BhdGNoKFxuICAgICAgdGhpcy5fdGltZXBpY2tlckFjdGlvbnMuY2hhbmdlTWludXRlcyh7IHN0ZXAsIHNvdXJjZSB9KVxuICAgICk7XG4gIH1cblxuICBjaGFuZ2VTZWNvbmRzKHN0ZXA6IG51bWJlciwgc291cmNlOiBUaW1lQ2hhbmdlU291cmNlID0gJycpOiB2b2lkIHtcbiAgICB0aGlzLnJlc2V0VmFsaWRhdGlvbigpO1xuICAgIHRoaXMuX3N0b3JlLmRpc3BhdGNoKFxuICAgICAgdGhpcy5fdGltZXBpY2tlckFjdGlvbnMuY2hhbmdlU2Vjb25kcyh7IHN0ZXAsIHNvdXJjZSB9KVxuICAgICk7XG4gIH1cblxuICB1cGRhdGVIb3Vycyhob3Vyczogc3RyaW5nKTogdm9pZCB7XG4gICAgdGhpcy5yZXNldFZhbGlkYXRpb24oKTtcbiAgICB0aGlzLmhvdXJzID0gaG91cnM7XG5cbiAgICBjb25zdCBpc1ZhbGlkID0gaXNIb3VySW5wdXRWYWxpZCh0aGlzLmhvdXJzLCB0aGlzLmlzUE0oKSkgJiYgdGhpcy5pc1ZhbGlkTGltaXQoKTtcblxuICAgIGlmICghaXNWYWxpZCkge1xuICAgICAgdGhpcy5pbnZhbGlkSG91cnMgPSB0cnVlO1xuICAgICAgdGhpcy5pc1ZhbGlkLmVtaXQoZmFsc2UpO1xuICAgICAgdGhpcy5vbkNoYW5nZShudWxsKTtcblxuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHRoaXMuX3VwZGF0ZVRpbWUoKTtcbiAgfVxuXG4gIHVwZGF0ZU1pbnV0ZXMobWludXRlczogc3RyaW5nKSB7XG4gICAgdGhpcy5yZXNldFZhbGlkYXRpb24oKTtcbiAgICB0aGlzLm1pbnV0ZXMgPSBtaW51dGVzO1xuXG4gICAgY29uc3QgaXNWYWxpZCA9IGlzTWludXRlSW5wdXRWYWxpZCh0aGlzLm1pbnV0ZXMpICYmIHRoaXMuaXNWYWxpZExpbWl0KCk7XG5cbiAgICBpZiAoIWlzVmFsaWQpIHtcbiAgICAgIHRoaXMuaW52YWxpZE1pbnV0ZXMgPSB0cnVlO1xuICAgICAgdGhpcy5pc1ZhbGlkLmVtaXQoZmFsc2UpO1xuICAgICAgdGhpcy5vbkNoYW5nZShudWxsKTtcblxuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHRoaXMuX3VwZGF0ZVRpbWUoKTtcbiAgfVxuXG4gIHVwZGF0ZVNlY29uZHMoc2Vjb25kczogc3RyaW5nKSB7XG4gICAgdGhpcy5yZXNldFZhbGlkYXRpb24oKTtcbiAgICB0aGlzLnNlY29uZHMgPSBzZWNvbmRzO1xuXG4gICAgY29uc3QgaXNWYWxpZCA9IGlzU2Vjb25kSW5wdXRWYWxpZCh0aGlzLnNlY29uZHMpICYmIHRoaXMuaXNWYWxpZExpbWl0KCk7XG5cbiAgICBpZiAoIWlzVmFsaWQpIHtcbiAgICAgIHRoaXMuaW52YWxpZFNlY29uZHMgPSB0cnVlO1xuICAgICAgdGhpcy5pc1ZhbGlkLmVtaXQoZmFsc2UpO1xuICAgICAgdGhpcy5vbkNoYW5nZShudWxsKTtcblxuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHRoaXMuX3VwZGF0ZVRpbWUoKTtcbiAgfVxuXG4gIGlzVmFsaWRMaW1pdCgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gaXNJbnB1dExpbWl0VmFsaWQoe1xuICAgICAgaG91cjogdGhpcy5ob3VycyxcbiAgICAgIG1pbnV0ZTogdGhpcy5taW51dGVzLFxuICAgICAgc2Vjb25kczogdGhpcy5zZWNvbmRzLFxuICAgICAgaXNQTTogdGhpcy5pc1BNKClcbiAgICB9LCB0aGlzLm1heCwgdGhpcy5taW4pO1xuICB9XG5cbiAgX3VwZGF0ZVRpbWUoKSB7XG4gICAgY29uc3QgX3NlY29uZHMgPSB0aGlzLnNob3dTZWNvbmRzID8gdGhpcy5zZWNvbmRzIDogdm9pZCAwO1xuICAgIGNvbnN0IF9taW51dGVzID0gdGhpcy5zaG93TWludXRlcyA/IHRoaXMubWludXRlcyA6IHZvaWQgMDtcbiAgICBpZiAoIWlzSW5wdXRWYWxpZCh0aGlzLmhvdXJzLCBfbWludXRlcywgX3NlY29uZHMsIHRoaXMuaXNQTSgpKSkge1xuICAgICAgdGhpcy5pc1ZhbGlkLmVtaXQoZmFsc2UpO1xuICAgICAgdGhpcy5vbkNoYW5nZShudWxsKTtcblxuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHRoaXMuX3N0b3JlLmRpc3BhdGNoKFxuICAgICAgdGhpcy5fdGltZXBpY2tlckFjdGlvbnMuc2V0VGltZSh7XG4gICAgICAgIGhvdXI6IHRoaXMuaG91cnMsXG4gICAgICAgIG1pbnV0ZTogdGhpcy5taW51dGVzLFxuICAgICAgICBzZWNvbmRzOiB0aGlzLnNlY29uZHMsXG4gICAgICAgIGlzUE06IHRoaXMuaXNQTSgpXG4gICAgICB9KVxuICAgICk7XG4gIH1cblxuICB0b2dnbGVNZXJpZGlhbigpOiB2b2lkIHtcbiAgICBpZiAoIXRoaXMuc2hvd01lcmlkaWFuIHx8ICF0aGlzLmlzRWRpdGFibGUpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCBfaG91cnNQZXJEYXlIYWxmID0gMTI7XG4gICAgdGhpcy5fc3RvcmUuZGlzcGF0Y2goXG4gICAgICB0aGlzLl90aW1lcGlja2VyQWN0aW9ucy5jaGFuZ2VIb3Vycyh7XG4gICAgICAgIHN0ZXA6IF9ob3Vyc1BlckRheUhhbGYsXG4gICAgICAgIHNvdXJjZTogJydcbiAgICAgIH0pXG4gICAgKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBXcml0ZSBhIG5ldyB2YWx1ZSB0byB0aGUgZWxlbWVudC5cbiAgICovXG4gIHdyaXRlVmFsdWUob2JqOiBzdHJpbmcgfCBudWxsIHwgdW5kZWZpbmVkIHwgRGF0ZSk6IHZvaWQge1xuICAgIGlmIChpc1ZhbGlkRGF0ZShvYmopKSB7XG4gICAgICB0aGlzLl9zdG9yZS5kaXNwYXRjaCh0aGlzLl90aW1lcGlja2VyQWN0aW9ucy53cml0ZVZhbHVlKHBhcnNlVGltZShvYmopKSk7XG4gICAgfSBlbHNlIGlmIChvYmogPT0gbnVsbCkge1xuICAgICAgdGhpcy5fc3RvcmUuZGlzcGF0Y2godGhpcy5fdGltZXBpY2tlckFjdGlvbnMud3JpdGVWYWx1ZShudWxsKSk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFNldCB0aGUgZnVuY3Rpb24gdG8gYmUgY2FsbGVkIHdoZW4gdGhlIGNvbnRyb2wgcmVjZWl2ZXMgYSBjaGFuZ2UgZXZlbnQuXG4gICAqL1xuICAvLyB0c2xpbnQ6ZGlzYWJsZS1uZXh0LWxpbmU6bm8tYW55XG4gIHJlZ2lzdGVyT25DaGFuZ2UoZm46IChfOiBhbnkpID0+IHt9KTogdm9pZCB7XG4gICAgdGhpcy5vbkNoYW5nZSA9IGZuO1xuICB9XG5cbiAgLyoqXG4gICAqIFNldCB0aGUgZnVuY3Rpb24gdG8gYmUgY2FsbGVkIHdoZW4gdGhlIGNvbnRyb2wgcmVjZWl2ZXMgYSB0b3VjaCBldmVudC5cbiAgICovXG4gIHJlZ2lzdGVyT25Ub3VjaGVkKGZuOiAoKSA9PiB7fSk6IHZvaWQge1xuICAgIHRoaXMub25Ub3VjaGVkID0gZm47XG4gIH1cblxuICAvKipcbiAgICogVGhpcyBmdW5jdGlvbiBpcyBjYWxsZWQgd2hlbiB0aGUgY29udHJvbCBzdGF0dXMgY2hhbmdlcyB0byBvciBmcm9tIFwiZGlzYWJsZWRcIi5cbiAgICogRGVwZW5kaW5nIG9uIHRoZSB2YWx1ZSwgaXQgd2lsbCBlbmFibGUgb3IgZGlzYWJsZSB0aGUgYXBwcm9wcmlhdGUgRE9NIGVsZW1lbnQuXG4gICAqXG4gICAqIEBwYXJhbSBpc0Rpc2FibGVkXG4gICAqL1xuICBzZXREaXNhYmxlZFN0YXRlKGlzRGlzYWJsZWQ6IGJvb2xlYW4pOiB2b2lkIHtcbiAgICB0aGlzLmRpc2FibGVkID0gaXNEaXNhYmxlZDtcbiAgfVxuXG4gIG5nT25EZXN0cm95KCk6IHZvaWQge1xuICAgIHRoaXMudGltZXBpY2tlclN1Yi51bnN1YnNjcmliZSgpO1xuICB9XG5cbiAgcHJpdmF0ZSBfcmVuZGVyVGltZSh2YWx1ZTogc3RyaW5nIHwgRGF0ZSk6IHZvaWQge1xuICAgIGlmICghaXNWYWxpZERhdGUodmFsdWUpKSB7XG4gICAgICB0aGlzLmhvdXJzID0gJyc7XG4gICAgICB0aGlzLm1pbnV0ZXMgPSAnJztcbiAgICAgIHRoaXMuc2Vjb25kcyA9ICcnO1xuICAgICAgdGhpcy5tZXJpZGlhbiA9IHRoaXMubWVyaWRpYW5zWzBdO1xuXG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3QgX3ZhbHVlID0gcGFyc2VUaW1lKHZhbHVlKTtcbiAgICBjb25zdCBfaG91cnNQZXJEYXlIYWxmID0gMTI7XG4gICAgbGV0IF9ob3VycyA9IF92YWx1ZS5nZXRIb3VycygpO1xuXG4gICAgaWYgKHRoaXMuc2hvd01lcmlkaWFuKSB7XG4gICAgICB0aGlzLm1lcmlkaWFuID0gdGhpcy5tZXJpZGlhbnNbX2hvdXJzID49IF9ob3Vyc1BlckRheUhhbGYgPyAxIDogMF07XG4gICAgICBfaG91cnMgPSBfaG91cnMgJSBfaG91cnNQZXJEYXlIYWxmO1xuICAgICAgLy8gc2hvdWxkIGJlIDEyIFBNLCBub3QgMDAgUE1cbiAgICAgIGlmIChfaG91cnMgPT09IDApIHtcbiAgICAgICAgX2hvdXJzID0gX2hvdXJzUGVyRGF5SGFsZjtcbiAgICAgIH1cbiAgICB9XG5cbiAgICB0aGlzLmhvdXJzID0gcGFkTnVtYmVyKF9ob3Vycyk7XG4gICAgdGhpcy5taW51dGVzID0gcGFkTnVtYmVyKF92YWx1ZS5nZXRNaW51dGVzKCkpO1xuICAgIHRoaXMuc2Vjb25kcyA9IHBhZE51bWJlcihfdmFsdWUuZ2V0VVRDU2Vjb25kcygpKTtcbiAgfVxufVxuIl19