@c8y/ngx-components
Version:
Angular modules for Cumulocity IoT applications
106 lines • 33.3 kB
JavaScript
import { Component, EventEmitter, ViewChild } from '@angular/core';
import { ApplicationService, UserGroupService, TenantLoginOptionType, InventoryRoleService } from '@c8y/client';
import { gettext, AlertService, ModalService, Status, LoginService, AppStateService, TenantUiService } from '@c8y/ngx-components';
import { BehaviorSubject, forkJoin, Subject } from 'rxjs';
import { shareReplay, tap, switchMap } from 'rxjs/operators';
import { TemplateType, templateTypeConfig } from './sso-configuration.model';
import { SsoConfigurationService } from './sso-configuration.service';
import { NgForm } from '@angular/forms';
import * as i0 from "@angular/core";
import * as i1 from "./sso-configuration.service";
import * as i2 from "@c8y/client";
import * as i3 from "@c8y/ngx-components";
import * as i4 from "@angular/common";
import * as i5 from "@angular/forms";
import * as i6 from "./templates/custom-template.component";
import * as i7 from "./templates/key-cloak-template.component";
import * as i8 from "./templates/aad-template.component";
export class SsoConfigurationComponent {
constructor(ssoConfigurationService, applicationService, userGroupService, inventoryRoleService, alertService, modalService, loginService, appStateService, tenantUiService) {
this.ssoConfigurationService = ssoConfigurationService;
this.applicationService = applicationService;
this.userGroupService = userGroupService;
this.inventoryRoleService = inventoryRoleService;
this.alertService = alertService;
this.modalService = modalService;
this.loginService = loginService;
this.appStateService = appStateService;
this.tenantUiService = tenantUiService;
this.templateType = TemplateType;
this.templateTypeConfig = templateTypeConfig;
this.reloading$ = new BehaviorSubject(false);
this.reload = new EventEmitter();
this.saveSubject = new Subject();
this.data$ = this.reload.pipe(tap(() => this.reloading$.next(true)), switchMap(() => forkJoin({
ssoConfiguration: this.ssoConfigurationService.getSsoConfiguration$(),
apps: this.getApplications(),
groups: this.getGroups(),
inventoryRoles: this.getInventoryRoles()
})), tap(() => this.reloading$.next(false)), shareReplay(1));
}
ngOnInit() {
this.dataSubscription = this.data$.subscribe(({ ssoConfiguration, apps, groups, inventoryRoles }) => {
this.apps = apps;
this.groups = groups;
this.inventoryRoles = inventoryRoles;
this.ssoConfiguration = ssoConfiguration;
});
this.loadSsoConfiguration();
}
ngOnDestroy() {
this.dataSubscription.unsubscribe();
}
loadSsoConfiguration() {
this.reload.next();
this.ssoConfigurationForm.form.markAsPristine();
}
async save(ssoConfiguration) {
try {
await this.warnAboutForceUsersLogOut();
const logoutRequired = this.tenantUiService.getCurrentUserLoginMode() !== TenantLoginOptionType.BASIC;
if (logoutRequired) {
await this.modalService.confirmLogout();
}
await this.ssoConfigurationService.save(ssoConfiguration);
if (logoutRequired) {
await this.loginService.logout(true);
}
else {
this.loadSsoConfiguration();
this.alertService.success(gettext('Configuration saved.'));
}
}
catch (ex) {
if (ex) {
this.alertService.addServerFailure(ex);
}
else {
this.loadSsoConfiguration();
}
}
}
getApplications() {
return this.applicationService.listByTenant(null, { pageSize: 100 }).then(res => res.data, error => this.alertService.addServerFailure(error));
}
getGroups() {
return this.userGroupService.list({ pageSize: 100 }).then(res => res.data, error => this.alertService.addServerFailure(error));
}
getInventoryRoles() {
return this.inventoryRoleService.list({ pageSize: 100 }).then(res => res.data, error => this.alertService.addServerFailure(error));
}
async warnAboutForceUsersLogOut() {
const modalLabels = { ok: gettext('Update and log out users'), cancel: gettext('Cancel') };
const modalBody = gettext('Updating SSO configuration will log out all users logged with "OAI-Secure" or "Single sign-on redirect". Do you want to proceed?');
return await this.modalService.confirm(gettext('Force users to log out'), modalBody, Status.WARNING, modalLabels);
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SsoConfigurationComponent, deps: [{ token: i1.SsoConfigurationService }, { token: i2.ApplicationService }, { token: i2.UserGroupService }, { token: i2.InventoryRoleService }, { token: i3.AlertService }, { token: i3.ModalService }, { token: i3.LoginService }, { token: i3.AppStateService }, { token: i3.TenantUiService }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: SsoConfigurationComponent, selector: "c8y-sso-configuration", viewQueries: [{ propertyName: "ssoConfigurationForm", first: true, predicate: ["ssoConfigurationForm"], descendants: true }], ngImport: i0, template: "<c8y-title>{{ 'Single sign-on' | translate }}</c8y-title>\n<c8y-breadcrumb>\n <c8y-breadcrumb-item\n [icon]=\"'cog'\"\n [label]=\"'Settings' | translate\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item\n [icon]=\"'cog'\"\n [label]=\"'Single sign-on' | translate\"\n ></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<c8y-action-bar-item [placement]=\"'right'\">\n <button\n class=\"btn btn-link\"\n title=\"{{ 'Reload' | translate }}\"\n type=\"button\"\n (click)=\"loadSsoConfiguration()\"\n >\n <i\n c8yIcon=\"refresh\"\n [ngClass]=\"{ 'icon-spin': reloading$ | async }\"\n ></i>\n {{ 'Reload' | translate }}\n </button>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item\n [placement]=\"'left'\"\n itemClass=\"navbar-form hidden-xs\"\n>\n <div\n class=\"form-group\"\n title=\"{{ 'Template' | translate }}\"\n >\n <label\n class=\"control-label\"\n for=\"template\"\n >\n {{ 'Template' | translate }}\n </label>\n <div class=\"c8y-select-wrapper\">\n <select\n class=\"form-control\"\n id=\"template\"\n name=\"template\"\n *ngIf=\"ssoConfiguration\"\n [(ngModel)]=\"ssoConfiguration.template\"\n >\n <option\n *ngFor=\"let templateType of templateTypeConfig | keyvalue\"\n [ngValue]=\"templateType.key\"\n >\n {{ templateType.value.label | translate }}\n </option>\n </select>\n <span></span>\n </div>\n </div>\n</c8y-action-bar-item>\n\n<div class=\"row\">\n <div class=\"col-lg-12 col-lg-max\">\n <form\n class=\"card card--fullpage\"\n #ssoConfigurationForm=\"ngForm\"\n novalidate\n >\n <div class=\"card-header separator\">\n <div class=\"card-title\">\n {{ 'Single sign-on' | translate }}\n </div>\n </div>\n\n <div class=\"inner-scroll\">\n <div\n class=\"card-block p-0\"\n *ngIf=\"ssoConfiguration\"\n >\n <c8y-custom-template\n *ngIf=\"ssoConfiguration.template === templateType.CUSTOM\"\n [ssoConfiguration]=\"ssoConfiguration\"\n [ssoConfigurationChangeTrigger]=\"saveSubject.asObservable()\"\n (ssoConfigurationChange)=\"save($event)\"\n [apps]=\"apps\"\n [groups]=\"groups\"\n [inventoryRoles]=\"inventoryRoles\"\n ></c8y-custom-template>\n\n <c8y-aad-template\n *ngIf=\"ssoConfiguration.template === templateType.AZURE\"\n [ssoConfiguration]=\"ssoConfiguration\"\n [ssoConfigurationChangeTrigger]=\"saveSubject.asObservable()\"\n (ssoConfigurationChange)=\"save($event)\"\n [apps]=\"apps\"\n [groups]=\"groups\"\n [inventoryRoles]=\"inventoryRoles\"\n ></c8y-aad-template>\n\n <c8y-key-cloak-template\n *ngIf=\"ssoConfiguration.template === templateType.KEYCLOAK\"\n [ssoConfiguration]=\"ssoConfiguration\"\n [ssoConfigurationChangeTrigger]=\"saveSubject.asObservable()\"\n (ssoConfigurationChange)=\"save($event)\"\n [apps]=\"apps\"\n [groups]=\"groups\"\n [inventoryRoles]=\"inventoryRoles\"\n ></c8y-key-cloak-template>\n </div>\n </div>\n <div class=\"card-footer separator\">\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Save' | translate }}\"\n type=\"submit\"\n (click)=\"saveSubject.next()\"\n [disabled]=\"!ssoConfigurationForm.form.valid || ssoConfigurationForm.form.pristine\"\n >\n {{ 'Save' | translate }}\n </button>\n </div>\n </form>\n </div>\n</div>\n", dependencies: [{ kind: "component", type: i3.ActionBarItemComponent, selector: "c8y-action-bar-item", inputs: ["placement", "priority", "itemClass", "injector", "groupId", "inGroupPriority"] }, { kind: "component", type: i3.BreadcrumbComponent, selector: "c8y-breadcrumb" }, { kind: "component", type: i3.BreadcrumbItemComponent, selector: "c8y-breadcrumb-item", inputs: ["icon", "translate", "label", "path", "injector"] }, { kind: "directive", type: i3.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { 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: "component", type: i3.TitleComponent, selector: "c8y-title", inputs: ["pageTitleUpdate"] }, { kind: "directive", type: i5.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i5.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i5.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i5.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i5.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i5.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i5.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i5.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: i6.CustomTemplateComponent, selector: "c8y-custom-template" }, { kind: "component", type: i7.KeyCloakTemplateComponent, selector: "c8y-key-cloak-template" }, { kind: "component", type: i8.AadTemplateComponent, selector: "c8y-aad-template" }, { kind: "pipe", type: i3.C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: i4.AsyncPipe, name: "async" }, { kind: "pipe", type: i4.KeyValuePipe, name: "keyvalue" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SsoConfigurationComponent, decorators: [{
type: Component,
args: [{ selector: 'c8y-sso-configuration', template: "<c8y-title>{{ 'Single sign-on' | translate }}</c8y-title>\n<c8y-breadcrumb>\n <c8y-breadcrumb-item\n [icon]=\"'cog'\"\n [label]=\"'Settings' | translate\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item\n [icon]=\"'cog'\"\n [label]=\"'Single sign-on' | translate\"\n ></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<c8y-action-bar-item [placement]=\"'right'\">\n <button\n class=\"btn btn-link\"\n title=\"{{ 'Reload' | translate }}\"\n type=\"button\"\n (click)=\"loadSsoConfiguration()\"\n >\n <i\n c8yIcon=\"refresh\"\n [ngClass]=\"{ 'icon-spin': reloading$ | async }\"\n ></i>\n {{ 'Reload' | translate }}\n </button>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item\n [placement]=\"'left'\"\n itemClass=\"navbar-form hidden-xs\"\n>\n <div\n class=\"form-group\"\n title=\"{{ 'Template' | translate }}\"\n >\n <label\n class=\"control-label\"\n for=\"template\"\n >\n {{ 'Template' | translate }}\n </label>\n <div class=\"c8y-select-wrapper\">\n <select\n class=\"form-control\"\n id=\"template\"\n name=\"template\"\n *ngIf=\"ssoConfiguration\"\n [(ngModel)]=\"ssoConfiguration.template\"\n >\n <option\n *ngFor=\"let templateType of templateTypeConfig | keyvalue\"\n [ngValue]=\"templateType.key\"\n >\n {{ templateType.value.label | translate }}\n </option>\n </select>\n <span></span>\n </div>\n </div>\n</c8y-action-bar-item>\n\n<div class=\"row\">\n <div class=\"col-lg-12 col-lg-max\">\n <form\n class=\"card card--fullpage\"\n #ssoConfigurationForm=\"ngForm\"\n novalidate\n >\n <div class=\"card-header separator\">\n <div class=\"card-title\">\n {{ 'Single sign-on' | translate }}\n </div>\n </div>\n\n <div class=\"inner-scroll\">\n <div\n class=\"card-block p-0\"\n *ngIf=\"ssoConfiguration\"\n >\n <c8y-custom-template\n *ngIf=\"ssoConfiguration.template === templateType.CUSTOM\"\n [ssoConfiguration]=\"ssoConfiguration\"\n [ssoConfigurationChangeTrigger]=\"saveSubject.asObservable()\"\n (ssoConfigurationChange)=\"save($event)\"\n [apps]=\"apps\"\n [groups]=\"groups\"\n [inventoryRoles]=\"inventoryRoles\"\n ></c8y-custom-template>\n\n <c8y-aad-template\n *ngIf=\"ssoConfiguration.template === templateType.AZURE\"\n [ssoConfiguration]=\"ssoConfiguration\"\n [ssoConfigurationChangeTrigger]=\"saveSubject.asObservable()\"\n (ssoConfigurationChange)=\"save($event)\"\n [apps]=\"apps\"\n [groups]=\"groups\"\n [inventoryRoles]=\"inventoryRoles\"\n ></c8y-aad-template>\n\n <c8y-key-cloak-template\n *ngIf=\"ssoConfiguration.template === templateType.KEYCLOAK\"\n [ssoConfiguration]=\"ssoConfiguration\"\n [ssoConfigurationChangeTrigger]=\"saveSubject.asObservable()\"\n (ssoConfigurationChange)=\"save($event)\"\n [apps]=\"apps\"\n [groups]=\"groups\"\n [inventoryRoles]=\"inventoryRoles\"\n ></c8y-key-cloak-template>\n </div>\n </div>\n <div class=\"card-footer separator\">\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Save' | translate }}\"\n type=\"submit\"\n (click)=\"saveSubject.next()\"\n [disabled]=\"!ssoConfigurationForm.form.valid || ssoConfigurationForm.form.pristine\"\n >\n {{ 'Save' | translate }}\n </button>\n </div>\n </form>\n </div>\n</div>\n" }]
}], ctorParameters: () => [{ type: i1.SsoConfigurationService }, { type: i2.ApplicationService }, { type: i2.UserGroupService }, { type: i2.InventoryRoleService }, { type: i3.AlertService }, { type: i3.ModalService }, { type: i3.LoginService }, { type: i3.AppStateService }, { type: i3.TenantUiService }], propDecorators: { ssoConfigurationForm: [{
type: ViewChild,
args: ['ssoConfigurationForm']
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3NvLWNvbmZpZ3VyYXRpb24uY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vYXV0aC1jb25maWd1cmF0aW9uL3Nzby1jb25maWd1cmF0aW9uL3Nzby1jb25maWd1cmF0aW9uLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uL2F1dGgtY29uZmlndXJhdGlvbi9zc28tY29uZmlndXJhdGlvbi9zc28tY29uZmlndXJhdGlvbi5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFFLFlBQVksRUFBVSxTQUFTLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDM0UsT0FBTyxFQUNMLGtCQUFrQixFQUNsQixnQkFBZ0IsRUFHaEIscUJBQXFCLEVBQ3JCLG9CQUFvQixFQUVyQixNQUFNLGFBQWEsQ0FBQztBQUNyQixPQUFPLEVBQ0wsT0FBTyxFQUNQLFlBQVksRUFDWixZQUFZLEVBQ1osTUFBTSxFQUNOLFlBQVksRUFDWixlQUFlLEVBQ2YsZUFBZSxFQUNoQixNQUFNLHFCQUFxQixDQUFDO0FBQzdCLE9BQU8sRUFBRSxlQUFlLEVBQUUsUUFBUSxFQUFnQixPQUFPLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDeEUsT0FBTyxFQUFFLFdBQVcsRUFBRSxHQUFHLEVBQUUsU0FBUyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDN0QsT0FBTyxFQUFvQixZQUFZLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUMvRixPQUFPLEVBQUUsdUJBQXVCLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUN0RSxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7Ozs7Ozs7Ozs7QUFNeEMsTUFBTSxPQUFPLHlCQUF5QjtJQStCcEMsWUFDVSx1QkFBZ0QsRUFDaEQsa0JBQXNDLEVBQ3RDLGdCQUFrQyxFQUNsQyxvQkFBMEMsRUFDMUMsWUFBMEIsRUFDMUIsWUFBMEIs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QVEsRUFBRSxHQUFHLEVBQUUsQ0FBQyxDQUFDLElBQUksQ0FDM0QsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsSUFBSSxFQUNmLEtBQUssQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxnQkFBZ0IsQ0FBQyxLQUFLLENBQUMsQ0FDbkQsQ0FBQztJQUNKLENBQUM7SUFFTyxLQUFLLENBQUMseUJBQXlCO1FBQ3JDLE1BQU0sV0FBVyxHQUFHLEVBQUUsRUFBRSxFQUFFLE9BQU8sQ0FBQywwQkFBMEIsQ0FBQyxFQUFFLE1BQU0sRUFBRSxPQUFPLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQztRQUMzRixNQUFNLFNBQVMsR0FBRyxPQUFPLENBQ3ZCLGtJQUFrSSxDQUNuSSxDQUFDO1FBQ0YsT0FBTyxNQUFNLElBQUksQ0FBQyxZQUFZLENBQUMsT0FBTyxDQUNwQyxPQUFPLENBQUMsd0JBQXdCLENBQUMsRUFDakMsU0FBUyxFQUNULE1BQU0sQ0FBQyxPQUFPLEVBQ2QsV0FBVyxDQUNaLENBQUM7SUFDSixDQUFDOytHQXhIVSx5QkFBeUI7bUdBQXpCLHlCQUF5QiwyTEM3QnRDLG1ySEE0SEE7OzRGRC9GYSx5QkFBeUI7a0JBSnJDLFNBQVM7K0JBQ0UsdUJBQXVCOzRVQWdCRSxvQkFBb0I7c0JBQXRELFNBQVM7dUJBQUMsc0JBQXNCIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29tcG9uZW50LCBFdmVudEVtaXR0ZXIsIE9uSW5pdCwgVmlld0NoaWxkIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQge1xuICBBcHBsaWNhdGlvblNlcnZpY2UsXG4gIFVzZXJHcm91cFNlcnZpY2UsXG4gIElBcHBsaWNhdGlvbixcbiAgSVVzZXJHcm91cCxcbiAgVGVuYW50TG9naW5PcHRpb25UeXBlLFxuICBJbnZlbnRvcnlSb2xlU2VydmljZSxcbiAgSUlkZW50aWZpZWRcbn0gZnJvbSAnQGM4eS9jbGllbnQnO1xuaW1wb3J0IHtcbiAgZ2V0dGV4dCxcbiAgQWxlcnRTZXJ2aWNlLFxuICBNb2RhbFNlcnZpY2UsXG4gIFN0YXR1cyxcbiAgTG9naW5TZXJ2aWNlLFxuICBBcHBTdGF0ZVNlcnZpY2UsXG4gIFRlbmFudFVpU2VydmljZVxufSBmcm9tICdAYzh5L25neC1jb21wb25lbnRzJztcbmltcG9ydCB7IEJlaGF2aW9yU3ViamVjdCwgZm9ya0pvaW4sIFN1YnNjcmlwdGlvbiwgU3ViamVjdCB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgc2hhcmVSZXBsYXksIHRhcCwgc3dpdGNoTWFwIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuaW1wb3J0IHsgU3NvQ29uZmlndXJhdGlvbiwgVGVtcGxhdGVUeXBlLCB0ZW1wbGF0ZVR5cGVDb25maWcgfSBmcm9tICcuL3Nzby1jb25maWd1cmF0aW9uLm1vZGVsJztcbmltcG9ydCB7IFNzb0NvbmZpZ3VyYXRpb25TZXJ2aWNlIH0gZnJvbSAnLi9zc28tY29uZmlndXJhdGlvbi5zZXJ2aWNlJztcbmltcG9ydCB7IE5nRm9ybSB9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcblxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnYzh5LXNzby1jb25maWd1cmF0aW9uJyxcbiAgdGVtcGxhdGVVcmw6ICcuL3Nzby1jb25maWd1cmF0aW9uLmNvbXBvbmVudC5odG1sJ1xufSlcbmV4cG9ydCBjbGFzcyBTc29Db25maWd1cmF0aW9uQ29tcG9uZW50IGltcGxlbWVudHMgT25Jbml0IHtcbiAgYXBwczogSUFwcGxpY2F0aW9uW107XG4gIGdyb3VwczogSVVzZXJHcm91cFtdO1xuICBpbnZlbnRvcnlSb2xlczogSUlkZW50aWZpZWRbXTtcbiAgc3NvQ29uZmlndXJhdGlvbjogU3NvQ29uZmlndXJhdGlvbjtcblxuICB0ZW1wbGF0ZVR5cGUgPSBUZW1wbGF0ZVR5cGU7XG4gIHRlbXBsYXRlVHlwZUNvbmZpZyA9IHRlbXBsYXRlVHlwZUNvbmZpZztcblxuICByZWxvYWRpbmckOiBCZWhhdmlvclN1YmplY3Q8Ym9vbGVhbj4gPSBuZXcgQmVoYXZpb3JTdWJqZWN0KGZhbHNlKTtcbiAgcmVsb2FkOiBFdmVudEVtaXR0ZXI8dm9pZD4gPSBuZXcgRXZlbnRFbWl0dGVyKCk7XG4gIHNhdmVTdWJqZWN0OiBTdWJqZWN0PHZvaWQ+ID0gbmV3IFN1YmplY3QoKTtcblxuICBAVmlld0NoaWxkKCdzc29Db25maWd1cmF0aW9uRm9ybScpIHNzb0NvbmZpZ3VyYXRpb25Gb3JtITogTmdGb3JtO1xuXG4gIHByaXZhdGUgZGF0YVN1YnNjcmlwdGlvbjogU3Vic2NyaXB0aW9uO1xuXG4gIHByaXZhdGUgZGF0YSQ6IGFueSA9IHRoaXMucmVsb2FkLnBpcGUoXG4gICAgdGFwKCgpID0+IHRoaXMucmVsb2FkaW5nJC5uZXh0KHRydWUpKSxcbiAgICBzd2l0Y2hNYXAoKCkgPT5cbiAgICAgIGZvcmtKb2luKHtcbiAgICAgICAgc3NvQ29uZmlndXJhdGlvbjogdGhpcy5zc29Db25maWd1cmF0aW9uU2VydmljZS5nZXRTc29Db25maWd1cmF0aW9uJCgpLFxuICAgICAgICBhcHBzOiB0aGlzLmdldEFwcGxpY2F0aW9ucygpLFxuICAgICAgICBncm91cHM6IHRoaXMuZ2V0R3JvdXBzKCksXG4gICAgICAgIGludmVudG9yeVJvbGVzOiB0aGlzLmdldEludmVudG9yeVJvbGVzKClcbiAgICAgIH0pXG4gICAgKSxcbiAgICB0YXAoKCkgPT4gdGhpcy5yZWxvYWRpbmckLm5leHQoZmFsc2UpKSxcbiAgICBzaGFyZVJlcGxheSgxKVxuICApO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgc3NvQ29uZmlndXJhdGlvblNlcnZpY2U6IFNzb0NvbmZpZ3VyYXRpb25TZXJ2aWNlLFxuICAgIHByaXZhdGUgYXBwbGljYXRpb25TZXJ2aWNlOiBBcHBsaWNhdGlvblNlcnZpY2UsXG4gICAgcHJpdmF0ZSB1c2VyR3JvdXBTZXJ2aWNlOiBVc2VyR3JvdXBTZXJ2aWNlLFxuICAgIHByaXZhdGUgaW52ZW50b3J5Um9sZVNlcnZpY2U6IEludmVudG9yeVJvbGVTZXJ2aWNlLFxuICAgIHByaXZhdGUgYWxlcnRTZXJ2aWNlOiBBbGVydFNlcnZpY2UsXG4gICAgcHJpdmF0ZSBtb2RhbFNlcnZpY2U6IE1vZGFsU2VydmljZSxcbiAgICBwcml2YXRlIGxvZ2luU2VydmljZTogTG9naW5TZXJ2aWNlLFxuICAgIHByaXZhdGUgYXBwU3RhdGVTZXJ2aWNlOiBBcHBTdGF0ZVNlcnZpY2UsXG4gICAgcHJpdmF0ZSB0ZW5hbnRVaVNlcnZpY2U6IFRlbmFudFVpU2VydmljZVxuICApIHt9XG5cbiAgbmdPbkluaXQoKTogdm9pZCB7XG4gICAgdGhpcy5kYXRhU3Vic2NyaXB0aW9uID0gdGhpcy5kYXRhJC5zdWJzY3JpYmUoXG4gICAgICAoeyBzc29Db25maWd1cmF0aW9uLCBhcHBzLCBncm91cHMsIGludmVudG9yeVJvbGVzIH0pID0+IHtcbiAgICAgICAgdGhpcy5hcHBzID0gYXBwcztcbiAgICAgICAgdGhpcy5ncm91cHMgPSBncm91cHM7XG4gICAgICAgIHRoaXMuaW52ZW50b3J5Um9sZXMgPSBpbnZlbnRvcnlSb2xlcztcbiAgICAgICAgdGhpcy5zc29Db25maWd1cmF0aW9uID0gc3NvQ29uZmlndXJhdGlvbjtcbiAgICAgIH1cbiAgICApO1xuICAgIHRoaXMubG9hZFNzb0NvbmZpZ3VyYXRpb24oKTtcbiAgfVxuXG4gIG5nT25EZXN0cm95KCk6IHZvaWQge1xuICAgIHRoaXMuZGF0YVN1YnNjcmlwdGlvbi51bnN1YnNjcmliZSgpO1xuICB9XG5cbiAgbG9hZFNzb0NvbmZpZ3VyYXRpb24oKSB7XG4gICAgdGhpcy5yZWxvYWQubmV4dCgpO1xuICAgIHRoaXMuc3NvQ29uZmlndXJhdGlvbkZvcm0uZm9ybS5tYXJrQXNQcmlzdGluZSgpO1xuICB9XG5cbiAgYXN5bmMgc2F2ZShzc29Db25maWd1cmF0aW9uKSB7XG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IHRoaXMud2FybkFib3V0Rm9yY2VVc2Vyc0xvZ091dCgpO1xuICAgICAgY29uc3QgbG9nb3V0UmVxdWlyZWQgPVxuICAgICAgICB0aGlzLnRlbmFudFVpU2VydmljZS5nZXRDdXJyZW50VXNlckxvZ2luTW9kZSgpICE9PSBUZW5hbnRMb2dpbk9wdGlvblR5cGUuQkFTSUM7XG4gICAgICBpZiAobG9nb3V0UmVxdWlyZWQpIHtcbiAgICAgICAgYXdhaXQgdGhpcy5tb2RhbFNlcnZpY2UuY29uZmlybUxvZ291dCgpO1xuICAgICAgfVxuICAgICAgYXdhaXQgdGhpcy5zc29Db25maWd1cmF0aW9uU2VydmljZS5zYXZlKHNzb0NvbmZpZ3VyYXRpb24pO1xuICAgICAgaWYgKGxvZ291dFJlcXVpcmVkKSB7XG4gICAgICAgIGF3YWl0IHRoaXMubG9naW5TZXJ2aWNlLmxvZ291dCh0cnVlKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRoaXMubG9hZFNzb0NvbmZpZ3VyYXRpb24oKTtcbiAgICAgICAgdGhpcy5hbGVydFNlcnZpY2Uuc3VjY2VzcyhnZXR0ZXh0KCdDb25maWd1cmF0aW9uIHNhdmVkLicpKTtcbiAgICAgIH1cbiAgICB9IGNhdGNoIChleCkge1xuICAgICAgaWYgKGV4KSB7XG4gICAgICAgIHRoaXMuYWxlcnRTZXJ2aWNlLmFkZFNlcnZlckZhaWx1cmUoZXgpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy5sb2FkU3NvQ29uZmlndXJhdGlvbigpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgZ2V0QXBwbGljYXRpb25zKCk6IFByb21pc2U8dm9pZCB8IElBcHBsaWNhdGlvbltdPiB7XG4gICAgcmV0dXJuIHRoaXMuYXBwbGljYXRpb25TZXJ2aWNlLmxpc3RCeVRlbmFudChudWxsLCB7IHBhZ2VTaXplOiAxMDAgfSkudGhlbihcbiAgICAgIHJlcyA9PiByZXMuZGF0YSxcbiAgICAgIGVycm9yID0+IHRoaXMuYWxlcnRTZXJ2aWNlLmFkZFNlcnZlckZhaWx1cmUoZXJyb3IpXG4gICAgKTtcbiAgfVxuXG4gIHByaXZhdGUgZ2V0R3JvdXBzKCk6IFByb21pc2U8dm9pZCB8IElVc2VyR3JvdXBbXT4ge1xuICAgIHJldHVybiB0aGlzLnVzZXJHcm91cFNlcnZpY2UubGlzdCh7IHBhZ2VTaXplOiAxMDAgfSkudGhlbihcbiAgICAgIHJlcyA9PiByZXMuZGF0YSxcbiAgICAgIGVycm9yID0+IHRoaXMuYWxlcnRTZXJ2aWNlLmFkZFNlcnZlckZhaWx1cmUoZXJyb3IpXG4gICAgKTtcbiAgfVxuXG4gIHByaXZhdGUgZ2V0SW52ZW50b3J5Um9sZXMoKTogUHJvbWlzZTx2b2lkIHwgSUlkZW50aWZpZWRbXT4ge1xuICAgIHJldHVybiB0aGlzLmludmVudG9yeVJvbGVTZXJ2aWNlLmxpc3QoeyBwYWdlU2l6ZTogMTAwIH0pLnRoZW4oXG4gICAgICByZXMgPT4gcmVzLmRhdGEsXG4gICAgICBlcnJvciA9PiB0aGlzLmFsZXJ0U2VydmljZS5hZGRTZXJ2ZXJGYWlsdXJlKGVycm9yKVxuICAgICk7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIHdhcm5BYm91dEZvcmNlVXNlcnNMb2dPdXQoKSB7XG4gICAgY29uc3QgbW9kYWxMYWJlbHMgPSB7IG9rOiBnZXR0ZXh0KCdVcGRhdGUgYW5kIGxvZyBvdXQgdXNlcnMnKSwgY2FuY2VsOiBnZXR0ZXh0KCdDYW5jZWwnKSB9O1xuICAgIGNvbnN0IG1vZGFsQm9keSA9IGdldHRleHQoXG4gICAgICAnVXBkYXRpbmcgU1NPIGNvbmZpZ3VyYXRpb24gd2lsbCBsb2cgb3V0IGFsbCB1c2VycyBsb2dnZWQgd2l0aCBcIk9BSS1TZWN1cmVcIiBvciBcIlNpbmdsZSBzaWduLW9uIHJlZGlyZWN0XCIuIERvIHlvdSB3YW50IHRvIHByb2NlZWQ/J1xuICAgICk7XG4gICAgcmV0dXJuIGF3YWl0IHRoaXMubW9kYWxTZXJ2aWNlLmNvbmZpcm0oXG4gICAgICBnZXR0ZXh0KCdGb3JjZSB1c2VycyB0byBsb2cgb3V0JyksXG4gICAgICBtb2RhbEJvZHksXG4gICAgICBTdGF0dXMuV0FSTklORyxcbiAgICAgIG1vZGFsTGFiZWxzXG4gICAgKTtcbiAgfVxufVxuIiwiPGM4eS10aXRsZT57eyAnU2luZ2xlIHNpZ24tb24nIHwgdHJhbnNsYXRlIH19PC9jOHktdGl0bGU+XG48Yzh5LWJyZWFkY3J1bWI+XG4gIDxjOHktYnJlYWRjcnVtYi1pdGVtXG4gICAgW2ljb25dPVwiJ2NvZydcIlxuICAgIFtsYWJlbF09XCInU2V0dGluZ3MnIHwgdHJhbnNsYXRlXCJcbiAgPjwvYzh5LWJyZWFkY3J1bWItaXRlbT5cbiAgPGM4eS1icmVhZGNydW1iLWl0ZW1cbiAgICBbaWNvbl09XCInY29nJ1wiXG4gICAgW2xhYmVsXT1cIidTaW5nbGUgc2lnbi1vbicgfCB0cmFuc2xhdGVcIlxuICA+PC9jOHktYnJlYWRjcnVtYi1pdGVtPlxuPC9jOHktYnJlYWRjcnVtYj5cblxuPGM4eS1hY3Rpb24tYmFyLWl0ZW0gW3BsYWNlbWVudF09XCIncmlnaHQnXCI+XG4gIDxidXR0b25cbiAgICBjbGFzcz1cImJ0biBidG4tbGlua1wiXG4gICAgdGl0bGU9XCJ7eyAnUmVsb2FkJyB8IHRyYW5zbGF0ZSB9fVwiXG4gICAgdHlwZT1cImJ1dHRvblwiXG4gICAgKGNsaWNrKT1cImxvYWRTc29Db25maWd1cmF0aW9uKClcIlxuICA+XG4gICAgPGlcbiAgICAgIGM4eUljb249XCJyZWZyZXNoXCJcbiAgICAgIFtuZ0NsYXNzXT1cInsgJ2ljb24tc3Bpbic6IHJlbG9hZGluZyQgfCBhc3luYyB9XCJcbiAgICA+PC9pPlxuICAgIHt7ICdSZWxvYWQnIHwgdHJhbnNsYXRlIH19XG4gIDwvYnV0dG9uPlxuPC9jOHktYWN0aW9uLWJhci1pdGVtPlxuXG48Yzh5LWFjdGlvbi1iYXItaXRlbVxuICBbcGxhY2VtZW50XT1cIidsZWZ0J1wiXG4gIGl0ZW1DbGFzcz1cIm5hdmJhci1mb3JtIGhpZGRlbi14c1wiXG4+XG4gIDxkaXZcbiAgICBjbGFzcz1cImZvcm0tZ3JvdXBcIlxuICAgIHRpdGxlPVwie3sgJ1RlbXBsYXRlJyB8IHRyYW5zbGF0ZSB9fVwiXG4gID5cbiAgICA8bGFiZWxcbiAgICAgIGNsYXNzPVwiY29udHJvbC1sYWJlbFwiXG4gICAgICBmb3I9XCJ0ZW1wbGF0ZVwiXG4gICAgPlxuICAgICAge3sgJ1RlbXBsYXRlJyB8IHRyYW5zbGF0ZSB9fVxuICAgIDwvbGFiZWw+XG4gICAgPGRpdiBjbGFzcz1cImM4eS1zZWxlY3Qtd3JhcHBlclwiPlxuICAgICAgPHNlbGVjdFxuICAgICAgICBjbGFzcz1cImZvcm0tY29udHJvbFwiXG4gICAgICAgIGlkPVwidGVtcGxhdGVcIlxuICAgICAgICBuYW1lPVwidGVtcGxhdGVcIlxuICAgICAgICAqbmdJZj1cInNzb0NvbmZpZ3VyYXRpb25cIlxuICAgICAgICBbKG5nTW9kZWwpXT1cInNzb0NvbmZpZ3VyYXRpb24udGVtcGxhdGVcIlxuICAgICAgPlxuICAgICAgICA8b3B0aW9uXG4gICAgICAgICAgKm5nRm9yPVwibGV0IHRlbXBsYXRlVHlwZSBvZiB0ZW1wbGF0ZVR5cGVDb25maWcgfCBrZXl2YWx1ZVwiXG4gICAgICAgICAgW25nVmFsdWVdPVwidGVtcGxhdGVUeXBlLmtleVwiXG4gICAgICAgID5cbiAgICAgICAgICB7eyB0ZW1wbGF0ZVR5cGUudmFsdWUubGFiZWwgfCB0cmFuc2xhdGUgfX1cbiAgICAgICAgPC9vcHRpb24+XG4gICAgICA8L3NlbGVjdD5cbiAgICAgIDxzcGFuPjwvc3Bhbj5cbiAgICA8L2Rpdj5cbiAgPC9kaXY+XG48L2M4eS1hY3Rpb24tYmFyLWl0ZW0+XG5cbjxkaXYgY2xhc3M9XCJyb3dcIj5cbiAgPGRpdiBjbGFzcz1cImNvbC1sZy0xMiBjb2wtbGctbWF4XCI+XG4gICAgPGZvcm1cbiAgICAgIGNsYXNzPVwiY2FyZCBjYXJkLS1mdWxscGFnZVwiXG4gICAgICAjc3NvQ29uZmlndXJhdGlvbkZvcm09XCJuZ0Zvcm1cIlxuICAgICAgbm92YWxpZGF0ZVxuICAgID5cbiAgICAgIDxkaXYgY2xhc3M9XCJjYXJkLWhlYWRlciBzZXBhcmF0b3JcIj5cbiAgICAgICAgPGRpdiBjbGFzcz1cImNhcmQtdGl0bGVcIj5cbiAgICAgICAgICB7eyAnU2luZ2xlIHNpZ24tb24nIHwgdHJhbnNsYXRlIH19XG4gICAgICAgIDwvZGl2PlxuICAgICAgPC9kaXY+XG5cbiAgICAgIDxkaXYgY2xhc3M9XCJpbm5lci1zY3JvbGxcIj5cbiAgICAgICAgPGRpdlxuICAgICAgICAgIGNsYXNzPVwiY2FyZC1ibG9jayBwLTBcIlxuICAgICAgICAgICpuZ0lmPVwic3NvQ29uZmlndXJhdGlvblwiXG4gICAgICAgID5cbiAgICAgICAgICA8Yzh5LWN1c3RvbS10ZW1wbGF0ZVxuICAgICAgICAgICAgKm5nSWY9XCJzc29Db25maWd1cmF0aW9uLnRlbXBsYXRlID09PSB0ZW1wbGF0ZVR5cGUuQ1VTVE9NXCJcbiAgICAgICAgICAgIFtzc29Db25maWd1cmF0aW9uXT1cInNzb0NvbmZpZ3VyYXRpb25cIlxuICAgICAgICAgICAgW3Nzb0NvbmZpZ3VyYXRpb25DaGFuZ2VUcmlnZ2VyXT1cInNhdmVTdWJqZWN0LmFzT2JzZXJ2YWJsZSgpXCJcbiAgICAgICAgICAgIChzc29Db25maWd1cmF0aW9uQ2hhbmdlKT1cInNhdmUoJGV2ZW50KVwiXG4gICAgICAgICAgICBbYXBwc109XCJhcHBzXCJcbiAgICAgICAgICAgIFtncm91cHNdPVwiZ3JvdXBzXCJcbiAgICAgICAgICAgIFtpbnZlbnRvcnlSb2xlc109XCJpbnZlbnRvcnlSb2xlc1wiXG4gICAgICAgICAgPjwvYzh5LWN1c3RvbS10ZW1wbGF0ZT5cblxuICAgICAgICAgIDxjOHktYWFkLXRlbXBsYXRlXG4gICAgICAgICAgICAqbmdJZj1cInNzb0NvbmZpZ3VyYXRpb24udGVtcGxhdGUgPT09IHRlbXBsYXRlVHlwZS5BWlVSRVwiXG4gICAgICAgICAgICBbc3NvQ29uZmlndXJhdGlvbl09XCJzc29Db25maWd1cmF0aW9uXCJcbiAgICAgICAgICAgIFtzc29Db25maWd1cmF0aW9uQ2hhbmdlVHJpZ2dlcl09XCJzYXZlU3ViamVjdC5hc09ic2VydmFibGUoKVwiXG4gICAgICAgICAgICAoc3NvQ29uZmlndXJhdGlvbkNoYW5nZSk9XCJzYXZlKCRldmVudClcIlxuICAgICAgICAgICAgW2FwcHNdPVwiYXBwc1wiXG4gICAgICAgICAgICBbZ3JvdXBzXT1cImdyb3Vwc1wiXG4gICAgICAgICAgICBbaW52ZW50b3J5Um9sZXNdPVwiaW52ZW50b3J5Um9sZXNcIlxuICAgICAgICAgID48L2M4eS1hYWQtdGVtcGxhdGU+XG5cbiAgICAgICAgICA8Yzh5LWtleS1jbG9hay10ZW1wbGF0ZVxuICAgICAgICAgICAgKm5nSWY9XCJzc29Db25maWd1cmF0aW9uLnRlbXBsYXRlID09PSB0ZW1wbGF0ZVR5cGUuS0VZQ0xPQUtcIlxuICAgICAgICAgICAgW3Nzb0NvbmZpZ3VyYXRpb25dPVwic3NvQ29uZmlndXJhdGlvblwiXG4gICAgICAgICAgICBbc3NvQ29uZmlndXJhdGlvbkNoYW5nZVRyaWdnZXJdPVwic2F2ZVN1YmplY3QuYXNPYnNlcnZhYmxlKClcIlxuICAgICAgICAgICAgKHNzb0NvbmZpZ3VyYXRpb25DaGFuZ2UpPVwic2F2ZSgkZXZlbnQpXCJcbiAgICAgICAgICAgIFthcHBzXT1cImFwcHNcIlxuICAgICAgICAgICAgW2dyb3Vwc109XCJncm91cHNcIlxuICAgICAgICAgICAgW2ludmVudG9yeVJvbGVzXT1cImludmVudG9yeVJvbGVzXCJcbiAgICAgICAgICA+PC9jOHkta2V5LWNsb2FrLXRlbXBsYXRlPlxuICAgICAgICA8L2Rpdj5cbiAgICAgIDwvZGl2PlxuICAgICAgPGRpdiBjbGFzcz1cImNhcmQtZm9vdGVyIHNlcGFyYXRvclwiPlxuICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgY2xhc3M9XCJidG4gYnRuLXByaW1hcnlcIlxuICAgICAgICAgIHRpdGxlPVwie3sgJ1NhdmUnIHwgdHJhbnNsYXRlIH19XCJcbiAgICAgICAgICB0eXBlPVwic3VibWl0XCJcbiAgICAgICAgICAoY2xpY2spPVwic2F2ZVN1YmplY3QubmV4dCgpXCJcbiAgICAgICAgICBbZGlzYWJsZWRdPVwiIXNzb0NvbmZpZ3VyYXRpb25Gb3JtLmZvcm0udmFsaWQgfHwgc3NvQ29uZmlndXJhdGlvbkZvcm0uZm9ybS5wcmlzdGluZVwiXG4gICAgICAgID5cbiAgICAgICAgICB7eyAnU2F2ZScgfCB0cmFuc2xhdGUgfX1cbiAgICAgICAgPC9idXR0b24+XG4gICAgICA8L2Rpdj5cbiAgICA8L2Zvcm0+XG4gIDwvZGl2PlxuPC9kaXY+XG4iXX0=