@c8y/ngx-components
Version:
Angular modules for Cumulocity IoT applications
108 lines • 42.3 kB
JavaScript
import { Component, ViewChild } from '@angular/core';
import { BehaviorSubject, combineLatest } from 'rxjs';
import { InventoryService } from '@c8y/client';
import { debounceTime, distinctUntilChanged, shareReplay, switchMap, tap } from 'rxjs/operators';
import { AlertService, FilterInputComponent, GainsightService, gettext, ModalService, Permissions, Status } from '@c8y/ngx-components';
import { ContextDashboardType, ContextDashboardService, PRODUCT_EXPERIENCE } from '@c8y/ngx-components/context-dashboard';
import { TranslateService } from '@ngx-translate/core';
import { ReportDashboardService } from './report-dashboard.service';
import * as i0 from "@angular/core";
import * as i1 from "@c8y/client";
import * as i2 from "@c8y/ngx-components/context-dashboard";
import * as i3 from "@ngx-translate/core";
import * as i4 from "@c8y/ngx-components";
import * as i5 from "./report-dashboard.service";
import * as i6 from "@angular/common";
import * as i7 from "@angular/forms";
import * as i8 from "ngx-bootstrap/tooltip";
import * as i9 from "@angular/router";
import * as i10 from "ngx-bootstrap/popover";
export class ReportDashboardListComponent {
constructor(inventoryService, contextDashboardService, translateService, modal, alertService, reportDashboardService, permissions, gainsightService) {
this.inventoryService = inventoryService;
this.contextDashboardService = contextDashboardService;
this.translateService = translateService;
this.modal = modal;
this.alertService = alertService;
this.reportDashboardService = reportDashboardService;
this.permissions = permissions;
this.gainsightService = gainsightService;
this.PRODUCT_EXPERIENCE = PRODUCT_EXPERIENCE;
this.textFilter$ = new BehaviorSubject('');
this.reload$ = new BehaviorSubject(null);
this.reloading = false;
this.reports$ = combineLatest(this.textFilter$.pipe(debounceTime(400), distinctUntilChanged()), this.reload$).pipe(tap(() => {
this.reloading = true;
}), switchMap(([text]) => this.loadReports(text)), tap(() => {
this.reloading = false;
}), shareReplay(1));
this.canAddReport = false;
this.DELETED_SUCCESS_MSG = gettext('Report deleted.');
}
ngOnInit() {
this.canAddReport = this.permissions.hasAnyRole([
Permissions.ROLE_INVENTORY_CREATE,
Permissions.ROLE_INVENTORY_ADMIN,
Permissions.ROLE_MANAGED_OBJECT_ADMIN,
Permissions.ROLE_MANAGED_OBJECT_CREATE
]);
}
async loadReports(partialName) {
return partialName
? this.reportDashboardService.listReports({ filter: { name: `*${partialName}*` } })
: this.reportDashboardService.listReports();
}
async delete(report) {
try {
const dashboard = await this.contextDashboardService
.getDashboard$(`report_${report.id}`, [ContextDashboardType.Named])
.toPromise();
const isDashboardFrozen = !!dashboard?.c8y_Dashboard?.isFrozen;
const msg = isDashboardFrozen
? gettext(`You are about to delete the report "{{ reportName }}". Be aware that the report has a locked dashboard assigned. Do you want to proceed?`)
: gettext(`You are about to delete the report "{{ reportName }}". Do you want to proceed?`);
await this.modal.confirm(gettext('Delete report'), this.translateService.instant(msg, {
reportName: report.name
}), Status.DANGER, {
ok: gettext('Delete'),
cancel: gettext('Cancel')
});
await this.contextDashboardService.delete(dashboard, false);
await this.inventoryService.delete(report.id);
this.alertService.success(this.DELETED_SUCCESS_MSG);
if (report.c8y_IsNavigatorNode) {
this.reportDashboardService.removeNavigatorNode(report);
}
this.reload$.next();
this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE.DASHBOARD.EVENTS.REPORTS, {
component: PRODUCT_EXPERIENCE.DASHBOARD.COMPONENTS.REPORTS_LIST,
action: PRODUCT_EXPERIENCE.DASHBOARD.ACTIONS.DELETE,
name: report.name,
id: report.id,
context: PRODUCT_EXPERIENCE.DASHBOARD.CONTEXT.REPORT
});
}
catch (ex) {
if (ex) {
throw new Error(`Something went wrong: ${ex}`);
}
}
}
async update(report) {
report.c8y_IsNavigatorNode = report.c8y_IsNavigatorNode ? {} : null;
await this.inventoryService.update(report);
report.c8y_IsNavigatorNode
? this.contextDashboardService.addReportNavigatorNode(report)
: this.reportDashboardService.removeNavigatorNode(report);
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ReportDashboardListComponent, deps: [{ token: i1.InventoryService }, { token: i2.ContextDashboardService }, { token: i3.TranslateService }, { token: i4.ModalService }, { token: i4.AlertService }, { token: i5.ReportDashboardService }, { token: i4.Permissions }, { token: i4.GainsightService }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: ReportDashboardListComponent, selector: "c8y-report-dashboard-list", viewQueries: [{ propertyName: "filter", first: true, predicate: FilterInputComponent, descendants: true }], ngImport: i0, template: "<c8y-title>\n {{ 'Reports' | translate }}\n</c8y-title>\n\n<c8y-action-bar-item\n [placement]=\"'left'\"\n itemClass=\"navbar-form\"\n>\n <div class=\"input-group input-group-search\">\n <input\n class=\"form-control\"\n [attr.aria-label]=\"'Filter' | translate\"\n placeholder=\"{{ 'Filter\u2026' | translate }}\"\n type=\"search\"\n [ngModel]=\"textFilter$ | async\"\n (ngModelChange)=\"textFilter$.next($event)\"\n />\n <span class=\"input-group-addon\">\n <i\n c8yIcon=\"search\"\n *ngIf=\"(textFilter$ | async).length === 0\"\n ></i>\n <i\n class=\"text-muted\"\n c8yIcon=\"times\"\n *ngIf=\"(textFilter$ | async).length > 0\"\n (click)=\"textFilter$.next('')\"\n px-event=\"Clear filtering reports\"\n ></i>\n </span>\n </div>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item [placement]=\"'right'\">\n <button\n class=\"btn btn-link\"\n title=\"{{ 'Add report' | translate }}\"\n type=\"button\"\n [attr.data-cy]=\"'reports-add-report-action-bar-button'\"\n routerLink=\"/report/new-report\"\n [disabled]=\"!canAddReport\"\n >\n <i c8yIcon=\"plus-circle\"></i>\n {{ 'Add report' | translate }}\n </button>\n <button\n class=\"btn btn-dot m-r-16\"\n aria-label=\"{{ 'Info' | translate }}\"\n popover=\"{{ 'You don\\'t have permission to add reports' | translate }}\"\n placement=\"top\"\n triggers=\"focus\"\n container=\"body\"\n type=\"button\"\n *ngIf=\"!canAddReport\"\n >\n <i\n class=\"text-primary\"\n [c8yIcon]=\"'info-circle'\"\n ></i>\n </button>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item [placement]=\"'right'\">\n <button\n class=\"btn btn-link\"\n title=\"{{ 'Reload' | translate }}\"\n type=\"button\"\n (click)=\"loadReports()\"\n >\n <i\n c8yIcon=\"refresh\"\n [ngClass]=\"{ 'icon-spin': reloading }\"\n ></i>\n {{ 'Reload' | translate }}\n </button>\n</c8y-action-bar-item>\n\n<c8y-help src=\"/docs/cockpit/working-with-reports/#working-with-reports\"></c8y-help>\n\n<c8y-list-group>\n <c8y-li\n class=\"page-sticky-header hidden-xs hidden-sm\"\n *ngIf=\"(reports$ | async)?.data.length > 0\"\n >\n <c8y-li-icon>\n <i class=\"p-l-24\"></i>\n </c8y-li-icon>\n <c8y-li-body class=\"content-flex-60\">\n <div class=\"col-3\">\n {{ 'Report' | translate }}\n </div>\n <div class=\"col-6\">\n {{ 'Description' | translate }}\n </div>\n <div class=\"col-2\">\n {{ 'Show in navigator' | translate }}\n </div>\n </c8y-li-body>\n </c8y-li>\n\n <c8y-li *c8yFor=\"let report of reports$; let i = index; loadMore: 'auto'\">\n <c8y-li-icon [icon]=\"report.icon\"></c8y-li-icon>\n <c8y-li-body class=\"content-flex-60\">\n <div class=\"col-3\">\n <button\n class=\"btn-clean\"\n title=\"{{ report.name }}\"\n type=\"button\"\n routerLink=\"/reports/{{ report.id }}\"\n >\n <span class=\"text-truncate\">\n {{ report.name }}\n </span>\n </button>\n </div>\n <div class=\"col-6\">\n <p class=\"small text-truncate-wrap\">\n <em\n class=\"text-muted\"\n *ngIf=\"!report.description; else showDescription\"\n >\n {{ 'No description available' | translate }}\n </em>\n <ng-template #showDescription>\n {{ report.description }}\n </ng-template>\n </p>\n </div>\n <div class=\"col-2 fit-h-20 m-t-xs-8\">\n <label\n class=\"c8y-switch c8y-switch--inline\"\n title=\"{{ 'Show in navigator' | translate }}\"\n >\n <input\n type=\"checkbox\"\n [ngModel]=\"!!report.c8y_IsNavigatorNode\" (ngModelChange)=\"report.c8y_IsNavigatorNode = $event\"\n (change)=\"update(report)\"\n />\n <span></span>\n <span class=\"visible-xs\">\n {{ 'Show in navigator' | translate }}\n </span>\n </label>\n </div>\n <div class=\"col-1 hidden-xs\">\n <button\n class=\"btn btn-dot btn-dot--danger showOnHover m-l-auto d-flex\"\n [attr.aria-label]=\"'Remove report' | translate\"\n tooltip=\"{{ 'Remove report' | translate }}\"\n type=\"button\"\n [delay]=\"500\"\n (click)=\"delete(report)\"\n >\n <i c8yIcon=\"minus-circle\"></i>\n </button>\n </div>\n <div class=\"visible-xs p-t-8 text-right\">\n <button\n class=\"btn btn-default btn-sm\"\n title=\"{{ 'Remove report' | translate }}\"\n type=\"button\"\n (click)=\"delete(report)\"\n >\n <i c8yIcon=\"delete\"></i>\n {{ 'Remove report' | translate }}\n </button>\n </div>\n </c8y-li-body>\n </c8y-li>\n</c8y-list-group>\n\n<c8y-ui-empty-state\n [icon]=\"'c8y-reports'\"\n [title]=\"'There are no reports defined.' | translate\"\n [subtitle]=\"'Add a report first.' | translate\"\n *ngIf=\"(reports$ | async)?.data.length === 0\"\n>\n <p>\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Add report' | translate }}\"\n type=\"button\"\n [attr.data-cy]=\"'reports-add-report-empty-state-button'\"\n [disabled]=\"!canAddReport\"\n routerLink=\"/report/new-report\"\n c8yProductExperience\n [actionName]=\"PRODUCT_EXPERIENCE.DASHBOARD.EVENTS.REPORTS\"\n [actionData]=\"{ action: PRODUCT_EXPERIENCE.DASHBOARD.ACTIONS.ADD_REPORT }\"\n >\n {{ 'Add report' | translate }}\n </button>\n </p>\n <p c8y-guide-docs>\n <small\n translate\n ngNonBindable\n >\n Find out more in the\n <a c8y-guide-href=\"/docs/cockpit/working-with-reports\">user documentation</a>\n .\n </small>\n </p>\n</c8y-ui-empty-state>\n", dependencies: [{ kind: "component", type: i4.ActionBarItemComponent, selector: "c8y-action-bar-item", inputs: ["placement", "priority", "itemClass", "injector", "groupId", "inGroupPriority"] }, { kind: "component", type: i4.EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "directive", type: i4.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i4.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i6.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i6.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i4.ForOfDirective, selector: "[c8yFor]", inputs: ["c8yForOf", "c8yForLoadMore", "c8yForPipe", "c8yForNotFound", "c8yForMaxIterations", "c8yForLoadingTemplate", "c8yForLoadNextLabel", "c8yForLoadingLabel", "c8yForRealtime", "c8yForRealtimeOptions", "c8yForComparator", "c8yForEnableVirtualScroll", "c8yForVirtualScrollElementSize", "c8yForVirtualScrollStrategy", "c8yForVirtualScrollContainerHeight"], outputs: ["c8yForCount", "c8yForChange", "c8yForLoadMoreComponent"] }, { kind: "component", type: i4.TitleComponent, selector: "c8y-title", inputs: ["pageTitleUpdate"] }, { kind: "directive", type: i7.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: i7.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i7.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i7.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i4.GuideHrefDirective, selector: "[c8y-guide-href]", inputs: ["c8y-guide-href"] }, { kind: "component", type: i4.GuideDocsComponent, selector: "[c8y-guide-docs]" }, { kind: "component", type: i4.ListGroupComponent, selector: "c8y-list-group" }, { kind: "component", type: i4.ListItemComponent, selector: "c8y-list-item, c8y-li", inputs: ["active", "highlighted", "emptyActions", "dense", "collapsed", "selectable"], outputs: ["collapsedChange"] }, { kind: "component", type: i4.ListItemIconComponent, selector: "c8y-list-item-icon, c8y-li-icon", inputs: ["icon", "status"] }, { kind: "component", type: i4.ListItemBodyComponent, selector: "c8y-list-item-body, c8y-li-body", inputs: ["body"] }, { kind: "directive", type: i4.ProductExperienceDirective, selector: "[c8yProductExperience]", inputs: ["actionName", "actionData", "inherit", "suppressDataOverriding"] }, { kind: "component", type: i4.HelpComponent, selector: "c8y-help", inputs: ["src", "isCollapsed", "priority", "icon"] }, { kind: "directive", type: i8.TooltipDirective, selector: "[tooltip], [tooltipHtml]", inputs: ["adaptivePosition", "tooltip", "placement", "triggers", "container", "containerClass", "boundariesElement", "isOpen", "isDisabled", "delay", "tooltipHtml", "tooltipPlacement", "tooltipIsOpen", "tooltipEnable", "tooltipAppendToBody", "tooltipAnimation", "tooltipClass", "tooltipContext", "tooltipPopupDelay", "tooltipFadeDuration", "tooltipTrigger"], outputs: ["tooltipChange", "onShown", "onHidden", "tooltipStateChanged"], exportAs: ["bs-tooltip"] }, { kind: "directive", type: i9.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: i10.PopoverDirective, selector: "[popover]", inputs: ["adaptivePosition", "boundariesElement", "popover", "popoverContext", "popoverTitle", "placement", "outsideClick", "triggers", "container", "containerClass", "isOpen", "delay"], outputs: ["onShown", "onHidden"], exportAs: ["bs-popover"] }, { kind: "pipe", type: i4.C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: i6.AsyncPipe, name: "async" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ReportDashboardListComponent, decorators: [{
type: Component,
args: [{ selector: 'c8y-report-dashboard-list', template: "<c8y-title>\n {{ 'Reports' | translate }}\n</c8y-title>\n\n<c8y-action-bar-item\n [placement]=\"'left'\"\n itemClass=\"navbar-form\"\n>\n <div class=\"input-group input-group-search\">\n <input\n class=\"form-control\"\n [attr.aria-label]=\"'Filter' | translate\"\n placeholder=\"{{ 'Filter\u2026' | translate }}\"\n type=\"search\"\n [ngModel]=\"textFilter$ | async\"\n (ngModelChange)=\"textFilter$.next($event)\"\n />\n <span class=\"input-group-addon\">\n <i\n c8yIcon=\"search\"\n *ngIf=\"(textFilter$ | async).length === 0\"\n ></i>\n <i\n class=\"text-muted\"\n c8yIcon=\"times\"\n *ngIf=\"(textFilter$ | async).length > 0\"\n (click)=\"textFilter$.next('')\"\n px-event=\"Clear filtering reports\"\n ></i>\n </span>\n </div>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item [placement]=\"'right'\">\n <button\n class=\"btn btn-link\"\n title=\"{{ 'Add report' | translate }}\"\n type=\"button\"\n [attr.data-cy]=\"'reports-add-report-action-bar-button'\"\n routerLink=\"/report/new-report\"\n [disabled]=\"!canAddReport\"\n >\n <i c8yIcon=\"plus-circle\"></i>\n {{ 'Add report' | translate }}\n </button>\n <button\n class=\"btn btn-dot m-r-16\"\n aria-label=\"{{ 'Info' | translate }}\"\n popover=\"{{ 'You don\\'t have permission to add reports' | translate }}\"\n placement=\"top\"\n triggers=\"focus\"\n container=\"body\"\n type=\"button\"\n *ngIf=\"!canAddReport\"\n >\n <i\n class=\"text-primary\"\n [c8yIcon]=\"'info-circle'\"\n ></i>\n </button>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item [placement]=\"'right'\">\n <button\n class=\"btn btn-link\"\n title=\"{{ 'Reload' | translate }}\"\n type=\"button\"\n (click)=\"loadReports()\"\n >\n <i\n c8yIcon=\"refresh\"\n [ngClass]=\"{ 'icon-spin': reloading }\"\n ></i>\n {{ 'Reload' | translate }}\n </button>\n</c8y-action-bar-item>\n\n<c8y-help src=\"/docs/cockpit/working-with-reports/#working-with-reports\"></c8y-help>\n\n<c8y-list-group>\n <c8y-li\n class=\"page-sticky-header hidden-xs hidden-sm\"\n *ngIf=\"(reports$ | async)?.data.length > 0\"\n >\n <c8y-li-icon>\n <i class=\"p-l-24\"></i>\n </c8y-li-icon>\n <c8y-li-body class=\"content-flex-60\">\n <div class=\"col-3\">\n {{ 'Report' | translate }}\n </div>\n <div class=\"col-6\">\n {{ 'Description' | translate }}\n </div>\n <div class=\"col-2\">\n {{ 'Show in navigator' | translate }}\n </div>\n </c8y-li-body>\n </c8y-li>\n\n <c8y-li *c8yFor=\"let report of reports$; let i = index; loadMore: 'auto'\">\n <c8y-li-icon [icon]=\"report.icon\"></c8y-li-icon>\n <c8y-li-body class=\"content-flex-60\">\n <div class=\"col-3\">\n <button\n class=\"btn-clean\"\n title=\"{{ report.name }}\"\n type=\"button\"\n routerLink=\"/reports/{{ report.id }}\"\n >\n <span class=\"text-truncate\">\n {{ report.name }}\n </span>\n </button>\n </div>\n <div class=\"col-6\">\n <p class=\"small text-truncate-wrap\">\n <em\n class=\"text-muted\"\n *ngIf=\"!report.description; else showDescription\"\n >\n {{ 'No description available' | translate }}\n </em>\n <ng-template #showDescription>\n {{ report.description }}\n </ng-template>\n </p>\n </div>\n <div class=\"col-2 fit-h-20 m-t-xs-8\">\n <label\n class=\"c8y-switch c8y-switch--inline\"\n title=\"{{ 'Show in navigator' | translate }}\"\n >\n <input\n type=\"checkbox\"\n [ngModel]=\"!!report.c8y_IsNavigatorNode\" (ngModelChange)=\"report.c8y_IsNavigatorNode = $event\"\n (change)=\"update(report)\"\n />\n <span></span>\n <span class=\"visible-xs\">\n {{ 'Show in navigator' | translate }}\n </span>\n </label>\n </div>\n <div class=\"col-1 hidden-xs\">\n <button\n class=\"btn btn-dot btn-dot--danger showOnHover m-l-auto d-flex\"\n [attr.aria-label]=\"'Remove report' | translate\"\n tooltip=\"{{ 'Remove report' | translate }}\"\n type=\"button\"\n [delay]=\"500\"\n (click)=\"delete(report)\"\n >\n <i c8yIcon=\"minus-circle\"></i>\n </button>\n </div>\n <div class=\"visible-xs p-t-8 text-right\">\n <button\n class=\"btn btn-default btn-sm\"\n title=\"{{ 'Remove report' | translate }}\"\n type=\"button\"\n (click)=\"delete(report)\"\n >\n <i c8yIcon=\"delete\"></i>\n {{ 'Remove report' | translate }}\n </button>\n </div>\n </c8y-li-body>\n </c8y-li>\n</c8y-list-group>\n\n<c8y-ui-empty-state\n [icon]=\"'c8y-reports'\"\n [title]=\"'There are no reports defined.' | translate\"\n [subtitle]=\"'Add a report first.' | translate\"\n *ngIf=\"(reports$ | async)?.data.length === 0\"\n>\n <p>\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Add report' | translate }}\"\n type=\"button\"\n [attr.data-cy]=\"'reports-add-report-empty-state-button'\"\n [disabled]=\"!canAddReport\"\n routerLink=\"/report/new-report\"\n c8yProductExperience\n [actionName]=\"PRODUCT_EXPERIENCE.DASHBOARD.EVENTS.REPORTS\"\n [actionData]=\"{ action: PRODUCT_EXPERIENCE.DASHBOARD.ACTIONS.ADD_REPORT }\"\n >\n {{ 'Add report' | translate }}\n </button>\n </p>\n <p c8y-guide-docs>\n <small\n translate\n ngNonBindable\n >\n Find out more in the\n <a c8y-guide-href=\"/docs/cockpit/working-with-reports\">user documentation</a>\n .\n </small>\n </p>\n</c8y-ui-empty-state>\n" }]
}], ctorParameters: () => [{ type: i1.InventoryService }, { type: i2.ContextDashboardService }, { type: i3.TranslateService }, { type: i4.ModalService }, { type: i4.AlertService }, { type: i5.ReportDashboardService }, { type: i4.Permissions }, { type: i4.GainsightService }], propDecorators: { filter: [{
type: ViewChild,
args: [FilterInputComponent, { static: false }]
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVwb3J0LWRhc2hib2FyZC1saXN0LmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3JlcG9ydC1kYXNoYm9hcmQvcmVwb3J0LWRhc2hib2FyZC1saXN0LmNvbXBvbmVudC50cyIsIi4uLy4uLy4uL3JlcG9ydC1kYXNoYm9hcmQvcmVwb3J0LWRhc2hib2FyZC1saXN0LmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQVUsU0FBUyxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQzdELE9BQU8sRUFBRSxlQUFlLEVBQUUsYUFBYSxFQUFjLE1BQU0sTUFBTSxDQUFDO0FBQ2xFLE9BQU8sRUFBa0IsZ0JBQWdCLEVBQWUsTUFBTSxhQUFhLENBQUM7QUFDNUUsT0FBTyxFQUFFLFlBQVksRUFBRSxvQkFBb0IsRUFBRSxXQUFXLEVBQUUsU0FBUyxFQUFFLEdBQUcsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQ2pHLE9BQU8sRUFDTCxZQUFZLEVBQ1osb0JBQW9CLEVBQ3BCLGdCQUFnQixFQUNoQixPQUFPLEVBQ1AsWUFBWSxFQUNaLFdBQVcsRUFDWCxNQUFNLEVBQ1AsTUFBTSxxQkFBcUIsQ0FBQztBQUM3QixPQUFPLEVBQ0wsb0JBQW9CLEVBQ3BCLHVCQUF1QixFQUN2QixrQkFBa0IsRUFDbkIsTUFBTSx1Q0FBdUMsQ0FBQztBQUMvQyxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUN2RCxPQUFPLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQzs7Ozs7Ozs7Ozs7O0FBTXBFLE1BQU0sT0FBTyw0QkFBNEI7SUF1QnZDLFlBQ1UsZ0JBQWtDLEVBQ2xDLHVCQUFnRCxFQUNoRCxnQkFBa0MsRUFDbEMsS0FBbUIsRUFDbkIsWUFBMEIsRUFDMUIsc0JBQThDLEVBQzlDLFdBQXdCLEVBQ3hCLGdCQUFrQztRQVBsQyxxQkFBZ0IsR0FBaEIsZ0JB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SUFFRCxLQUFLLENBQUMsTUFBTSxDQUFDLE1BQXNCO1FBQ2pDLE1BQU0sQ0FBQyxtQkFBbUIsR0FBRyxNQUFNLENBQUMsbUJBQW1CLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDO1FBQ3BFLE1BQU0sSUFBSSxDQUFDLGdCQUFnQixDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUMzQyxNQUFNLENBQUMsbUJBQW1CO1lBQ3hCLENBQUMsQ0FBQyxJQUFJLENBQUMsdUJBQXVCLENBQUMsc0JBQXNCLENBQUMsTUFBTSxDQUFDO1lBQzdELENBQUMsQ0FBQyxJQUFJLENBQUMsc0JBQXNCLENBQUMsbUJBQW1CLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDOUQsQ0FBQzsrR0FyR1UsNEJBQTRCO21HQUE1Qiw0QkFBNEIseUdBRzVCLG9CQUFvQixnREM1QmpDLG0xTEEyTUE7OzRGRGxMYSw0QkFBNEI7a0JBSnhDLFNBQVM7K0JBQ0UsMkJBQTJCOzhTQU1lLE1BQU07c0JBQXpELFNBQVM7dUJBQUMsb0JBQW9CLEVBQUUsRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFFIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29tcG9uZW50LCBPbkluaXQsIFZpZXdDaGlsZCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgQmVoYXZpb3JTdWJqZWN0LCBjb21iaW5lTGF0ZXN0LCBPYnNlcnZhYmxlIH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyBJTWFuYWdlZE9iamVjdCwgSW52ZW50b3J5U2VydmljZSwgSVJlc3VsdExpc3QgfSBmcm9tICdAYzh5L2NsaWVudCc7XG5pbXBvcnQgeyBkZWJvdW5jZVRpbWUsIGRpc3RpbmN0VW50aWxDaGFuZ2VkLCBzaGFyZVJlcGxheSwgc3dpdGNoTWFwLCB0YXAgfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5pbXBvcnQge1xuICBBbGVydFNlcnZpY2UsXG4gIEZpbHRlcklucHV0Q29tcG9uZW50LFxuICBHYWluc2lnaHRTZXJ2aWNlLFxuICBnZXR0ZXh0LFxuICBNb2RhbFNlcnZpY2UsXG4gIFBlcm1pc3Npb25zLFxuICBTdGF0dXNcbn0gZnJvbSAnQGM4eS9uZ3gtY29tcG9uZW50cyc7XG5pbXBvcnQge1xuICBDb250ZXh0RGFzaGJvYXJkVHlwZSxcbiAgQ29udGV4dERhc2hib2FyZFNlcnZpY2UsXG4gIFBST0RVQ1RfRVhQRVJJRU5DRVxufSBmcm9tICdAYzh5L25neC1jb21wb25lbnRzL2NvbnRleHQtZGFzaGJvYXJkJztcbmltcG9ydCB7IFRyYW5zbGF0ZVNlcnZpY2UgfSBmcm9tICdAbmd4LXRyYW5zbGF0ZS9jb3JlJztcbmltcG9ydCB7IFJlcG9ydERhc2hib2FyZFNlcnZpY2UgfSBmcm9tICcuL3JlcG9ydC1kYXNoYm9hcmQuc2VydmljZSc7XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ2M4eS1yZXBvcnQtZGFzaGJvYXJkLWxpc3QnLFxuICB0ZW1wbGF0ZVVybDogJy4vcmVwb3J0LWRhc2hib2FyZC1saXN0LmNvbXBvbmVudC5odG1sJ1xufSlcbmV4cG9ydCBjbGFzcyBSZXBvcnREYXNoYm9hcmRMaXN0Q29tcG9uZW50IGltcGxlbWVudHMgT25Jbml0IHtcbiAgUFJPRFVDVF9FWFBFUklFTkNFID0gUFJPRFVDVF9FWFBFUklFTkNFO1xuXG4gIEBWaWV3Q2hpbGQoRmlsdGVySW5wdXRDb21wb25lbnQsIHsgc3RhdGljOiBmYWxzZSB9KSBmaWx0ZXI6IEZpbHRlcklucHV0Q29tcG9uZW50O1xuICB0ZXh0RmlsdGVyJDogQmVoYXZpb3JTdWJqZWN0PHN0cmluZz4gPSBuZXcgQmVoYXZpb3JTdWJqZWN0KCcnKTtcbiAgcmVsb2FkJDogQmVoYXZpb3JTdWJqZWN0PHZvaWQ+ID0gbmV3IEJlaGF2aW9yU3ViamVjdChudWxsKTtcbiAgcmVsb2FkaW5nID0gZmFsc2U7XG4gIHJlcG9ydHMkOiBPYnNlcnZhYmxlPElSZXN1bHRMaXN0PElNYW5hZ2VkT2JqZWN0Pj4gPSBjb21iaW5lTGF0ZXN0KFxuICAgIHRoaXMudGV4dEZpbHRlciQucGlwZShkZWJvdW5jZVRpbWUoNDAwKSwgZGlzdGluY3RVbnRpbENoYW5nZWQoKSksXG4gICAgdGhpcy5yZWxvYWQkXG4gICkucGlwZShcbiAgICB0YXAoKCkgPT4ge1xuICAgICAgdGhpcy5yZWxvYWRpbmcgPSB0cnVlO1xuICAgIH0pLFxuICAgIHN3aXRjaE1hcCgoW3RleHRdKSA9PiB0aGlzLmxvYWRSZXBvcnRzKHRleHQpKSxcbiAgICB0YXAoKCkgPT4ge1xuICAgICAgdGhpcy5yZWxvYWRpbmcgPSBmYWxzZTtcbiAgICB9KSxcbiAgICBzaGFyZVJlcGxheSgxKVxuICApO1xuICBjYW5BZGRSZXBvcnQgPSBmYWxzZTtcbiAgcHJpdmF0ZSByZWFkb25seSBERUxFVEVEX1NVQ0NFU1NfTVNHID0gZ2V0dGV4dCgnUmVwb3J0IGRlbGV0ZWQuJyk7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSBpbnZlbnRvcnlTZXJ2aWNlOiBJbnZlbnRvcnlTZXJ2aWNlLFxuICAgIHByaXZhdGUgY29udGV4dERhc2hib2FyZFNlcnZpY2U6IENvbnRleHREYXNoYm9hcmRTZXJ2aWNlLFxuICAgIHByaXZhdGUgdHJhbnNsYXRlU2VydmljZTogVHJhbnNsYXRlU2VydmljZSxcbiAgICBwcml2YXRlIG1vZGFsOiBNb2RhbFNlcnZpY2UsXG4gICAgcHJpdmF0ZSBhbGVydFNlcnZpY2U6IEFsZXJ0U2VydmljZSxcbiAgICBwcml2YXRlIHJlcG9ydERhc2hib2FyZFNlcnZpY2U6IFJlcG9ydERhc2hib2FyZFNlcnZpY2UsXG4gICAgcHJpdmF0ZSBwZXJtaXNzaW9uczogUGVybWlzc2lvbnMsXG4gICAgcHJpdmF0ZSBnYWluc2lnaHRTZXJ2aWNlOiBHYWluc2lnaHRTZXJ2aWNlXG4gICkge31cblxuICBuZ09uSW5pdCgpIHtcbiAgICB0aGlzLmNhbkFkZFJlcG9ydCA9IHRoaXMucGVybWlzc2lvbnMuaGFzQW55Um9sZShbXG4gICAgICBQZXJtaXNzaW9ucy5ST0xFX0lOVkVOVE9SWV9DUkVBVEUsXG4gICAgICBQZXJtaXNzaW9ucy5ST0xFX0lOVkVOVE9SWV9BRE1JTixcbiAgICAgIFBlcm1pc3Npb25zLlJPTEVfTUFOQUdFRF9PQkpFQ1RfQURNSU4sXG4gICAgICBQZXJtaXNzaW9ucy5ST0xFX01BTkFHRURfT0JKRUNUX0NSRUFURVxuICAgIF0pO1xuICB9XG5cbiAgYXN5bmMgbG9hZFJlcG9ydHMocGFydGlhbE5hbWU/OiBzdHJpbmcpIHtcbiAgICByZXR1cm4gcGFydGlhbE5hbWVcbiAgICAgID8gdGhpcy5yZXBvcnREYXNoYm9hcmRTZXJ2aWNlLmxpc3RSZXBvcnRzKHsgZmlsdGVyOiB7IG5hbWU6IGAqJHtwYXJ0aWFsTmFtZX0qYCB9IH0pXG4gICAgICA6IHRoaXMucmVwb3J0RGFzaGJvYXJkU2VydmljZS5saXN0UmVwb3J0cygpO1xuICB9XG5cbiAgYXN5bmMgZGVsZXRlKHJlcG9ydDogSU1hbmFnZWRPYmplY3QpIHtcbiAgICB0cnkge1xuICAgICAgY29uc3QgZGFzaGJvYXJkID0gYXdhaXQgdGhpcy5jb250ZXh0RGFzaGJvYXJkU2VydmljZVxuICAgICAgICAuZ2V0RGFzaGJvYXJkJChgcmVwb3J0XyR7cmVwb3J0LmlkfWAsIFtDb250ZXh0RGFzaGJvYXJkVHlwZS5OYW1lZF0pXG4gICAgICAgIC50b1Byb21pc2UoKTtcbiAgICAgIGNvbnN0IGlzRGFzaGJvYXJkRnJvemVuID0gISFkYXNoYm9hcmQ/LmM4eV9EYXNoYm9hcmQ/LmlzRnJvemVuO1xuXG4gICAgICBjb25zdCBtc2cgPSBpc0Rhc2hib2FyZEZyb3plblxuICAgICAgICA/IGdldHRleHQoXG4gICAgICAgICAgICBgWW91IGFyZSBhYm91dCB0byBkZWxldGUgdGhlIHJlcG9ydCBcInt7IHJlcG9ydE5hbWUgfX1cIi4gQmUgYXdhcmUgdGhhdCB0aGUgcmVwb3J0IGhhcyBhIGxvY2tlZCBkYXNoYm9hcmQgYXNzaWduZWQuIERvIHlvdSB3YW50IHRvIHByb2NlZWQ/YFxuICAgICAgICAgIClcbiAgICAgICAgOiBnZXR0ZXh0KGBZb3UgYXJlIGFib3V0IHRvIGRlbGV0ZSB0aGUgcmVwb3J0IFwie3sgcmVwb3J0TmFtZSB9fVwiLiBEbyB5b3Ugd2FudCB0byBwcm9jZWVkP2ApO1xuXG4gICAgICBhd2FpdCB0aGlzLm1vZGFsLmNvbmZpcm0oXG4gICAgICAgIGdldHRleHQoJ0RlbGV0ZSByZXBvcnQnKSxcbiAgICAgICAgdGhpcy50cmFuc2xhdGVTZXJ2aWNlLmluc3RhbnQobXNnLCB7XG4gICAgICAgICAgcmVwb3J0TmFtZTogcmVwb3J0Lm5hbWVcbiAgICAgICAgfSksXG4gICAgICAgIFN0YXR1cy5EQU5HRVIsXG4gICAgICAgIHtcbiAgICAgICAgICBvazogZ2V0dGV4dCgnRGVsZXRlJyksXG4gICAgICAgICAgY2FuY2VsOiBnZXR0ZXh0KCdDYW5jZWwnKVxuICAgICAgICB9XG4gICAgICApO1xuXG4gICAgICBhd2FpdCB0aGlzLmNvbnRleHREYXNoYm9hcmRTZXJ2aWNlLmRlbGV0ZShkYXNoYm9hcmQsIGZhbHNlKTtcbiAgICAgIGF3YWl0IHRoaXMuaW52ZW50b3J5U2VydmljZS5kZWxldGUocmVwb3J0LmlkKTtcbiAgICAgIHRoaXMuYWxlcnRTZXJ2aWNlLnN1Y2Nlc3ModGhpcy5ERUxFVEVEX1NVQ0NFU1NfTVNHKTtcbiAgICAgIGlmIChyZXBvcnQuYzh5X0lzTmF2aWdhdG9yTm9kZSkge1xuICAgICAgICB0aGlzLnJlcG9ydERhc2hib2FyZFNlcnZpY2UucmVtb3ZlTmF2aWdhdG9yTm9kZShyZXBvcnQpO1xuICAgICAgfVxuICAgICAgdGhpcy5yZWxvYWQkLm5leHQoKTtcbiAgICAgIHRoaXMuZ2FpbnNpZ2h0U2VydmljZS50cmlnZ2VyRXZlbnQoUFJPRFVDVF9FWFBFUklFTkNFLkRBU0hCT0FSRC5FVkVOVFMuUkVQT1JUUywge1xuICAgICAgICBjb21wb25lbnQ6IFBST0RVQ1RfRVhQRVJJRU5DRS5EQVNIQk9BUkQuQ09NUE9ORU5UUy5SRVBPUlRTX0xJU1QsXG4gICAgICAgIGFjdGlvbjogUFJPRFVDVF9FWFBFUklFTkNFLkRBU0hCT0FSRC5BQ1RJT05TLkRFTEVURSxcbiAgICAgICAgbmFtZTogcmVwb3J0Lm5hbWUsXG4gICAgICAgIGlkOiByZXBvcnQuaWQsXG4gICAgICAgIGNvbnRleHQ6IFBST0RVQ1RfRVhQRVJJRU5DRS5EQVNIQk9BUkQuQ09OVEVYVC5SRVBPUlRcbiAgICAgIH0pO1xuICAgIH0gY2F0Y2ggKGV4KSB7XG4gICAgICBpZiAoZXgpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBTb21ldGhpbmcgd2VudCB3cm9uZzogJHtleH1gKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBhc3luYyB1cGRhdGUocmVwb3J0OiBJTWFuYWdlZE9iamVjdCkge1xuICAgIHJlcG9ydC5jOHlfSXNOYXZpZ2F0b3JOb2RlID0gcmVwb3J0LmM4eV9Jc05hdmlnYXRvck5vZGUgPyB7fSA6IG51bGw7XG4gICAgYXdhaXQgdGhpcy5pbnZlbnRvcnlTZXJ2aWNlLnVwZGF0ZShyZXBvcnQpO1xuICAgIHJlcG9ydC5jOHlfSXNOYXZpZ2F0b3JOb2RlXG4gICAgICA/IHRoaXMuY29udGV4dERhc2hib2FyZFNlcnZpY2UuYWRkUmVwb3J0TmF2aWdhdG9yTm9kZShyZXBvcnQpXG4gICAgICA6IHRoaXMucmVwb3J0RGFzaGJvYXJkU2VydmljZS5yZW1vdmVOYXZpZ2F0b3JOb2RlKHJlcG9ydCk7XG4gIH1cbn1cbiIsIjxjOHktdGl0bGU+XG4gIHt7ICdSZXBvcnRzJyB8IHRyYW5zbGF0ZSB9fVxuPC9jOHktdGl0bGU+XG5cbjxjOHktYWN0aW9uLWJhci1pdGVtXG4gIFtwbGFjZW1lbnRdPVwiJ2xlZnQnXCJcbiAgaXRlbUNsYXNzPVwibmF2YmFyLWZvcm1cIlxuPlxuICA8ZGl2IGNsYXNzPVwiaW5wdXQtZ3JvdXAgaW5wdXQtZ3JvdXAtc2VhcmNoXCI+XG4gICAgPGlucHV0XG4gICAgICBjbGFzcz1cImZvcm0tY29udHJvbFwiXG4gICAgICBbYXR0ci5hcmlhLWxhYmVsXT1cIidGaWx0ZXInIHwgdHJhbnNsYXRlXCJcbiAgICAgIHBsYWNlaG9sZGVyPVwie3sgJ0ZpbHRlcuKApicgfCB0cmFuc2xhdGUgfX1cIlxuICAgICAgdHlwZT1cInNlYXJjaFwiXG4gICAgICBbbmdNb2RlbF09XCJ0ZXh0RmlsdGVyJCB8IGFzeW5jXCJcbiAgICAgIChuZ01vZGVsQ2hhbmdlKT1cInRleHRGaWx0ZXIkLm5leHQoJGV2ZW50KVwiXG4gICAgLz5cbiAgICA8c3BhbiBjbGFzcz1cImlucHV0LWdyb3VwLWFkZG9uXCI+XG4gICAgICA8aVxuICAgICAgICBjOHlJY29uPVwic2VhcmNoXCJcbiAgICAgICAgKm5nSWY9XCIodGV4dEZpbHRlciQgfCBhc3luYykubGVuZ3RoID09PSAwXCJcbiAgICAgID48L2k+XG4gICAgICA8aVxuICAgICAgICBjbGFzcz1cInRleHQtbXV0ZWRcIlxuICAgICAgICBjOHlJY29uPVwidGltZXNcIlxuICAgICAgICAqbmdJZj1cIih0ZXh0RmlsdGVyJCB8IGFzeW5jKS5sZW5ndGggPiAwXCJcbiAgICAgICAgKGNsaWNrKT1cInRleHRGaWx0ZXIkLm5leHQoJycpXCJcbiAgICAgICAgcHgtZXZlbnQ9XCJDbGVhciBmaWx0ZXJpbmcgcmVwb3J0c1wiXG4gICAgICA+PC9pPlxuICAgIDwvc3Bhbj5cbiAgPC9kaXY+XG48L2M4eS1hY3Rpb24tYmFyLWl0ZW0+XG5cbjxjOHktYWN0aW9uLWJhci1pdGVtIFtwbGFjZW1lbnRdPVwiJ3JpZ2h0J1wiPlxuICA8YnV0dG9uXG4gICAgY2xhc3M9XCJidG4gYnRuLWxpbmtcIlxuICAgIHRpdGxlPVwie3sgJ0FkZCByZXBvcnQnIHwgdHJhbnNsYXRlIH19XCJcbiAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICBbYXR0ci5kYXRhLWN5XT1cIidyZXBvcnRzLWFkZC1yZXBvcnQtYWN0aW9uLWJhci1idXR0b24nXCJcbiAgICByb3V0ZXJMaW5rPVwiL3JlcG9ydC9uZXctcmVwb3J0XCJcbiAgICBbZGlzYWJsZWRdPVwiIWNhbkFkZFJlcG9ydFwiXG4gID5cbiAgICA8aSBjOHlJY29uPVwicGx1cy1jaXJjbGVcIj48L2k+XG4gICAge3sgJ0FkZCByZXBvcnQnIHwgdHJhbnNsYXRlIH19XG4gIDwvYnV0dG9uPlxuICA8YnV0dG9uXG4gICAgY2xhc3M9XCJidG4gYnRuLWRvdCBtLXItMTZcIlxuICAgIGFyaWEtbGFiZWw9XCJ7eyAnSW5mbycgfCB0cmFuc2xhdGUgfX1cIlxuICAgIHBvcG92ZXI9XCJ7eyAnWW91IGRvblxcJ3QgaGF2ZSBwZXJtaXNzaW9uIHRvIGFkZCByZXBvcnRzJyB8IHRyYW5zbGF0ZSB9fVwiXG4gICAgcGxhY2VtZW50PVwidG9wXCJcbiAgICB0cmlnZ2Vycz1cImZvY3VzXCJcbiAgICBjb250YWluZXI9XCJib2R5XCJcbiAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAqbmdJZj1cIiFjYW5BZGRSZXBvcnRcIlxuICA+XG4gICAgPGlcbiAgICAgIGNsYXNzPVwidGV4dC1wcmltYXJ5XCJcbiAgICAgIFtjOHlJY29uXT1cIidpbmZvLWNpcmNsZSdcIlxuICAgID48L2k+XG4gIDwvYnV0dG9uPlxuPC9jOHktYWN0aW9uLWJhci1pdGVtPlxuXG48Yzh5LWFjdGlvbi1iYXItaXRlbSBbcGxhY2VtZW50XT1cIidyaWdodCdcIj5cbiAgPGJ1dHRvblxuICAgIGNsYXNzPVwiYnRuIGJ0bi1saW5rXCJcbiAgICB0aXRsZT1cInt7ICdSZWxvYWQnIHwgdHJhbnNsYXRlIH19XCJcbiAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAoY2xpY2spPVwibG9hZFJlcG9ydHMoKVwiXG4gID5cbiAgICA8aVxuICAgICAgYzh5SWNvbj1cInJlZnJlc2hcIlxuICAgICAgW25nQ2xhc3NdPVwieyAnaWNvbi1zcGluJzogcmVsb2FkaW5nIH1cIlxuICAgID48L2k+XG4gICAge3sgJ1JlbG9hZCcgfCB0cmFuc2xhdGUgfX1cbiAgPC9idXR0b24+XG48L2M4eS1hY3Rpb24tYmFyLWl0ZW0+XG5cbjxjOHktaGVscCBzcmM9XCIvZG9jcy9jb2NrcGl0L3dvcmtpbmctd2l0aC1yZXBvcnRzLyN3b3JraW5nLXdpdGgtcmVwb3J0c1wiPjwvYzh5LWhlbHA+XG5cbjxjOHktbGlzdC1ncm91cD5cbiAgPGM4eS1saVxuICAgIGNsYXNzPVwicGFnZS1zdGlja3ktaGVhZGVyIGhpZGRlbi14cyBoaWRkZW4tc21cIlxuICAgICpuZ0lmPVwiKHJlcG9ydHMkIHwgYXN5bmMpPy5kYXRhLmxlbmd0aCA+IDBcIlxuICA+XG4gICAgPGM4eS1saS1pY29uPlxuICAgICAgPGkgY2xhc3M9XCJwLWwtMjRcIj48L2k+XG4gICAgPC9jOHktbGktaWNvbj5cbiAgICA8Yzh5LWxpLWJvZHkgY2xhc3M9XCJjb250ZW50LWZsZXgtNjBcIj5cbiAgICAgIDxkaXYgY2xhc3M9XCJjb2wtM1wiPlxuICAgICAgICB7eyAnUmVwb3J0JyB8IHRyYW5zbGF0ZSB9fVxuICAgICAgPC9kaXY+XG4gICAgICA8ZGl2IGNsYXNzPVwiY29sLTZcIj5cbiAgICAgICAge3sgJ0Rlc2NyaXB0aW9uJyB8IHRyYW5zbGF0ZSB9fVxuICAgICAgPC9kaXY+XG4gICAgICA8ZGl2IGNsYXNzPVwiY29sLTJcIj5cbiAgICAgICAge3sgJ1Nob3cgaW4gbmF2aWdhdG9yJyB8IHRyYW5zbGF0ZSB9fVxuICAgICAgPC9kaXY+XG4gICAgPC9jOHktbGktYm9keT5cbiAgPC9jOHktbGk+XG5cbiAgPGM4eS1saSAqYzh5Rm9yPVwibGV0IHJlcG9ydCBvZiByZXBvcnRzJDsgbGV0IGkgPSBpbmRleDsgbG9hZE1vcmU6ICdhdXRvJ1wiPlxuICAgIDxjOHktbGktaWNvbiBbaWNvbl09XCJyZXBvcnQuaWNvblwiPjwvYzh5LWxpLWljb24+XG4gICAgPGM4eS1saS1ib2R5IGNsYXNzPVwiY29udGVudC1mbGV4LTYwXCI+XG4gICAgICA8ZGl2IGNsYXNzPVwiY29sLTNcIj5cbiAgICAgICAgPGJ1dHRvblxuICAgICAgICAgIGNsYXNzPVwiYnRuLWNsZWFuXCJcbiAgICAgICAgICB0aXRsZT1cInt7IHJlcG9ydC5uYW1lIH19XCJcbiAgICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgICByb3V0ZXJMaW5rPVwiL3JlcG9ydHMve3sgcmVwb3J0LmlkIH19XCJcbiAgICAgICAgPlxuICAgICAgICAgIDxzcGFuIGNsYXNzPVwidGV4dC10cnVuY2F0ZVwiPlxuICAgICAgICAgICAge3sgcmVwb3J0Lm5hbWUgfX1cbiAgICAgICAgICA8L3NwYW4+XG4gICAgICAgIDwvYnV0dG9uPlxuICAgICAgPC9kaXY+XG4gICAgICA8ZGl2IGNsYXNzPVwiY29sLTZcIj5cbiAgICAgICAgPHAgY2xhc3M9XCJzbWFsbCB0ZXh0LXRydW5jYXRlLXdyYXBcIj5cbiAgICAgICAgICA8ZW1cbiAgICAgICAgICAgIGNsYXNzPVwidGV4dC1tdXRlZFwiXG4gICAgICAgICAgICAqbmdJZj1cIiFyZXBvcnQuZGVzY3JpcHRpb247IGVsc2Ugc2hvd0Rlc2NyaXB0aW9uXCJcbiAgICAgICAgICA+XG4gICAgICAgICAgICB7eyAnTm8gZGVzY3JpcHRpb24gYXZhaWxhYmxlJyB8IHRyYW5zbGF0ZSB9fVxuICAgICAgICAgIDwvZW0+XG4gICAgICAgICAgPG5nLXRlbXBsYXRlICNzaG93RGVzY3JpcHRpb24+XG4gICAgICAgICAgICB7eyByZXBvcnQuZGVzY3JpcHRpb24gfX1cbiAgICAgICAgICA8L25nLXRlbXBsYXRlPlxuICAgICAgICA8L3A+XG4gICAgICA8L2Rpdj5cbiAgICAgIDxkaXYgY2xhc3M9XCJjb2wtMiBmaXQtaC0yMCBtLXQteHMtOFwiPlxuICAgICAgICA8bGFiZWxcbiAgICAgICAgICBjbGFzcz1cImM4eS1zd2l0Y2ggYzh5LXN3aXRjaC0taW5saW5lXCJcbiAgICAgICAgICB0aXRsZT1cInt7ICdTaG93IGluIG5hdmlnYXRvcicgfCB0cmFuc2xhdGUgfX1cIlxuICAgICAgICA+XG4gICAgICAgICAgPGlucHV0XG4gICAgICAgICAgICB0eXBlPVwiY2hlY2tib3hcIlxuICAgICAgICAgICAgW25nTW9kZWxdPVwiISFyZXBvcnQuYzh5X0lzTmF2aWdhdG9yTm9kZVwiIChuZ01vZGVsQ2hhbmdlKT1cInJlcG9ydC5jOHlfSXNOYXZpZ2F0b3JOb2RlID0gJGV2ZW50XCJcbiAgICAgICAgICAgIChjaGFuZ2UpPVwidXBkYXRlKHJlcG9ydClcIlxuICAgICAgICAgIC8+XG4gICAgICAgICAgPHNwYW4+PC9zcGFuPlxuICAgICAgICAgIDxzcGFuIGNsYXNzPVwidmlzaWJsZS14c1wiPlxuICAgICAgICAgICAge3sgJ1Nob3cgaW4gbmF2aWdhdG9yJyB8IHRyYW5zbGF0ZSB9fVxuICAgICAgICAgIDwvc3Bhbj5cbiAgICAgICAgPC9sYWJlbD5cbiAgICAgIDwvZGl2PlxuICAgICAgPGRpdiBjbGFzcz1cImNvbC0xIGhpZGRlbi14c1wiPlxuICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgY2xhc3M9XCJidG4gYnRuLWRvdCBidG4tZG90LS1kYW5nZXIgc2hvd09uSG92ZXIgbS1sLWF1dG8gZC1mbGV4XCJcbiAgICAgICAgICBbYXR0ci5hcmlhLWxhYmVsXT1cIidSZW1vdmUgcmVwb3J0JyB8IHRyYW5zbGF0ZVwiXG4gICAgICAgICAgdG9vbHRpcD1cInt7ICdSZW1vdmUgcmVwb3J0JyB8IHRyYW5zbGF0ZSB9fVwiXG4gICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgW2RlbGF5XT1cIjUwMFwiXG4gICAgICAgICAgKGNsaWNrKT1cImRlbGV0ZShyZXBvcnQpXCJcbiAgICAgICAgPlxuICAgICAgICAgIDxpIGM4eUljb249XCJtaW51cy1jaXJjbGVcIj48L2k+XG4gICAgICAgIDwvYnV0dG9uPlxuICAgICAgPC9kaXY+XG4gICAgICA8ZGl2IGNsYXNzPVwidmlzaWJsZS14cyBwLXQtOCB0ZXh0LXJpZ2h0XCI+XG4gICAgICAgIDxidXR0b25cbiAgICAgICAgICBjbGFzcz1cImJ0biBidG4tZGVmYXVsdCBidG4tc21cIlxuICAgICAgICAgIHRpdGxlPVwie3sgJ1JlbW92ZSByZXBvcnQnIHwgdHJhbnNsYXRlIH19XCJcbiAgICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgICAoY2xpY2spPVwiZGVsZXRlKHJlcG9ydClcIlxuICAgICAgICA+XG4gICAgICAgICAgPGkgYzh5SWNvbj1cImRlbGV0ZVwiPjwvaT5cbiAgICAgICAgICB7eyAnUmVtb3ZlIHJlcG9ydCcgfCB0cmFuc2xhdGUgfX1cbiAgICAgICAgPC9idXR0b24+XG4gICAgICA8L2Rpdj5cbiAgICA8L2M4eS1saS1ib2R5PlxuICA8L2M4eS1saT5cbjwvYzh5LWxpc3QtZ3JvdXA+XG5cbjxjOHktdWktZW1wdHktc3RhdGVcbiAgW2ljb25dPVwiJ2M4eS1yZXBvcnRzJ1wiXG4gIFt0aXRsZV09XCInVGhlcmUgYXJlIG5vIHJlcG9ydHMgZGVmaW5lZC4nIHwgdHJhbnNsYXRlXCJcbiAgW3N1YnRpdGxlXT1cIidBZGQgYSByZXBvcnQgZmlyc3QuJyB8IHRyYW5zbGF0ZVwiXG4gICpuZ0lmPVwiKHJlcG9ydHMkIHwgYXN5bmMpPy5kYXRhLmxlbmd0aCA9PT0gMFwiXG4+XG4gIDxwPlxuICAgIDxidXR0b25cbiAgICAgIGNsYXNzPVwiYnRuIGJ0bi1wcmltYXJ5XCJcbiAgICAgIHRpdGxlPVwie3sgJ0FkZCByZXBvcnQnIHwgdHJhbnNsYXRlIH19XCJcbiAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgW2F0dHIuZGF0YS1jeV09XCIncmVwb3J0cy1hZGQtcmVwb3J0LWVtcHR5LXN0YXRlLWJ1dHRvbidcIlxuICAgICAgW2Rpc2FibGVkXT1cIiFjYW5BZGRSZXBvcnRcIlxuICAgICAgcm91dGVyTGluaz1cIi9yZXBvcnQvbmV3LXJlcG9ydFwiXG4gICAgICBjOHlQcm9kdWN0RXhwZXJpZW5jZVxuICAgICAgW2FjdGlvbk5hbWVdPVwiUFJPRFVDVF9FWFBFUklFTkNFLkRBU0hCT0FSRC5FVkVOVFMuUkVQT1JUU1wiXG4gICAgICBbYWN0aW9uRGF0YV09XCJ7IGFjdGlvbjogUFJPRFVDVF9FWFBFUklFTkNFLkRBU0hCT0FSRC5BQ1RJT05TLkFERF9SRVBPUlQgfVwiXG4gICAgPlxuICAgICAge3sgJ0FkZCByZXBvcnQnIHwgdHJhbnNsYXRlIH19XG4gICAgPC9idXR0b24+XG4gIDwvcD5cbiAgPHAgYzh5LWd1aWRlLWRvY3M+XG4gICAgPHNtYWxsXG4gICAgICB0cmFuc2xhdGVcbiAgICAgIG5nTm9uQmluZGFibGVcbiAgICA+XG4gICAgICBGaW5kIG91dCBtb3JlIGluIHRoZVxuICAgICAgPGEgYzh5LWd1aWRlLWhyZWY9XCIvZG9jcy9jb2NrcGl0L3dvcmtpbmctd2l0aC1yZXBvcnRzXCI+dXNlciBkb2N1bWVudGF0aW9uPC9hPlxuICAgICAgLlxuICAgIDwvc21hbGw+XG4gIDwvcD5cbjwvYzh5LXVpLWVtcHR5LXN0YXRlPlxuIl19