@c8y/ngx-components
Version:
Angular modules for Cumulocity IoT applications
144 lines • 43.4 kB
JavaScript
import { Component } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { ActivatedRoute } from '@angular/router';
import { ɵdefineHiddenProp } from '@ngx-formly/core';
import { find, forOwn, get, mapValues, pick } from 'lodash-es';
import { BehaviorSubject, Subject, combineLatest, from, merge, of } from 'rxjs';
import { catchError, map, shareReplay, switchMap, tap } from 'rxjs/operators';
import { AlertService } from '../alert/alert.service';
import { Permissions, Status } from '../common/index';
import { C8yJSONSchema } from '../dynamic-forms/json-schema/c8y-json-schema.service';
import { ModalService } from '../modal/modal.service';
import { ProviderConfigurationService } from './service/provider-configuration.service';
import { ProviderDefinitionsService } from './service/provider-definitions.service';
import * as i0 from "@angular/core";
import * as i1 from "../common/index";
import * as i2 from "@angular/router";
import * as i3 from "../modal/modal.service";
import * as i4 from "../alert/alert.service";
import * as i5 from "./service/provider-definitions.service";
import * as i6 from "./service/provider-configuration.service";
import * as i7 from "../dynamic-forms/json-schema/c8y-json-schema.service";
import * as i8 from "../breadcrumb/breadcrumb.component";
import * as i9 from "../breadcrumb/breadcrumb-item.component";
import * as i10 from "@angular/common";
import * as i11 from "../common/if-allowed.directive";
import * as i12 from "../header/title/title.component";
import * as i13 from "../search/highlight.component";
import * as i14 from "../select/typeahead.component";
import * as i15 from "@angular/forms";
import * as i16 from "../forms/form-group.component";
import * as i17 from "../forms/message.directive";
import * as i18 from "../forms/messages.component";
import * as i19 from "../list-group/list-item.component";
import * as i20 from "@ngx-formly/core";
import * as i21 from "../i18n/c8y-translate.pipe";
export class ProviderConfigurationComponent {
constructor(permissions, activatedRoute, modalService, alertService, providerDefinitionsService, providerConfigurationService, jsonschema) {
this.permissions = permissions;
this.activatedRoute = activatedRoute;
this.modalService = modalService;
this.alertService = alertService;
this.providerDefinitionsService = providerDefinitionsService;
this.providerConfigurationService = providerConfigurationService;
this.jsonschema = jsonschema;
this.layout$ = this.activatedRoute.data.pipe(map((config) => config.layout), tap((layout) => (this.layout = layout)), tap((layout) => {
this.options.formState.disabled = !this.permissions.hasAllRoles(layout.saveRoles || []);
this.beforeSaveHook = layout.beforeSaveHook;
}));
this.allRoles$ = this.layout$.pipe(map((layout) => [
...(layout.deleteRoles || []),
...(layout.saveRoles || [])
]));
this.changeProvider$ = new BehaviorSubject(null);
this.providerInput$ = new BehaviorSubject('');
this.form = new FormGroup({});
this.fields = [];
this.options = {
formState: {
disabled: false
}
};
this.reload$ = new BehaviorSubject(null);
this.updatedConfiguration$ = new Subject();
}
ngOnInit() {
const allProviders$ = from(this.providerDefinitionsService.list()).pipe(map(result => result.data), shareReplay(1));
this.providers$ = combineLatest(allProviders$, this.providerInput$).pipe(map(([providers, input]) => input
? providers.filter(el => el.displayName.toLowerCase().indexOf(input.toLowerCase()) >= 0)
: providers), shareReplay(1));
this.configuration$ = merge(this.updatedConfiguration$, this.reload$.pipe(switchMap(() => from(this.providerConfigurationService.detail()).pipe(catchError(() => of({})))), map(result => result.data))).pipe(map(this.removeEncryptedValues), shareReplay(1));
this.selectedProvider$ = combineLatest(allProviders$, this.configuration$, this.changeProvider$).pipe(tap(([_, configuration, newProvider]) => (this.model = newProvider
? pick(this.model, 'sms.senderName', 'sms.senderAddress')
: configuration)), map(([providers, configuration, newProvider]) => newProvider ||
find(providers, (provider) => get(configuration, 'provider') === provider.id)), tap((provider) => {
if (provider) {
const config = this.jsonschema.toFieldConfig(get(provider, 'schema'));
if (config.fieldGroup) {
config.fieldGroup.forEach((fieldConfig) => {
ɵdefineHiddenProp(fieldConfig, '_keyPath', {
key: fieldConfig.key,
path: [fieldConfig.key]
});
fieldConfig.expressionProperties = {
'templateOptions.disabled': 'formState.disabled'
};
});
}
this.fields = [config];
this.form = new FormGroup({});
}
}), shareReplay(1));
}
async saveProviderConfiguration() {
const modelToSave = !!this.beforeSaveHook
? await this.beforeSaveHook(this.model, this.fields)
: this.model;
forOwn(modelToSave, (value, key) => {
if (Array.isArray(value)) {
modelToSave[key] = value
.filter(item => !!item || item === 0)
.map(item => (typeof item === 'string' ? item.trim() : item));
}
else if (typeof value === 'string') {
modelToSave[key] = value.trim();
}
});
try {
const res = await this.providerConfigurationService.update(modelToSave);
this.changeProvider$.next(null);
this.updatedConfiguration$.next(res.data);
this.alertService.success(this.layout.configurationUpdatedSuccessMsg);
this.form.markAsPristine();
}
catch (err) {
this.alertService.addServerFailure(err);
}
}
async deleteProviderConfiguration() {
try {
await this.modalService.confirm(this.layout.deleteConfigurationModalTitle, this.layout.deleteConfigurationModalBody, Status.DANGER, {
ok: this.layout.deleteConfigurationModalOkBtnLabel,
cancel: this.layout.deleteConfigurationModalCancelBtnLabel
});
await this.providerConfigurationService.delete();
this.reload$.next();
this.alertService.success(this.layout.configurationDeletedSuccessMsg);
}
catch (err) {
if (err) {
this.alertService.addServerFailure(err);
}
}
}
removeEncryptedValues(configuration) {
return mapValues(configuration, value => (value === '<<Encrypted>>' ? undefined : value));
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ProviderConfigurationComponent, deps: [{ token: i1.Permissions }, { token: i2.ActivatedRoute }, { token: i3.ModalService }, { token: i4.AlertService }, { token: i5.ProviderDefinitionsService }, { token: i6.ProviderConfigurationService }, { token: i7.C8yJSONSchema }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: ProviderConfigurationComponent, selector: "c8y-sms-gateway", providers: [ProviderConfigurationService, ProviderDefinitionsService], ngImport: i0, template: "<c8y-title>\n {{ (layout$ | async)?.pageTitle | translate }}\n</c8y-title>\n\n<c8y-breadcrumb>\n <c8y-breadcrumb-item\n [label]=\"'Settings' | translate\"\n [icon]=\"'cog'\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item *ngIf=\"(layout$ | async)?.pageTitle !='Connectivity'\"\n [label]=\"'SMS provider' | translate\"\n [icon]=\"'cog'\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item *ngIf=\"(layout$ | async)?.pageTitle =='Connectivity'\"\n [label]=\"'Connectivity' | translate\"\n [icon]=\"'cog'\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item *ngIf=\"(layout$ | async)?.pageTitle =='Connectivity'\"\n [icon]=\"'cog'\"\n [label]=\"'SIM provider settings' | translate\"\n ></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<div class=\"row\">\n <div class=\"col-md-8 col-xs-12\">\n <form class=\"card card--fullpage\" (ngSubmit)=\"saveProviderConfiguration()\">\n <div class=\"card-header separator\">\n <div class=\"card-title\">\n {{ (layout$ | async)?.cardTitle | translate }}\n </div>\n </div>\n <div class=\"inner-scroll\">\n <div class=\"card-block\">\n <p *ngIf=\"!!(layout$ | async)?.description\" class=\"m-b-8\">\n {{ (layout$ | async)?.description | translate }}\n </p>\n <c8y-form-group>\n <label for=\"providerName\">{{ (layout$ | async)?.providerName | translate }}</label>\n <c8y-typeahead\n [disabled]=\"!permissions.hasAllRoles((layout$ | async)?.saveRoles || [])\"\n [ngModel]=\"selectedProvider$ | async\"\n [displayProperty]=\"'displayName'\"\n name=\"providerName\"\n placeholder=\"{{ (layout$ | async)?.providerNamePlaceholder | translate }}\"\n (onSearch)=\"providerInput$.next($event)\"\n [allowFreeEntries]=\"false\"\n [required]=\"true\"\n [container]=\"'body'\"\n >\n <c8y-li\n *ngFor=\"let provider of providers$ | async\"\n class=\"p-l-8 p-r-8 c8y-list__item--link\"\n (click)=\"changeProvider$.next(provider); providerInput$.next('')\"\n [active]=\"(selectedProvider$ | async) === provider\"\n [attr.role]=\"'menuitem'\"\n >\n <c8y-highlight\n [text]=\"provider.displayName || '--'\"\n [pattern]=\"providerInput$ | async\"\n ></c8y-highlight>\n </c8y-li>\n </c8y-typeahead>\n <c8y-messages>\n <c8y-message\n name=\"notExisting\"\n [text]=\"(layout$ | async)?.providerNameNoMatchesHint | translate\"\n ></c8y-message>\n </c8y-messages>\n </c8y-form-group>\n <formly-form\n *ngIf=\"selectedProvider$ | async\"\n [form]=\"form\"\n [fields]=\"fields\"\n [model]=\"model\"\n [options]=\"options\"\n ></formly-form>\n </div>\n </div>\n <div class=\"card-footer separator\" *c8yIfAllowed=\"allRoles$ | async; allowAny\">\n <button\n *c8yIfAllowed=\"(layout$ | async)?.deleteRoles\"\n class=\"btn btn-default\"\n type=\"button\"\n (click)=\"deleteProviderConfiguration()\"\n [disabled]=\"\n !(configuration$ | async)?.provider && !(configuration$ | async)?.providerName\n \"\n title=\"{{ (layout$ | async)?.deleteBtnLabel | translate }}\"\n >\n {{ (layout$ | async)?.deleteBtnLabel | translate }}\n </button>\n <button\n *c8yIfAllowed=\"(layout$ | async)?.saveRoles\"\n class=\"btn btn-primary\"\n type=\"submit\"\n [disabled]=\"form.invalid || form.pristine\"\n title=\"{{ (layout$ | async)?.saveBtnLabel | translate }}\"\n >\n {{ (layout$ | async)?.saveBtnLabel | translate }}\n </button>\n </div>\n </form>\n </div>\n</div>\n", dependencies: [{ kind: "component", type: i8.BreadcrumbComponent, selector: "c8y-breadcrumb" }, { kind: "component", type: i9.BreadcrumbItemComponent, selector: "c8y-breadcrumb-item", inputs: ["icon", "translate", "label", "path", "injector"] }, { kind: "directive", type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i11.IfAllowedDirective, selector: "[c8yIfAllowed]", inputs: ["c8yIfAllowed", "c8yIfAllowedAllowAny"] }, { kind: "component", type: i12.TitleComponent, selector: "c8y-title", inputs: ["pageTitleUpdate"] }, { kind: "component", type: i13.HighlightComponent, selector: "c8y-highlight", inputs: ["pattern", "text", "elementClass", "shouldTrimPattern"] }, { kind: "component", type: i14.TypeaheadComponent, selector: "c8y-typeahead", inputs: ["required", "maxlength", "disabled", "allowFreeEntries", "placeholder", "displayProperty", "icon", "name", "autoClose", "hideNew", "container", "selected", "highlightFirstItem"], outputs: ["onSearch", "onIconClick"] }, { kind: "directive", type: i15.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i15.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i15.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i15.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i15.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i15.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: i16.FormGroupComponent, selector: "c8y-form-group", inputs: ["hasError", "hasWarning", "hasSuccess", "novalidation", "status"] }, { kind: "directive", type: i17.MessageDirective, selector: "c8y-message", inputs: ["name", "text"] }, { kind: "component", type: i18.MessagesComponent, selector: "c8y-messages", inputs: ["show", "defaults", "helpMessage"] }, { kind: "component", type: i19.ListItemComponent, selector: "c8y-list-item, c8y-li", inputs: ["active", "highlighted", "emptyActions", "dense", "collapsed", "selectable"], outputs: ["collapsedChange"] }, { kind: "component", type: i20.FormlyForm, selector: "formly-form", inputs: ["form", "model", "fields", "options"], outputs: ["modelChange"] }, { kind: "pipe", type: i21.C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: i10.AsyncPipe, name: "async" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ProviderConfigurationComponent, decorators: [{
type: Component,
args: [{ selector: 'c8y-sms-gateway', providers: [ProviderConfigurationService, ProviderDefinitionsService], template: "<c8y-title>\n {{ (layout$ | async)?.pageTitle | translate }}\n</c8y-title>\n\n<c8y-breadcrumb>\n <c8y-breadcrumb-item\n [label]=\"'Settings' | translate\"\n [icon]=\"'cog'\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item *ngIf=\"(layout$ | async)?.pageTitle !='Connectivity'\"\n [label]=\"'SMS provider' | translate\"\n [icon]=\"'cog'\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item *ngIf=\"(layout$ | async)?.pageTitle =='Connectivity'\"\n [label]=\"'Connectivity' | translate\"\n [icon]=\"'cog'\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item *ngIf=\"(layout$ | async)?.pageTitle =='Connectivity'\"\n [icon]=\"'cog'\"\n [label]=\"'SIM provider settings' | translate\"\n ></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<div class=\"row\">\n <div class=\"col-md-8 col-xs-12\">\n <form class=\"card card--fullpage\" (ngSubmit)=\"saveProviderConfiguration()\">\n <div class=\"card-header separator\">\n <div class=\"card-title\">\n {{ (layout$ | async)?.cardTitle | translate }}\n </div>\n </div>\n <div class=\"inner-scroll\">\n <div class=\"card-block\">\n <p *ngIf=\"!!(layout$ | async)?.description\" class=\"m-b-8\">\n {{ (layout$ | async)?.description | translate }}\n </p>\n <c8y-form-group>\n <label for=\"providerName\">{{ (layout$ | async)?.providerName | translate }}</label>\n <c8y-typeahead\n [disabled]=\"!permissions.hasAllRoles((layout$ | async)?.saveRoles || [])\"\n [ngModel]=\"selectedProvider$ | async\"\n [displayProperty]=\"'displayName'\"\n name=\"providerName\"\n placeholder=\"{{ (layout$ | async)?.providerNamePlaceholder | translate }}\"\n (onSearch)=\"providerInput$.next($event)\"\n [allowFreeEntries]=\"false\"\n [required]=\"true\"\n [container]=\"'body'\"\n >\n <c8y-li\n *ngFor=\"let provider of providers$ | async\"\n class=\"p-l-8 p-r-8 c8y-list__item--link\"\n (click)=\"changeProvider$.next(provider); providerInput$.next('')\"\n [active]=\"(selectedProvider$ | async) === provider\"\n [attr.role]=\"'menuitem'\"\n >\n <c8y-highlight\n [text]=\"provider.displayName || '--'\"\n [pattern]=\"providerInput$ | async\"\n ></c8y-highlight>\n </c8y-li>\n </c8y-typeahead>\n <c8y-messages>\n <c8y-message\n name=\"notExisting\"\n [text]=\"(layout$ | async)?.providerNameNoMatchesHint | translate\"\n ></c8y-message>\n </c8y-messages>\n </c8y-form-group>\n <formly-form\n *ngIf=\"selectedProvider$ | async\"\n [form]=\"form\"\n [fields]=\"fields\"\n [model]=\"model\"\n [options]=\"options\"\n ></formly-form>\n </div>\n </div>\n <div class=\"card-footer separator\" *c8yIfAllowed=\"allRoles$ | async; allowAny\">\n <button\n *c8yIfAllowed=\"(layout$ | async)?.deleteRoles\"\n class=\"btn btn-default\"\n type=\"button\"\n (click)=\"deleteProviderConfiguration()\"\n [disabled]=\"\n !(configuration$ | async)?.provider && !(configuration$ | async)?.providerName\n \"\n title=\"{{ (layout$ | async)?.deleteBtnLabel | translate }}\"\n >\n {{ (layout$ | async)?.deleteBtnLabel | translate }}\n </button>\n <button\n *c8yIfAllowed=\"(layout$ | async)?.saveRoles\"\n class=\"btn btn-primary\"\n type=\"submit\"\n [disabled]=\"form.invalid || form.pristine\"\n title=\"{{ (layout$ | async)?.saveBtnLabel | translate }}\"\n >\n {{ (layout$ | async)?.saveBtnLabel | translate }}\n </button>\n </div>\n </form>\n </div>\n</div>\n" }]
}], ctorParameters: () => [{ type: i1.Permissions }, { type: i2.ActivatedRoute }, { type: i3.ModalService }, { type: i4.AlertService }, { type: i5.ProviderDefinitionsService }, { type: i6.ProviderConfigurationService }, { type: i7.C8yJSONSchema }] });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJvdmlkZXItY29uZmlndXJhdGlvbi5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9jb3JlL3Byb3ZpZGVyLWNvbmZpZ3VyYXRpb24vcHJvdmlkZXItY29uZmlndXJhdGlvbi5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi9jb3JlL3Byb3ZpZGVyLWNvbmZpZ3VyYXRpb24vcHJvdmlkZXItY29uZmlndXJhdGlvbi5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQzFDLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUMzQyxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFFakQsT0FBTyxFQUF3QyxpQkFBaUIsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQzNGLE9BQU8sRUFBRSxJQUFJLEVBQUUsTUFBTSxFQUFFLEdBQUcsRUFBRSxTQUFTLEVBQUUsSUFBSSxFQUFFLE1BQU0sV0FBVyxDQUFDO0FBQy9ELE9BQU8sRUFBRSxlQUFlLEVBQWMsT0FBTyxFQUFFLGFBQWEsRUFBRSxJQUFJLEVBQUUsS0FBSyxFQUFFLEVBQUUsRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUM1RixPQUFPLEVBQUUsVUFBVSxFQUFFLEdBQUcsRUFBRSxXQUFXLEVBQUUsU0FBUyxFQUFFLEdBQUcsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQzlFLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUN0RCxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQ3RELE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxzREFBc0QsQ0FBQztBQUNyRixPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFPdEQsT0FBTyxFQUFFLDRCQUE0QixF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dXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBvbmVudCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgRm9ybUdyb3VwIH0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xuaW1wb3J0IHsgQWN0aXZhdGVkUm91dGUgfSBmcm9tICdAYW5ndWxhci9yb3V0ZXInO1xuaW1wb3J0IHsgSVJlc3VsdCB9IGZyb20gJ0BjOHkvY2xpZW50JztcbmltcG9ydCB7IEZvcm1seUZpZWxkQ29uZmlnLCBGb3JtbHlGb3JtT3B0aW9ucywgybVkZWZpbmVIaWRkZW5Qcm9wIH0gZnJvbSAnQG5neC1mb3JtbHkvY29yZSc7XG5pbXBvcnQgeyBmaW5kLCBmb3JPd24sIGdldCwgbWFwVmFsdWVzLCBwaWNrIH0gZnJvbSAnbG9kYXNoLWVzJztcbmltcG9ydCB7IEJlaGF2aW9yU3ViamVjdCwgT2JzZXJ2YWJsZSwgU3ViamVjdCwgY29tYmluZUxhdGVzdCwgZnJvbSwgbWVyZ2UsIG9mIH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyBjYXRjaEVycm9yLCBtYXAsIHNoYXJlUmVwbGF5LCBzd2l0Y2hNYXAsIHRhcCB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcbmltcG9ydCB7IEFsZXJ0U2VydmljZSB9IGZyb20gJy4uL2FsZXJ0L2FsZXJ0LnNlcnZpY2UnO1xuaW1wb3J0IHsgUGVybWlzc2lvbnMsIFN0YXR1cyB9IGZyb20gJy4uL2NvbW1vbi9pbmRleCc7XG5pbXBvcnQgeyBDOHlKU09OU2NoZW1hIH0gZnJvbSAnLi4vZHluYW1pYy1mb3Jtcy9qc29uLXNjaGVtYS9jOHktanNvbi1zY2hlbWEuc2VydmljZSc7XG5pbXBvcnQgeyBNb2RhbFNlcnZpY2UgfSBmcm9tICcuLi9tb2RhbC9tb2RhbC5zZXJ2aWNlJztcbmltcG9ydCB7XG4gIER5bmFtaWNQcm92aWRlckNvbmZpZyxcbiAgRHluYW1pY1Byb3ZpZGVyTGF5b3V0Q29uZmlnXG59IGZyb20gJy4vbW9kZWwvZHluYW1pYy1wcm92aWRlci1jb25maWcubW9kZWwnO1xuaW1wb3J0IHsgUHJvdmlkZXJEZWZpbml0aW9uIH0gZnJvbSAnLi9tb2RlbC9wcm92aWRlci1kZWZpbml0aW9uLm1vZGVsJztcbmltcG9ydCB7IFByb3ZpZGVyUHJvcGVydGllcyB9IGZyb20gJy4vbW9kZWwvcHJvdmlkZXItcHJvcGVydGllcy5tb2RlbCc7XG5pbXBvcnQgeyBQcm92aWRlckNvbmZpZ3VyYXRpb25TZXJ2aWNlIH0gZnJvbSAnLi9zZXJ2aWNlL3Byb3ZpZGVyLWNvbmZpZ3VyYXRpb24uc2VydmljZSc7XG5pbXBvcnQgeyBQcm92aWRlckRlZmluaXRpb25zU2VydmljZSB9IGZyb20gJy4vc2VydmljZS9wcm92aWRlci1kZWZpbml0aW9ucy5zZXJ2aWNlJztcblxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnYzh5LXNtcy1nYXRld2F5JyxcbiAgdGVtcGxhdGVVcmw6ICcuL3Byb3ZpZGVyLWNvbmZpZ3VyYXRpb24uY29tcG9uZW50Lmh0bWwnLFxuICBwcm92aWRlcnM6IFtQcm92aWRlckNvbmZpZ3VyYXRpb25TZXJ2aWNlLCBQcm92aWRlckRlZmluaXRpb25zU2VydmljZV1cbn0pXG5leHBvcnQgY2xhc3MgUHJvdmlkZXJDb25maWd1cmF0aW9uQ29tcG9uZW50IHtcbiAgbGF5b3V0JDogT2JzZXJ2YWJsZTxEeW5hbWljUHJvdmlkZXJMYXlvdXRDb25maWc+ID0gdGhpcy5hY3RpdmF0ZWRSb3V0ZS5kYXRhLnBpcGUoXG4gICAgbWFwKChjb25maWc6IER5bmFtaWNQcm92aWRlckNvbmZpZykgPT4gY29uZmlnLmxheW91dCksXG4gICAgdGFwKChsYXlvdXQ6IER5bmFtaWNQcm92aWRlckxheW91dENvbmZpZykgPT4gKHRoaXMubGF5b3V0ID0gbGF5b3V0KSksXG4gICAgdGFwKChsYXlvdXQ6IER5bmFtaWNQcm92aWRlckxheW91dENvbmZpZykgPT4ge1xuICAgICAgdGhpcy5vcHRpb25zLmZvcm1TdGF0ZS5kaXNhYmxlZCA9ICF0aGlzLnBlcm1pc3Npb25zLmhhc0FsbFJvbGVzKGxheW91dC5zYXZlUm9sZXMgfHwgW10pO1xuICAgICAgdGhpcy5iZWZvcmVTYXZlSG9vayA9IGxheW91dC5iZWZvcmVTYXZlSG9vaztcbiAgICB9KVxuICApO1xuXG4gIGFsbFJvbGVzJDogT2JzZXJ2YWJsZTxzdHJpbmdbXT4gPSB0aGlzLmxheW91dCQucGlwZShcbiAgICBtYXAoKGxheW91dDogRHluYW1pY1Byb3ZpZGVyTGF5b3V0Q29uZmlnKSA9PiBbXG4gICAgICAuLi4obGF5b3V0LmRlbGV0ZVJvbGVzIHx8IFtdKSxcbiAgICAgIC4uLihsYXlvdXQuc2F2ZVJvbGVzIHx8IFtdKVxuICAgIF0pXG4gICk7XG5cbiAgcHJvdmlkZXJzJDogT2JzZXJ2YWJsZTxQcm92aWRlckRlZmluaXRpb25bXT47XG4gIHNlbGVjdGVkUHJvdmlkZXIkOiBPYnNlcnZhYmxlPFByb3ZpZGVyRGVmaW5pdGlvbj47XG4gIGNoYW5nZVByb3ZpZGVyJDogU3ViamVjdDxQcm92aWRlckRlZmluaXRpb24+ID0gbmV3IEJlaGF2aW9yU3ViamVjdChudWxsKTtcbiAgY29uZmlndXJhdGlvbiQ6IE9ic2VydmFibGU8UHJvdmlkZXJQcm9wZXJ0aWVzPjtcbiAgcHJvdmlkZXJJbnB1dCQgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PHN0cmluZz4oJycpO1xuXG4gIGZvcm0gPSBuZXcgRm9ybUdyb3VwKHt9KTtcbiAgbW9kZWw6IFByb3ZpZGVyUHJvcGVydGllcztcbiAgZmllbGRzOiBGb3JtbHlGaWVsZENvbmZpZ1tdID0gW107XG4gIG9wdGlvbnM6IEZvcm1seUZvcm1PcHRpb25zID0ge1xuICAgIGZvcm1TdGF0ZToge1xuICAgICAgZGlzYWJsZWQ6IGZhbHNlXG4gICAgfVxuICB9O1xuXG4gIHByaXZhdGUgcmVsb2FkJCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8dm9pZD4obnVsbCk7XG4gIHByaXZhdGUgdXBkYXRlZENvbmZpZ3VyYXRpb24kID0gbmV3IFN1YmplY3Q8UHJvdmlkZXJQcm9wZXJ0aWVzPigpO1xuICBwcml2YXRlIGxheW91dDogRHluYW1pY1Byb3ZpZGVyTGF5b3V0Q29uZmlnO1xuICBwcml2YXRlIGJlZm9yZVNhdmVIb29rOiAoXG4gICAgbW9kZWw6IFByb3ZpZGVyUHJvcGVydGllcyxcbiAgICBmaWVsZHM6IEZvcm1seUZpZWxkQ29uZmlnW11cbiAgKSA9PiBQcm9taXNlPFByb3ZpZGVyUHJvcGVydGllcz4gfCBQcm92aWRlclByb3BlcnRpZXM7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHVibGljIHBlcm1pc3Npb25zOiBQZXJtaXNzaW9ucyxcbiAgICBwcml2YXRlIGFjdGl2YXRlZFJvdXRlOiBBY3RpdmF0ZWRSb3V0ZSxcbiAgICBwcml2YXRlIG1vZGFsU2VydmljZTogTW9kYWxTZXJ2aWNlLFxuICAgIHByaXZhdGUgYWxlcnRTZXJ2aWNlOiBBbGVydFNlcnZpY2UsXG4gICAgcHJpdmF0ZSBwcm92aWRlckRlZmluaXRpb25zU2VydmljZTogUHJvdmlkZXJEZWZpbml0aW9uc1NlcnZpY2UsXG4gICAgcHJpdmF0ZSBwcm92aWRlckNvbmZpZ3VyYXRpb25TZXJ2aWNlOiBQcm92aWRlckNvbmZpZ3VyYXRpb25TZXJ2aWNlLFxuICAgIHByaXZhdGUganNvbnNjaGVtYTogQzh5SlNPTlNjaGVtYVxuICApIHt9XG5cbiAgbmdPbkluaXQoKSB7XG4gICAgY29uc3QgYWxsUHJvdmlkZXJzJDogT2JzZXJ2YWJsZTxQcm92aWRlckRlZmluaXRpb25bXT4gPSBmcm9tKFxuICAgICAgdGhpcy5wcm92aWRlckRlZmluaXRpb25zU2VydmljZS5saXN0KClcbiAgICApLnBpcGUoXG4gICAgICBtYXAocmVzdWx0ID0+IHJlc3VsdC5kYXRhKSxcbiAgICAgIHNoYXJlUmVwbGF5KDEpXG4gICAgKTtcblxuICAgIHRoaXMucHJvdmlkZXJzJCA9IGNvbWJpbmVMYXRlc3QoYWxsUHJvdmlkZXJzJCwgdGhpcy5wcm92aWRlcklucHV0JCkucGlwZShcbiAgICAgIG1hcCgoW3Byb3ZpZGVycywgaW5wdXRdOiBbUHJvdmlkZXJEZWZpbml0aW9uW10sIHN0cmluZ10pID0+XG4gICAgICAgIGlucHV0XG4gICAgICAgICAgPyBwcm92aWRlcnMuZmlsdGVyKGVsID0+IGVsLmRpc3BsYXlOYW1lLnRvTG93ZXJDYXNlKCkuaW5kZXhPZihpbnB1dC50b0xvd2VyQ2FzZSgpKSA+PSAwKVxuICAgICAgICAgIDogcHJvdmlkZXJzXG4gICAgICApLFxuICAgICAgc2hhcmVSZXBsYXkoMSlcbiAgICApO1xuXG4gICAgdGhpcy5jb25maWd1cmF0aW9uJCA9IG1lcmdlKFxuICAgICAgdGhpcy51cGRhdGVkQ29uZmlndXJhdGlvbiQsXG4gICAgICB0aGlzLnJlbG9hZCQucGlwZShcbiAgICAgICAgc3dpdGNoTWFwKCgpID0+XG4gICAgICAgICAgZnJvbSh0aGlzLnByb3ZpZGVyQ29uZmlndXJhdGlvblNlcnZpY2UuZGV0YWlsKCkpLnBpcGUoY2F0Y2hFcnJvcigoKSA9PiBvZih7fSBhcyBhbnkpKSlcbiAgICAgICAgKSxcbiAgICAgICAgbWFwKHJlc3VsdCA9PiByZXN1bHQuZGF0YSlcbiAgICAgIClcbiAgICApLnBpcGUobWFwKHRoaXMucmVtb3ZlRW5jcnlwdGVkVmFsdWVzKSwgc2hhcmVSZXBsYXkoMSkpO1xuXG4gICAgdGhpcy5zZWxlY3RlZFByb3ZpZGVyJCA9IGNvbWJpbmVMYXRlc3QoXG4gICAgICBhbGxQcm92aWRlcnMkLFxuICAgICAgdGhpcy5jb25maWd1cmF0aW9uJCxcbiAgICAgIHRoaXMuY2hhbmdlUHJvdmlkZXIkXG4gICAgKS5waXBlKFxuICAgICAgdGFwKFxuICAgICAgICAoW18sIGNvbmZpZ3VyYXRpb24sIG5ld1Byb3ZpZGVyXTogW1xuICAgICAgICAgIFByb3ZpZGVyRGVmaW5pdGlvbltdLFxuICAgICAgICAgIFByb3ZpZGVyUHJvcGVydGllcyxcbiAgICAgICAgICBQcm92aWRlckRlZmluaXRpb25cbiAgICAgICAgXSkgPT5cbiAgICAgICAgICAodGhpcy5tb2RlbCA9IG5ld1Byb3ZpZGVyXG4gICAgICAgICAgICA/IHBpY2sodGhpcy5tb2RlbCwgJ3Ntcy5zZW5kZXJOYW1lJywgJ3Ntcy5zZW5kZXJBZGRyZXNzJylcbiAgICAgICAgICAgIDogY29uZmlndXJhdGlvbilcbiAgICAgICksXG4gICAgICBtYXAoXG4gICAgICAgIChbcHJvdmlkZXJzLCBjb25maWd1cmF0aW9uLCBuZXdQcm92aWRlcl06IFtcbiAgICAgICAgICBQcm92aWRlckRlZmluaXRpb25bXSxcbiAgICAgICAgICBQcm92aWRlclByb3BlcnRpZXMsXG4gICAgICAgICAgUHJvdmlkZXJEZWZpbml0aW9uXG4gICAgICAgIF0pID0+XG4gICAgICAgICAgbmV3UHJvdmlkZXIgfHxcbiAgICAgICAgICBmaW5kKFxuICAgICAgICAgICAgcHJvdmlkZXJzLFxuICAgICAgICAgICAgKHByb3ZpZGVyOiBQcm92aWRlckRlZmluaXRpb24pID0+IGdldChjb25maWd1cmF0aW9uLCAncHJvdmlkZXInKSA9PT0gcHJvdmlkZXIuaWRcbiAgICAgICAgICApXG4gICAgICApLFxuICAgICAgdGFwKChwcm92aWRlcjogUHJvdmlkZXJEZWZpbml0aW9uKSA9PiB7XG4gICAgICAgIGlmIChwcm92aWRlcikge1xuICAgICAgICAgIGNvbnN0IGNvbmZpZzogRm9ybWx5RmllbGRDb25maWcgPSB0aGlzLmpzb25zY2hlbWEudG9GaWVsZENvbmZpZyhnZXQocHJvdmlkZXIsICdzY2hlbWEnKSk7XG4gICAgICAgICAgaWYgKGNvbmZpZy5maWVsZEdyb3VwKSB7XG4gICAgICAgICAgICBjb25maWcuZmllbGRHcm91cC5mb3JFYWNoKChmaWVsZENvbmZpZzogRm9ybWx5RmllbGRDb25maWcpID0+IHtcbiAgICAgICAgICAgICAgybVkZWZpbmVIaWRkZW5Qcm9wKGZpZWxkQ29uZmlnLCAnX2tleVBhdGgnLCB7XG4gICAgICAgICAgICAgICAga2V5OiBmaWVsZENvbmZpZy5rZXksXG4gICAgICAgICAgICAgICAgcGF0aDogW2ZpZWxkQ29uZmlnLmtleV1cbiAgICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgICAgZmllbGRDb25maWcuZXhwcmVzc2lvblByb3BlcnRpZXMgPSB7XG4gICAgICAgICAgICAgICAgJ3RlbXBsYXRlT3B0aW9ucy5kaXNhYmxlZCc6ICdmb3JtU3RhdGUuZGlzYWJsZWQnXG4gICAgICAgICAgICAgIH07XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9XG4gICAgICAgICAgdGhpcy5maWVsZHMgPSBbY29uZmlnXTtcbiAgICAgICAgICB0aGlzLmZvcm0gPSBuZXcgRm9ybUdyb3VwKHt9KTtcbiAgICAgICAgfVxuICAgICAgfSksXG4gICAgICBzaGFyZVJlcGxheSgxKVxuICAgICk7XG4gIH1cblxuICBhc3luYyBzYXZlUHJvdmlkZXJDb25maWd1cmF0aW9uKCkge1xuICAgIGNvbnN0IG1vZGVsVG9TYXZlOiBQcm92aWRlclByb3BlcnRpZXMgPSAhIXRoaXMuYmVmb3JlU2F2ZUhvb2tcbiAgICAgID8gYXdhaXQgdGhpcy5iZWZvcmVTYXZlSG9vayh0aGlzLm1vZGVsLCB0aGlzLmZpZWxkcylcbiAgICAgIDogdGhpcy5tb2RlbDtcblxuICAgIGZvck93bihtb2RlbFRvU2F2ZSwgKHZhbHVlOiBhbnksIGtleTogc3RyaW5nKSA9PiB7XG4gICAgICBpZiAoQXJyYXkuaXNBcnJheSh2YWx1ZSkpIHtcbiAgICAgICAgbW9kZWxUb1NhdmVba2V5XSA9IHZhbHVlXG4gICAgICAgICAgLmZpbHRlcihpdGVtID0+ICEhaXRlbSB8fCBpdGVtID09PSAwKVxuICAgICAgICAgIC5tYXAoaXRlbSA9PiAodHlwZW9mIGl0ZW0gPT09ICdzdHJpbmcnID8gaXRlbS50cmltKCkgOiBpdGVtKSk7XG4gICAgICB9IGVsc2UgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgbW9kZWxUb1NhdmVba2V5XSA9IHZhbHVlLnRyaW0oKTtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIHRyeSB7XG4gICAgICBjb25zdCByZXM6IElSZXN1bHQ8UHJvdmlkZXJQcm9wZXJ0aWVzPiA9XG4gICAgICAgIGF3YWl0IHRoaXMucHJvdmlkZXJDb25maWd1cmF0aW9uU2VydmljZS51cGRhdGUobW9kZWxUb1NhdmUpO1xuICAgICAgdGhpcy5jaGFuZ2VQcm92aWRlciQubmV4dChudWxsKTtcbiAgICAgIHRoaXMudXBkYXRlZENvbmZpZ3VyYXRpb24kLm5leHQocmVzLmRhdGEpO1xuICAgICAgdGhpcy5hbGVydFNlcnZpY2Uuc3VjY2Vzcyh0aGlzLmxheW91dC5jb25maWd1cmF0aW9uVXBkYXRlZFN1Y2Nlc3NNc2cpO1xuICAgICAgdGhpcy5mb3JtLm1hcmtBc1ByaXN0aW5lKCk7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICB0aGlzLmFsZXJ0U2VydmljZS5hZGRTZXJ2ZXJGYWlsdXJlKGVycik7XG4gICAgfVxuICB9XG5cbiAgYXN5bmMgZGVsZXRlUHJvdmlkZXJDb25maWd1cmF0aW9uKCkge1xuICAgIHRyeSB7XG4gICAgICBhd2FpdCB0aGlzLm1vZGFsU2VydmljZS5jb25maXJtKFxuICAgICAgICB0aGlzLmxheW91dC5kZWxldGVDb25maWd1cmF0aW9uTW9kYWxUaXRsZSxcbiAgICAgICAgdGhpcy5sYXlvdXQuZGVsZXRlQ29uZmlndXJhdGlvbk1vZGFsQm9keSxcbiAgICAgICAgU3RhdHVzLkRBTkdFUixcbiAgICAgICAge1xuICAgICAgICAgIG9rOiB0aGlzLmxheW91dC5kZWxldGVDb25maWd1cmF0aW9uTW9kYWxPa0J0bkxhYmVsLFxuICAgICAgICAgIGNhbmNlbDogdGhpcy5sYXlvdXQuZGVsZXRlQ29uZmlndXJhdGlvbk1vZGFsQ2FuY2VsQnRuTGFiZWxcbiAgICAgICAgfVxuICAgICAgKTtcbiAgICAgIGF3YWl0IHRoaXMucHJvdmlkZXJDb25maWd1cmF0aW9uU2VydmljZS5kZWxldGUoKTtcbiAgICAgIHRoaXMucmVsb2FkJC5uZXh0KCk7XG4gICAgICB0aGlzLmFsZXJ0U2VydmljZS5zdWNjZXNzKHRoaXMubGF5b3V0LmNvbmZpZ3VyYXRpb25EZWxldGVkU3VjY2Vzc01zZyk7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICBpZiAoZXJyKSB7XG4gICAgICAgIHRoaXMuYWxlcnRTZXJ2aWNlLmFkZFNlcnZlckZhaWx1cmUoZXJyKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBwcml2YXRlIHJlbW92ZUVuY3J5cHRlZFZhbHVlcyhjb25maWd1cmF0aW9uOiBQcm92aWRlclByb3BlcnRpZXMpOiBQcm92aWRlclByb3BlcnRpZXMge1xuICAgIHJldHVybiBtYXBWYWx1ZXMoY29uZmlndXJhdGlvbiwgdmFsdWUgPT4gKHZhbHVlID09PSAnPDxFbmNyeXB0ZWQ+PicgPyB1bmRlZmluZWQgOiB2YWx1ZSkpO1xuICB9XG59XG4iLCI8Yzh5LXRpdGxlPlxuICB7eyAobGF5b3V0JCB8IGFzeW5jKT8ucGFnZVRpdGxlIHwgdHJhbnNsYXRlIH19XG48L2M4eS10aXRsZT5cblxuPGM4eS1icmVhZGNydW1iPlxuICA8Yzh5LWJyZWFkY3J1bWItaXRlbVxuICAgIFtsYWJlbF09XCInU2V0dGluZ3MnIHwgdHJhbnNsYXRlXCJcbiAgICBbaWNvbl09XCInY29nJ1wiXG4gID48L2M4eS1icmVhZGNydW1iLWl0ZW0+XG4gIDxjOHktYnJlYWRjcnVtYi1pdGVtICpuZ0lmPVwiKGxheW91dCQgfCBhc3luYyk/LnBhZ2VUaXRsZSAhPSdDb25uZWN0aXZpdHknXCJcbiAgICBbbGFiZWxdPVwiJ1NNUyBwcm92aWRlcicgfCB0cmFuc2xhdGVcIlxuICAgIFtpY29uXT1cIidjb2cnXCJcbiAgPjwvYzh5LWJyZWFkY3J1bWItaXRlbT5cbiAgPGM4eS1icmVhZGNydW1iLWl0ZW0gKm5nSWY9XCIobGF5b3V0JCB8IGFzeW5jKT8ucGFnZVRpdGxlID09J0Nvbm5lY3Rpdml0eSdcIlxuICAgIFtsYWJlbF09XCInQ29ubmVjdGl2aXR5JyB8IHRyYW5zbGF0ZVwiXG4gICAgW2ljb25dPVwiJ2NvZydcIlxuICA+PC9jOHktYnJlYWRjcnVtYi1pdGVtPlxuICA8Yzh5LWJyZWFkY3J1bWItaXRlbSAqbmdJZj1cIihsYXlvdXQkIHwgYXN5bmMpPy5wYWdlVGl0bGUgPT0nQ29ubmVjdGl2aXR5J1wiXG4gICAgW2ljb25dPVwiJ2NvZydcIlxuICAgIFtsYWJlbF09XCInU0lNIHByb3ZpZGVyIHNldHRpbmdzJyB8IHRyYW5zbGF0ZVwiXG4gID48L2M4eS1icmVhZGNydW1iLWl0ZW0+XG48L2M4eS1icmVhZGNydW1iPlxuXG48ZGl2IGNsYXNzPVwicm93XCI+XG4gIDxkaXYgY2xhc3M9XCJjb2wtbWQtOCBjb2wteHMtMTJcIj5cbiAgICA8Zm9ybSBjbGFzcz1cImNhcmQgY2FyZC0tZnVsbHBhZ2VcIiAobmdTdWJtaXQpPVwic2F2ZVByb3ZpZGVyQ29uZmlndXJhdGlvbigpXCI+XG4gICAgICA8ZGl2IGNsYXNzPVwiY2FyZC1oZWFkZXIgc2VwYXJhdG9yXCI+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJjYXJkLXRpdGxlXCI+XG4gICAgICAgICAge3sgKGxheW91dCQgfCBhc3luYyk/LmNhcmRUaXRsZSB8IHRyYW5zbGF0ZSB9fVxuICAgICAgICA8L2Rpdj5cbiAgICAgIDwvZGl2PlxuICAgICAgPGRpdiBjbGFzcz1cImlubmVyLXNjcm9sbFwiPlxuICAgICAgICA8ZGl2IGNsYXNzPVwiY2FyZC1ibG9ja1wiPlxuICAgICAgICAgIDxwICpuZ0lmPVwiISEobGF5b3V0JCB8IGFzeW5jKT8uZGVzY3JpcHRpb25cIiBjbGFzcz1cIm0tYi04XCI+XG4gICAgICAgICAgICB7eyAobGF5b3V0JCB8IGFzeW5jKT8uZGVzY3JpcHRpb24gfCB0cmFuc2xhdGUgfX1cbiAgICAgICAgICA8L3A+XG4gICAgICAgICAgPGM4eS1mb3JtLWdyb3VwPlxuICAgICAgICAgICAgPGxhYmVsIGZvcj1cInByb3ZpZGVyTmFtZVwiPnt7IChsYXlvdXQkIHwgYXN5bmMpPy5wcm92aWRlck5hbWUgfCB0cmFuc2xhdGUgfX08L2xhYmVsPlxuICAgICAgICAgICAgPGM4eS10eXBlYWhlYWRcbiAgICAgICAgICAgICAgW2Rpc2FibGVkXT1cIiFwZXJtaXNzaW9ucy5oYXNBbGxSb2xlcygobGF5b3V0JCB8IGFzeW5jKT8uc2F2ZVJvbGVzIHx8IFtdKVwiXG4gICAgICAgICAgICAgIFtuZ01vZGVsXT1cInNlbGVjdGVkUHJvdmlkZXIkIHwgYXN5bmNcIlxuICAgICAgICAgICAgICBbZGlzcGxheVByb3BlcnR5XT1cIidkaXNwbGF5TmFtZSdcIlxuICAgICAgICAgICAgICBuYW1lPVwicHJvdmlkZXJOYW1lXCJcbiAgICAgICAgICAgICAgcGxhY2Vob2xkZXI9XCJ7eyAobGF5b3V0JCB8IGFzeW5jKT8ucHJvdmlkZXJOYW1lUGxhY2Vob2xkZXIgfCB0cmFuc2xhdGUgfX1cIlxuICAgICAgICAgICAgICAob25TZWFyY2gpPVwicHJvdmlkZXJJbnB1dCQubmV4dCgkZXZlbnQpXCJcbiAgICAgICAgICAgICAgW2FsbG93RnJlZUVudHJpZXNdPVwiZmFsc2VcIlxuICAgICAgICAgICAgICBbcmVxdWlyZWRdPVwidHJ1ZVwiXG4gICAgICAgICAgICAgIFtjb250YWluZXJdPVwiJ2JvZHknXCJcbiAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgPGM4eS1saVxuICAgICAgICAgICAgICAgICpuZ0Zvcj1cImxldCBwcm92aWRlciBvZiBwcm92aWRlcnMkIHwgYXN5bmNcIlxuICAgICAgICAgICAgICAgIGNsYXNzPVwicC1sLTggcC1yLTggYzh5LWxpc3RfX2l0ZW0tLWxpbmtcIlxuICAgICAgICAgICAgICAgIChjbGljayk9XCJjaGFuZ2VQcm92aWRlciQubmV4dChwcm92aWRlcik7IHByb3ZpZGVySW5wdXQkLm5leHQoJycpXCJcbiAgICAgICAgICAgICAgICBbYWN0aXZlXT1cIihzZWxlY3RlZFByb3ZpZGVyJCB8IGFzeW5jKSA9PT0gcHJvdmlkZXJcIlxuICAgICAgICAgICAgICAgIFthdHRyLnJvbGVdPVwiJ21lbnVpdGVtJ1wiXG4gICAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgICA8Yzh5LWhpZ2hsaWdodFxuICAgICAgICAgICAgICAgICAgW3RleHRdPVwicHJvdmlkZXIuZGlzcGxheU5hbWUgfHwgJy0tJ1wiXG4gICAgICAgICAgICAgICAgICBbcGF0dGVybl09XCJwcm92aWRlcklucHV0JCB8IGFzeW5jXCJcbiAgICAgICAgICAgICAgICA+PC9jOHktaGlnaGxpZ2h0PlxuICAgICAgICAgICAgICA8L2M4eS1saT5cbiAgICAgICAgICAgIDwvYzh5LXR5cGVhaGVhZD5cbiAgICAgICAgICAgIDxjOHktbWVzc2FnZXM+XG4gICAgICAgICAgICAgIDxjOHktbWVzc2FnZVxuICAgICAgICAgICAgICAgIG5hbWU9XCJub3RFeGlzdGluZ1wiXG4gICAgICAgICAgICAgICAgW3RleHRdPVwiKGxheW91dCQgfCBhc3luYyk/LnByb3ZpZGVyTmFtZU5vTWF0Y2hlc0hpbnQgfCB0cmFuc2xhdGVcIlxuICAgICAgICAgICAgICA+PC9jOHktbWVzc2FnZT5cbiAgICAgICAgICAgIDwvYzh5LW1lc3NhZ2VzPlxuICAgICAgICAgIDwvYzh5LWZvcm0tZ3JvdXA+XG4gICAgICAgICAgPGZvcm1seS1mb3JtXG4gICAgICAgICAgICAqbmdJZj1cInNlbGVjdGVkUHJvdmlkZXIkIHwgYXN5bmNcIlxuICAgICAgICAgICAgW2Zvcm1dPVwiZm9ybVwiXG4gICAgICAgICAgICBbZmllbGRzXT1cImZpZWxkc1wiXG4gICAgICAgICAgICBbbW9kZWxdPVwibW9kZWxcIlxuICAgICAgICAgICAgW29wdGlvbnNdPVwib3B0aW9uc1wiXG4gICAgICAgICAgPjwvZm9ybWx5LWZvcm0+XG4gICAgICAgIDwvZGl2PlxuICAgICAgPC9kaXY+XG4gICAgICA8ZGl2IGNsYXNzPVwiY2FyZC1mb290ZXIgc2VwYXJhdG9yXCIgKmM4eUlmQWxsb3dlZD1cImFsbFJvbGVzJCB8IGFzeW5jOyBhbGxvd0FueVwiPlxuICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgKmM4eUlmQWxsb3dlZD1cIihsYXlvdXQkIHwgYXN5bmMpPy5kZWxldGVSb2xlc1wiXG4gICAgICAgICAgY2xhc3M9XCJidG4gYnRuLWRlZmF1bHRcIlxuICAgICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICAgIChjbGljayk9XCJkZWxldGVQcm92aWRlckNvbmZpZ3VyYXRpb24oKVwiXG4gICAgICAgICAgW2Rpc2FibGVkXT1cIlxuICAgICAgICAgICAgIShjb25maWd1cmF0aW9uJCB8IGFzeW5jKT8ucHJvdmlkZXIgJiYgIShjb25maWd1cmF0aW9uJCB8IGFzeW5jKT8ucHJvdmlkZXJOYW1lXG4gICAgICAgICAgXCJcbiAgICAgICAgICB0aXRsZT1cInt7IChsYXlvdXQkIHwgYXN5bmMpPy5kZWxldGVCdG5MYWJlbCB8IHRyYW5zbGF0ZSB9fVwiXG4gICAgICAgID5cbiAgICAgICAgICB7eyAobGF5b3V0JCB8IGFzeW5jKT8uZGVsZXRlQnRuTGFiZWwgfCB0cmFuc2xhdGUgfX1cbiAgICAgICAgPC9idXR0b24+XG4gICAgICAgIDxidXR0b25cbiAgICAgICAgICAqYzh5SWZBbGxvd2VkPVwiKGxheW91dCQgfCBhc3luYyk/LnNhdmVSb2xlc1wiXG4gICAgICAgICAgY2xhc3M9XCJidG4gYnRuLXByaW1hcnlcIlxuICAgICAgICAgIHR5cGU9XCJzdWJtaXRcIlxuICAgICAgICAgIFtkaXNhYmxlZF09XCJmb3JtLmludmFsaWQgfHwgZm9ybS5wcmlzdGluZVwiXG4gICAgICAgICAgdGl0bGU9XCJ7eyAobGF5b3V0JCB8IGFzeW5jKT8uc2F2ZUJ0bkxhYmVsIHwgdHJhbnNsYXRlIH19XCJcbiAgICAgICAgPlxuICAgICAgICAgIHt7IChsYXlvdXQkIHwgYXN5bmMpPy5zYXZlQnRuTGFiZWwgfCB0cmFuc2xhdGUgfX1cbiAgICAgICAgPC9idXR0b24+XG4gICAgICA8L2Rpdj5cbiAgICA8L2Zvcm0+XG4gIDwvZGl2PlxuPC9kaXY+XG4iXX0=