@c8y/ngx-components
Version:
Angular modules for Cumulocity IoT applications
156 lines • 38.3 kB
JavaScript
import { Component, EventEmitter, forwardRef, Input, Output, TemplateRef } from '@angular/core';
import { assign } from 'lodash-es';
import { BsModalRef } from 'ngx-bootstrap/modal';
import { Subject } from 'rxjs';
import { debounceTime } from 'rxjs/operators';
import { gettext } from '../i18n/gettext';
import { PRODUCT_EXPERIENCE_EVENT_SOURCE } from '../product-experience/product-experience.model';
import { ModalSelectionMode } from './select-modal.model';
import * as i0 from "@angular/core";
import * as i1 from "ngx-bootstrap/modal";
import * as i2 from "../common/icon.directive";
import * as i3 from "../i18n/c8y-translate.directive";
import * as i4 from "@angular/common";
import * as i5 from "../list-group/list-group.component";
import * as i6 from "../list-group/list-item.component";
import * as i7 from "../list-group/list-item-icon.component";
import * as i8 from "../list-group/list-item-body.component";
import * as i9 from "../list-group/list-item-collapse.component";
import * as i10 from "../list-group/list-item-radio.component";
import * as i11 from "../search/highlight.component";
import * as i12 from "../forms/filter-input.component";
import * as i13 from "../product-experience/product-experience.directive";
import * as i14 from "../i18n/c8y-translate.pipe";
import * as i15 from "./select-modal-filter.pipe";
export class SelectModalComponent {
set labels(labels) {
const { ok = this.labels.ok, cancel = this.labels.cancel } = labels || {};
this._labels = { ok, cancel };
}
get labels() {
return this._labels;
}
constructor(bsModalRef) {
this.bsModalRef = bsModalRef;
this.subTitle = gettext('Select from the list of items matching the device type');
this.mode = ModalSelectionMode.MULTI;
this.disableSelected = true;
this.showFilter = true;
this.areMoreEntries = false;
this.result = new EventEmitter();
this.search = new EventEmitter();
this.onChoiceUpdated = new EventEmitter();
this.selected = false;
this.filterTerm = '';
this.listItems = [];
this.productExperienceEvent = {
eventName: undefined, // supress emitting events if a parent component does not declare event name
data: {
component: 'select-modal'
}
};
this.debouncer = new Subject();
this._labels = { ok: gettext('Confirm'), cancel: gettext('Cancel') };
this.debouncer.pipe(debounceTime(500)).subscribe(value => {
this.search.emit(value);
});
}
async ngOnChanges(changes) {
if (changes.items && changes.items.currentValue) {
const itemsPromise = changes.items.currentValue.map(async (item) => {
item.options = await item.options;
const selected = item.options.find(option => option.selected);
if (selected) {
item.selectedId = selected.obj.id;
if (this.disableSelected) {
item.options.map(option => assign(option, { disabled: true }));
}
}
return item;
});
this.listItems = await Promise.all(itemsPromise);
this.emptyItemsOnly = this.listItems.every(item => !item.options || item.options.length === 0);
}
if (changes.title && !!this.productExperienceEvent?.data) {
this.productExperienceEvent.data.title = changes.title.currentValue;
}
}
updatePipe(filterTerm) {
this.debouncer.next(filterTerm);
this.filterTerm = filterTerm;
}
updateChoice({ item, id }) {
if (this.mode === 'single') {
this.listItems.map(value => (value.selectedId = undefined));
}
item.selectedId = id;
this.selected = true;
this.onChoiceUpdated.emit(item);
}
dismiss() {
this.bsModalRef.hide();
}
select() {
this.result.emit(this.getOutput());
this.bsModalRef.hide();
}
ngOnDestroy() {
this.debouncer.complete();
this.result.complete();
this.search.complete();
}
getOutput() {
return this.listItems
.filter(item => item.selectedId)
.map(item => item.options.find(option => item.selectedId === option.obj.id))
.filter(option => !option.selected)
.map(selectedOption => selectedOption.obj);
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SelectModalComponent, deps: [{ token: i1.BsModalRef }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: SelectModalComponent, selector: "c8y-select-modal", inputs: { icon: "icon", title: "title", subTitle: "subTitle", items: "items", mode: "mode", disableSelected: "disableSelected", showFilter: "showFilter", additionalFilterTemplate: "additionalFilterTemplate", areMoreEntries: "areMoreEntries", labels: "labels", noItemsMessage: "noItemsMessage", hideEmptyItems: "hideEmptyItems" }, outputs: { result: "result", search: "search", onChoiceUpdated: "onChoiceUpdated" }, providers: [
{
provide: PRODUCT_EXPERIENCE_EVENT_SOURCE,
useExisting: forwardRef(() => SelectModalComponent)
}
], usesOnChanges: true, ngImport: i0, template: "<div class=\"viewport-modal\">\n <div class=\"modal-header dialog-header\">\n <i [c8yIcon]=\"icon\"></i>\n <h1\n class=\"h3\"\n id=\"modal-title\"\n >\n {{ title | translate }}\n </h1>\n </div>\n <div class=\"p-16 text-center separator-bottom min-height-fit\">\n <p class=\"m-b-8\">{{ subTitle | translate }}</p>\n <div class=\"row\">\n <div\n *ngIf=\"showFilter\"\n [ngClass]=\"{\n 'col-xs-6': showFilter && additionalFilterTemplate,\n 'col-xs-12': !showFilter || !additionalFilterTemplate\n }\"\n >\n <c8y-filter\n [icon]=\"'search'\"\n (onSearch)=\"updatePipe($event)\"\n ></c8y-filter>\n </div>\n <div\n *ngIf=\"additionalFilterTemplate\"\n [ngClass]=\"{\n 'col-xs-6': showFilter && additionalFilterTemplate,\n 'col-xs-12': !showFilter || !additionalFilterTemplate\n }\"\n >\n <ng-container *ngTemplateOutlet=\"additionalFilterTemplate\"></ng-container>\n </div>\n </div>\n </div>\n <div\n class=\"modal-inner-scroll\"\n id=\"modal-body\"\n >\n <div class=\"p-l-16 p-r-16\">\n <div\n class=\"panel m-t-8 m-b-8\"\n *ngIf=\"!items || items.length === 0 || (emptyItemsOnly && hideEmptyItems)\"\n >\n <div class=\"c8y-empty-state text-left\">\n <h1\n class=\"c8y-icon-duocolor\"\n c8yIcon=\"{{ icon }} \"\n ></h1>\n <p>{{ (noItemsMessage | translate) ?? 'No items to display.' | translate }}</p>\n </div>\n </div>\n </div>\n <c8y-list-group>\n <ng-container *ngFor=\"let item of listItems | selectModalFilterPipe : filterTerm\">\n <c8y-li *ngIf=\"item.options?.length > 0 || !hideEmptyItems\">\n <c8y-li-icon>\n <i c8yIcon=\"{{ icon }}\"></i>\n </c8y-li-icon>\n\n <c8y-li-body class=\"content-flex-30\">\n <div class=\"col-9\">\n <div\n *ngFor=\"let bodyPart of item.body\"\n [ngClass]=\"bodyPart.class\"\n >\n <c8y-highlight\n [title]=\"bodyPart.value\"\n [pattern]=\"filterTerm\"\n [text]=\"bodyPart.value\"\n ></c8y-highlight>\n </div>\n </div>\n\n <div\n class=\"col-3 text-right\"\n *ngIf=\"item.additionalInformation\"\n >\n <div [ngClass]=\"item.additionalInformation.class\">\n {{ item.additionalInformation.value }}\n </div>\n </div>\n </c8y-li-body>\n\n <c8y-li-collapse *ngIf=\"item.options?.length > 0\">\n <c8y-list-group>\n <c8y-li *ngFor=\"let option of item.options\">\n <c8y-li-radio\n [name]=\"mode === 'single' ? 'single' : item.groupId\"\n (onSelect)=\"updateChoice({ item: item, id: option.obj.id })\"\n [disabled]=\"option.disabled\"\n [selected]=\"option.selected\"\n ></c8y-li-radio>\n <c8y-li-body class=\"content-flex-20\">\n <div\n *ngFor=\"let optionPart of option.body; let i = index\"\n [ngClass]=\"optionPart.class\"\n >\n <c8y-highlight\n [pattern]=\"filterTerm\"\n [text]=\"optionPart.value\"\n ></c8y-highlight>\n </div>\n <ng-container\n *ngIf=\"option.template\"\n [ngTemplateOutlet]=\"option.template\"\n [ngTemplateOutletContext]=\"{ $implicit: item, option: option }\"\n ></ng-container>\n </c8y-li-body>\n </c8y-li>\n </c8y-list-group>\n </c8y-li-collapse>\n </c8y-li>\n </ng-container>\n <div *ngIf=\"areMoreEntries\">\n <div\n class=\"alert alert-info m-t-16 m-r-8 m-l-8\"\n translate\n >\n Some entries might not be shown. Try narrowing search criteria.\n </div>\n </div>\n </c8y-list-group>\n </div>\n\n <div class=\"modal-footer\">\n <button\n class=\"btn btn-default\"\n title=\"{{ labels.cancel | translate }}\"\n type=\"button\"\n data-cy=\"select-modal--Cancel-button\"\n *ngIf=\"labels.cancel\"\n (click)=\"dismiss()\"\n c8yProductExperience\n inherit\n [actionData]=\"{ result: labels.cancel }\"\n >\n {{ labels.cancel | translate }}\n </button>\n <button\n class=\"btn btn-primary\"\n title=\"{{ labels.ok | translate }}\"\n type=\"button\"\n data-cy=\"select-modal--Save-button\"\n (click)=\"select()\"\n [disabled]=\"!selected\"\n c8yProductExperience\n inherit\n [actionData]=\"{ result: labels.ok }\"\n >\n {{ labels.ok | translate }}\n </button>\n </div>\n</div>\n", dependencies: [{ kind: "directive", type: i2.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i3.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { 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.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: i5.ListGroupComponent, selector: "c8y-list-group" }, { kind: "component", type: i6.ListItemComponent, selector: "c8y-list-item, c8y-li", inputs: ["active", "highlighted", "emptyActions", "dense", "collapsed", "selectable"], outputs: ["collapsedChange"] }, { kind: "component", type: i7.ListItemIconComponent, selector: "c8y-list-item-icon, c8y-li-icon", inputs: ["icon", "status"] }, { kind: "component", type: i8.ListItemBodyComponent, selector: "c8y-list-item-body, c8y-li-body", inputs: ["body"] }, { kind: "component", type: i9.ListItemCollapseComponent, selector: "c8y-list-item-collapse, c8y-li-collapse", inputs: ["collapseWay"] }, { kind: "component", type: i10.ListItemRadioComponent, selector: "c8y-list-item-radio, c8y-li-radio", inputs: ["selected", "name", "disabled", "value"], outputs: ["onSelect"] }, { kind: "component", type: i11.HighlightComponent, selector: "c8y-highlight", inputs: ["pattern", "text", "elementClass", "shouldTrimPattern"] }, { kind: "component", type: i12.FilterInputComponent, selector: "c8y-filter", inputs: ["icon", "filterTerm"], outputs: ["onSearch"] }, { kind: "directive", type: i13.ProductExperienceDirective, selector: "[c8yProductExperience]", inputs: ["actionName", "actionData", "inherit", "suppressDataOverriding"] }, { kind: "pipe", type: i14.C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: i15.SelectModalFilterPipe, name: "selectModalFilterPipe" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SelectModalComponent, decorators: [{
type: Component,
args: [{ selector: 'c8y-select-modal', providers: [
{
provide: PRODUCT_EXPERIENCE_EVENT_SOURCE,
useExisting: forwardRef(() => SelectModalComponent)
}
], template: "<div class=\"viewport-modal\">\n <div class=\"modal-header dialog-header\">\n <i [c8yIcon]=\"icon\"></i>\n <h1\n class=\"h3\"\n id=\"modal-title\"\n >\n {{ title | translate }}\n </h1>\n </div>\n <div class=\"p-16 text-center separator-bottom min-height-fit\">\n <p class=\"m-b-8\">{{ subTitle | translate }}</p>\n <div class=\"row\">\n <div\n *ngIf=\"showFilter\"\n [ngClass]=\"{\n 'col-xs-6': showFilter && additionalFilterTemplate,\n 'col-xs-12': !showFilter || !additionalFilterTemplate\n }\"\n >\n <c8y-filter\n [icon]=\"'search'\"\n (onSearch)=\"updatePipe($event)\"\n ></c8y-filter>\n </div>\n <div\n *ngIf=\"additionalFilterTemplate\"\n [ngClass]=\"{\n 'col-xs-6': showFilter && additionalFilterTemplate,\n 'col-xs-12': !showFilter || !additionalFilterTemplate\n }\"\n >\n <ng-container *ngTemplateOutlet=\"additionalFilterTemplate\"></ng-container>\n </div>\n </div>\n </div>\n <div\n class=\"modal-inner-scroll\"\n id=\"modal-body\"\n >\n <div class=\"p-l-16 p-r-16\">\n <div\n class=\"panel m-t-8 m-b-8\"\n *ngIf=\"!items || items.length === 0 || (emptyItemsOnly && hideEmptyItems)\"\n >\n <div class=\"c8y-empty-state text-left\">\n <h1\n class=\"c8y-icon-duocolor\"\n c8yIcon=\"{{ icon }} \"\n ></h1>\n <p>{{ (noItemsMessage | translate) ?? 'No items to display.' | translate }}</p>\n </div>\n </div>\n </div>\n <c8y-list-group>\n <ng-container *ngFor=\"let item of listItems | selectModalFilterPipe : filterTerm\">\n <c8y-li *ngIf=\"item.options?.length > 0 || !hideEmptyItems\">\n <c8y-li-icon>\n <i c8yIcon=\"{{ icon }}\"></i>\n </c8y-li-icon>\n\n <c8y-li-body class=\"content-flex-30\">\n <div class=\"col-9\">\n <div\n *ngFor=\"let bodyPart of item.body\"\n [ngClass]=\"bodyPart.class\"\n >\n <c8y-highlight\n [title]=\"bodyPart.value\"\n [pattern]=\"filterTerm\"\n [text]=\"bodyPart.value\"\n ></c8y-highlight>\n </div>\n </div>\n\n <div\n class=\"col-3 text-right\"\n *ngIf=\"item.additionalInformation\"\n >\n <div [ngClass]=\"item.additionalInformation.class\">\n {{ item.additionalInformation.value }}\n </div>\n </div>\n </c8y-li-body>\n\n <c8y-li-collapse *ngIf=\"item.options?.length > 0\">\n <c8y-list-group>\n <c8y-li *ngFor=\"let option of item.options\">\n <c8y-li-radio\n [name]=\"mode === 'single' ? 'single' : item.groupId\"\n (onSelect)=\"updateChoice({ item: item, id: option.obj.id })\"\n [disabled]=\"option.disabled\"\n [selected]=\"option.selected\"\n ></c8y-li-radio>\n <c8y-li-body class=\"content-flex-20\">\n <div\n *ngFor=\"let optionPart of option.body; let i = index\"\n [ngClass]=\"optionPart.class\"\n >\n <c8y-highlight\n [pattern]=\"filterTerm\"\n [text]=\"optionPart.value\"\n ></c8y-highlight>\n </div>\n <ng-container\n *ngIf=\"option.template\"\n [ngTemplateOutlet]=\"option.template\"\n [ngTemplateOutletContext]=\"{ $implicit: item, option: option }\"\n ></ng-container>\n </c8y-li-body>\n </c8y-li>\n </c8y-list-group>\n </c8y-li-collapse>\n </c8y-li>\n </ng-container>\n <div *ngIf=\"areMoreEntries\">\n <div\n class=\"alert alert-info m-t-16 m-r-8 m-l-8\"\n translate\n >\n Some entries might not be shown. Try narrowing search criteria.\n </div>\n </div>\n </c8y-list-group>\n </div>\n\n <div class=\"modal-footer\">\n <button\n class=\"btn btn-default\"\n title=\"{{ labels.cancel | translate }}\"\n type=\"button\"\n data-cy=\"select-modal--Cancel-button\"\n *ngIf=\"labels.cancel\"\n (click)=\"dismiss()\"\n c8yProductExperience\n inherit\n [actionData]=\"{ result: labels.cancel }\"\n >\n {{ labels.cancel | translate }}\n </button>\n <button\n class=\"btn btn-primary\"\n title=\"{{ labels.ok | translate }}\"\n type=\"button\"\n data-cy=\"select-modal--Save-button\"\n (click)=\"select()\"\n [disabled]=\"!selected\"\n c8yProductExperience\n inherit\n [actionData]=\"{ result: labels.ok }\"\n >\n {{ labels.ok | translate }}\n </button>\n </div>\n</div>\n" }]
}], ctorParameters: () => [{ type: i1.BsModalRef }], propDecorators: { icon: [{
type: Input
}], title: [{
type: Input
}], subTitle: [{
type: Input
}], items: [{
type: Input
}], mode: [{
type: Input
}], disableSelected: [{
type: Input
}], showFilter: [{
type: Input
}], additionalFilterTemplate: [{
type: Input
}], areMoreEntries: [{
type: Input
}], labels: [{
type: Input
}], noItemsMessage: [{
type: Input
}], hideEmptyItems: [{
type: Input
}], result: [{
type: Output
}], search: [{
type: Output
}], onChoiceUpdated: [{
type: Output
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VsZWN0LW1vZGFsLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL2NvcmUvc2VsZWN0LW1vZGFsL3NlbGVjdC1tb2RhbC5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi9jb3JlL3NlbGVjdC1tb2RhbC9zZWxlY3QtbW9kYWwuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUNMLFNBQVMsRUFDVCxZQUFZLEVBQ1osVUFBVSxFQUNWLEtBQUssRUFDTCxNQUFNLEVBRU4sV0FBVyxFQUNaLE1BQU0sZUFBZSxDQUFDO0FBRXZCLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFDbkMsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQ2pELE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDL0IsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQzlDLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUMxQyxPQUFPLEVBR0wsK0JBQStCLEVBQ2hDLE1BQU0sZ0RBQWdELENBQUM7QUFDeEQsT0FBTyxFQUFtQyxrQkFBa0IsRUFBRSxNQUFNLHNCQUFzQixDQUFDOzs7Ozs7Ozs7Ozs7Ozs7OztBQWlCM0YsTUFBTSxPQUFPLG9CQUFvQjtJQVUvQixJQUFhLE1BQU0sQ0FBQyxNQUFtQjtRQUNyQyxNQUFNLEVBQUUsRUFBRSxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsRUFBRSxFQUFFLE1BQU0sR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLE1BQU0sRUFBRSxHQUFHLE1BQU0sSUFBSSxFQUFFLENBQUM7UUFDMUUsSUFBSSxDQUFDLE9BQU8sR0FBRyxFQUFFLEVBQUUsRUFBRSxNQUFNLEVBQUUsQ0FBQztJQUNoQyxDQUFDO0lBQ0QsSUFBSSxNQUFNO1FBQ1IsT0FBTyxJQUFJLENBQUMs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ZixNQUFNO2dCQUNHLGVBQWU7c0JBQXhCLE1BQU0iLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBDb21wb25lbnQsXG4gIEV2ZW50RW1pdHRlcixcbiAgZm9yd2FyZFJlZixcbiAgSW5wdXQsXG4gIE91dHB1dCxcbiAgU2ltcGxlQ2hhbmdlcyxcbiAgVGVtcGxhdGVSZWZcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBJSWRlbnRpZmllZCB9IGZyb20gJ0BjOHkvY2xpZW50JztcbmltcG9ydCB7IGFzc2lnbiB9IGZyb20gJ2xvZGFzaC1lcyc7XG5pbXBvcnQgeyBCc01vZGFsUmVmIH0gZnJvbSAnbmd4LWJvb3RzdHJhcC9tb2RhbCc7XG5pbXBvcnQgeyBTdWJqZWN0IH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyBkZWJvdW5jZVRpbWUgfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5pbXBvcnQgeyBnZXR0ZXh0IH0gZnJvbSAnLi4vaTE4bi9nZXR0ZXh0JztcbmltcG9ydCB7XG4gIFByb2R1Y3RFeHBlcmllbmNlRXZlbnQsXG4gIFByb2R1Y3RFeHBlcmllbmNlRXZlbnRTb3VyY2UsXG4gIFBST0RVQ1RfRVhQRVJJRU5DRV9FVkVOVF9TT1VSQ0Vcbn0gZnJvbSAnLi4vcHJvZHVjdC1leHBlcmllbmNlL3Byb2R1Y3QtZXhwZXJpZW5jZS5tb2RlbCc7XG5pbXBvcnQgeyBJU2VsZWN0TW9kYWxPYmplY3QsIE1vZGFsTGFiZWxzLCBNb2RhbFNlbGVjdGlvbk1vZGUgfSBmcm9tICcuL3NlbGVjdC1tb2RhbC5tb2RlbCc7XG5pbXBvcnQgeyBTdXBwb3J0ZWRJY29uc1N1Z2dlc3Rpb25zIH0gZnJvbSAnQGM4eS9uZ3gtY29tcG9uZW50cy9pY29uLXNlbGVjdG9yL2ljb25zJztcblxuaW50ZXJmYWNlIElTZWxlY3RNb2RhbEludGVybmFsT2JqZWN0IGV4dGVuZHMgSVNlbGVjdE1vZGFsT2JqZWN0IHtcbiAgc2VsZWN0ZWRJZDogc3RyaW5nIHwgbnVtYmVyO1xufVxuXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICdjOHktc2VsZWN0LW1vZGFsJyxcbiAgdGVtcGxhdGVVcmw6ICcuL3NlbGVjdC1tb2RhbC5jb21wb25lbnQuaHRtbCcsXG4gIHByb3ZpZGVyczogW1xuICAgIHtcbiAgICAgIHByb3ZpZGU6IFBST0RVQ1RfRVhQRVJJRU5DRV9FVkVOVF9TT1VSQ0UsXG4gICAgICB1c2VFeGlzdGluZzogZm9yd2FyZFJlZigoKSA9PiBTZWxlY3RNb2RhbENvbXBvbmVudClcbiAgICB9XG4gIF1cbn0pXG5leHBvcnQgY2xhc3MgU2VsZWN0TW9kYWxDb21wb25lbnQgaW1wbGVtZW50cyBQcm9kdWN0RXhwZXJpZW5jZUV2ZW50U291cmNlIHtcbiAgQElucHV0KCkgaWNvbjogU3VwcG9ydGVkSWNvbnNTdWdnZXN0aW9ucztcbiAgQElucHV0KCkgdGl0bGU6IHN0cmluZztcbiAgQElucHV0KCkgc3ViVGl0bGU6IHN0cmluZyA9IGdldHRleHQoJ1NlbGVjdCBmcm9tIHRoZSBsaXN0IG9mIGl0ZW1zIG1hdGNoaW5nIHRoZSBkZXZpY2UgdHlwZScpO1xuICBASW5wdXQoKSBpdGVtczogSVNlbGVjdE1vZGFsSW50ZXJuYWxPYmplY3RbXTtcbiAgQElucHV0KCkgbW9kZTogTW9kYWxTZWxlY3Rpb25Nb2RlID0gTW9kYWxTZWxlY3Rpb25Nb2RlLk1VTFRJO1xuICBASW5wdXQoKSBkaXNhYmxlU2VsZWN0ZWQgPSB0cnVlO1xuICBASW5wdXQoKSBzaG93RmlsdGVyID0gdHJ1ZTtcbiAgQElucHV0KCkgYWRkaXRpb25hbEZpbHRlclRlbXBsYXRlOiBUZW1wbGF0ZVJlZjxhbnk+O1xuICBASW5wdXQoKSBhcmVNb3JlRW50cmllcyA9IGZhbHNlO1xuICBASW5wdXQoKSBzZXQgbGFiZWxzKGxhYmVsczogTW9kYWxMYWJlbHMpIHtcbiAgICBjb25zdCB7IG9rID0gdGhpcy5sYWJlbHMub2ssIGNhbmNlbCA9IHRoaXMubGFiZWxzLmNhbmNlbCB9ID0gbGFiZWxzIHx8IHt9O1xuICAgIHRoaXMuX2xhYmVscyA9IHsgb2ssIGNhbmNlbCB9O1xuICB9XG4gIGdldCBsYWJlbHMoKTogTW9kYWxMYWJlbHMge1xuICAgIHJldHVybiB0aGlzLl9sYWJlbHM7XG4gIH1cbiAgQElucHV0KCkgbm9JdGVtc01lc3NhZ2U6IHN0cmluZztcbiAgQElucHV0KCkgaGlkZUVtcHR5SXRlbXM6IGJvb2xlYW47XG4gIEBPdXRwdXQoKSByZXN1bHQ6IEV2ZW50RW1pdHRlcjxJSWRlbnRpZmllZFtdPiA9IG5ldyBFdmVudEVtaXR0ZXI8SUlkZW50aWZpZWRbXT4oKTtcbiAgQE91dHB1dCgpIHNlYXJjaDogRXZlbnRFbWl0dGVyPHN0cmluZz4gPSBuZXcgRXZlbnRFbWl0dGVyPHN0cmluZz4oKTtcbiAgQE91dHB1dCgpIG9uQ2hvaWNlVXBkYXRlZDogRXZlbnRFbWl0dGVyPElJZGVudGlmaWVkPiA9IG5ldyBFdmVudEVtaXR0ZXI8SUlkZW50aWZpZWQ+KCk7XG4gIHNlbGVjdGVkID0gZmFsc2U7XG4gIGZpbHRlclRlcm0gPSAnJztcbiAgbGlzdEl0ZW1zOiBJU2VsZWN0TW9kYWxJbnRlcm5hbE9iamVjdFtdID0gW107XG4gIHByb2R1Y3RFeHBlcmllbmNlRXZlbnQ6IFByb2R1Y3RFeHBlcmllbmNlRXZlbnQgPSB7XG4gICAgZXZlbnROYW1lOiB1bmRlZmluZWQsIC8vIHN1cHJlc3MgZW1pdHRpbmcgZXZlbnRzIGlmIGEgcGFyZW50IGNvbXBvbmVudCBkb2VzIG5vdCBkZWNsYXJlIGV2ZW50IG5hbWVcbiAgICBkYXRhOiB7XG4gICAgICBjb21wb25lbnQ6ICdzZWxlY3QtbW9kYWwnXG4gICAgfVxuICB9O1xuICBlbXB0eUl0ZW1zT25seTogYm9vbGVhbjtcbiAgcHJpdmF0ZSBkZWJvdW5jZXI6IFN1YmplY3Q8c3RyaW5nPiA9IG5ldyBTdWJqZWN0PHN0cmluZz4oKTtcbiAgcHJpdmF0ZSBfbGFiZWxzOiBNb2RhbExhYmVscyA9IHsgb2s6IGdldHRleHQoJ0NvbmZpcm0nKSwgY2FuY2VsOiBnZXR0ZXh0KCdDYW5jZWwnKSB9O1xuXG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgYnNNb2RhbFJlZjogQnNNb2RhbFJlZikge1xuICAgIHRoaXMuZGVib3VuY2VyLnBpcGUoZGVib3VuY2VUaW1lKDUwMCkpLnN1YnNjcmliZSh2YWx1ZSA9PiB7XG4gICAgICB0aGlzLnNlYXJjaC5lbWl0KHZhbHVlKTtcbiAgICB9KTtcbiAgfVxuXG4gIGFzeW5jIG5nT25DaGFuZ2VzKGNoYW5nZXM6IFNpbXBsZUNoYW5nZXMpIHtcbiAgICBpZiAoY2hhbmdlcy5pdGVtcyAmJiBjaGFuZ2VzLml0ZW1zLmN1cnJlbnRWYWx1ZSkge1xuICAgICAgY29uc3QgaXRlbXNQcm9taXNlID0gY2hhbmdlcy5pdGVtcy5jdXJyZW50VmFsdWUubWFwKGFzeW5jIGl0ZW0gPT4ge1xuICAgICAgICBpdGVtLm9wdGlvbnMgPSBhd2FpdCBpdGVtLm9wdGlvbnM7XG4gICAgICAgIGNvbnN0IHNlbGVjdGVkID0gaXRlbS5vcHRpb25zLmZpbmQob3B0aW9uID0+IG9wdGlvbi5zZWxlY3RlZCk7XG4gICAgICAgIGlmIChzZWxlY3RlZCkge1xuICAgICAgICAgIGl0ZW0uc2VsZWN0ZWRJZCA9IHNlbGVjdGVkLm9iai5pZDtcbiAgICAgICAgICBpZiAodGhpcy5kaXNhYmxlU2VsZWN0ZWQpIHtcbiAgICAgICAgICAgIGl0ZW0ub3B0aW9ucy5tYXAob3B0aW9uID0+IGFzc2lnbihvcHRpb24sIHsgZGlzYWJsZWQ6IHRydWUgfSkpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gaXRlbTtcbiAgICAgIH0pO1xuICAgICAgdGhpcy5saXN0SXRlbXMgPSBhd2FpdCBQcm9taXNlLmFsbChpdGVtc1Byb21pc2UpO1xuICAgICAgdGhpcy5lbXB0eUl0ZW1zT25seSA9IHRoaXMubGlzdEl0ZW1zLmV2ZXJ5KFxuICAgICAgICBpdGVtID0+ICFpdGVtLm9wdGlvbnMgfHwgaXRlbS5vcHRpb25zLmxlbmd0aCA9PT0gMFxuICAgICAgKTtcbiAgICB9XG4gICAgaWYgKGNoYW5nZXMudGl0bGUgJiYgISF0aGlzLnByb2R1Y3RFeHBlcmllbmNlRXZlbnQ/LmRhdGEpIHtcbiAgICAgIHRoaXMucHJvZHVjdEV4cGVyaWVuY2VFdmVudC5kYXRhLnRpdGxlID0gY2hhbmdlcy50aXRsZS5jdXJyZW50VmFsdWU7XG4gICAgfVxuICB9XG5cbiAgdXBkYXRlUGlwZShmaWx0ZXJUZXJtOiBzdHJpbmcpIHtcbiAgICB0aGlzLmRlYm91bmNlci5uZXh0KGZpbHRlclRlcm0pO1xuICAgIHRoaXMuZmlsdGVyVGVybSA9IGZpbHRlclRlcm07XG4gIH1cblxuICB1cGRhdGVDaG9pY2UoeyBpdGVtLCBpZCB9KSB7XG4gICAgaWYgKHRoaXMubW9kZSA9PT0gJ3NpbmdsZScpIHtcbiAgICAgIHRoaXMubGlzdEl0ZW1zLm1hcCh2YWx1ZSA9PiAodmFsdWUuc2VsZWN0ZWRJZCA9IHVuZGVmaW5lZCkpO1xuICAgIH1cbiAgICBpdGVtLnNlbGVjdGVkSWQgPSBpZDtcbiAgICB0aGlzLnNlbGVjdGVkID0gdHJ1ZTtcbiAgICB0aGlzLm9uQ2hvaWNlVXBkYXRlZC5lbWl0KGl0ZW0pO1xuICB9XG5cbiAgZGlzbWlzcygpIHtcbiAgICB0aGlzLmJzTW9kYWxSZWYuaGlkZSgpO1xuICB9XG5cbiAgc2VsZWN0KCkge1xuICAgIHRoaXMucmVzdWx0LmVtaXQodGhpcy5nZXRPdXRwdXQoKSk7XG4gICAgdGhpcy5ic01vZGFsUmVmLmhpZGUoKTtcbiAgfVxuXG4gIG5nT25EZXN0cm95KCkge1xuICAgIHRoaXMuZGVib3VuY2VyLmNvbXBsZXRlKCk7XG4gICAgdGhpcy5yZXN1bHQuY29tcGxldGUoKTtcbiAgICB0aGlzLnNlYXJjaC5jb21wbGV0ZSgpO1xuICB9XG5cbiAgcHJpdmF0ZSBnZXRPdXRwdXQoKTogSUlkZW50aWZpZWRbXSB7XG4gICAgcmV0dXJuIHRoaXMubGlzdEl0ZW1zXG4gICAgICAuZmlsdGVyKGl0ZW0gPT4gaXRlbS5zZWxlY3RlZElkKVxuICAgICAgLm1hcChpdGVtID0+IGl0ZW0ub3B0aW9ucy5maW5kKG9wdGlvbiA9PiBpdGVtLnNlbGVjdGVkSWQgPT09IG9wdGlvbi5vYmouaWQpKVxuICAgICAgLmZpbHRlcihvcHRpb24gPT4gIW9wdGlvbi5zZWxlY3RlZClcbiAgICAgIC5tYXAoc2VsZWN0ZWRPcHRpb24gPT4gc2VsZWN0ZWRPcHRpb24ub2JqKTtcbiAgfVxufVxuIiwiPGRpdiBjbGFzcz1cInZpZXdwb3J0LW1vZGFsXCI+XG4gIDxkaXYgY2xhc3M9XCJtb2RhbC1oZWFkZXIgZGlhbG9nLWhlYWRlclwiPlxuICAgIDxpIFtjOHlJY29uXT1cImljb25cIj48L2k+XG4gICAgPGgxXG4gICAgICBjbGFzcz1cImgzXCJcbiAgICAgIGlkPVwibW9kYWwtdGl0bGVcIlxuICAgID5cbiAgICAgIHt7IHRpdGxlIHwgdHJhbnNsYXRlIH19XG4gICAgPC9oMT5cbiAgPC9kaXY+XG4gIDxkaXYgY2xhc3M9XCJwLTE2IHRleHQtY2VudGVyIHNlcGFyYXRvci1ib3R0b20gbWluLWhlaWdodC1maXRcIj5cbiAgICA8cCBjbGFzcz1cIm0tYi04XCI+e3sgc3ViVGl0bGUgfCB0cmFuc2xhdGUgfX08L3A+XG4gICAgPGRpdiBjbGFzcz1cInJvd1wiPlxuICAgICAgPGRpdlxuICAgICAgICAqbmdJZj1cInNob3dGaWx0ZXJcIlxuICAgICAgICBbbmdDbGFzc109XCJ7XG4gICAgICAgICAgJ2NvbC14cy02Jzogc2hvd0ZpbHRlciAmJiBhZGRpdGlvbmFsRmlsdGVyVGVtcGxhdGUsXG4gICAgICAgICAgJ2NvbC14cy0xMic6ICFzaG93RmlsdGVyIHx8ICFhZGRpdGlvbmFsRmlsdGVyVGVtcGxhdGVcbiAgICAgICAgfVwiXG4gICAgICA+XG4gICAgICAgIDxjOHktZmlsdGVyXG4gICAgICAgICAgW2ljb25dPVwiJ3NlYXJjaCdcIlxuICAgICAgICAgIChvblNlYXJjaCk9XCJ1cGRhdGVQaXBlKCRldmVudClcIlxuICAgICAgICA+PC9jOHktZmlsdGVyPlxuICAgICAgPC9kaXY+XG4gICAgICA8ZGl2XG4gICAgICAgICpuZ0lmPVwiYWRkaXRpb25hbEZpbHRlclRlbXBsYXRlXCJcbiAgICAgICAgW25nQ2xhc3NdPVwie1xuICAgICAgICAgICdjb2wteHMtNic6IHNob3dGaWx0ZXIgJiYgYWRkaXRpb25hbEZpbHRlclRlbXBsYXRlLFxuICAgICAgICAgICdjb2wteHMtMTInOiAhc2hvd0ZpbHRlciB8fCAhYWRkaXRpb25hbEZpbHRlclRlbXBsYXRlXG4gICAgICAgIH1cIlxuICAgICAgPlxuICAgICAgICA8bmctY29udGFpbmVyICpuZ1RlbXBsYXRlT3V0bGV0PVwiYWRkaXRpb25hbEZpbHRlclRlbXBsYXRlXCI+PC9uZy1jb250YWluZXI+XG4gICAgICA8L2Rpdj5cbiAgICA8L2Rpdj5cbiAgPC9kaXY+XG4gIDxkaXZcbiAgICBjbGFzcz1cIm1vZGFsLWlubmVyLXNjcm9sbFwiXG4gICAgaWQ9XCJtb2RhbC1ib2R5XCJcbiAgPlxuICAgIDxkaXYgY2xhc3M9XCJwLWwtMTYgcC1yLTE2XCI+XG4gICAgICA8ZGl2XG4gICAgICAgIGNsYXNzPVwicGFuZWwgbS10LTggbS1iLThcIlxuICAgICAgICAqbmdJZj1cIiFpdGVtcyB8fCBpdGVtcy5sZW5ndGggPT09IDAgfHwgKGVtcHR5SXRlbXNPbmx5ICYmIGhpZGVFbXB0eUl0ZW1zKVwiXG4gICAgICA+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJjOHktZW1wdHktc3RhdGUgdGV4dC1sZWZ0XCI+XG4gICAgICAgICAgPGgxXG4gICAgICAgICAgICBjbGFzcz1cImM4eS1pY29uLWR1b2NvbG9yXCJcbiAgICAgICAgICAgIGM4eUljb249XCJ7eyBpY29uIH19IFwiXG4gICAgICAgICAgPjwvaDE+XG4gICAgICAgICAgPHA+e3sgKG5vSXRlbXNNZXNzYWdlIHwgdHJhbnNsYXRlKSA/PyAnTm8gaXRlbXMgdG8gZGlzcGxheS4nIHwgdHJhbnNsYXRlIH19PC9wPlxuICAgICAgICA8L2Rpdj5cbiAgICAgIDwvZGl2PlxuICAgIDwvZGl2PlxuICAgIDxjOHktbGlzdC1ncm91cD5cbiAgICAgIDxuZy1jb250YWluZXIgKm5nRm9yPVwibGV0IGl0ZW0gb2YgbGlzdEl0ZW1zIHwgc2VsZWN0TW9kYWxGaWx0ZXJQaXBlIDogZmlsdGVyVGVybVwiPlxuICAgICAgICA8Yzh5LWxpICpuZ0lmPVwiaXRlbS5vcHRpb25zPy5sZW5ndGggPiAwIHx8ICFoaWRlRW1wdHlJdGVtc1wiPlxuICAgICAgICAgIDxjOHktbGktaWNvbj5cbiAgICAgICAgICAgIDxpIGM4eUljb249XCJ7eyBpY29uIH19XCI+PC9pPlxuICAgICAgICAgIDwvYzh5LWxpLWljb24+XG5cbiAgICAgICAgICA8Yzh5LWxpLWJvZHkgY2xhc3M9XCJjb250ZW50LWZsZXgtMzBcIj5cbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJjb2wtOVwiPlxuICAgICAgICAgICAgICA8ZGl2XG4gICAgICAgICAgICAgICAgKm5nRm9yPVwibGV0IGJvZHlQYXJ0IG9mIGl0ZW0uYm9keVwiXG4gICAgICAgICAgICAgICAgW25nQ2xhc3NdPVwiYm9keVBhcnQuY2xhc3NcIlxuICAgICAgICAgICAgICA+XG4gICAgICAgICAgICAgICAgPGM4eS1oaWdobGlnaHRcbiAgICAgICAgICAgICAgICAgIFt0aXRsZV09XCJib2R5UGFydC52YWx1ZVwiXG4gICAgICAgICAgICAgICAgICBbcGF0dGVybl09XCJmaWx0ZXJUZXJtXCJcbiAgICAgICAgICAgICAgICAgIFt0ZXh0XT1cImJvZHlQYXJ0LnZhbHVlXCJcbiAgICAgICAgICAgICAgICA+PC9jOHktaGlnaGxpZ2h0PlxuICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgIDwvZGl2PlxuXG4gICAgICAgICAgICA8ZGl2XG4gICAgICAgICAgICAgIGNsYXNzPVwiY29sLTMgdGV4dC1yaWdodFwiXG4gICAgICAgICAgICAgICpuZ0lmPVwiaXRlbS5hZGRpdGlvbmFsSW5mb3JtYXRpb25cIlxuICAgICAgICAgICAgPlxuICAgICAgICAgICAgICA8ZGl2IFtuZ0NsYXNzXT1cIml0ZW0uYWRkaXRpb25hbEluZm9ybWF0aW9uLmNsYXNzXCI+XG4gICAgICAgICAgICAgICAge3sgaXRlbS5hZGRpdGlvbmFsSW5mb3JtYXRpb24udmFsdWUgfX1cbiAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICA8L2M4eS1saS1ib2R5PlxuXG4gICAgICAgICAgPGM4eS1saS1jb2xsYXBzZSAqbmdJZj1cIml0ZW0ub3B0aW9ucz8ubGVuZ3RoID4gMFwiPlxuICAgICAgICAgICAgPGM4eS1saXN0LWdyb3VwPlxuICAgICAgICAgICAgICA8Yzh5LWxpICpuZ0Zvcj1cImxldCBvcHRpb24gb2YgaXRlbS5vcHRpb25zXCI+XG4gICAgICAgICAgICAgICAgPGM4eS1saS1yYWRpb1xuICAgICAgICAgICAgICAgICAgW25hbWVdPVwibW9kZSA9PT0gJ3NpbmdsZScgPyAnc2luZ2xlJyA6IGl0ZW0uZ3JvdXBJZFwiXG4gICAgICAgICAgICAgICAgICAob25TZWxlY3QpPVwidXBkYXRlQ2hvaWNlKHsgaXRlbTogaXRlbSwgaWQ6IG9wdGlvbi5vYmouaWQgfSlcIlxuICAgICAgICAgICAgICAgICAgW2Rpc2FibGVkXT1cIm9wdGlvbi5kaXNhYmxlZFwiXG4gICAgICAgICAgICAgICAgICBbc2VsZWN0ZWRdPVwib3B0aW9uLnNlbGVjdGVkXCJcbiAgICAgICAgICAgICAgICA+PC9jOHktbGktcmFkaW8+XG4gICAgICAgICAgICAgICAgPGM4eS1saS1ib2R5IGNsYXNzPVwiY29udGVudC1mbGV4LTIwXCI+XG4gICAgICAgICAgICAgICAgICA8ZGl2XG4gICAgICAgICAgICAgICAgICAgICpuZ0Zvcj1cImxldCBvcHRpb25QYXJ0IG9mIG9wdGlvbi5ib2R5OyBsZXQgaSA9IGluZGV4XCJcbiAgICAgICAgICAgICAgICAgICAgW25nQ2xhc3NdPVwib3B0aW9uUGFydC5jbGFzc1wiXG4gICAgICAgICAgICAgICAgICA+XG4gICAgICAgICAgICAgICAgICAgIDxjOHktaGlnaGxpZ2h0XG4gICAgICAgICAgICAgICAgICAgICAgW3BhdHRlcm5dPVwiZmlsdGVyVGVybVwiXG4gICAgICAgICAgICAgICAgICAgICAgW3RleHRdPVwib3B0aW9uUGFydC52YWx1ZVwiXG4gICAgICAgICAgICAgICAgICAgID48L2M4eS1oaWdobGlnaHQ+XG4gICAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgICAgIDxuZy1jb250YWluZXJcbiAgICAgICAgICAgICAgICAgICAgKm5nSWY9XCJvcHRpb24udGVtcGxhdGVcIlxuICAgICAgICAgICAgICAgICAgICBbbmdUZW1wbGF0ZU91dGxldF09XCJvcHRpb24udGVtcGxhdGVcIlxuICAgICAgICAgICAgICAgICAgICBbbmdUZW1wbGF0ZU91dGxldENvbnRleHRdPVwieyAkaW1wbGljaXQ6IGl0ZW0sIG9wdGlvbjogb3B0aW9uIH1cIlxuICAgICAgICAgICAgICAgICAgPjwvbmctY29udGFpbmVyPlxuICAgICAgICAgICAgICAgIDwvYzh5LWxpLWJvZHk+XG4gICAgICAgICAgICAgIDwvYzh5LWxpPlxuICAgICAgICAgICAgPC9jOHktbGlzdC1ncm91cD5cbiAgICAgICAgICA8L2M4eS1saS1jb2xsYXBzZT5cbiAgICAgICAgPC9jOHktbGk+XG4gICAgICA8L25nLWNvbnRhaW5lcj5cbiAgICAgIDxkaXYgKm5nSWY9XCJhcmVNb3JlRW50cmllc1wiPlxuICAgICAgICA8ZGl2XG4gICAgICAgICAgY2xhc3M9XCJhbGVydCBhbGVydC1pbmZvIG0tdC0xNiBtLXItOCBtLWwtOFwiXG4gICAgICAgICAgdHJhbnNsYXRlXG4gICAgICAgID5cbiAgICAgICAgICBTb21lIGVudHJpZXMgbWlnaHQgbm90IGJlIHNob3duLiBUcnkgbmFycm93aW5nIHNlYXJjaCBjcml0ZXJpYS5cbiAgICAgICAgPC9kaXY+XG4gICAgICA8L2Rpdj5cbiAgICA8L2M4eS1saXN0LWdyb3VwPlxuICA8L2Rpdj5cblxuICA8ZGl2IGNsYXNzPVwibW9kYWwtZm9vdGVyXCI+XG4gICAgPGJ1dHRvblxuICAgICAgY2xhc3M9XCJidG4gYnRuLWRlZmF1bHRcIlxuICAgICAgdGl0bGU9XCJ7eyBsYWJlbHMuY2FuY2VsIHwgdHJhbnNsYXRlIH19XCJcbiAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgZGF0YS1jeT1cInNlbGVjdC1tb2RhbC0tQ2FuY2VsLWJ1dHRvblwiXG4gICAgICAqbmdJZj1cImxhYmVscy5jYW5jZWxcIlxuICAgICAgKGNsaWNrKT1cImRpc21pc3MoKVwiXG4gICAgICBjOHlQcm9kdWN0RXhwZXJpZW5jZVxuICAgICAgaW5oZXJpdFxuICAgICAgW2FjdGlvbkRhdGFdPVwieyByZXN1bHQ6IGxhYmVscy5jYW5jZWwgfVwiXG4gICAgPlxuICAgICAge3sgbGFiZWxzLmNhbmNlbCB8IHRyYW5zbGF0ZSB9fVxuICAgIDwvYnV0dG9uPlxuICAgIDxidXR0b25cbiAgICAgIGNsYXNzPVwiYnRuIGJ0bi1wcmltYXJ5XCJcbiAgICAgIHRpdGxlPVwie3sgbGFiZWxzLm9rIHwgdHJhbnNsYXRlIH19XCJcbiAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgZGF0YS1jeT1cInNlbGVjdC1tb2RhbC0tU2F2ZS1idXR0b25cIlxuICAgICAgKGNsaWNrKT1cInNlbGVjdCgpXCJcbiAgICAgIFtkaXNhYmxlZF09XCIhc2VsZWN0ZWRcIlxuICAgICAgYzh5UHJvZHVjdEV4cGVyaWVuY2VcbiAgICAgIGluaGVyaXRcbiAgICAgIFthY3Rpb25EYXRhXT1cInsgcmVzdWx0OiBsYWJlbHMub2sgfVwiXG4gICAgPlxuICAgICAge3sgbGFiZWxzLm9rIHwgdHJhbnNsYXRlIH19XG4gICAgPC9idXR0b24+XG4gIDwvZGl2PlxuPC9kaXY+XG4iXX0=