UNPKG

@igor2017/sat-popover

Version:
465 lines 60.8 kB
import { Component, ElementRef, EventEmitter, Inject, Input, ViewChild, ViewEncapsulation, TemplateRef, Optional, Output, Directive } from '@angular/core'; import { DOCUMENT } from '@angular/common'; import { coerceBooleanProperty, coerceNumberProperty } from '@angular/cdk/coercion'; import { transformPopover } from './popover.animations'; import { getUnanchoredPopoverError, getInvalidHorizontalAlignError, getInvalidVerticalAlignError, getInvalidScrollStrategyError, getInvalidPopoverAnchorError, getInvalidSatPopoverAnchorError, getInvalidPopoverError } from './popover.errors'; import { VALID_SCROLL, VALID_HORIZ_ALIGN, VALID_VERT_ALIGN } from './types'; import { SatPopoverAnchoringService } from './popover-anchoring.service'; import { DEFAULT_TRANSITION } from './tokens'; import * as i0 from "@angular/core"; import * as i1 from "@angular/cdk/a11y"; import * as i2 from "./popover-anchoring.service"; import * as i3 from "@angular/common"; const DEFAULT_OPEN_ANIMATION_START_SCALE = 0.3; const DEFAULT_CLOSE_ANIMATION_END_SCALE = 0.5; class SatPopoverAnchor { elementRef; viewContainerRef; get popover() { return this._popover; } set popover(val) { if (val instanceof SatPopover) { val.anchor = this; } else { // when a directive is added with no arguments, // angular assigns `''` as the argument if (val !== '') { throw getInvalidPopoverError(); } } } /** @internal */ _popover; constructor(elementRef, viewContainerRef) { this.elementRef = elementRef; this.viewContainerRef = viewContainerRef; } ngAfterViewInit() { if (!this.popover) { throw getInvalidSatPopoverAnchorError(); } } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: SatPopoverAnchor, deps: [{ token: i0.ElementRef }, { token: i0.ViewContainerRef }], target: i0.ɵɵFactoryTarget.Directive }); static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.0.0", type: SatPopoverAnchor, selector: "[satPopoverAnchor]", inputs: { popover: ["satPopoverAnchor", "popover"] }, exportAs: ["satPopoverAnchor"], ngImport: i0 }); } export { SatPopoverAnchor }; i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: SatPopoverAnchor, decorators: [{ type: Directive, args: [{ selector: '[satPopoverAnchor]', exportAs: 'satPopoverAnchor' }] }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.ViewContainerRef }]; }, propDecorators: { popover: [{ type: Input, args: ['satPopoverAnchor'] }] } }); class SatPopover { _focusTrapFactory; _viewContainerRef; _defaultTransition; _document; /** Anchor element. */ get anchor() { return this._anchor; } set anchor(val) { if (val instanceof SatPopoverAnchor) { val._popover = this; this._anchoringService.anchor(this, val.viewContainerRef, val.elementRef); this._anchor = val; } else if (val instanceof ElementRef || val instanceof HTMLElement) { this._anchoringService.anchor(this, this._viewContainerRef, val); this._anchor = val; } else if (val) { throw getInvalidPopoverAnchorError(); } } _anchor; /** Alignment of the popover on the horizontal axis. */ get horizontalAlign() { return this._horizontalAlign; } set horizontalAlign(val) { this._validateHorizontalAlign(val); if (this._horizontalAlign !== val) { this._horizontalAlign = val; this._anchoringService.repositionPopover(); } } _horizontalAlign = 'center'; /** Alignment of the popover on the x axis. Alias for `horizontalAlign`. */ get xAlign() { return this.horizontalAlign; } set xAlign(val) { this.horizontalAlign = val; } /** Alignment of the popover on the vertical axis. */ get verticalAlign() { return this._verticalAlign; } set verticalAlign(val) { this._validateVerticalAlign(val); if (this._verticalAlign !== val) { this._verticalAlign = val; this._anchoringService.repositionPopover(); } } _verticalAlign = 'center'; /** Alignment of the popover on the y axis. Alias for `verticalAlign`. */ get yAlign() { return this.verticalAlign; } set yAlign(val) { this.verticalAlign = val; } /** Whether the popover always opens with the specified alignment. */ get forceAlignment() { return this._forceAlignment; } set forceAlignment(val) { const coercedVal = coerceBooleanProperty(val); if (this._forceAlignment !== coercedVal) { this._forceAlignment = coercedVal; this._anchoringService.repositionPopover(); } } _forceAlignment = false; /** * Whether the popover's alignment is locked after opening. This prevents the popover * from changing its alignement when scrolling or changing the size of the viewport. */ get lockAlignment() { return this._lockAlignment; } set lockAlignment(val) { const coercedVal = coerceBooleanProperty(val); if (this._lockAlignment !== coercedVal) { this._lockAlignment = coerceBooleanProperty(val); this._anchoringService.repositionPopover(); } } _lockAlignment = false; /** Whether the first focusable element should be focused on open. */ get autoFocus() { return this._autoFocus && this._autoFocusOverride; } set autoFocus(val) { this._autoFocus = coerceBooleanProperty(val); } _autoFocus = true; _autoFocusOverride = true; /** Whether the popover should return focus to the previously focused element after closing. */ get restoreFocus() { return this._restoreFocus && this._restoreFocusOverride; } set restoreFocus(val) { this._restoreFocus = coerceBooleanProperty(val); } _restoreFocus = true; _restoreFocusOverride = true; /** How the popover should handle scrolling. */ get scrollStrategy() { return this._scrollStrategy; } set scrollStrategy(val) { this._validateScrollStrategy(val); if (this._scrollStrategy !== val) { this._scrollStrategy = val; this._anchoringService.updatePopoverConfig(); } } _scrollStrategy = 'reposition'; /** Whether the popover should have a backdrop (includes closing on click). */ get hasBackdrop() { return this._hasBackdrop; } set hasBackdrop(val) { this._hasBackdrop = coerceBooleanProperty(val); } _hasBackdrop = false; /** Whether the popover should close when the user clicks the backdrop or presses ESC. */ get interactiveClose() { return this._interactiveClose; } set interactiveClose(val) { this._interactiveClose = coerceBooleanProperty(val); } _interactiveClose = true; /** Custom transition to use while opening. */ get openTransition() { return this._openTransition; } set openTransition(val) { if (val) { this._openTransition = val; } } _openTransition = this._defaultTransition; /** Custom transition to use while closing. */ get closeTransition() { return this._closeTransition; } set closeTransition(val) { if (val) { this._closeTransition = val; } } _closeTransition = this._defaultTransition; /** Scale value at the start of the :enter animation. */ get openAnimationStartAtScale() { return this._openAnimationStartAtScale; } set openAnimationStartAtScale(val) { const coercedVal = coerceNumberProperty(val); if (!isNaN(coercedVal)) { this._openAnimationStartAtScale = coercedVal; } } _openAnimationStartAtScale = DEFAULT_OPEN_ANIMATION_START_SCALE; /** Scale value at the end of the :leave animation */ get closeAnimationEndAtScale() { return this._closeAnimationEndAtScale; } set closeAnimationEndAtScale(val) { const coercedVal = coerceNumberProperty(val); if (!isNaN(coercedVal)) { this._closeAnimationEndAtScale = coercedVal; } } _closeAnimationEndAtScale = DEFAULT_CLOSE_ANIMATION_END_SCALE; /** Optional backdrop class. */ backdropClass = ''; /** Optional custom class to add to the overlay pane. */ panelClass = ''; /** Emits when the popover is opened. */ opened = new EventEmitter(); /** Emits when the popover is closed. */ closed = new EventEmitter(); /** Emits when the popover has finished opening. */ afterOpen = new EventEmitter(); /** Emits when the popover has finished closing. */ afterClose = new EventEmitter(); /** Emits when the backdrop is clicked. */ backdropClicked = new EventEmitter(); /** Emits when a keydown event is targeted to this popover's overlay. */ overlayKeydown = new EventEmitter(); /** Reference to template so it can be placed within a portal. */ _templateRef; /** Classes to be added to the popover for setting the correct transform origin. */ _classList = {}; /** Whether the popover is presently open. */ _open = false; _state = 'enter'; /** @internal */ _anchoringService; /** Reference to the element to build a focus trap around. */ _focusTrapElement; /** Reference to the element that was focused before opening. */ _previouslyFocusedElement; /** Reference to a focus trap around the popover. */ _focusTrap; constructor(_focusTrapFactory, _anchoringService, _viewContainerRef, _defaultTransition, _document) { this._focusTrapFactory = _focusTrapFactory; this._viewContainerRef = _viewContainerRef; this._defaultTransition = _defaultTransition; this._document = _document; // `@internal` stripping doesn't seem to work if the property is // declared inside the constructor this._anchoringService = _anchoringService; this._openTransition = this._defaultTransition; this._closeTransition = this._defaultTransition; } ngOnInit() { this._setAlignmentClasses(); } /** Open this popover. */ open(options = {}) { if (this._anchor) { this._anchoringService.openPopover(options); return; } throw getUnanchoredPopoverError(); } /** Close this popover. */ close(value) { this._anchoringService.closePopover(value); } /** Toggle this popover open or closed. */ toggle() { this._anchoringService.togglePopover(); } /** Realign the popover to the anchor. */ realign() { this._anchoringService.realignPopoverToAnchor(); } /** Gets whether the popover is presently open. */ isOpen() { return this._open; } /** Allows programmatically setting a custom anchor. */ setCustomAnchor(viewContainer, el) { this._anchor = el; this._anchoringService.anchor(this, viewContainer, el); } /** Gets an animation config with customized (or default) transition values. */ get state() { return this._state; } get params() { return { openTransition: this.openTransition, closeTransition: this.closeTransition, startAtScale: this.openAnimationStartAtScale, endAtScale: this.closeAnimationEndAtScale }; } /** Callback for when the popover is finished animating in or out. */ _onAnimationDone({ toState }) { if (toState === 'enter') { this._trapFocus(); this.afterOpen.emit(); } else if (toState === 'exit' || toState === 'void') { this._restoreFocusAndDestroyTrap(); this.afterClose.emit(); } } /** Starts the dialog exit animation. */ _startExitAnimation() { this._state = 'exit'; } /** Apply alignment classes based on alignment inputs. */ _setAlignmentClasses(horizAlign = this.horizontalAlign, vertAlign = this.verticalAlign) { this._classList['sat-popover-before'] = horizAlign === 'before' || horizAlign === 'end'; this._classList['sat-popover-after'] = horizAlign === 'after' || horizAlign === 'start'; this._classList['sat-popover-above'] = vertAlign === 'above' || vertAlign === 'end'; this._classList['sat-popover-below'] = vertAlign === 'below' || vertAlign === 'start'; this._classList['sat-popover-center'] = horizAlign === 'center' || vertAlign === 'center'; } /** Move the focus inside the focus trap and remember where to return later. */ _trapFocus() { this._savePreviouslyFocusedElement(); // There won't be a focus trap element if the close animation starts before open finishes if (!this._focusTrapElement) { return; } if (!this._focusTrap && this._focusTrapElement) { this._focusTrap = this._focusTrapFactory.create(this._focusTrapElement.nativeElement); } if (this.autoFocus) { this._focusTrap.focusInitialElementWhenReady(); } } /** Restore focus to the element focused before the popover opened. Also destroy trap. */ _restoreFocusAndDestroyTrap() { const toFocus = this._previouslyFocusedElement; // Must check active element is focusable for IE sake if (toFocus && 'focus' in toFocus && this.restoreFocus) { this._previouslyFocusedElement.focus(); } this._previouslyFocusedElement = null; if (this._focusTrap) { this._focusTrap.destroy(); this._focusTrap = undefined; } } /** Save a reference to the element focused before the popover was opened. */ _savePreviouslyFocusedElement() { if (this._document) { this._previouslyFocusedElement = this._document.activeElement; } } /** Throws an error if the alignment is not a valid horizontalAlign. */ _validateHorizontalAlign(pos) { if (VALID_HORIZ_ALIGN.indexOf(pos) === -1) { throw getInvalidHorizontalAlignError(pos); } } /** Throws an error if the alignment is not a valid verticalAlign. */ _validateVerticalAlign(pos) { if (VALID_VERT_ALIGN.indexOf(pos) === -1) { throw getInvalidVerticalAlignError(pos); } } /** Throws an error if the scroll strategy is not a valid strategy. */ _validateScrollStrategy(strategy) { if (VALID_SCROLL.indexOf(strategy) === -1) { throw getInvalidScrollStrategyError(strategy); } } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: SatPopover, deps: [{ token: i1.ConfigurableFocusTrapFactory }, { token: i2.SatPopoverAnchoringService }, { token: i0.ViewContainerRef }, { token: DEFAULT_TRANSITION }, { token: DOCUMENT, optional: true }], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.0.0", type: SatPopover, selector: "sat-popover", inputs: { anchor: "anchor", horizontalAlign: "horizontalAlign", xAlign: "xAlign", verticalAlign: "verticalAlign", yAlign: "yAlign", forceAlignment: "forceAlignment", lockAlignment: "lockAlignment", autoFocus: "autoFocus", restoreFocus: "restoreFocus", scrollStrategy: "scrollStrategy", hasBackdrop: "hasBackdrop", interactiveClose: "interactiveClose", openTransition: "openTransition", closeTransition: "closeTransition", openAnimationStartAtScale: "openAnimationStartAtScale", closeAnimationEndAtScale: "closeAnimationEndAtScale", backdropClass: "backdropClass", panelClass: "panelClass" }, outputs: { opened: "opened", closed: "closed", afterOpen: "afterOpen", afterClose: "afterClose", backdropClicked: "backdropClicked", overlayKeydown: "overlayKeydown" }, providers: [SatPopoverAnchoringService], viewQueries: [{ propertyName: "_templateRef", first: true, predicate: TemplateRef, descendants: true, static: true }, { propertyName: "_focusTrapElement", first: true, predicate: ["focusTrapElement"], descendants: true }], ngImport: i0, template: "<ng-template>\n <div\n class=\"sat-popover-container\"\n #focusTrapElement\n [ngClass]=\"_classList\"\n [@transformPopover]=\"{ value: state, params: params }\"\n (@transformPopover.done)=\"_onAnimationDone($event)\"\n >\n <ng-content></ng-content>\n </div>\n</ng-template>\n", styles: [".cdk-overlay-container,.cdk-global-overlay-wrapper{pointer-events:none;top:0;left:0;height:100%;width:100%}.cdk-overlay-container{position:fixed;z-index:1000}.cdk-overlay-container:empty{display:none}.cdk-global-overlay-wrapper{display:flex;position:absolute;z-index:1000}.cdk-overlay-pane{position:absolute;pointer-events:auto;box-sizing:border-box;z-index:1000;display:flex;max-width:100%;max-height:100%}.cdk-overlay-backdrop{position:absolute;inset:0;z-index:1000;pointer-events:auto;-webkit-tap-highlight-color:transparent;transition:opacity .4s cubic-bezier(.25,.8,.25,1);opacity:0}.cdk-overlay-backdrop.cdk-overlay-backdrop-showing{opacity:1}.cdk-high-contrast-active .cdk-overlay-backdrop.cdk-overlay-backdrop-showing{opacity:.6}.cdk-overlay-dark-backdrop{background:rgba(0,0,0,.32)}.cdk-overlay-transparent-backdrop{transition:visibility 1ms linear,opacity 1ms linear;visibility:hidden;opacity:1}.cdk-overlay-transparent-backdrop.cdk-overlay-backdrop-showing{opacity:0;visibility:visible}.cdk-overlay-backdrop-noop-animation{transition:none}.cdk-overlay-connected-position-bounding-box{position:absolute;z-index:1000;display:flex;flex-direction:column;min-width:1px;min-height:1px}.cdk-global-scrollblock{position:fixed;width:100%;overflow-y:scroll}.sat-popover-container.sat-popover-before.sat-popover-above{transform-origin:right bottom}[dir=rtl] .sat-popover-container.sat-popover-before.sat-popover-above{transform-origin:left bottom}.sat-popover-container.sat-popover-before.sat-popover-center{transform-origin:right center}[dir=rtl] .sat-popover-container.sat-popover-before.sat-popover-center{transform-origin:left center}.sat-popover-container.sat-popover-before.sat-popover-below{transform-origin:right top}[dir=rtl] .sat-popover-container.sat-popover-before.sat-popover-below{transform-origin:left top}.sat-popover-container.sat-popover-center.sat-popover-above{transform-origin:center bottom}.sat-popover-container.sat-popover-center.sat-popover-below{transform-origin:center top}.sat-popover-container.sat-popover-after.sat-popover-above{transform-origin:left bottom}[dir=rtl] .sat-popover-container.sat-popover-after.sat-popover-above{transform-origin:right bottom}.sat-popover-container.sat-popover-after.sat-popover-center{transform-origin:left center}[dir=rtl] .sat-popover-container.sat-popover-after.sat-popover-center{transform-origin:right center}.sat-popover-container.sat-popover-after.sat-popover-below{transform-origin:left top}[dir=rtl] .sat-popover-container.sat-popover-after.sat-popover-below{transform-origin:right top}\n"], dependencies: [{ kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], animations: [transformPopover], encapsulation: i0.ViewEncapsulation.None }); } export { SatPopover }; i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: SatPopover, decorators: [{ type: Component, args: [{ selector: 'sat-popover', encapsulation: ViewEncapsulation.None, animations: [transformPopover], providers: [SatPopoverAnchoringService], template: "<ng-template>\n <div\n class=\"sat-popover-container\"\n #focusTrapElement\n [ngClass]=\"_classList\"\n [@transformPopover]=\"{ value: state, params: params }\"\n (@transformPopover.done)=\"_onAnimationDone($event)\"\n >\n <ng-content></ng-content>\n </div>\n</ng-template>\n", styles: [".cdk-overlay-container,.cdk-global-overlay-wrapper{pointer-events:none;top:0;left:0;height:100%;width:100%}.cdk-overlay-container{position:fixed;z-index:1000}.cdk-overlay-container:empty{display:none}.cdk-global-overlay-wrapper{display:flex;position:absolute;z-index:1000}.cdk-overlay-pane{position:absolute;pointer-events:auto;box-sizing:border-box;z-index:1000;display:flex;max-width:100%;max-height:100%}.cdk-overlay-backdrop{position:absolute;inset:0;z-index:1000;pointer-events:auto;-webkit-tap-highlight-color:transparent;transition:opacity .4s cubic-bezier(.25,.8,.25,1);opacity:0}.cdk-overlay-backdrop.cdk-overlay-backdrop-showing{opacity:1}.cdk-high-contrast-active .cdk-overlay-backdrop.cdk-overlay-backdrop-showing{opacity:.6}.cdk-overlay-dark-backdrop{background:rgba(0,0,0,.32)}.cdk-overlay-transparent-backdrop{transition:visibility 1ms linear,opacity 1ms linear;visibility:hidden;opacity:1}.cdk-overlay-transparent-backdrop.cdk-overlay-backdrop-showing{opacity:0;visibility:visible}.cdk-overlay-backdrop-noop-animation{transition:none}.cdk-overlay-connected-position-bounding-box{position:absolute;z-index:1000;display:flex;flex-direction:column;min-width:1px;min-height:1px}.cdk-global-scrollblock{position:fixed;width:100%;overflow-y:scroll}.sat-popover-container.sat-popover-before.sat-popover-above{transform-origin:right bottom}[dir=rtl] .sat-popover-container.sat-popover-before.sat-popover-above{transform-origin:left bottom}.sat-popover-container.sat-popover-before.sat-popover-center{transform-origin:right center}[dir=rtl] .sat-popover-container.sat-popover-before.sat-popover-center{transform-origin:left center}.sat-popover-container.sat-popover-before.sat-popover-below{transform-origin:right top}[dir=rtl] .sat-popover-container.sat-popover-before.sat-popover-below{transform-origin:left top}.sat-popover-container.sat-popover-center.sat-popover-above{transform-origin:center bottom}.sat-popover-container.sat-popover-center.sat-popover-below{transform-origin:center top}.sat-popover-container.sat-popover-after.sat-popover-above{transform-origin:left bottom}[dir=rtl] .sat-popover-container.sat-popover-after.sat-popover-above{transform-origin:right bottom}.sat-popover-container.sat-popover-after.sat-popover-center{transform-origin:left center}[dir=rtl] .sat-popover-container.sat-popover-after.sat-popover-center{transform-origin:right center}.sat-popover-container.sat-popover-after.sat-popover-below{transform-origin:left top}[dir=rtl] .sat-popover-container.sat-popover-after.sat-popover-below{transform-origin:right top}\n"] }] }], ctorParameters: function () { return [{ type: i1.ConfigurableFocusTrapFactory }, { type: i2.SatPopoverAnchoringService }, { type: i0.ViewContainerRef }, { type: undefined, decorators: [{ type: Inject, args: [DEFAULT_TRANSITION] }] }, { type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [DOCUMENT] }] }]; }, propDecorators: { anchor: [{ type: Input }], horizontalAlign: [{ type: Input }], xAlign: [{ type: Input }], verticalAlign: [{ type: Input }], yAlign: [{ type: Input }], forceAlignment: [{ type: Input }], lockAlignment: [{ type: Input }], autoFocus: [{ type: Input }], restoreFocus: [{ type: Input }], scrollStrategy: [{ type: Input }], hasBackdrop: [{ type: Input }], interactiveClose: [{ type: Input }], openTransition: [{ type: Input }], closeTransition: [{ type: Input }], openAnimationStartAtScale: [{ type: Input }], closeAnimationEndAtScale: [{ type: Input }], backdropClass: [{ type: Input }], panelClass: [{ type: Input }], opened: [{ type: Output }], closed: [{ type: Output }], afterOpen: [{ type: Output }], afterClose: [{ type: Output }], backdropClicked: [{ type: Output }], overlayKeydown: [{ type: Output }], _templateRef: [{ type: ViewChild, args: [TemplateRef, { static: true }] }], _focusTrapElement: [{ type: ViewChild, args: ['focusTrapElement'] }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicG9wb3Zlci5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvbGliL3BvcG92ZXIvcG9wb3Zlci5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi9zcmMvbGliL3BvcG92ZXIvcG9wb3Zlci5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQ0wsU0FBUyxFQUNULFVBQVUsRUFDVixZQUFZLEVBQ1osTUFBTSxFQUNOLEtBQUssRUFDTCxTQUFTLEVBQ1QsaUJBQWlCLEVBQ2pCLFdBQVcsRUFFWCxRQUFRLEVBQ1IsTUFBTSxFQUNOLFNBQVMsRUFHVixNQUFNLGVBQWUsQ0FBQztBQUV2QixPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFFM0MsT0FBTyxFQUFnQixxQkFBcUIsRUFBRSxvQkFBb0IsRUFBZSxNQUFNLHVCQUF1QixDQUFDO0FBRS9HLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQ3hELE9BQU8sRUFDTCx5QkFBeUIsRUFDekIsOEJBQThCLEVBQzlCLDRCQUE0QixFQUM1Qiw2QkFBNkIsRUFDN0IsNEJBQTRCLEVBQzVCLCtCQUErQixFQUMvQixzQkFBc0IsRUFDdkIsTUFBTSxrQkFBa0IsQ0FBQztBQUMxQixPQUFPLEVBSUwsWUFBWSxFQUNaLGlCQUFpQixFQUNqQixnQkFBZ0IsRUFFakIsTUFBTSxTQUFTLENBQUM7QUFDakIsT0FBTyxFQUFFLDBCQUEwQixFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFDekUsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sVUFBVSxDQUFDOzs7OztBQUU5QyxNQUFNLGtDQUFrQyxHQUFHLEdBQUcsQ0FBQztBQUMvQyxNQUFNLGlDQUFpQyxHQUFHLEdBQUcsQ0FBQztBQUU5QyxNQUlhLGdCQUFnQjtJQW9CUjtJQUErQjtJQW5CbEQsSUFDSSxPQUFPO1FBQ1QsT0FBTyxJQUFJLENB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RUFBRSxJQUFJLEVBQUU7Z0JBZWhDLGlCQUFpQjtzQkFEeEIsU0FBUzt1QkFBQyxrQkFBa0IiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBDb21wb25lbnQsXG4gIEVsZW1lbnRSZWYsXG4gIEV2ZW50RW1pdHRlcixcbiAgSW5qZWN0LFxuICBJbnB1dCxcbiAgVmlld0NoaWxkLFxuICBWaWV3RW5jYXBzdWxhdGlvbixcbiAgVGVtcGxhdGVSZWYsXG4gIE9uSW5pdCxcbiAgT3B0aW9uYWwsXG4gIE91dHB1dCxcbiAgRGlyZWN0aXZlLFxuICBWaWV3Q29udGFpbmVyUmVmLFxuICBBZnRlclZpZXdJbml0XG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgQW5pbWF0aW9uRXZlbnQgfSBmcm9tICdAYW5ndWxhci9hbmltYXRpb25zJztcbmltcG9ydCB7IERPQ1VNRU5UIH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uJztcbmltcG9ydCB7IENvbmZpZ3VyYWJsZUZvY3VzVHJhcCwgQ29uZmlndXJhYmxlRm9jdXNUcmFwRmFjdG9yeSwgRm9jdXNUcmFwLCBGb2N1c1RyYXBGYWN0b3J5IH0gZnJvbSAnQGFuZ3VsYXIvY2RrL2ExMXknO1xuaW1wb3J0IHsgQm9vbGVhbklucHV0LCBjb2VyY2VCb29sZWFuUHJvcGVydHksIGNvZXJjZU51bWJlclByb3BlcnR5LCBOdW1iZXJJbnB1dCB9IGZyb20gJ0Bhbmd1bGFyL2Nkay9jb2VyY2lvbic7XG5cbmltcG9ydCB7IHRyYW5zZm9ybVBvcG92ZXIgfSBmcm9tICcuL3BvcG92ZXIuYW5pbWF0aW9ucyc7XG5pbXBvcnQge1xuICBnZXRVbmFuY2hvcmVkUG9wb3ZlckVycm9yLFxuICBnZXRJbnZhbGlkSG9yaXpvbnRhbEFsaWduRXJyb3IsXG4gIGdldEludmFsaWRWZXJ0aWNhbEFsaWduRXJyb3IsXG4gIGdldEludmFsaWRTY3JvbGxTdHJhdGVneUVycm9yLFxuICBnZXRJbnZhbGlkUG9wb3ZlckFuY2hvckVycm9yLFxuICBnZXRJbnZhbGlkU2F0UG9wb3ZlckFuY2hvckVycm9yLFxuICBnZXRJbnZhbGlkUG9wb3ZlckVycm9yXG59IGZyb20gJy4vcG9wb3Zlci5lcnJvcnMnO1xuaW1wb3J0IHtcbiAgU2F0UG9wb3ZlclNjcm9sbFN0cmF0ZWd5LFxuICBTYXRQb3BvdmVySG9yaXpvbnRhbEFsaWduLFxuICBTYXRQb3BvdmVyVmVydGljYWxBbGlnbixcbiAgVkFMSURfU0NST0xMLFxuICBWQUxJRF9IT1JJWl9BTElHTixcbiAgVkFMSURfVkVSVF9BTElHTixcbiAgU2F0UG9wb3Zlck9wZW5PcHRpb25zXG59IGZyb20gJy4vdHlwZXMnO1xuaW1wb3J0IHsgU2F0UG9wb3ZlckFuY2hvcmluZ1NlcnZpY2UgfSBmcm9tICcuL3BvcG92ZXItYW5jaG9yaW5nLnNlcnZpY2UnO1xuaW1wb3J0IHsgREVGQVVMVF9UUkFOU0lUSU9OIH0gZnJvbSAnLi90b2tlbnMnO1xuXG5jb25zdCBERUZBVUxUX09QRU5fQU5JTUFUSU9OX1NUQVJUX1NDQUxFID0gMC4zO1xuY29uc3QgREVGQVVMVF9DTE9TRV9BTklNQVRJT05fRU5EX1NDQUxFID0gMC41O1xuXG5ARGlyZWN0aXZlKHtcbiAgc2VsZWN0b3I6ICdbc2F0UG9wb3ZlckFuY2hvcl0nLFxuICBleHBvcnRBczogJ3NhdFBvcG92ZXJBbmNob3InXG59KVxuZXhwb3J0IGNsYXNzIFNhdFBvcG92ZXJBbmNob3IgaW1wbGVtZW50cyBBZnRlclZpZXdJbml0IHtcbiAgQElucHV0KCdzYXRQb3BvdmVyQW5jaG9yJylcbiAgZ2V0IHBvcG92ZXIoKSB7XG4gICAgcmV0dXJuIHRoaXMuX3BvcG92ZXI7XG4gIH1cbiAgc2V0IHBvcG92ZXIodmFsOiBTYXRQb3BvdmVyKSB7XG4gICAgaWYgKHZhbCBpbnN0YW5jZW9mIFNhdFBvcG92ZXIpIHtcbiAgICAgIHZhbC5hbmNob3IgPSB0aGlzO1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyB3aGVuIGEgZGlyZWN0aXZlIGlzIGFkZGVkIHdpdGggbm8gYXJndW1lbnRzLFxuICAgICAgLy8gYW5ndWxhciBhc3NpZ25zIGAnJ2AgYXMgdGhlIGFyZ3VtZW50XG4gICAgICBpZiAodmFsICE9PSAnJykge1xuICAgICAgICB0aHJvdyBnZXRJbnZhbGlkUG9wb3ZlckVycm9yKCk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLyoqIEBpbnRlcm5hbCAqL1xuICBfcG9wb3ZlcjogU2F0UG9wb3ZlcjtcblxuICBjb25zdHJ1Y3RvcihwdWJsaWMgZWxlbWVudFJlZjogRWxlbWVudFJlZiwgcHVibGljIHZpZXdDb250YWluZXJSZWY6IFZpZXdDb250YWluZXJSZWYpIHt9XG5cbiAgbmdBZnRlclZpZXdJbml0KCkge1xuICAgIGlmICghdGhpcy5wb3BvdmVyKSB7XG4gICAgICB0aHJvdyBnZXRJbnZhbGlkU2F0UG9wb3ZlckFuY2hvckVycm9yKCk7XG4gICAgfVxuICB9XG59XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ3NhdC1wb3BvdmVyJyxcbiAgZW5jYXBzdWxhdGlvbjogVmlld0VuY2Fwc3VsYXRpb24uTm9uZSxcbiAgYW5pbWF0aW9uczogW3RyYW5zZm9ybVBvcG92ZXJdLFxuICBzdHlsZVVybHM6IFsnLi9wb3BvdmVyLmNvbXBvbmVudC5zY3NzJ10sXG4gIHRlbXBsYXRlVXJsOiAnLi9wb3BvdmVyLmNvbXBvbmVudC5odG1sJyxcbiAgcHJvdmlkZXJzOiBbU2F0UG9wb3ZlckFuY2hvcmluZ1NlcnZpY2VdXG59KVxuZXhwb3J0IGNsYXNzIFNhdFBvcG92ZXIgaW1wbGVtZW50cyBPbkluaXQge1xuICAvKiogQW5jaG9yIGVsZW1lbnQuICovXG4gIEBJbnB1dCgpXG4gIGdldCBhbmNob3IoKSB7XG4gICAgcmV0dXJuIHRoaXMuX2FuY2hvcjtcbiAgfVxuICBzZXQgYW5jaG9yKHZhbDogU2F0UG9wb3ZlckFuY2hvciB8IEVsZW1lbnRSZWY8SFRNTEVsZW1lbnQ+IHwgSFRNTEVsZW1lbnQpIHtcbiAgICBpZiAodmFsIGluc3RhbmNlb2YgU2F0UG9wb3ZlckFuY2hvcikge1xuICAgICAgdmFsLl9wb3BvdmVyID0gdGhpcztcbiAgICAgIHRoaXMuX2FuY2hvcmluZ1NlcnZpY2UuYW5jaG9yKHRoaXMsIHZhbC52aWV3Q29udGFpbmVyUmVmLCB2YWwuZWxlbWVudFJlZik7XG4gICAgICB0aGlzLl9hbmNob3IgPSB2YWw7XG4gICAgfSBlbHNlIGlmICh2YWwgaW5zdGFuY2VvZiBFbGVtZW50UmVmIHx8IHZhbCBpbnN0YW5jZW9mIEhUTUxFbGVtZW50KSB7XG4gICAgICB0aGlzLl9hbmNob3JpbmdTZXJ2aWNlLmFuY2hvcih0aGlzLCB0aGlzLl92aWV3Q29udGFpbmVyUmVmLCB2YWwpO1xuICAgICAgdGhpcy5fYW5jaG9yID0gdmFsO1xuICAgIH0gZWxzZSBpZiAodmFsKSB7XG4gICAgICB0aHJvdyBnZXRJbnZhbGlkUG9wb3ZlckFuY2hvckVycm9yKCk7XG4gICAgfVxuICB9XG4gIHByaXZhdGUgX2FuY2hvcjogU2F0UG9wb3ZlckFuY2hvciB8IEVsZW1lbnRSZWY8SFRNTEVsZW1lbnQ+IHwgSFRNTEVsZW1lbnQ7XG5cbiAgLyoqIEFsaWdubWVudCBvZiB0aGUgcG9wb3ZlciBvbiB0aGUgaG9yaXpvbnRhbCBheGlzLiAqL1xuICBASW5wdXQoKVxuICBnZXQgaG9yaXpvbnRhbEFsaWduKCkge1xuICAgIHJldHVybiB0aGlzLl9ob3Jpem9udGFsQWxpZ247XG4gIH1cbiAgc2V0IGhvcml6b250YWxBbGlnbih2YWw6IFNhdFBvcG92ZXJIb3Jpem9udGFsQWxpZ24pIHtcbiAgICB0aGlzLl92YWxpZGF0ZUhvcml6b250YWxBbGlnbih2YWwpO1xuICAgIGlmICh0aGlzLl9ob3Jpem9udGFsQWxpZ24gIT09IHZhbCkge1xuICAgICAgdGhpcy5faG9yaXpvbnRhbEFsaWduID0gdmFsO1xuICAgICAgdGhpcy5fYW5jaG9yaW5nU2VydmljZS5yZXBvc2l0aW9uUG9wb3ZlcigpO1xuICAgIH1cbiAgfVxuICBwcml2YXRlIF9ob3Jpem9udGFsQWxpZ246IFNhdFBvcG92ZXJIb3Jpem9udGFsQWxpZ24gPSAnY2VudGVyJztcblxuICAvKiogQWxpZ25tZW50IG9mIHRoZSBwb3BvdmVyIG9uIHRoZSB4IGF4aXMuIEFsaWFzIGZvciBgaG9yaXpvbnRhbEFsaWduYC4gKi9cbiAgQElucHV0KClcbiAgZ2V0IHhBbGlnbigpIHtcbiAgICByZXR1cm4gdGhpcy5ob3Jpem9udGFsQWxpZ247XG4gIH1cbiAgc2V0IHhBbGlnbih2YWw6IFNhdFBvcG92ZXJIb3Jpem9udGFsQWxpZ24pIHtcbiAgICB0aGlzLmhvcml6b250YWxBbGlnbiA9IHZhbDtcbiAgfVxuXG4gIC8qKiBBbGlnbm1lbnQgb2YgdGhlIHBvcG92ZXIgb24gdGhlIHZlcnRpY2FsIGF4aXMuICovXG4gIEBJbnB1dCgpXG4gIGdldCB2ZXJ0aWNhbEFsaWduKCkge1xuICAgIHJldHVybiB0aGlzLl92ZXJ0aWNhbEFsaWduO1xuICB9XG4gIHNldCB2ZXJ0aWNhbEFsaWduKHZhbDogU2F0UG9wb3ZlclZlcnRpY2FsQWxpZ24pIHtcbiAgICB0aGlzLl92YWxpZGF0ZVZlcnRpY2FsQWxpZ24odmFsKTtcbiAgICBpZiAodGhpcy5fdmVydGljYWxBbGlnbiAhPT0gdmFsKSB7XG4gICAgICB0aGlzLl92ZXJ0aWNhbEFsaWduID0gdmFsO1xuICAgICAgdGhpcy5fYW5jaG9yaW5nU2VydmljZS5yZXBvc2l0aW9uUG9wb3ZlcigpO1xuICAgIH1cbiAgfVxuICBwcml2YXRlIF92ZXJ0aWNhbEFsaWduOiBTYXRQb3BvdmVyVmVydGljYWxBbGlnbiA9ICdjZW50ZXInO1xuXG4gIC8qKiBBbGlnbm1lbnQgb2YgdGhlIHBvcG92ZXIgb24gdGhlIHkgYXhpcy4gQWxpYXMgZm9yIGB2ZXJ0aWNhbEFsaWduYC4gKi9cbiAgQElucHV0KClcbiAgZ2V0IHlBbGlnbigpIHtcbiAgICByZXR1cm4gdGhpcy52ZXJ0aWNhbEFsaWduO1xuICB9XG4gIHNldCB5QWxpZ24odmFsOiBTYXRQb3BvdmVyVmVydGljYWxBbGlnbikge1xuICAgIHRoaXMudmVydGljYWxBbGlnbiA9IHZhbDtcbiAgfVxuXG4gIC8qKiBXaGV0aGVyIHRoZSBwb3BvdmVyIGFsd2F5cyBvcGVucyB3aXRoIHRoZSBzcGVjaWZpZWQgYWxpZ25tZW50LiAqL1xuICBASW5wdXQoKVxuICBnZXQgZm9yY2VBbGlnbm1lbnQoKSB7XG4gICAgcmV0dXJuIHRoaXMuX2ZvcmNlQWxpZ25tZW50O1xuICB9XG4gIHNldCBmb3JjZUFsaWdubWVudCh2YWw6IEJvb2xlYW5JbnB1dCkge1xuICAgIGNvbnN0IGNvZXJjZWRWYWwgPSBjb2VyY2VCb29sZWFuUHJvcGVydHkodmFsKTtcbiAgICBpZiAodGhpcy5fZm9yY2VBbGlnbm1lbnQgIT09IGNvZXJjZWRWYWwpIHtcbiAgICAgIHRoaXMuX2ZvcmNlQWxpZ25tZW50ID0gY29lcmNlZFZhbDtcbiAgICAgIHRoaXMuX2FuY2hvcmluZ1NlcnZpY2UucmVwb3NpdGlvblBvcG92ZXIoKTtcbiAgICB9XG4gIH1cbiAgcHJpdmF0ZSBfZm9yY2VBbGlnbm1lbnQgPSBmYWxzZTtcblxuICAvKipcbiAgICogV2hldGhlciB0aGUgcG9wb3ZlcidzIGFsaWdubWVudCBpcyBsb2NrZWQgYWZ0ZXIgb3BlbmluZy4gVGhpcyBwcmV2ZW50cyB0aGUgcG9wb3ZlclxuICAgKiBmcm9tIGNoYW5naW5nIGl0cyBhbGlnbmVtZW50IHdoZW4gc2Nyb2xsaW5nIG9yIGNoYW5naW5nIHRoZSBzaXplIG9mIHRoZSB2aWV3cG9ydC5cbiAgICovXG4gIEBJbnB1dCgpXG4gIGdldCBsb2NrQWxpZ25tZW50KCkge1xuICAgIHJldHVybiB0aGlzLl9sb2NrQWxpZ25tZW50O1xuICB9XG4gIHNldCBsb2NrQWxpZ25tZW50KHZhbDogQm9vbGVhbklucHV0KSB7XG4gICAgY29uc3QgY29lcmNlZFZhbCA9IGNvZXJjZUJvb2xlYW5Qcm9wZXJ0eSh2YWwpO1xuICAgIGlmICh0aGlzLl9sb2NrQWxpZ25tZW50ICE9PSBjb2VyY2VkVmFsKSB7XG4gICAgICB0aGlzLl9sb2NrQWxpZ25tZW50ID0gY29lcmNlQm9vbGVhblByb3BlcnR5KHZhbCk7XG4gICAgICB0aGlzLl9hbmNob3JpbmdTZXJ2aWNlLnJlcG9zaXRpb25Qb3BvdmVyKCk7XG4gICAgfVxuICB9XG4gIHByaXZhdGUgX2xvY2tBbGlnbm1lbnQgPSBmYWxzZTtcblxuICAvKiogV2hldGhlciB0aGUgZmlyc3QgZm9jdXNhYmxlIGVsZW1lbnQgc2hvdWxkIGJlIGZvY3VzZWQgb24gb3Blbi4gKi9cbiAgQElucHV0KClcbiAgZ2V0IGF1dG9Gb2N1cygpIHtcbiAgICByZXR1cm4gdGhpcy5fYXV0b0ZvY3VzICYmIHRoaXMuX2F1dG9Gb2N1c092ZXJyaWRlO1xuICB9XG4gIHNldCBhdXRvRm9jdXModmFsOiBCb29sZWFuSW5wdXQpIHtcbiAgICB0aGlzLl9hdXRvRm9jdXMgPSBjb2VyY2VCb29sZWFuUHJvcGVydHkodmFsKTtcbiAgfVxuICBwcml2YXRlIF9hdXRvRm9jdXMgPSB0cnVlO1xuICBfYXV0b0ZvY3VzT3ZlcnJpZGUgPSB0cnVlO1xuXG4gIC8qKiBXaGV0aGVyIHRoZSBwb3BvdmVyIHNob3VsZCByZXR1cm4gZm9jdXMgdG8gdGhlIHByZXZpb3VzbHkgZm9jdXNlZCBlbGVtZW50IGFmdGVyIGNsb3NpbmcuICovXG4gIEBJbnB1dCgpXG4gIGdldCByZXN0b3JlRm9jdXMoKSB7XG4gICAgcmV0dXJuIHRoaXMuX3Jlc3RvcmVGb2N1cyAmJiB0aGlzLl9yZXN0b3JlRm9jdXNPdmVycmlkZTtcbiAgfVxuICBzZXQgcmVzdG9yZUZvY3VzKHZhbDogQm9vbGVhbklucHV0KSB7XG4gICAgdGhpcy5fcmVzdG9yZUZvY3VzID0gY29lcmNlQm9vbGVhblByb3BlcnR5KHZhbCk7XG4gIH1cbiAgcHJpdmF0ZSBfcmVzdG9yZUZvY3VzID0gdHJ1ZTtcbiAgX3Jlc3RvcmVGb2N1c092ZXJyaWRlID0gdHJ1ZTtcblxuICAvKiogSG93IHRoZSBwb3BvdmVyIHNob3VsZCBoYW5kbGUgc2Nyb2xsaW5nLiAqL1xuICBASW5wdXQoKVxuICBnZXQgc2Nyb2xsU3RyYXRlZ3koKSB7XG4gICAgcmV0dXJuIHRoaXMuX3Njcm9sbFN0cmF0ZWd5O1xuICB9XG4gIHNldCBzY3JvbGxTdHJhdGVneSh2YWw6IFNhdFBvcG92ZXJTY3JvbGxTdHJhdGVneSkge1xuICAgIHRoaXMuX3ZhbGlkYXRlU2Nyb2xsU3RyYXRlZ3kodmFsKTtcbiAgICBpZiAodGhpcy5fc2Nyb2xsU3RyYXRlZ3kgIT09IHZhbCkge1xuICAgICAgdGhpcy5fc2Nyb2xsU3RyYXRlZ3kgPSB2YWw7XG4gICAgICB0aGlzLl9hbmNob3JpbmdTZXJ2aWNlLnVwZGF0ZVBvcG92ZXJDb25maWcoKTtcbiAgICB9XG4gIH1cbiAgcHJpdmF0ZSBfc2Nyb2xsU3RyYXRlZ3k6IFNhdFBvcG92ZXJTY3JvbGxTdHJhdGVneSA9ICdyZXBvc2l0aW9uJztcblxuICAvKiogV2hldGhlciB0aGUgcG9wb3ZlciBzaG91bGQgaGF2ZSBhIGJhY2tkcm9wIChpbmNsdWRlcyBjbG9zaW5nIG9uIGNsaWNrKS4gKi9cbiAgQElucHV0KClcbiAgZ2V0IGhhc0JhY2tkcm9wKCkge1xuICAgIHJldHVybiB0aGlzLl9oYXNCYWNrZHJvcDtcbiAgfVxuICBzZXQgaGFzQmFja2Ryb3AodmFsOiBCb29sZWFuSW5wdXQpIHtcbiAgICB0aGlzLl9oYXNCYWNrZHJvcCA9IGNvZXJjZUJvb2xlYW5Qcm9wZXJ0eSh2YWwpO1xuICB9XG4gIHByaXZhdGUgX2hhc0JhY2tkcm9wID0gZmFsc2U7XG5cbiAgLyoqIFdoZXRoZXIgdGhlIHBvcG92ZXIgc2hvdWxkIGNsb3NlIHdoZW4gdGhlIHVzZXIgY2xpY2tzIHRoZSBiYWNrZHJvcCBvciBwcmVzc2VzIEVTQy4gKi9cbiAgQElucHV0KClcbiAgZ2V0IGludGVyYWN0aXZlQ2xvc2UoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuX2ludGVyYWN0aXZlQ2xvc2U7XG4gIH1cbiAgc2V0IGludGVyYWN0aXZlQ2xvc2UodmFsOiBCb29sZWFuSW5wdXQpIHtcbiAgICB0aGlzLl9pbnRlcmFjdGl2ZUNsb3NlID0gY29lcmNlQm9vbGVhblByb3BlcnR5KHZhbCk7XG4gIH1cbiAgcHJpdmF0ZSBfaW50ZXJhY3RpdmVDbG9zZSA9IHRydWU7XG5cbiAgLyoqIEN1c3RvbSB0cmFuc2l0aW9uIHRvIHVzZSB3aGlsZSBvcGVuaW5nLiAqL1xuICBASW5wdXQoKVxuICBnZXQgb3BlblRyYW5zaXRpb24oKSB7XG4gICAgcmV0dXJuIHRoaXMuX29wZW5UcmFuc2l0aW9uO1xuICB9XG4gIHNldCBvcGVuVHJhbnNpdGlvbih2YWw6IHN0cmluZykge1xuICAgIGlmICh2YWwpIHtcbiAgICAgIHRoaXMuX29wZW5UcmFuc2l0aW9uID0gdmFsO1xuICAgIH1cbiAgfVxuICBwcml2YXRlIF9vcGVuVHJhbnNpdGlvbiA9IHRoaXMuX2RlZmF1bHRUcmFuc2l0aW9uO1xuXG4gIC8qKiBDdXN0b20gdHJhbnNpdGlvbiB0byB1c2Ugd2hpbGUgY2xvc2luZy4gKi9cbiAgQElucHV0KClcbiAgZ2V0IGNsb3NlVHJhbnNpdGlvbigpIHtcbiAgICByZXR1cm4gdGhpcy5fY2xvc2VUcmFuc2l0aW9uO1xuICB9XG4gIHNldCBjbG9zZVRyYW5zaXRpb24odmFsOiBzdHJpbmcpIHtcbiAgICBpZiAodmFsKSB7XG4gICAgICB0aGlzLl9jbG9zZVRyYW5zaXRpb24gPSB2YWw7XG4gICAgfVxuICB9XG4gIHByaXZhdGUgX2Nsb3NlVHJhbnNpdGlvbiA9IHRoaXMuX2RlZmF1b