fundamental-ngx
Version:
SAP Fundamentals, implemented in Angular
695 lines • 53.4 kB
JavaScript
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
import { ChangeDetectorRef, Component, ElementRef, EventEmitter, forwardRef, HostListener, Input, Output, ViewChild, ViewEncapsulation } from '@angular/core';
import { NG_VALIDATORS, NG_VALUE_ACCESSOR } from '@angular/forms';
import { TimeComponent } from '../time/time.component';
import { DateTimeFormatParser } from './format/datetime-parser';
import { CalendarComponent } from '../calendar/calendar.component';
import { FdDatetime } from './models/fd-datetime';
/**
* The datetime picker component is an opinionated composition of the fd-popover,
* fd-calendar and fd-time components to accomplish the UI pattern for picking a date and time.
*/
export class DatetimePickerComponent {
/**
* @hidden
* @param {?} elRef
* @param {?} changeDetRef
* @param {?} dateTimeAdapter
*/
constructor(elRef, changeDetRef, dateTimeAdapter) {
this.elRef = elRef;
this.changeDetRef = changeDetRef;
this.dateTimeAdapter = dateTimeAdapter;
/**
* @hidden Date of the input field. Internal use.
* For programmatic selection, use two-way binding on the date input.
*/
this.inputFieldDate = null;
/**
* @hidden The Time object which interacts with the inner Time component. Internal use.
*/
this.isInvalidDateInput = false;
/**
* @hidden The Time object which interacts with the inner Time component. Internal use.
*/
this.time = { hour: 0, minute: 0, second: 0 };
/**
* Placeholder for the inner input element.
*/
this.placeholder = 'mm/dd/yyyy, hh:mm:ss am';
/**
* Whether the component should be in compact mode.
*/
this.compact = false;
/**
* The placement of the popover. It can be one of: top, top-start, top-end, bottom,
* bottom-start, bottom-end, right, right-start, right-end, left, left-start, left-end.
*/
this.placement = 'bottom-start';
/**
* Whether the time component should be meridian (am/pm).
*/
this.meridian = true;
/**
* Whether the time component shows spinners for changing the time.
*/
this.spinners = true;
/**
* Whether the time component shows seconds.
*/
this.displaySeconds = true;
/**
* Whether to perform visual validation on the picker input.
*/
this.useValidation = true;
/**
* Current selected date. Two-way binding is supported.
*/
this.date = FdDatetime.getToday();
/**
* Whether the popover is open. Two-way binding is supported.
*/
this.isOpen = false;
/**
* The disableFunction for the calendar.
*/
this.startingDayOfWeek = 1;
/**
* Actually shown active view one of 'day' | 'month' | 'year' in calendar component
*/
this.activeView = 'day';
/**
* Aria label for the datetime picker input.
*/
this.datetimeInputLabel = 'Datetime input';
/**
* Aria label for the button to show/hide the calendar.
*/
this.displayDatetimeToggleLabel = 'Display calendar toggle';
/**
* Whether a null input is considered valid.
*/
this.allowNull = true;
/**
* Event thrown every time calendar active view is changed
*/
this.activeViewChange = new EventEmitter();
/**
* Event emitted when the date changes. This can be a time or day change.
*/
this.dateChange = new EventEmitter();
/**
* Event emitted when the day changes from the calendar.
*/
this.calendarChange = new EventEmitter();
/**
* Event emitted when the time changes from the time component.
*/
this.timeChange = new EventEmitter();
/**
* Event emitted when popover closes.
*/
this.onClose = new EventEmitter();
/**
* @hidden
*/
this.onChange = (/**
* @param {?} selected
* @return {?}
*/
(selected) => {
});
/**
* @hidden
*/
this.onTouched = (/**
* @return {?}
*/
() => {
});
/**
* Function used to disable certain dates in the calendar.
* @param fdDate FdDate
*/
this.disableFunction = (/**
* @param {?} fdDate
* @return {?}
*/
function (fdDate) {
return false;
});
/**
* Function used to disable certain dates in the calendar for the range start selection.
* @param fdDate FdDate
*/
this.disableRangeStartFunction = (/**
* @param {?} fdDate
* @return {?}
*/
function (fdDate) {
return false;
});
/**
* Function used to disable certain dates in the calendar for the range end selection.
* @param fdDate FdDate
*/
this.disableRangeEndFunction = (/**
* @param {?} fdDate
* @return {?}
*/
function (fdDate) {
return false;
});
/**
* Function used to block certain dates in the calendar for the range start selection.
* @param fdDate FdDate
*/
this.blockRangeStartFunction = (/**
* @param {?} fdDate
* @return {?}
*/
function (fdDate) {
return false;
});
/**
* Function used to block certain dates in the calendar for the range end selection.
* @param fdDate FdDate
*/
this.blockRangeEndFunction = (/**
* @param {?} fdDate
* @return {?}
*/
function (fdDate) {
return false;
});
/**
* Function used to block certain dates in the calendar.
* @param fdDate FdDate
*/
this.blockFunction = (/**
* @param {?} fdDate
* @return {?}
*/
function (fdDate) {
return false;
});
}
/**
* @hidden
* Function that implements Validator Interface, adds validation support for forms
* @param {?} control
* @return {?}
*/
validate(control) {
return this.isModelValid() ? null : {
dateValidation: {
valid: false
}
};
}
/**
* Toggles the popover.
* @return {?}
*/
togglePopover() {
this.onTouched();
if (this.isOpen) {
this.closePopover();
}
else {
this.openPopover();
}
}
/**
* Method that handle calendar active view change and throws event.
* @param {?} activeView
* @return {?}
*/
handleCalendarActiveViewChange(activeView) {
this.activeViewChange.emit(activeView);
}
/**
* Opens the popover.
* @return {?}
*/
openPopover() {
if (!this.isOpen && !this.disabled) {
this.onTouched();
this.isOpen = true;
}
}
/**
* Closes the popover and refresh model
* @return {?}
*/
closePopover() {
if (this.isOpen) {
this.handleInputChange(this.inputFieldDate);
this.onClose.emit();
this.isOpen = false;
}
}
/**
* @hidden
* @param {?} e
* @return {?}
*/
isInvalidDateInputHandler(e) {
this.isInvalidDateInput = e;
}
/**
* @hidden
* @return {?}
*/
onEscapeKeydownHandler() {
this.closePopover();
}
/**
* @hidden
* @param {?} event
* @return {?}
*/
onGlobalClick(event) {
if (!this.elRef.nativeElement.contains(event.target)) {
this.closePopover();
}
}
/**
* @hidden
* @return {?}
*/
ngOnInit() {
if (this.date && this.inputFieldDate !== null) {
this.selectedDate = this.date.date;
this.time = this.date.time;
}
}
/**
* @hidden
* @return {?}
*/
ngOnDestroy() {
if (this.dateFromInputSubscription) {
this.dateFromInputSubscription.unsubscribe();
}
}
/**
* @hidden
* @param {?} fn
* @return {?}
*/
registerOnChange(fn) {
this.onChange = fn;
}
/**
* @hidden
* @param {?} fn
* @return {?}
*/
registerOnTouched(fn) {
this.onTouched = fn;
}
/**
* @hidden
* @param {?} isDisabled
* @return {?}
*/
setDisabledState(isDisabled) {
this.disabled = isDisabled;
}
/**
* @hidden
* Function that provides support for ControlValueAccessor that allows to use [(ngModel)] or forms
* @param {?} selected
* @return {?}
*/
writeValue(selected) {
if (!selected || !(selected instanceof FdDatetime)) {
return;
}
this.selectedDate = selected.date;
this.time = selected.time;
this.date = new FdDatetime(this.selectedDate, this.time);
if (this.isModelValid()) {
this.calendarComponent.setCurrentlyDisplayed(this.date.date);
this.setInput(this.date);
}
}
/**
* @hidden
* Method that is triggered by events from calendar component, when there is selected date changed.
* If invalid time model is detected, it takes time model data from TimeComponent.
* @param {?} date
* @return {?}
*/
handleDateChange(date) {
this.selectedDate = date;
if (!this.date.isTimeValid()) {
this.time = this.timeComponent.time;
}
this.date = new FdDatetime(this.selectedDate, this.time);
this.isInvalidDateInput = !this.isModelValid();
this.setInput(this.date);
this.onChange(this.date);
}
/**
* @hidden
* Method that is triggered by events from time component, when there is selected time changed
* @param {?} time
* @return {?}
*/
handleTimeChange(time) {
this.time = time;
this.date = new FdDatetime(this.selectedDate, this.time);
this.isInvalidDateInput = !this.isModelValid();
this.setInput(this.date);
this.onChange(this.date);
}
/**
* @hidden
* @return {?}
*/
focusArrowLeft() {
if (this.elRef.nativeElement.querySelector('#' + this.calendarComponent.id + '-left-arrow')) {
this.elRef.nativeElement.querySelector('#' + this.calendarComponent.id + '-left-arrow').focus();
}
}
/**
* @hidden
* Method, which is responsible for transforming string to datetime, depending on type or
* validation the results are different. It also changes to state of isInvalidDateInput.
* @param {?} date
* @return {?}
*/
handleInputChange(date) {
/** @type {?} */
const fdTimeDate = this.dateTimeAdapter.parse(date);
this.selectedDate = fdTimeDate.date;
this.time = fdTimeDate.time;
this.date = new FdDatetime(this.selectedDate, this.time);
this.isInvalidDateInput = !this.isModelValid();
this.onChange(fdTimeDate);
if (!this.isInvalidDateInput) {
this.calendarComponent.setCurrentlyDisplayed(fdTimeDate.date);
}
if (!date && this.allowNull) {
this.isInvalidDateInput = false;
this.date = FdDatetime.getToday();
this.selectedDate = this.date.date;
this.time = this.date.time;
this.calendarComponent.setCurrentlyDisplayed(this.date.date);
this.onChange(null);
}
else if (!this.allowNull) {
this.isInvalidDateInput = true;
}
}
/**
* Method that provides information if model selected date/dates have properly types and are valid
* @return {?}
*/
isModelValid() {
return this.date &&
this.date instanceof FdDatetime &&
this.date.isDateValid() && this.date.isTimeValid();
}
/**
* @private
* @param {?} fdDateTime
* @return {?}
*/
setInput(fdDateTime) {
this.inputFieldDate = this.dateTimeAdapter.format(fdDateTime);
this.changeDetRef.detectChanges();
}
}
DatetimePickerComponent.decorators = [
{ type: Component, args: [{
selector: 'fd-datetime-picker',
template: "<div class=\"fd-datetime\">\n <fd-popover [(isOpen)]=\"isOpen\"\n (isOpenChange)=\"handleInputChange(dateTimePicker.value)\"\n [closeOnOutsideClick]=\"false\"\n [closeOnEscapeKey]=\"false\"\n [triggers]=\"[]\"\n [disabled]=\"disabled\"\n [placement]=\"placement\">\n <fd-popover-control>\n <div class=\"fd-input-group fd-input-group--after\"\n [ngClass]=\"{'fd-input-group--compact' : compact}\">\n <input type=\"text\"\n #dateTimePicker\n [attr.aria-label]=\"datetimeInputLabel\"\n [(ngModel)]=\"inputFieldDate\"\n [placeholder]=\"placeholder\"\n (keyup.enter)=\"handleInputChange(dateTimePicker.value)\"\n (click)=\"openPopover()\"\n [ngClass]=\"{ 'fd-input--compact': compact, 'is-invalid': isInvalidDateInput && useValidation }\"\n [disabled]=\"disabled\">\n <span class=\"fd-input-group__addon fd-input-group__addon--after fd-input-group__addon--button\">\n <button class=\"fd-popover__control fd-button--icon fd-button--light sap-icon--date-time\"\n (click)=\"togglePopover()\" [attr.aria-label]=\"displayDatetimeToggleLabel\"\n [attr.aria-expanded]=\"isOpen\" type=\"button\" [disabled]=\"disabled\"></button>\n </span>\n </div>\n </fd-popover-control>\n <fd-popover-body\n [attr.aria-expanded]=\"isOpen\"\n [attr.aria-hidden]=\"!isOpen\"\n [style.display]=\"'block'\">\n <div class=\"fd-datetime__container\">\n <fd-calendar calType=\"single\"\n [activeView]=\"activeView\"\n (activeViewChange)=\"handleCalendarActiveViewChange($event)\"\n [disableFunction]=\"disableFunction ? disableFunction : null\"\n [blockFunction]=\"blockFunction ? blockFunction : null\"\n [disableRangeStartFunction]=\"disableRangeStartFunction ? disableRangeStartFunction : null\"\n [disableRangeEndFunction]=\"disableRangeEndFunction ? disableRangeEndFunction : null\"\n [blockRangeStartFunction]=\"blockRangeStartFunction ? blockRangeStartFunction : null\"\n [blockRangeEndFunction]=\"blockRangeEndFunction ? blockRangeEndFunction : null\"\n [selectedDate]=\"selectedDate\"\n (selectedDateChange)=\"handleDateChange($event)\"\n (isValidDateChange)=\"isInvalidDateInputHandler($event)\"\n [escapeFocusFunction]=\"null\"\n [startingDayOfWeek]=\"startingDayOfWeek\"></fd-calendar>\n <div class=\"fd-datetime__separator\"></div>\n <fd-time [disabled]=\"disabled\"\n [meridian]=\"meridian\"\n [ngModel]=\"time\"\n (ngModelChange)=\"handleTimeChange($event)\"\n [spinners]=\"spinners\"\n [displaySeconds]=\"displaySeconds\"\n (focusArrowLeft)=\"focusArrowLeft()\"></fd-time>\n </div>\n </fd-popover-body>\n </fd-popover>\n</div>\n",
host: {
'(blur)': 'onTouched()',
'[class.fd-datetime-host]': 'true'
},
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef((/**
* @return {?}
*/
() => DatetimePickerComponent)),
multi: true
},
{
provide: NG_VALIDATORS,
useExisting: forwardRef((/**
* @return {?}
*/
() => DatetimePickerComponent)),
multi: true
}
],
encapsulation: ViewEncapsulation.None,
styles: [".fd-datetime-host{display:inline-block;width:230px}.fd-datetime-host .fd-datetime{display:block}.fd-datetime-host .fd-datetime__container{display:flex;align-items:center;margin:0 16px}.fd-datetime-host .fd-datetime__separator{background-color:#d3d3d3;width:1px;margin:42px 28px;-ms-grid-row-align:stretch;align-self:stretch}.fd-datetime-host .fd-datetime fd-popover{display:block}.fd-datetime-host .fd-datetime fd-time{width:auto}"]
}] }
];
/** @nocollapse */
DatetimePickerComponent.ctorParameters = () => [
{ type: ElementRef },
{ type: ChangeDetectorRef },
{ type: DateTimeFormatParser }
];
DatetimePickerComponent.propDecorators = {
timeComponent: [{ type: ViewChild, args: [TimeComponent,] }],
calendarComponent: [{ type: ViewChild, args: [CalendarComponent,] }],
placeholder: [{ type: Input }],
compact: [{ type: Input }],
placement: [{ type: Input }],
meridian: [{ type: Input }],
disabled: [{ type: Input }],
spinners: [{ type: Input }],
displaySeconds: [{ type: Input }],
useValidation: [{ type: Input }],
date: [{ type: Input }],
isOpen: [{ type: Input }],
startingDayOfWeek: [{ type: Input }],
activeView: [{ type: Input }],
datetimeInputLabel: [{ type: Input }],
displayDatetimeToggleLabel: [{ type: Input }],
allowNull: [{ type: Input }],
activeViewChange: [{ type: Output }],
dateChange: [{ type: Output }],
calendarChange: [{ type: Output }],
timeChange: [{ type: Output }],
onClose: [{ type: Output }],
disableFunction: [{ type: Input }],
disableRangeStartFunction: [{ type: Input }],
disableRangeEndFunction: [{ type: Input }],
blockRangeStartFunction: [{ type: Input }],
blockRangeEndFunction: [{ type: Input }],
blockFunction: [{ type: Input }],
onEscapeKeydownHandler: [{ type: HostListener, args: ['document:keydown.escape', [],] }],
onGlobalClick: [{ type: HostListener, args: ['document:click', ['$event'],] }]
};
if (false) {
/**
* @hidden Reference to the inner time component.
* @type {?}
*/
DatetimePickerComponent.prototype.timeComponent;
/**
* @hidden Reference to the inner calendar component.
* @type {?}
*/
DatetimePickerComponent.prototype.calendarComponent;
/**
* @hidden Date of the input field. Internal use.
* For programmatic selection, use two-way binding on the date input.
* @type {?}
*/
DatetimePickerComponent.prototype.inputFieldDate;
/**
* @hidden The Time object which interacts with the inner Time component. Internal use.
* @type {?}
*/
DatetimePickerComponent.prototype.isInvalidDateInput;
/**
* @hidden The Time object which interacts with the inner Time component. Internal use.
* @type {?}
*/
DatetimePickerComponent.prototype.time;
/**
* @hidden The CalendarDay object which interacts with the inner Calendar component. Internal use.
* @type {?}
*/
DatetimePickerComponent.prototype.selectedDate;
/**
* Subscription of the dateFromInput.
* @type {?}
* @private
*/
DatetimePickerComponent.prototype.dateFromInputSubscription;
/**
* Placeholder for the inner input element.
* @type {?}
*/
DatetimePickerComponent.prototype.placeholder;
/**
* Whether the component should be in compact mode.
* @type {?}
*/
DatetimePickerComponent.prototype.compact;
/**
* The placement of the popover. It can be one of: top, top-start, top-end, bottom,
* bottom-start, bottom-end, right, right-start, right-end, left, left-start, left-end.
* @type {?}
*/
DatetimePickerComponent.prototype.placement;
/**
* Whether the time component should be meridian (am/pm).
* @type {?}
*/
DatetimePickerComponent.prototype.meridian;
/**
* Whether the component is disabled.
* @type {?}
*/
DatetimePickerComponent.prototype.disabled;
/**
* Whether the time component shows spinners for changing the time.
* @type {?}
*/
DatetimePickerComponent.prototype.spinners;
/**
* Whether the time component shows seconds.
* @type {?}
*/
DatetimePickerComponent.prototype.displaySeconds;
/**
* Whether to perform visual validation on the picker input.
* @type {?}
*/
DatetimePickerComponent.prototype.useValidation;
/**
* Current selected date. Two-way binding is supported.
* @type {?}
*/
DatetimePickerComponent.prototype.date;
/**
* Whether the popover is open. Two-way binding is supported.
* @type {?}
*/
DatetimePickerComponent.prototype.isOpen;
/**
* The disableFunction for the calendar.
* @type {?}
*/
DatetimePickerComponent.prototype.startingDayOfWeek;
/**
* Actually shown active view one of 'day' | 'month' | 'year' in calendar component
* @type {?}
*/
DatetimePickerComponent.prototype.activeView;
/**
* Aria label for the datetime picker input.
* @type {?}
*/
DatetimePickerComponent.prototype.datetimeInputLabel;
/**
* Aria label for the button to show/hide the calendar.
* @type {?}
*/
DatetimePickerComponent.prototype.displayDatetimeToggleLabel;
/**
* Whether a null input is considered valid.
* @type {?}
*/
DatetimePickerComponent.prototype.allowNull;
/**
* Event thrown every time calendar active view is changed
* @type {?}
*/
DatetimePickerComponent.prototype.activeViewChange;
/**
* Event emitted when the date changes. This can be a time or day change.
* @type {?}
*/
DatetimePickerComponent.prototype.dateChange;
/**
* Event emitted when the day changes from the calendar.
* @type {?}
*/
DatetimePickerComponent.prototype.calendarChange;
/**
* Event emitted when the time changes from the time component.
* @type {?}
*/
DatetimePickerComponent.prototype.timeChange;
/**
* Event emitted when popover closes.
* @type {?}
*/
DatetimePickerComponent.prototype.onClose;
/**
* @hidden
* @type {?}
*/
DatetimePickerComponent.prototype.onChange;
/**
* @hidden
* @type {?}
*/
DatetimePickerComponent.prototype.onTouched;
/**
* Function used to disable certain dates in the calendar.
* \@param fdDate FdDate
* @type {?}
*/
DatetimePickerComponent.prototype.disableFunction;
/**
* Function used to disable certain dates in the calendar for the range start selection.
* \@param fdDate FdDate
* @type {?}
*/
DatetimePickerComponent.prototype.disableRangeStartFunction;
/**
* Function used to disable certain dates in the calendar for the range end selection.
* \@param fdDate FdDate
* @type {?}
*/
DatetimePickerComponent.prototype.disableRangeEndFunction;
/**
* Function used to block certain dates in the calendar for the range start selection.
* \@param fdDate FdDate
* @type {?}
*/
DatetimePickerComponent.prototype.blockRangeStartFunction;
/**
* Function used to block certain dates in the calendar for the range end selection.
* \@param fdDate FdDate
* @type {?}
*/
DatetimePickerComponent.prototype.blockRangeEndFunction;
/**
* Function used to block certain dates in the calendar.
* \@param fdDate FdDate
* @type {?}
*/
DatetimePickerComponent.prototype.blockFunction;
/**
* @type {?}
* @private
*/
DatetimePickerComponent.prototype.elRef;
/**
* @type {?}
* @private
*/
DatetimePickerComponent.prototype.changeDetRef;
/** @type {?} */
DatetimePickerComponent.prototype.dateTimeAdapter;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGF0ZXRpbWUtcGlja2VyLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiJuZzovL2Z1bmRhbWVudGFsLW5neC8iLCJzb3VyY2VzIjpbImxpYi9kYXRldGltZS1waWNrZXIvZGF0ZXRpbWUtcGlja2VyLmNvbXBvbmVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7O0FBQUEsT0FBTyxFQUNILGlCQUFpQixFQUNqQixTQUFTLEVBQ1QsVUFBVSxFQUNWLFlBQVksRUFDWixVQUFVLEVBQ1YsWUFBWSxFQUNaLEtBQUssRUFHTCxNQUFNLEVBQ04sU0FBUyxFQUNULGlCQUFpQixFQUNwQixNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQXlDLGFBQWEsRUFBRSxpQkFBaUIsRUFBYSxNQUFNLGdCQUFnQixDQUFDO0FBR3BILE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUV2RCxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUVoRSxPQUFPLEVBQUUsaUJBQWlCLEVBQThCLE1BQU0sZ0NBQWdDLENBQUM7QUFDL0YsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLHNCQUFzQixDQUFDOzs7OztBQTRCbEQsTUFBTSxPQUFPLHVCQUF1Qjs7Ozs7OztJQWdRaEMsWUFBb0IsS0FBaUIsRUFDakIsWUFBK0IsRUFDaEMsZUFBcUM7UUFGcEMsVUFBSyxHQUFMLEtBQUssQ0FBWTtRQUNqQixpQkFBWSxHQUFaLFlBQVksQ0FBbUI7UUFDaEMsb0JBQWUsR0FBZixlQUFlLENBQXNCOzs7OztRQXBQeEQsbUJBQWMsR0FBVyxJQUFJLENBQUM7Ozs7UUFHOUIsdUJBQWtCLEdBQVksS0FBSyxDQUFDOzs7O1FBR3BDLFNBQUksR0FBZSxFQUFFLElBQUksRUFBRSxDQUFDLEVBQUUsTUFBTSxFQUFFLENBQUMsRUFBRSxNQUFNLEVBQUUsQ0FBQyxFQUFFLENBQUM7Ozs7UUFVckQsZ0JBQVcsR0FBVyx5QkFBeUIsQ0FBQzs7OztRQUloRCxZ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QzZCOzs7OztJQUc3QixvREFDcUM7Ozs7OztJQU1yQyxpREFBOEI7Ozs7O0lBRzlCLHFEQUFvQzs7Ozs7SUFHcEMsdUNBQXFEOzs7OztJQUdyRCwrQ0FBcUI7Ozs7OztJQUdyQiw0REFBZ0Q7Ozs7O0lBR2hELDhDQUNnRDs7Ozs7SUFHaEQsMENBQ3lCOzs7Ozs7SUFNekIsNENBQ3NDOzs7OztJQUd0QywyQ0FDeUI7Ozs7O0lBR3pCLDJDQUNrQjs7Ozs7SUFHbEIsMkNBQ3lCOzs7OztJQUd6QixpREFDK0I7Ozs7O0lBRy9CLGdEQUM4Qjs7Ozs7SUFHOUIsdUNBQ3lDOzs7OztJQUd6Qyx5Q0FDd0I7Ozs7O0lBR3hCLG9EQUNrQzs7Ozs7SUFHbEMsNkNBQzBDOzs7OztJQUcxQyxxREFDOEM7Ozs7O0lBRzlDLDZEQUMrRDs7Ozs7SUFHL0QsNENBQzBCOzs7OztJQUcxQixtREFDb0c7Ozs7O0lBR3BHLDZDQUMrRTs7Ozs7SUFHL0UsaURBQ21GOzs7OztJQUduRiw2Q0FDK0U7Ozs7O0lBRy9FLDBDQUNnRTs7Ozs7SUFHaEUsMkNBQ0U7Ozs7O0lBR0YsNENBQ0U7Ozs7OztJQU1GLGtEQUdFOzs7Ozs7SUFNRiw0REFHRTs7Ozs7O0lBTUYsMERBR0U7Ozs7OztJQU1GLDBEQUdFOzs7Ozs7SUFNRix3REFHRTs7Ozs7O0lBTUYsZ0RBR0U7Ozs7O0lBcUZVLHdDQUF5Qjs7Ozs7SUFDekIsK0NBQXVDOztJQUN2QyxrREFBNEMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICAgIENoYW5nZURldGVjdG9yUmVmLFxuICAgIENvbXBvbmVudCxcbiAgICBFbGVtZW50UmVmLFxuICAgIEV2ZW50RW1pdHRlcixcbiAgICBmb3J3YXJkUmVmLFxuICAgIEhvc3RMaXN0ZW5lcixcbiAgICBJbnB1dCxcbiAgICBPbkRlc3Ryb3ksXG4gICAgT25Jbml0LFxuICAgIE91dHB1dCxcbiAgICBWaWV3Q2hpbGQsXG4gICAgVmlld0VuY2Fwc3VsYXRpb25cbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBBYnN0cmFjdENvbnRyb2wsIENvbnRyb2xWYWx1ZUFjY2Vzc29yLCBOR19WQUxJREFUT1JTLCBOR19WQUxVRV9BQ0NFU1NPUiwgVmFsaWRhdG9yIH0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xuaW1wb3J0IHsgU3Vic2NyaXB0aW9uIH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyBUaW1lT2JqZWN0IH0gZnJvbSAnLi4vdGltZS90aW1lLW9iamVjdCc7XG5pbXBvcnQgeyBUaW1lQ29tcG9uZW50IH0gZnJvbSAnLi4vdGltZS90aW1lLmNvbXBvbmVudCc7XG5pbXBvcnQgeyBQbGFjZW1lbnQgfSBmcm9tICdwb3BwZXIuanMnO1xuaW1wb3J0IHsgRGF0ZVRpbWVGb3JtYXRQYXJzZXIgfSBmcm9tICcuL2Zvcm1hdC9kYXRldGltZS1wYXJzZXInO1xuaW1wb3J0IHsgRmREYXRlIH0gZnJvbSAnLi4vY2FsZW5kYXIvbW9kZWxzL2ZkLWRhdGUnO1xuaW1wb3J0IHsgQ2FsZW5kYXJDb21wb25lbnQsIERheXNPZldlZWssIEZkQ2FsZW5kYXJWaWV3IH0gZnJvbSAnLi4vY2FsZW5kYXIvY2FsZW5kYXIuY29tcG9uZW50JztcbmltcG9ydCB7IEZkRGF0ZXRpbWUgfSBmcm9tICcuL21vZGVscy9mZC1kYXRldGltZSc7XG5cbi8qKlxuICogVGhlIGRhdGV0aW1lIHBpY2tlciBjb21wb25lbnQgaXMgYW4gb3BpbmlvbmF0ZWQgY29tcG9zaXRpb24gb2YgdGhlIGZkLXBvcG92ZXIsXG4gKiBmZC1jYWxlbmRhciBhbmQgZmQtdGltZSBjb21wb25lbnRzIHRvIGFjY29tcGxpc2ggdGhlIFVJIHBhdHRlcm4gZm9yIHBpY2tpbmcgYSBkYXRlIGFuZCB0aW1lLlxuICovXG5AQ29tcG9uZW50KHtcbiAgICBzZWxlY3RvcjogJ2ZkLWRhdGV0aW1lLXBpY2tlcicsXG4gICAgdGVtcGxhdGVVcmw6ICcuL2RhdGV0aW1lLXBpY2tlci5jb21wb25lbnQuaHRtbCcsXG4gICAgc3R5bGVVcmxzOiBbJy4vZGF0ZXRpbWUtcGlja2VyLmNvbXBvbmVudC5zY3NzJ10sXG4gICAgaG9zdDoge1xuICAgICAgICAnKGJsdXIpJzogJ29uVG91Y2hlZCgpJyxcbiAgICAgICAgJ1tjbGFzcy5mZC1kYXRldGltZS1ob3N0XSc6ICd0cnVlJ1xuICAgIH0sXG4gICAgcHJvdmlkZXJzOiBbXG4gICAgICAgIHtcbiAgICAgICAgICAgIHByb3ZpZGU6IE5HX1ZBTFVFX0FDQ0VTU09SLFxuICAgICAgICAgICAgdXNlRXhpc3Rpbmc6IGZvcndhcmRSZWYoKCkgPT4gRGF0ZXRpbWVQaWNrZXJDb21wb25lbnQpLFxuICAgICAgICAgICAgbXVsdGk6IHRydWVcbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgICAgcHJvdmlkZTogTkdfVkFMSURBVE9SUyxcbiAgICAgICAgICAgIHVzZUV4aXN0aW5nOiBmb3J3YXJkUmVmKCgpID0+IERhdGV0aW1lUGlja2VyQ29tcG9uZW50KSxcbiAgICAgICAgICAgIG11bHRpOiB0cnVlXG4gICAgICAgIH1cbiAgICBdLFxuICAgIGVuY2Fwc3VsYXRpb246IFZpZXdFbmNhcHN1bGF0aW9uLk5vbmVcbn0pXG5leHBvcnQgY2xhc3MgRGF0ZXRpbWVQaWNrZXJDb21wb25lbnQgaW1wbGVtZW50cyBPbkluaXQsIE9uRGVzdHJveSwgQ29udHJvbFZhbHVlQWNjZXNzb3IsIFZhbGlkYXRvciB7XG5cbiAgICAvKiogQGhpZGRlbiBSZWZlcmVuY2UgdG8gdGhlIGlubmVyIHRpbWUgY29tcG9uZW50LiAqL1xuICAgIEBWaWV3Q2hpbGQoVGltZUNvbXBvbmVudClcbiAgICB0aW1lQ29tcG9uZW50OiBUaW1lQ29tcG9uZW50O1xuXG4gICAgLyoqIEBoaWRkZW4gUmVmZXJlbmNlIHRvIHRoZSBpbm5lciBjYWxlbmRhciBjb21wb25lbnQuICovXG4gICAgQFZpZXdDaGlsZChDYWxlbmRhckNvbXBvbmVudClcbiAgICBjYWxlbmRhckNvbXBvbmVudDogQ2FsZW5kYXJDb21wb25lbnQ7XG5cbiAgICAvKipcbiAgICAgKiBAaGlkZGVuIERhdGUgb2YgdGhlIGlucHV0IGZpZWxkLiBJbnRlcm5hbCB1c2UuXG4gICAgICogRm9yIHByb2dyYW1tYXRpYyBzZWxlY3Rpb24sIHVzZSB0d28td2F5IGJpbmRpbmcgb24gdGhlIGRhdGUgaW5wdXQuXG4gICAgICovXG4gICAgaW5wdXRGaWVsZERhdGU6IHN0cmluZyA9IG51bGw7XG5cbiAgICAvKiogQGhpZGRlbiBUaGUgVGltZSBvYmplY3Qgd2hpY2ggaW50ZXJhY3RzIHdpdGggdGhlIGlubmVyIFRpbWUgY29tcG9uZW50LiBJbnRlcm5hbCB1c2UuICovXG4gICAgaXNJbnZhbGlkRGF0ZUlucHV0OiBib29sZWFuID0gZmFsc2U7XG5cbiAgICAvKiogQGhpZGRlbiBUaGUgVGltZSBvYmplY3Qgd2hpY2ggaW50ZXJhY3RzIHdpdGggdGhlIGlubmVyIFRpbWUgY29tcG9uZW50LiBJbnRlcm5hbCB1c2UuICovXG4gICAgdGltZTogVGltZU9iamVjdCA9IHsgaG91cjogMCwgbWludXRlOiAwLCBzZWNvbmQ6IDAgfTtcblxuICAgIC8qKiBAaGlkZGVuIFRoZSBDYWxlbmRhckRheSBvYmplY3Qgd2hpY2ggaW50ZXJhY3RzIHdpdGggdGhlIGlubmVyIENhbGVuZGFyIGNvbXBvbmVudC4gSW50ZXJuYWwgdXNlLiAqL1xuICAgIHNlbGVjdGVkRGF0ZTogRmREYXRlO1xuXG4gICAgLyoqIFN1YnNjcmlwdGlvbiBvZiB0aGUgZGF0ZUZyb21JbnB1dC4gKi9cbiAgICBwcml2YXRlIGRhdGVGcm9tSW5wdXRTdWJzY3JpcHRpb246IFN1YnNjcmlwdGlvbjtcblxuICAgIC8qKiBQbGFjZWhvbGRlciBmb3IgdGhlIGlubmVyIGlucHV0IGVsZW1lbnQuICovXG4gICAgQElucHV0KClcbiAgICBwbGFjZWhvbGRlcjogc3RyaW5nID0gJ21tL2RkL3l5eXksIGhoOm1tOnNzIGFtJztcblxuICAgIC8qKiBXaGV0aGVyIHRoZSBjb21wb25lbnQgc2hvdWxkIGJlIGluIGNvbXBhY3QgbW9kZS4gKi9cbiAgICBASW5wdXQoKVxuICAgIGNvbXBhY3Q6IGJvb2xlYW4gPSBmYWxzZTtcblxuICAgIC8qKlxuICAgICAqICBUaGUgcGxhY2VtZW50IG9mIHRoZSBwb3BvdmVyLiBJdCBjYW4gYmUgb25lIG9mOiB0b3AsIHRvcC1zdGFydCwgdG9wLWVuZCwgYm90dG9tLFxuICAgICAqICBib3R0b20tc3RhcnQsIGJvdHRvbS1lbmQsIHJpZ2h0LCByaWdodC1zdGFydCwgcmlnaHQtZW5kLCBsZWZ0LCBsZWZ0LXN0YXJ0LCBsZWZ0LWVuZC5cbiAgICAgKi9cbiAgICBASW5wdXQoKVxuICAgIHBsYWNlbWVudDogUGxhY2VtZW50ID0gJ2JvdHRvbS1zdGFydCc7XG5cbiAgICAvKiogV2hldGhlciB0aGUgdGltZSBjb21wb25lbnQgc2hvdWxkIGJlIG1lcmlkaWFuIChhbS9wbSkuICovXG4gICAgQElucHV0KClcbiAgICBtZXJpZGlhbjogYm9vbGVhbiA9IHRydWU7XG5cbiAgICAvKiogV2hldGhlciB0aGUgY29tcG9uZW50IGlzIGRpc2FibGVkLiAqL1xuICAgIEBJbnB1dCgpXG4gICAgZGlzYWJsZWQ6IGJvb2xlYW47XG5cbiAgICAvKiogV2hldGhlciB0aGUgdGltZSBjb21wb25lbnQgc2hvd3Mgc3Bpbm5lcnMgZm9yIGNoYW5naW5nIHRoZSB0aW1lLiAqL1xuICAgIEBJbnB1dCgpXG4gICAgc3Bpbm5lcnM6IGJvb2xlYW4gPSB0cnVlO1xuXG4gICAgLyoqIFdoZXRoZXIgdGhlIHRpbWUgY29tcG9uZW50IHNob3dzIHNlY29uZHMuICovXG4gICAgQElucHV0KClcbiAgICBkaXNwbGF5U2Vjb25kczogYm9vbGVhbiA9IHRydWU7XG5cbiAgICAvKiogV2hldGhlciB0byBwZXJmb3JtIHZpc3VhbCB2YWxpZGF0aW9uIG9uIHRoZSBwaWNrZXIgaW5wdXQuICovXG4gICAgQElucHV0KClcbiAgICB1c2VWYWxpZGF0aW9uOiBib29sZWFuID0gdHJ1ZTtcblxuICAgIC8qKiBDdXJyZW50IHNlbGVjdGVkIGRhdGUuIFR3by13YXkgYmluZGluZyBpcyBzdXBwb3J0ZWQuICovXG4gICAgQElucHV0KClcbiAgICBkYXRlOiBGZERhdGV0aW1lID0gRmREYXRldGltZS5nZXRUb2RheSgpO1xuXG4gICAgLyoqIFdoZXRoZXIgdGhlIHBvcG92ZXIgaXMgb3Blbi4gVHdvLXdheSBiaW5kaW5nIGlzIHN1cHBvcnRlZC4gKi9cbiAgICBASW5wdXQoKVxuICAgIGlzT3BlbjogYm9vbGVhbiA9IGZhbHNlO1xuXG4gICAgLyoqIFRoZSBkaXNhYmxlRnVuY3Rpb24gZm9yIHRoZSBjYWxlbmRhci4gKi9cbiAgICBASW5wdXQoKVxuICAgIHN0YXJ0aW5nRGF5T2ZXZWVrOiBEYXlzT2ZXZWVrID0gMTtcblxuICAgIC8qKiBBY3R1YWxseSBzaG93biBhY3RpdmUgdmlldyBvbmUgb2YgJ2RheScgfCAnbW9udGgnIHwgJ3llYXInIGluIGNhbGVuZGFyIGNvbXBvbmVudCovXG4gICAgQElucHV0KClcbiAgICBwdWJsaWMgYWN0aXZlVmlldzogRmRDYWxlbmRhclZpZXcgPSAnZGF5JztcblxuICAgIC8qKiBBcmlhIGxhYmVsIGZvciB0aGUgZGF0ZXRpbWUgcGlja2VyIGlucHV0LiAqL1xuICAgIEBJbnB1dCgpXG4gICAgZGF0ZXRpbWVJbnB1dExhYmVsOiBzdHJpbmcgPSAnRGF0ZXRpbWUgaW5wdXQnO1xuXG4gICAgLyoqIEFyaWEgbGFiZWwgZm9yIHRoZSBidXR0b24gdG8gc2hvdy9oaWRlIHRoZSBjYWxlbmRhci4gKi9cbiAgICBASW5wdXQoKVxuICAgIGRpc3BsYXlEYXRldGltZVRvZ2dsZUxhYmVsOiBzdHJpbmcgPSAnRGlzcGxheSBjYWxlbmRhciB0b2dnbGUnO1xuXG4gICAgLyoqIFdoZXRoZXIgYSBudWxsIGlucHV0IGlzIGNvbnNpZGVyZWQgdmFsaWQuICovXG4gICAgQElucHV0KClcbiAgICBhbGxvd051bGw6IGJvb2xlYW4gPSB0cnVlO1xuXG4gICAgLyoqIEV2ZW50IHRocm93biBldmVyeSB0aW1lIGNhbGVuZGFyIGFjdGl2ZSB2aWV3IGlzIGNoYW5nZWQgKi9cbiAgICBAT3V0cHV0KClcbiAgICBwdWJsaWMgcmVhZG9ubHkgYWN0aXZlVmlld0NoYW5nZTogRXZlbnRFbWl0dGVyPEZkQ2FsZW5kYXJWaWV3PiA9IG5ldyBFdmVudEVtaXR0ZXI8RmRDYWxlbmRhclZpZXc+KCk7XG5cbiAgICAvKiogRXZlbnQgZW1pdHRlZCB3aGVuIHRoZSBkYXRlIGNoYW5nZXMuIFRoaXMgY2FuIGJlIGEgdGltZSBvciBkYXkgY2hhbmdlLiAqL1xuICAgIEBPdXRwdXQoKVxuICAgIHJlYWRvbmx5IGRhdGVDaGFuZ2U6IEV2ZW50RW1pdHRlcjxGZERhdGV0aW1lPiA9IG5ldyBFdmVudEVtaXR0ZXI8RmREYXRldGltZT4oKTtcblxuICAgIC8qKiBFdmVudCBlbWl0dGVkIHdoZW4gdGhlIGRheSBjaGFuZ2VzIGZyb20gdGhlIGNhbGVuZGFyLiAqL1xuICAgIEBPdXRwdXQoKVxuICAgIHJlYWRvbmx5IGNhbGVuZGFyQ2hhbmdlOiBFdmVudEVtaXR0ZXI8RmREYXRldGltZT4gPSBuZXcgRXZlbnRFbWl0dGVyPEZkRGF0ZXRpbWU+KCk7XG5cbiAgICAvKiogRXZlbnQgZW1pdHRlZCB3aGVuIHRoZSB0aW1lIGNoYW5nZXMgZnJvbSB0aGUgdGltZSBjb21wb25lbnQuICovXG4gICAgQE91dHB1dCgpXG4gICAgcmVhZG9ubHkgdGltZUNoYW5nZTogRXZlbnRFbWl0dGVyPEZkRGF0ZXRpbWU+ID0gbmV3IEV2ZW50RW1pdHRlcjxGZERhdGV0aW1lPigpO1xuXG4gICAgLyoqIEV2ZW50IGVtaXR0ZWQgd2hlbiBwb3BvdmVyIGNsb3Nlcy4gKi9cbiAgICBAT3V0cHV0KClcbiAgICByZWFkb25seSBvbkNsb3NlOiBFdmVudEVtaXR0ZXI8dm9pZD4gPSBuZXcgRXZlbnRFbWl0dGVyPHZvaWQ+KCk7XG5cbiAgICAvKiogQGhpZGRlbiAqL1xuICAgIG9uQ2hhbmdlOiBhbnkgPSAoc2VsZWN0ZWQ6IGFueSkgPT4ge1xuICAgIH07XG5cbiAgICAvKiogQGhpZGRlbiAqL1xuICAgIG9uVG91Y2hlZDogYW55ID0gKCkgPT4ge1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBGdW5jdGlvbiB1c2VkIHRvIGRpc2FibGUgY2VydGFpbiBkYXRlcyBpbiB0aGUgY2FsZW5kYXIuXG4gICAgICogQHBhcmFtIGZkRGF0ZSBGZERhdGVcbiAgICAgKi9cbiAgICBASW5wdXQoKVxuICAgIGRpc2FibGVGdW5jdGlvbiA9IGZ1bmN0aW9uKGZkRGF0ZTogRmREYXRlKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogRnVuY3Rpb24gdXNlZCB0byBkaXNhYmxlIGNlcnRhaW4gZGF0ZXMgaW4gdGhlIGNhbGVuZGFyIGZvciB0aGUgcmFuZ2Ugc3RhcnQgc2VsZWN0aW9uLlxuICAgICAqIEBwYXJhbSBmZERhdGUgRmREYXRlXG4gICAgICovXG4gICAgQElucHV0KClcbiAgICBkaXNhYmxlUmFuZ2VTdGFydEZ1bmN0aW9uID0gZnVuY3Rpb24oZmREYXRlOiBGZERhdGUpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBGdW5jdGlvbiB1c2VkIHRvIGRpc2FibGUgY2VydGFpbiBkYXRlcyBpbiB0aGUgY2FsZW5kYXIgZm9yIHRoZSByYW5nZSBlbmQgc2VsZWN0aW9uLlxuICAgICAqIEBwYXJhbSBmZERhdGUgRmREYXRlXG4gICAgICovXG4gICAgQElucHV0KClcbiAgICBkaXNhYmxlUmFuZ2VFbmRGdW5jdGlvbiA9IGZ1bmN0aW9uKGZkRGF0ZTogRmREYXRlKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogRnVuY3Rpb24gdXNlZCB0byBibG9jayBjZXJ0YWluIGRhdGVzIGluIHRoZSBjYWxlbmRhciBmb3IgdGhlIHJhbmdlIHN0YXJ0IHNlbGVjdGlvbi5cbiAgICAgKiBAcGFyYW0gZmREYXRlIEZkRGF0ZVxuICAgICAqL1xuICAgIEBJbnB1dCgpXG4gICAgYmxvY2tSYW5nZVN0YXJ0RnVuY3Rpb24gPSBmdW5jdGlvbihmZERhdGU6IEZkRGF0ZSk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIEZ1bmN0aW9uIHVzZWQgdG8gYmxvY2sgY2VydGFpbiBkYXRlcyBpbiB0aGUgY2FsZW5kYXIgZm9yIHRoZSByYW5nZSBlbmQgc2VsZWN0aW9uLlxuICAgICAqIEBwYXJhbSBmZERhdGUgRmREYXRlXG4gICAgICovXG4gICAgQElucHV0KClcbiAgICBibG9ja1JhbmdlRW5kRnVuY3Rpb24gPSBmdW5jdGlvbihmZERhdGU6IEZkRGF0ZSk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIEZ1bmN0aW9uIHVzZWQgdG8gYmxvY2sgY2VydGFpbiBkYXRlcyBpbiB0aGUgY2FsZW5kYXIuXG4gICAgICogQHBhcmFtIGZkRGF0ZSBGZERhdGVcbiAgICAgKi9cbiAgICBASW5wdXQoKVxuICAgIGJsb2NrRnVuY3Rpb24gPSBmdW5jdGlvbihmZERhdGU6IEZkRGF0ZSk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIEBoaWRkZW5cbiAgICAgKiBGdW5jdGlvbiB0aGF0IGltcGxlbWVudHMgVmFsaWRhdG9yIEludGVyZmFjZSwgYWRkcyB2YWxpZGF0aW9uIHN1cHBvcnQgZm9yIGZvcm1zXG4gICAgICovXG4gICAgdmFsaWRhdGUoY29udHJvbDogQWJzdHJhY3RDb250cm9sKToge1xuICAgICAgICBba2V5OiBzdHJpbmddOiBhbnlcbiAgICB9IHtcbiAgICAgICAgcmV0dXJuIHRoaXMuaXNNb2RlbFZhbGlkKCkgPyBudWxsIDoge1xuICAgICAgICAgICAgZGF0ZVZhbGlkYXRpb246IHtcbiAgICAgICAgICAgICAgICB2YWxpZDogZmFsc2VcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICAvKiogVG9nZ2xlcyB0aGUgcG9wb3Zlci4gKi9cbiAgICB0b2dnbGVQb3BvdmVyKCk6IHZvaWQge1xuICAgICAgICB0aGlzLm9uVG91Y2hlZCgpO1xuICAgICAgICBpZiAodGhpcy5pc09wZW4pIHtcbiAgICAgICAgICAgIHRoaXMuY2xvc2VQb3BvdmVyKCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLm9wZW5Qb3BvdmVyKCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBNZXRob2QgdGhhdCBoYW5kbGUgY2FsZW5kYXIgYWN0aXZlIHZpZXcgY2hhbmdlIGFuZCB0aHJvd3MgZXZlbnQuXG4gICAgICovXG4gICAgcHVibGljIGhhbmRsZUNhbGVuZGFyQWN0aXZlVmlld0NoYW5nZShhY3RpdmVWaWV3OiBGZENhbGVuZGFyVmlldyk6IHZvaWQge1xuICAgICAgICB0aGlzLmFjdGl2ZVZpZXdDaGFuZ2UuZW1pdChhY3RpdmVWaWV3KTtcbiAgICB9XG5cbiAgICAvKiogT3BlbnMgdGhlIHBvcG92ZXIuICovXG4gICAgb3BlblBvcG92ZXIoKTogdm9pZCB7XG4gICAgICAgIGlmICghdGhpcy5pc09wZW4gJiYgIXRoaXMuZGlzYWJsZWQpIHtcbiAgICAgICAgICAgIHRoaXMub25Ub3VjaGVkKCk7XG4gICAgICAgICAgICB0aGlzLmlzT3BlbiA9IHRydWU7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKiogQ2xvc2VzIHRoZSBwb3BvdmVyIGFuZCByZWZyZXNoIG1vZGVsICovXG4gICAgY2xvc2VQb3BvdmVyKCk6IHZvaWQge1xuICAgICAgICBpZiAodGhpcy5pc09wZW4pIHtcbiAgICAgICAgICAgIHRoaXMuaGFuZGxlSW5wdXRDaGFuZ2UodGhpcy5pbnB1dEZpZWxkRGF0ZSk7XG4gICAgICAgICAgICB0aGlzLm9uQ2xvc2UuZW1pdCgpO1xuICAgICAgICAgICAgdGhpcy5pc09wZW4gPSBmYWxzZTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKiBAaGlkZGVuICovXG4gICAgaXNJbnZhbGlkRGF0ZUlucHV0SGFuZGxlcihlKTogdm9pZCB7XG4gICAgICAgIHRoaXMuaXNJbnZhbGlkRGF0ZUlucHV0ID0gZTtcbiAgICB9XG5cbiAgICAvKiogQGhpZGRlbiAqL1xuICAgIEBIb3N0TGlzdGVuZXIoJ2RvY3VtZW50OmtleWRvd24uZXNjYXBlJywgW10pXG4gICAgb25Fc2NhcGVLZXlkb3duSGFuZGxlcigpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5jbG9zZVBvcG92ZXIoKTtcbiAgICB9XG5cbiAgICAvKiogQGhpZGRlbiAqL1xuICAgIEBIb3N0TGlzdGVuZXIoJ2RvY3VtZW50OmNsaWNrJywgWyckZXZlbnQnXSlcbiAgICBwdWJsaWMgb25HbG9iYWxDbGljayhldmVudDogTW91c2VFdmVudCk6IHZvaWQge1xuICAgICAgICBpZiAoIXRoaXMuZWxSZWYubmF0aXZlRWxlbWVudC5jb250YWlucyhldmVudC50YXJnZXQpKSB7XG4gICAgICAgICAgICB0aGlzLmNsb3NlUG9wb3ZlcigpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqIEBoaWRkZW4gKi9cbiAgICBuZ09uSW5pdCgpOiB2b2lkIHtcbiAgICAgICAgaWYgKHRoaXMuZGF0ZSAmJiB0aGlzLmlucHV0RmllbGREYXRlICE9PSBudWxsKSB7XG4gICAgICAgICAgICB0aGlzLnNlbGVjdGVkRGF0ZSA9IHRoaXMuZGF0ZS5kYXRlO1xuICAgICAgICAgICAgdGhpcy50aW1lID0gdGhpcy5kYXRlLnRpbWU7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKiogQGhpZGRlbiAqL1xuICAgIG5nT25EZXN0cm95KCk6IHZvaWQge1xuICAgICAgICBpZiAodGhpcy5kYXRlRnJvbUlucHV0U3Vic2NyaXB0aW9uKSB7XG4gICAgICAgICAgICB0aGlzLmRhdGVGcm9tSW5wdXRTdWJzY3JpcHRpb24udW5zdWJzY3JpYmUoKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKiBAaGlkZGVuICovXG4gICAgY29uc3RydWN0b3IocHJpdmF0ZSBlbFJlZjogRWxlbWVudFJlZixcbiAgICAgICAgICAgICAgICBwcml2YXRlIGNoYW5nZURldFJlZjogQ2hhbmdlRGV0ZWN0b3JSZWYsXG4gICAgICAgICAgICAgICAgcHVibGljIGRhdGVUaW1lQWRhcHRlcjogRGF0ZVRpbWVGb3JtYXRQYXJzZXJcbiAgICApIHtcbiAgICB9XG5cbiAgICAvKiogQGhpZGRlbiAqL1xuICAgIHJlZ2lzdGVyT25DaGFuZ2UoZm46IChzZWxlY3RlZDogYW55KSA9PiB7IHZvaWQgfSk6IHZvaWQge1xuICAgICAgICB0aGlzLm9uQ2hhbmdlID0gZm47XG4gICAgfVxuXG4gICAgLyoqIEBoaWRkZW4gKi9cbiAgICByZWdpc3Rlck9uVG91Y2hlZChmbjogYW55KTogdm9pZCB7XG4gICAgICAgIHRoaXMub25Ub3VjaGVkID0gZm47XG4gICAgfVxuXG4gICAgLyoqIEBoaWRkZW4gKi9cbiAgICBzZXREaXNhYmxlZFN0YXRlKGlzRGlzYWJsZWQ6IGJvb2xlYW4pOiB2b2lkIHtcbiAgICAgICAgdGhpcy5kaXNhYmxlZCA9IGlzRGlzYWJsZWQ7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQGhpZGRlblxuICAgICAqIEZ1bmN0aW9uIHRoYXQgcHJvdmlkZXMgc3VwcG9ydCBmb3IgQ29udHJvbFZhbHVlQWNjZXNzb3IgdGhhdCBhbGxvd3MgdG8gdXNlIFsobmdNb2RlbCldIG9yIGZvcm1zXG4gICAgICovXG4gICAgd3JpdGVWYWx1ZShzZWxlY3RlZDogRmREYXRldGltZSk6IHZvaWQge1xuICAgICAgICBpZiAoIXNlbGVjdGVkIHx8ICEoc2VsZWN0ZWQgaW5zdGFuY2VvZiBGZERhdGV0aW1lKSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuc2VsZWN0ZWREYXRlID0gc2VsZWN0ZWQuZGF0ZTtcbiAgICAgICAgdGhpcy50aW1lID0gc2VsZWN0ZWQudGltZTtcbiAgICAgICAgdGhpcy5kYXRlID0gbmV3IEZkRGF0ZXRpbWUodGhpcy5zZWxlY3RlZERhdGUsIHRoaXMudGltZSk7XG4gICAgICAgIGlmICh0aGlzLmlzTW9kZWxWYWxpZCgpKSB7XG4gICAgICAgICAgICB0aGlzLmNhbGVuZGFyQ29tcG9uZW50LnNldEN1cnJlbnRseURpc3BsYXllZCh0aGlzLmRhdGUuZGF0ZSk7XG4gICAgICAgICAgICB0aGlzLnNldElucHV0KHRoaXMuZGF0ZSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBAaGlkZGVuXG4gICAgICogTWV0aG9kIHRoYXQgaXMgdHJpZ2dlcmVkIGJ5IGV2ZW50cyBmcm9tIGNhbGVuZGFyIGNvbXBvbmVudCwgd2hlbiB0aGVyZSBpcyBzZWxlY3RlZCBkYXRlIGNoYW5nZWQuXG4gICAgICogSWYgaW52YWxpZCB0aW1lIG1vZGVsIGlzIGRldGVjdGVkLCBpdCB0YWtlcyB0aW1lIG1vZGVsIGRhdGEgZnJvbSBUaW1lQ29tcG9uZW50LlxuICAgICAqL1xuICAgIGhhbmRsZURhdGVDaGFuZ2UoZGF0ZTogRmREYXRlKTogdm9pZCB7XG4gICAgICAgIHRoaXMuc2VsZWN0ZWREYXRlID0gZGF0ZTtcbiAgICAgICAgaWYgKCF0aGlzLmRhdGUuaXNUaW1lVmFsaWQoKSkge1xuICAgICAgICAgICAgdGh