UNPKG

@microsoft/windows-admin-center-sdk

Version:

Microsoft - Windows Admin Center Shell

463 lines 70 kB
import { __decorate, __metadata } from "tslib"; import { Component, ElementRef, EventEmitter, HostListener, Inject, Injector, IterableDiffers, Optional, Output, Renderer2, ViewChild } from '@angular/core'; import { Yield } from '@microsoft/windows-admin-center-sdk/core/base/decorators/yield.decorator'; import { KeyCode } from '@microsoft/windows-admin-center-sdk/core/data/accessibility-manager'; import { Logging } from '@microsoft/windows-admin-center-sdk/core/diagnostics/logging'; import { take } from 'rxjs/operators'; import { SME_LAYOUT_PROVIDER } from '../../../common/layout'; import { DropdownComponent } from '../../../dropdown/dropdown.component'; import { ActionContainerComponent } from '../action-container.component'; import * as i0 from "@angular/core"; import * as i1 from "@angular/common"; import * as i2 from "../../../dropdown/dropdown.component"; import * as i3 from "../../../tooltip/tooltip.directive"; import * as i4 from "../action-menu/action-menu.component"; import * as i5 from "../../items/dynamic-action-item.component"; const _c0 = ["actionBarElement"]; const _c1 = ["dropDownButton"]; const _c2 = ["dropDown"]; function ActionBarComponent_sme_dynamic_action_item_2_Template(rf, ctx) { if (rf & 1) { const _r6 = i0.ɵɵgetCurrentView(); i0.ɵɵelementStart(0, "sme-dynamic-action-item", 10); i0.ɵɵlistener("itemChanged", function ActionBarComponent_sme_dynamic_action_item_2_Template_sme_dynamic_action_item_itemChanged_0_listener() { i0.ɵɵrestoreView(_r6); const ctx_r5 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r5.onActionItemChanged()); }); i0.ɵɵelementEnd(); } if (rf & 2) { const item_r4 = ctx.$implicit; const ctx_r1 = i0.ɵɵnextContext(); i0.ɵɵclassProp("sme-action-bar-item-no-padding-v", ctx_r1.heightOverflow); i0.ɵɵproperty("item", item_r4); } } const _c3 = ["*"]; /** * * @smeDoc {@label Actions @id sme-actions} * * @overview * @file {@filepath ./examples/overview.md} * * @example {@label Defined actions from component @id defined-actions-from-component} * @file {@filename component.html @filepath ./examples/defined-actions-from-component.component.html} * @file {@filename component.ts @filepath ./examples/actions-example.component.ts} * * @example {@label Defined actions from html @id defined-actions-from-html} * @file {@filename component.html @filepath ./examples/defined-actions-from-html.component.html} * @file {@filename component.ts @filepath ./examples/actions-example.component.ts} * * @example {@label Defined actions from both @id defined-actions-from-both} * @file {@filename component.html @filepath ./examples/defined-actions-from-both.component.html} * @file {@filename component.ts @filepath ./examples/actions-example.component.ts} * * @example {@label All buttons disabled @id all-buttons-disabled} * @file {@filename component.html @filepath ./examples/all-buttons-disabled.component.html} * @file {@filename component.ts @filepath ./examples/actions-example.component.ts} * * @example {@label Model driven action bar @id model-driven} * @file {@filename component.html @filepath ./examples/model-driven.component.html} * @file {@filename component.ts @filepath ./examples/actions-example.component.ts} * * @example {@label Container embedded action bar @id container-embedded-action-bar} * @file {@filename component.html @filepath ./examples/container-embedded-action-bar.component.html} * @file {@filename component.ts @filepath ./examples/actions-example.component.ts} */ export class ActionBarComponent extends ActionContainerComponent { /** * Constructor for the ActionBarComponent. */ constructor(iterableDiffers, renderer, hostElement, layout, injector) { super(iterableDiffers, injector); this.renderer = renderer; this.hostElement = hostElement; /** * List of ActionItem objects that we want to perform. */ this.displayedActions = []; /** * List of ActionItem objects that are collapsed into dropdown. */ this.trayActions = []; /** * Localized set of strings. */ this.strings = MsftSme.getStrings(); this.isCompact = false; this.hovered = false; this.focused = false; this.shouldShow = true; this.isVisible = true; /** * Event fired when list of ActionItems changes. */ this.actionsUpdated = new EventEmitter(); renderer.addClass(hostElement.nativeElement, 'sme-position-stretch-h'); renderer.addClass(hostElement.nativeElement, 'sme-layout-action-bar'); renderer.addClass(hostElement.nativeElement, 'sme-arrange-stack-h'); renderer.addClass(hostElement.nativeElement, 'sme-arrange-ws-nowrap'); renderer.addClass(hostElement.nativeElement, 'sme-arrange-overflow-show'); renderer.setStyle(this.hostElement.nativeElement, 'opacity', 0); this.moreActionsDisplay = this.strings.MsftSmeShell.Angular.Common.more; this.actionsAriaLabel = this.strings.MsftSmeShell.Angular.Common.actions; if (layout) { this.layoutSubscription = layout.layoutChanged.subscribe(() => this.onLayoutChanged()); } } /** * Flag that when set will display minimal UI for the action bar. */ get compact() { return this.isCompact; } /** * Attribute that sets vertical or horizontal orientation where vertical displays action bar from top to bottom of page * and horizontal displays action bar from left to right. */ get orientation() { return 'vertical'; } get isAttached() { return !MsftSme.isNullOrUndefined(this.attachedTo); } /** * Filters out ActionItem objects to be hidden. * @param items ActionItem objects to check. * @returns List of unhidden ActionItem objects. */ hiddenFilter(items) { return items.filter(item => !item.hidden); } /** * Callback triggered after view initializes. */ ngAfterViewInit() { setTimeout(() => { this.updateActionBar(); }); } /** * Callback triggered after component is destroyed. */ ngOnDestroy() { super.ngOnDestroy(); this.layoutSubscription?.unsubscribe(); } /** * On layout changed event handler, occurs every time the layout has been changed. */ onLayoutChanged() { this.updateActionBar(); } /** * Host listeners for focus events. */ onFocusEvent(event) { // on focus in/out change focused state this.focused = event.type === 'focusin' || (this.focused && event.type !== 'focusout'); this.updateHeight(); } /** * Host listeners for keyboard events. */ onToggleKeydown(event) { // accessibility, take focus to the more button after a selection in dropdown elements. switch (event.keyCode) { case KeyCode.Enter: { if (this.dropDown) { if (this.moreButtonElement && this.dropDown.isOpen && this.dropDown.contentElement) { this.moreButtonElement.focus(); } else { this.dropDown.onToggled.pipe(take(1)).subscribe(open => { if (open) { // blur/focus to refresh focus - this will make the tooltip disappear // while menu is open (b/c tooltip will block view) this.dropDownButtonElement.nativeElement.blur(); this.dropDownButtonElement.nativeElement.focus(); this.moreButtonElement = document.activeElement; } }); } } break; } } } /** * Host listeners for mouse events. */ onMouseEvent(event) { // on mouse enter/leave change hovered state this.hovered = event.type === 'mouseenter' || (this.hovered && event.type !== 'mouseleave'); this.updateHeight(); } /** * Host listener for page resize event. */ onResize() { this.updateActionBar(); } /** * Callback triggered after child ActionItem changes. */ onActionItemChanged() { setTimeout(() => { this.updateActionBar(); }); } updateHeight() { if (this.isAttached) { if (this.isVisible && (this.shouldShow || this.focused || this.hovered)) { this.renderer.removeStyle(this.hostElement.nativeElement, 'overflow'); this.renderer.removeClass(this.hostElement.nativeElement, 'sme-animation-fade-out-xs'); this.renderer.addClass(this.hostElement.nativeElement, 'sme-animation-fade-in-xs'); } else { this.renderer.setStyle(this.hostElement.nativeElement, 'opacity', 0); this.renderer.setStyle(this.hostElement.nativeElement, 'overflow', 'hidden'); this.renderer.addClass(this.hostElement.nativeElement, 'sme-animation-fade-out-xs'); } } } /** * Method to set visibility for ActionBarComponent. * @param isVisible True for visible, false for not. */ setVisibility(isVisible) { this.isVisible = isVisible; this.updateHeight(); } /** * Method to set visibility for ActionBarComponent. * @param shouldShow True for showing, false for not. */ showHide(shouldShow) { this.shouldShow = shouldShow; this.updateHeight(); } /** * Repositions given HTMLElement to be relative to its sibling element. * @param element Element to reposition. * @param compact Boolean flag to set whether or not ActionBarComponent should be compact. */ repositionRelativeTo(element, compact) { if (MsftSme.isNullOrUndefined(element.offsetParent)) { return; } let isSibling = false; const siblings = element.parentElement.children; for (let i = 0; i < siblings.length; i++) { const sibling = siblings.item(i); if (sibling === this.hostElement.nativeElement) { isSibling = true; break; } } if (!isSibling) { Logging.logError('ActionBar.repositionRelativeTo', 'ActionBar can only be positioned relative to a sibling element.'); return; } const wasAttached = this.isAttached; this.attachedTo = element; if (!wasAttached) { this.showHide(false); } // when positioning on an element, use compact settings if desired this.isCompact = compact; // change classes to account for different positioning mechanism this.renderer.removeStyle(this.hostElement.nativeElement, 'position'); this.renderer.removeClass(this.hostElement.nativeElement, 'sme-position-stretch-h'); this.renderer.addClass(this.hostElement.nativeElement, 'sme-layout-absolute'); this.renderer.addClass(this.hostElement.nativeElement, 'sme-background-color-base'); // Calculate new position const style = window.getComputedStyle(element); const margin = { top: parseInt(style.marginTop, 10), bottom: parseInt(style.marginBottom, 10), left: parseInt(style.marginLeft, 10), right: parseInt(style.marginRight, 10) }; const border = { top: parseInt(style.borderTop, 10), bottom: parseInt(style.borderBottom, 10), left: parseInt(style.borderLeft, 10), right: parseInt(style.borderRight, 10) }; const availableWidth = element.clientWidth - border.left - border.right - margin.left - margin.right; const availableHeight = element.clientHeight - border.bottom - margin.bottom; const width = Math.min(Math.max(availableWidth / 2, 300), availableWidth); const right = element.offsetParent.clientWidth - (element.offsetLeft + element.clientWidth); const top = element.offsetTop + border.top + margin.top; this.renderer.setStyle(this.hostElement.nativeElement, 'right', `${right}px`); this.renderer.setStyle(this.hostElement.nativeElement, 'top', `${top}px`); this.renderer.setStyle(this.hostElement.nativeElement, 'width', `unset`); this.renderer.setStyle(this.hostElement.nativeElement, 'max-width', `${width}px`); this.renderer.setStyle(this.hostElement.nativeElement, 'max-height', `${availableHeight}px`); this.renderer.setStyle(this.hostElement.nativeElement, 'justify-content', `flex-end`); // if the height of the bar is currently greater than the available height of the target, // then make sure displayed items are adjusted accordingly this.heightOverflow = parseInt(style.height, 10) > availableHeight; setTimeout(() => { this.updateActionBar(); }); } /** * Method to update how ActionBarComponent is displayed. */ updateActionBar() { let currentFill = 0; // Set up the following styles during the UI calculation to make sure the html element flickering won't exceed // the action bar container. // The following inline styles will be removed after the UI calculation is done. const hostElement = this.hostElement.nativeElement; this.renderer.setStyle(hostElement, 'overflow', `hidden`); if (!this.isAttached) { this.renderer.setStyle(hostElement, 'position', `relative`); this.renderer.removeStyle(this.hostElement.nativeElement, 'opacity'); } this.displayedActions = []; this.trayActions = []; const style = getComputedStyle(hostElement); const padding = parseInt(style.getPropertyValue('padding-left'), 10) + parseInt(style.getPropertyValue('padding-right'), 10); const containerWidth = (this.isAttached ? parseInt(style.maxWidth, 10) : hostElement.offsetWidth) - padding; // Firstly, we need to calculate the total width of all buttons without "more" button. let buttonsTotalWidth = 0; for (let i = 0; i < this.actions.length; ++i) { const action = this.actions[i]; // assume hidden actions have a 0 width. When they are un-hidden, there width will change and trigger another update. const actionWidth = action.hidden ? 0 : action.width || 0; buttonsTotalWidth += actionWidth; } if (buttonsTotalWidth <= containerWidth) { for (let index = 0; index < this.actions.length; ++index) { this.displayedActions.push(this.actions[index]); } } else { // If the buttons total width exceeds the container width, then we calculate which button should be // displayed and which button should be put into "more" drop-down. // Note: the available container width should be the container width - "more" button's width. const visibleButtonContainerWidth = containerWidth - this.dropDownButtonElement.nativeElement.offsetWidth; for (let index = 0; index < this.actions.length; ++index) { const action = this.actions[index]; // assume hidden actions have a 0 width. When they are un-hidden, there width will change and trigger another update. const actionWidth = action.hidden ? 0 : action.width || 0; if (currentFill + actionWidth > visibleButtonContainerWidth) { this.trayActions.push(action); } else { this.displayedActions.push(action); } currentFill += actionWidth; } } if (this.displayedActions.length === 0) { this.moreActionsDisplay = this.strings.MsftSmeShell.Angular.Common.actions; } else { this.moreActionsDisplay = this.strings.MsftSmeShell.Angular.Common.more; } // If any action bar width is NaN, that means not all the action-buttons finished rendering on the UI. // Thus "currentFill" is still NaN. Otherwise, we consider all the action-buttons finish rendering. // Then it's time to remove the temporary inline styles. if (!!currentFill) { if (!this.isAttached && (this.shouldShow || this.hovered || this.focused)) { this.renderer.removeStyle(hostElement, 'overflow'); } this.renderer.removeStyle(hostElement, 'position'); } // some action item states depend on what container they reside in. // TrayActions will be updated because they were moved into the actionMenu, // however displayed actions should be reset as they may have moved. if (this.displayedActions && this.displayedActions.length > 0) { this.displayedActions.forEach(action => action.setActionState(this.target, this)); } this.actionsUpdated.emit(); } } /** @nocollapse */ ActionBarComponent.ɵfac = function ActionBarComponent_Factory(t) { return new (t || ActionBarComponent)(i0.ɵɵdirectiveInject(i0.IterableDiffers), i0.ɵɵdirectiveInject(i0.Renderer2), i0.ɵɵdirectiveInject(i0.ElementRef), i0.ɵɵdirectiveInject(SME_LAYOUT_PROVIDER, 8), i0.ɵɵdirectiveInject(i0.Injector)); }; /** @nocollapse */ ActionBarComponent.ɵcmp = /** @pureOrBreakMyCode */ i0.ɵɵdefineComponent({ type: ActionBarComponent, selectors: [["sme-action-bar"]], viewQuery: function ActionBarComponent_Query(rf, ctx) { if (rf & 1) { i0.ɵɵviewQuery(_c0, 5); i0.ɵɵviewQuery(_c1, 5); i0.ɵɵviewQuery(_c2, 5); } if (rf & 2) { let _t; i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.element = _t.first); i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.dropDownButtonElement = _t.first); i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.dropDown = _t.first); } }, hostBindings: function ActionBarComponent_HostBindings(rf, ctx) { if (rf & 1) { i0.ɵɵlistener("focusin", function ActionBarComponent_focusin_HostBindingHandler($event) { return ctx.onFocusEvent($event); })("focusout", function ActionBarComponent_focusout_HostBindingHandler($event) { return ctx.onFocusEvent($event); })("keydown", function ActionBarComponent_keydown_HostBindingHandler($event) { return ctx.onToggleKeydown($event); })("mouseenter", function ActionBarComponent_mouseenter_HostBindingHandler($event) { return ctx.onMouseEvent($event); })("mouseleave", function ActionBarComponent_mouseleave_HostBindingHandler($event) { return ctx.onMouseEvent($event); })("resize", function ActionBarComponent_resize_HostBindingHandler() { return ctx.onResize(); }, false, i0.ɵɵresolveWindow); } }, outputs: { actionsUpdated: "actionsUpdated" }, features: [i0.ɵɵInheritDefinitionFeature], ngContentSelectors: _c3, decls: 12, vars: 16, consts: [["role", "menubar", 1, "sme-position-flex-none", "sme-arrange-stack-h"], ["actionBarElement", ""], ["class", "sme-arrange-stack-h sme-arrange-stack-centered sme-arrange-stack-inline", 3, "item", "sme-action-bar-item-no-padding-v", "itemChanged", 4, "ngFor", "ngForOf"], ["role", "presentation", 1, "sme-position-flex-none", 3, "title", "smeTooltipShow"], ["dropDown", ""], ["type", "button", "role", "menuitem", "aria-haspopup", "true", "data-uta-id", "action-bar-more", 1, "sme-button-trigger", "sme-layout-action-bar-item-height", "sme-button-auto-width", "sme-dropdown-toggle"], ["dropDownButton", ""], [1, "sme-icon", "sme-icon-more", 3, "title"], [1, "sme-screen-reader"], ["role", "menu", 1, "sme-dropdown-content", 3, "actions", "target", "targetChange", "error", "executed"], [1, "sme-arrange-stack-h", "sme-arrange-stack-centered", "sme-arrange-stack-inline", 3, "item", "itemChanged"]], template: function ActionBarComponent_Template(rf, ctx) { if (rf & 1) { i0.ɵɵprojectionDef(); i0.ɵɵelementStart(0, "div", 0, 1); i0.ɵɵtemplate(2, ActionBarComponent_sme_dynamic_action_item_2_Template, 1, 3, "sme-dynamic-action-item", 2); i0.ɵɵelementStart(3, "sme-dropdown", 3, 4)(5, "button", 5, 6); i0.ɵɵelement(7, "span", 7); i0.ɵɵelementStart(8, "span", 8); i0.ɵɵtext(9); i0.ɵɵelementEnd()(); i0.ɵɵelementStart(10, "sme-action-menu", 9); i0.ɵɵlistener("targetChange", function ActionBarComponent_Template_sme_action_menu_targetChange_10_listener($event) { return ctx.target = $event; })("error", function ActionBarComponent_Template_sme_action_menu_error_10_listener($event) { return ctx.error.emit($event); })("executed", function ActionBarComponent_Template_sme_action_menu_executed_10_listener($event) { return ctx.executed.emit($event); }); i0.ɵɵelementEnd()(); i0.ɵɵprojection(11); i0.ɵɵelementEnd(); } if (rf & 2) { const _r2 = i0.ɵɵreference(4); i0.ɵɵattribute("aria-label", ctx.actionsAriaLabel); i0.ɵɵadvance(2); i0.ɵɵproperty("ngForOf", ctx.hiddenFilter(ctx.displayedActions)); i0.ɵɵadvance(1); i0.ɵɵclassProp("sme-layout-hidden", !ctx.compact && ctx.trayActions.length === 0)("sme-layout-none", ctx.compact && ctx.trayActions.length === 0); i0.ɵɵproperty("title", ctx.moreActionsDisplay)("smeTooltipShow", !_r2.isOpen); i0.ɵɵadvance(2); i0.ɵɵclassProp("sme-toggled", _r2.isOpen); i0.ɵɵattribute("aria-label", ctx.moreActionsDisplay)("aria-expanded", _r2.isOpen); i0.ɵɵadvance(2); i0.ɵɵproperty("title", ctx.moreActionsDisplay); i0.ɵɵadvance(2); i0.ɵɵtextInterpolate(ctx.moreActionsDisplay); i0.ɵɵadvance(1); i0.ɵɵproperty("actions", ctx.trayActions)("target", ctx.target); } }, dependencies: [i1.NgForOf, i2.DropdownComponent, i3.TooltipDirective, i4.ActionMenuComponent, i5.DynamicActionItemComponent], encapsulation: 2 }); __decorate([ Yield(), __metadata("design:type", Function), __metadata("design:paramtypes", []), __metadata("design:returntype", void 0) ], ActionBarComponent.prototype, "onLayoutChanged", null); (function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ActionBarComponent, [{ type: Component, args: [{ selector: 'sme-action-bar', template: "<div role=\"menubar\" [attr.aria-label]=\"actionsAriaLabel\" class=\"sme-position-flex-none sme-arrange-stack-h\" #actionBarElement>\r\n <sme-dynamic-action-item *ngFor=\"let item of hiddenFilter(displayedActions)\" [item]=\"item\"\r\n (itemChanged)=\"onActionItemChanged()\"\r\n class=\"sme-arrange-stack-h sme-arrange-stack-centered sme-arrange-stack-inline\"\r\n [class.sme-action-bar-item-no-padding-v]=\"heightOverflow\"></sme-dynamic-action-item>\r\n\r\n <sme-dropdown #dropDown role=\"presentation\" class=\"sme-position-flex-none\"\r\n [class.sme-layout-hidden]=\"!compact && trayActions.length === 0\"\r\n [class.sme-layout-none]=\"compact && trayActions.length === 0\" [title]=\"moreActionsDisplay\" [smeTooltipShow]=\"!this.dropDown.isOpen\">\r\n <button #dropDownButton type=\"button\" [attr.aria-label]=\"moreActionsDisplay\" role=\"menuitem\"\r\n class=\"sme-button-trigger sme-layout-action-bar-item-height sme-button-auto-width sme-dropdown-toggle\"\r\n [class.sme-toggled]=\"dropDown.isOpen\" [attr.aria-expanded]=\"dropDown.isOpen\" aria-haspopup=\"true\"\r\n data-uta-id=\"action-bar-more\">\r\n <span class=\"sme-icon sme-icon-more\" [title]=\"moreActionsDisplay\"></span>\r\n <span class=\"sme-screen-reader\">{{ moreActionsDisplay }}</span>\r\n </button>\r\n <sme-action-menu [actions]=\"trayActions\" role=\"menu\" class=\"sme-dropdown-content\" [(target)]=\"target\"\r\n (error)=\"error.emit($event)\" (executed)=\"executed.emit($event)\"></sme-action-menu>\r\n </sme-dropdown>\r\n <ng-content></ng-content>\r\n</div>\r\n" }] }], function () { return [{ type: i0.IterableDiffers }, { type: i0.Renderer2 }, { type: i0.ElementRef }, { type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [SME_LAYOUT_PROVIDER] }] }, { type: i0.Injector }]; }, { actionsUpdated: [{ type: Output }], element: [{ type: ViewChild, args: ['actionBarElement'] }], dropDownButtonElement: [{ type: ViewChild, args: ['dropDownButton'] }], dropDown: [{ type: ViewChild, args: ['dropDown'] }], onLayoutChanged: [], onFocusEvent: [{ type: HostListener, args: ['focusin', ['$event']] }, { type: HostListener, args: ['focusout', ['$event']] }], onToggleKeydown: [{ type: HostListener, args: ['keydown', ['$event']] }], onMouseEvent: [{ type: HostListener, args: ['mouseenter', ['$event']] }, { type: HostListener, args: ['mouseleave', ['$event']] }], onResize: [{ type: HostListener, args: ['window:resize'] }] }); })(); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWN0aW9uLWJhci5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9hbmd1bGFyL3NyYy9jb250cm9scy9hY3Rpb25zL2NvbnRhaW5lcnMvYWN0aW9uLWJhci9hY3Rpb24tYmFyLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uL2FuZ3VsYXIvc3JjL2NvbnRyb2xzL2FjdGlvbnMvY29udGFpbmVycy9hY3Rpb24tYmFyL2FjdGlvbi1iYXIuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLE9BQU8sRUFFSCxTQUFTLEVBRVQsVUFBVSxFQUNWLFlBQVksRUFDWixZQUFZLEVBQ1osTUFBTSxFQUNOLFFBQVEsRUFDUixlQUFlLEVBRWYsUUFBUSxFQUNSLE1BQU0sRUFDTixTQUFTLEVBQ1QsU0FBUyxFQUNaLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBRSxLQUFLLEVBQUUsTUFBTSwwRUFBMEUsQ0FBQztBQUNqRyxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0scUVBQXFFLENBQUM7QUFDOUYsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLDhEQUE4RCxDQUFDO0FBRXZGLE9BQU8sRUFBRSxJQUFJLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUV0QyxPQUFPLEVBQVUsbUJBQW1CLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUNyRSxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxzQ0FBc0MsQ0FBQztBQUd6RSxPQUFPLEVBQUUsd0JBQXdCLEVBQUUsTUFBTSwrQkFBK0IsQ0FBQzs7Ozs7Ozs7Ozs7O0lDekJ2RSxtREFHNEQ7SUFGMUQsZ05BQWUsZUFBQSw0QkFBcUIsQ0FBQSxJQUFDO0lBRXFCLGlCQUEwQjs7OztJQUFwRix5RUFBeUQ7SUFIa0IsOEJBQWE7OztBRDJCNUY7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztH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O1lBV3RDLFFBQVE7a0JBRFAsWUFBWTttQkFBQyxlQUFlIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcclxuICAgIEFmdGVyVmlld0luaXQsXHJcbiAgICBDb21wb25lbnQsXHJcbiAgICBEb0NoZWNrLFxyXG4gICAgRWxlbWVudFJlZixcclxuICAgIEV2ZW50RW1pdHRlcixcclxuICAgIEhvc3RMaXN0ZW5lcixcclxuICAgIEluamVjdCxcclxuICAgIEluamVjdG9yLFxyXG4gICAgSXRlcmFibGVEaWZmZXJzLFxyXG4gICAgT25EZXN0cm95LFxyXG4gICAgT3B0aW9uYWwsXHJcbiAgICBPdXRwdXQsXHJcbiAgICBSZW5kZXJlcjIsXHJcbiAgICBWaWV3Q2hpbGRcclxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHsgWWllbGQgfSBmcm9tICdAbWljcm9zb2Z0L3dpbmRvd3MtYWRtaW4tY2VudGVyLXNkay9jb3JlL2Jhc2UvZGVjb3JhdG9ycy95aWVsZC5kZWNvcmF0b3InO1xyXG5pbXBvcnQgeyBLZXlDb2RlIH0gZnJvbSAnQG1pY3Jvc29mdC93aW5kb3dzLWFkbWluLWNlbnRlci1zZGsvY29yZS9kYXRhL2FjY2Vzc2liaWxpdHktbWFuYWdlcic7XHJcbmltcG9ydCB7IExvZ2dpbmcgfSBmcm9tICdAbWljcm9zb2Z0L3dpbmRvd3MtYWRtaW4tY2VudGVyLXNkay9jb3JlL2RpYWdub3N0aWNzL2xvZ2dpbmcnO1xyXG5pbXBvcnQgeyBTdWJzY3JpcHRpb24gfSBmcm9tICdyeGpzJztcclxuaW1wb3J0IHsgdGFrZSB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcclxuaW1wb3J0IHsgU3RyaW5ncyB9IGZyb20gJy4uLy4uLy4uLy4uL2dlbmVyYXRlZC9zdHJpbmdzJztcclxuaW1wb3J0IHsgTGF5b3V0LCBTTUVfTEFZT1VUX1BST1ZJREVSIH0gZnJvbSAnLi4vLi4vLi4vY29tbW9uL2xheW91dCc7XHJcbmltcG9ydCB7IERyb3Bkb3duQ29tcG9uZW50IH0gZnJvbSAnLi4vLi4vLi4vZHJvcGRvd24vZHJvcGRvd24uY29tcG9uZW50JztcclxuaW1wb3J0IHsgQWN0aW9uSXRlbSB9IGZyb20gJy4uLy4uL2l0ZW1zL2FjdGlvbi1pdGVtLmNvbXBvbmVudCc7XHJcbmltcG9ydCB7IEFjdGlvbkNvbnRhaW5lck9yaWVudGF0aW9uIH0gZnJvbSAnLi4vYWN0aW9uLWNvbnRhaW5lcic7XHJcbmltcG9ydCB7IEFjdGlvbkNvbnRhaW5lckNvbXBvbmVudCB9IGZyb20gJy4uL2FjdGlvbi1jb250YWluZXIuY29tcG9uZW50JztcclxuXHJcbi8qKlxyXG4gKlxyXG4gKiBAc21lRG9jIHtAbGFiZWwgQWN0aW9ucyBAaWQgc21lLWFjdGlvbnN9XHJcbiAqXHJcbiAqIEBvdmVydmlld1xyXG4gKiBAZmlsZSB7QGZpbGVwYXRoIC4vZXhhbXBsZXMvb3ZlcnZpZXcubWR9XHJcbiAqXHJcbiAqIEBleGFtcGxlIHtAbGFiZWwgRGVmaW5lZCBhY3Rpb25zIGZyb20gY29tcG9uZW50IEBpZCBkZWZpbmVkLWFjdGlvbnMtZnJvbS1jb21wb25lbnR9XHJcbiAqIEBmaWxlIHtAZmlsZW5hbWUgY29tcG9uZW50Lmh0bWwgQGZpbGVwYXRoIC4vZXhhbXBsZXMvZGVmaW5lZC1hY3Rpb25zLWZyb20tY29tcG9uZW50LmNvbXBvbmVudC5odG1sfVxyXG4gKiBAZmlsZSB7QGZpbGVuYW1lIGNvbXBvbmVudC50cyBAZmlsZXBhdGggLi9leGFtcGxlcy9hY3Rpb25zLWV4YW1wbGUuY29tcG9uZW50LnRzfVxyXG4gKlxyXG4gKiBAZXhhbXBsZSB7QGxhYmVsIERlZmluZWQgYWN0aW9ucyBmcm9tIGh0bWwgQGlkIGRlZmluZWQtYWN0aW9ucy1mcm9tLWh0bWx9XHJcbiAqIEBmaWxlIHtAZmlsZW5hbWUgY29tcG9uZW50Lmh0bWwgQGZpbGVwYXRoIC4vZXhhbXBsZXMvZGVmaW5lZC1hY3Rpb25zLWZyb20taHRtbC5jb21wb25lbnQuaHRtbH1cclxuICogQGZpbGUge0BmaWxlbmFtZSBjb21wb25lbnQudHMgQGZpbGVwYXRoIC4vZXhhbXBsZXMvYWN0aW9ucy1leGFtcGxlLmNvbXBvbmVudC50c31cclxuICpcclxuICogQGV4YW1wbGUge0BsYWJlbCBEZWZpbmVkIGFjdGlvbnMgZnJvbSBib3RoIEBpZCBkZWZpbmVkLWFjdGlvbnMtZnJvbS1ib3RofVxyXG4gKiBAZmlsZSB7QGZpbGVuYW1lIGNvbXBvbmVudC5odG1sIEBmaWxlcGF0aCAuL2V4YW1wbGVzL2RlZmluZWQtYWN0aW9ucy1mcm9tLWJvdGguY29tcG9uZW50Lmh0bWx9XHJcbiAqIEBmaWxlIHtAZmlsZW5hbWUgY29tcG9uZW50LnRzIEBmaWxlcGF0aCAuL2V4YW1wbGVzL2FjdGlvbnMtZXhhbXBsZS5jb21wb25lbnQudHN9XHJcbiAqXHJcbiAqIEBleGFtcGxlIHtAbGFiZWwgQWxsIGJ1dHRvbnMgZGlzYWJsZWQgQGlkIGFsbC1idXR0b25zLWRpc2FibGVkfVxyXG4gKiBAZmlsZSB7QGZpbGVuYW1lIGNvbXBvbmVudC5odG1sIEBmaWxlcGF0aCAuL2V4YW1wbGVzL2FsbC1idXR0b25zLWRpc2FibGVkLmNvbXBvbmVudC5odG1sfVxyXG4gKiBAZmlsZSB7QGZpbGVuYW1lIGNvbXBvbmVudC50cyBAZmlsZXBhdGggLi9leGFtcGxlcy9hY3Rpb25zLWV4YW1wbGUuY29tcG9uZW50LnRzfVxyXG4gKlxyXG4gKiBAZXhhbXBsZSB7QGxhYmVsIE1vZGVsIGRyaXZlbiBhY3Rpb24gYmFyIEBpZCBtb2RlbC1kcml2ZW59XHJcbiAqIEBmaWxlIHtAZmlsZW5hbWUgY29tcG9uZW50Lmh0bWwgQGZpbGVwYXRoIC4vZXhhbXBsZXMvbW9kZWwtZHJpdmVuLmNvbXBvbmVudC5odG1sfVxyXG4gKiBAZmlsZSB7QGZpbGVuYW1lIGNvbXBvbmVudC50cyBAZmlsZXBhdGggLi9leGFtcGxlcy9hY3Rpb25zLWV4YW1wbGUuY29tcG9uZW50LnRzfVxyXG4gKlxyXG4gKiBAZXhhbXBsZSB7QGxhYmVsIENvbnRhaW5lciBlbWJlZGRlZCBhY3Rpb24gYmFyIEBpZCBjb250YWluZXItZW1iZWRkZWQtYWN0aW9uLWJhcn1cclxuICogQGZpbGUge0BmaWxlbmFtZSBjb21wb25lbnQuaHRtbCBAZmlsZXBhdGggLi9leGFtcGxlcy9jb250YWluZXItZW1iZWRkZWQtYWN0aW9uLWJhci5jb21wb25lbnQuaHRtbH1cclxuICogQGZpbGUge0BmaWxlbmFtZSBjb21wb25lbnQudHMgQGZpbGVwYXRoIC4vZXhhbXBsZXMvYWN0aW9ucy1leGFtcGxlLmNvbXBvbmVudC50c31cclxuICovXHJcblxyXG5AQ29tcG9uZW50KHtcclxuICAgIHNlbGVjdG9yOiAnc21lLWFjdGlvbi1iYXInLFxyXG4gICAgdGVtcGxhdGVVcmw6ICcuL2FjdGlvbi1iYXIuY29tcG9uZW50Lmh0bWwnXHJcbn0pXHJcbmV4cG9ydCBjbGFzcyBBY3Rpb25CYXJDb21wb25lbnQgZXh0ZW5kcyBBY3Rpb25Db250YWluZXJDb21wb25lbnQgaW1wbGVtZW50cyBEb0NoZWNrLCBBZnRlclZpZXdJbml0LCBPbkRlc3Ryb3kge1xyXG4gICAgcHJvdGVjdGVkIGxvZ1NvdXJjZU5hbWU6IHN0cmluZztcclxuXHJcbiAgICAvKipcclxuICAgICAqIEZsYWcgdGhhdCB3aGVuIHNldCB3aWxsIGRpc3BsYXkgbWluaW1hbCBVSSBmb3IgdGhlIGFjdGlvbiBiYXIuXHJcbiAgICAgKi9cclxuICAgIHB1YmxpYyBnZXQgY29tcGFjdCgpOiBib29sZWFuIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5pc0NvbXBhY3Q7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBBdHRyaWJ1dGUgdGhhdCBzZXRzIHZlcnRpY2FsIG9yIGhvcml6b250YWwgb3JpZW50YXRpb24gd2hlcmUgdmVydGljYWwgZGlzcGxheXMgYWN0aW9uIGJhciBmcm9tIHRvcCB0byBib3R0b20gb2YgcGFnZVxyXG4gICAgICogYW5kIGhvcml6b250YWwgZGlzcGxheXMgYWN0aW9uIGJhciBmcm9tIGxlZnQgdG8gcmlnaHQuXHJcbiAgICAgKi9cclxuICAgIHB1YmxpYyBnZXQgb3JpZW50YXRpb24oKTogQWN0aW9uQ29udGFpbmVyT3JpZW50YXRpb24ge1xyXG4gICAgICAgIHJldHVybiAndmVydGljYWwnO1xyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogTGlzdCBvZiBBY3Rpb25JdGVtIG9iamVjdHMgdGhhdCB3ZSB3YW50IHRvIHBlcmZvcm0uXHJcbiAgICAgKi9cclxuICAgIHB1YmxpYyBkaXNwbGF5ZWRBY3Rpb25zOiBBY3Rpb25JdGVtW10gPSBbXTtcclxuXHJcbiAgICAvKipcclxuICAgICAqIExpc3Qgb2YgQWN0aW9uSXRlbSBvYmplY3RzIHRoYXQgYXJlIGNvbGxhcHNlZCBpbnRvIGRyb3Bkb3duLlxyXG4gICAgICovXHJcbiAgICBwdWJsaWMgdHJheUFjdGlvbnM6IEFjdGlvbkl0ZW1bXSA9IFtdO1xyXG5cclxuICAgIC8qKlxyXG4gICAgICogVGV4dCBkaXNwbGF5ZWQgZm9yIHRyYXkgZHJvcGRvd24uXHJcbiAgICAgKi9cclxuICAgIHB1YmxpYyBtb3JlQWN0aW9uc0Rpc3BsYXk6IHN0cmluZztcclxuXHJcbiAgICAvKipcclxuICAgICAqIExhYmVsIG9uIGFjdGlvbiBtZW51IGZvciBhY2Nlc3NpYmlsaXR5LlxyXG4gICAgICovXHJcbiAgICBwdWJsaWMgYWN0aW9uc0FyaWFMYWJlbDogc3RyaW5nO1xyXG5cclxuICAgIC8qKlxyXG4gICAgICogRmxhZyB0byBtYWtlIHN1cmUgaWYgdGhlIGhlaWdodCBvZiB0aGUgYmFyIGlzIGN1cnJlbnRseSBncmVhdGVyIHRoYW4gdGhlIGF2YWlsYWJsZSBoZWlnaHQgb2YgdGhlIHRhcmdldCxcclxuICAgICAqIHRoZW4gdGhlIGl0ZW1zIGFyZSBhZGp1c3RlZCBhY2NvcmRpbmdseS5cclxuICAgICAqL1xyXG4gICAgcHVibGljIGhlaWdodE92ZXJmbG93OiBib29sZWFuO1xyXG5cclxuICAgIC8qKlxyXG4gICAgICogQnV0dG9uIGVsZW1lbnQgZm9yIHRyYXkgZHJvcGRvd24uXHJcbiAgICAgKi9cclxuICAgIHB1YmxpYyBtb3JlQnV0dG9uRWxlbWVudDogSFRNTEVsZW1lbnQ7XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBMb2NhbGl6ZWQgc2V0IG9mIHN0cmluZ3MuXHJcbiAgICAgKi9cclxuICAgIHB1YmxpYyBzdHJpbmdzID0gTXNmdFNtZS5nZXRTdHJpbmdzPFN0cmluZ3M+KCk7XHJcbiAgICBwcml2YXRlIGlzQ29tcGFjdCA9IGZhbHNlO1xyXG4gICAgcHJpdmF0ZSBob3ZlcmVkID0gZmFsc2U7XHJcbiAgICBwcml2YXRlIGZvY3VzZWQgPSBmYWxzZTtcclxuICAgIHByaXZhdGUgYXR0YWNoZWRUbzogSFRNTEVsZW1lbnQ7XHJcbiAgICBwcml2YXRlIHNob3VsZFNob3cgPSB0cnVlO1xyXG4gICAgcHJpdmF0ZSBpc1Zpc2libGUgPSB0cnVlO1xyXG4gICAgcHJpdmF0ZSBsYXlvdXRTdWJzY3JpcHRpb246IFN1YnNjcmlwdGlvbjtcclxuXHJcbiAgICAvKipcclxuICAgICAqIEV2ZW50IGZpcmVkIHdoZW4gbGlzdCBvZiBBY3Rpb25JdGVtcyBjaGFuZ2VzLlxyXG4gICAgICovXHJcbiAgICBAT3V0cHV0KClcclxuICAgIHB1YmxpYyBhY3Rpb25zVXBkYXRlZCA9IG5ldyBFdmVudEVtaXR0ZXI8YW55PigpO1xyXG5cclxuICAgIHByaXZhdGUgZ2V0IGlzQXR0YWNoZWQoKTogYm9vbGVhbiB7XHJcbiAgICAgICAgcmV0dXJuICFNc2Z0U21lLmlzTnVsbE9yVW5kZWZpbmVkKHRoaXMuYXR0YWNoZWRUbyk7XHJcbiAgICB9XHJcblxyXG4gICAgQFZpZXdDaGlsZCgnYWN0aW9uQmFyRWxlbWVudCcpIHByaXZhdGUgZWxlbWVudDogRWxlbWVudFJlZjtcclxuICAgIEBWaWV3Q2hpbGQoJ2Ryb3BEb3duQnV0dG9uJykgcHJpdmF0ZSBkcm9wRG93bkJ1dHRvbkVsZW1lbnQ6IEVsZW1lbnRSZWY7XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBEcm9wZG93bkNvbXBvbmVudCBlbGVtZW50IGZvciBhY3Rpb24gdHJheS5cclxuICAgICAqL1xyXG4gICAgQFZpZXdDaGlsZCgnZHJvcERvd24nKSBwdWJsaWMgZHJvcERvd246IERyb3Bkb3duQ29tcG9uZW50O1xyXG5cclxuICAgIC8qKlxyXG4gICAgICogQ29uc3RydWN0b3IgZm9yIHRoZSBBY3Rpb25CYXJDb21wb25lbnQuXHJcbiAgICAgKi9cclxuICAgIGNvbnN0cnVjdG9yKGl0ZXJhYmxlRGlmZmVyczogSXRlcmFibGVEaWZmZXJzLCBwdWJsaWMgcmVuZGVyZXI6IFJlbmRlcmVyMiwgcHVibGljIGhvc3RFbGVtZW50OiBFbGVtZW50UmVmLFxyXG4gICAgICAgIEBPcHRpb25hbCgpIEBJbmplY3QoU01FX0xBWU9VVF9QUk9WSURFUikgbGF5b3V0OiBMYXlvdXQsIGluamVjdG9yOiBJbmplY3Rvcikge1xyXG4gICAgICAgIHN1cGVyKGl0ZXJhYmxlRGlmZmVycywgaW5qZWN0b3IpO1xyXG4gICAgICAgIHJlbmRlcmVyLmFkZENsYXNzKGhvc3RFbGVtZW50Lm5hdGl2ZUVsZW1lbnQsICdzbWUtcG9zaXRpb24tc3RyZXRjaC1oJyk7XHJcbiAgICAgICAgcmVuZGVyZXIuYWRkQ2xhc3MoaG9zdEVsZW1lbnQubmF0aXZlRWxlbWVudCwgJ3NtZS1sYXlvdXQtYWN0aW9uLWJhcicpO1xyXG4gICAgICAgIHJlbmRlcmVyLmFkZENsYXNzKGhvc3RFbGVtZW50Lm5hdGl2ZUVsZW1lbnQsICdzbWUtYXJyYW5nZS1zdGFjay1oJyk7XHJcbiAgICAgICAgcmVuZGVyZXIuYWRkQ2xhc3MoaG9zdEVsZW1lbnQubmF0aXZlRWxlbWVudCwgJ3NtZS1hcnJhbmdlLXdzLW5vd3JhcCcpO1xyXG4gICAgICAgIHJlbmRlcmVyLmFkZENsYXNzKGhvc3RFbGVtZW50Lm5hdGl2ZUVsZW1lbnQsICdzbWUtYXJyYW5nZS1vdmVyZmxvdy1zaG93Jyk7XHJcbiAgICAgICAgcmVuZGVyZXIuc2V0U3R5bGUodGhpcy5ob3N0RWxlbWVudC5uYXRpdmVFbGVtZW50LCAnb3BhY2l0eScsIDApO1xyXG4gICAgICAgIHRoaXMu