@c8y/ngx-components
Version:
Angular modules for Cumulocity IoT applications
221 lines • 42.1 kB
JavaScript
import { BsDropdownDirective } from 'ngx-bootstrap/dropdown';
import { gettext } from '../i18n/gettext';
import { Component, EventEmitter, HostListener, Input, Output, ViewChild, ContentChildren, inject } from '@angular/core';
import { ListItemComponent } from '../list-group/list-item.component';
import { TranslateService } from '@ngx-translate/core';
import { PropertyValueTransformService } from '../i18n';
import * as i0 from "@angular/core";
import * as i1 from "ngx-bootstrap/dropdown";
import * as i2 from "../common/icon.directive";
import * as i3 from "@angular/common";
import * as i4 from "../common/dropdown-direction.directive";
import * as i5 from "@angular/forms";
import * as i6 from "../i18n/c8y-translate.pipe";
import * as i7 from "../i18n/name-transform.pipe";
export class SelectLegacyComponent {
constructor() {
this.placeholder = gettext('Select item');
this.applyLabel = gettext('Apply');
this.disableApplyOnNoSelection = false;
this.addDropdownContainerToBody = false;
this.onChange = new EventEmitter();
this.textFilter = '';
this.labelText = '';
this.isOpen = false;
this.filteredItems = [];
this.searchFilter = null;
this.sizeToShowFilter = 5;
this.labelsForSelectAll = {
all: gettext('All'),
allFiltered: gettext('All filtered'),
none: gettext('Select filter…')
};
this.showAllLabel = false;
this.itemsSelected = new Set();
this.stopClicks = false;
this.propertyValueTransformService = inject(PropertyValueTransformService);
this.translateService = inject(TranslateService);
}
set selected(value) {
this._selected = value || [];
}
get selected() {
return this._selected;
}
preventClick(evt) {
if (this.stopClicks) {
evt.stopPropagation();
}
this.stopClicks = this.isOpen;
}
isOpenChange(isOpen) {
this.isOpen = isOpen;
if (isOpen) {
this.updateSelected();
this.searchFilter = null;
}
else {
this.stopClicks = false;
}
}
outterSelected(item) {
const { selected } = this;
let isSelected = () => false;
if (typeof selected === 'function') {
isSelected = selected;
}
else if (Array.isArray(selected)) {
isSelected = (i) => selected.indexOf(i) > -1;
}
return isSelected(item);
}
isSelected(item) {
return this.itemsSelected.has(item);
}
isAllItemsSelected() {
return this.itemsSelected.size === this.items.length;
}
isAllFilteredSelected() {
return this.itemsSelected.size === this.filteredItems.length;
}
isNoItemSelected() {
return !this.itemsSelected.size;
}
applyChanges() {
const selected = Array.from(this.itemsSelected.values());
this.onChange.emit(selected);
this.dropdown.hide();
}
selectAll(checked) {
this.itemsSelected.clear();
this.filteredItems.forEach(item => this.onChangeItem(checked, item));
}
ngOnInit() {
if (this.updateItems) {
this.updateItems.subscribe(() => {
this.updateSelected();
this.updateLabel();
this.showAllLabel = this.isAllItemsSelected();
});
}
}
onChangeItem(checked, item) {
if (checked) {
this.itemsSelected.add(item);
}
else {
this.itemsSelected.delete(item);
}
}
deselectItem(item) {
this.itemsSelected.delete(item);
const selected = Array.from(this.itemsSelected.values());
this.onChange.emit(selected);
}
updateFiltered(term) {
if (term) {
const search = new RegExp(term, 'i');
this.filteredItems = this.items.filter(({ name }) => search.test(name));
}
else {
this.filteredItems = this.items;
}
}
getSelectAllToggleStatus() {
const label = this.getLabel();
const checked = this.isAllSelected();
const indeterminate = !checked && this.itemsSelected.size > 0;
return { label, checked, indeterminate };
}
ngOnChanges(changes) {
if (this.isOpen) {
return;
}
if (changes.items || changes.selected || changes.applyLabel) {
this.updateSelected();
this.updateLabel();
this.showAllLabel = this.isAllItemsSelected();
}
}
ngOnDestroy() {
if (this.updateItems && !this.updateItems.closed) {
this.updateItems.unsubscribe();
}
}
updateLabel() {
const outterSelected = this.items.filter(i => this.outterSelected(i));
if (typeof this.selectedLabel === 'string') {
const itemName = this.propertyValueTransformService.getName({ name: this.selectedLabel });
this.labelText = itemName && this.translateService.instant(itemName);
}
else if (typeof this.selectedLabel === 'function') {
const itemName = this.propertyValueTransformService.getName({
name: this.selectedLabel(outterSelected)
});
this.labelText = itemName && this.translateService.instant(itemName);
}
else {
this.labelText = outterSelected
.map(({ name }) => {
const itemName = this.propertyValueTransformService.getName({ name });
return itemName && this.translateService.instant(itemName);
})
.join(', ');
}
}
updateSelected() {
const { itemsSelected, items } = this;
itemsSelected.clear();
items.forEach(item => {
if (this.outterSelected(item)) {
itemsSelected.add(item);
}
});
this.filteredItems = items;
}
isAllSelected() {
if (this.getLabel() === this.labelsForSelectAll.allFiltered) {
return this.isAllFilteredSelected();
}
else {
return this.isAllItemsSelected();
}
}
getLabel() {
return this.searchFilter ? this.labelsForSelectAll.allFiltered : this.labelsForSelectAll.all;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SelectLegacyComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: SelectLegacyComponent, selector: "c8y-select-legacy", inputs: { placeholder: "placeholder", selectedLabel: "selectedLabel", applyLabel: "applyLabel", items: "items", selected: "selected", updateItems: "updateItems", disableApplyOnNoSelection: "disableApplyOnNoSelection", addDropdownContainerToBody: "addDropdownContainerToBody" }, outputs: { onChange: "onChange" }, host: { listeners: { "click": "preventClick($event)" } }, queries: [{ propertyName: "liChildren", predicate: ListItemComponent }], viewQueries: [{ propertyName: "dropdown", first: true, predicate: BsDropdownDirective, descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div\n class=\"dropdown fit-w\"\n container=\"{{ addDropdownContainerToBody ? 'body' : null }}\"\n (isOpenChange)=\"isOpenChange($event)\"\n dropdown\n #dropdown=\"bs-dropdown\"\n c8yDropdownDirection\n px-event=\"Select type\"\n [insideClick]=\"true\"\n>\n <div class=\"input-group dropdown-toggle\">\n <div\n class=\"form-control pointer d-flex inner-scroll\"\n (click)=\"dropdown.isOpen = !dropdown.isOpen\"\n >\n <ng-container *ngIf=\"itemsSelected.size !== items.length; else all\">\n <em\n class=\"text-muted\"\n *ngIf=\"itemsSelected.size === 0\"\n >\n {{ placeholder | translate }}\n </em>\n <span\n class=\"tag tag--info chip\"\n *ngFor=\"let selectedItem of itemsSelected\"\n >\n <button\n class=\"btn btn-xs btn-clean text-10\"\n title=\"{{ 'Remove' | translate }}\"\n type=\"button\"\n (click)=\"deselectItem(selectedItem); $event.stopPropagation()\"\n >\n <i [c8yIcon]=\"'times'\"></i>\n </button>\n {{ selectedItem.name | nameTransform | translate }}\n </span>\n </ng-container>\n <ng-template #all>\n {{ 'All`possible options`' | translate }}\n </ng-template>\n </div>\n <div class=\"input-group-btn\">\n <button\n class=\"btn btn-default d-flex a-i-center w-auto\"\n title=\"{{ labelText || placeholder | translate }}\"\n aria-haspopup=\"true\"\n dropdownToggle\n >\n <i class=\"c8y-glyph-caret icon-16\"></i>\n </button>\n </div>\n </div>\n\n <ul\n class=\"dropdown-menu multiselect-container\"\n *dropdownMenu\n >\n <ng-content select=\"c8y-li\"></ng-content>\n <ng-container *ngIf=\"liChildren.length === 0\">\n <li\n class=\"multiselect-item sticky-top\"\n *ngIf=\"items.length > sizeToShowFilter\"\n >\n <div class=\"input-group input-group-search\">\n <input\n class=\"form-control\"\n placeholder=\"{{ 'Filter' | translate }}\u2026\"\n type=\"search\"\n (keyup)=\"updateFiltered($event.target.value)\"\n [(ngModel)]=\"searchFilter\"\n />\n <span class=\"input-group-addon\">\n <i\n c8yIcon=\"search\"\n *ngIf=\"!textFilter\"\n ></i>\n <i\n class=\"text-muted\"\n c8yIcon=\"times\"\n *ngIf=\"textFilter\"\n (click)=\"textFilter = ''\"\n ></i>\n </span>\n </div>\n </li>\n\n <li class=\"multiselect-item\">\n <label\n class=\"c8y-checkbox input-sm\"\n [title]=\"getSelectAllToggleStatus().label | translate\"\n ng-click=\"vm.toggleSelectAll(); $event.preventDefault()\"\n >\n <input\n class=\"m-t-0\"\n type=\"checkbox\"\n [checked]=\"getSelectAllToggleStatus().checked\"\n (change)=\"selectAll($event.target.checked)\"\n [indeterminate]=\"getSelectAllToggleStatus().indeterminate\"\n />\n <span></span>\n <span class=\"label-text\">\n {{ getSelectAllToggleStatus().label | translate }}\n </span>\n </label>\n </li>\n\n <li\n class=\"multiselect-item\"\n *ngFor=\"let item of filteredItems\"\n >\n <label\n class=\"c8y-checkbox d-flex a-i-center\"\n [title]=\"item.name | nameTransform | translate\"\n >\n <input\n type=\"checkbox\"\n [checked]=\"isSelected(item)\"\n (change)=\"onChangeItem($event.target.checked, item)\"\n />\n <span></span>\n <span class=\"m-l-8\">{{ item.name | nameTransform | translate }}</span>\n </label>\n </li>\n <li class=\"divider\"></li>\n <li class=\"sticky-bottom bg-level-0\">\n <button\n class=\"btn btn-primary btn-block\"\n title=\"{{ applyLabel | translate }}\"\n [disabled]=\"disableApplyOnNoSelection && isNoItemSelected()\"\n (click)=\"applyChanges()\"\n >\n {{ applyLabel | translate }}\n </button>\n </li>\n </ng-container>\n </ul>\n</div>\n", dependencies: [{ kind: "directive", type: i1.BsDropdownMenuDirective, selector: "[bsDropdownMenu],[dropdownMenu]", exportAs: ["bs-dropdown-menu"] }, { kind: "directive", type: i1.BsDropdownToggleDirective, selector: "[bsDropdownToggle],[dropdownToggle]", exportAs: ["bs-dropdown-toggle"] }, { kind: "directive", type: i1.BsDropdownDirective, selector: "[bsDropdown], [dropdown]", inputs: ["placement", "triggers", "container", "dropup", "autoClose", "isAnimated", "insideClick", "isDisabled", "isOpen"], outputs: ["isOpenChange", "onShown", "onHidden"], exportAs: ["bs-dropdown"] }, { kind: "directive", type: i2.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i4.DropdownDirectionDirective, selector: "[dropdown][c8yBsDropdownDirection],[dropdown][c8yDropdownDirection]" }, { kind: "directive", type: i5.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: i5.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i5.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "pipe", type: i6.C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: i7.NameTransformPipe, name: "nameTransform" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SelectLegacyComponent, decorators: [{
type: Component,
args: [{ selector: 'c8y-select-legacy', template: "<div\n class=\"dropdown fit-w\"\n container=\"{{ addDropdownContainerToBody ? 'body' : null }}\"\n (isOpenChange)=\"isOpenChange($event)\"\n dropdown\n #dropdown=\"bs-dropdown\"\n c8yDropdownDirection\n px-event=\"Select type\"\n [insideClick]=\"true\"\n>\n <div class=\"input-group dropdown-toggle\">\n <div\n class=\"form-control pointer d-flex inner-scroll\"\n (click)=\"dropdown.isOpen = !dropdown.isOpen\"\n >\n <ng-container *ngIf=\"itemsSelected.size !== items.length; else all\">\n <em\n class=\"text-muted\"\n *ngIf=\"itemsSelected.size === 0\"\n >\n {{ placeholder | translate }}\n </em>\n <span\n class=\"tag tag--info chip\"\n *ngFor=\"let selectedItem of itemsSelected\"\n >\n <button\n class=\"btn btn-xs btn-clean text-10\"\n title=\"{{ 'Remove' | translate }}\"\n type=\"button\"\n (click)=\"deselectItem(selectedItem); $event.stopPropagation()\"\n >\n <i [c8yIcon]=\"'times'\"></i>\n </button>\n {{ selectedItem.name | nameTransform | translate }}\n </span>\n </ng-container>\n <ng-template #all>\n {{ 'All`possible options`' | translate }}\n </ng-template>\n </div>\n <div class=\"input-group-btn\">\n <button\n class=\"btn btn-default d-flex a-i-center w-auto\"\n title=\"{{ labelText || placeholder | translate }}\"\n aria-haspopup=\"true\"\n dropdownToggle\n >\n <i class=\"c8y-glyph-caret icon-16\"></i>\n </button>\n </div>\n </div>\n\n <ul\n class=\"dropdown-menu multiselect-container\"\n *dropdownMenu\n >\n <ng-content select=\"c8y-li\"></ng-content>\n <ng-container *ngIf=\"liChildren.length === 0\">\n <li\n class=\"multiselect-item sticky-top\"\n *ngIf=\"items.length > sizeToShowFilter\"\n >\n <div class=\"input-group input-group-search\">\n <input\n class=\"form-control\"\n placeholder=\"{{ 'Filter' | translate }}\u2026\"\n type=\"search\"\n (keyup)=\"updateFiltered($event.target.value)\"\n [(ngModel)]=\"searchFilter\"\n />\n <span class=\"input-group-addon\">\n <i\n c8yIcon=\"search\"\n *ngIf=\"!textFilter\"\n ></i>\n <i\n class=\"text-muted\"\n c8yIcon=\"times\"\n *ngIf=\"textFilter\"\n (click)=\"textFilter = ''\"\n ></i>\n </span>\n </div>\n </li>\n\n <li class=\"multiselect-item\">\n <label\n class=\"c8y-checkbox input-sm\"\n [title]=\"getSelectAllToggleStatus().label | translate\"\n ng-click=\"vm.toggleSelectAll(); $event.preventDefault()\"\n >\n <input\n class=\"m-t-0\"\n type=\"checkbox\"\n [checked]=\"getSelectAllToggleStatus().checked\"\n (change)=\"selectAll($event.target.checked)\"\n [indeterminate]=\"getSelectAllToggleStatus().indeterminate\"\n />\n <span></span>\n <span class=\"label-text\">\n {{ getSelectAllToggleStatus().label | translate }}\n </span>\n </label>\n </li>\n\n <li\n class=\"multiselect-item\"\n *ngFor=\"let item of filteredItems\"\n >\n <label\n class=\"c8y-checkbox d-flex a-i-center\"\n [title]=\"item.name | nameTransform | translate\"\n >\n <input\n type=\"checkbox\"\n [checked]=\"isSelected(item)\"\n (change)=\"onChangeItem($event.target.checked, item)\"\n />\n <span></span>\n <span class=\"m-l-8\">{{ item.name | nameTransform | translate }}</span>\n </label>\n </li>\n <li class=\"divider\"></li>\n <li class=\"sticky-bottom bg-level-0\">\n <button\n class=\"btn btn-primary btn-block\"\n title=\"{{ applyLabel | translate }}\"\n [disabled]=\"disableApplyOnNoSelection && isNoItemSelected()\"\n (click)=\"applyChanges()\"\n >\n {{ applyLabel | translate }}\n </button>\n </li>\n </ng-container>\n </ul>\n</div>\n" }]
}], propDecorators: { placeholder: [{
type: Input
}], selectedLabel: [{
type: Input
}], applyLabel: [{
type: Input
}], items: [{
type: Input
}], selected: [{
type: Input
}], updateItems: [{
type: Input
}], disableApplyOnNoSelection: [{
type: Input
}], addDropdownContainerToBody: [{
type: Input
}], onChange: [{
type: Output
}], dropdown: [{
type: ViewChild,
args: [BsDropdownDirective, { static: false }]
}], liChildren: [{
type: ContentChildren,
args: [ListItemComponent]
}], preventClick: [{
type: HostListener,
args: ['click', ['$event']]
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VsZWN0LWxlZ2FjeS5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9jb3JlL3NlbGVjdC9zZWxlY3QtbGVnYWN5LmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uL2NvcmUvc2VsZWN0L3NlbGVjdC1sZWdhY3kuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDN0QsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQzFDLE9BQU8sRUFDTCxTQUFTLEVBQ1QsWUFBWSxFQUNaLFlBQVksRUFDWixLQUFLLEVBRUwsTUFBTSxFQUVOLFNBQVMsRUFDVCxlQUFlLEVBRWYsTUFBTSxFQUNQLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLG1DQUFtQyxDQUFDO0FBRXRFLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQ3ZELE9BQU8sRUFBRSw2QkFBNkIsRUFBRSxNQUFNLFNBQVMsQ0FBQzs7Ozs7Ozs7O0FBTXhELE1BQU0sT0FBTyxxQkFBcUI7SUFKbEM7UUFLVyxnQkFBVyxHQUFXLE9BQU8sQ0FBQyxhQUFhLENBQUMsQ0FBQztRQUU3QyxlQUFVLEdBQVcsT0FBTyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBWXRDLDhCQUF5QixHQUFHLEtBQUssQ0FBQztRQUNsQywrQkFBMEIsR0FBRyxLQUFLLENBQUM7UUFDbEMsYUFBUSxHQUF5QixJQUFJLFlBQVksRUFBRSxDQUFDO1FBRzlELGVBQVUsR0FBRyxFQUFFLENBQUM7UUFDaEIsY0FBUyxHQUFHLEVBQUUsQ0FBQztRQUNmLFdBQU0sR0FBRyxLQUFLLENBQUM7UUFDZixrQkFBYSxHQUFXLEVBQUUsQ0FBQztRQUMzQixpQkFBWSxHQUFHLElBQUksQ0FBQztRQUNYLHFCQUFnQixHQUFXLENB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Z0JBUUcsV0FBVztzQkFBbkIsS0FBSztnQkFDRyx5QkFBeUI7c0JBQWpDLEtBQUs7Z0JBQ0csMEJBQTBCO3NCQUFsQyxLQUFLO2dCQUNJLFFBQVE7c0JBQWpCLE1BQU07Z0JBQzRDLFFBQVE7c0JBQTFELFNBQVM7dUJBQUMsbUJBQW1CLEVBQUUsRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFFO2dCQUNiLFVBQVU7c0JBQTdDLGVBQWU7dUJBQUMsaUJBQWlCO2dCQW9CbEMsWUFBWTtzQkFEWCxZQUFZO3VCQUFDLE9BQU8sRUFBRSxDQUFDLFFBQVEsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEJzRHJvcGRvd25EaXJlY3RpdmUgfSBmcm9tICduZ3gtYm9vdHN0cmFwL2Ryb3Bkb3duJztcbmltcG9ydCB7IGdldHRleHQgfSBmcm9tICcuLi9pMThuL2dldHRleHQnO1xuaW1wb3J0IHtcbiAgQ29tcG9uZW50LFxuICBFdmVudEVtaXR0ZXIsXG4gIEhvc3RMaXN0ZW5lcixcbiAgSW5wdXQsXG4gIE9uQ2hhbmdlcyxcbiAgT3V0cHV0LFxuICBTaW1wbGVDaGFuZ2VzLFxuICBWaWV3Q2hpbGQsXG4gIENvbnRlbnRDaGlsZHJlbixcbiAgT25Jbml0LFxuICBpbmplY3Rcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBMaXN0SXRlbUNvbXBvbmVudCB9IGZyb20gJy4uL2xpc3QtZ3JvdXAvbGlzdC1pdGVtLmNvbXBvbmVudCc7XG5pbXBvcnQgeyBJdGVtLCBzZWxlY3RlZEZ1bmN0aW9uLCBzZWxlY3RlZExhYmVsRnVuY3Rpb24gfSBmcm9tICcuL3NlbGVjdC5tb2RlbCc7XG5pbXBvcnQgeyBUcmFuc2xhdGVTZXJ2aWNlIH0gZnJvbSAnQG5neC10cmFuc2xhdGUvY29yZSc7XG5pbXBvcnQgeyBQcm9wZXJ0eVZhbHVlVHJhbnNmb3JtU2VydmljZSB9IGZyb20gJy4uL2kxOG4nO1xuXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICdjOHktc2VsZWN0LWxlZ2FjeScsXG4gIHRlbXBsYXRlVXJsOiAnLi9zZWxlY3QtbGVnYWN5LmNvbXBvbmVudC5odG1sJ1xufSlcbmV4cG9ydCBjbGFzcyBTZWxlY3RMZWdhY3lDb21wb25lbnQgaW1wbGVtZW50cyBPbkNoYW5nZXMsIE9uSW5pdCB7XG4gIEBJbnB1dCgpIHBsYWNlaG9sZGVyOiBzdHJpbmcgPSBnZXR0ZXh0KCdTZWxlY3QgaXRlbScpO1xuICBASW5wdXQoKSBzZWxlY3RlZExhYmVsOiBzdHJpbmcgfCBzZWxlY3RlZExhYmVsRnVuY3Rpb247XG4gIEBJbnB1dCgpIGFwcGx5TGFiZWw6IHN0cmluZyA9IGdldHRleHQoJ0FwcGx5Jyk7XG4gIEBJbnB1dCgpIGl0ZW1zOiBJdGVtW107XG5cbiAgQElucHV0KClcbiAgc2V0IHNlbGVjdGVkKHZhbHVlOiBJdGVtW10gfCBzZWxlY3RlZEZ1bmN0aW9uKSB7XG4gICAgdGhpcy5fc2VsZWN0ZWQgPSB2YWx1ZSB8fCBbXTtcbiAgfVxuICBnZXQgc2VsZWN0ZWQoKTogSXRlbVtdIHwgc2VsZWN0ZWRGdW5jdGlvbiB7XG4gICAgcmV0dXJuIHRoaXMuX3NlbGVjdGVkO1xuICB9XG5cbiAgQElucHV0KCkgdXBkYXRlSXRlbXM6IEV2ZW50RW1pdHRlcjxib29sZWFuPjtcbiAgQElucHV0KCkgZGlzYWJsZUFwcGx5T25Ob1NlbGVjdGlvbiA9IGZhbHNlO1xuICBASW5wdXQoKSBhZGREcm9wZG93bkNvbnRhaW5lclRvQm9keSA9IGZhbHNlO1xuICBAT3V0cHV0KCkgb25DaGFuZ2U6IEV2ZW50RW1pdHRlcjxJdGVtW10+ID0gbmV3IEV2ZW50RW1pdHRlcigpO1xuICBAVmlld0NoaWxkKEJzRHJvcGRvd25EaXJlY3RpdmUsIHsgc3RhdGljOiBmYWxzZSB9KSBkcm9wZG93bjogQnNEcm9wZG93bkRpcmVjdGl2ZTtcbiAgQENvbnRlbnRDaGlsZHJlbihMaXN0SXRlbUNvbXBvbmVudCkgbGlDaGlsZHJlbjtcbiAgdGV4dEZpbHRlciA9ICcnO1xuICBsYWJlbFRleHQgPSAnJztcbiAgaXNPcGVuID0gZmFsc2U7XG4gIGZpbHRlcmVkSXRlbXM6IEl0ZW1bXSA9IFtdO1xuICBzZWFyY2hGaWx0ZXIgPSBudWxsO1xuICByZWFkb25seSBzaXplVG9TaG93RmlsdGVyOiBudW1iZXIgPSA1O1xuICBsYWJlbHNGb3JTZWxlY3RBbGw6IGFueSA9IHtcbiAgICBhbGw6IGdldHRleHQoJ0FsbCcpLFxuICAgIGFsbEZpbHRlcmVkOiBnZXR0ZXh0KCdBbGwgZmlsdGVyZWQnKSxcbiAgICBub25lOiBnZXR0ZXh0KCdTZWxlY3QgZmlsdGVy4oCmJylcbiAgfTtcbiAgc2hvd0FsbExhYmVsID0gZmFsc2U7XG4gIGl0ZW1zU2VsZWN0ZWQ6IFNldDxJdGVtPiA9IG5ldyBTZXQoKTtcbiAgcHJpdmF0ZSBzdG9wQ2xpY2tzID0gZmFsc2U7XG4gIHByaXZhdGUgcHJvcGVydHlWYWx1ZVRyYW5zZm9ybVNlcnZpY2UgPSBpbmplY3QoUHJvcGVydHlWYWx1ZVRyYW5zZm9ybVNlcnZpY2UpO1xuICBwcml2YXRlIHRyYW5zbGF0ZVNlcnZpY2UgPSBpbmplY3QoVHJhbnNsYXRlU2VydmljZSk7XG4gIHByaXZhdGUgX3NlbGVjdGVkOiBJdGVtW10gfCBzZWxlY3RlZEZ1bmN0aW9uO1xuXG4gIEBIb3N0TGlzdGVuZXIoJ2NsaWNrJywgWyckZXZlbnQnXSlcbiAgcHJldmVudENsaWNrKGV2dCkge1xuICAgIGlmICh0aGlzLnN0b3BDbGlja3MpIHtcbiAgICAgIGV2dC5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICB9XG4gICAgdGhpcy5zdG9wQ2xpY2tzID0gdGhpcy5pc09wZW47XG4gIH1cblxuICBpc09wZW5DaGFuZ2UoaXNPcGVuOiBib29sZWFuKSB7XG4gICAgdGhpcy5pc09wZW4gPSBpc09wZW47XG4gICAgaWYgKGlzT3Blbikge1xuICAgICAgdGhpcy51cGRhdGVTZWxlY3RlZCgpO1xuICAgICAgdGhpcy5zZWFyY2hGaWx0ZXIgPSBudWxsO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLnN0b3BDbGlja3MgPSBmYWxzZTtcbiAgICB9XG4gIH1cblxuICBvdXR0ZXJTZWxlY3RlZChpdGVtOiBJdGVtKSB7XG4gICAgY29uc3QgeyBzZWxlY3RlZCB9ID0gdGhpcztcbiAgICBsZXQgaXNTZWxlY3RlZDogYW55ID0gKCkgPT4gZmFsc2U7XG4gICAgaWYgKHR5cGVvZiBzZWxlY3RlZCA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgaXNTZWxlY3RlZCA9IHNlbGVjdGVkO1xuICAgIH0gZWxzZSBpZiAoQXJyYXkuaXNBcnJheShzZWxlY3RlZCkpIHtcbiAgICAgIGlzU2VsZWN0ZWQgPSAoaTogSXRlbSkgPT4gc2VsZWN0ZWQuaW5kZXhPZihpKSA+IC0xO1xuICAgIH1cbiAgICByZXR1cm4gaXNTZWxlY3RlZChpdGVtKTtcbiAgfVxuXG4gIGlzU2VsZWN0ZWQoaXRlbTogSXRlbSkge1xuICAgIHJldHVybiB0aGlzLml0ZW1zU2VsZWN0ZWQuaGFzKGl0ZW0pO1xuICB9XG5cbiAgaXNBbGxJdGVtc1NlbGVjdGVkKCkge1xuICAgIHJldHVybiB0aGlzLml0ZW1zU2VsZWN0ZWQuc2l6ZSA9PT0gdGhpcy5pdGVtcy5sZW5ndGg7XG4gIH1cblxuICBpc0FsbEZpbHRlcmVkU2VsZWN0ZWQoKSB7XG4gICAgcmV0dXJuIHRoaXMuaXRlbXNTZWxlY3RlZC5zaXplID09PSB0aGlzLmZpbHRlcmVkSXRlbXMubGVuZ3RoO1xuICB9XG5cbiAgaXNOb0l0ZW1TZWxlY3RlZCgpIHtcbiAgICByZXR1cm4gIXRoaXMuaXRlbXNTZWxlY3RlZC5zaXplO1xuICB9XG5cbiAgYXBwbHlDaGFuZ2VzKCkge1xuICAgIGNvbnN0IHNlbGVjdGVkID0gQXJyYXkuZnJvbSh0aGlzLml0ZW1zU2VsZWN0ZWQudmFsdWVzKCkpO1xuICAgIHRoaXMub25DaGFuZ2UuZW1pdChzZWxlY3RlZCk7XG4gICAgdGhpcy5kcm9wZG93bi5oaWRlKCk7XG4gIH1cblxuICBzZWxlY3RBbGwoY2hlY2tlZDogYm9vbGVhbikge1xuICAgIHRoaXMuaXRlbXNTZWxlY3RlZC5jbGVhcigpO1xuICAgIHRoaXMuZmlsdGVyZWRJdGVtcy5mb3JFYWNoKGl0ZW0gPT4gdGhpcy5vbkNoYW5nZUl0ZW0oY2hlY2tlZCwgaXRlbSkpO1xuICB9XG5cbiAgbmdPbkluaXQoKSB7XG4gICAgaWYgKHRoaXMudXBkYXRlSXRlbXMpIHtcbiAgICAgIHRoaXMudXBkYXRlSXRlbXMuc3Vic2NyaWJlKCgpID0+IHtcbiAgICAgICAgdGhpcy51cGRhdGVTZWxlY3RlZCgpO1xuICAgICAgICB0aGlzLnVwZGF0ZUxhYmVsKCk7XG4gICAgICAgIHRoaXMuc2hvd0FsbExhYmVsID0gdGhpcy5pc0FsbEl0ZW1zU2VsZWN0ZWQoKTtcbiAgICAgIH0pO1xuICAgIH1cbiAgfVxuXG4gIG9uQ2hhbmdlSXRlbShjaGVja2VkOiBib29sZWFuLCBpdGVtOiBJdGVtKSB7XG4gICAgaWYgKGNoZWNrZWQpIHtcbiAgICAgIHRoaXMuaXRlbXNTZWxlY3RlZC5hZGQoaXRlbSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuaXRlbXNTZWxlY3RlZC5kZWxldGUoaXRlbSk7XG4gICAgfVxuICB9XG5cbiAgZGVzZWxlY3RJdGVtKGl0ZW06IEl0ZW0pIHtcbiAgICB0aGlzLml0ZW1zU2VsZWN0ZWQuZGVsZXRlKGl0ZW0pO1xuICAgIGNvbnN0IHNlbGVjdGVkID0gQXJyYXkuZnJvbSh0aGlzLml0ZW1zU2VsZWN0ZWQudmFsdWVzKCkpO1xuICAgIHRoaXMub25DaGFuZ2UuZW1pdChzZWxlY3RlZCk7XG4gIH1cblxuICB1cGRhdGVGaWx0ZXJlZCh0ZXJtOiBzdHJpbmcpIHtcbiAgICBpZiAodGVybSkge1xuICAgICAgY29uc3Qgc2VhcmNoID0gbmV3IFJlZ0V4cCh0ZXJtLCAnaScpO1xuICAgICAgdGhpcy5maWx0ZXJlZEl0ZW1zID0gdGhpcy5pdGVtcy5maWx0ZXIoKHsgbmFtZSB9KSA9PiBzZWFyY2gudGVzdChuYW1lKSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuZmlsdGVyZWRJdGVtcyA9IHRoaXMuaXRlbXM7XG4gICAgfVxuICB9XG5cbiAgZ2V0U2VsZWN0QWxsVG9nZ2xlU3RhdHVzKCkge1xuICAgIGNvbnN0IGxhYmVsID0gdGhpcy5nZXRMYWJlbCgpO1xuICAgIGNvbnN0IGNoZWNrZWQgPSB0aGlzLmlzQWxsU2VsZWN0ZWQoKTtcbiAgICBjb25zdCBpbmRldGVybWluYXRlID0gIWNoZWNrZWQgJiYgdGhpcy5pdGVtc1NlbGVjdGVkLnNpemUgPiAwO1xuXG4gICAgcmV0dXJuIHsgbGFiZWwsIGNoZWNrZWQsIGluZGV0ZXJtaW5hdGUgfTtcbiAgfVxuICBuZ09uQ2hhbmdlcyhjaGFuZ2VzOiBTaW1wbGVDaGFuZ2VzKSB7XG4gICAgaWYgKHRoaXMuaXNPcGVuKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGlmIChjaGFuZ2VzLml0ZW1zIHx8IGNoYW5nZXMuc2VsZWN0ZWQgfHwgY2hhbmdlcy5hcHBseUxhYmVsKSB7XG4gICAgICB0aGlzLnVwZGF0ZVNlbGVjdGVkKCk7XG4gICAgICB0aGlzLnVwZGF0ZUxhYmVsKCk7XG4gICAgICB0aGlzLnNob3dBbGxMYWJlbCA9IHRoaXMuaXNBbGxJdGVtc1NlbGVjdGVkKCk7XG4gICAgfVxuICB9XG5cbiAgbmdPbkRlc3Ryb3koKSB7XG4gICAgaWYgKHRoaXMudXBkYXRlSXRlbXMgJiYgIXRoaXMudXBkYXRlSXRlbXMuY2xvc2VkKSB7XG4gICAgICB0aGlzLnVwZGF0ZUl0ZW1zLnVuc3Vic2NyaWJlKCk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSB1cGRhdGVMYWJlbCgpIHtcbiAgICBjb25zdCBvdXR0ZXJTZWxlY3RlZCA9IHRoaXMuaXRlbXMuZmlsdGVyKGkgPT4gdGhpcy5vdXR0ZXJTZWxlY3RlZChpKSk7XG4gICAgaWYgKHR5cGVvZiB0aGlzLnNlbGVjdGVkTGFiZWwgPT09ICdzdHJpbmcnKSB7XG4gICAgICBjb25zdCBpdGVtTmFtZSA9IHRoaXMucHJvcGVydHlWYWx1ZVRyYW5zZm9ybVNlcnZpY2UuZ2V0TmFtZSh7IG5hbWU6IHRoaXMuc2VsZWN0ZWRMYWJlbCB9KTtcbiAgICAgIHRoaXMubGFiZWxUZXh0ID0gaXRlbU5hbWUgJiYgdGhpcy50cmFuc2xhdGVTZXJ2aWNlLmluc3RhbnQoaXRlbU5hbWUpO1xuICAgIH0gZWxzZSBpZiAodHlwZW9mIHRoaXMuc2VsZWN0ZWRMYWJlbCA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgY29uc3QgaXRlbU5hbWUgPSB0aGlzLnByb3BlcnR5VmFsdWVUcmFuc2Zvcm1TZXJ2aWNlLmdldE5hbWUoe1xuICAgICAgICBuYW1lOiB0aGlzLnNlbGVjdGVkTGFiZWwob3V0dGVyU2VsZWN0ZWQpXG4gICAgICB9KTtcbiAgICAgIHRoaXMubGFiZWxUZXh0ID0gaXRlbU5hbWUgJiYgdGhpcy50cmFuc2xhdGVTZXJ2aWNlLmluc3RhbnQoaXRlbU5hbWUpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLmxhYmVsVGV4dCA9IG91dHRlclNlbGVjdGVkXG4gICAgICAgIC5tYXAoKHsgbmFtZSB9KSA9PiB7XG4gICAgICAgICAgY29uc3QgaXRlbU5hbWUgPSB0aGlzLnByb3BlcnR5VmFsdWVUcmFuc2Zvcm1TZXJ2aWNlLmdldE5hbWUoeyBuYW1lIH0pO1xuICAgICAgICAgIHJldHVybiBpdGVtTmFtZSAmJiB0aGlzLnRyYW5zbGF0ZVNlcnZpY2UuaW5zdGFudChpdGVtTmFtZSk7XG4gICAgICAgIH0pXG4gICAgICAgIC5qb2luKCcsICcpO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgdXBkYXRlU2VsZWN0ZWQoKSB7XG4gICAgY29uc3QgeyBpdGVtc1NlbGVjdGVkLCBpdGVtcyB9ID0gdGhpcztcbiAgICBpdGVtc1NlbGVjdGVkLmNsZWFyKCk7XG4gICAgaXRlbXMuZm9yRWFjaChpdGVtID0+IHtcbiAgICAgIGlmICh0aGlzLm91dHRlclNlbGVjdGVkKGl0ZW0pKSB7XG4gICAgICAgIGl0ZW1zU2VsZWN0ZWQuYWRkKGl0ZW0pO1xuICAgICAgfVxuICAgIH0pO1xuICAgIHRoaXMuZmlsdGVyZWRJdGVtcyA9IGl0ZW1zO1xuICB9XG5cbiAgcHJpdmF0ZSBpc0FsbFNlbGVjdGVkKCkge1xuICAgIGlmICh0aGlzLmdldExhYmVsKCkgPT09IHRoaXMubGFiZWxzRm9yU2VsZWN0QWxsLmFsbEZpbHRlcmVkKSB7XG4gICAgICByZXR1cm4gdGhpcy5pc0FsbEZpbHRlcmVkU2VsZWN0ZWQoKTtcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIHRoaXMuaXNBbGxJdGVtc1NlbGVjdGVkKCk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBnZXRMYWJlbCgpIHtcbiAgICByZXR1cm4gdGhpcy5zZWFyY2hGaWx0ZXIgPyB0aGlzLmxhYmVsc0ZvclNlbGVjdEFsbC5hbGxGaWx0ZXJlZCA6IHRoaXMubGFiZWxzRm9yU2VsZWN0QWxsLmFsbDtcbiAgfVxufVxuIiwiPGRpdlxuICBjbGFzcz1cImRyb3Bkb3duIGZpdC13XCJcbiAgY29udGFpbmVyPVwie3sgYWRkRHJvcGRvd25Db250YWluZXJUb0JvZHkgPyAnYm9keScgOiBudWxsIH19XCJcbiAgKGlzT3BlbkNoYW5nZSk9XCJpc09wZW5DaGFuZ2UoJGV2ZW50KVwiXG4gIGRyb3Bkb3duXG4gICNkcm9wZG93bj1cImJzLWRyb3Bkb3duXCJcbiAgYzh5RHJvcGRvd25EaXJlY3Rpb25cbiAgcHgtZXZlbnQ9XCJTZWxlY3QgdHlwZVwiXG4gIFtpbnNpZGVDbGlja109XCJ0cnVlXCJcbj5cbiAgPGRpdiBjbGFzcz1cImlucHV0LWdyb3VwIGRyb3Bkb3duLXRvZ2dsZVwiPlxuICAgIDxkaXZcbiAgICAgIGNsYXNzPVwiZm9ybS1jb250cm9sIHBvaW50ZXIgZC1mbGV4IGlubmVyLXNjcm9sbFwiXG4gICAgICAoY2xpY2spPVwiZHJvcGRvd24uaXNPcGVuID0gIWRyb3Bkb3duLmlzT3BlblwiXG4gICAgPlxuICAgICAgPG5nLWNvbnRhaW5lciAqbmdJZj1cIml0ZW1zU2VsZWN0ZWQuc2l6ZSAhPT0gaXRlbXMubGVuZ3RoOyBlbHNlIGFsbFwiPlxuICAgICAgICA8ZW1cbiAgICAgICAgICBjbGFzcz1cInRleHQtbXV0ZWRcIlxuICAgICAgICAgICpuZ0lmPVwiaXRlbXNTZWxlY3RlZC5zaXplID09PSAwXCJcbiAgICAgICAgPlxuICAgICAgICAgIHt7IHBsYWNlaG9sZGVyIHwgdHJhbnNsYXRlIH19XG4gICAgICAgIDwvZW0+XG4gICAgICAgIDxzcGFuXG4gICAgICAgICAgY2xhc3M9XCJ0YWcgdGFnLS1pbmZvIGNoaXBcIlxuICAgICAgICAgICpuZ0Zvcj1cImxldCBzZWxlY3RlZEl0ZW0gb2YgaXRlbXNTZWxlY3RlZFwiXG4gICAgICAgID5cbiAgICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgICBjbGFzcz1cImJ0biBidG4teHMgYnRuLWNsZWFuIHRleHQtMTBcIlxuICAgICAgICAgICAgdGl0bGU9XCJ7eyAnUmVtb3ZlJyB8IHRyYW5zbGF0ZSB9fVwiXG4gICAgICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgICAgIChjbGljayk9XCJkZXNlbGVjdEl0ZW0oc2VsZWN0ZWRJdGVtKTsgJGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpXCJcbiAgICAgICAgICA+XG4gICAgICAgICAgICA8aSBbYzh5SWNvbl09XCIndGltZXMnXCI+PC9pPlxuICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICAgIHt7IHNlbGVjdGVkSXRlbS5uYW1lIHwgbmFtZVRyYW5zZm9ybSB8IHRyYW5zbGF0ZSB9fVxuICAgICAgICA8L3NwYW4+XG4gICAgICA8L25nLWNvbnRhaW5lcj5cbiAgICAgIDxuZy10ZW1wbGF0ZSAjYWxsPlxuICAgICAgICB7eyAnQWxsYHBvc3NpYmxlIG9wdGlvbnNgJyB8IHRyYW5zbGF0ZSB9fVxuICAgICAgPC9uZy10ZW1wbGF0ZT5cbiAgICA8L2Rpdj5cbiAgICA8ZGl2IGNsYXNzPVwiaW5wdXQtZ3JvdXAtYnRuXCI+XG4gICAgICA8YnV0dG9uXG4gICAgICAgIGNsYXNzPVwiYnRuIGJ0bi1kZWZhdWx0IGQtZmxleCBhLWktY2VudGVyIHctYXV0b1wiXG4gICAgICAgIHRpdGxlPVwie3sgbGFiZWxUZXh0IHx8IHBsYWNlaG9sZGVyIHwgdHJhbnNsYXRlIH19XCJcbiAgICAgICAgYXJpYS1oYXNwb3B1cD1cInRydWVcIlxuICAgICAgICBkcm9wZG93blRvZ2dsZVxuICAgICAgPlxuICAgICAgICA8aSBjbGFzcz1cImM4eS1nbHlwaC1jYXJldCBpY29uLTE2XCI+PC9pPlxuICAgICAgPC9idXR0b24+XG4gICAgPC9kaXY+XG4gIDwvZGl2PlxuXG4gIDx1bFxuICAgIGNsYXNzPVwiZHJvcGRvd24tbWVudSBtdWx0aXNlbGVjdC1jb250YWluZXJcIlxuICAgICpkcm9wZG93bk1lbnVcbiAgPlxuICAgIDxuZy1jb250ZW50IHNlbGVjdD1cImM4eS1saVwiPjwvbmctY29udGVudD5cbiAgICA8bmctY29udGFpbmVyICpuZ0lmPVwibGlDaGlsZHJlbi5sZW5ndGggPT09IDBcIj5cbiAgICAgIDxsaVxuICAgICAgICBjbGFzcz1cIm11bHRpc2VsZWN0LWl0ZW0gc3RpY2t5LXRvcFwiXG4gICAgICAgICpuZ0lmPVwiaXRlbXMubGVuZ3RoID4gc2l6ZVRvU2hvd0ZpbHRlclwiXG4gICAgICA+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJpbnB1dC1ncm91cCBpbnB1dC1ncm91cC1zZWFyY2hcIj5cbiAgICAgICAgICA8aW5wdXRcbiAgICAgICAgICAgIGNsYXNzPVwiZm9ybS1jb250cm9sXCJcbiAgICAgICAgICAgIHBsYWNlaG9sZGVyPVwie3sgJ0ZpbHRlcicgfCB0cmFuc2xhdGUgfX3igKZcIlxuICAgICAgICAgICAgdHlwZT1cInNlYXJjaFwiXG4gICAgICAgICAgICAoa2V5dXApPVwidXBkYXRlRmlsdGVyZWQoJGV2ZW50LnRhcmdldC52YWx1ZSlcIlxuICAgICAgICAgICAgWyhuZ01vZGVsKV09XCJzZWFyY2hGaWx0ZXJcIlxuICAgICAgICAgIC8+XG4gICAgICAgICAgPHNwYW4gY2xhc3M9XCJpbnB1dC1ncm91cC1hZGRvblwiPlxuICAgICAgICAgICAgPGlcbiAgICAgICAgICAgICAgYzh5SWNvbj1cInNlYXJjaFwiXG4gICAgICAgICAgICAgICpuZ0lmPVwiIXRleHRGaWx0ZXJcIlxuICAgICAgICAgICAgPjwvaT5cbiAgICAgICAgICAgIDxpXG4gICAgICAgICAgICAgIGNsYXNzPVwidGV4dC1tdXRlZFwiXG4gICAgICAgICAgICAgIGM4eUljb249XCJ0aW1lc1wiXG4gICAgICAgICAgICAgICpuZ0lmPVwidGV4dEZpbHRlclwiXG4gICAgICAgICAgICAgIChjbGljayk9XCJ0ZXh0RmlsdGVyID0gJydcIlxuICAgICAgICAgICAgPjwvaT5cbiAgICAgICAgICA8L3NwYW4+XG4gICAgICAgIDwvZGl2PlxuICAgICAgPC9saT5cblxuICAgICAgPGxpIGNsYXNzPVwibXVsdGlzZWxlY3QtaXRlbVwiPlxuICAgICAgICA8bGFiZWxcbiAgICAgICAgICBjbGFzcz1cImM4eS1jaGVja2JveCBpbnB1dC1zbVwiXG4gICAgICAgICAgW3RpdGxlXT1cImdldFNlbGVjdEFsbFRvZ2dsZVN0YXR1cygpLmxhYmVsIHwgdHJhbnNsYXRlXCJcbiAgICAgICAgICBuZy1jbGljaz1cInZtLnRvZ2dsZVNlbGVjdEFsbCgpOyAkZXZlbnQucHJldmVudERlZmF1bHQoKVwiXG4gICAgICAgID5cbiAgICAgICAgICA8aW5wdXRcbiAgICAgICAgICAgIGNsYXNzPVwibS10LTBcIlxuICAgICAgICAgICAgdHlwZT1cImNoZWNrYm94XCJcbiAgICAgICAgICAgIFtjaGVja2VkXT1cImdldFNlbGVjdEFsbFRvZ2dsZVN0YXR1cygpLmNoZWNrZWRcIlxuICAgICAgICAgICAgKGNoYW5nZSk9XCJzZWxlY3RBbGwoJGV2ZW50LnRhcmdldC5jaGVja2VkKVwiXG4gICAgICAgICAgICBbaW5kZXRlcm1pbmF0ZV09XCJnZXRTZWxlY3RBbGxUb2dnbGVTdGF0dXMoKS5pbmRldGVybWluYXRlXCJcbiAgICAgICAgICAvPlxuICAgICAgICAgIDxzcGFuPjwvc3Bhbj5cbiAgICAgICAgICA8c3BhbiBjbGFzcz1cImxhYmVsLXRleHRcIj5cbiAgICAgICAgICAgIHt7IGdldFNlbGVjdEFsbFRvZ2dsZVN0YXR1cygpLmxhYmVsIHwgdHJhbnNsYXRlIH19XG4gICAgICAgICAgPC9zcGFuPlxuICAgICAgICA8L2xhYmVsPlxuICAgICAgPC9saT5cblxuICAgICAgPGxpXG4gICAgICAgIGNsYXNzPVwibXVsdGlzZWxlY3QtaXRlbVwiXG4gICAgICAgICpuZ0Zvcj1cImxldCBpdGVtIG9mIGZpbHRlcmVkSXRlbXNcIlxuICAgICAgPlxuICAgICAgICA8bGFiZWxcbiAgICAgICAgICBjbGFzcz1cImM4eS1jaGVja2JveCBkLWZsZXggYS1pLWNlbnRlclwiXG4gICAgICAgICAgW3RpdGxlXT1cIml0ZW0ubmFtZSB8IG5hbWVUcmFuc2Zvcm0gfCB0cmFuc2xhdGVcIlxuICAgICAgICA+XG4gICAgICAgICAgPGlucHV0XG4gICAgICAgICAgICB0eXBlPVwiY2hlY2tib3hcIlxuICAgICAgICAgICAgW2NoZWNrZWRdPVwiaXNTZWxlY3RlZChpdGVtKVwiXG4gICAgICAgICAgICAoY2hhbmdlKT1cIm9uQ2hhbmdlSXRlbSgkZXZlbnQudGFyZ2V0LmNoZWNrZWQsIGl0ZW0pXCJcbiAgICAgICAgICAvPlxuICAgICAgICAgIDxzcGFuPjwvc3Bhbj5cbiAgICAgICAgICA8c3BhbiBjbGFzcz1cIm0tbC04XCI+e3sgaXRlbS5uYW1lIHwgbmFtZVRyYW5zZm9ybSB8IHRyYW5zbGF0ZSB9fTwvc3Bhbj5cbiAgICAgICAgPC9sYWJlbD5cbiAgICAgIDwvbGk+XG4gICAgICA8bGkgY2xhc3M9XCJkaXZpZGVyXCI+PC9saT5cbiAgICAgIDxsaSBjbGFzcz1cInN0aWNreS1ib3R0b20gYmctbGV2ZWwtMFwiPlxuICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgY2xhc3M9XCJidG4gYnRuLXByaW1hcnkgYnRuLWJsb2NrXCJcbiAgICAgICAgICB0aXRsZT1cInt7IGFwcGx5TGFiZWwgfCB0cmFuc2xhdGUgfX1cIlxuICAgICAgICAgIFtkaXNhYmxlZF09XCJkaXNhYmxlQXBwbHlPbk5vU2VsZWN0aW9uICYmIGlzTm9JdGVtU2VsZWN0ZWQoKVwiXG4gICAgICAgICAgKGNsaWNrKT1cImFwcGx5Q2hhbmdlcygpXCJcbiAgICAgICAgPlxuICAgICAgICAgIHt7IGFwcGx5TGFiZWwgfCB0cmFuc2xhdGUgfX1cbiAgICAgICAgPC9idXR0b24+XG4gICAgICA8L2xpPlxuICAgIDwvbmctY29udGFpbmVyPlxuICA8L3VsPlxuPC9kaXY+XG4iXX0=