UNPKG

@nova-ui/bits

Version:

SolarWinds Nova Framework

326 lines 52.9 kB
import { ChangeDetectorRef, Component, ElementRef, EventEmitter, forwardRef, HostListener, Input, Output, ViewChild, ViewEncapsulation, } from "@angular/core"; import { NG_VALUE_ACCESSOR } from "@angular/forms"; import _isEmpty from "lodash/isEmpty"; import _isNil from "lodash/isNil"; import moment from "moment/moment"; import { Subject } from "rxjs"; import { debounceTime, takeUntil } from "rxjs/operators"; import { TimePickerKeyboardService } from "./time-picker-keyboard.service"; import { NuiFormFieldControl } from "../form-field/public-api"; import { MenuPopupComponent } from "../menu"; import { OVERLAY_WITH_POPUP_STYLES_CLASS } from "../overlay/constants"; import { OverlayComponent } from "../overlay/overlay-component/overlay.component"; import { OverlayUtilitiesService } from "../overlay/overlay-utilities.service"; import { TextboxComponent } from "../textbox/textbox.component"; import * as i0 from "@angular/core"; import * as i1 from "./time-picker-keyboard.service"; import * as i2 from "../textbox/textbox.component"; import * as i3 from "../icon/icon.component"; import * as i4 from "../overlay/overlay-component/overlay.component"; import * as i5 from "../menu/menu-popup/menu-popup.component"; // <example-url>./../examples/index.html#/time-picker</example-url><br /> export class TimePickerComponent { get model() { return this.innerModel; } set model(value) { if (!moment(value).isValid()) { return; } if (value && !this.preserveInsignificant) { value.year(0).month(0).date(0); } this.innerModel = value; this.textbox.writeValue(moment(this.innerModel).format(this.timeFormat)); } constructor(elementRef, keyboardService, cdr) { this.elementRef = elementRef; this.keyboardService = keyboardService; this.cdr = cdr; /** sets a step (difference between item in picker) */ this.timeStep = 30; /** sets custom formatting for time */ this.timeFormat = "LT"; /** tells timepicker whether to save year, month, day and seconds of the date */ this.preserveInsignificant = false; /** to apply error state styles */ this.isInErrorState = false; /** Input to set aria label text */ this.ariaLabel = "Time Picker"; /** Allows popup box to be attached to document.body */ this.appendToBody = false; this.timeChanged = new EventEmitter(); this.inputBlurred = new EventEmitter(); this.itemsSource = [ { itemsSource: [], }, ]; this.overlayConfig = { panelClass: [OVERLAY_WITH_POPUP_STYLES_CLASS, "nui-timepicker__menu"], }; this.onDestroy$ = new Subject(); this.popupUtilities = new OverlayUtilitiesService(); this.inputChanged = new Subject(); } ngOnInit() { this.times = this.generateTimeItems(this.timeStep); this.times.map((value) => { this.itemsSource[0].itemsSource.push({ title: value, displayFormat: this.timeFormat, isSelected: false, }); }); if (!this.initEmpty) { this.innerModel = moment(this.model).clone() || moment(); this.textbox.writeValue(moment(this.innerModel).format(this.timeFormat)); } this.itemToSelect = this.getItemToSelect(); this.inputChanged.pipe(debounceTime(500)).subscribe((value) => { this.updateInnerModel(value); this.itemToSelect = this.getItemToSelect(); this.timeChanged.emit(this.innerModel); this.onChange(this.innerModel); this.setErrorState(value); }); this.onAppendToBodyChange(this.appendToBody); } ngOnChanges(changes) { if (changes.appendToBody) { this.onAppendToBodyChange(changes.appendToBody.currentValue); } } ngAfterViewInit() { this.overlay.clickOutside .pipe(takeUntil(this.onDestroy$)) .subscribe((_) => this.overlay.hide()); this.initPopupUtilities(); this.keyboardService.initService(this.popup, this.overlay, this.menuTrigger.nativeElement); this.cdr.detectChanges(); } onChange(value) { } onTouched() { } onKeyDown(event) { this.keyboardService.onKeyDown(event); } onFocusOut(event) { if (!this.overlay.showing || !document.activeElement) { return; } if (this.popupArea.nativeElement.contains(event.relatedTarget)) { return; } if (!this.containerEl.nativeElement.contains(event.relatedTarget)) { this.overlay.hide(); } } updateInnerModel(value) { setTimeout(() => this.inputBlurred.emit(), 100); if (value instanceof moment && !this.preserveInsignificant) { value.year(0); value.date(1); value.month(0); value.seconds(0); } this.innerModel = _isEmpty(value) || value.length === 0 ? undefined : moment(value, this.timeFormat); if (!moment(this.innerModel).isValid()) { this.innerModel = value; } this.onTouched(); if (!_isEmpty(this.times) && !_isEmpty(this.innerModel) && !_isNil(this.innerModel)) { const index = this.getItemIndexToSelect(this.innerModel, this.timeStep, this.times); this.unselectAllItems(); if (isFinite(index)) { this.itemsSource[0].itemsSource[index].isSelected = true; this.itemToSelect = this.itemsSource[0].itemsSource[index]; } } this.setErrorState(value); } writeValue(value) { this.textbox.writeValue(this.formatValue(value)); this.updateInnerModel(this.formatValue(value)); } setErrorState(value) { this.isInErrorState = !moment(value, this.timeFormat, true).isValid(); } registerOnChange(fn) { this.onChange = fn; } registerOnTouched(fn) { this.onTouched = fn; } setDisabledState(isDisabled) { this.isDisabled = isDisabled; } focusOnForm() { this.textbox.focus(); } onInputActiveDateChanged(value) { this.inputChanged.next(value); } select(time) { this.updateInnerModel(time.title); this.textbox.writeValue(this.formatValue()); this.timeChanged.emit(this.innerModel); this.onChange(this.innerModel); this.overlay.hide(); } scrollToView() { if (!this.isDisabled) { this.overlay.toggle(); } const selectedItem = this.elementRef.nativeElement.getElementsByClassName("nui-menu-item--selected")[0]; selectedItem?.scrollIntoView({ block: "center" }); } generateTimeItems(timeStep) { const time = this.preserveInsignificant ? moment().hour(0).startOf("hour") : moment().year(0).startOf("year"); const initialDay = time.dayOfYear(); const times = []; while (time.dayOfYear() === initialDay) { times.push(time.clone()); time.add(timeStep, "minute"); } return times; } isItemSelected(timeItem) { return moment(timeItem).isSame(this.itemToSelect.title); } getItemIndexToSelect(model, timeStep, times) { const time = moment(model); const minutes = time.get("hours") * 60 + time.get("minutes"); const index = Math.round(minutes / timeStep); return index === times.length ? 0 : index; } getItemToSelect() { if (_isEmpty(this.innerModel) || _isNil(this.innerModel)) { this.unselectAllItems(); return; } const index = this.getItemIndexToSelect(this.innerModel, this.timeStep, this.times); this.unselectAllItems(); if (isFinite(index)) { this.itemsSource[0].itemsSource[index].isSelected = true; return this.itemsSource[0].itemsSource[index]; } } unselectAllItems() { this.itemsSource[0].itemsSource.forEach((el) => (el.isSelected = false)); } formatValue(value = this.innerModel) { return moment(value).isValid() ? moment(value).format(this.timeFormat) : value; } getIconColor() { return this.isDisabled ? "gray" : "primary-blue"; } onAppendToBodyChange(appendToBody) { this.customContainer = appendToBody ? undefined : this.popupArea; } initPopupUtilities() { const resizeObserver = this.popupUtilities .setPopupComponent(this.overlay) .getResizeObserver(); this.overlay.show$.pipe(takeUntil(this.onDestroy$)).subscribe(() => { this.popupUtilities.syncWidth(); resizeObserver.observe(this.elementRef.nativeElement); }); this.overlay.hide$.pipe(takeUntil(this.onDestroy$)).subscribe(() => { resizeObserver.unobserve(this.elementRef.nativeElement); }); } ngOnDestroy() { if (this.overlay?.showing) { this.overlay.hide(); } this.onDestroy$.next(); this.onDestroy$.complete(); this.inputChanged.unsubscribe(); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TimePickerComponent, deps: [{ token: i0.ElementRef }, { token: i1.TimePickerKeyboardService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: TimePickerComponent, selector: "nui-time-picker", inputs: { timeStep: "timeStep", isDisabled: "isDisabled", timeFormat: "timeFormat", preserveInsignificant: "preserveInsignificant", isInErrorState: "isInErrorState", ariaLabel: "ariaLabel", initEmpty: "initEmpty", appendToBody: "appendToBody", model: "model" }, outputs: { timeChanged: "timeChanged", inputBlurred: "inputBlurred" }, host: { listeners: { "keydown": "onKeyDown($event)", "focusout": "onFocusOut($event)" } }, providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => TimePickerComponent), multi: true, }, { provide: NuiFormFieldControl, useExisting: forwardRef(() => TimePickerComponent), multi: true, }, TimePickerKeyboardService, ], viewQueries: [{ propertyName: "textbox", first: true, predicate: ["date"], descendants: true, static: true }, { propertyName: "popupArea", first: true, predicate: ["popupArea"], descendants: true, static: true }, { propertyName: "containerEl", first: true, predicate: ["toggleRef"], descendants: true, static: true }, { propertyName: "overlay", first: true, predicate: OverlayComponent, descendants: true }, { propertyName: "popup", first: true, predicate: ["popup"], descendants: true }, { propertyName: "menuTrigger", first: true, predicate: ["menuTrigger"], descendants: true, read: ElementRef }], usesOnChanges: true, ngImport: i0, template: "<div class=\"nui-timepicker\">\n <div class=\"nui-timepicker__container\" (click)=\"scrollToView()\" #toggleRef>\n <nui-textbox\n [disabled]=\"isDisabled\"\n autocomplete=\"off\"\n [class.nui-timepicker__input-disabled]=\"isDisabled\"\n #date\n [isInErrorState]=\"isInErrorState\"\n (textChange)=\"onInputActiveDateChanged($event)\"\n (blurred)=\"updateInnerModel($event)\"\n [ariaLabel]=\"ariaLabel\"\n >\n </nui-textbox>\n <nui-icon\n #menuTrigger\n class=\"nui-timepicker__icon\"\n icon=\"clock\"\n tabindex=\"0\"\n (click)=\"focusOnForm()\"\n [iconColor]=\"getIconColor()\"\n >\n </nui-icon>\n </div>\n\n <div #popupArea></div>\n\n <nui-overlay\n #overlay\n [toggleReference]=\"toggleRef\"\n [overlayConfig]=\"overlayConfig\"\n [customContainer]=\"customContainer\"\n >\n <nui-menu-popup\n #popup\n [itemsSource]=\"itemsSource\"\n (menuItemClicked)=\"select($event)\"\n >\n </nui-menu-popup>\n </nui-overlay>\n</div>\n", styles: [".nui .nui-timepicker__container{width:135px;height:30px;position:relative}.nui .nui-timepicker__icon{cursor:pointer;position:absolute;top:7px;right:7px;z-index:501}.nui .nui-timepicker__icon:focus{border-radius:3px;outline:none;box-shadow:0 0 0 2px #00c4d280}.nui .nui-timepicker__menu{background-color:var(--nui-color-bg-content_popover,#fff);box-shadow:0 0 5px 0 var(--nui-shadow-color, rgba(17, 17, 17, .3));max-height:300px;overflow-y:auto;min-width:135px;text-align:left}.nui .nui-timepicker__input-disabled+.nui-timepicker__icon{pointer-events:auto;cursor:not-allowed}.nui .nui-timepicker .nui-popup-container{display:inline-flex}.nui .nui-timepicker .nui-textbox .has-feedback .nui-textbox__input{line-height:14px}\n"], dependencies: [{ kind: "component", type: i2.TextboxComponent, selector: "nui-textbox", inputs: ["caption", "autocomplete", "info", "customBoxWidth", "disabled", "hint", "name", "placeholder", "readonly", "rows", "type", "value", "isInErrorState", "ariaLabel", "isBusy"], outputs: ["textChange", "blurred"] }, { kind: "component", type: i3.IconComponent, selector: "nui-icon", inputs: ["iconColor", "brushType", "iconHoverColor", "iconSize", "cssClass", "fillContainer", "status", "childStatus", "icon", "counter"] }, { kind: "component", type: i4.OverlayComponent, selector: "nui-overlay", inputs: ["overlayConfig", "toggleReference", "viewportMargin", "customContainer", "roleAttr"], outputs: ["clickOutside"] }, { kind: "component", type: i5.MenuPopupComponent, selector: "nui-menu-popup", inputs: ["itemsSource", "size"], outputs: ["menuItemClicked"] }], encapsulation: i0.ViewEncapsulation.None }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TimePickerComponent, decorators: [{ type: Component, args: [{ selector: "nui-time-picker", providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => TimePickerComponent), multi: true, }, { provide: NuiFormFieldControl, useExisting: forwardRef(() => TimePickerComponent), multi: true, }, TimePickerKeyboardService, ], encapsulation: ViewEncapsulation.None, template: "<div class=\"nui-timepicker\">\n <div class=\"nui-timepicker__container\" (click)=\"scrollToView()\" #toggleRef>\n <nui-textbox\n [disabled]=\"isDisabled\"\n autocomplete=\"off\"\n [class.nui-timepicker__input-disabled]=\"isDisabled\"\n #date\n [isInErrorState]=\"isInErrorState\"\n (textChange)=\"onInputActiveDateChanged($event)\"\n (blurred)=\"updateInnerModel($event)\"\n [ariaLabel]=\"ariaLabel\"\n >\n </nui-textbox>\n <nui-icon\n #menuTrigger\n class=\"nui-timepicker__icon\"\n icon=\"clock\"\n tabindex=\"0\"\n (click)=\"focusOnForm()\"\n [iconColor]=\"getIconColor()\"\n >\n </nui-icon>\n </div>\n\n <div #popupArea></div>\n\n <nui-overlay\n #overlay\n [toggleReference]=\"toggleRef\"\n [overlayConfig]=\"overlayConfig\"\n [customContainer]=\"customContainer\"\n >\n <nui-menu-popup\n #popup\n [itemsSource]=\"itemsSource\"\n (menuItemClicked)=\"select($event)\"\n >\n </nui-menu-popup>\n </nui-overlay>\n</div>\n", styles: [".nui .nui-timepicker__container{width:135px;height:30px;position:relative}.nui .nui-timepicker__icon{cursor:pointer;position:absolute;top:7px;right:7px;z-index:501}.nui .nui-timepicker__icon:focus{border-radius:3px;outline:none;box-shadow:0 0 0 2px #00c4d280}.nui .nui-timepicker__menu{background-color:var(--nui-color-bg-content_popover,#fff);box-shadow:0 0 5px 0 var(--nui-shadow-color, rgba(17, 17, 17, .3));max-height:300px;overflow-y:auto;min-width:135px;text-align:left}.nui .nui-timepicker__input-disabled+.nui-timepicker__icon{pointer-events:auto;cursor:not-allowed}.nui .nui-timepicker .nui-popup-container{display:inline-flex}.nui .nui-timepicker .nui-textbox .has-feedback .nui-textbox__input{line-height:14px}\n"] }] }], ctorParameters: () => [{ type: i0.ElementRef }, { type: i1.TimePickerKeyboardService }, { type: i0.ChangeDetectorRef }], propDecorators: { textbox: [{ type: ViewChild, args: ["date", { static: true }] }], popupArea: [{ type: ViewChild, args: ["popupArea", { static: true }] }], containerEl: [{ type: ViewChild, args: ["toggleRef", { static: true }] }], overlay: [{ type: ViewChild, args: [OverlayComponent] }], popup: [{ type: ViewChild, args: ["popup"] }], menuTrigger: [{ type: ViewChild, args: ["menuTrigger", { read: ElementRef }] }], timeStep: [{ type: Input }], isDisabled: [{ type: Input }], timeFormat: [{ type: Input }], preserveInsignificant: [{ type: Input }], isInErrorState: [{ type: Input }], ariaLabel: [{ type: Input }], initEmpty: [{ type: Input }], appendToBody: [{ type: Input }], model: [{ type: Input }], timeChanged: [{ type: Output }], inputBlurred: [{ type: Output }], onKeyDown: [{ type: HostListener, args: ["keydown", ["$event"]] }], onFocusOut: [{ type: HostListener, args: ["focusout", ["$event"]] }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGltZS1waWNrZXIuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2xpYi90aW1lLXBpY2tlci90aW1lLXBpY2tlci5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi9zcmMvbGliL3RpbWUtcGlja2VyL3RpbWUtcGlja2VyLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQXFCQSxPQUFPLEVBRUgsaUJBQWlCLEVBQ2pCLFNBQVMsRUFDVCxVQUFVLEVBQ1YsWUFBWSxFQUNaLFVBQVUsRUFDVixZQUFZLEVBQ1osS0FBSyxFQUlMLE1BQU0sRUFFTixTQUFTLEVBQ1QsaUJBQWlCLEdBQ3BCLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBd0IsaUJBQWlCLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUN6RSxPQUFPLFFBQVEsTUFBTSxnQkFBZ0IsQ0FBQztBQUN0QyxPQUFPLE1BQU0sTUFBTSxjQUFjLENBQUM7QUFDbEMsT0FBTyxNQUFNLE1BQU0sZUFBZSxDQUFDO0FBRW5DLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDL0IsT0FBTyxFQUFFLFlBQVksRUFBRSxTQUFTLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUV6RCxPQUFPLEVBQUUseUJBQXlCLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQztBQUMzRSxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUMvRCxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSxTQUFTLENBQUM7QUFFN0MsT0FBTyxFQUFFLCtCQUErQixFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDdkUsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sZ0RBQWdELENBQUM7QUFDbEYsT0FBTyxFQUFFLHVCQUF1QixFQUFFLE1BQU0sc0NBQXNDLENBQUM7QUFDL0UsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sOEJBQThCLENBQUM7Ozs7Ozs7QUFFaEUseUVBQXlFO0FBcUJ6RSxNQUFNLE9BQU8sbUJBQW1CO0lBaUM1QixJQUNJLEtBQUs7UUFDTCxPQUFPLElBQUksQ0FBQyxVQUFVLENBQUM7SUFDM0IsQ0FBQztJQUVELElBQUksS0FBSyxDQUFDLEtBQXlCO1FBQy9CLElBQUksQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUMsT0FBTyxFQUFFLEVBQUU7WUFDMUIsT0FBTztTQUNWO1FBRUQsSUFBSSxLQUFLLElBQUksQ0FBQyxJQUFJLENBQUMscUJBQXFCLEVBQUU7WUFDdEMsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO1NBQ2xDO1FBQ0QsSUFBSSxDQUFDLFVBQVUsR0FBRyxLQUFLLENBQUM7UUFDeEIsSUFBSSxDQUFDLE9BQU8sQ0FBQyxVQUFVLENBQ25CLE1BQU0sQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FDbEQsQ0FBQztJQUNOLENBQUM7SUF3QkQsWUFDWSxVQUFzQixFQUN0QixlQUEwQyxFQUMxQyxHQUFzQjtRQUZ0QixlQUFVLEdBQVYsVUFBVSxDQUFZO1FBQ3RCLG9CQUFlLEdBQWYsZUFBZSxDQUEyQjtRQUMxQyxRQUFHLEdBQUgsR0FBRyxDQUFtQjtRQTdEbEMsc0RBQXNEO1FBQzdDLGFBQVEsR0FBRyxFQUFFLENBQUM7UUFHdkIsc0NBQXNDO1FBQzdCLGVBQVUsR0FBRyxJQUFJLENBQUM7UUFDM0IsZ0ZBQWdGO1FBQ3ZFLDBCQUFxQixHQUFHLEtBQUssQ0FBQztRQUN2QyxrQ0FBa0M7UUFDekIsbUJBQWMsR0FBRyxLQUFLLENBQUM7UUFDaEMsbUNBQW1DO1FBQ25CLGNBQVMsR0FBVyxhQUFhLENBQUM7UUFHbEQsdURBQXVEO1FBQzlDLGlCQUFZLEdBQVksS0FBSyxDQUFDO1FBcUJ0QixnQkFBVyxHQUFHLElBQUksWUFBWSxFQUFFLENBQUM7UUFDeEMsaUJBQVksR0FBc0IsSUFBSSxZQUFZLEVBQVUsQ0FBQztRQUdoRSxnQkFBVyxHQUFpQjtZQUMvQjtnQkFDSSxXQUFXLEVBQUUsRUFBRTthQUNsQjtTQUNKLENBQUM7UUFHSyxrQkFBYSxHQUFrQjtZQUNsQyxVQUFVLEVBQUUsQ0FBQywrQkFBK0IsRUFBRSxzQkFBc0IsQ0FBQztTQUN4RSxDQUFDO1FBQ0ssZUFBVSxHQUFHLElBQUksT0FBTyxFQUFRLENBQUM7UUFFOUIsbUJBQWMsR0FDcEIsSUFBSSx1QkFBdUIsRUFBRSxDQUFDO1FBRzFCLGlCQUFZLEdBQW9CLElBQUksT0FBTyxFQUFVLENBQUM7SUFNM0QsQ0FBQztJQUVHLFFBQVE7UUFDWCxJQUFJLENBQUMsS0FBSyxHQUFHLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUM7UUFDbkQsSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxLQUFhLEVBQUUsRUFBRTtZQUM3QixJQUFJLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUM7Z0JBQ2pDLEtBQUssRUFBRSxLQUFLO2dCQUNaLGFBQWEsRUFBRSxJQUFJLENBQUMsVUFBVTtnQkFDOUIsVUFBVSxFQUFFLEtBQUs7YUFDcEIsQ0FBQyxDQUFDO1FBQ1AsQ0FBQyxDQUFDLENBQUM7UUFDSCxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRTtZQUNqQixJQUFJLENBQUMsVUFBVSxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsS0FBSyxFQUFFLElBQUksTUFBTSxFQUFFLENBQUM7WUFDekQsSUFBSSxDQUFDLE9BQU8sQ0FBQyxVQUFVLENBQ25CLE1BQU0sQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FDbEQsQ0FBQztTQUNMO1FBRUQsSUFBSSxDQUFDLFlBQVksR0FBRyxJQUFJLENBQUMsZUFBZSxFQUFFLENBQUM7UUFDM0MsSUFBSSxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLENBQUMsS0FBSyxFQUFFLEVBQUU7WUFDMUQsSUFBSSxDQUFDLGdCQUFnQixDQUFDLEtBQUssQ0FBQyxDQUFDO1lBQzdCLElBQUksQ0FBQyxZQUFZLEdBQUcsSUFBSSxDQUFDLGVBQWUsRUFBRSxDQUFDO1lBQzNDLElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQztZQUN2QyxJQUFJLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQztZQUMvQixJQUFJLENBQUMsYUFBYSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQzlCLENBQUMsQ0FBQyxDQUFDO1FBQ0gsSUFBSSxDQUFDLG9CQUFvQixDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsQ0FBQztJQUNqRCxDQUFDO0lBRU0sV0FBVyxDQUFDLE9BQXNCO1FBQ3JDLElBQUksT0FBTyxDQUFDLFlBQVksRUFBRTtZQUN0QixJQUFJLENBQUMsb0JBQW9CLENBQUMsT0FBTyxDQUFDLFlBQVksQ0FBQyxZQUFZLENBQUMsQ0FBQztTQUNoRTtJQUNMLENBQUM7SUFFTSxlQUFlO1FBQ2xCLElBQUksQ0FBQyxPQUFPLENBQUMsWUFBWTthQUNwQixJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQzthQUNoQyxTQUFTLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQztRQUUzQyxJQUFJLENBQUMsa0JBQWtCLEVBQUUsQ0FBQztRQUMxQixJQUFJLENBQUMsZUFBZSxDQUFDLFdBQVcsQ0FDNUIsSUFBSSxDQUFDLEtBQUssRUFDVixJQUFJLENBQUMsT0FBTyxFQUNaLElBQUksQ0FBQyxXQUFXLENBQUMsYUFBYSxDQUNqQyxDQUFDO1FBQ0YsSUFBSSxDQUFDLEdBQUcsQ0FBQyxhQUFhLEVBQUUsQ0FBQztJQUM3QixDQUFDO0lBRUQsUUFBUSxDQUFDLEtBQVUsSUFBUyxDQUFDO0lBRTdCLFNBQVMsS0FBVSxDQUFDO0lBR2IsU0FBUyxDQUFDLEtBQW9CO1FBQ2pDLElBQUksQ0FBQyxlQUFlLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQzFDLENBQUM7SUFHTSxVQUFVLENBQUMsS0FBaUI7UUFDL0IsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsT0FBTyxJQUFJLENBQUMsUUFBUSxDQUFDLGFBQWEsRUFBRTtZQUNsRCxPQUFPO1NBQ1Y7UUFFRCxJQUNJLElBQUksQ0FBQyxTQUFTLENBQUMsYUFBYSxDQUFDLFFBQVEsQ0FDakMsS0FBSyxDQUFDLGFBQTRCLENBQ3JDLEVBQ0g7WUFDRSxPQUFPO1NBQ1Y7UUFFRCxJQUNJLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxhQUFhLENBQUMsUUFBUSxDQUNwQyxLQUFLLENBQUMsYUFBNEIsQ0FDckMsRUFDSDtZQUNFLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxFQUFFLENBQUM7U0FDdkI7SUFDTCxDQUFDO0lBRUQsZ0JBQWdCLENBQUMsS0FBVTtRQUN2QixVQUFVLENBQUMsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxJQUFJLEVBQUUsRUFBRSxHQUFHLENBQUMsQ0FBQztRQUNoRCxJQUFJLEtBQUssWUFBWSxNQUFNLElBQUksQ0FBQyxJQUFJLENBQUMscUJBQXFCLEVBQUU7WUFDdkQsS0FBZ0IsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDekIsS0FBZ0IsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDekIsS0FBZ0IsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDMUIsS0FBZ0IsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUM7U0FDaEM7UUFDRCxJQUFJLENBQUMsVUFBVTtZQUNYLFFBQVEsQ0FBQyxLQUFLLENBQUMsSUFBSSxLQUFLLENBQUMsTUFBTSxLQUFLLENBQUM7Z0JBQ2pDLENBQUMsQ0FBQyxTQUFTO2dCQUNYLENBQUMsQ0FBQyxNQUFNLENBQUMsS0FBSyxFQUFFLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQztRQUN6QyxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQyxPQUFPLEVBQUUsRUFBRTtZQUNwQyxJQUFJLENBQUMsVUFBVSxHQUFHLEtBQUssQ0FBQztTQUMzQjtRQUNELElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQztRQUNqQixJQUNJLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUM7WUFDckIsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQztZQUMxQixDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLEVBQzFCO1lBQ0UsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLG9CQUFvQixDQUNuQyxJQUFJLENBQUMsVUFBVSxFQUNmLElBQUksQ0FBQyxRQUFRLEVBQ2IsSUFBSSxDQUFDLEtBQUssQ0FDYixDQUFDO1lBQ0YsSUFBSSxDQUFDLGdCQUFnQixFQUFFLENBQUM7WUFDeEIsSUFBSSxRQUFRLENBQUMsS0FBSyxDQUFDLEVBQUU7Z0JBQ2pCLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDLENBQUMsV0FBVyxDQUFDLEtBQUssQ0FBQyxDQUFDLFVBQVUsR0FBRyxJQUFJLENBQUM7Z0JBQ3pELElBQUksQ0FBQyxZQUFZLEdBQUcsSUFBSSxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxXQUFXLENBQUMsS0FBSyxDQUFDLENBQUM7YUFDOUQ7U0FDSjtRQUNELElBQUksQ0FBQyxhQUFhLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDOUIsQ0FBQztJQUVELFVBQVUsQ0FBQyxLQUFVO1FBQ2pCLElBQUksQ0FBQyxPQUFPLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQztRQUNqRCxJQUFJLENBQUMsZ0JBQWdCLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDO0lBQ25ELENBQUM7SUFFRCxhQUFhLENBQUMsS0FBYTtRQUN2QixJQUFJLENBQUMsY0FBYyxHQUFHLENBQUMsTUFBTSxDQUFDLEtBQUssRUFBRSxJQUFJLENBQUMsVUFBVSxFQUFFLElBQUksQ0FBQyxDQUFDLE9BQU8sRUFBRSxDQUFDO0lBQzFFLENBQUM7SUFFRCxnQkFBZ0IsQ0FBQyxFQUF3QjtRQUNyQyxJQUFJLENBQUMsUUFBUSxHQUFHLEVBQUUsQ0FBQztJQUN2QixDQUFDO0lBRUQsaUJBQWlCLENBQUMsRUFBYztRQUM1QixJQUFJLENBQUMsU0FBUyxHQUFHLEVBQUUsQ0FBQztJQUN4QixDQUFDO0lBRUQsZ0JBQWdCLENBQUMsVUFBbUI7UUFDaEMsSUFBSSxDQUFDLFVBQVUsR0FBRyxVQUFVLENBQUM7SUFDakMsQ0FBQztJQUVELFdBQVc7UUFDUCxJQUFJLENBQUMsT0FBTyxDQUFDLEtBQUssRUFBRSxDQUFDO0lBQ3pCLENBQUM7SUFFTSx3QkFBd0IsQ0FBQyxLQUFhO1FBQ3pDLElBQUksQ0FBQyxZQUFZLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ2xDLENBQUM7SUFFTSxNQUFNLENBQUMsSUFBZTtRQUN6QixJQUFJLENBQUMsZ0JBQWdCLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQ2xDLElBQUksQ0FBQyxPQUFPLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxXQUFXLEVBQVksQ0FBQyxDQUFDO1FBQ3RELElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQztRQUN2QyxJQUFJLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQztRQUMvQixJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksRUFBRSxDQUFDO0lBQ3hCLENBQUM7SUFFTSxZQUFZO1FBQ2YsSUFBSSxDQUFDLElBQUksQ0FBQyxVQUFVLEVBQUU7WUFDbEIsSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLEVBQUUsQ0FBQztTQUN6QjtRQUNELE1BQU0sWUFBWSxHQUNkLElBQUksQ0FBQyxVQUFVLENBQUMsYUFBYSxDQUFDLHNCQUFzQixDQUNoRCx5QkFBeUIsQ0FDNUIsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUNULFlBQVksRUFBRSxjQUFjLENBQUMsRUFBRSxLQUFLLEVBQUUsUUFBUSxFQUFFLENBQUMsQ0FBQztJQUN0RCxDQUFDO0lBRU0saUJBQWlCLENBQUMsUUFBZ0I7UUFDckMsTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLHFCQUFxQjtZQUNuQyxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUM7WUFDbEMsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLENBQUM7UUFFdkMsTUFBTSxVQUFVLEdBQUcsSUFBSSxDQUFDLFNBQVMsRUFBRSxDQUFDO1FBQ3BDLE1BQU0sS0FBSyxHQUFhLEVBQUUsQ0FBQztRQUMzQixPQUFPLElBQUksQ0FBQyxTQUFTLEVBQUUsS0FBSyxVQUFVLEVBQUU7WUFDcEMsS0FBSyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsS0FBSyxFQUFFLENBQUMsQ0FBQztZQUN6QixJQUFJLENBQUMsR0FBRyxDQUFDLFFBQVEsRUFBRSxRQUFRLENBQUMsQ0FBQztTQUNoQztRQUNELE9BQU8sS0FBSyxDQUFDO0lBQ2pCLENBQUM7SUFFTSxjQUFjLENBQUMsUUFBZ0I7UUFDbEMsT0FBTyxNQUFNLENBQUMsUUFBUSxDQUFDLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDNUQsQ0FBQztJQUVNLG9CQUFvQixDQUN2QixLQUFzQixFQUN0QixRQUFnQixFQUNoQixLQUFlO1FBRWYsTUFBTSxJQUFJLEdBQUcsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQzNCLE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsU0FBUyxDQUFDLENBQUM7UUFDN0QsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLEdBQUcsUUFBUSxDQUFDLENBQUM7UUFDN0MsT0FBTyxLQUFLLEtBQUssS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUM7SUFDOUMsQ0FBQztJQUVNLGVBQWU7UUFDbEIsSUFBSSxRQUFRLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxJQUFJLE1BQU0sQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLEVBQUU7WUFDdEQsSUFBSSxDQUFDLGdCQUFnQixFQUFFLENBQUM7WUFDeEIsT0FBTztTQUNWO1FBRUQsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLG9CQUFvQixDQUNuQyxJQUFJLENBQUMsVUFBVSxFQUNmLElBQUksQ0FBQyxRQUFRLEVBQ2IsSUFBSSxDQUFDLEtBQUssQ0FDYixDQUFDO1FBQ0YsSUFBSSxDQUFDLGdCQUFnQixFQUFFLENBQUM7UUFDeEIsSUFBSSxRQUFRLENBQUMsS0FBSyxDQUFDLEVBQUU7WUFDakIsSUFBSSxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxXQUFXLENBQUMsS0FBSyxDQUFDLENBQUMsVUFBVSxHQUFHLElBQUksQ0FBQztZQUN6RCxPQUFPLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDLENBQUMsV0FBVyxDQUFDLEtBQUssQ0FBQyxDQUFDO1NBQ2pEO0lBQ0wsQ0FBQztJQUVNLGdCQUFnQjtRQUNuQixJQUFJLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxDQUFDLFdBQVcsQ0FBQyxPQUFPLENBQ25DLENBQUMsRUFBYSxFQUFFLEVBQUUsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxVQUFVLEdBQUcsS0FBSyxDQUFDLENBQzdDLENBQUM7SUFDTixDQUFDO0lBRU0sV0FBVyxDQUFDLFFBQWEsSUFBSSxDQUFDLFVBQVU7UUFDM0MsT0FBTyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUMsT0FBTyxFQUFFO1lBQzFCLENBQUMsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUM7WUFDdkMsQ0FBQyxDQUFDLEtBQUssQ0FBQztJQUNoQixDQUFDO0lBRU0sWUFBWTtRQUNmLE9BQU8sSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxjQUFjLENBQUM7SUFDckQsQ0FBQztJQUVPLG9CQUFvQixDQUFDLFlBQXFCO1FBQzlDLElBQUksQ0FBQyxlQUFlLEdBQUcsWUFBWSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUM7SUFDckUsQ0FBQztJQUVPLGtCQUFrQjtRQUN0QixNQUFNLGNBQWMsR0FBRyxJQUFJLENBQUMsY0FBYzthQUNyQyxpQkFBaUIsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDO2FBQy9CLGlCQUFpQixFQUFFLENBQUM7UUFFekIsSUFBSSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsR0FBRyxFQUFFO1lBQy9ELElBQUksQ0FBQyxjQUFjLENBQUMsU0FBUyxFQUFFLENBQUM7WUFDaEMsY0FBYyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLGFBQWEsQ0FBQyxDQUFDO1FBQzFELENBQUMsQ0FBQyxDQUFDO1FBRUgsSUFBSSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsR0FBRyxFQUFFO1lBQy9ELGNBQWMsQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxhQUFhLENBQUMsQ0FBQztRQUM1RCxDQUFDLENBQUMsQ0FBQztJQUNQLENBQUM7SUFFTSxXQUFXO1FBQ2QsSUFBSSxJQUFJLENBQUMsT0FBTyxFQUFFLE9BQU8sRUFBRTtZQUN2QixJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksRUFBRSxDQUFDO1NBQ3ZCO1FBRUQsSUFBSSxDQUFDLFVBQVUsQ0FBQyxJQUFJLEVBQUUsQ0FBQztRQUN2QixJQUFJLENBQUMsVUFBVSxDQUFDLFFBQVEsRUFBRSxDQUFDO1FBRTNCLElBQUksQ0FBQyxZQUFZLENBQUMsV0FBVyxFQUFFLENBQUM7SUFDcEMsQ0FBQzsrR0E3VVEsbUJBQW1CO21HQUFuQixtQkFBbUIsa2RBaEJqQjtZQUNQO2dCQUNJLE9BQU8sRUFBRSxpQkFBaUI7Z0JBQzFCLFdBQVcsRUFBRSxVQUFVLENBQUMsR0FBRyxFQUFFLENBQUMsbUJBQW1CLENBQUM7Z0JBQ2xELEtBQUssRUFBRSxJQUFJO2FBQ2Q7WUFDRDtnQkFDSSxPQUFPLEVBQUUsbUJBQW1CO2dCQUM1QixXQUFXLEVBQUUsVUFBVSxDQUFDLEdBQUcsRUFBRSxDQUFDLG1CQUFtQixDQUFDO2dCQUNsRCxLQUFLLEVBQUUsSUFBSTthQUNkO1lBQ0QseUJBQXlCO1NBQzVCLG1YQWdCVSxnQkFBZ0IseU1BRU8sVUFBVSxrREMxRmhELG9zQ0F3Q0E7OzRGRG9DYSxtQkFBbUI7a0JBbkIvQixTQUFTOytCQUNJLGlCQUFpQixhQUVoQjt3QkFDUDs0QkFDSSxPQUFPLEVBQUUsaUJBQWlCOzRCQUMxQixXQUFXLEVBQUUsVUFBVSxDQUFDLEdBQUcsRUFBRSxvQkFBb0IsQ0FBQzs0QkFDbEQsS0FBSyxFQUFFLElBQUk7eUJBQ2Q7d0JBQ0Q7NEJBQ0ksT0FBTyxFQUFFLG1CQUFtQjs0QkFDNUIsV0FBVyxFQUFFLFVBQVUsQ0FBQyxHQUFHLEVBQUUsb0JBQW9CLENBQUM7NEJBQ2xELEtBQUssRUFBRSxJQUFJO3lCQUNkO3dCQUNELHlCQUF5QjtxQkFDNUIsaUJBRWMsaUJBQWlCLENBQUMsSUFBSTt1SkFXQSxPQUFPO3NCQUEzQyxTQUFTO3VCQUFDLE1BQU0sRUFBRSxFQUFFLE1BQU0sRUFBRSxJQUFJLEVBQUU7Z0JBQ08sU0FBUztzQkFBbEQsU0FBUzt1QkFBQyxXQUFXLEVBQUUsRUFBRSxNQUFNLEVBQUUsSUFBSSxFQUFFO2dCQUNFLFdBQVc7c0JBQXBELFNBQVM7dUJBQUMsV0FBVyxFQUFFLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRTtnQkFDSixPQUFPO3NCQUExQyxTQUFTO3VCQUFDLGdCQUFnQjtnQkFDQSxLQUFLO3NCQUEvQixTQUFTO3VCQUFDLE9BQU87Z0JBRVgsV0FBVztzQkFEakIsU0FBUzt1QkFBQyxhQUFhLEVBQUUsRUFBRSxJQUFJLEVBQUUsVUFBVSxFQUFFO2dCQUdyQyxRQUFRO3NCQUFoQixLQUFLO2dCQUVHLFVBQVU7c0JBQWxCLEtBQUs7Z0JBRUcsVUFBVTtzQkFBbEIsS0FBSztnQkFFRyxxQkFBcUI7c0JBQTdCLEtBQUs7Z0JBRUcsY0FBYztzQkFBdEIsS0FBSztnQkFFVSxTQUFTO3NCQUF4QixLQUFLO2dCQUVHLFNBQVM7c0JBQWpCLEtBQUs7Z0JBRUcsWUFBWTtzQkFBcEIsS0FBSztnQkFHRixLQUFLO3NCQURSLEtBQUs7Z0JBbUJXLFdBQVc7c0JBQTNCLE1BQU07Z0JBQ0csWUFBWTtzQkFBckIsTUFBTTtnQkErRUEsU0FBUztzQkFEZixZQUFZO3VCQUFDLFNBQVMsRUFBRSxDQUFDLFFBQVEsQ0FBQztnQkFNNUIsVUFBVTtzQkFEaEIsWUFBWTt1QkFBQyxVQUFVLEVBQUUsQ0FBQyxRQUFRLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyDCqSAyMDIyIFNvbGFyV2luZHMgV29ybGR3aWRlLCBMTEMuIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4vL1xuLy8gUGVybWlzc2lvbiBpcyBoZXJlYnkgZ3JhbnRlZCwgZnJlZSBvZiBjaGFyZ2UsIHRvIGFueSBwZXJzb24gb2J0YWluaW5nIGEgY29weVxuLy8gIG9mIHRoaXMgc29mdHdhcmUgYW5kIGFzc29jaWF0ZWQgZG9jdW1lbnRhdGlvbiBmaWxlcyAodGhlIFwiU29mdHdhcmVcIiksIHRvXG4vLyAgZGVhbCBpbiB0aGUgU29mdHdhcmUgd2l0aG91dCByZXN0cmljdGlvbiwgaW5jbHVkaW5nIHdpdGhvdXQgbGltaXRhdGlvbiB0aGVcbi8vICByaWdodHMgdG8gdXNlLCBjb3B5LCBtb2RpZnksIG1lcmdlLCBwdWJsaXNoLCBkaXN0cmlidXRlLCBzdWJsaWNlbnNlLCBhbmQvb3Jcbi8vICBzZWxsIGNvcGllcyBvZiB0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJtaXQgcGVyc29ucyB0byB3aG9tIHRoZSBTb2Z0d2FyZSBpc1xuLy8gIGZ1cm5pc2hlZCB0byBkbyBzbywgc3ViamVjdCB0byB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6XG4vL1xuLy8gVGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMgcGVybWlzc2lvbiBub3RpY2Ugc2hhbGwgYmUgaW5jbHVkZWQgaW5cbi8vICBhbGwgY29waWVzIG9yIHN1YnN0YW50aWFsIHBvcnRpb25zIG9mIHRoZSBTb2Z0d2FyZS5cbi8vXG4vLyBUSEUgU09GVFdBUkUgSVMgUFJPVklERUQgXCJBUyBJU1wiLCBXSVRIT1VUIFdBUlJBTlRZIE9GIEFOWSBLSU5ELCBFWFBSRVNTIE9SXG4vLyAgSU1QTElFRCwgSU5DTFVESU5HIEJVVCBOT1QgTElNSVRFRCBUTyBUSEUgV0FSUkFOVElFUyBPRiBNRVJDSEFOVEFCSUxJVFksXG4vLyAgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UgQU5EIE5PTklORlJJTkdFTUVOVC4gSU4gTk8gRVZFTlQgU0hBTEwgVEhFXG4vLyAgQVVUSE9SUyBPUiBDT1BZUklHSFQgSE9MREVSUyBCRSBMSUFCTEUgRk9SIEFOWSBDTEFJTSwgREFNQUdFUyBPUiBPVEhFUlxuLy8gIExJQUJJTElUWSwgV0hFVEhFUiBJTiBBTiBBQ1RJT04gT0YgQ09OVFJBQ1QsIFRPUlQgT1IgT1RIRVJXSVNFLCBBUklTSU5HIEZST00sXG4vLyAgT1VUIE9GIE9SIElOIENPTk5FQ1RJT04gV0lUSCBUSEUgU09GVFdBUkUgT1IgVEhFIFVTRSBPUiBPVEhFUiBERUFMSU5HUyBJTlxuLy8gIFRIRSBTT0ZUV0FSRS5cblxuaW1wb3J0IHsgT3ZlcmxheUNvbmZpZyB9IGZyb20gXCJAYW5ndWxhci9jZGsvb3ZlcmxheVwiO1xuaW1wb3J0IHtcbiAgICBBZnRlclZpZXdJbml0LFxuICAgIENoYW5nZURldGVjdG9yUmVmLFxuICAgIENvbXBvbmVudCxcbiAgICBFbGVtZW50UmVmLFxuICAgIEV2ZW50RW1pdHRlcixcbiAgICBmb3J3YXJkUmVmLFxuICAgIEhvc3RMaXN0ZW5lcixcbiAgICBJbnB1dCxcbiAgICBPbkNoYW5nZXMsXG4gICAgT25EZXN0cm95LFxuICAgIE9uSW5pdCxcbiAgICBPdXRwdXQsXG4gICAgU2ltcGxlQ2hhbmdlcyxcbiAgICBWaWV3Q2hpbGQsXG4gICAgVmlld0VuY2Fwc3VsYXRpb24sXG59IGZyb20gXCJAYW5ndWxhci9jb3JlXCI7XG5pbXBvcnQgeyBDb250cm9sVmFsdWVBY2Nlc3NvciwgTkdfVkFMVUVfQUNDRVNTT1IgfSBmcm9tIFwiQGFuZ3VsYXIvZm9ybXNcIjtcbmltcG9ydCBfaXNFbXB0eSBmcm9tIFwibG9kYXNoL2lzRW1wdHlcIjtcbmltcG9ydCBfaXNOaWwgZnJvbSBcImxvZGFzaC9pc05pbFwiO1xuaW1wb3J0IG1vbWVudCBmcm9tIFwibW9tZW50L21vbWVudFwiO1xuaW1wb3J0IHsgTW9tZW50IH0gZnJvbSBcIm1vbWVudC9tb21lbnRcIjtcbmltcG9ydCB7IFN1YmplY3QgfSBmcm9tIFwicnhqc1wiO1xuaW1wb3J0IHsgZGVib3VuY2VUaW1lLCB0YWtlVW50aWwgfSBmcm9tIFwicnhqcy9vcGVyYXRvcnNcIjtcblxuaW1wb3J0IHsgVGltZVBpY2tlcktleWJvYXJkU2VydmljZSB9IGZyb20gXCIuL3RpbWUtcGlja2VyLWtleWJvYXJkLnNlcnZpY2VcIjtcbmltcG9ydCB7IE51aUZvcm1GaWVsZENvbnRyb2wgfSBmcm9tIFwiLi4vZm9ybS1maWVsZC9wdWJsaWMtYXBpXCI7XG5pbXBvcnQgeyBNZW51UG9wdXBDb21wb25lbnQgfSBmcm9tIFwiLi4vbWVudVwiO1xuaW1wb3J0IHsgSU1lbnVHcm91cCwgSU1lbnVJdGVtIH0gZnJvbSBcIi4uL21lbnUvcHVibGljLWFwaVwiO1xuaW1wb3J0IHsgT1ZFUkxBWV9XSVRIX1BPUFVQX1NUWUxFU19DTEFTUyB9IGZyb20gXCIuLi9vdmVybGF5L2NvbnN0YW50c1wiO1xuaW1wb3J0IHsgT3ZlcmxheUNvbXBvbmVudCB9IGZyb20gXCIuLi9vdmVybGF5L292ZXJsYXktY29tcG9uZW50L292ZXJsYXkuY29tcG9uZW50XCI7XG5pbXBvcnQgeyBPdmVybGF5VXRpbGl0aWVzU2VydmljZSB9IGZyb20gXCIuLi9vdmVybGF5L292ZXJsYXktdXRpbGl0aWVzLnNlcnZpY2VcIjtcbmltcG9ydCB7IFRleHRib3hDb21wb25lbnQgfSBmcm9tIFwiLi4vdGV4dGJveC90ZXh0Ym94LmNvbXBvbmVudFwiO1xuXG4vLyA8ZXhhbXBsZS11cmw+Li8uLi9leGFtcGxlcy9pbmRleC5odG1sIy90aW1lLXBpY2tlcjwvZXhhbXBsZS11cmw+PGJyIC8+XG5cbkBDb21wb25lbnQoe1xuICAgIHNlbGVjdG9yOiBcIm51aS10aW1lLXBpY2tlclwiLFxuICAgIHRlbXBsYXRlVXJsOiBcIi4vdGltZS1waWNrZXIuY29tcG9uZW50Lmh0bWxcIixcbiAgICBwcm92aWRlcnM6IFtcbiAgICAgICAge1xuICAgICAgICAgICAgcHJvdmlkZTogTkdfVkFMVUVfQUNDRVNTT1IsXG4gICAgICAgICAgICB1c2VFeGlzdGluZzogZm9yd2FyZFJlZigoKSA9PiBUaW1lUGlja2VyQ29tcG9uZW50KSxcbiAgICAgICAgICAgIG11bHRpOiB0cnVlLFxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgICBwcm92aWRlOiBOdWlGb3JtRmllbGRDb250cm9sLFxuICAgICAgICAgICAgdXNlRXhpc3Rpbmc6IGZvcndhcmRSZWYoKCkgPT4gVGltZVBpY2tlckNvbXBvbmVudCksXG4gICAgICAgICAgICBtdWx0aTogdHJ1ZSxcbiAgICAgICAgfSxcbiAgICAgICAgVGltZVBpY2tlcktleWJvYXJkU2VydmljZSxcbiAgICBdLFxuICAgIHN0eWxlVXJsczogW1wiLi90aW1lLXBpY2tlci5jb21wb25lbnQubGVzc1wiXSxcbiAgICBlbmNhcHN1bGF0aW9uOiBWaWV3RW5jYXBzdWxhdGlvbi5Ob25lLFxufSlcbmV4cG9ydCBjbGFzcyBUaW1lUGlja2VyQ29tcG9uZW50XG4gICAgaW1wbGVtZW50c1xuICAgICAgICBPbkluaXQsXG4gICAgICAgIE9uRGVzdHJveSxcbiAgICAgICAgT25DaGFuZ2VzLFxuICAgICAgICBBZnRlclZpZXdJbml0LFxuICAgICAgICBDb250cm9sVmFsdWVBY2Nlc3NvcixcbiAgICAgICAgTnVpRm9ybUZpZWxkQ29udHJvbFxue1xuICAgIEBWaWV3Q2hpbGQoXCJkYXRlXCIsIHsgc3RhdGljOiB0cnVlIH0pIHRleHRib3g6IFRleHRib3hDb21wb25lbnQ7XG4gICAgQFZpZXdDaGlsZChcInBvcHVwQXJlYVwiLCB7IHN0YXRpYzogdHJ1ZSB9KSBwb3B1cEFyZWE6IEVsZW1lbnRSZWY7XG4gICAgQFZpZXdDaGlsZChcInRvZ2dsZVJlZlwiLCB7IHN0YXRpYzogdHJ1ZSB9KSBjb250YWluZXJFbDogRWxlbWVudFJlZjtcbiAgICBAVmlld0NoaWxkKE92ZXJsYXlDb21wb25lbnQpIHB1YmxpYyBvdmVybGF5OiBPdmVybGF5Q29tcG9uZW50O1xuICAgIEBWaWV3Q2hpbGQoXCJwb3B1cFwiKSBwdWJsaWMgcG9wdXA6IE1lbnVQb3B1cENvbXBvbmVudDtcbiAgICBAVmlld0NoaWxkKFwibWVudVRyaWdnZXJcIiwgeyByZWFkOiBFbGVtZW50UmVmIH0pXG4gICAgcHVibGljIG1lbnVUcmlnZ2VyOiBFbGVtZW50UmVmO1xuICAgIC8qKiBzZXRzIGEgc3RlcCAoZGlmZmVyZW5jZSBiZXR3ZWVuIGl0ZW0gaW4gcGlja2VyKSAqL1xuICAgIEBJbnB1dCgpIHRpbWVTdGVwID0gMzA7XG4gICAgLyoqIHNldHMgZGlzYWJsZSBzdGF0ZSBvZiB0aGUgdGltZXBpY2tlciAqL1xuICAgIEBJbnB1dCgpIGlzRGlzYWJsZWQ6IGJvb2xlYW47XG4gICAgLyoqIHNldHMgY3VzdG9tIGZvcm1hdHRpbmcgZm9yIHRpbWUgKi9cbiAgICBASW5wdXQoKSB0aW1lRm9ybWF0ID0gXCJMVFwiO1xuICAgIC8qKiB0ZWxscyB0aW1lcGlja2VyIHdoZXRoZXIgdG8gc2F2ZSB5ZWFyLCBtb250aCwgZGF5IGFuZCBzZWNvbmRzIG9mIHRoZSBkYXRlICovXG4gICAgQElucHV0KCkgcHJlc2VydmVJbnNpZ25pZmljYW50ID0gZmFsc2U7XG4gICAgLyoqIHRvIGFwcGx5IGVycm9yIHN0YXRlIHN0eWxlcyAqL1xuICAgIEBJbnB1dCgpIGlzSW5FcnJvclN0YXRlID0gZmFsc2U7XG4gICAgLyoqIElucHV0IHRvIHNldCBhcmlhIGxhYmVsIHRleHQgKi9cbiAgICBASW5wdXQoKSBwdWJsaWMgYXJpYUxhYmVsOiBzdHJpbmcgPSBcIlRpbWUgUGlja2VyXCI7XG4gICAgLyoqIHRvIGFsbG93IHRoZSBlbXB0eSB2YWx1ZXMgZm9yIGluaXQgc3RhdGUgKi9cbiAgICBASW5wdXQoKSBpbml0RW1wdHk6IGJvb2xlYW47XG4gICAgLyoqIEFsbG93cyBwb3B1cCBib3ggdG8gYmUgYXR0YWNoZWQgdG8gZG9jdW1lbnQuYm9keSAqL1xuICAgIEBJbnB1dCgpIGFwcGVuZFRvQm9keTogYm9vbGVhbiA9IGZhbHNlO1xuXG4gICAgQElucHV0KClcbiAgICBnZXQgbW9kZWwoKTogTW9tZW50IHwgdW5kZWZpbmVkIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuaW5uZXJNb2RlbDtcbiAgICB9XG5cbiAgICBzZXQgbW9kZWwodmFsdWU6IE1vbWVudCB8IHVuZGVmaW5lZCkge1xuICAgICAgICBpZiAoIW1vbWVudCh2YWx1ZSkuaXNWYWxpZCgpKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodmFsdWUgJiYgIXRoaXMucHJlc2VydmVJbnNpZ25pZmljYW50KSB7XG4gICAgICAgICAgICB2YWx1ZS55ZWFyKDApLm1vbnRoKDApLmRhdGUoMCk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5pbm5lck1vZGVsID0gdmFsdWU7XG4gICAgICAgIHRoaXMudGV4dGJveC53cml0ZVZhbHVlKFxuICAgICAgICAgICAgbW9tZW50KHRoaXMuaW5uZXJNb2RlbCkuZm9ybWF0KHRoaXMudGltZUZvcm1hdClcbiAgICAgICAgKTtcbiAgICB9XG5cbiAgICBAT3V0cHV0KCkgcHVibGljIHRpbWVDaGFuZ2VkID0gbmV3IEV2ZW50RW1pdHRlcigpO1xuICAgIEBPdXRwdXQoKSBpbnB1dEJsdXJyZWQ6IEV2ZW50RW1pdHRlcjxhbnk+ID0gbmV3IEV2ZW50RW1pdHRlcjxNb21lbnQ+KCk7XG5cbiAgICBwdWJsaWMgdGltZXM6IE1vbWVudFtdO1xuICAgIHB1YmxpYyBpdGVtc1NvdXJjZTogSU1lbnVHcm91cFtdID0gW1xuICAgICAgICB7XG4gICAgICAgICAgICBpdGVtc1NvdXJjZTogW10sXG4gICAgICAgIH0sXG4gICAgXTtcbiAgICBwdWJsaWMgaW5uZXJNb2RlbD86IE1vbWVudDtcbiAgICBwdWJsaWMgY3VzdG9tQ29udGFpbmVyOiBFbGVtZW50UmVmIHwgdW5kZWZpbmVkO1xuICAgIHB1YmxpYyBvdmVybGF5Q29uZmlnOiBPdmVybGF5Q29uZmlnID0ge1xuICAgICAgICBwYW5lbENsYXNzOiBbT1ZFUkxBWV9XSVRIX1BPUFVQX1NUWUxFU19DTEFTUywgXCJudWktdGltZXBpY2tlcl9fbWVudVwiXSxcbiAgICB9O1xuICAgIHB1YmxpYyBvbkRlc3Ryb3kkID0gbmV3IFN1YmplY3Q8dm9pZD4oKTtcblxuICAgIHByb3RlY3RlZCBwb3B1cFV0aWxpdGllczogT3ZlcmxheVV0aWxpdGllc1NlcnZpY2UgPVxuICAgICAgICBuZXcgT3ZlcmxheVV0aWxpdGllc1NlcnZpY2UoKTtcblxuICAgIHByaXZhdGUgaXRlbVRvU2VsZWN0OiBhbnk7XG4gICAgcHJpdmF0ZSBpbnB1dENoYW5nZWQ6IFN1YmplY3Q8c3RyaW5nPiA9IG5ldyBTdWJqZWN0PHN0cmluZz4oKTtcblxuICAgIGNvbnN0cnVjdG9yKFxuICAgICAgICBwcml2YXRlIGVsZW1lbnRSZWY6IEVsZW1lbnRSZWYsXG4gICAgICAgIHByaXZhdGUga2V5Ym9hcmRTZXJ2aWNlOiBUaW1lUGlja2VyS2V5Ym9hcmRTZXJ2aWNlLFxuICAgICAgICBwcml2YXRlIGNkcjogQ2hhbmdlRGV0ZWN0b3JSZWZcbiAgICApIHt9XG5cbiAgICBwdWJsaWMgbmdPbkluaXQoKTogdm9pZCB7XG4gICAgICAgIHRoaXMudGltZXMgPSB0aGlzLmdlbmVyYXRlVGltZUl0ZW1zKHRoaXMudGltZVN0ZXApO1xuICAgICAgICB0aGlzLnRpbWVzLm1hcCgodmFsdWU6IE1vbWVudCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5pdGVtc1NvdXJjZVswXS5pdGVtc1NvdXJjZS5wdXNoKHtcbiAgICAgICAgICAgICAgICB0aXRsZTogdmFsdWUsXG4gICAgICAgICAgICAgICAgZGlzcGxheUZvcm1hdDogdGhpcy50aW1lRm9ybWF0LFxuICAgICAgICAgICAgICAgIGlzU2VsZWN0ZWQ6IGZhbHNlLFxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuICAgICAgICBpZiAoIXRoaXMuaW5pdEVtcHR5KSB7XG4gICAgICAgICAgICB0aGlzLmlubmVyTW9kZWwgPSBtb21lbnQodGhpcy5tb2RlbCkuY2xvbmUoKSB8fCBtb21lbnQoKTtcbiAgICAgICAgICAgIHRoaXMudGV4dGJveC53cml0ZVZhbHVlKFxuICAgICAgICAgICAgICAgIG1vbWVudCh0aGlzLmlubmVyTW9kZWwpLmZvcm1hdCh0aGlzLnRpbWVGb3JtYXQpXG4gICAgICAgICAgICApO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5pdGVtVG9TZWxlY3QgPSB0aGlzLmdldEl0ZW1Ub1NlbGVjdCgpO1xuICAgICAgICB0aGlzLmlucHV0Q2hhbmdlZC5waXBlKGRlYm91bmNlVGltZSg1MDApKS5zdWJzY3JpYmUoKHZhbHVlKSA9PiB7XG4gICAgICAgICAgICB0aGlzLnVwZGF0ZUlubmVyTW9kZWwodmFsdWUpO1xuICAgICAgICAgICAgdGhpcy5pdGVtVG9TZWxlY3QgPSB0aGlzLmdldEl0ZW1Ub1NlbGVjdCgpO1xuICAgICAgICAgICAgdGhpcy50aW1lQ2hhbmdlZC5lbWl0KHRoaXMuaW5uZXJNb2RlbCk7XG4gICAgICAgICAgICB0aGlzLm9uQ2hhbmdlKHRoaXMuaW5uZXJNb2RlbCk7XG4gICAgICAgICAgICB0aGlzLnNldEVycm9yU3RhdGUodmFsdWUpO1xuICAgICAgICB9KTtcbiAgICAgICAgdGhpcy5vbkFwcGVuZFRvQm9keUNoYW5nZSh0aGlzLmFwcGVuZFRvQm9keSk7XG4gICAgfVxuXG4gICAgcHVibGljIG5nT25DaGFuZ2VzKGNoYW5nZXM6IFNpbXBsZUNoYW5nZXMpOiB2b2lkIHtcbiAgICAgICAgaWYgKGNoYW5nZXMuYXBwZW5kVG9Cb2R5KSB7XG4gICAgICAgICAgICB0aGlzLm9uQXBwZW5kVG9Cb2R5Q2hhbmdlKGNoYW5nZXMuYXBwZW5kVG9Cb2R5LmN1cnJlbnRWYWx1ZSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwdWJsaWMgbmdBZnRlclZpZXdJbml0KCk6IHZvaWQge1xuICAgICAgICB0aGlzLm92ZXJsYXkuY2xpY2tPdXRzaWRlXG4gICAgICAgICAgICAucGlwZSh0YWtlVW50aWwodGhpcy5vbkRlc3Ryb3kkKSlcbiAgICAgICAgICAgIC5zdWJzY3JpYmUoKF8pID0+IHRoaXMub3ZlcmxheS5oaWRlKCkpO1xuXG4gICAgICAgIHRoaXMuaW5pdFBvcHVwVXRpbGl0aWVzKCk7XG4gICAgICAgIHRoaXMua2V5Ym9hcmRTZXJ2aWNlLmluaXRTZXJ2aWNlKFxuICAgICAgICAgICAgdGhpcy5wb3B1cCxcbiAgICAgICAgICAgIHRoaXMub3ZlcmxheSxcbiAgICAgICAgICAgIHRoaXMubWVudVRyaWdnZXIubmF0aXZlRWxlbWVudFxuICAgICAgICApO1xuICAgICAgICB0aGlzLmNkci5kZXRlY3RDaGFuZ2VzKCk7XG4gICAgfVxuXG4gICAgb25DaGFuZ2UodmFsdWU6IGFueSk6IHZvaWQge31cblxuICAgIG9uVG91Y2hlZCgpOiB2b2lkIHt9XG5cbiAgICBASG9zdExpc3RlbmVyKFwia2V5ZG93blwiLCBbXCIkZXZlbnRcIl0pXG4gICAgcHVibGljIG9uS2V5RG93bihldmVudDogS2V5Ym9hcmRFdmVudCk6IHZvaWQge1xuICAgICAgICB0aGlzLmtleWJvYXJkU2VydmljZS5vbktleURvd24oZXZlbnQpO1xuICAgIH1cblxuICAgIEBIb3N0TGlzdGVuZXIoXCJmb2N1c291dFwiLCBbXCIkZXZlbnRcIl0pXG4gICAgcHVibGljIG9uRm9jdXNPdXQoZXZlbnQ6IEZvY3VzRXZlbnQpOiB2b2lkIHtcbiAgICAgICAgaWYgKCF0aGlzLm92ZXJsYXkuc2hvd2luZyB8fCAhZG9jdW1lbnQuYWN0aXZlRWxlbWVudCkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKFxuICAgICAgICAgICAgdGhpcy5wb3B1cEFyZWEubmF0aXZlRWxlbWVudC5jb250YWlucyhcbiAgICAgICAgICAgICAgICBldmVudC5yZWxhdGVkVGFyZ2V0IGFzIEhUTUxFbGVtZW50XG4gICAgICAgICAgICApXG4gICAgICAgICkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKFxuICAgICAgICAgICAgIXRoaXMuY29udGFpbmVyRWwubmF0aXZlRWxlbWVudC5jb250YWlucyhcbiAgICAgICAgICAgICAgICBldmVudC5yZWxhdGVkVGFyZ2V0IGFzIEhUTUxFbGVtZW50XG4gICAgICAgICAgICApXG4gICAgICAgICkge1xuICAgICAgICAgICAgdGhpcy5vdmVybGF5LmhpZGUoKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHVwZGF0ZUlubmVyTW9kZWwodmFsdWU6IGFueSk6IHZvaWQge1xuICAgICAgICBzZXRUaW1lb3V0KCgpID0+IHRoaXMuaW5wdXRCbHVycmVkLmVtaXQoKSwgMTAwKTtcbiAgICAgICAgaWYgKHZhbHVlIGluc3RhbmNlb2YgbW9tZW50ICYmICF0aGlzLnByZXNlcnZlSW5zaWduaWZpY2FudCkge1xuICAgICAgICAgICAgKHZhbHVlIGFzIE1vbWVudCkueWVhcigwKTtcbiAgICAgICAgICAgICh2YWx1ZSBhcyBNb21lbnQpLmRhdGUoMSk7XG4gICAgICAgICAgICAodmFsdWUgYXMgTW9tZW50KS5tb250aCgwKTtcbiAgICAgICAgICAgICh2YWx1ZSBhcyBNb21lbnQpLnNlY29uZHMoMCk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5pbm5lck1vZGVsID1cbiAgICAgICAgICAgIF9pc0VtcHR5KHZhbHVlKSB8fCB2YWx1ZS5sZW5ndGggPT09IDBcbiAgICAgICAgICAgICAgICA/IHVuZGVmaW5lZFxuICAgICAgICAgICAgICAgIDogbW9tZW50KHZhbHVlLCB0aGlzLnRpbWVGb3JtYXQpO1xuICAgICAgICBpZiAoIW1vbWVudCh0aGlzLmlubmVyTW9kZWwpLmlzVmFsaWQoKSkge1xuICAgICAgICAgICAgdGhpcy5pbm5lck1vZGVsID0gdmFsdWU7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5vblRvdWNoZWQoKTtcbiAgICAgICAgaWYgKFxuICAgICAgICAgICAgIV9pc0VtcHR5KHRoaXMudGltZXMpICYmXG4gICAgICAgICAgICAhX2lzRW1wdHkodGhpcy5pbm5lck1vZGVsKSAmJlxuICAgICAgICAgICAgIV9pc05pbCh0aGlzLmlubmVyTW9kZWwpXG4gICAgICAgICkge1xuICAgICAgICAgICAgY29uc3QgaW5kZXggPSB0aGlzLmdldEl0ZW1JbmRleFRvU2VsZWN0KFxuICAgICAgICAgICAgICAgIHRoaXMuaW5uZXJNb2RlbCxcbiAgICAgICAgICAgICAgICB0aGlzLnRpbWVTdGVwLFxuICAgICAgICAgICAgICAgIHRoaXMudGltZXNcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICB0aGlzLnVuc2VsZWN0QWxsSXRlbXMoKTtcbiAgICAgICAgICAgIGlmIChpc0Zpbml0ZShpbmRleCkpIHtcbiAgICAgICAgICAgICAgICB0aGlzLml0ZW1zU291cmNlWzBdLml0ZW1zU291cmNlW2luZGV4XS5pc1NlbGVjdGVkID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICB0aGlzLml0ZW1Ub1NlbGVjdCA9IHRoaXMuaXRlbXNTb3VyY2VbMF0uaXRlbXNTb3VyY2VbaW5kZXhdO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHRoaXMuc2V0RXJyb3JTdGF0ZSh2YWx1ZSk7XG4gICAgfVxuXG4gICAgd3JpdGVWYWx1ZSh2YWx1ZTogYW55KTogdm9pZCB7XG4gICAgICAgIHRoaXMudGV4dGJveC53cml0ZVZhbHVlKHRoaXMuZm9ybWF0VmFsdWUodmFsdWUpKTtcbiAgICAgICAgdGhpcy51cGRhdGVJbm5lck1vZGVsKHRoaXMuZm9ybWF0VmFsdWUodmFsdWUpKTtcbiAgICB9XG5cbiAgICBzZXRFcnJvclN0YXRlKHZhbHVlOiBzdHJpbmcpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5pc0luRXJyb3JTdGF0ZSA9ICFtb21lbnQodmFsdWUsIHRoaXMudGltZUZvcm1hdCwgdHJ1ZSkuaXNWYWxpZCgpO1xuICAgIH1cblxuICAgIHJlZ2lzdGVyT25DaGFuZ2UoZm46ICh2YWx1ZTogYW55KSA9PiB2b2lkKTogdm9pZCB7XG4gICAgICAgIHRoaXMub25DaGFuZ2UgPSBmbjtcbiAgICB9XG5cbiAgICByZWdpc3Rlck9uVG91Y2hlZChmbjogKCkgPT4gdm9pZCk6IHZvaWQge1xuICAgICAgICB0aGlzLm9uVG91Y2hlZCA9IGZuO1xuICAgIH1cblxuICAgIHNldERpc2FibGVkU3RhdGUoaXNEaXNhYmxlZDogYm9vbGVhbik6IHZvaWQge1xuICAgICAgICB0aGlzLmlzRGlzYWJsZWQgPSBpc0Rpc2FibGVkO1xuICAgIH1cblxuICAgIGZvY3VzT25Gb3JtKCk6IHZvaWQge1xuICAgICAgICB0aGlzLnRleHRib3guZm9jdXMoKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgb25JbnB1dEFjdGl2ZURhdGVDaGFuZ2VkKHZhbHVlOiBzdHJpbmcpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5pbnB1dENoYW5nZWQubmV4dCh2YWx1ZSk7XG4gICAgfVxuXG4gICAgcHVibGljIHNlbGVjdCh0aW1lOiBJTWVudUl0ZW0pOiB2b2lkIHtcbiAgICAgICAgdGhpcy51cGRhdGVJbm5lck1vZGVsKHRpbWUudGl0bGUpO1xuICAgICAgICB0aGlzLnRleHRib3gud3JpdGVWYWx1ZSh0aGlzLmZvcm1hdFZhbHVlKCkgYXMgc3RyaW5nKTtcbiAgICAgICAgdGhpcy50aW1lQ2hhbmdlZC5lbWl0KHRoaXMuaW5uZXJNb2RlbCk7XG4gICAgICAgIHRoaXMub25DaGFuZ2UodGhpcy5pbm5lck1vZGVsKTtcbiAgICAgICAgdGhpcy5vdmVybGF5LmhpZGUoKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgc2Nyb2xsVG9WaWV3KCk6IHZvaWQge1xuICAgICAgICBpZiAoIXRoaXMuaXNEaXNhYmxlZCkge1xuICAgICAgICAgICAgdGhpcy5vdmVybGF5LnRvZ2dsZSgpO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IHNlbGVjdGVkSXRlbSA9XG4gICAgICAgICAgICB0aGlzLmVsZW1lbnRSZWYubmF0aXZlRWxlbWVudC5nZXRFbGVtZW50c0J5Q2xhc3NOYW1lKFxuICAgICAgICAgICAgICAgIFwibnVpLW1lbnUtaXRlbS0tc2VsZWN0ZWRcIlxuICAgICAgICAgICAgKVswXTtcbiAgICAgICAgc2VsZWN0ZWRJdGVtPy5zY3JvbGxJbnRvVmlldyh7IGJsb2NrOiBcImNlbnRlclwiIH0pO1xuICAgIH1cblxuICAgIHB1YmxpYyBnZW5lcmF0ZVRpbWVJdGVtcyh0aW1lU3RlcDogbnVtYmVyKTogTW9tZW50W10ge1xuICAgICAgICBjb25zdCB0aW1lID0gdGhpcy5wcmVzZXJ2ZUluc2lnbmlmaWNhbnRcbiAgICAgICAgICAgID8gbW9tZW50KCkuaG91cigwKS5zdGFydE9mKFwiaG91clwiKVxuICAgICAgICAgICAgOiBtb21lbnQoKS55ZWFyKDApLnN0YXJ0T2YoXCJ5ZWFyXCIpO1xuXG4gICAgICAgIGNvbnN0IGluaXRpYWxEYXkgPSB0aW1lLmRheU9mWWVhcigpO1xuICAgICAgICBjb25zdCB0aW1lczogTW9tZW50W10gPSBbXTtcbiAgICAgICAgd2hpbGUgKHRpbWUuZGF5T2ZZZWFyKCkgPT09IGluaXRpYWxEYXkpIHtcbiAgICAgICAgICAgIHRpbWVzLnB1c2godGltZS5jbG9uZSgpKTtcbiAgICAgICAgICAgIHRpbWUuYWRkKHRpbWVTdGVwLCBcIm1pbnV0ZVwiKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdGltZXM7XG4gICAgfVxuXG4gICAgcHVibGljIGlzSXRlbVNlbGVjdGVkKHRpbWVJdGVtOiBNb21lbnQpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuIG1vbWVudCh0aW1lSXRlbSkuaXNTYW1lKHRoaXMuaXRlbVRvU2VsZWN0LnRpdGxlKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0SXRlbUluZGV4VG9TZWxlY3QoXG4gICAgICAgIG1vZGVsOiBNb21lbnQgfCBzdHJpbmcsXG4gICAgICAgIHRpbWVTdGVwOiBudW1iZXIsXG4gICAgICAgIHRpbWVzOiBNb21lbnRbXVxuICAgICk6IG51bWJlciB7XG4gICAgICAgIGNvbnN0IHRpbWUgPSBtb21lbnQobW9kZWwpO1xuICAgICAgICBjb25zdCBtaW51dGVzID0gdGltZS5nZXQoXCJob3Vyc1wiKSAqIDYwICsgdGltZS5nZXQoXCJtaW51dGVzXCIpO1xuICAgICAgICBjb25zdCBpbmRleCA9IE1hdGgucm91bmQobWludXRlcyAvIHRpbWVTdGVwKTtcbiAgICAgICAgcmV0dXJuIGluZGV4ID09PSB0aW1lcy5sZW5ndGggPyAwIDogaW5kZXg7XG4gICAgfVxuXG4gICAgcHVibGljIGdldEl0ZW1Ub1NlbGVjdCgpOiBJTWVudUl0ZW0gfCB1bmRlZmluZWQge1xuICAgICAgICBpZiAoX2lzRW1wdHkodGhpcy5pbm5lck1vZGVsKSB8fCBfaXNOaWwodGhpcy5pbm5lck1vZGVsKSkge1xuICAgICAgICAgICAgdGhpcy51bnNlbGVjdEFsbEl0ZW1zKCk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBpbmRleCA9IHRoaXMuZ2V0SXRlbUluZGV4VG9TZWxlY3QoXG4gICAgICAgICAgICB0aGlzLmlubmVyTW9kZWwsXG4gICAgICAgICAgICB0aGlzLnRpbWVTdGVwLFxuICAgICAgICAgICAgdGhpcy50aW1lc1xuICAgICAgICApO1xuICAgICAgICB0aGlzLnVuc2VsZWN0QWxsSXRlbXMoKTtcbiAgICAgICAgaWYgKGlzRmluaXRlKGluZGV4KSkge1xuICAgICAgICAgICAgdGhpcy5pdGVtc1NvdXJjZVswXS5pdGVtc1NvdXJjZVtpbmRleF0uaXNTZWxlY3RlZCA9IHRydWU7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5pdGVtc1NvdXJjZVswXS5pdGVtc1NvdXJjZVtpbmRleF07XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwdWJsaWMgdW5zZWxlY3RBbGxJdGVtcygpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5pdGVtc1NvdXJjZVswXS5pdGVtc1NvdXJjZS5mb3JFYWNoKFxuICAgICAgICAgICAgKGVsOiBJTWVudUl0ZW0pID0+IChlbC5pc1NlbGVjdGVkID0gZmFsc2UpXG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgcHVibGljIGZvcm1hdFZhbHVlKHZhbHVlOiBhbnkgPSB0aGlzLmlubmVyTW9kZWwpOiBzdHJpbmcge1xuICAgICAgICByZXR1cm4gbW9tZW50KHZhbHVlKS5pc1ZhbGlkKClcbiAgICAgICAgICAgID8gbW9tZW50KHZhbHVlKS5mb3JtYXQodGhpcy50aW1lRm9ybWF0KVxuICAgICAgICAgICAgOiB2YWx1ZTtcbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0SWNvbkNvbG9yKCk6IHN0cmluZyB7XG4gICAgICAgIHJldHVybiB0aGlzLmlzRGlzYWJsZWQgPyBcImdyYXlcIiA6IFwicHJpbWFyeS1ibHVlXCI7XG4gICAgfVxuXG4gICA