UNPKG

ngx-material-drawer

Version:

A dynamic, configurable Angular Material drawer with dashboard capabilities

112 lines 42.9 kB
import { Component, Input, ViewChild, ElementRef } from "@angular/core"; import { NgxNavService } from "../utils/nav.service"; import { NgxMaterialDrawerEventEmitter } from "../utils/mat-event-emitter.service"; import { trigger, style, animate, transition } from "@angular/animations"; import { NgxUtilsService } from "../utils/utils.service"; import * as i0 from "@angular/core"; import * as i1 from "../utils/mat-event-emitter.service"; import * as i2 from "../utils/nav.service"; import * as i3 from "../utils/utils.service"; import * as i4 from "@angular/common"; import * as i5 from "@angular/material/button"; import * as i6 from "@angular/material/icon"; import * as i7 from "@angular/material/menu"; import * as i8 from "@angular/material/toolbar"; import * as i9 from "@angular/flex-layout/extended"; import * as i10 from "@angular/forms"; import * as i11 from "../menu-list-item/menu-list-item.component"; import * as i12 from "../card-holder/card-holder.component"; export class NgxTopNavComponent { constructor(matEventEmitterService, navService, ngxUtilsService) { this.matEventEmitterService = matEventEmitterService; this.navService = navService; this.ngxUtilsService = ngxUtilsService; this.isSearchActive = false; this.searchValue = ""; } ngOnInit() { } ngAfterViewInit() { this.matEventEmitterService.onNavStateChange.subscribe((flag) => { this.isDrawerOpened = flag.isOpened; }); this.matEventEmitterService.onSideNavClosed.subscribe((flag) => { this.isDrawerOpened = flag.isOpened; }); this.matEventEmitterService.onSideNavClosed.subscribe((flag) => { this.isDrawerOpened = flag.isOpened; }); } onItemSelected(item) { if (!item.children || !item.children.length) { this.matEventEmitterService.menuItemClick(item); } } toggleSearchBar() { this.isSearchActive = !this.isSearchActive; let searchObject = { value: this.searchValue, inputRef: this.ngxSearchBox, }; if (this.isSearchActive) { this.matEventEmitterService.serachInputOpen(searchObject); } else { this.matEventEmitterService.serachInputClosed(searchObject); } } onSearchValueChange(event) { let searchObject = { value: this.searchValue, inputRef: this.ngxSearchBox, }; this.matEventEmitterService.searchValueChange(searchObject); } onSerachFocusIn(event) { let searchObject = { value: this.searchValue, inputRef: this.ngxSearchBox, }; this.matEventEmitterService.serachFocusIn(searchObject); } onSerachFocusOut(event) { let searchObject = { value: this.searchValue, inputRef: this.ngxSearchBox, }; this.matEventEmitterService.serachFocusOut(searchObject); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: NgxTopNavComponent, deps: [{ token: i1.NgxMaterialDrawerEventEmitter }, { token: i2.NgxNavService }, { token: i3.NgxUtilsService }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: NgxTopNavComponent, selector: "lib-top-nav", inputs: { config: "config" }, viewQueries: [{ propertyName: "ngxSearchBox", first: true, predicate: ["ngxSearchBox"], descendants: true }], ngImport: i0, template: "<mat-toolbar\n color=\"primary\"\n class=\"mat-elevation-z1 ngx-material-toolbar\"\n>\n <ng-container *ngIf=\"!isSearchActive\">\n <!-- DrawerToggle menu -->\n <button\n class=\"btn-toggle\"\n mat-icon-button\n id=\"menu\"\n (click)=\"navService.toggleNav()\"\n >\n <!-- <mat-icon>{{config?.toggleIcon ? config.toggleIcon : 'menu'}}</mat-icon> -->\n <div\n class=\"wrapper-menu\"\n *ngIf=\"!config?.toggleIcon\"\n [ngClass]=\"isDrawerOpened ? 'open' : 'close'\"\n >\n <div class=\"line-menu half start\"></div>\n <div class=\"line-menu\"></div>\n <div class=\"line-menu half end\"></div>\n </div>\n <ng-container *ngIf=\"config?.toggleIcon\">\n <mat-icon>\n {{!isDrawerOpened ? config.toggleIcon : config?.closedToggleIcon ? config?.closedToggleIcon : 'close'}}\n </mat-icon>\n </ng-container>\n </button>\n <span>\n {{config?.appName ? config.appName : 'Default name'}}\n </span>\n <!-- Right Menu -->\n <span class=\"toolbar-spacer\"></span>\n <div\n class=\"right-nav\"\n [ngStyle]=\"config?.rightMenus?.style? config?.rightMenus.style : ''\"\n >\n <button\n *ngIf=\"config?.search?.isEnable\"\n mat-button\n mat-icon-button\n (click)=\"toggleSearchBar()\"\n >\n <mat-icon>search</mat-icon>\n </button>\n <ng-container *ngIf=\"config?.rightMenus?.data\">\n <span *ngFor=\"let item of config?.rightMenus?.data\">\n <!-- Handle branch node buttons here -->\n <span *ngIf=\"item.children && item.children.length > 0\">\n <ng-container *ngIf=\"item.component; else elseBlock\">\n <lib-card-holder\n [matMenuTriggerFor]=\"menu.childMenu\"\n [cardData]=\"ngxUtilsService.getExtendedData(item.component)\"\n ></lib-card-holder>\n </ng-container>\n <ng-template #elseBlock>\n <button\n *ngIf=\"item.displayName?.trim()\"\n [ngStyle]=\"item?.style? item.style : ''\"\n mat-button\n [matMenuTriggerFor]=\"menu.childMenu\"\n [disabled]=\"item.disabled\"\n >\n <mat-icon>{{item.iconName}}</mat-icon>\n <span>{{item.displayName}}</span>\n </button>\n <button\n *ngIf=\"!item?.displayName?.trim()\"\n [ngStyle]=\"item?.style? item.style : ''\"\n mat-icon-button\n [matMenuTriggerFor]=\"menu.childMenu\"\n [disabled]=\"item.disabled\"\n >\n <mat-icon>{{item.iconName}}</mat-icon>\n </button>\n </ng-template>\n <lib-menu-list-item\n #menu\n [menus]=\"item.children\"\n ></lib-menu-list-item>\n </span>\n <!-- Leaf node buttons here -->\n <span *ngIf=\"!item.children || item.children.length === 0\">\n <ng-container *ngIf=\"item.component; else elseBlock\">\n <lib-card-holder [cardData]=\"ngxUtilsService.getExtendedData(item.component)\"></lib-card-holder>\n </ng-container>\n <ng-template #elseBlock>\n <button\n *ngIf=\"item.displayName?.trim()\"\n [ngStyle]=\"item?.style? item.style : ''\"\n mat-button\n (click)=\"onItemSelected(item)\"\n [disabled]=\"item.disabled\"\n >\n <mat-icon>{{item.iconName}}</mat-icon>\n <span>{{item.displayName}}</span>\n </button>\n <button\n *ngIf=\"!item?.displayName?.trim()\"\n [ngStyle]=\"item?.style? item.style : ''\"\n mat-icon-button\n (click)=\"onItemSelected(item)\"\n [disabled]=\"item.disabled\"\n >\n <mat-icon>{{item.iconName}}</mat-icon>\n </button>\n </ng-template>\n </span>\n </span>\n </ng-container>\n </div>\n </ng-container>\n <ng-container *ngIf=\"isSearchActive\">\n <div\n class=\"searchBarMain\"\n [ngStyle]=\"config?.search?.style ? config?.search?.style : ''\"\n [@enterAnimation]\n >\n <i\n (click)=\"toggleSearchBar()\"\n class=\"material-icons searchBarSearchIcon\"\n >\n {{config?.search?.backIcon ? config?.search?.backIcon : 'arrow_back'}}\n </i>\n <input\n type=\"text\"\n #ngxSearchBox\n name=\"header-search\"\n [(ngModel)]=\"searchValue\"\n class=\"searchBarInput\"\n (input)=\"onSearchValueChange($event)\"\n (focus)=\"onSerachFocusIn($event)\"\n (focusout)=\"onSerachFocusOut($event)\"\n [placeholder]=\"config?.search?.placeHolder ? config?.search?.placeHolder : 'Search, discover, explore...'\"\n >\n <i\n *ngIf=\"searchValue.length\"\n (click)=\"searchValue = ''\"\n class=\"material-icons clearSearchBarField\"\n >\n {{config?.search?.clearIcon ? config?.search?.clearIcon : 'clear'}}\n </i>\n </div>\n </ng-container>\n</mat-toolbar>\n", styles: [".ngx-material-toolbar .wrapper-menu{width:40px;height:25px;display:flex;flex-direction:column;justify-content:space-between;cursor:pointer;transition:transform .33s ease-out}.ngx-material-toolbar .wrapper-menu.open{transform:rotate(-45deg)}.ngx-material-toolbar .line-menu{background-color:#fff;border-radius:5px;width:100%;height:4px}.ngx-material-toolbar .line-menu.half{width:50%}.ngx-material-toolbar .line-menu.start{transition:transform .33s cubic-bezier(.54,-.81,.57,.57);transform-origin:right}.ngx-material-toolbar .open .line-menu.start{transform:rotate(-90deg) translate(3px)}.ngx-material-toolbar .line-menu.end{align-self:flex-end;transition:transform .33s cubic-bezier(.54,-.81,.57,.57);transform-origin:left}.ngx-material-toolbar .open .line-menu.end{transform:rotate(-90deg) translate(-3px)}.ngx-material-toolbar .btn-toggle{margin-right:5px}.ngx-material-toolbar .toolbar-spacer{flex:1 1 auto}.ngx-material-toolbar .right-nav{display:flex}.ngx-material-toolbar .searchBarMain{background:#fff;width:90%;margin:11px auto 0;height:42px;border-radius:2px;box-shadow:0 1px 8px #00000024;position:fixed;left:0;right:0;top:0}.ngx-material-toolbar .searchBarMain i.searchBarSearchIcon{height:100%;line-height:42px;float:left;width:52px;cursor:pointer;text-align:center;color:#44444480}.ngx-material-toolbar .searchBarMain input.searchBarInput{height:42px;padding:0 32px 0 0;margin:0;border:0;box-sizing:border-box;background:transparent;width:calc(100% - 52px);outline:none;font-size:16px;color:#000000c2;font-weight:400;font-family:Roboto,sans-serif}.ngx-material-toolbar .searchBarMain i.clearSearchBarField{position:absolute;right:12px;top:11px;color:#000000d6;font-size:20px;cursor:pointer}\n"], dependencies: [{ kind: "directive", type: i4.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i4.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i4.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: i5.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "component", type: i5.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "component", type: i6.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: i7.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "component", type: i8.MatToolbar, selector: "mat-toolbar", inputs: ["color"], exportAs: ["matToolbar"] }, { kind: "directive", type: i9.DefaultClassDirective, selector: " [ngClass], [ngClass.xs], [ngClass.sm], [ngClass.md], [ngClass.lg], [ngClass.xl], [ngClass.lt-sm], [ngClass.lt-md], [ngClass.lt-lg], [ngClass.lt-xl], [ngClass.gt-xs], [ngClass.gt-sm], [ngClass.gt-md], [ngClass.gt-lg]", inputs: ["ngClass", "ngClass.xs", "ngClass.sm", "ngClass.md", "ngClass.lg", "ngClass.xl", "ngClass.lt-sm", "ngClass.lt-md", "ngClass.lt-lg", "ngClass.lt-xl", "ngClass.gt-xs", "ngClass.gt-sm", "ngClass.gt-md", "ngClass.gt-lg"] }, { kind: "directive", type: i9.DefaultStyleDirective, selector: " [ngStyle], [ngStyle.xs], [ngStyle.sm], [ngStyle.md], [ngStyle.lg], [ngStyle.xl], [ngStyle.lt-sm], [ngStyle.lt-md], [ngStyle.lt-lg], [ngStyle.lt-xl], [ngStyle.gt-xs], [ngStyle.gt-sm], [ngStyle.gt-md], [ngStyle.gt-lg]", inputs: ["ngStyle", "ngStyle.xs", "ngStyle.sm", "ngStyle.md", "ngStyle.lg", "ngStyle.xl", "ngStyle.lt-sm", "ngStyle.lt-md", "ngStyle.lt-lg", "ngStyle.lt-xl", "ngStyle.gt-xs", "ngStyle.gt-sm", "ngStyle.gt-md", "ngStyle.gt-lg"] }, { kind: "directive", type: i10.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i10.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i10.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i11.NgxMenuListItemComponent, selector: "lib-menu-list-item", inputs: ["menus", "depth", "matMenu"], exportAs: ["menuInMenuListItemComponent"] }, { kind: "component", type: i12.CardHolderComponent, selector: "lib-card-holder", inputs: ["cardData"] }], animations: [ trigger("enterAnimation", [ transition(":enter", [ style({ transform: "translateX(100%)", opacity: 0 }), animate("500ms", style({ transform: "translateX(0)", opacity: 1 })), ]), transition(":leave", [ style({ transform: "translateX(0)", opacity: 1 }), animate("500ms", style({ transform: "translateX(100%)", opacity: 0 })), ]), ]), ] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: NgxTopNavComponent, decorators: [{ type: Component, args: [{ selector: "lib-top-nav", animations: [ trigger("enterAnimation", [ transition(":enter", [ style({ transform: "translateX(100%)", opacity: 0 }), animate("500ms", style({ transform: "translateX(0)", opacity: 1 })), ]), transition(":leave", [ style({ transform: "translateX(0)", opacity: 1 }), animate("500ms", style({ transform: "translateX(100%)", opacity: 0 })), ]), ]), ], template: "<mat-toolbar\n color=\"primary\"\n class=\"mat-elevation-z1 ngx-material-toolbar\"\n>\n <ng-container *ngIf=\"!isSearchActive\">\n <!-- DrawerToggle menu -->\n <button\n class=\"btn-toggle\"\n mat-icon-button\n id=\"menu\"\n (click)=\"navService.toggleNav()\"\n >\n <!-- <mat-icon>{{config?.toggleIcon ? config.toggleIcon : 'menu'}}</mat-icon> -->\n <div\n class=\"wrapper-menu\"\n *ngIf=\"!config?.toggleIcon\"\n [ngClass]=\"isDrawerOpened ? 'open' : 'close'\"\n >\n <div class=\"line-menu half start\"></div>\n <div class=\"line-menu\"></div>\n <div class=\"line-menu half end\"></div>\n </div>\n <ng-container *ngIf=\"config?.toggleIcon\">\n <mat-icon>\n {{!isDrawerOpened ? config.toggleIcon : config?.closedToggleIcon ? config?.closedToggleIcon : 'close'}}\n </mat-icon>\n </ng-container>\n </button>\n <span>\n {{config?.appName ? config.appName : 'Default name'}}\n </span>\n <!-- Right Menu -->\n <span class=\"toolbar-spacer\"></span>\n <div\n class=\"right-nav\"\n [ngStyle]=\"config?.rightMenus?.style? config?.rightMenus.style : ''\"\n >\n <button\n *ngIf=\"config?.search?.isEnable\"\n mat-button\n mat-icon-button\n (click)=\"toggleSearchBar()\"\n >\n <mat-icon>search</mat-icon>\n </button>\n <ng-container *ngIf=\"config?.rightMenus?.data\">\n <span *ngFor=\"let item of config?.rightMenus?.data\">\n <!-- Handle branch node buttons here -->\n <span *ngIf=\"item.children && item.children.length > 0\">\n <ng-container *ngIf=\"item.component; else elseBlock\">\n <lib-card-holder\n [matMenuTriggerFor]=\"menu.childMenu\"\n [cardData]=\"ngxUtilsService.getExtendedData(item.component)\"\n ></lib-card-holder>\n </ng-container>\n <ng-template #elseBlock>\n <button\n *ngIf=\"item.displayName?.trim()\"\n [ngStyle]=\"item?.style? item.style : ''\"\n mat-button\n [matMenuTriggerFor]=\"menu.childMenu\"\n [disabled]=\"item.disabled\"\n >\n <mat-icon>{{item.iconName}}</mat-icon>\n <span>{{item.displayName}}</span>\n </button>\n <button\n *ngIf=\"!item?.displayName?.trim()\"\n [ngStyle]=\"item?.style? item.style : ''\"\n mat-icon-button\n [matMenuTriggerFor]=\"menu.childMenu\"\n [disabled]=\"item.disabled\"\n >\n <mat-icon>{{item.iconName}}</mat-icon>\n </button>\n </ng-template>\n <lib-menu-list-item\n #menu\n [menus]=\"item.children\"\n ></lib-menu-list-item>\n </span>\n <!-- Leaf node buttons here -->\n <span *ngIf=\"!item.children || item.children.length === 0\">\n <ng-container *ngIf=\"item.component; else elseBlock\">\n <lib-card-holder [cardData]=\"ngxUtilsService.getExtendedData(item.component)\"></lib-card-holder>\n </ng-container>\n <ng-template #elseBlock>\n <button\n *ngIf=\"item.displayName?.trim()\"\n [ngStyle]=\"item?.style? item.style : ''\"\n mat-button\n (click)=\"onItemSelected(item)\"\n [disabled]=\"item.disabled\"\n >\n <mat-icon>{{item.iconName}}</mat-icon>\n <span>{{item.displayName}}</span>\n </button>\n <button\n *ngIf=\"!item?.displayName?.trim()\"\n [ngStyle]=\"item?.style? item.style : ''\"\n mat-icon-button\n (click)=\"onItemSelected(item)\"\n [disabled]=\"item.disabled\"\n >\n <mat-icon>{{item.iconName}}</mat-icon>\n </button>\n </ng-template>\n </span>\n </span>\n </ng-container>\n </div>\n </ng-container>\n <ng-container *ngIf=\"isSearchActive\">\n <div\n class=\"searchBarMain\"\n [ngStyle]=\"config?.search?.style ? config?.search?.style : ''\"\n [@enterAnimation]\n >\n <i\n (click)=\"toggleSearchBar()\"\n class=\"material-icons searchBarSearchIcon\"\n >\n {{config?.search?.backIcon ? config?.search?.backIcon : 'arrow_back'}}\n </i>\n <input\n type=\"text\"\n #ngxSearchBox\n name=\"header-search\"\n [(ngModel)]=\"searchValue\"\n class=\"searchBarInput\"\n (input)=\"onSearchValueChange($event)\"\n (focus)=\"onSerachFocusIn($event)\"\n (focusout)=\"onSerachFocusOut($event)\"\n [placeholder]=\"config?.search?.placeHolder ? config?.search?.placeHolder : 'Search, discover, explore...'\"\n >\n <i\n *ngIf=\"searchValue.length\"\n (click)=\"searchValue = ''\"\n class=\"material-icons clearSearchBarField\"\n >\n {{config?.search?.clearIcon ? config?.search?.clearIcon : 'clear'}}\n </i>\n </div>\n </ng-container>\n</mat-toolbar>\n", styles: [".ngx-material-toolbar .wrapper-menu{width:40px;height:25px;display:flex;flex-direction:column;justify-content:space-between;cursor:pointer;transition:transform .33s ease-out}.ngx-material-toolbar .wrapper-menu.open{transform:rotate(-45deg)}.ngx-material-toolbar .line-menu{background-color:#fff;border-radius:5px;width:100%;height:4px}.ngx-material-toolbar .line-menu.half{width:50%}.ngx-material-toolbar .line-menu.start{transition:transform .33s cubic-bezier(.54,-.81,.57,.57);transform-origin:right}.ngx-material-toolbar .open .line-menu.start{transform:rotate(-90deg) translate(3px)}.ngx-material-toolbar .line-menu.end{align-self:flex-end;transition:transform .33s cubic-bezier(.54,-.81,.57,.57);transform-origin:left}.ngx-material-toolbar .open .line-menu.end{transform:rotate(-90deg) translate(-3px)}.ngx-material-toolbar .btn-toggle{margin-right:5px}.ngx-material-toolbar .toolbar-spacer{flex:1 1 auto}.ngx-material-toolbar .right-nav{display:flex}.ngx-material-toolbar .searchBarMain{background:#fff;width:90%;margin:11px auto 0;height:42px;border-radius:2px;box-shadow:0 1px 8px #00000024;position:fixed;left:0;right:0;top:0}.ngx-material-toolbar .searchBarMain i.searchBarSearchIcon{height:100%;line-height:42px;float:left;width:52px;cursor:pointer;text-align:center;color:#44444480}.ngx-material-toolbar .searchBarMain input.searchBarInput{height:42px;padding:0 32px 0 0;margin:0;border:0;box-sizing:border-box;background:transparent;width:calc(100% - 52px);outline:none;font-size:16px;color:#000000c2;font-weight:400;font-family:Roboto,sans-serif}.ngx-material-toolbar .searchBarMain i.clearSearchBarField{position:absolute;right:12px;top:11px;color:#000000d6;font-size:20px;cursor:pointer}\n"] }] }], ctorParameters: () => [{ type: i1.NgxMaterialDrawerEventEmitter }, { type: i2.NgxNavService }, { type: i3.NgxUtilsService }], propDecorators: { ngxSearchBox: [{ type: ViewChild, args: ["ngxSearchBox", { static: false }] }], config: [{ type: Input }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidG9wLW5hdi5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9uZ3gtbWF0ZXJpYWwtZHJhd2VyL3NyYy9saWIvYXBwL3RvcC1uYXYvdG9wLW5hdi5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9uZ3gtbWF0ZXJpYWwtZHJhd2VyL3NyYy9saWIvYXBwL3RvcC1uYXYvdG9wLW5hdi5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFVLEtBQUssRUFBRSxTQUFTLEVBQUUsVUFBVSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ2hGLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUNyRCxPQUFPLEVBQUUsNkJBQTZCLEVBQUUsTUFBTSxvQ0FBb0MsQ0FBQztBQUNuRixPQUFPLEVBQUUsT0FBTyxFQUFFLEtBQUssRUFBRSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDMUUsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLHdCQUF3QixDQUFDOzs7Ozs7Ozs7Ozs7OztBQW1CekQsTUFBTSxPQUFPLGtCQUFrQjtJQU83QixZQUNTLHNCQUFxRCxFQUNyRCxVQUF5QixFQUN6QixlQUFnQztRQUZoQywyQkFBc0IsR0FBdEIsc0JBQXNCLENBQStCO1FBQ3JELGVBQVUsR0FBVixVQUFVLENBQWU7UUFDekIsb0JBQWUsR0FBZixlQUFlLENBQWlCO1FBTmxDLG1CQUFjLEdBQVksS0FBSyxDQUFDO1FBQ2hDLGdCQUFXLEdBQVcsRUFBRSxDQUFDO0lBTTdCLENBQUM7SUFFSixRQUFRLEtBQUksQ0FBQztJQUViLGVBQWU7UUFDYixJQUFJLENBQUMsc0JBQXNCLENBQUMsZ0JBQWdCLENBQUMsU0FBUyxDQUFDLENBQUMsSUFBUyxFQUFFLEVBQUU7WUFDbkUsSUFBSSxDQUFDLGNBQWMs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LEVBQUUsT0FBTyxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUM7aUJBQ3ZFLENBQUM7YUFDSCxDQUFDO1NBQ0g7OzRGQUVVLGtCQUFrQjtrQkFqQjlCLFNBQVM7K0JBQ0UsYUFBYSxjQUdYO3dCQUNWLE9BQU8sQ0FBQyxnQkFBZ0IsRUFBRTs0QkFDeEIsVUFBVSxDQUFDLFFBQVEsRUFBRTtnQ0FDbkIsS0FBSyxDQUFDLEVBQUUsU0FBUyxFQUFFLGtCQUFrQixFQUFFLE9BQU8sRUFBRSxDQUFDLEVBQUUsQ0FBQztnQ0FDcEQsT0FBTyxDQUFDLE9BQU8sRUFBRSxLQUFLLENBQUMsRUFBRSxTQUFTLEVBQUUsZUFBZSxFQUFFLE9BQU8sRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDOzZCQUNwRSxDQUFDOzRCQUNGLFVBQVUsQ0FBQyxRQUFRLEVBQUU7Z0NBQ25CLEtBQUssQ0FBQyxFQUFFLFNBQVMsRUFBRSxlQUFlLEVBQUUsT0FBTyxFQUFFLENBQUMsRUFBRSxDQUFDO2dDQUNqRCxPQUFPLENBQUMsT0FBTyxFQUFFLEtBQUssQ0FBQyxFQUFFLFNBQVMsRUFBRSxrQkFBa0IsRUFBRSxPQUFPLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQzs2QkFDdkUsQ0FBQzt5QkFDSCxDQUFDO3FCQUNIOzRKQUc2QyxZQUFZO3NCQUF6RCxTQUFTO3VCQUFDLGNBQWMsRUFBRSxFQUFFLE1BQU0sRUFBRSxLQUFLLEVBQUU7Z0JBQ25DLE1BQU07c0JBQWQsS0FBSyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBvbmVudCwgT25Jbml0LCBJbnB1dCwgVmlld0NoaWxkLCBFbGVtZW50UmVmIH0gZnJvbSBcIkBhbmd1bGFyL2NvcmVcIjtcbmltcG9ydCB7IE5neE5hdlNlcnZpY2UgfSBmcm9tIFwiLi4vdXRpbHMvbmF2LnNlcnZpY2VcIjtcbmltcG9ydCB7IE5neE1hdGVyaWFsRHJhd2VyRXZlbnRFbWl0dGVyIH0gZnJvbSBcIi4uL3V0aWxzL21hdC1ldmVudC1lbWl0dGVyLnNlcnZpY2VcIjtcbmltcG9ydCB7IHRyaWdnZXIsIHN0eWxlLCBhbmltYXRlLCB0cmFuc2l0aW9uIH0gZnJvbSBcIkBhbmd1bGFyL2FuaW1hdGlvbnNcIjtcbmltcG9ydCB7IE5neFV0aWxzU2VydmljZSB9IGZyb20gXCIuLi91dGlscy91dGlscy5zZXJ2aWNlXCI7XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogXCJsaWItdG9wLW5hdlwiLFxuICB0ZW1wbGF0ZVVybDogXCIuL3RvcC1uYXYuY29tcG9uZW50Lmh0bWxcIixcbiAgc3R5bGVVcmxzOiBbXCIuL3RvcC1uYXYuY29tcG9uZW50LnNjc3NcIl0sXG4gIGFuaW1hdGlvbnM6IFtcbiAgICB0cmlnZ2VyKFwiZW50ZXJBbmltYXRpb25cIiwgW1xuICAgICAgdHJhbnNpdGlvbihcIjplbnRlclwiLCBbXG4gICAgICAgIHN0eWxlKHsgdHJhbnNmb3JtOiBcInRyYW5zbGF0ZVgoMTAwJSlcIiwgb3BhY2l0eTogMCB9KSxcbiAgICAgICAgYW5pbWF0ZShcIjUwMG1zXCIsIHN0eWxlKHsgdHJhbnNmb3JtOiBcInRyYW5zbGF0ZVgoMClcIiwgb3BhY2l0eTogMSB9KSksXG4gICAgICBdKSxcbiAgICAgIHRyYW5zaXRpb24oXCI6bGVhdmVcIiwgW1xuICAgICAgICBzdHlsZSh7IHRyYW5zZm9ybTogXCJ0cmFuc2xhdGVYKDApXCIsIG9wYWNpdHk6IDEgfSksXG4gICAgICAgIGFuaW1hdGUoXCI1MDBtc1wiLCBzdHlsZSh7IHRyYW5zZm9ybTogXCJ0cmFuc2xhdGVYKDEwMCUpXCIsIG9wYWNpdHk6IDAgfSkpLFxuICAgICAgXSksXG4gICAgXSksXG4gIF0sXG59KVxuZXhwb3J0IGNsYXNzIE5neFRvcE5hdkNvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCB7XG4gIEBWaWV3Q2hpbGQoXCJuZ3hTZWFyY2hCb3hcIiwgeyBzdGF0aWM6IGZhbHNlIH0pIG5neFNlYXJjaEJveCE6IEVsZW1lbnRSZWY7XG4gIEBJbnB1dCgpIGNvbmZpZzogYW55O1xuICBwdWJsaWMgaXNEcmF3ZXJPcGVuZWQ6IGFueTtcbiAgcHVibGljIGlzU2VhcmNoQWN0aXZlOiBib29sZWFuID0gZmFsc2U7XG4gIHB1YmxpYyBzZWFyY2hWYWx1ZTogc3RyaW5nID0gXCJcIjtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBwdWJsaWMgbWF0RXZlbnRFbWl0dGVyU2VydmljZTogTmd4TWF0ZXJpYWxEcmF3ZXJFdmVudEVtaXR0ZXIsXG4gICAgcHVibGljIG5hdlNlcnZpY2U6IE5neE5hdlNlcnZpY2UsXG4gICAgcHVibGljIG5neFV0aWxzU2VydmljZTogTmd4VXRpbHNTZXJ2aWNlXG4gICkge31cblxuICBuZ09uSW5pdCgpIHt9XG5cbiAgbmdBZnRlclZpZXdJbml0KCkge1xuICAgIHRoaXMubWF0RXZlbnRFbWl0dGVyU2VydmljZS5vbk5hdlN0YXRlQ2hhbmdlLnN1YnNjcmliZSgoZmxhZzogYW55KSA9PiB7XG4gICAgICB0aGlzLmlzRHJhd2VyT3BlbmVkID0gZmxhZy5pc09wZW5lZDtcbiAgICB9KTtcbiAgICB0aGlzLm1hdEV2ZW50RW1pdHRlclNlcnZpY2Uub25TaWRlTmF2Q2xvc2VkLnN1YnNjcmliZSgoZmxhZzogYW55KSA9PiB7XG4gICAgICB0aGlzLmlzRHJhd2VyT3BlbmVkID0gZmxhZy5pc09wZW5lZDtcbiAgICB9KTtcbiAgICB0aGlzLm1hdEV2ZW50RW1pdHRlclNlcnZpY2Uub25TaWRlTmF2Q2xvc2VkLnN1YnNjcmliZSgoZmxhZzogYW55KSA9PiB7XG4gICAgICB0aGlzLmlzRHJhd2VyT3BlbmVkID0gZmxhZy5pc09wZW5lZDtcbiAgICB9KTtcbiAgfVxuXG4gIHB1YmxpYyBvbkl0ZW1TZWxlY3RlZChpdGVtOiBhbnkpIHtcbiAgICBpZiAoIWl0ZW0uY2hpbGRyZW4gfHwgIWl0ZW0uY2hpbGRyZW4ubGVuZ3RoKSB7XG4gICAgICB0aGlzLm1hdEV2ZW50RW1pdHRlclNlcnZpY2UubWVudUl0ZW1DbGljayhpdGVtKTtcbiAgICB9XG4gIH1cblxuICBwdWJsaWMgdG9nZ2xlU2VhcmNoQmFyKCkge1xuICAgIHRoaXMuaXNTZWFyY2hBY3RpdmUgPSAhdGhpcy5pc1NlYXJjaEFjdGl2ZTtcbiAgICBsZXQgc2VhcmNoT2JqZWN0ID0ge1xuICAgICAgdmFsdWU6IHRoaXMuc2VhcmNoVmFsdWUsXG4gICAgICBpbnB1dFJlZjogdGhpcy5uZ3hTZWFyY2hCb3gsXG4gICAgfTtcbiAgICBpZiAodGhpcy5pc1NlYXJjaEFjdGl2ZSkge1xuICAgICAgdGhpcy5tYXRFdmVudEVtaXR0ZXJTZXJ2aWNlLnNlcmFjaElucHV0T3BlbihzZWFyY2hPYmplY3QpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLm1hdEV2ZW50RW1pdHRlclNlcnZpY2Uuc2VyYWNoSW5wdXRDbG9zZWQoc2VhcmNoT2JqZWN0KTtcbiAgICB9XG4gIH1cblxuICBwdWJsaWMgb25TZWFyY2hWYWx1ZUNoYW5nZShldmVudDogYW55KSB7XG4gICAgbGV0IHNlYXJjaE9iamVjdCA9IHtcbiAgICAgIHZhbHVlOiB0aGlzLnNlYXJjaFZhbHVlLFxuICAgICAgaW5wdXRSZWY6IHRoaXMubmd4U2VhcmNoQm94LFxuICAgIH07XG4gICAgdGhpcy5tYXRFdmVudEVtaXR0ZXJTZXJ2aWNlLnNlYXJjaFZhbHVlQ2hhbmdlKHNlYXJjaE9iamVjdCk7XG4gIH1cblxuICBwdWJsaWMgb25TZXJhY2hGb2N1c0luKGV2ZW50OiBhbnkpIHtcbiAgICBsZXQgc2VhcmNoT2JqZWN0ID0ge1xuICAgICAgdmFsdWU6IHRoaXMuc2VhcmNoVmFsdWUsXG4gICAgICBpbnB1dFJlZjogdGhpcy5uZ3hTZWFyY2hCb3gsXG4gICAgfTtcbiAgICB0aGlzLm1hdEV2ZW50RW1pdHRlclNlcnZpY2Uuc2VyYWNoRm9jdXNJbihzZWFyY2hPYmplY3QpO1xuICB9XG5cbiAgcHVibGljIG9uU2VyYWNoRm9jdXNPdXQoZXZlbnQ6IGFueSkge1xuICAgIGxldCBzZWFyY2hPYmplY3QgPSB7XG4gICAgICB2YWx1ZTogdGhpcy5zZWFyY2hWYWx1ZSxcbiAgICAgIGlucHV0UmVmOiB0aGlzLm5neFNlYXJjaEJveCxcbiAgICB9O1xuICAgIHRoaXMubWF0RXZlbnRFbWl0dGVyU2VydmljZS5zZXJhY2hGb2N1c091dChzZWFyY2hPYmplY3QpO1xuICB9XG59XG4iLCI8bWF0LXRvb2xiYXJcbiAgICBjb2xvcj1cInByaW1hcnlcIlxuICAgIGNsYXNzPVwibWF0LWVsZXZhdGlvbi16MSBuZ3gtbWF0ZXJpYWwtdG9vbGJhclwiXG4+XG4gICAgPG5nLWNvbnRhaW5lciAqbmdJZj1cIiFpc1NlYXJjaEFjdGl2ZVwiPlxuICAgICAgICA8IS0tIERyYXdlclRvZ2dsZSBtZW51IC0tPlxuICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgICBjbGFzcz1cImJ0bi10b2dnbGVcIlxuICAgICAgICAgICAgbWF0LWljb24tYnV0dG9uXG4gICAgICAgICAgICBpZD1cIm1lbnVcIlxuICAgICAgICAgICAgKGNsaWNrKT1cIm5hdlNlcnZpY2UudG9nZ2xlTmF2KClcIlxuICAgICAgICA+XG4gICAgICAgICAgICA8IS0tIDxtYXQtaWNvbj57e2NvbmZpZz8udG9nZ2xlSWNvbiA/IGNvbmZpZy50b2dnbGVJY29uIDogJ21lbnUnfX08L21hdC1pY29uPiAtLT5cbiAgICAgICAgICAgIDxkaXZcbiAgICAgICAgICAgICAgICBjbGFzcz1cIndyYXBwZXItbWVudVwiXG4gICAgICAgICAgICAgICAgKm5nSWY9XCIhY29uZmlnPy50b2dnbGVJY29uXCJcbiAgICAgICAgICAgICAgICBbbmdDbGFzc109XCJpc0RyYXdlck9wZW5lZCA/ICdvcGVuJyA6ICdjbG9zZSdcIlxuICAgICAgICAgICAgPlxuICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJsaW5lLW1lbnUgaGFsZiBzdGFydFwiPjwvZGl2PlxuICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJsaW5lLW1lbnVcIj48L2Rpdj5cbiAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwibGluZS1tZW51IGhhbGYgZW5kXCI+PC9kaXY+XG4gICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgIDxuZy1jb250YWluZXIgKm5nSWY9XCJjb25maWc/LnRvZ2dsZUljb25cIj5cbiAgICAgICAgICAgICAgICA8bWF0LWljb24+XG4gICAgICAgICAgICAgICAgICAgIHt7IWlzRHJhd2VyT3BlbmVkID8gY29uZmlnLnRvZ2dsZUljb24gOiBjb25maWc/LmNsb3NlZFRvZ2dsZUljb24gPyBjb25maWc/LmNsb3NlZFRvZ2dsZUljb24gOiAnY2xvc2UnfX1cbiAgICAgICAgICAgICAgICA8L21hdC1pY29uPlxuICAgICAgICAgICAgPC9uZy1jb250YWluZXI+XG4gICAgICAgIDwvYnV0dG9uPlxuICAgICAgICA8c3Bhbj5cbiAgICAgICAgICAgIHt7Y29uZmlnPy5hcHBOYW1lID8gY29uZmlnLmFwcE5hbWUgOiAnRGVmYXVsdCBuYW1lJ319XG4gICAgICAgIDwvc3Bhbj5cbiAgICAgICAgPCEtLSBSaWdodCBNZW51IC0tPlxuICAgICAgICA8c3BhbiBjbGFzcz1cInRvb2xiYXItc3BhY2VyXCI+PC9zcGFuPlxuICAgICAgICA8ZGl2XG4gICAgICAgICAgICBjbGFzcz1cInJpZ2h0LW5hdlwiXG4gICAgICAgICAgICBbbmdTdHlsZV09XCJjb25maWc/LnJpZ2h0TWVudXM/LnN0eWxlPyBjb25maWc/LnJpZ2h0TWVudXMuc3R5bGUgOiAnJ1wiXG4gICAgICAgID5cbiAgICAgICAgICAgIDxidXR0b25cbiAgICAgICAgICAgICAgICAqbmdJZj1cImNvbmZpZz8uc2VhcmNoPy5pc0VuYWJsZVwiXG4gICAgICAgICAgICAgICAgbWF0LWJ1dHRvblxuICAgICAgICAgICAgICAgIG1hdC1pY29uLWJ1dHRvblxuICAgICAgICAgICAgICAgIChjbGljayk9XCJ0b2dnbGVTZWFyY2hCYXIoKVwiXG4gICAgICAgICAgICA+XG4gICAgICAgICAgICAgICAgPG1hdC1pY29uPnNlYXJjaDwvbWF0LWljb24+XG4gICAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgICAgIDxuZy1jb250YWluZXIgKm5nSWY9XCJjb25maWc/LnJpZ2h0TWVudXM/LmRhdGFcIj5cbiAgICAgICAgICAgICAgICA8c3BhbiAqbmdGb3I9XCJsZXQgaXRlbSBvZiBjb25maWc/LnJpZ2h0TWVudXM/LmRhdGFcIj5cbiAgICAgICAgICAgICAgICAgICAgPCEtLSBIYW5kbGUgYnJhbmNoIG5vZGUgYnV0dG9ucyBoZXJlIC0tPlxuICAgICAgICAgICAgICAgICAgICA8c3BhbiAqbmdJZj1cIml0ZW0uY2hpbGRyZW4gJiYgaXRlbS5jaGlsZHJlbi5sZW5ndGggPiAwXCI+XG4gICAgICAgICAgICAgICAgICAgICAgICA8bmctY29udGFpbmVyICpuZ0lmPVwiaXRlbS5jb21wb25lbnQ7IGVsc2UgZWxzZUJsb2NrXCI+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgPGxpYi1jYXJkLWhvbGRlclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBbbWF0TWVudVRyaWdnZXJGb3JdPVwibWVudS5jaGlsZE1lbnVcIlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBbY2FyZERhdGFdPVwibmd4VXRpbHNTZXJ2aWNlLmdldEV4dGVuZGVkRGF0YShpdGVtLmNvbXBvbmVudClcIlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgID48L2xpYi1jYXJkLWhvbGRlcj5cbiAgICAgICAgICAgICAgICAgICAgICAgIDwvbmctY29udGFpbmVyPlxuICAgICAgICAgICAgICAgICAgICAgICAgPG5nLXRlbXBsYXRlICNlbHNlQmxvY2s+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgPGJ1dHRvblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAqbmdJZj1cIml0ZW0uZGlzcGxheU5hbWU/LnRyaW0oKVwiXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFtuZ1N0eWxlXT1cIml0ZW0/LnN0eWxlPyBpdGVtLnN0eWxlIDogJydcIlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXQtYnV0dG9uXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFttYXRNZW51VHJpZ2dlckZvcl09XCJtZW51LmNoaWxkTWVudVwiXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFtkaXNhYmxlZF09XCJpdGVtLmRpc2FibGVkXCJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxtYXQtaWNvbj57e2l0ZW0uaWNvbk5hbWV9fTwvbWF0LWljb24+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxzcGFuPnt7aXRlbS5kaXNwbGF5TmFtZX19PC9zcGFuPlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxidXR0b25cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKm5nSWY9XCIhaXRlbT8uZGlzcGxheU5hbWU/LnRyaW0oKVwiXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFtuZ1N0eWxlXT1cIml0ZW0/LnN0eWxlPyBpdGVtLnN0eWxlIDogJydcIlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXQtaWNvbi1idXR0b25cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgW21hdE1lbnVUcmlnZ2VyRm9yXT1cIm1lbnUuY2hpbGRNZW51XCJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgW2Rpc2FibGVkXT1cIml0ZW0uZGlzYWJsZWRcIlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPG1hdC1pY29uPnt7aXRlbS5pY29uTmFtZX19PC9tYXQtaWNvbj5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgICAgICAgICAgICAgICAgIDwvbmctdGVtcGxhdGU+XG4gICAgICAgICAgICAgICAgICAgICAgICA8bGliLW1lbnUtbGlzdC1pdGVtXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgI21lbnVcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBbbWVudXNdPVwiaXRlbS5jaGlsZHJlblwiXG4gICAgICAgICAgICAgICAgICAgICAgICA+PC9saWItbWVudS1saXN0LWl0ZW0+XG4gICAgICAgICAgICAgICAgICAgIDwvc3Bhbj5cbiAgICAgICAgICAgICAgICAgICAgPCEtLSBMZWFmIG5vZGUgYnV0dG9ucyBoZXJlIC0tPlxuICAgICAgICAgICAgICAgICAgICA8c3BhbiAqbmdJZj1cIiFpdGVtLmNoaWxkcmVuIHx8IGl0ZW0uY2hpbGRyZW4ubGVuZ3RoID09PSAwXCI+XG4gICAgICAgICAgICAgICAgICAgICAgICA8bmctY29udGFpbmVyICpuZ0lmPVwiaXRlbS5jb21wb25lbnQ7IGVsc2UgZWxzZUJsb2NrXCI+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgPGxpYi1jYXJkLWhvbGRlciBbY2FyZERhdGFdPVwibmd4VXRpbHNTZXJ2aWNlLmdldEV4dGVuZGVkRGF0YShpdGVtLmNvbXBvbmVudClcIj48L2xpYi1jYXJkLWhvbGRlcj5cbiAgICAgICAgICAgICAgICAgICAgICAgIDwvbmctY29udGFpbmVyPlxuICAgICAgICAgICAgICAgICAgICAgICAgPG5nLXRlbXBsYXRlICNlbHNlQmxvY2s+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgPGJ1dHRvblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAqbmdJZj1cIml0ZW0uZGlzcGxheU5hbWU/LnRyaW0oKVwiXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFtuZ1N0eWxlXT1cIml0ZW0/LnN0eWxlPyBpdGVtLnN0eWxlIDogJydcIlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXQtYnV0dG9uXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChjbGljayk9XCJvbkl0ZW1TZWxlY3RlZChpdGVtKVwiXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFtkaXNhYmxlZF09XCJpdGVtLmRpc2FibGVkXCJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxtYXQtaWNvbj57e2l0ZW0uaWNvbk5hbWV9fTwvbWF0LWljb24+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxzcGFuPnt7aXRlbS5kaXNwbGF5TmFtZX19PC9zcGFuPlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxidXR0b25cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKm5nSWY9XCIhaXRlbT8uZGlzcGxheU5hbWU/LnRyaW0oKVwiXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFtuZ1N0eWxlXT1cIml0ZW0/LnN0eWxlPyBpdGVtLnN0eWxlIDogJydcIlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXQtaWNvbi1idXR0b25cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKGNsaWNrKT1cIm9uSXRlbVNlbGVjdGVkKGl0ZW0pXCJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgW2Rpc2FibGVkXT1cIml0ZW0uZGlzYWJsZWRcIlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPG1hdC1pY29uPnt7aXRlbS5pY29uTmFtZX19PC9tYXQtaWNvbj5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgICAgICAgICAgICAgICAgIDwvbmctdGVtcGxhdGU+XG4gICAgICAgICAgICAgICAgICAgIDwvc3Bhbj5cbiAgICAgICAgICAgICAgICA8L3NwYW4+XG4gICAgICAgICAgICA8L25nLWNvbnRhaW5lcj5cbiAgICAgICAgPC9kaXY+XG4gICAgPC9uZy1jb250YWluZXI+XG4gICAgPG5nLWNvbnRhaW5lciAqbmdJZj1cImlzU2VhcmNoQWN0aXZlXCI+XG4gICAgICAgIDxkaXZcbiAgICAgICAgICAgIGNsYXNzPVwic2VhcmNoQmFyTWFpblwiXG4gICAgICAgICAgICBbbmdTdHlsZV09XCJjb25maWc/LnNlYXJjaD8uc3R5bGUgPyBjb25maWc/LnNlYXJjaD8uc3R5bGUgOiAnJ1wiXG4gICAgICAgICAgICBbQGVudGVyQW5pbWF0aW9uXVxuICAgICAgICA+XG4gICAgICAgICAgICA8aVxuICAgICAgICAgICAgICAgIChjbGljayk9XCJ0b2dnbGVTZWFyY2hCYXIoKVwiXG4gICAgICAgICAgICAgICAgY2xhc3M9XCJtYXRlcmlhbC1pY29ucyBzZWFyY2hCYXJTZWFyY2hJY29uXCJcbiAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgICB7e2NvbmZpZz8uc2VhcmNoPy5iYWNrSWNvbiA/IGNvbmZpZz8uc2VhcmNoPy5iYWNrSWNvbiA6ICdhcnJvd19iYWNrJ319XG4gICAgICAgICAgICA8L2k+XG4gICAgICAgICAgICA8aW5wdXRcbiAgICAgICAgICAgICAgICB0eXBlPVwidGV4dFwiXG4gICAgICAgICAgICAgICAgI25neFNlYXJjaEJveFxuICAgICAgICAgICAgICAgIG5hbWU9XCJoZWFkZXItc2VhcmNoXCJcbiAgICAgICAgICAgICAgICBbKG5nTW9kZWwpXT1cInNlYXJjaFZhbHVlXCJcbiAgICAgICAgICAgICAgICBjbGFzcz1cInNlYXJjaEJhcklucHV0XCJcbiAgICAgICAgICAgICAgICAoaW5wdXQpPVwib25TZWFyY2hWYWx1ZUNoYW5nZSgkZXZlbnQpXCJcbiAgICAgICAgICAgICAgICAoZm9jdXMpPVwib25TZXJhY2hGb2N1c0luKCRldmVudClcIlxuICAgICAgICAgICAgICAgIChmb2N1c291dCk9XCJvblNlcmFjaEZvY3VzT3V0KCRldmVudClcIlxuICAgICAgICAgICAgICAgIFtwbGFjZWhvbGRlcl09XCJjb25maWc/LnNlYXJjaD8ucGxhY2VIb2xkZXIgPyBjb25maWc/LnNlYXJjaD8ucGxhY2VIb2xkZXIgOiAnU2VhcmNoLCBkaXNjb3ZlciwgZXhwbG9yZS4uLidcIlxuICAgICAgICAgICAgPlxuICAgICAgICAgICAgPGlcbiAgICAgICAgICAgICAgICAqbmdJZj1cInNlYXJjaFZhbHVlLmxlbmd0aFwiXG4gICAgICAgICAgICAgICAgKGNsaWNrKT1cInNlYXJjaFZhbHVlID0gJydcIlxuICAgICAgICAgICAgICAgIGNsYXNzPVwibWF0ZXJpYWwtaWNvbnMgY2xlYXJTZWFyY2hCYXJGaWVsZFwiXG4gICAgICAgICAgICA+XG4gICAgICAgICAgICAgICAge3tjb25maWc/LnNlYXJjaD8uY2xlYXJJY29uID8gY29uZmlnPy5zZWFyY2g/LmNsZWFySWNvbiA6ICdjbGVhcid9fVxuICAgICAgICAgICAgPC9pPlxuICAgICAgICA8L2Rpdj5cbiAgICA8L25nLWNvbnRhaW5lcj5cbjwvbWF0LXRvb2xiYXI+XG4iXX0=