UNPKG

angular-bootstrap-datetimepicker

Version:

Native Angular (8+) datetime picker component styled by Twitter Bootstrap 4.

516 lines 53.9 kB
/** * @license * Copyright 2013-present Dale Lotts All Rights Reserved. * http://www.dalelotts.com * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://github.com/dalelotts/angular-bootstrap-datetimepicker/blob/master/LICENSE */ var DlDateTimePickerComponent_1; import * as tslib_1 from "tslib"; import { ChangeDetectionStrategy, Component, ElementRef, EventEmitter, Input, NgZone, OnChanges, OnInit, Output, SimpleChanges } from '@angular/core'; import { NG_VALUE_ACCESSOR } from '@angular/forms'; import * as _moment from 'moment'; import { take } from 'rxjs/operators'; import { DlDateAdapter } from '../core/public-api'; import { DlDateTimePickerChange } from './dl-date-time-picker-change'; import { DlDayModelProvider } from './dl-model-provider-day'; import { DlHourModelProvider } from './dl-model-provider-hour'; import { DlMinuteModelProvider } from './dl-model-provider-minute'; import { DlMonthModelProvider } from './dl-model-provider-month'; import { DlYearModelProvider } from './dl-model-provider-year'; /** * Work around for moment namespace conflict when used with webpack and rollup. * See https://github.com/dherges/ng-packagr/issues/163 * * Depending on whether rollup is used, moment needs to be imported differently. * Since Moment.js doesn't have a default export, we normally need to import using * the `* as`syntax. * * rollup creates a synthetic default module and we thus need to import it using * the `default as` syntax. * * @internal **/ const moment = _moment; /** * Maps key codes to the model provider function name * that should be called to perform the action. * * @internal **/ const keyCodeToModelProviderMethod = { 'ArrowDown': 'goDown', 'ArrowLeft': 'goLeft', 'ArrowRight': 'goRight', 'ArrowUp': 'goUp', 'Down': 'goDown', 'End': 'goEnd', 'Home': 'goHome', 'Left': 'goLeft', 'PageDown': 'pageDown', 'PageUp': 'pageUp', 'Right': 'goRight', 'Up': 'goUp', 33: 'pageUp', 34: 'pageDown', 35: 'goEnd', 36: 'goHome', 37: 'goLeft', 38: 'goUp', 39: 'goRight', 40: 'goDown', }; /** * List of view names for the calendar. * * This list must be in order from * smallest increment of time to largest increment of time. * * @internal **/ const VIEWS = [ 'minute', 'hour', 'day', 'month', 'year' ]; /** * Component that provides all of the user facing functionality of the date/time picker. */ let DlDateTimePickerComponent = DlDateTimePickerComponent_1 = class DlDateTimePickerComponent { /** * Used to construct a new instance of a date/time picker. * * @param _elementRef * reference to this element. * @param _ngZone * reference to an NgZone instance used to select the active element outside of angular. * @param _dateAdapter * date adapter for the date type in the model. * @param yearModelComponent * provider for the year view model. * @param monthModelComponent * provider for the month view model. * @param dayModelComponent * provider for the day view model. * @param hourModelComponent * provider for the hour view model. * @param minuteModelComponent * provider for the minute view model. */ constructor(_elementRef, _ngZone, _dateAdapter, // @ts-ignore yearModelComponent, // @ts-ignore monthModelComponent, // @ts-ignore dayModelComponent, // @ts-ignore hourModelComponent, // @ts-ignore minuteModelComponent) { this._elementRef = _elementRef; this._ngZone = _ngZone; this._dateAdapter = _dateAdapter; this.yearModelComponent = yearModelComponent; this.monthModelComponent = monthModelComponent; this.dayModelComponent = dayModelComponent; this.hourModelComponent = hourModelComponent; this.minuteModelComponent = minuteModelComponent; /** * Change listener callback functions registered * via `registerOnChange` * @internal **/ this._changed = []; /** * Maps view name to the next view (the view for the next smallest increment of time). * @internal **/ this._nextView = { 'year': 'month', 'month': 'day', 'day': 'hour', 'hour': 'minute' }; /** * Maps view name to the previous view (the view for the next largest increment of time). * @internal **/ this._previousView = { 'minute': 'hour', 'hour': 'day', 'day': 'month', 'month': 'year' }; /** * Touch listener callback functions registered * via `registerOnChange` * @internal **/ this._touched = []; /** * Emits when a `change` event when date/time is selected or * the value of the date/time picker changes. **/ this.change = new EventEmitter(); /** * Specifies the classes used to display the left icon. * * This component uses OPENICONIC https://useiconic.com/open * by default but any icon library may be used. */ this.leftIconClass = [ 'oi', 'oi-chevron-left' ]; /** * The highest view that the date/time picker can show. * Setting this to a view less than year could make it more * difficult for the end-user to navigate to certain dates. */ this.maxView = 'year'; /** * The view that will be used for date/time selection. * * The default of `minute means that selection will not happen * until the end-user clicks on a cell in the minute view. * * for example, if you want the end-user to select a only day (date), * setting `minView` to `day` will cause selection to happen when the * end-user selects a cell in the day view. * * NOTE: This must be set lower than or equal to `startView' */ this.minView = 'minute'; /** * The number of minutes between each `.dl-abdtp-minute` button. * * Must be greater than `0` and less than `60`. */ this.minuteStep = 5; /** * Specifies the classes used to display the right icon. * * This component uses OPENICONIC https://useiconic.com/open * by default but any icon library may be used. */ this.rightIconClass = [ 'oi', 'oi-chevron-right' ]; /* tslint:disable:member-ordering */ /** * Determine whether or not the `DateButton` is selectable by the end user. */ this.selectFilter = () => true; /** * The initial view that the date/time picker will show. * The picker will also return to this view after a date/time * is selected. * * NOTE: This must be set lower than or equal to `maxView' */ this.startView = 'day'; /** * Specifies the classes used to display the up icon. * * This component uses OPENICONIC https://useiconic.com/open * by default but any icon library may be used. */ this.upIconClass = [ 'oi', 'oi-chevron-top' ]; this._viewToModelProvider = { year: yearModelComponent, month: monthModelComponent, day: dayModelComponent, hour: hourModelComponent, minute: minuteModelComponent, }; } /* tslint:enable:member-ordering */ /** * Set's the model for the current view after applying the selection filter. * * @internal **/ set model(model) { this._model = this.applySelectFilter(model); } /** * Returns `D` value of the date/time picker or undefined/null if no value is set. **/ get value() { return this._value; } /** * Sets value of the date/time picker and emits a change event if the * new value is different from the previous value. **/ set value(value) { if (this._value !== value) { this._value = value; this.model = this._viewToModelProvider[this._model.viewName].getModel(this.getStartDate(), this.valueOf); this._changed.forEach(f => f(value)); this.change.emit(new DlDateTimePickerChange(value)); } } /** * Returns `milliseconds` value of the date/time picker or undefined/null if no value is set. **/ get valueOf() { return this._dateAdapter.toMilliseconds(this._value); } /** * Applies the `selectionFilter` by adding the `dl-abdtp-disabled` * class to any `DateButton` where `selectFilter` returned false. * * @param model * the new model * * @returns * the supplied model with zero or more `DateButton`'s * having the `dl-abdtp-disabled` class set to `true` if the * selection for that date should be disabled. * * @internal */ applySelectFilter(model) { if (this.selectFilter) { model.rows = model.rows.map((row) => { row.cells.map((dateButton) => { const disabled = !this.selectFilter(dateButton, model.viewName); dateButton.classes['dl-abdtp-disabled'] = disabled; if (disabled) { dateButton.classes['aria-disabled'] = true; } return dateButton; }); return row; }); } return model; } /** * Focuses the `.dl-abdtp-active` cell after the microtask queue is empty. * @internal **/ focusActiveCell() { this._ngZone.runOutsideAngular(() => { this._ngZone.onStable.asObservable().pipe(take(1)).subscribe(() => { this._elementRef.nativeElement.querySelector('.dl-abdtp-active').focus(); }); }); } /** * Determines the start date for the picker. * @internal **/ getStartDate() { if (hasValue(this._value)) { return this._dateAdapter.toMilliseconds(this._value); } if (hasValue(this.startDate)) { return this.startDate; } return moment().valueOf(); } /** * Determine the start view for the picker * @returns * the largest time increment view between the `minView` or `minute` view and the `startView` or `day` view. */ getStartView() { const startIndex = Math.max(VIEWS.indexOf(this.minView || 'minute'), VIEWS.indexOf(this.startView || 'day')); return VIEWS[startIndex]; } /** * Calls all registered `touch` callback functions. * @internal **/ onTouch() { this._touched.forEach((onTouched) => onTouched()); } /** * Receives configuration changes detected by Angular and passes the changes on * to the model providers so the provider is aware of any necessary configuration * changes (i.e. minuteStep) * * @param changes * the input changes detected by Angular. */ ngOnChanges(changes) { Object.values(this._viewToModelProvider).forEach((provider) => provider.onChanges(changes)); if (this._model) { // only update the model after ngOnInit has set it the first time. this.model = this._viewToModelProvider[this._model.viewName].getModel(this._model.activeDate, this.valueOf); } } /** * Sets the initial model. * * @internal **/ ngOnInit() { this.model = this._viewToModelProvider[this.getStartView()].getModel(this.getStartDate(), this.valueOf); } /** * Handles click (and enter & space key down) events on the date elements. * * If the current view is the minimum view then the date value is selected * and the picker returns to the start view. * * Otherwise the picker displays the next view with the next * smallest time increment. * * @internal **/ _onDateClick(dateButton) { if (dateButton.classes['dl-abdtp-disabled']) { return; } let nextView = this._nextView[this._model.viewName]; if ((this.minView || 'minute') === this._model.viewName) { this.value = this._dateAdapter.fromMilliseconds(dateButton.value); nextView = this.startView; } this.model = this._viewToModelProvider[nextView].getModel(dateButton.value, this.valueOf); this.onTouch(); } /** * Handles click (and enter & space key down) events on the left button. * * Changes the displayed time range of the picker to the previous time range. * For example, in year view, the previous decade is displayed. * * @internal **/ _onLeftClick() { this.model = this._viewToModelProvider[this._model.viewName].getModel(this._model.leftButton.value, this.valueOf); this.onTouch(); } /** * Handles click (and enter & space key down) events on the up button. * * Changes the view of the picker to the next largest time increment. * For example, in day view, the next view displayed will be month view. * * @internal **/ _onUpClick() { this.model = this._viewToModelProvider[this._previousView[this._model.viewName]].getModel(this._model.upButton.value, this.valueOf); } /** * Handles click (and enter & space key down) events on the right button. * * Changes the displayed time range of the picker to the next time range. * For example, in year view, the next decade is displayed. * * @internal **/ _onRightClick() { this.model = this._viewToModelProvider[this._model.viewName].getModel(this._model.rightButton.value, this.valueOf); this.onTouch(); } /** * Handles various key down events to move the `active date` around the calendar. * * @internal **/ _handleKeyDown($event) { const functionName = keyCodeToModelProviderMethod[$event.key]; if (functionName) { const modelProvider = this._viewToModelProvider[this._model.viewName]; this.model = modelProvider[functionName](this._model.activeDate, this.valueOf); this.focusActiveCell(); // Prevent unexpected default actions such as form submission. $event.preventDefault(); } } /** * Implements ControlValueAccessor.registerOnChange to register change listeners. * @internal **/ registerOnChange(fn) { this._changed.push(fn); } /** * Implements ControlValueAccessor.registerOnTouched to register touch listeners. * @internal **/ registerOnTouched(fn) { this._touched.push(fn); } /** * Implements ControlValueAccessor.writeValue to store the value from the model. * @internal **/ writeValue(value) { this.value = value; } }; DlDateTimePickerComponent.ctorParameters = () => [ { type: ElementRef }, { type: NgZone }, { type: DlDateAdapter }, { type: DlYearModelProvider }, { type: DlMonthModelProvider }, { type: DlDayModelProvider }, { type: DlHourModelProvider }, { type: DlMinuteModelProvider } ]; tslib_1.__decorate([ Output() ], DlDateTimePickerComponent.prototype, "change", void 0); tslib_1.__decorate([ Input() ], DlDateTimePickerComponent.prototype, "leftIconClass", void 0); tslib_1.__decorate([ Input() ], DlDateTimePickerComponent.prototype, "maxView", void 0); tslib_1.__decorate([ Input() ], DlDateTimePickerComponent.prototype, "minView", void 0); tslib_1.__decorate([ Input() ], DlDateTimePickerComponent.prototype, "minuteStep", void 0); tslib_1.__decorate([ Input() ], DlDateTimePickerComponent.prototype, "rightIconClass", void 0); tslib_1.__decorate([ Input() ], DlDateTimePickerComponent.prototype, "selectFilter", void 0); tslib_1.__decorate([ Input() ], DlDateTimePickerComponent.prototype, "startDate", void 0); tslib_1.__decorate([ Input() ], DlDateTimePickerComponent.prototype, "startView", void 0); tslib_1.__decorate([ Input() ], DlDateTimePickerComponent.prototype, "upIconClass", void 0); DlDateTimePickerComponent = DlDateTimePickerComponent_1 = tslib_1.__decorate([ Component({ changeDetection: ChangeDetectionStrategy.OnPush, preserveWhitespaces: false, providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: DlDateTimePickerComponent_1, multi: true } ], selector: 'dl-date-time-picker', template: "<div class=\"text-center dl-abdtp-{{_model.viewName}}-view\" [attr.data-dl-abdtp-view]=\"_model.viewName\">\n <div class=\"row align-items-center no-gutters\">\n <button class=\"col dl-abdtp-left-button align-items-center\"\n type=\"button\"\n [attr.aria-label]=\"_model.leftButton.ariaLabel\"\n [attr.dl-abdtp-value]=\"_model.leftButton.value\"\n [attr.title]=\"_model.leftButton.ariaLabel\"\n (click)=\"_onLeftClick()\"\n ><span class=\"left-icon\" [ngClass]=\"leftIconClass\"></span>\n </button>\n\n <div *ngIf=\"_model.viewName === (this.maxView || 'year'); then maxViewLabel else defaultViewLabel;\"></div>\n\n <button class=\"col dl-abdtp-right-button\"\n type=\"button\"\n [attr.aria-label]=\"_model.rightButton.ariaLabel\"\n [attr.dl-abdtp-value]=\"_model.rightButton.value\"\n [attr.title]=\"_model.rightButton.ariaLabel\"\n (click)=\"_onRightClick()\"\n ><span class=\"right-icon\" [ngClass]=\"rightIconClass\"></span>\n </button>\n </div>\n <div (keydown)=\"_handleKeyDown($event)\">\n <div *ngIf=\"_model.rowLabels?.length\" class=\"row no-gutters\">\n <div *ngFor=\"let label of _model.rowLabels\"\n class=\"col align-items-center no-gutters dl-abdtp-col-label\">{{label}}</div>\n </div>\n <div *ngFor=\"let row of _model.rows\" class=\"row align-items-center no-gutters\">\n <div *ngFor=\"let cell of row.cells\"\n role=\"gridcell\"\n class=\"col dl-abdtp-date-button dl-abdtp-{{_model.viewName}}\"\n [ngClass]=\"cell.classes\"\n [attr.aria-label]=\"cell.ariaLabel\"\n [attr.aria-disabled]=\"cell.classes['dl-abdtp-disabled']\"\n [attr.dl-abdtp-value]=\"cell.value\"\n [attr.tabindex]=\"cell.classes['dl-abdtp-active'] ? 0 : -1\"\n (click)=\"_onDateClick(cell)\"\n (keydown.space)=\"_onDateClick(cell)\"\n (keydown.enter)=\"_onDateClick(cell)\"\n >{{cell.display}}</div>\n </div>\n </div>\n</div>\n\n<ng-template #maxViewLabel>\n <div class=\"col-10 dl-abdtp-view-label\">{{_model.viewLabel}}</div>\n</ng-template>\n<ng-template #defaultViewLabel>\n <button class=\"col-10 dl-abdtp-view-label dl-abdtp-up-button\"\n type=\"button\"\n [attr.aria-label]=\"_model.upButton.ariaLabel\"\n [attr.dl-abdtp-value]=\"_model.upButton.value\"\n [attr.title]=\"_model.upButton.ariaLabel\"\n (click)=\"_onUpClick()\"\n [ngClass]=\"_model.upButton.classes\"\n >{{_model.viewLabel}}&nbsp;<span class=\"up-icon\" [ngClass]=\"upIconClass\"></span>\n </button>\n</ng-template>\n", styles: [":host{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.dl-abdtp-col-label,.dl-abdtp-view-label{font-weight:700}.dl-abdtp-date-button,.dl-abdtp-left-button,.dl-abdtp-right-button,.dl-abdtp-view-label{padding:5px;border-radius:999px;cursor:pointer;color:rgba(0,0,0,.87);outline:0}.dl-abdtp-date-button,.dl-abdtp-left-button,.dl-abdtp-right-button,.dl-abdtp-up-button{border-width:0}.dl-abdtp-active:focus,.dl-abdtp-date-button:focus,.dl-abdtp-date-button:hover,.dl-abdtp-left-button:focus,.dl-abdtp-left-button:hover,.dl-abdtp-right-button:focus,.dl-abdtp-right-button:hover,.dl-abdtp-up-button:focus,.dl-abdtp-up-button:hover,.dl-abdtp-view-label:focus{background:rgba(0,0,0,.04)}.dl-abdtp-future,.dl-abdtp-past{color:rgba(0,0,0,.04)}.dl-abdtp-now,.dl-abdtp-now.disabled,.dl-abdtp-now.disabled:hover,.dl-abdtp-now:hover{border-radius:999px;border:1px solid rgba(0,0,0,.25)}.dl-abdtp-selected{color:#fff;background:rgba(0,82,204,.75)}.dl-abdtp-selected:focus,.dl-abdtp-selected:hover{background:#0052cc}.dl-abdtp-disabled{cursor:default;color:rgba(0,0,0,.25)}"] }) ], DlDateTimePickerComponent); export { DlDateTimePickerComponent }; /** @internal */ function hasValue(value) { return (typeof value !== 'undefined') && (value !== null); } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGwtZGF0ZS10aW1lLXBpY2tlci5jb21wb25lbnQuanMiLCJzb3VyY2VSb290Ijoibmc6Ly9hbmd1bGFyLWJvb3RzdHJhcC1kYXRldGltZXBpY2tlci8iLCJzb3VyY2VzIjpbImRsLWRhdGUtdGltZS1waWNrZXIvZGwtZGF0ZS10aW1lLXBpY2tlci5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7R0FPRzs7O0FBRUgsT0FBTyxFQUNMLHVCQUF1QixFQUN2QixTQUFTLEVBQ1QsVUFBVSxFQUNWLFlBQVksRUFDWixLQUFLLEVBQ0wsTUFBTSxFQUNOLFNBQVMsRUFDVCxNQUFNLEVBQ04sTUFBTSxFQUNOLGFBQWEsRUFDZCxNQUFNLGVBQWUsQ0FBQztBQUV2QixPQUFPLEVBQXVCLGlCQUFpQixFQUFDLE1BQU0sZ0JBQWdCLENBQUM7QUFDdkUsT0FBTyxLQUFLLE9BQU8sTUFBTSxRQUFRLENBQUM7QUFDbEMsT0FBTyxFQUFDLElBQUksRUFBQyxNQUFNLGdCQUFnQixDQUFDO0FBQ3BDLE9BQU8sRUFBQyxhQUFhLEVBQUMsTUFBTSxvQkFBb0IsQ0FBQztBQUNqRCxPQUFPLEVBQUMsc0JBQXNCLEVBQUMsTUFBTSw4QkFBOEIsQ0FBQztBQUlwRSxPQUFPLEVBQUMsa0JBQWtCLEVBQUMsTUFBTSx5QkFBeUIsQ0FBQztBQUMzRCxPQUFPLEVBQUMsbUJBQW1CLEVBQUMsTUFBTSwwQkFBMEIsQ0FBQztBQUM3RCxPQUFPLEVBQUMscUJBQXFCLEVBQUMsTUFBTSw0QkFBNEIsQ0FBQztBQUNqRSxPQUFPLEVBQUMsb0JBQW9CLEVBQUMsTUFBTSwyQkFBMkIsQ0FBQztBQUMvRCxPQUFPLEVBQUMsbUJBQW1CLEVBQUMsTUFBTSwwQkFBMEIsQ0FBQztBQUU3RDs7Ozs7Ozs7Ozs7O0lBWUk7QUFDSixNQUFNLE1BQU0sR0FBRyxPQUFPLENBQUM7QUFHdkI7Ozs7O0lBS0k7QUFFSixNQUFNLDRCQUE0QixHQUFHO0lBQ25DLFdBQVcsRUFBRSxRQUFRO0lBQ3JCLFdBQVcsRUFBRSxRQUFRO0lBQ3JCLFlBQVksRUFBRSxTQUFTO0lBQ3ZCLFNBQVMsRUFBRSxNQUFNO0lBQ2pCLE1BQU0sRUFBRSxRQUFRO0lBQ2hCLEtBQUssRUFBRSxPQUFPO0lBQ2QsTUFBTSxFQUFFLFFBQVE7SUFDaEIsTUFBTSxFQUFFLFFBQVE7SUFDaEIsVUFBVSxFQUFFLFVBQVU7SUFDdEIsUUFBUSxFQUFFLFFBQVE7SUFDbEIsT0FBTyxFQUFFLFNBQVM7SUFDbEIsSUFBSSxFQUFFLE1BQU07SUFDWixFQUFFLEVBQUUsUUFBUTtJQUNaLEVBQUUsRUFBRSxVQUFVO0lBQ2QsRUFBRSxFQUFFLE9BQU87SUFDWCxFQUFFLEVBQUUsUUFBUTtJQUNaLEVBQUUsRUFBRSxRQUFRO0lBQ1osRUFBRSxFQUFFLE1BQU07SUFDVixFQUFFLEVBQUUsU0FBUztJQUNiLEVBQUUsRUFBRSxRQUFRO0NBQ2IsQ0FBQztBQUdGOzs7Ozs7O0lBT0k7QUFDSixNQUFNLEtBQUssR0FBRztJQUNaLFFBQVE7SUFDUixNQUFNO0lBQ04sS0FBSztJQUNMLE9BQU87SUFDUCxNQUFNO0NBQ1AsQ0FBQztBQUVGOztHQUVHO0FBZ0JILElBQWEseUJBQXlCLGlDQUF0QyxNQUFhLHlCQUF5QjtJQW9KcEM7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7T0FtQkc7SUFDSCxZQUFvQixXQUF1QixFQUN2QixPQUFlLEVBQ2YsWUFBOEI7SUFDdEMsYUFBYTtJQUNMLGtCQUF1QztJQUMvQyxhQUFhO0lBQ0wsbUJBQXlDO0lBQ2pELGFBQWE7SUFDTCxpQkFBcUM7SUFDN0MsYUFBYTtJQUNMLGtCQUF1QztJQUMvQyxhQUFhO0lBQ0wsb0JBQTJDO1FBWjNDLGdCQUFXLEdBQVgsV0FBVyxDQUFZO1FBQ3ZCLFlBQU8sR0FBUCxPQUFPLENBQVE7UUFDZixpQkFBWSxHQUFaLFlBQVksQ0FBa0I7UUFFOUIsdUJBQWtCLEdBQWxCLGtCQUFrQixDQUFxQjtRQUV2Qyx3QkFBbUIsR0FBbkIsbUJBQW1CLENBQXNCO1FBRXpDLHNCQUFpQixHQUFqQixpQkFBaUIsQ0FBb0I7UUFFckMsdUJBQWtCLEdBQWxCLGtCQUFrQixDQUFxQjtRQUV2Qyx5QkFBb0IsR0FBcEIsb0JBQW9CLENBQXVCO1FBbEwvRDs7OztZQUlJO1FBQ0ksYUFBUSxHQUEyQixFQUFFLENBQUM7UUFPOUM7OztZQUdJO1FBQ0ksY0FBUyxHQUFHO1lBQ2xCLE1BQU0sRUFBRSxPQUFPO1lBQ2YsT0FBTyxFQUFFLEtBQUs7WUFDZCxLQUFLLEVBQUUsTUFBTTtZQUNiLE1BQU0sRUFBRSxRQUFRO1NBQ2pCLENBQUM7UUFDRjs7O1lBR0k7UUFDSSxrQkFBYSxHQUFHO1lBQ3RCLFFBQVEsRUFBRSxNQUFNO1lBQ2hCLE1BQU0sRUFBRSxLQUFLO1lBQ2IsS0FBSyxFQUFFLE9BQU87WUFDZCxPQUFPLEVBQUUsTUFBTTtTQUNoQixDQUFDO1FBQ0Y7Ozs7WUFJSTtRQUNJLGFBQVEsR0FBbUIsRUFBRSxDQUFDO1FBaUJ0Qzs7O1lBR0k7UUFFSyxXQUFNLEdBQUcsSUFBSSxZQUFZLEVBQTZCLENBQUM7UUFDaEU7Ozs7O1dBS0c7UUFFSCxrQkFBYSxHQUF5QztZQUNwRCxJQUFJO1lBQ0osaUJBQWlCO1NBQ2xCLENBQUM7UUFDRjs7OztXQUlHO1FBRUgsWUFBTyxHQUFpRCxNQUFNLENBQUM7UUFDL0Q7Ozs7Ozs7Ozs7O1dBV0c7UUFFSCxZQUFPLEdBQWlELFFBQVEsQ0FBQztRQUNqRTs7OztXQUlHO1FBRUgsZUFBVSxHQUFHLENBQUMsQ0FBQztRQUNmOzs7OztXQUtHO1FBRUgsbUJBQWMsR0FBRztZQUNmLElBQUk7WUFDSixrQkFBa0I7U0FDbkIsQ0FBQztRQUVGLG9DQUFvQztRQUNwQzs7V0FFRztRQUVILGlCQUFZLEdBQTBELEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQTtRQVFoRjs7Ozs7O1dBTUc7UUFFSCxjQUFTLEdBQWlELEtBQUssQ0FBQztRQUVoRTs7Ozs7V0FLRztRQUVILGdCQUFXLEdBQUc7WUFDWixJQUFJO1lBQ0osZ0JBQWdCO1NBQ2pCLENBQUM7UUFvQ0EsSUFBSSxDQUFDLG9CQUFvQixHQUFHO1lBQzFCLElBQUksRUFBRSxrQkFBa0I7WUFDeEIsS0FBSyxFQUFFLG1CQUFtQjtZQUMxQixHQUFHLEVBQUUsaUJBQWlCO1lBQ3RCLElBQUksRUFBRSxrQkFBa0I7WUFDeEIsTUFBTSxFQUFFLG9CQUFvQjtTQUM3QixDQUFDO0lBQ0osQ0FBQztJQUVELG1DQUFtQztJQUNuQzs7OztRQUlJO0lBQ0osSUFBWSxLQUFLLENBQUMsS0FBNEI7UUFDNUMsSUFBSSxDQUFDLE1BQU0sR0FBRyxJQUFJLENBQUMsaUJBQWlCLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDOUMsQ0FBQztJQUVEOztRQUVJO0lBQ0osSUFBSSxLQUFLO1FBQ1AsT0FBTyxJQUFJLENBQUMsTUFBTSxDQUFDO0lBQ3JCLENBQUM7SUFFRDs7O1FBR0k7SUFDSixJQUFJLEtBQUssQ0FBQyxLQUFRO1FBQ2hCLElBQUksSUFBSSxDQUFDLE1BQU0sS0FBSyxLQUFLLEVBQUU7WUFDekIsSUFBSSxDQUFDLE1BQU0sR0FBRyxLQUFLLENBQUM7WUFDcEIsSUFBSSxDQUFDLEtBQUssR0FBRyxJQUFJLENBQUMsb0JBQW9CLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLFlBQVksRUFBRSxFQUFFLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUN6RyxJQUFJLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDO1lBQ3JDLElBQUksQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLElBQUksc0JBQXNCLENBQUksS0FBSyxDQUFDLENBQUMsQ0FBQztTQUN4RDtJQUNILENBQUM7SUFFRDs7UUFFSTtJQUNKLElBQUksT0FBTztRQUNULE9BQU8sSUFBSSxDQUFDLFlBQVksQ0FBQyxjQUFjLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQ3ZELENBQUM7SUFFRDs7Ozs7Ozs7Ozs7OztPQWFHO0lBQ0ssaUJBQWlCLENBQUMsS0FBNEI7UUFDcEQsSUFBSSxJQUFJLENBQUMsWUFBWSxFQUFFO1lBQ3JCLEtBQUssQ0FBQyxJQUFJLEdBQUcsS0FBSyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxHQUFHLEVBQUUsRUFBRTtnQkFDbEMsR0FBRyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxVQUFzQixFQUFFLEVBQUU7b0JBQ3ZDLE1BQU0sUUFBUSxHQUFHLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxVQUFVLEVBQUUsS0FBSyxDQUFDLFFBQVEsQ0FBQyxDQUFDO29CQUNoRSxVQUFVLENBQUMsT0FBTyxDQUFDLG1CQUFtQixDQUFDLEdBQUcsUUFBUSxDQUFDO29CQUNuRCxJQUFJLFFBQVEsRUFBRTt3QkFDWixVQUFVLENBQUMsT0FBTyxDQUFDLGVBQWUsQ0FBQyxHQUFHLElBQUksQ0FBQztxQkFDNUM7b0JBQ0QsT0FBTyxVQUFVLENBQUM7Z0JBQ3BCLENBQUMsQ0FBQyxDQUFDO2dCQUNILE9BQU8sR0FBRyxDQUFDO1lBQ2IsQ0FBQyxDQUFDLENBQUM7U0FDSjtRQUVELE9BQU8sS0FBSyxDQUFDO0lBQ2YsQ0FBQztJQUVEOzs7UUFHSTtJQUNJLGVBQWU7UUFDckIsSUFBSSxDQUFDLE9BQU8sQ0FBQyxpQkFBaUIsQ0FBQyxHQUFHLEVBQUU7WUFDbEMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsWUFBWSxFQUFFLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxHQUFHLEVBQUU7Z0JBQ2hFLElBQUksQ0FBQyxXQUFXLENBQUMsYUFBYSxDQUFDLGFBQWEsQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDLEtBQUssRUFBRSxDQUFDO1lBQzNFLENBQUMsQ0FBQyxDQUFDO1FBQ0wsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQ7OztRQUdJO0lBQ0ksWUFBWTtRQUNsQixJQUFJLFFBQVEsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLEVBQUU7WUFDekIsT0FBTyxJQUFJLENBQUMsWUFBWSxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7U0FDdEQ7UUFDRCxJQUFJLFFBQVEsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLEVBQUU7WUFDNUIsT0FBTyxJQUFJLENBQUMsU0FBUyxDQUFDO1NBQ3ZCO1FBQ0QsT0FBTyxNQUFNLEVBQUUsQ0FBQyxPQUFPLEVBQUUsQ0FBQztJQUM1QixDQUFDO0lBRUQ7Ozs7T0FJRztJQUNLLFlBQVk7UUFDbEIsTUFBTSxVQUFVLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxPQUFPLElBQUksUUFBUSxDQUFDLEVBQUUsS0FBSyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsU0FBUyxJQUFJLEtBQUssQ0FBQyxDQUFDLENBQUM7UUFDN0csT0FBTyxLQUFLLENBQUMsVUFBVSxDQUFDLENBQUM7SUFDM0IsQ0FBQztJQUVEOzs7UUFHSTtJQUNJLE9BQU87UUFDYixJQUFJLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxDQUFDLFNBQVMsRUFBRSxFQUFFLENBQUMsU0FBUyxFQUFFLENBQUMsQ0FBQztJQUNwRCxDQUFDO0lBRUQ7Ozs7Ozs7T0FPRztJQUNILFdBQVcsQ0FBQyxPQUFzQjtRQUNoQyxNQUFNLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDLFFBQXlCLEVBQUUsRUFBRSxDQUFDLFFBQVEsQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQztRQUU3RyxJQUFJLElBQUksQ0FBQyxNQUFNLEVBQUUsRUFBRSxrRUFBa0U7WUFDbkYsSUFBSSxDQUFDLEtBQUssR0FBRyxJQUFJLENBQUMsb0JBQW9CLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxVQUFVLEVBQUUsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1NBQzdHO0lBQ0gsQ0FBQztJQUVEOzs7O1FBSUk7SUFDSixRQUFRO1FBQ04sSUFBSSxDQUFDLEtBQUssR0FBRyxJQUFJLENBQUMsb0JBQW9CLENBQUMsSUFBSSxDQUFDLFlBQVksRUFBRSxDQUFDLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxZQUFZLEVBQUUsRUFBRSxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDMUcsQ0FBQztJQUVEOzs7Ozs7Ozs7O1FBVUk7SUFDSixZQUFZLENBQUMsVUFBc0I7UUFDakMsSUFBSSxVQUFVLENBQUMsT0FBTyxDQUFDLG1CQUFtQixDQUFDLEVBQUU7WUFDM0MsT0FBTztTQUNSO1FBRUQsSUFBSSxRQUFRLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBRXBELElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxJQUFJLFFBQVEsQ0FBQyxLQUFLLElBQUksQ0FBQyxNQUFNLENBQUMsUUFBUSxFQUFFO1lBQ3ZELElBQUksQ0FBQyxLQUFLLEdBQUcsSUFBSSxDQUFDLFlBQVksQ0FBQyxnQkFBZ0IsQ0FBQyxVQUFVLENBQUMsS0FBSyxDQUFDLENBQUM7WUFDbEUsUUFBUSxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUM7U0FDM0I7UUFFRCxJQUFJLENBQUMsS0FBSyxHQUFHLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxRQUFRLENBQUMsQ0FBQyxRQUFRLENBQUMsVUFBVSxDQUFDLEtBQUssRUFBRSxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7UUFFMUYsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDO0lBQ2pCLENBQUM7SUFFRDs7Ozs7OztRQU9JO0lBQ0osWUFBWTtRQUNWLElBQUksQ0FBQyxLQUFLLEdBQUcsSUFBSSxDQUFDLG9CQUFvQixDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsVUFBVSxDQUFDLEtBQUssRUFBRSxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDbEgsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDO0lBQ2pCLENBQUM7SUFFRDs7Ozs7OztRQU9JO0lBQ0osVUFBVTtRQUNSLElBQUksQ0FBQyxLQUFLLEdBQUcsSUFBSSxDQUFDLG9CQUFvQixDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxLQUFLLEVBQUUsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQ3RJLENBQUM7SUFFRDs7Ozs7OztRQU9JO0lBQ0osYUFBYTtRQUNYLElBQUksQ0FBQyxLQUFLLEdBQUcsSUFBSSxDQUFDLG9CQUFvQixDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsV0FBVyxDQUFDLEtBQUssRUFBRSxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDbkgsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDO0lBQ2pCLENBQUM7SUFFRDs7OztRQUlJO0lBQ0osY0FBYyxDQUFDLE1BQXFCO1FBQ2xDLE1BQU0sWUFBWSxHQUFHLDRCQUE0QixDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUU5RCxJQUFJLFlBQVksRUFBRTtZQUNoQixNQUFNLGFBQWEsR0FBRyxJQUFJLENBQUMsb0JBQW9CLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsQ0FBQztZQUN0RSxJQUFJLENBQUMsS0FBSyxHQUFHLGFBQWEsQ0FBQyxZQUFZLENBQUMsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLFVBQVUsRUFBRSxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7WUFFL0UsSUFBSSxDQUFDLGVBQWUsRUFBRSxDQUFDO1lBQ3ZCLDhEQUE4RDtZQUM5RCxNQUFNLENBQUMsY0FBYyxFQUFFLENBQUM7U0FDekI7SUFDSCxDQUFDO0lBRUQ7OztRQUdJO0lBQ0osZ0JBQWdCLENBQUMsRUFBc0I7UUFDckMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDekIsQ0FBQztJQUVEOzs7UUFHSTtJQUNKLGlCQUFpQixDQUFDLEVBQWM7UUFDOUIsSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDekIsQ0FBQztJQUVEOzs7UUFHSTtJQUNKLFVBQVUsQ0FBQyxLQUFRO1FBQ2pCLElBQUksQ0FBQyxLQUFLLEdBQUcsS0FBSyxDQUFDO0lBQ3JCLENBQUM7Q0FFRixDQUFBOztZQTdRa0MsVUFBVTtZQUNkLE1BQU07WUFDRCxhQUFhO1lBRVAsbUJBQW1CO1lBRWxCLG9CQUFvQjtZQUV0QixrQkFBa0I7WUFFakIsbUJBQW1CO1lBRWpCLHFCQUFxQjs7QUF2SC9EO0lBREMsTUFBTSxFQUFFO3lEQUN1RDtBQVFoRTtJQURDLEtBQUssRUFBRTtnRUFJTjtBQU9GO0lBREMsS0FBSyxFQUFFOzBEQUN1RDtBQWMvRDtJQURDLEtBQUssRUFBRTswREFDeUQ7QUFPakU7SUFEQyxLQUFLLEVBQUU7NkRBQ087QUFRZjtJQURDLEtBQUssRUFBRTtpRUFJTjtBQU9GO0lBREMsS0FBSyxFQUFFOytEQUN3RTtBQU1oRjtJQURDLEtBQUssRUFBRTs0REFDVTtBQVVsQjtJQURDLEtBQUssRUFBRTs0REFDd0Q7QUFTaEU7SUFEQyxLQUFLLEVBQUU7OERBSU47QUFsSlMseUJBQXlCO0lBZHJDLFNBQVMsQ0FBQztRQUNULGVBQWUsRUFBRSx1QkFBdUIsQ0FBQyxNQUFNO1FBQy9DLG1CQUFtQixFQUFFLEtBQUs7UUFDMUIsU0FBUyxFQUFFO1lBQ1Q7Z0JBQ0UsT0FBTyxFQUFFLGlCQUFpQjtnQkFDMUIsV0FBVyxFQUFFLDJCQUF5QjtnQkFDdEMsS0FBSyxFQUFFLElBQUk7YUFDWjtTQUNGO1FBQ0QsUUFBUSxFQUFFLHFCQUFxQjtRQUUvQiw0cEZBQW1EOztLQUNwRCxDQUFDO0dBQ1cseUJBQXlCLENBcWJyQztTQXJiWSx5QkFBeUI7QUF1YnRDLGdCQUFnQjtBQUNoQixTQUFTLFFBQVEsQ0FBQyxLQUFVO0lBQzFCLE9BQU8sQ0FBQyxPQUFPLEtBQUssS0FBSyxXQUFXLENBQUMsSUFBSSxDQUFDLEtBQUssS0FBSyxJQUFJLENBQUMsQ0FBQztBQUM1RCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBAbGljZW5zZVxuICogQ29weXJpZ2h0IDIwMTMtcHJlc2VudCBEYWxlIExvdHRzIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG4gKiBodHRwOi8vd3d3LmRhbGVsb3R0cy5jb21cbiAqXG4gKiBVc2Ugb2YgdGhpcyBzb3VyY2UgY29kZSBpcyBnb3Zlcm5lZCBieSBhbiBNSVQtc3R5bGUgbGljZW5zZSB0aGF0IGNhbiBiZVxuICogZm91bmQgaW4gdGhlIExJQ0VOU0UgZmlsZSBhdCBodHRwczovL2dpdGh1Yi5jb20vZGFsZWxvdHRzL2FuZ3VsYXItYm9vdHN0cmFwLWRhdGV0aW1lcGlja2VyL2Jsb2IvbWFzdGVyL0xJQ0VOU0VcbiAqL1xuXG5pbXBvcnQge1xuICBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneSxcbiAgQ29tcG9uZW50LFxuICBFbGVtZW50UmVmLFxuICBFdmVudEVtaXR0ZXIsXG4gIElucHV0LFxuICBOZ1pvbmUsXG4gIE9uQ2hhbmdlcyxcbiAgT25Jbml0LFxuICBPdXRwdXQsXG4gIFNpbXBsZUNoYW5nZXNcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5cbmltcG9ydCB7Q29udHJvbFZhbHVlQWNjZXNzb3IsIE5HX1ZBTFVFX0FDQ0VTU09SfSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XG5pbXBvcnQgKiBhcyBfbW9tZW50IGZyb20gJ21vbWVudCc7XG5pbXBvcnQge3Rha2V9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcbmltcG9ydCB7RGxEYXRlQWRhcHRlcn0gZnJvbSAnLi4vY29yZS9wdWJsaWMtYXBpJztcbmltcG9ydCB7RGxEYXRlVGltZVBpY2tlckNoYW5nZX0gZnJvbSAnLi9kbC1kYXRlLXRpbWUtcGlja2VyLWNoYW5nZSc7XG5pbXBvcnQge0RhdGVCdXR0b259IGZyb20gJy4vZGwtZGF0ZS10aW1lLXBpY2tlci1kYXRlLWJ1dHRvbic7XG5pbXBvcnQge0RsRGF0ZVRpbWVQaWNrZXJNb2RlbH0gZnJvbSAnLi9kbC1kYXRlLXRpbWUtcGlja2VyLW1vZGVsJztcbmltcG9ydCB7RGxNb2RlbFByb3ZpZGVyfSBmcm9tICcuL2RsLW1vZGVsLXByb3ZpZGVyJztcbmltcG9ydCB7RGxEYXlNb2RlbFByb3ZpZGVyfSBmcm9tICcuL2RsLW1vZGVsLXByb3ZpZGVyLWRheSc7XG5pbXBvcnQge0RsSG91ck1vZGVsUHJvdmlkZXJ9IGZyb20gJy4vZGwtbW9kZWwtcHJvdmlkZXItaG91cic7XG5pbXBvcnQge0RsTWludXRlTW9kZWxQcm92aWRlcn0gZnJvbSAnLi9kbC1tb2RlbC1wcm92aWRlci1taW51dGUnO1xuaW1wb3J0IHtEbE1vbnRoTW9kZWxQcm92aWRlcn0gZnJvbSAnLi9kbC1tb2RlbC1wcm92aWRlci1tb250aCc7XG5pbXBvcnQge0RsWWVhck1vZGVsUHJvdmlkZXJ9IGZyb20gJy4vZGwtbW9kZWwtcHJvdmlkZXIteWVhcic7XG5cbi8qKlxuICogV29yayBhcm91bmQgZm9yIG1vbWVudCBuYW1lc3BhY2UgY29uZmxpY3Qgd2hlbiB1c2VkIHdpdGggd2VicGFjayBhbmQgcm9sbHVwLlxuICogU2VlIGh0dHBzOi8vZ2l0aHViLmNvbS9kaGVyZ2VzL25nLXBhY2thZ3IvaXNzdWVzLzE2M1xuICpcbiAqIERlcGVuZGluZyBvbiB3aGV0aGVyIHJvbGx1cCBpcyB1c2VkLCBtb21lbnQgbmVlZHMgdG8gYmUgaW1wb3J0ZWQgZGlmZmVyZW50bHkuXG4gKiBTaW5jZSBNb21lbnQuanMgZG9lc24ndCBoYXZlIGEgZGVmYXVsdCBleHBvcnQsIHdlIG5vcm1hbGx5IG5lZWQgdG8gaW1wb3J0IHVzaW5nXG4gKiB0aGUgYCogYXNgc3ludGF4LlxuICpcbiAqIHJvbGx1cCBjcmVhdGVzIGEgc3ludGhldGljIGRlZmF1bHQgbW9kdWxlIGFuZCB3ZSB0aHVzIG5lZWQgdG8gaW1wb3J0IGl0IHVzaW5nXG4gKiB0aGUgYGRlZmF1bHQgYXNgIHN5bnRheC5cbiAqXG4gKiBAaW50ZXJuYWxcbiAqKi9cbmNvbnN0IG1vbWVudCA9IF9tb21lbnQ7XG5cblxuLyoqXG4gKiBNYXBzIGtleSBjb2RlcyB0byB0aGUgbW9kZWwgcHJvdmlkZXIgZnVuY3Rpb24gbmFtZVxuICogdGhhdCBzaG91bGQgYmUgY2FsbGVkIHRvIHBlcmZvcm0gdGhlIGFjdGlvbi5cbiAqXG4gKiBAaW50ZXJuYWxcbiAqKi9cblxuY29uc3Qga2V5Q29kZVRvTW9kZWxQcm92aWRlck1ldGhvZCA9IHtcbiAgJ0Fycm93RG93bic6ICdnb0Rvd24nLFxuICAnQXJyb3dMZWZ0JzogJ2dvTGVmdCcsXG4gICdBcnJvd1JpZ2h0JzogJ2dvUmlnaHQnLFxuICAnQXJyb3dVcCc6ICdnb1VwJyxcbiAgJ0Rvd24nOiAnZ29Eb3duJyxcbiAgJ0VuZCc6ICdnb0VuZCcsXG4gICdIb21lJzogJ2dvSG9tZScsXG4gICdMZWZ0JzogJ2dvTGVmdCcsXG4gICdQYWdlRG93bic6ICdwYWdlRG93bicsXG4gICdQYWdlVXAnOiAncGFnZVVwJyxcbiAgJ1JpZ2h0JzogJ2dvUmlnaHQnLFxuICAnVXAnOiAnZ29VcCcsXG4gIDMzOiAncGFnZVVwJyxcbiAgMzQ6ICdwYWdlRG93bicsXG4gIDM1OiAnZ29FbmQnLFxuICAzNjogJ2dvSG9tZScsXG4gIDM3OiAnZ29MZWZ0JyxcbiAgMzg6ICdnb1VwJyxcbiAgMzk6ICdnb1JpZ2h0JyxcbiAgNDA6ICdnb0Rvd24nLFxufTtcblxuXG4vKipcbiAqIExpc3Qgb2YgdmlldyBuYW1lcyBmb3IgdGhlIGNhbGVuZGFyLlxuICpcbiAqIFRoaXMgbGlzdCBtdXN0IGJlIGluIG9yZGVyIGZyb21cbiAqIHNtYWxsZXN0IGluY3JlbWVudCBvZiB0aW1lIHRvIGxhcmdlc3QgaW5jcmVtZW50IG9mIHRpbWUuXG4gKlxuICogQGludGVybmFsXG4gKiovXG5jb25zdCBWSUVXUyA9IFtcbiAgJ21pbnV0ZScsXG4gICdob3VyJyxcbiAgJ2RheScsXG4gICdtb250aCcsXG4gICd5ZWFyJ1xuXTtcblxuLyoqXG4gKiBDb21wb25lbnQgdGhhdCBwcm92aWRlcyBhbGwgb2YgdGhlIHVzZXIgZmFjaW5nIGZ1bmN0aW9uYWxpdHkgb2YgdGhlIGRhdGUvdGltZSBwaWNrZXIuXG4gKi9cblxuQENvbXBvbmVudCh7XG4gIGNoYW5nZURldGVjdGlvbjogQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3kuT25QdXNoLFxuICBwcmVzZXJ2ZVdoaXRlc3BhY2VzOiBmYWxzZSxcbiAgcHJvdmlkZXJzOiBbXG4gICAge1xuICAgICAgcHJvdmlkZTogTkdfVkFMVUVfQUNDRVNTT1IsXG4gICAgICB1c2VFeGlzdGluZzogRGxEYXRlVGltZVBpY2tlckNvbXBvbmVudCxcbiAgICAgIG11bHRpOiB0cnVlXG4gICAgfVxuICBdLFxuICBzZWxlY3RvcjogJ2RsLWRhdGUtdGltZS1waWNrZXInLFxuICBzdHlsZVVybHM6IFsnLi9kbC1kYXRlLXRpbWUtcGlja2VyLmNvbXBvbmVudC5zY3NzJ10sXG4gIHRlbXBsYXRlVXJsOiAnLi9kbC1kYXRlLXRpbWUtcGlja2VyLmNvbXBvbmVudC5odG1sJyxcbn0pXG5leHBvcnQgY2xhc3MgRGxEYXRlVGltZVBpY2tlckNvbXBvbmVudDxEPiBpbXBsZW1lbnRzIE9uQ2hhbmdlcywgT25Jbml0LCBDb250cm9sVmFsdWVBY2Nlc3NvciB7XG5cbiAgLyoqXG4gICAqIENoYW5nZSBsaXN0ZW5lciBjYWxsYmFjayBmdW5jdGlvbnMgcmVnaXN0ZXJlZFxuICAgKiB2aWEgYHJlZ2lzdGVyT25DaGFuZ2VgXG4gICAqIEBpbnRlcm5hbFxuICAgKiovXG4gIHByaXZhdGUgX2NoYW5nZWQ6ICgodmFsdWU6IEQpID0+IHZvaWQpW10gPSBbXTtcbiAgLyoqXG4gICAqIE1vZGVsIGZvciB0aGUgY3VycmVudCB2aWV3LlxuICAgKlxuICAgKiBAaW50ZXJuYWxcbiAgICoqL1xuICBfbW9kZWw6IERsRGF0ZVRpbWVQaWNrZXJNb2RlbDtcbiAgLyoqXG4gICAqIE1hcHMgdmlldyBuYW1lIHRvIHRoZSBuZXh0IHZpZXcgKHRoZSB2aWV3IGZvciB0aGUgbmV4dCBzbWFsbGVzdCBpbmNyZW1lbnQgb2YgdGltZSkuXG4gICAqIEBpbnRlcm5hbFxuICAgKiovXG4gIHByaXZhdGUgX25leHRWaWV3ID0ge1xuICAgICd5ZWFyJzogJ21vbnRoJyxcbiAgICAnbW9udGgnOiAnZGF5JyxcbiAgICAnZGF5JzogJ2hvdXInLFxuICAgICdob3VyJzogJ21pbnV0ZSdcbiAgfTtcbiAgLyoqXG4gICAqIE1hcHMgdmlldyBuYW1lIHRvIHRoZSBwcmV2aW91cyB2aWV3ICh0aGUgdmlldyBmb3IgdGhlIG5leHQgbGFyZ2VzdCBpbmNyZW1lbnQgb2YgdGltZSkuXG4gICAqIEBpbnRlcm5hbFxuICAgKiovXG4gIHByaXZhdGUgX3ByZXZpb3VzVmlldyA9IHtcbiAgICAnbWludXRlJzogJ2hvdXInLFxuICAgICdob3VyJzogJ2RheScsXG4gICAgJ2RheSc6ICdtb250aCcsXG4gICAgJ21vbnRoJzogJ3llYXInXG4gIH07XG4gIC8qKlxuICAgKiBUb3VjaCBsaXN0ZW5lciBjYWxsYmFjayBmdW5jdGlvbnMgcmVnaXN0ZXJlZFxuICAgKiB2aWEgYHJlZ2lzdGVyT25DaGFuZ2VgXG4gICAqIEBpbnRlcm5hbFxuICAgKiovXG4gIHByaXZhdGUgX3RvdWNoZWQ6ICgoKSA9PiB2b2lkKVtdID0gW107XG4gIC8qKlxuICAgKiBTdG9yZXMgdGhlIHNlbGVjdGVkIHZhbHVlIGZvciB0aGlzIHBpY2tlci5cbiAgICogQGludGVybmFsXG4gICAqKi9cbiAgcHJpdmF0ZSBfdmFsdWU6IEQ7XG4gIC8qKlxuICAgKiBNYXBzIHZpZXcgbmFtZSB0byB0aGUgbW9kZWwgcHJvdmlkZXIgZm9yIHRoYXQgdmlldy5cbiAgICogQGludGVybmFsXG4gICAqKi9cbiAgcHJpdmF0ZSByZWFkb25seSBfdmlld1RvTW9kZWxQcm92aWRlcjoge1xuICAgIHllYXI6IERsTW9kZWxQcm92aWRlcjtcbiAgICBtb250aDogRGxNb2RlbFByb3ZpZGVyO1xuICAgIGRheTogRGxNb2RlbFByb3ZpZGVyO1xuICAgIGhvdXI6IERsTW9kZWxQcm92aWRlcjtcbiAgICBtaW51dGU6IERsTW9kZWxQcm92aWRlcjtcbiAgfTtcbiAgLyoqXG4gICAqIEVtaXRzIHdoZW4gYSBgY2hhbmdlYCBldmVudCB3aGVuIGRhdGUvdGltZSBpcyBzZWxlY3RlZCBvclxuICAgKiB0aGUgdmFsdWUgb2YgdGhlIGRhdGUvdGltZSBwaWNrZXIgY2hhbmdlcy5cbiAgICoqL1xuICBAT3V0cHV0KClcbiAgcmVhZG9ubHkgY2hhbmdlID0gbmV3IEV2ZW50RW1pdHRlcjxEbERhdGVUaW1lUGlja2VyQ2hhbmdlPEQ+PigpO1xuICAvKipcbiAgICogU3BlY2lmaWVzIHRoZSBjbGFzc2VzIHVzZWQgdG8gZGlzcGxheSB0aGUgbGVmdCBpY29uLlxuICAgKlxuICAgKiBUaGlzIGNvbXBvbmVudCB1c2VzIE9QRU5JQ09OSUMgaHR0cHM6Ly91c2VpY29uaWMuY29tL29wZW5cbiAgICogYnkgZGVmYXVsdCBidXQgYW55IGljb24gbGlicmFyeSBtYXkgYmUgdXNlZC5cbiAgICovXG4gIEBJbnB1dCgpXG4gIGxlZnRJY29uQ2xhc3M6IHN0cmluZyB8IHN0cmluZ1tdIHwgU2V0PHN0cmluZz4gfCB7fSA9IFtcbiAgICAnb2knLFxuICAgICdvaS1jaGV2cm9uLWxlZnQnXG4gIF07XG4gIC8qKlxuICAgKiBUaGUgaGlnaGVzdCB2aWV3IHRoYXQgdGhlIGRhdGUvdGltZSBwaWNrZXIgY2FuIHNob3cuXG4gICAqIFNldHRpbmcgdGhpcyB0byBhIHZpZXcgbGVzcyB0aGFuIHllYXIgY291bGQgbWFrZSBpdCBtb3JlXG4gICAqIGRpZmZpY3VsdCBmb3IgdGhlIGVuZC11c2VyIHRvIG5hdmlnYXRlIHRvIGNlcnRhaW4gZGF0ZXMuXG4gICAqL1xuICBASW5wdXQoKVxuICBtYXhWaWV3OiAneWVhcicgfCAnbW9udGgnIHwgJ2RheScgfCAnaG91cicgfCAnbWludXRlJyA9ICd5ZWFyJztcbiAgLyoqXG4gICAqIFRoZSB2aWV3IHRoYXQgd2lsbCBiZSB1c2VkIGZvciBkYXRlL3RpbWUgc2VsZWN0aW9uLlxuICAgKlxuICAgKiBUaGUgZGVmYXVsdCBvZiBgbWludXRlICBtZWFucyB0aGF0IHNlbGVjdGlvbiB3aWxsIG5vdCBoYXBwZW5cbiAgICogdW50aWwgdGhlIGVuZC11c2VyIGNsaWNrcyBvbiBhIGNlbGwgaW4gdGhlIG1pbnV0ZSB2aWV3LlxuICAgKlxuICAgKiBmb3IgZXhhbXBsZSwgaWYgeW91IHdhbnQgdGhlIGVuZC11c2VyIHRvIHNlbGVjdCBhIG9ubHkgZGF5IChkYXRlKSxcbiAgICogc2V0dGluZyBgbWluVmlld2AgdG8gYGRheWAgd2lsbCBjYXVzZSBzZWxlY3Rpb24gdG8gaGFwcGVuIHdoZW4gdGhlXG4gICAqIGVuZC11c2VyIHNlbGVjdHMgYSBjZWxsIGluIHRoZSBkYXkgdmlldy5cbiAgICpcbiAgICogTk9URTogVGhpcyBtdXN0IGJlIHNldCBsb3dlciB0aGFuIG9yIGVxdWFsIHRvIGBzdGFydFZpZXcnXG4gICAqL1xuICBASW5wdXQoKVxuICBtaW5WaWV3OiAneWVhcicgfCAnbW9udGgnIHwgJ2RheScgfCAnaG91cicgfCAnbWludXRlJyA9ICdtaW51dGUnO1xuICAvKipcbiAgICogVGhlIG51bWJlciBvZiBtaW51dGVzIGJldHdlZW4gZWFjaCBgLmRsLWFiZHRwLW1pbnV0ZWAgYnV0dG9uLlxuICAgKlxuICAgKiBNdXN0IGJlIGdyZWF0ZXIgdGhhbiBgMGAgYW5kIGxlc3MgdGhhbiBgNjBgLlxuICAgKi9cbiAgQElucHV0KClcbiAgbWludXRlU3RlcCA9IDU7XG4gIC8qKlxuICAgKiBTcGVjaWZpZXMgdGhlIGNsYXNzZXMgdXNlZCB0byBkaXNwbGF5IHRoZSByaWdodCBpY29uLlxuICAgKlxuICAgKiBUaGlzIGNvbXBvbmVudCB1c2VzIE9QRU5JQ09OSUMgaHR0cHM6Ly91c2VpY29uaWMuY29tL29wZW5cbiAgICogYnkgZGVmYXVsdCBidXQgYW55IGljb24gbGlicmFyeSBtYXkgYmUgdXNlZC5cbiAgICovXG4gIEBJbnB1dCgpXG4gIHJpZ2h0SWNvbkNsYXNzID0gW1xuICAgICdvaScsXG4gICAgJ29pLWNoZXZyb24tcmlnaHQnXG4gIF07XG5cbiAgLyogdHNsaW50OmRpc2FibGU6bWVtYmVyLW9yZGVyaW5nICovXG4gIC8qKlxuICAgKiAgRGV0ZXJtaW5lIHdoZXRoZXIgb3Igbm90IHRoZSBgRGF0ZUJ1dHRvbmAgaXMgc2VsZWN0YWJsZSBieSB0aGUgZW5kIHVzZXIuXG4gICAqL1xuICBASW5wdXQoKVxuICBzZWxlY3RGaWx0ZXI6IChkYXRlQnV0dG9uOiBEYXRlQnV0dG9uLCB2aWV3TmFtZTogc3RyaW5nKSA9PiBib29sZWFuID0gKCkgPT4gdHJ1ZVxuXG4gIC8qKlxuICAgKiAgU3RhcnQgYXQgdGhlIHZpZXcgY29udGFpbmluZyBzdGFydERhdGUgd2hlbiBubyB2YWx1ZSBpcyBzZWxlY3RlZC5cbiAgICovXG4gIEBJbnB1dCgpXG4gIHN0YXJ0RGF0ZTogbnVtYmVyO1xuXG4gIC8qKlxuICAgKiBUaGUgaW5pdGlhbCB2aWV3IHRoYXQgdGhlIGRhdGUvdGltZSBwaWNrZXIgd2lsbCBzaG93LlxuICAgKiBUaGUgcGlja2VyIHdpbGwgYWxzbyByZXR1cm4gdG8gdGhpcyB2aWV3IGFmdGVyIGEgZGF0ZS90aW1lXG4gICAqIGlzIHNlbGVjdGVkLlxuICAgKlxuICAgKiBOT1RFOiBUaGlzIG11c3QgYmUgc2V0IGxvd2VyIHRoYW4gb3IgZXF1YWwgdG8gYG1heFZpZXcnXG4gICAqL1xuICBASW5wdXQoKVxuICBzdGFydFZpZXc6ICd5ZWFyJyB8ICdtb250aCcgfCAnZGF5JyB8ICdob3VyJyB8ICdtaW51dGUnID0gJ2RheSc7XG5cbiAgLyoqXG4gICAqIFNwZWNpZmllcyB0aGUgY2xhc3NlcyB1c2VkIHRvIGRpc3BsYXkgdGhlIHVwIGljb24uXG4gICAqXG4gICAqIFRoaXMgY29tcG9uZW50IHVzZXMgT1BFTklDT05JQyBodHRwczovL3VzZWljb25pYy5jb20vb3BlblxuICAgKiBieSBkZWZhdWx0IGJ1dCBhbnkgaWNvbiBsaWJyYXJ5IG1heSBiZSB1c2VkLlxuICAgKi9cbiAgQElucHV0KClcbiAgdXBJY29uQ2xhc3MgPSBbXG4gICAgJ29pJyxcbiAgICAnb2ktY2hldnJvbi10b3AnXG4gIF07XG5cbiAgLyoqXG4gICAqIFVzZWQgdG8gY29uc3RydWN0IGEgbmV3IGluc3RhbmNlIG9mIGEgZGF0ZS90aW1lIHBpY2tlci5cbiAgICpcbiAgICogQHBhcmFtIF9lbGVtZW50UmVmXG4gICAqICByZWZlcmVuY2UgdG8gdGhpcyBlbGVtZW50LlxuICAgKiBAcGFyYW0gX25nWm9uZVxuICAgKiAgcmVmZXJlbmNlIHRvIGFuIE5nWm9uZSBpbnN0YW5jZSB1c2VkIHRvIHNlbGVjdCB0aGUgYWN0aXZlIGVsZW1lbnQgb3V0c2lkZSBvZiBhbmd1bGFyLlxuICAgKiBAcGFyYW0gX2RhdGVBZGFwdGVyXG4gICAqICBkYXRlIGFkYXB0ZXIgZm9yIHRoZSBkYXRlIHR5cGUgaW4gdGhlIG1vZGVsLlxuICAgKiBAcGFyYW0geWVhck1vZGVsQ29tcG9uZW50XG4gICAqICBwcm92aWRlciBmb3IgdGhlIHllYXIgdmlldyBtb2RlbC5cbiAgICogQHBhcmFtIG1vbnRoTW9kZWxDb21wb25lbnRcbiAgICogIHByb3ZpZGVyIGZvciB0aGUgbW9udGggdmlldyBtb2RlbC5cbiAgICogQHBhcmFtIGRheU1vZGVsQ29tcG9uZW50XG4gICAqICBwcm92aWRlciBmb3IgdGhlIGRheSB2aWV3IG1vZGVsLlxuICAgKiBAcGFyYW0gaG91ck1vZGVsQ29tcG9uZW50XG4gICAqICBwcm92aWRlciBmb3IgdGhlIGhvdXIgdmlldyBtb2RlbC5cbiAgICogQHBhcmFtIG1pbnV0ZU1vZGVsQ29tcG9uZW50XG4gICAqICBwcm92aWRlciBmb3IgdGhlIG1pbnV0ZSB2aWV3IG1vZGVsLlxuICAgKi9cbiAgY29uc3RydWN0b3IocHJpdmF0ZSBfZWxlbWVudFJlZjogRWxlbWVudFJlZixcbiAgICAgICAgICAgICAgcHJpdmF0ZSBfbmdab25lOiBOZ1pvbmUsXG4gICAgICAgICAgICAgIHByaXZhdGUgX2RhdGVBZGFwdGVyOiBEbERhdGVBZGFwdGVyPEQ+LFxuICAgICAgICAgICAgICAvLyBAdHMtaWdub3JlXG4gICAgICAgICAgICAgIHByaXZhdGUgeWVhck1vZGVsQ29tcG9uZW50OiBEbFllYXJNb2RlbFByb3ZpZGVyLFxuICAgICAgICAgICAgICAvLyBAdHMtaWdub3JlXG4gICAgICAgICAgICAgIHByaXZhdGUgbW9udGhNb2RlbENvbXBvbmVudDogRGxNb250aE1vZGVsUHJvdmlkZXIsXG4gICAgICAgICAgICAgIC8vIEB0cy1pZ25vcmVcbiAgICAgICAgICAgICAgcHJpdmF0ZSBkYXlNb2RlbENvbXBvbmVudDogRGxEYXlNb2RlbFByb3ZpZGVyLFxuICAgICAgICAgICAgICAvLyBAdHMtaWdub3JlXG4gICAgICAgICAgICAgIHByaXZhdGUgaG91ck1vZGVsQ29tcG9uZW50OiBEbEhvdXJNb2RlbFByb3ZpZGVyLFxuICAgICAgICAgICAgICAvLyBAdHMtaWdub3JlXG4gICAgICAgICAgICAgIHByaXZhdGUgbWludXRlTW9kZWxDb21wb25lbnQ6IERsTWludXRlTW9kZWxQcm92aWRlcikge1xuXG4gICAgdGhpcy5fdmlld1RvTW9kZWxQcm92aWRlciA9IHtcbiAgICAgIHllYXI6IHllYXJNb2RlbENvbXBvbmVudCxcbiAgICAgIG1vbnRoOiBtb250aE1vZGVsQ29tcG9uZW50LFxuICAgICAgZGF5OiBkYXlNb2RlbENvbXBvbmVudCxcbiAgICAgIGhvdXI6IGhvdXJNb2RlbENvbXBvbmVudCxcbiAgICAgIG1pbnV0ZTogbWludXRlTW9kZWxDb21wb25lbnQsXG4gICAgfTtcbiAgfVxuXG4gIC8qIHRzbGludDplbmFibGU6bWVtYmVyLW9yZGVyaW5nICovXG4gIC8qKlxuICAgKiBTZXQncyB0aGUgbW9kZWwgZm9yIHRoZSBjdXJyZW50IHZpZXcgYWZ0ZXIgYXBwbHlpbmcgdGhlIHNlbGVjdGlvbiBmaWx0ZXIuXG4gICAqXG4gICAqIEBpbnRlcm5hbFxuICAgKiovXG4gIHByaXZhdGUgc2V0IG1vZGVsKG1vZGVsOiBEbERhdGVUaW1lUGlja2VyTW9kZWwpIHtcbiAgICB0aGlzLl9tb2RlbCA9IHRoaXMuYXBwbHlTZWxlY3RGaWx0ZXIobW9kZWwpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgYERgIHZhbHVlIG9mIHRoZSBkYXRlL3RpbWUgcGlja2VyIG9yIHVuZGVmaW5lZC9udWxsIGlmIG5vIHZhbHVlIGlzIHNldC5cbiAgICoqL1xuICBnZXQgdmFsdWUoKTogRCB7XG4gICAgcmV0dXJuIHRoaXMuX3ZhbHVlO1xuICB9XG5cbiAgLyoqXG4gICAqIFNldHMgdmFsdWUgb2YgdGhlIGRhdGUvdGltZSBwaWNrZXIgYW5kIGVtaXRzIGEgY2hhbmdlIGV2ZW50IGlmIHRoZVxuICAgKiBuZXcgdmFsdWUgaXMgZGlmZmVyZW50IGZyb20gdGhlIHByZXZpb3VzIHZhbHVlLlxuICAgKiovXG4gIHNldCB2YWx1ZSh2YWx1ZTogRCkge1xuICAgIGlmICh0aGlzLl92YWx1ZSAhPT0gdmFsdWUpIHtcbiAgICAgIHRoaXMuX3ZhbHVlID0gdmFsdWU7XG4gICAgICB0aGlzLm1vZGVsID0gdGhpcy5fdmlld1RvTW9kZWxQcm92aWRlclt0aGlzLl9tb2RlbC52aWV3TmFtZV0uZ2V0TW9kZWwodGhpcy5nZXRTdGFydERhdGUoKSwgdGhpcy52YWx1ZU9mKTtcbiAgICAgIHRoaXMuX2NoYW5nZWQuZm9yRWFjaChmID0+IGYodmFsdWUpKTtcbiAgICAgIHRoaXMuY2hhbmdlLmVtaXQobmV3IERsRGF0ZVRpbWVQaWNrZXJDaGFuZ2U8RD4odmFsdWUpKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyBgbWlsbGlzZWNvbmRzYCB2YWx1ZSBvZiB0aGUgZGF0ZS90aW1lIHBpY2tlciBvciB1bmRlZmluZWQvbnVsbCBpZiBubyB2YWx1ZSBpcyBzZXQuXG4gICAqKi9cbiAgZ2V0IHZhbHVlT2YoKTogbnVtYmVyIHwgbnVsbCB7XG4gICAgcmV0dXJuIHRoaXMuX2RhdGVBZGFwdGVyLnRvTWlsbGlzZWNvbmRzKHRoaXMuX3ZhbHVlKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBcHBsaWVzIHRoZSBgc2VsZWN0aW9uRmlsdGVyYCBieSBhZGRpbmcgdGhlIGBkbC1hYmR0cC1kaXNhYmxlZGBcbiAgICogY2xhc3MgdG8gYW55IGBEYXRlQnV0dG9uYCB3aGVyZSBgc2VsZWN0RmlsdGVyYCByZXR1cm5lZCBmYWxzZS5cbiAgICpcbiAgICogQHBhcmFtIG1vZGVsXG4gICAqICB0aGUgbmV3IG1vZGVsXG4gICAqXG4gICAqIEByZXR1cm5zXG4gICAqICB0aGUgc3VwcGxpZWQgbW9kZWwgd2l0aCB6ZXJvIG9yIG1vcmUgYERhdGVCdXR0b25gJ3NcbiAgICogIGhhdmluZyB0aGUgYGRsLWFiZHRwLWRpc2FibGVkYCBjbGFzcyBzZXQgdG8gYHRydWVgIGlmIHRoZVxuICAgKiAgc2VsZWN0aW9uIGZvciB0aGF0IGRhdGUgc2hvdWxkIGJlIGRpc2FibGVkLlxuICAgKlxuICAgKiBAaW50ZXJuYWxcbiAgICovXG4gIHByaXZhdGUgYXBwbHlTZWxlY3RGaWx0ZXIobW9kZWw6IERsRGF0ZVRpbWVQaWNrZXJNb2RlbCk6IERsRGF0ZVRpbWVQaWNrZXJNb2RlbCB7XG4gICAgaWYgKHRoaXMuc2VsZWN0RmlsdGVyKSB7XG4gICAgICBtb2RlbC5yb3dzID0gbW9kZWwucm93cy5tYXAoKHJvdykgPT4ge1xuICAgICAgICByb3cuY2VsbHMubWFwKChkYXRlQnV0dG9uOiBEYXRlQnV0dG9uKSA9PiB7XG4gICAgICAgICAgY29uc3QgZGlzYWJsZWQgPSAhdGhpcy5zZWxlY3RGaWx0ZXIoZGF0ZUJ1dHRvbiwgbW9kZWwudmlld05hbWUpO1xuICAgICAgICAgIGRhdGVCdXR0b24uY2xhc3Nlc1snZGwtYWJkdHAtZGlzYWJsZWQnXSA9IGRpc2FibGVkO1xuICAgICAgICAgIGlmIChkaXNhYmxlZCkge1xuICAgICAgICAgICAgZGF0ZUJ1dHRvbi5jbGFzc2VzWydhcmlhLWRpc2FibGVkJ10gPSB0cnVlO1xuICAgICAgICAgIH1cbiAgICAgICAgICByZXR1cm4gZGF0ZUJ1dHRvbjtcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybiByb3c7XG4gICAgICB9KTtcbiAgICB9XG5cbiAgICByZXR1cm4gbW9kZWw7XG4gIH1cblxuICAvKipcbiAgICogRm9jdXNlcyB0aGUgYC5kbC1hYmR0cC1hY3RpdmVgIGNlbGwgYWZ0ZXIgdGhlIG1pY3JvdGFzayBxdWV1ZSBpcyBlbXB0eS5cbiAgICogQGludGVybmFsXG4gICAqKi9cbiAgcHJpdmF0ZSBmb2N1c0FjdGl2ZUNlbGwoKSB7XG4gICAgdGhpcy5fbmdab25lLnJ1bk91dHNpZGVBbmd1bGFyKCgpID0+IHtcbiAgICAgIHRoaXMuX25nWm9uZS5vblN0YWJsZS5hc09ic2VydmFibGUoKS5waXBlKHRha2UoMSkpLnN1YnNjcmliZSgoKSA9PiB7XG4gICAgICAgIHRoaXMuX2VsZW1lbnRSZWYubmF0aXZlRWxlbWVudC5xdWVyeVNlbGVjdG9yKCcuZGwtYWJkdHAtYWN0aXZlJykuZm9jdXMoKTtcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIERldGVybWluZXMgdGhlIHN0YXJ0IGRhdGUgZm9yIHRoZSBwaWNrZXIuXG4gICAqIEBpbnRlcm5hbFxuICAgKiovXG4gIHByaXZhdGUgZ2V0U3RhcnREYXRlKCkge1xuICAgIGlmIChoYXNWYWx1ZSh0aGlzLl92YWx1ZSkpIHtcbiAgICAgIHJldHVybiB0aGlzLl9kYXRlQWRhcHRlci50b01pbGxpc2Vjb25kcyh0aGlzLl92YWx1ZSk7XG4gICAgfVxuICAgIGlmIChoYXNWYWx1ZSh0aGlzLnN0YXJ0RGF0ZSkpIHtcbiAgICAgIHJldHVybiB0aGlzLnN0YXJ0RGF0ZTtcbiAgICB9XG4gICAgcmV0dXJuIG1vbWVudCgpLnZhbHVlT2YoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBEZXRlcm1pbmUgdGhlIHN0YXJ0IHZpZXcgZm9yIHRoZSBwaWNrZXJcbiAgICogQHJldHVybnNcbiAgICogIHRoZSBsYXJnZXN0IHRpbWUgaW5jcmVtZW50IHZpZXcgYmV0d2VlbiB0aGUgYG1pblZpZXdgIG9yIGBtaW51dGVgIHZpZXcgYW5kIHRoZSBgc3RhcnRWaWV3YCBvciBgZGF5YCB2aWV3LlxuICAgKi9cbiAgcHJpdmF0ZSBnZXRTdGFydFZpZXcoKTogc3RyaW5nIHtcbiAgICBjb25zdCBzdGFydEluZGV4ID0gTWF0aC5tYXgoVklFV1MuaW5kZXhPZih0aGlzLm1pblZpZXcgfHwgJ21pbnV0ZScpLCBWSUVXUy5pbmRleE9mKHRoaXMuc3RhcnRWaWV3IHx8ICdkYXknKSk7XG4gICAgcmV0dXJuIFZJRVdTW3N0YXJ0SW5kZXhdO1xuICB9XG5cbiAgLyoqXG4gICAqIENhbGxzIGFsbCByZWdpc3RlcmVkIGB0b3VjaGAgY2FsbGJhY2sgZnVuY3Rpb25zLlxuICAgKiBAaW50ZXJuYWxcbiAgICoqL1xuICBwcml2YXRlIG9uVG91Y2goKSB7XG4gICAgdGhpcy5fdG91Y2hlZC5mb3JFYWNoKChvblRvdWNoZWQpID0+IG9uVG91Y2hlZCgpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZWNlaXZlcyBjb25maWd1cmF0aW9uIGNoYW5nZXMgZGV0ZWN0ZWQgYnkgQW5ndWxhciBhbmQgcGFzc2VzIHRoZSBjaGFuZ2VzIG9uXG4gICAqIHRvIHRoZSBtb2RlbCBwcm92aWRlcnMgc28gdGhlIHByb3ZpZGVyIGlzIGF3YXJlIG9mIGFueSBuZWNlc3NhcnkgY29uZmlndXJhdGlvblxuICAgKiBjaGFuZ2VzIChpLmUuIG1pbnV0ZVN0ZXApXG4gICAqXG4gICAqIEBwYXJhbSBjaGFuZ2VzXG4gICAqICB0aGUgaW5wdXQgY2hhbmdlcyBkZXRlY3RlZCBieSBBbmd1bGFyLlxuICAgKi9cbiAgbmdPbkNoYW5nZXMoY2hhbmdlczogU2ltcGxlQ2hhbmdlcyk6IHZvaWQge1xuICAgIE9iamVjdC52YWx1ZXModGhpcy5fdmlld1RvTW9kZWxQcm92aWRlcikuZm9yRWFjaCgocHJvdmlkZXI6IERsTW9kZWxQcm92aWRlcikgPT4gcHJvdmlkZXIub25DaGFuZ2VzKGNoYW5nZXMpKTtcblxuICAgIGlmICh0aGlzLl9tb2RlbCkgeyAvLyBvbmx5IHVwZGF0ZSB0aGUgbW9kZWwgYWZ0ZXIgbmdPbkluaXQgaGFzIHNldCBpdCB0aGUgZmlyc3QgdGltZS5cbiAgICAgIHRoaXMubW9kZWwgPSB0aGlzLl92aWV3VG9Nb2RlbFByb3ZpZGVyW3RoaXMuX21vZGVsLnZpZXdOYW1lXS5nZXRNb2RlbCh0aGlzLl9tb2RlbC5hY3RpdmVEYXRlLCB0aGlzLnZhbHVlT2YpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBTZXRzIHRoZSBpbml0aWFsIG1vZGVsLlxuICAgKlxuICAgKiBAaW50ZXJuYWxcbiAgICoqL1xuICBuZ09uSW5pdCgpOiB2b2lkIHtcbiAgICB0aGlzLm1vZGVsID0gdGhpcy5fdmlld1RvTW9kZWxQcm92aWRlclt0aGlzLmdldFN0YXJ0VmlldygpXS5nZXRNb2RlbCh0aGlzLmdldFN0YXJ0RGF0ZSgpLCB0aGlzLnZhbHVlT2YpO1xuICB9XG5cbiAgLyoqXG4gICAqIEhhbmRsZXMgY2xpY2sgKGFuZCBlbnRlciAmIHNwYWNlIGtleSBkb3duKSBldmVudHMgb24gdGhlIGRhdGUgZWxlbWVudHMuXG4gICAqXG4gICAqIElmIHRoZSBjdXJyZW50IHZpZXcgaXMgdGhlIG1pbmltdW0gdmlldyB0aGVuIHRoZSBkYXRlIHZhbHVlIGlzIHNlbGVjdGVkXG4gICAqIGFuZCB0aGUgcGlja2VyIHJldHVybnMgdG8gdGhlIHN0YXJ0IHZpZXcuXG4gICAqXG4gICAqIE90aGVyd2lzZSB0aGUgcGlja2VyIGRpc3BsYXlzIHRoZSBuZXh0IHZpZXcgd2l0aCB0aGUgbmV4dFxuICAgKiBzbWFsbGVzdCB0aW1lIGluY3JlbWVudC5cbiAgICpcbiAgICogQGludGVybmFsXG4gICAqKi9cbiAgX29uRGF0ZUNsaWNrKGRhdGVCdXR0b246IERhdGVCdXR0b24pIHtcbiAgICBpZiAoZGF0ZUJ1dHRvbi5jbGFzc2VzWydkbC1hYmR0cC1kaXNhYmxlZCddKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgbGV0IG5leHRWaWV3ID0gdG