UNPKG

fundamental-ngx

Version:

SAP Fundamentals, implemented in Angular

657 lines 56.4 kB
/** * @fileoverview added by tsickle * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ import { ChangeDetectorRef, Component, EventEmitter, forwardRef, HostBinding, Input, Output, ViewChild, ViewEncapsulation } from '@angular/core'; import { CalendarI18n } from './i18n/calendar-i18n'; import { FdDate } from './models/fd-date'; import { NG_VALIDATORS, NG_VALUE_ACCESSOR } from '@angular/forms'; import { CalendarDayViewComponent } from './calendar-views/calendar-day-view/calendar-day-view.component'; import { CalendarYearViewComponent } from './calendar-views/calendar-year-view/calendar-year-view.component'; /** @type {?} */ let calendarUniqueId = 0; /** * Months: 1 = January, 12 = december. * Days: 1 = Sunday, 7 = Saturday * * Calendar component used for selecting dates, typically used by the DatePicker and DateTimePicker components. * Supports the Angular forms module, enabling form validity, ngModel, etc. */ export class CalendarComponent { /** * @hidden * @param {?} calendarI18n * @param {?} changeDetectorRef */ constructor(calendarI18n, changeDetectorRef) { this.calendarI18n = calendarI18n; this.changeDetectorRef = changeDetectorRef; /** * @hidden */ this.fdCalendarClass = true; /** * @hidden */ this.fdHasDisplayBlockClass = true; /** * The currently selected FdDate model in single mode. */ this.selectedDate = FdDate.getToday(); /** * Actually shown active view one of 'day' | 'month' | 'year' */ this.activeView = 'day'; /** * The day of the week the calendar should start on. 0 represents Sunday, 1 is Monday, 2 is Tuesday, and so on. */ this.startingDayOfWeek = 1; /** * The type of calendar, 'single' for single date selection or 'range' for a range of dates. */ this.calType = 'single'; /** * Id of the calendar. If none is provided, one will be generated. */ this.id = 'fd-calendar-' + calendarUniqueId++; /** * Event thrown every time active view is changed */ this.activeViewChange = new EventEmitter(); /** * Event thrown every time selected date in single mode is changed */ this.selectedDateChange = new EventEmitter(); /** * Event thrown every time selected first or last date in range mode is changed */ this.selectedRangeDateChange = new EventEmitter(); /** * Event thrown every time when value is overwritten from outside and throw back isValid */ this.isValidDateChange = new EventEmitter(); /** * Event thrown every time when calendar should be closed */ this.closeCalendar = new EventEmitter(); /** * @hidden */ this.onChange = (/** * @return {?} */ () => { }); /** * @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; }); /** * That allows to define function that should happen, when focus should normally escape of component */ this.escapeFocusFunction = (/** * @return {?} */ () => { if (document.getElementById(this.id + '-left-arrow')) { document.getElementById(this.id + '-left-arrow').focus(); } }); } /** * @hidden * @return {?} */ ngOnInit() { this.prepareDisplayedView(); } /** * @hidden * Function that provides support for ControlValueAccessor that allows to use [(ngModel)] or forms. * @param {?} selected * @return {?} */ writeValue(selected) { /** @type {?} */ let valid = true; if (selected) { if (this.calType === 'single') { selected = (/** @type {?} */ (selected)); valid = selected.isDateValid(); this.selectedDate = selected; if (selected.isDateValid()) { this.prepareDisplayedView(); } } else if (this.calType === 'range') { selected = (/** @type {?} */ (selected)); if (!selected.start || !selected.end) { valid = false; } if (selected.start && !selected.start.isDateValid()) { valid = false; } if (selected.end && !selected.end.isDateValid()) { valid = false; } this.selectedRangeDate = { start: selected.start, end: selected.end }; if (valid) { this.prepareDisplayedView(); } } } this.isValidDateChange.emit(valid); } /** * @hidden * Function that implements Validator Interface, adds validation support for forms * @param {?} control * @return {?} */ validate(control) { return this.isModelValid() ? null : { dateValidation: { valid: false } }; } /** * @hidden * @param {?} fn * @return {?} */ registerOnChange(fn) { this.onChange = fn; } /** * @hidden * @param {?} fn * @return {?} */ registerOnTouched(fn) { this.onTouched = fn; } /** * @hidden * @param {?} isDisabled * @return {?} */ setDisabledState(isDisabled) { // Not needed } /** * Method that handle active view change and throws event. * @param {?} activeView * @return {?} */ handleActiveViewChange(activeView) { this.activeView = activeView; this.activeViewChange.emit(activeView); } /** * @hidden * Method that is triggered by events from day view component, when there is selected single date changed * @param {?} date * @return {?} */ selectedDateChanged(date) { this.selectedDate = date; this.onChange(date); this.onTouched(); this.selectedDateChange.emit(date); this.closeCalendar.emit(); } /** * @hidden * Method that is triggered by events from day view component, when there is selected range date changed * @param {?} dates * @return {?} */ selectedRangeDateChanged(dates) { if (dates) { this.selectedRangeDate = { start: dates.start, end: dates.end ? dates.end : dates.start }; this.selectedRangeDateChange.emit(this.selectedRangeDate); this.onChange(this.selectedRangeDate); this.onTouched(); this.closeCalendar.emit(); } } /** * Function that handles next arrow icon click, depending on current view it changes month, year or list of years * @return {?} */ handleNextArrowClick() { switch (this.activeView) { case 'day': this.displayNextMonth(); break; case 'month': this.displayNextYear(); break; case 'year': this.displayNextYearList(); break; } this.onTouched(); } /** * Function that handles previous arrow icon click, depending on current view it changes month, year or list of years * @return {?} */ handlePreviousArrowClick() { switch (this.activeView) { case 'day': this.displayPreviousMonth(); break; case 'month': this.displayPreviousYear(); break; case 'year': this.displayPreviousYearList(); break; } this.onTouched(); } /** * Function that allows to switch actual view to next month * @return {?} */ displayNextMonth() { if (this.currentlyDisplayed.month === 12) { this.currentlyDisplayed = { year: this.currentlyDisplayed.year + 1, month: 1 }; } else { this.currentlyDisplayed = { year: this.currentlyDisplayed.year, month: this.currentlyDisplayed.month + 1 }; } } /** * Function that allows to switch actual view to previous month * @return {?} */ displayPreviousMonth() { if (this.currentlyDisplayed.month <= 1) { this.currentlyDisplayed = { year: this.currentlyDisplayed.year - 1, month: 12 }; } else { this.currentlyDisplayed = { year: this.currentlyDisplayed.year, month: this.currentlyDisplayed.month - 1 }; } } /** * Function that allows to switch actual view to next year * @return {?} */ displayNextYear() { this.currentlyDisplayed = { month: this.currentlyDisplayed.month, year: this.currentlyDisplayed.year + 1 }; } /** * Function that allows to switch actual view to previous year * @return {?} */ displayPreviousYear() { this.currentlyDisplayed = { month: this.currentlyDisplayed.month, year: this.currentlyDisplayed.year - 1 }; } /** * Function that allows to switch actually displayed list of year to next year list * @return {?} */ displayNextYearList() { this.yearViewComponent.loadNextYearList(); } /** * Function that allows to switch actually displayed list of year to previous year list * @return {?} */ displayPreviousYearList() { this.yearViewComponent.loadPreviousYearList(); } /** * Function that allows to change currently displayed month/year configuration, * which are connected to days displayed * @param {?} fdDate * @return {?} */ setCurrentlyDisplayed(fdDate) { this.currentlyDisplayed = { month: fdDate.month, year: fdDate.year }; } /** * @hidden * Function that handles changes from month view child component, changes actual view and changes currently displayed month * @param {?} month * @return {?} */ handleMonthViewChange(month) { this.currentlyDisplayed = { month: month, year: this.currentlyDisplayed.year }; this.activeView = 'day'; this.activeViewChange.emit(this.activeView); this.changeDetectorRef.detectChanges(); this.dayViewComponent.focusActiveDay(); } /** * @param {?} yearSelected * @return {?} */ selectedYear(yearSelected) { this.activeView = 'day'; this.currentlyDisplayed.year = yearSelected; this.changeDetectorRef.detectChanges(); this.dayViewComponent.focusActiveDay(); } /** * Method that provides information if model selected date/dates have properly types and are valid * @return {?} */ isModelValid() { if (this.calType === 'single') { return this.selectedDate && this.selectedDate instanceof FdDate && this.selectedDate.isDateValid(); } else { return this.selectedRangeDate && (this.selectedRangeDate.start && this.selectedRangeDate.start instanceof FdDate && this.selectedRangeDate.start.isDateValid()) && (this.selectedRangeDate.end && this.selectedRangeDate.end instanceof FdDate && this.selectedRangeDate.start.isDateValid()); } } /** * @hidden * Method that sets up the currently displayed variables, like shown month and year. * Day grid is based on currently displayed month and year * @private * @return {?} */ prepareDisplayedView() { if (this.calType === 'single' && this.selectedDate && this.selectedDate.month && this.selectedDate.year) { this.currentlyDisplayed = { month: this.selectedDate.month, year: this.selectedDate.year }; } else if (this.selectedRangeDate && this.selectedRangeDate.start) { this.currentlyDisplayed = { month: this.selectedRangeDate.start.month, year: this.selectedRangeDate.start.year }; } else if (this.selectedRangeDate && this.selectedRangeDate.end) { this.currentlyDisplayed = { month: this.selectedRangeDate.end.month, year: this.selectedRangeDate.end.year }; } else { /** @type {?} */ const tempDate = FdDate.getToday(); this.currentlyDisplayed = { month: tempDate.month, year: tempDate.year }; } } } CalendarComponent.decorators = [ { type: Component, args: [{ selector: 'fd-calendar', template: "<fd-calendar-header [currentlyDisplayed]=\"currentlyDisplayed\"\n [activeView]=\"activeView\"\n (activeViewChange)=\"handleActiveViewChange($event)\"\n [id]=\"id\"\n (nextClicked)=\"handleNextArrowClick()\"\n (previousClicked)=\"handlePreviousArrowClick()\"\n></fd-calendar-header>\n<ng-container [ngSwitch]=\"activeView\">\n <div class=\"fd-calendar__content\">\n <fd-calendar-day-view *ngSwitchCase=\"'day'\"\n [selectedDate]=\"selectedDate\"\n (selectedDateChange)=\"selectedDateChanged($event)\"\n [selectedRangeDate]=\"selectedRangeDate\"\n (selectedRangeDateChange)=\"selectedRangeDateChanged($event)\"\n [currentlyDisplayed]=\"currentlyDisplayed\"\n [startingDayOfWeek]=\"startingDayOfWeek\"\n [blockFunction]=\"blockFunction\"\n [disableFunction]=\"disableFunction\"\n [disableRangeEndFunction]=\"disableRangeEndFunction\"\n [blockRangeEndFunction]=\"blockRangeEndFunction\"\n [disableRangeStartFunction]=\"disableRangeStartFunction\"\n [blockRangeStartFunction]=\"blockRangeStartFunction\"\n [calType]=\"calType\"\n [id]=\"id\"\n [focusEscapeFunction]=\"escapeFocusFunction\"\n (nextMonthSelect)=\"displayNextMonth()\"\n (previousMonthSelect)=\"displayPreviousMonth()\"\n ></fd-calendar-day-view>\n <fd-calendar-month-view *ngSwitchCase=\"'month'\"\n [monthSelected]=\"currentlyDisplayed?.month\"\n [id]=\"id\"\n [focusEscapeFunction]=\"escapeFocusFunction\"\n (monthClicked)=\"handleMonthViewChange($event)\"\n ></fd-calendar-month-view>\n <fd-calendar-year-view *ngSwitchCase=\"'year'\"\n (yearClicked)=\"selectedYear($event)\"\n [yearSelected]=\"currentlyDisplayed.year\"\n [id]=\"id\"\n [focusEscapeFunction]=\"escapeFocusFunction\">\n </fd-calendar-year-view>\n </div>\n</ng-container>\n\n", encapsulation: ViewEncapsulation.None, providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef((/** * @return {?} */ () => CalendarComponent)), multi: true }, { provide: NG_VALIDATORS, useExisting: forwardRef((/** * @return {?} */ () => CalendarComponent)), multi: true } ], host: { '(blur)': 'onTouched()', '[attr.id]': 'id' }, styles: [".fd-calendar__content{min-height:276px;background:#fff}.fd-calendar__content li:focus,.fd-calendar__content td:focus{outline:0;box-shadow:inset 0 0 2px 2px var(--fd-color-neutral-3)}.fd-calendar__content li:focus:after,.fd-calendar__content td:focus:after{display:none}"] }] } ]; /** @nocollapse */ CalendarComponent.ctorParameters = () => [ { type: CalendarI18n }, { type: ChangeDetectorRef } ]; CalendarComponent.propDecorators = { dayViewComponent: [{ type: ViewChild, args: [CalendarDayViewComponent,] }], yearViewComponent: [{ type: ViewChild, args: [CalendarYearViewComponent,] }], fdCalendarClass: [{ type: HostBinding, args: ['class.fd-calendar',] }], fdHasDisplayBlockClass: [{ type: HostBinding, args: ['class.fd-has-display-block',] }], selectedDate: [{ type: Input }], selectedRangeDate: [{ type: Input }], activeView: [{ type: Input }], startingDayOfWeek: [{ type: Input }], calType: [{ type: Input }], id: [{ type: Input }], activeViewChange: [{ type: Output }], selectedDateChange: [{ type: Output }], selectedRangeDateChange: [{ type: Output }], isValidDateChange: [{ type: Output }], closeCalendar: [{ type: Output }], disableFunction: [{ type: Input }], disableRangeStartFunction: [{ type: Input }], disableRangeEndFunction: [{ type: Input }], blockRangeStartFunction: [{ type: Input }], blockRangeEndFunction: [{ type: Input }], blockFunction: [{ type: Input }], escapeFocusFunction: [{ type: Input }] }; if (false) { /** * @hidden * @type {?} */ CalendarComponent.prototype.dayViewComponent; /** * @hidden * @type {?} */ CalendarComponent.prototype.yearViewComponent; /** * @hidden * @type {?} */ CalendarComponent.prototype.fdCalendarClass; /** * @hidden * @type {?} */ CalendarComponent.prototype.fdHasDisplayBlockClass; /** * Currently displayed days depending on month and year * @type {?} */ CalendarComponent.prototype.currentlyDisplayed; /** * The currently selected FdDate model in single mode. * @type {?} */ CalendarComponent.prototype.selectedDate; /** * The currently selected FdDates model start and end in range mode. * @type {?} */ CalendarComponent.prototype.selectedRangeDate; /** * Actually shown active view one of 'day' | 'month' | 'year' * @type {?} */ CalendarComponent.prototype.activeView; /** * The day of the week the calendar should start on. 0 represents Sunday, 1 is Monday, 2 is Tuesday, and so on. * @type {?} */ CalendarComponent.prototype.startingDayOfWeek; /** * The type of calendar, 'single' for single date selection or 'range' for a range of dates. * @type {?} */ CalendarComponent.prototype.calType; /** * Id of the calendar. If none is provided, one will be generated. * @type {?} */ CalendarComponent.prototype.id; /** * Event thrown every time active view is changed * @type {?} */ CalendarComponent.prototype.activeViewChange; /** * Event thrown every time selected date in single mode is changed * @type {?} */ CalendarComponent.prototype.selectedDateChange; /** * Event thrown every time selected first or last date in range mode is changed * @type {?} */ CalendarComponent.prototype.selectedRangeDateChange; /** * Event thrown every time when value is overwritten from outside and throw back isValid * @type {?} */ CalendarComponent.prototype.isValidDateChange; /** * Event thrown every time when calendar should be closed * @type {?} */ CalendarComponent.prototype.closeCalendar; /** * @hidden * @type {?} */ CalendarComponent.prototype.onChange; /** * @hidden * @type {?} */ CalendarComponent.prototype.onTouched; /** * Function used to disable certain dates in the calendar. * \@param fdDate FdDate * @type {?} */ CalendarComponent.prototype.disableFunction; /** * Function used to disable certain dates in the calendar for the range start selection. * \@param fdDate FdDate * @type {?} */ CalendarComponent.prototype.disableRangeStartFunction; /** * Function used to disable certain dates in the calendar for the range end selection. * \@param fdDate FdDate * @type {?} */ CalendarComponent.prototype.disableRangeEndFunction; /** * Function used to block certain dates in the calendar for the range start selection. * \@param fdDate FdDate * @type {?} */ CalendarComponent.prototype.blockRangeStartFunction; /** * Function used to block certain dates in the calendar for the range end selection. * \@param fdDate FdDate * @type {?} */ CalendarComponent.prototype.blockRangeEndFunction; /** * Function used to block certain dates in the calendar. * \@param fdDate FdDate * @type {?} */ CalendarComponent.prototype.blockFunction; /** * That allows to define function that should happen, when focus should normally escape of component * @type {?} */ CalendarComponent.prototype.escapeFocusFunction; /** @type {?} */ CalendarComponent.prototype.calendarI18n; /** * @type {?} * @private */ CalendarComponent.prototype.changeDetectorRef; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2FsZW5kYXIuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6Im5nOi8vZnVuZGFtZW50YWwtbmd4LyIsInNvdXJjZXMiOlsibGliL2NhbGVuZGFyL2NhbGVuZGFyLmNvbXBvbmVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7O0FBQUEsT0FBTyxFQUNILGlCQUFpQixFQUNqQixTQUFTLEVBQ1QsWUFBWSxFQUNaLFVBQVUsRUFDVixXQUFXLEVBQ1gsS0FBSyxFQUVMLE1BQU0sRUFDTixTQUFTLEVBQ1QsaUJBQWlCLEVBQ3BCLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUNwRCxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFFMUMsT0FBTyxFQUF5QyxhQUFhLEVBQUUsaUJBQWlCLEVBQWEsTUFBTSxnQkFBZ0IsQ0FBQztBQUNwSCxPQUFPLEVBQUUsd0JBQXdCLEVBQUUsTUFBTSxnRUFBZ0UsQ0FBQztBQUUxRyxPQUFPLEVBQUUseUJBQXlCLEVBQUUsTUFBTSxrRUFBa0UsQ0FBQzs7SUFFekcsZ0JBQWdCLEdBQVcsQ0FBQzs7Ozs7Ozs7QUF3Q2hDLE1BQU0sT0FBTyxpQkFBaUI7Ozs7OztJQXNJMUIsWUFDVyxZQUEwQixFQUN6QixpQkFBb0M7UUFEckMsaUJBQVksR0FBWixZQUFZLENBQWM7UUFDekIsc0JBQWlCLEdBQWpCLGlCQUFpQixDQUFtQjs7OztRQTlIaEQsb0JBQWUsR0FBWSxJQUFJLENBQUM7Ozs7UUFJaEMsMkJBQXNCLEdBQVksSUFBSSxDQUFDOzs7O1FBT2hDLGlCQUFZLEdBQVcsTUFBTSxDQUFDLFFBQVEsRUFBRSxDQUFDOzs7O1FBUXpDLGVBQVUsR0FBbUIsS0FBSyxDQUFDOzs7O1FBSW5DLHNCQUFpQixHQUFlLENBQUMsQ0FBQzs7OztRQUlsQyxZQUFPLEdBQWlCLFFBQVEsQ0FBQzs7OztRQUl4QyxPQUFFLEdBQUcsY0FBYyxHQUFHLGdCQUFnQixF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QUMsd0JBQXdCO2dDQUdsQyxTQUFTLFNBQUMseUJBQXlCOzhCQUduQyxXQUFXLFNBQUMsbUJBQW1CO3FDQUkvQixXQUFXLFNBQUMsNEJBQTRCOzJCQU94QyxLQUFLO2dDQUlMLEtBQUs7eUJBSUwsS0FBSztnQ0FJTCxLQUFLO3NCQUlMLEtBQUs7aUJBSUwsS0FBSzsrQkFJTCxNQUFNO2lDQUlOLE1BQU07c0NBSU4sTUFBTTtnQ0FJTixNQUFNOzRCQUlOLE1BQU07OEJBZU4sS0FBSzt3Q0FTTCxLQUFLO3NDQVNMLEtBQUs7c0NBU0wsS0FBSztvQ0FTTCxLQUFLOzRCQVNMLEtBQUs7a0NBTUwsS0FBSzs7Ozs7OztJQTNITiw2Q0FBZ0Y7Ozs7O0lBR2hGLDhDQUFtRjs7Ozs7SUFHbkYsNENBQ2dDOzs7OztJQUdoQyxtREFDdUM7Ozs7O0lBR3ZDLCtDQUFvQzs7Ozs7SUFHcEMseUNBQ2dEOzs7OztJQUdoRCw4Q0FDc0M7Ozs7O0lBR3RDLHVDQUMwQzs7Ozs7SUFHMUMsOENBQ3lDOzs7OztJQUd6QyxvQ0FDd0M7Ozs7O0lBR3hDLCtCQUN5Qzs7Ozs7SUFHekMsNkNBQ29HOzs7OztJQUdwRywrQ0FDc0Y7Ozs7O0lBR3RGLG9EQUNxRzs7Ozs7SUFHckcsOENBQ3VGOzs7OztJQUd2RiwwQ0FDNkU7Ozs7O0lBRzdFLHFDQUNFOzs7OztJQUdGLHNDQUNFOzs7Ozs7SUFNRiw0Q0FHRTs7Ozs7O0lBTUYsc0RBR0U7Ozs7OztJQU1GLG9EQUdFOzs7Ozs7SUFNRixvREFHRTs7Ozs7O0lBTUYsa0RBR0U7Ozs7OztJQU1GLDBDQUdFOzs7OztJQUdGLGdEQUtFOztJQUlFLHlDQUFpQzs7Ozs7SUFDakMsOENBQTRDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgICBDaGFuZ2VEZXRlY3RvclJlZixcbiAgICBDb21wb25lbnQsXG4gICAgRXZlbnRFbWl0dGVyLFxuICAgIGZvcndhcmRSZWYsXG4gICAgSG9zdEJpbmRpbmcsXG4gICAgSW5wdXQsXG4gICAgT25Jbml0LFxuICAgIE91dHB1dCxcbiAgICBWaWV3Q2hpbGQsXG4gICAgVmlld0VuY2Fwc3VsYXRpb25cbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBDYWxlbmRhckkxOG4gfSBmcm9tICcuL2kxOG4vY2FsZW5kYXItaTE4bic7XG5pbXBvcnQgeyBGZERhdGUgfSBmcm9tICcuL21vZGVscy9mZC1kYXRlJztcbmltcG9ydCB7IENhbGVuZGFyQ3VycmVudCB9IGZyb20gJy4vbW9kZWxzL2NhbGVuZGFyLWN1cnJlbnQnO1xuaW1wb3J0IHsgQWJzdHJhY3RDb250cm9sLCBDb250cm9sVmFsdWVBY2Nlc3NvciwgTkdfVkFMSURBVE9SUywgTkdfVkFMVUVfQUNDRVNTT1IsIFZhbGlkYXRvciB9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcbmltcG9ydCB7IENhbGVuZGFyRGF5Vmlld0NvbXBvbmVudCB9IGZyb20gJy4vY2FsZW5kYXItdmlld3MvY2FsZW5kYXItZGF5LXZpZXcvY2FsZW5kYXItZGF5LXZpZXcuY29tcG9uZW50JztcbmltcG9ydCB7IEZkUmFuZ2VEYXRlIH0gZnJvbSAnLi9tb2RlbHMvZmQtcmFuZ2UtZGF0ZSc7XG5pbXBvcnQgeyBDYWxlbmRhclllYXJWaWV3Q29tcG9uZW50IH0gZnJvbSAnLi9jYWxlbmRhci12aWV3cy9jYWxlbmRhci15ZWFyLXZpZXcvY2FsZW5kYXIteWVhci12aWV3LmNvbXBvbmVudCc7XG5cbmxldCBjYWxlbmRhclVuaXF1ZUlkOiBudW1iZXIgPSAwO1xuXG4vKiogVHlwZSBvZiBjYWxlbmRhciAqL1xuZXhwb3J0IHR5cGUgQ2FsZW5kYXJUeXBlID0gJ3NpbmdsZScgfCAncmFuZ2UnO1xuXG4vKiogVHlwZSBmb3IgdGhlIGNhbGVuZGFyIHZpZXcgKi9cbmV4cG9ydCB0eXBlIEZkQ2FsZW5kYXJWaWV3ID0gJ2RheScgfCAnbW9udGgnIHwgJ3llYXInO1xuXG4vKiogVHlwZSBmb3IgdGhlIGRheXMgb2YgdGhlIHdlZWsuICovXG5leHBvcnQgdHlwZSBEYXlzT2ZXZWVrID0gMSB8IDIgfCAzIHwgNCB8IDUgfCA2IHwgNztcblxuLyoqXG4gKiBNb250aHM6IDEgPSBKYW51YXJ5LCAxMiA9IGRlY2VtYmVyLlxuICogRGF5czogMSA9IFN1bmRheSwgNyA9IFNhdHVyZGF5XG4gKlxuICogQ2FsZW5kYXIgY29tcG9uZW50IHVzZWQgZm9yIHNlbGVjdGluZyBkYXRlcywgdHlwaWNhbGx5IHVzZWQgYnkgdGhlIERhdGVQaWNrZXIgYW5kIERhdGVUaW1lUGlja2VyIGNvbXBvbmVudHMuXG4gKiBTdXBwb3J0cyB0aGUgQW5ndWxhciBmb3JtcyBtb2R1bGUsIGVuYWJsaW5nIGZvcm0gdmFsaWRpdHksIG5nTW9kZWwsIGV0Yy5cbiAqL1xuQENvbXBvbmVudCh7XG4gICAgc2VsZWN0b3I6ICdmZC1jYWxlbmRhcicsXG4gICAgdGVtcGxhdGVVcmw6ICcuL2NhbGVuZGFyLmNvbXBvbmVudC5odG1sJyxcbiAgICBzdHlsZVVybHM6IFsnLi9jYWxlbmRhci5jb21wb25lbnQuc2NzcyddLFxuICAgIGVuY2Fwc3VsYXRpb246IFZpZXdFbmNhcHN1bGF0aW9uLk5vbmUsXG4gICAgcHJvdmlkZXJzOiBbXG4gICAgICAgIHtcbiAgICAgICAgICAgIHByb3ZpZGU6IE5HX1ZBTFVFX0FDQ0VTU09SLFxuICAgICAgICAgICAgdXNlRXhpc3Rpbmc6IGZvcndhcmRSZWYoKCkgPT4gQ2FsZW5kYXJDb21wb25lbnQpLFxuICAgICAgICAgICAgbXVsdGk6IHRydWVcbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgICAgcHJvdmlkZTogTkdfVkFMSURBVE9SUyxcbiAgICAgICAgICAgIHVzZUV4aXN0aW5nOiBmb3J3YXJkUmVmKCgpID0+IENhbGVuZGFyQ29tcG9uZW50KSxcbiAgICAgICAgICAgIG11bHRpOiB0cnVlXG4gICAgICAgIH1cbiAgICBdLFxuICAgIGhvc3Q6IHtcbiAgICAgICAgJyhibHVyKSc6ICdvblRvdWNoZWQoKScsXG4gICAgICAgICdbYXR0ci5pZF0nOiAnaWQnXG4gICAgfVxufSlcbmV4cG9ydCBjbGFzcyBDYWxlbmRhckNvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCwgQ29udHJvbFZhbHVlQWNjZXNzb3IsIFZhbGlkYXRvciB7XG5cbiAgICAvKiogQGhpZGRlbiAqL1xuICAgIEBWaWV3Q2hpbGQoQ2FsZW5kYXJEYXlWaWV3Q29tcG9uZW50KSBkYXlWaWV3Q29tcG9uZW50OiBDYWxlbmRhckRheVZpZXdDb21wb25lbnQ7XG5cbiAgICAvKiogQGhpZGRlbiAqL1xuICAgIEBWaWV3Q2hpbGQoQ2FsZW5kYXJZZWFyVmlld0NvbXBvbmVudCkgeWVhclZpZXdDb21wb25lbnQ6IENhbGVuZGFyWWVhclZpZXdDb21wb25lbnQ7XG5cbiAgICAvKiogQGhpZGRlbiAqL1xuICAgIEBIb3N0QmluZGluZygnY2xhc3MuZmQtY2FsZW5kYXInKVxuICAgIGZkQ2FsZW5kYXJDbGFzczogYm9vbGVhbiA9IHRydWU7XG5cbiAgICAvKiogQGhpZGRlbiAqL1xuICAgIEBIb3N0QmluZGluZygnY2xhc3MuZmQtaGFzLWRpc3BsYXktYmxvY2snKVxuICAgIGZkSGFzRGlzcGxheUJsb2NrQ2xhc3M6IGJvb2xlYW4gPSB0cnVlO1xuXG4gICAgLyoqIEN1cnJlbnRseSBkaXNwbGF5ZWQgZGF5cyBkZXBlbmRpbmcgb24gbW9udGggYW5kIHllYXIgKi9cbiAgICBjdXJyZW50bHlEaXNwbGF5ZWQ6IENhbGVuZGFyQ3VycmVudDtcblxuICAgIC8qKiBUaGUgY3VycmVudGx5IHNlbGVjdGVkIEZkRGF0ZSBtb2RlbCBpbiBzaW5nbGUgbW9kZS4gKi9cbiAgICBASW5wdXQoKVxuICAgIHB1YmxpYyBzZWxlY3RlZERhdGU6IEZkRGF0ZSA9IEZkRGF0ZS5nZXRUb2RheSgpO1xuXG4gICAgLyoqIFRoZSBjdXJyZW50bHkgc2VsZWN0ZWQgRmREYXRlcyBtb2RlbCBzdGFydCBhbmQgZW5kIGluIHJhbmdlIG1vZGUuICovXG4gICAgQElucHV0KClcbiAgICBwdWJsaWMgc2VsZWN0ZWRSYW5nZURhdGU6IEZkUmFuZ2VEYXRlO1xuXG4gICAgLyoqIEFjdHVhbGx5IHNob3duIGFjdGl2ZSB2aWV3IG9uZSBvZiAnZGF5JyB8ICdtb250aCcgfCAneWVhcicgKi9cbiAgICBASW5wdXQoKVxuICAgIHB1YmxpYyBhY3RpdmVWaWV3OiBGZENhbGVuZGFyVmlldyA9ICdkYXknO1xuXG4gICAgLyoqIFRoZSBkYXkgb2YgdGhlIHdlZWsgdGhlIGNhbGVuZGFyIHNob3VsZCBzdGFydCBvbi4gMCByZXByZXNlbnRzIFN1bmRheSwgMSBpcyBNb25kYXksIDIgaXMgVHVlc2RheSwgYW5kIHNvIG9uLiAqL1xuICAgIEBJbnB1dCgpXG4gICAgcHVibGljIHN0YXJ0aW5nRGF5T2ZXZWVrOiBEYXlzT2ZXZWVrID0gMTtcblxuICAgIC8qKiBUaGUgdHlwZSBvZiBjYWxlbmRhciwgJ3NpbmdsZScgZm9yIHNpbmdsZSBkYXRlIHNlbGVjdGlvbiBvciAncmFuZ2UnIGZvciBhIHJhbmdlIG9mIGRhdGVzLiAqL1xuICAgIEBJbnB1dCgpXG4gICAgcHVibGljIGNhbFR5cGU6IENhbGVuZGFyVHlwZSA9ICdzaW5nbGUnO1xuXG4gICAgLyoqIElkIG9mIHRoZSBjYWxlbmRhci4gSWYgbm9uZSBpcyBwcm92aWRlZCwgb25lIHdpbGwgYmUgZ2VuZXJhdGVkLiAqL1xuICAgIEBJbnB1dCgpXG4gICAgaWQgPSAnZmQtY2FsZW5kYXItJyArIGNhbGVuZGFyVW5pcXVlSWQrKztcblxuICAgIC8qKiBFdmVudCB0aHJvd24gZXZlcnkgdGltZSBhY3RpdmUgdmlldyBpcyBjaGFuZ2VkICovXG4gICAgQE91dHB1dCgpXG4gICAgcHVibGljIHJlYWRvbmx5IGFjdGl2ZVZpZXdDaGFuZ2U6IEV2ZW50RW1pdHRlcjxGZENhbGVuZGFyVmlldz4gPSBuZXcgRXZlbnRFbWl0dGVyPEZkQ2FsZW5kYXJWaWV3PigpO1xuXG4gICAgLyoqIEV2ZW50IHRocm93biBldmVyeSB0aW1lIHNlbGVjdGVkIGRhdGUgaW4gc2luZ2xlIG1vZGUgaXMgY2hhbmdlZCAqL1xuICAgIEBPdXRwdXQoKVxuICAgIHB1YmxpYyByZWFkb25seSBzZWxlY3RlZERhdGVDaGFuZ2U6IEV2ZW50RW1pdHRlcjxGZERhdGU+ID0gbmV3IEV2ZW50RW1pdHRlcjxGZERhdGU+KCk7XG5cbiAgICAvKiogRXZlbnQgdGhyb3duIGV2ZXJ5IHRpbWUgc2VsZWN0ZWQgZmlyc3Qgb3IgbGFzdCBkYXRlIGluIHJhbmdlIG1vZGUgaXMgY2hhbmdlZCAqL1xuICAgIEBPdXRwdXQoKVxuICAgIHB1YmxpYyByZWFkb25seSBzZWxlY3RlZFJhbmdlRGF0ZUNoYW5nZTogRXZlbnRFbWl0dGVyPEZkUmFuZ2VEYXRlPiA9IG5ldyBFdmVudEVtaXR0ZXI8RmRSYW5nZURhdGU+KCk7XG5cbiAgICAvKiogRXZlbnQgdGhyb3duIGV2ZXJ5IHRpbWUgd2hlbiB2YWx1ZSBpcyBvdmVyd3JpdHRlbiBmcm9tIG91dHNpZGUgYW5kIHRocm93IGJhY2sgaXNWYWxpZCAqL1xuICAgIEBPdXRwdXQoKVxuICAgIHB1YmxpYyByZWFkb25seSBpc1ZhbGlkRGF0ZUNoYW5nZTogRXZlbnRFbWl0dGVyPGJvb2xlYW4+ID0gbmV3IEV2ZW50RW1pdHRlcjxib29sZWFuPigpO1xuXG4gICAgLyoqIEV2ZW50IHRocm93biBldmVyeSB0aW1lIHdoZW4gY2FsZW5kYXIgc2hvdWxkIGJlIGNsb3NlZCAqL1xuICAgIEBPdXRwdXQoKVxuICAgIHB1YmxpYyByZWFkb25seSBjbG9zZUNhbGVuZGFyOiBFdmVudEVtaXR0ZXI8dm9pZD4gPSBuZXcgRXZlbnRFbWl0dGVyPHZvaWQ+KCk7XG5cbiAgICAvKiogQGhpZGRlbiAqL1xuICAgIG9uQ2hhbmdlOiBGdW5jdGlvbiA9ICgpID0+IHtcbiAgICB9O1xuXG4gICAgLyoqIEBoaWRkZW4gKi9cbiAgICBvblRvdWNoZWQ6IEZ1bmN0aW9uID0gKCkgPT4ge1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBGdW5jdGlvbiB1c2VkIHRvIGRpc2FibGUgY2VydGFpbiBkYXRlcyBpbiB0aGUgY2FsZW5kYXIuXG4gICAgICogQHBhcmFtIGZkRGF0ZSBGZERhdGVcbiAgICAgKi9cbiAgICBASW5wdXQoKVxuICAgIGRpc2FibGVGdW5jdGlvbiA9IGZ1bmN0aW9uKGZkRGF0ZTogRmREYXRlKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogRnVuY3Rpb24gdXNlZCB0byBkaXNhYmxlIGNlcnRhaW4gZGF0ZXMgaW4gdGhlIGNhbGVuZGFyIGZvciB0aGUgcmFuZ2Ugc3RhcnQgc2VsZWN0aW9uLlxuICAgICAqIEBwYXJhbSBmZERhdGUgRmREYXRlXG4gICAgICovXG4gICAgQElucHV0KClcbiAgICBkaXNhYmxlUmFuZ2VTdGFydEZ1bmN0aW9uID0gZnVuY3Rpb24oZmREYXRlOiBGZERhdGUpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBGdW5jdGlvbiB1c2VkIHRvIGRpc2FibGUgY2VydGFpbiBkYXRlcyBpbiB0aGUgY2FsZW5kYXIgZm9yIHRoZSByYW5nZSBlbmQgc2VsZWN0aW9uLlxuICAgICAqIEBwYXJhbSBmZERhdGUgRmREYXRlXG4gICAgICovXG4gICAgQElucHV0KClcbiAgICBkaXNhYmxlUmFuZ2VFbmRGdW5jdGlvbiA9IGZ1bmN0aW9uKGZkRGF0ZTogRmREYXRlKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogRnVuY3Rpb24gdXNlZCB0byBibG9jayBjZXJ0YWluIGRhdGVzIGluIHRoZSBjYWxlbmRhciBmb3IgdGhlIHJhbmdlIHN0YXJ0IHNlbGVjdGlvbi5cbiAgICAgKiBAcGFyYW0gZmREYXRlIEZkRGF0ZVxuICAgICAqL1xuICAgIEBJbnB1dCgpXG4gICAgYmxvY2tSYW5nZVN0YXJ0RnVuY3Rpb24gPSBmdW5jdGlvbihmZERhdGU6IEZkRGF0ZSk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIEZ1bmN0aW9uIHVzZWQgdG8gYmxvY2sgY2VydGFpbiBkYXRlcyBpbiB0aGUgY2FsZW5kYXIgZm9yIHRoZSByYW5nZSBlbmQgc2VsZWN0aW9uLlxuICAgICAqIEBwYXJhbSBmZERhdGUgRmREYXRlXG4gICAgICovXG4gICAgQElucHV0KClcbiAgICBibG9ja1JhbmdlRW5kRnVuY3Rpb24gPSBmdW5jdGlvbihmZERhdGU6IEZkRGF0ZSk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIEZ1bmN0aW9uIHVzZWQgdG8gYmxvY2sgY2VydGFpbiBkYXRlcyBpbiB0aGUgY2FsZW5kYXIuXG4gICAgICogQHBhcmFtIGZkRGF0ZSBGZERhdGVcbiAgICAgKi9cbiAgICBASW5wdXQoKVxuICAgIGJsb2NrRnVuY3Rpb24gPSBmdW5jdGlvbihmZERhdGU6IEZkRGF0ZSk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfTtcblxuICAgIC8qKiBUaGF0IGFsbG93cyB0byBkZWZpbmUgZnVuY3Rpb24gdGhhdCBzaG91bGQgaGFwcGVuLCB3aGVuIGZvY3VzIHNob3VsZCBub3JtYWxseSBlc2NhcGUgb2YgY29tcG9uZW50ICovXG4gICAgQElucHV0KClcbiAgICBlc2NhcGVGb2N1c0Z1bmN0aW9uOiBGdW5jdGlvbiA9ICgpOiB2b2lkID0+IHtcbiAgICAgICAgaWYgKGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKHRoaXMuaWQgKyAnLWxlZnQtYXJyb3cnKSkge1xuICAgICAgICAgICAgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQodGhpcy5pZCArICctbGVmdC1hcnJvdycpLmZvY3VzKCk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgLyoqIEBoaWRkZW4gKi9cbiAgICBjb25zdHJ1Y3RvcihcbiAgICAgICAgcHVibGljIGNhbGVuZGFySTE4bjogQ2FsZW5kYXJJMThuLFxuICAgICAgICBwcml2YXRlIGNoYW5nZURldGVjdG9yUmVmOiBDaGFuZ2VEZXRlY3RvclJlZlxuICAgICkge31cblxuICAgIC8qKiBAaGlkZGVuICovXG4gICAgbmdPbkluaXQoKTogdm9pZCB7XG4gICAgICAgIHRoaXMucHJlcGFyZURpc3BsYXllZFZpZXcoKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBAaGlkZGVuXG4gICAgICogRnVuY3Rpb24gdGhhdCBwcm92aWRlcyBzdXBwb3J0IGZvciBDb250cm9sVmFsdWVBY2Nlc3NvciB0aGF0IGFsbG93cyB0byB1c2UgWyhuZ01vZGVsKV0gb3IgZm9ybXMuXG4gICAgICovXG4gICAgd3JpdGVWYWx1ZShzZWxlY3RlZDogRmRSYW5nZURhdGUgfCBGZERhdGUpOiB2b2lkIHtcbiAgICAgICAgbGV0IHZhbGlkOiBib29sZWFuID0gdHJ1ZTtcbiAgICAgICAgaWYgKHNlbGVjdGVkKSB7XG4gICAgICAgICAgICBpZiAodGhpcy5jYWxUeXBlID09PSAnc2luZ2xlJykge1xuICAgICAgICAgICAgICAgIHNlbGVjdGVkID0gPEZkRGF0ZT5zZWxlY3RlZDtcblxuICAgICAgICAgICAgICAgIHZhbGlkID0gc2VsZWN0ZWQuaXNEYXRlVmFsaWQoKTtcbiAgICAgICAgICAgICAgICB0aGlzLnNlbGVjdGVkRGF0ZSA9IHNlbGVjdGVkO1xuXG4gICAgICAgICAgICAgICAgaWYgKHNlbGVjdGVkLmlzRGF0ZVZhbGlkKCkpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5wcmVwYXJlRGlzcGxheWVkVmlldygpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0gZWxzZSBpZiAodGhpcy5jYWxUeXBlID09PSAncmFuZ2UnKSB7XG4gICAgICAgICAgICAgICAgc2VsZWN0ZWQgPSA8RmRSYW5nZURhdGU+c2VsZWN0ZWQ7XG5cbiAgICAgICAgICAgICAgICBpZiAoIXNlbGVjdGVkLnN0YXJ0IHx8ICFzZWxlY3RlZC5lbmQpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFsaWQgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKHNlbGVjdGVkLnN0YXJ0ICYmICFzZWxlY3RlZC5zdGFydC5pc0RhdGVWYWxpZCgpKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhbGlkID0gZmFsc2U7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGlmIChzZWxlY3RlZC5lbmQgJiYgIXNlbGVjdGVkLmVuZC5pc0RhdGVWYWxpZCgpKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhbGlkID0gZmFsc2U7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHRoaXMuc2VsZWN0ZWRSYW5nZURhdGUgPSB7IHN0YXJ0OiBzZWxlY3RlZC5zdGFydCwgZW5kOiBzZWxlY3RlZC5lbmQgfTtcbiAgICAgICAgICAgICAgICBpZiAodmFsaWQpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5wcmVwYXJlRGlzcGxheWVkVmlldygpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICB0aGlzLmlzVmFsaWREYXRlQ2hhbmdlLmVtaXQodmFsaWQpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEBoaWRkZW5cbiAgICAgKiBGdW5jdGlvbiB0aGF0IGltcGxlbWVudHMgVmFsaWRhdG9yIEludGVyZmFjZSwgYWRkcyB2YWxpZGF0aW9uIHN1cHBvcnQgZm9yIGZvcm1zXG4gICAgICovXG4gICAgdmFsaWRhdGUoY29udHJvbDogQWJzdHJhY3RDb250cm9sKToge1xuICAgICAgICBba2V5OiBzdHJpbmddOiBhbnlcbiAgICB9IHtcbiAgICAgICAgcmV0dXJuIHRoaXMuaXNNb2RlbFZhbGlkKCkgPyBudWxsIDoge1xuICAgICAgICAgICAgZGF0ZVZhbGlkYXRpb246IHtcbiAgICAgICAgICAgICAgICB2YWxpZDogZmFsc2VcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICAvKiogQGhpZGRlbiAqL1xuICAgIHJlZ2lzdGVyT25DaGFuZ2UoZm46IGFueSk6IHZvaWQge1xuICAgICAgICB0aGlzLm9uQ2hhbmdlID0gZm47XG4gICAgfVxuXG4gICAgLyoqIEBoaWRkZW4gKi9cbiAgICByZWdpc3Rlck9uVG91Y2hlZChmbjogYW55KTogdm9pZCB7XG4gICAgICAgIHRoaXMub25Ub3VjaGVkID0gZm47XG4gICAgfVxuXG4gICAgLyoqIEBoaWRkZW4gKi9cbiAgICBzZXREaXNhYmxlZFN0YXRlPyhpc0Rpc2FibGVkOiBib29sZWFuKTogdm9pZCB7XG4gICAgICAgIC8vIE5vdCBuZWVkZWRcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBNZXRob2QgdGhhdCBoYW5kbGUgYWN0aXZlIHZpZXcgY2hhbmdlIGFuZCB0aHJvd3MgZXZlbnQuXG4gICAgICovXG4gICAgcHVibGljIGhhbmRsZUFjdGl2ZVZpZXdDaGFuZ2UoYWN0aXZlVmlldzogRmRDYWxlbmRhclZpZXcpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5hY3RpdmVWaWV3ID0gYWN0aXZlVmlldztcbiAgICAgICAgdGhpcy5hY3RpdmVWaWV3Q2hhbmdlLmVtaXQoYWN0aXZlVmlldyk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQGhpZGRlblxuICAgICAqIE1ldGhvZCB0aGF0IGlzIHRyaWdnZXJlZCBieSBldmVudHMgZnJvbSBkYXkgdmlldyBjb21wb25lbnQsIHdoZW4gdGhlcmUgaXMgc2VsZWN0ZWQgc2luZ2xlIGRhdGUgY2hhbmdlZFxuICAgICAqL1xuICAgIHNlbGVjdGVkRGF0ZUNoYW5nZWQoZGF0ZTogRmREYXRlKTogdm9pZCB7XG4gICAgICAgIHRoaXMuc2VsZWN0ZWREYXRlID0gZGF0ZTtcbiAgICAgICAgdGhpcy5vbkNoYW5nZShkYXRlKTtcbiAgICAgICAgdGhpcy5vblRvdWNoZWQoKTtcbiAgICAgICAgdGhpcy5zZWxlY3RlZERhdGVDaGFuZ2UuZW1pdChkYXRlKTtcbiAgICAgICAgdGhpcy5jbG9zZUNhbGVuZGFyLmVtaXQoKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBAaGlkZGVuXG4gICAgICogTWV0aG9kIHRoYXQgaXMgdHJpZ2dlcmVkIGJ5IGV2ZW50cyBmcm9tIGRheSB2aWV3IGNvbXBvbmVudCwgd2hlbiB0aGVyZSBpcyBzZWxlY3RlZCByYW5nZSBkYXRlIGNoYW5nZWRcbiAgICAgKi9cbiAgICBwdWJsaWMgc2VsZWN0ZWRSYW5nZURhdGVDaGFuZ2VkKGRhdGVzOiBGZFJhbmdlRGF0ZSk6IHZvaWQge1xuICAgICAgICBpZiAoZGF0ZXMpIHtcbiAgICAgICAgICAgIHRoaXMuc2VsZWN0ZWRSYW5nZURhdGUgPSB7IHN0YXJ0OiBkYXRlcy5zdGFydCwgZW5kOiBkYXRlcy5lbmQgPyBkYXRlcy5lbmQgOiBkYXRlcy5zdGFydCB9O1xuICAgICAgICAgICAgdGhpcy5zZWxlY3RlZFJhbmdlRGF0ZUNoYW5nZS5lbWl0KHRoaXMuc2VsZWN0ZWRSYW5nZURhdGUpO1xuICAgICAgICAgICAgdGhpcy5vbkNoYW5nZSh0aGlzLnNlbGVjdGVkUmFuZ2VEYXRlKTtcbiAgICAgICAgICAgIHRoaXMub25Ub3VjaGVkKCk7XG4gICAgICAgICAgICB0aGlzLmNsb3NlQ2FsZW5kYXIuZW1pdCgpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqIEZ1bmN0aW9uIHRoYXQgaGFuZGxlcyBuZXh0IGFycm93IGljb24gY2xpY2ssIGRlcGVuZGluZyBvbiBjdXJyZW50IHZpZXcgaXQgY2hhbmdlcyBtb250aCwgeWVhciBvciBsaXN0IG9mIHllYXJzICovXG4gICAgcHVibGljIGhhbmRsZU5leHRBcnJvd0NsaWNrKCk6IHZvaWQge1xuICAgICAgICBzd2l0Y2ggKHRoaXMuYWN0aXZlVmlldykge1xuICAgICAgICAgICAgY2FzZSAnZGF5JzpcbiAgICAgICAgICAgICAgICB0aGlzLmRpc3BsYXlOZXh0TW9udGgoKTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgJ21vbnRoJzpcbiAgICAgICAgICAgICAgICB0aGlzLmRpc3BsYXlOZXh0WWVhcigpO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSAneWVhcic6XG4gICAgICAgICAgICAgICAgdGhpcy5kaXNwbGF5TmV4dFllYXJMaXN0KCk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5vblRvdWNoZWQoKTtcbiAgICB9XG5cbiAgICAvKiogRnVuY3Rpb24gdGhhdCBoYW5kbGVzIHByZXZpb3VzIGFycm93IGljb24gY2xpY2ssIGRlcGVuZGluZyBvbiBjdXJyZW50IHZpZXcgaXQgY2hhbmdlcyBtb250aCwgeWVhciBvciBsaXN0IG9mIHllYXJzICovXG4gICAgcHVibGljIGhhbmRsZVByZXZpb3VzQXJyb3dDbGljaygpOiB2b2lkIHtcbiAgICAgICAgc3dpdGNoICh0aGlzLmFjdGl2ZVZpZXcpIHtcbiAgICAgICAgICAgIGNhc2UgJ2RheSc6XG4gICAgICAgICAgICAgICAgdGhpcy5kaXNwbGF5UHJldmlvdXNNb250aCgpO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSAnbW9udGgnOlxuICAgICAgICAgICAgICAgIHRoaXMuZGlzcGxheVByZXZpb3VzWWVhcigpO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSAneWVhcic6XG4gICAgICAgICAgICAgICAgdGhpcy5kaXNwbGF5UHJldmlvdXNZZW