@igor2017/sat-popover
Version:
Popover component for Angular
465 lines • 60.8 kB
JavaScript
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