@c8y/ngx-components
Version:
Angular modules for Cumulocity IoT applications
188 lines • 56.7 kB
JavaScript
import { Component } from '@angular/core';
import { FormBuilder } from '@angular/forms';
import { AlertService, gettext } from '@c8y/ngx-components';
import { DefaultSubscriptionsService } from './default-subscriptions.service';
import * as i0 from "@angular/core";
import * as i1 from "@angular/forms";
import * as i2 from "./default-subscriptions.service";
import * as i3 from "@c8y/ngx-components";
import * as i4 from "@angular/common";
/**
* The component shows the main view for managing default subscriptions configuration.
*/
export class DefaultSubscriptionsComponent {
constructor(fb, defaultSubscriptionsService, alertService) {
this.fb = fb;
this.defaultSubscriptionsService = defaultSubscriptionsService;
this.alertService = alertService;
/** Hint text for disabled checkboxes. */
this.disabledCheckboxHint = gettext('Select "Override inherited" to enable.');
}
/** Initializes the loading of the form and the current settings. */
async ngOnInit() {
this.loading = true;
await this.initForm();
await this.loadDefaultSubscriptions();
this.loading = false;
}
/** Loads the list of apps, builds the form and hooks value change events for override switches. */
async initForm() {
this.form = this.fb.group({
overrideOnCreationSubscriptions: [''],
overrideOnUpgradeSubscriptions: [''],
appRows: this.fb.array([])
});
const apps = await this.defaultSubscriptionsService.getSubscribableTenantApps();
const appRows = this.form.controls.appRows;
apps.forEach(app => {
appRows.push(this.fb.group({
app: [app],
subscribedOnCreation: [''],
subscribedOnUpgrade: ['']
}));
});
this.form
.get('overrideOnCreationSubscriptions')
.valueChanges.subscribe(value => this.onOverrideOnCreationSubscriptionsChange(value));
this.form
.get('overrideOnUpgradeSubscriptions')
.valueChanges.subscribe(value => this.onOverrideOnUpgradeSubscriptionsChange(value));
}
/**
* Checks if given application row should be displayed.
* The row is displayed when any of its checkboxes is selected or any of the lists is being overridden.
*/
shouldShowAppRow(appRowRawValue) {
const { subscribedOnCreation, subscribedOnUpgrade } = appRowRawValue;
const { overrideOnCreationSubscriptions, overrideOnUpgradeSubscriptions } = this.form.value;
return (subscribedOnCreation ||
subscribedOnUpgrade ||
overrideOnCreationSubscriptions ||
overrideOnUpgradeSubscriptions);
}
/** Checks if there are no application rows to be displayed. */
isEmptyView() {
return !this.form
.getRawValue()
.appRows.some(appRowRawValue => this.shouldShowAppRow(appRowRawValue));
}
/**
* Checks if given application is subscribed (present in the given list of applications).
* @param app Application object to check.
* @param subscribedApps The list of application objects to check against.
* @returns True, if the application is present in the list.
*/
isSubscribed(app, subscribedApps) {
return subscribedApps && subscribedApps.some(subscribedApp => subscribedApp.name === app.name);
}
/** Saves the current value of form object to backend. */
async save() {
try {
const defaultSubscriptions = this.getDefaultSubscriptionsForSave();
await this.defaultSubscriptionsService.saveDefaultSubscriptionsToCurrentTenant(defaultSubscriptions);
this.alertService.success(gettext('Saved.'));
}
catch (ex) {
this.alertService.addServerFailure(ex);
}
}
onOverrideOnCreationSubscriptionsChange(overrideOnCreationSubscriptions) {
if (overrideOnCreationSubscriptions) {
this.enableSubscribeOnCreationCheckboxes();
return;
}
this.disableSubscribeOnCreationCheckboxes();
this.restoreSubscribeOnCreationFromParent();
}
enableSubscribeOnCreationCheckboxes() {
const appRowsControls = this.form.controls.appRows.controls;
appRowsControls.forEach(appRowControl => {
appRowControl.get('subscribedOnCreation').enable({ emitEvent: false });
});
}
disableSubscribeOnCreationCheckboxes() {
const appRowsControls = this.form.controls.appRows.controls;
appRowsControls.forEach(appRowControl => {
appRowControl.get('subscribedOnCreation').disable({ emitEvent: false });
});
}
restoreSubscribeOnCreationFromParent() {
const appRowsControls = this.form.controls.appRows.controls;
appRowsControls.forEach(appRowControl => {
appRowControl.patchValue({
subscribedOnCreation: this.isSubscribed(appRowControl.value.app, this.parentDefaultSubscriptions.onCreationSubscriptions)
});
});
}
onOverrideOnUpgradeSubscriptionsChange(overrideOnUpgradeSubscriptions) {
if (overrideOnUpgradeSubscriptions) {
this.enableSubscribeOnUpgradeCheckboxes();
return;
}
this.disableSubscribeOnUpgradeCheckboxes();
this.restoreSubscribeOnUpgradeFromParent();
}
enableSubscribeOnUpgradeCheckboxes() {
const appRowsControls = this.form.controls.appRows.controls;
appRowsControls.forEach(appRowControl => {
appRowControl.get('subscribedOnUpgrade').enable({ emitEvent: false });
});
}
disableSubscribeOnUpgradeCheckboxes() {
const appRowsControls = this.form.controls.appRows.controls;
appRowsControls.forEach(appRowControl => {
appRowControl.get('subscribedOnUpgrade').disable({ emitEvent: false });
});
}
restoreSubscribeOnUpgradeFromParent() {
const appRowsControls = this.form.controls.appRows.controls;
appRowsControls.forEach(appRowControl => {
appRowControl.patchValue({
subscribedOnUpgrade: this.isSubscribed(appRowControl.value.app, this.parentDefaultSubscriptions.onUpgradeSubscriptions)
});
});
}
async loadDefaultSubscriptions() {
this.parentDefaultSubscriptions =
await this.defaultSubscriptionsService.getDefaultSubscriptionsEvaluatedFromParentTenant();
this.currentDefaultSubscriptions =
await this.defaultSubscriptionsService.getDefaultSubscriptionsFromCurrentTenant();
const { overrideOnCreationSubscriptions, overrideOnUpgradeSubscriptions } = this.currentDefaultSubscriptions;
const onCreationSubscriptions = overrideOnCreationSubscriptions
? this.currentDefaultSubscriptions.onCreationSubscriptions
: this.parentDefaultSubscriptions.onCreationSubscriptions;
const onUpgradeSubscriptions = overrideOnUpgradeSubscriptions
? this.currentDefaultSubscriptions.onUpgradeSubscriptions
: this.parentDefaultSubscriptions.onUpgradeSubscriptions;
this.form.patchValue({
overrideOnCreationSubscriptions,
overrideOnUpgradeSubscriptions
});
this.form.controls.appRows.controls.forEach(appRowControl => {
appRowControl.patchValue({
subscribedOnCreation: this.isSubscribed(appRowControl.value.app, onCreationSubscriptions),
subscribedOnUpgrade: this.isSubscribed(appRowControl.value.app, onUpgradeSubscriptions)
});
});
}
getDefaultSubscriptionsForSave() {
const { value } = this.form;
return {
overrideOnCreationSubscriptions: value.overrideOnCreationSubscriptions,
onCreationSubscriptions: value.overrideOnCreationSubscriptions
? value.appRows.filter(app => app.subscribedOnCreation).map(app => app.app)
: null,
overrideOnUpgradeSubscriptions: value.overrideOnUpgradeSubscriptions,
onUpgradeSubscriptions: value.overrideOnUpgradeSubscriptions
? value.appRows.filter(app => app.subscribedOnUpgrade).map(app => app.app)
: null
};
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DefaultSubscriptionsComponent, deps: [{ token: i1.FormBuilder }, { token: i2.DefaultSubscriptionsService }, { token: i3.AlertService }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: DefaultSubscriptionsComponent, selector: "c8y-default-subscriptions", ngImport: i0, template: "<c8y-title>{{ 'Default subscriptions' | translate }}</c8y-title>\n\n<c8y-breadcrumb>\n <c8y-breadcrumb-item [label]=\"'Ecosystem' | translate\" [icon]=\"'c8y-atom'\"></c8y-breadcrumb-item>\n <c8y-breadcrumb-item\n [label]=\"'Default subscriptions' | translate\"\n [icon]=\"'c8y-atom'\"\n ></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<form [formGroup]=\"form\" (ngSubmit)=\"save()\">\n <div class=\"card card--fullpage col-lg-max\">\n <div class=\"card-header separator\">\n <div class=\"card-title\" translate>Applications</div>\n </div>\n <div class=\"inner-scroll\">\n <div class=\"sticky-top separator-bottom\">\n <div class=\"d-flex\">\n <div class=\"col-sm-6 col-xs-6 p-24 p-t-16 p-l-xs-16\">\n <p translate>\n Configure default subscriptions in the platform, both for tenant creation and for\n platform upgrade. To display a full list of available applications, override inherited\n settings.\n </p>\n </div>\n <div class=\"col-sm-6 col-xs-6 bg-level-1 p-16 text-center separator-bottom\">\n <div class=\"row\">\n <div class=\"col-sm-6 col-xs-6\">\n <p><strong translate>Subscribed on tenant creation</strong></p>\n <div>\n <label class=\"c8y-switch\" title=\"{{ 'Override inherited' | translate }}\">\n <input type=\"checkbox\" formControlName=\"overrideOnCreationSubscriptions\" />\n <span></span>\n <span>\n {{ 'Override inherited' | translate }}\n </span>\n </label>\n </div>\n </div>\n <div class=\"col-sm-6 col-xs-6\">\n <p><strong translate>Subscribed on platform upgrade</strong></p>\n <div>\n <label class=\"c8y-switch\" title=\"{{ 'Override inherited' | translate }}\">\n <input type=\"checkbox\" formControlName=\"overrideOnUpgradeSubscriptions\" />\n <span></span>\n <span>\n {{ 'Override inherited' | translate }}\n </span>\n </label>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n <div class=\"card-block\" *ngIf=\"loading\"></div>\n <div class=\"card-block card-block d-flex a-i-center j-c-center d-col\" *ngIf=\"loading\">\n <c8y-loading></c8y-loading>\n </div>\n <div class=\"card-block\" *ngIf=\"loading\"></div>\n\n <ng-container formArrayName=\"appRows\">\n <div class=\"bg-level-1\" *ngIf=\"!loading && isEmptyView()\"></div>\n <div class=\"card-block bg-level-0\" *ngIf=\"!loading && isEmptyView()\">\n <c8y-ui-empty-state\n [icon]=\"'c8y-c8y-data'\"\n [title]=\"'No application subscriptions yet.' | translate\"\n [subtitle]=\"\n 'Select "Override inherited" to define the list of subscribed applications.'\n | translate\n \"\n ></c8y-ui-empty-state>\n </div>\n <div class=\"bg-level-1\" *ngIf=\"!loading && isEmptyView()\"></div>\n\n <div *ngFor=\"let appRowControl of form.get('appRows')['controls']; let i = index\">\n <ng-container\n *ngIf=\"shouldShowAppRow(appRowControl.getRawValue())\"\n formArrayName=\"{{ i }}\"\n >\n <div class=\"d-flex a-i-stretch\">\n <div class=\"col-sm-6 col-xs-6 separator-bottom\">\n <div class=\"c8y-list__item__block\">\n <div class=\"c8y-list__item__appicon\">\n <c8y-app-icon\n [app]=\"appRowControl.value.app\"\n [name]=\"appRowControl.value.app.name\"\n [contextPath]=\"appRowControl.value.app.contextPath\"\n ></c8y-app-icon>\n </div>\n <div class=\"c8y-list__item__body\" data-cy=\"defaultSubscriptionForm--c8y-list_item\">\n <div class=\"content-flex-30\">\n <div class=\"col-6\">\n <p\n class=\"text-truncate\"\n title=\"{{ appRowControl.value.app | humanizeAppName | async }}\"\n >\n {{ appRowControl.value.app | humanizeAppName | async }}\n </p>\n <small class=\"text-muted\">{{ appRowControl.value.app.contextPath }}</small>\n </div>\n <div class=\"col-6 text-right-sm\">\n <p>\n <span class=\"text-label-small m-r-4\" translate>Tenant ID</span>\n {{ appRowControl.value.app.owner.tenant.id }}\n </p>\n <!-- TODO: uncomment when company name is available\n <p>\n <span class=\"text-label-small m-r-4\" translate>Company</span>\n <small class=\"text-muted\">company name</small>\n </p> -->\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <div\n class=\"col-sm-3 col-xs-3 bg-level-1 separator-bottom d-flex j-c-center a-i-center\"\n >\n <label\n class=\"c8y-checkbox\"\n [ngClass]=\"{ disabled: appRowControl.controls.subscribedOnCreation.disabled }\"\n >\n <input type=\"checkbox\" formControlName=\"subscribedOnCreation\" />\n <span *ngIf=\"!appRowControl.controls.subscribedOnCreation.disabled\"></span>\n <span\n *ngIf=\"appRowControl.controls.subscribedOnCreation.disabled\"\n title=\"{{ disabledCheckboxHint | translate }}\"\n ></span>\n <span class=\"sr-only\">{{ 'Subscribed on tenant creation' | translate }}</span>\n </label>\n </div>\n\n <div\n class=\"col-sm-3 col-xs-3 bg-level-1 separator-bottom d-flex j-c-center a-i-center\"\n >\n <label\n class=\"c8y-checkbox\"\n [ngClass]=\"{ disabled: appRowControl.controls.subscribedOnUpgrade.disabled }\"\n >\n <input type=\"checkbox\" formControlName=\"subscribedOnUpgrade\" />\n <span *ngIf=\"!appRowControl.controls.subscribedOnUpgrade.disabled\"></span>\n <span\n *ngIf=\"appRowControl.controls.subscribedOnUpgrade.disabled\"\n title=\"{{ disabledCheckboxHint | translate }}\"\n ></span>\n <span class=\"sr-only\">{{ 'Subscribed on platform upgrade' | translate }}</span>\n </label>\n </div>\n </div>\n </ng-container>\n </div>\n </ng-container>\n </div>\n <div class=\"card-footer separator\">\n <button\n class=\"btn btn-primary\"\n type=\"submit\"\n title=\"{{ 'Save default subscriptions' | translate }}\"\n [disabled]=\"form.invalid || form.pristine\"\n >\n {{ 'Save' | translate }}\n </button>\n </div>\n </div>\n</form>\n", dependencies: [{ kind: "component", type: i3.AppIconComponent, selector: "c8y-app-icon", inputs: ["contextPath", "name", "app"] }, { kind: "component", type: i3.BreadcrumbComponent, selector: "c8y-breadcrumb" }, { kind: "component", type: i3.BreadcrumbItemComponent, selector: "c8y-breadcrumb-item", inputs: ["icon", "translate", "label", "path", "injector"] }, { kind: "component", type: i3.EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "directive", type: i3.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i4.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i4.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i3.LoadingComponent, selector: "c8y-loading", inputs: ["layout", "progress", "message"] }, { kind: "component", type: i3.TitleComponent, selector: "c8y-title", inputs: ["pageTitleUpdate"] }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i3.RequiredInputPlaceholderDirective, selector: "input[required], input[formControlName]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i1.FormArrayName, selector: "[formArrayName]", inputs: ["formArrayName"] }, { kind: "pipe", type: i3.C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: i4.AsyncPipe, name: "async" }, { kind: "pipe", type: i3.HumanizeAppNamePipe, name: "humanizeAppName" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DefaultSubscriptionsComponent, decorators: [{
type: Component,
args: [{ selector: 'c8y-default-subscriptions', template: "<c8y-title>{{ 'Default subscriptions' | translate }}</c8y-title>\n\n<c8y-breadcrumb>\n <c8y-breadcrumb-item [label]=\"'Ecosystem' | translate\" [icon]=\"'c8y-atom'\"></c8y-breadcrumb-item>\n <c8y-breadcrumb-item\n [label]=\"'Default subscriptions' | translate\"\n [icon]=\"'c8y-atom'\"\n ></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<form [formGroup]=\"form\" (ngSubmit)=\"save()\">\n <div class=\"card card--fullpage col-lg-max\">\n <div class=\"card-header separator\">\n <div class=\"card-title\" translate>Applications</div>\n </div>\n <div class=\"inner-scroll\">\n <div class=\"sticky-top separator-bottom\">\n <div class=\"d-flex\">\n <div class=\"col-sm-6 col-xs-6 p-24 p-t-16 p-l-xs-16\">\n <p translate>\n Configure default subscriptions in the platform, both for tenant creation and for\n platform upgrade. To display a full list of available applications, override inherited\n settings.\n </p>\n </div>\n <div class=\"col-sm-6 col-xs-6 bg-level-1 p-16 text-center separator-bottom\">\n <div class=\"row\">\n <div class=\"col-sm-6 col-xs-6\">\n <p><strong translate>Subscribed on tenant creation</strong></p>\n <div>\n <label class=\"c8y-switch\" title=\"{{ 'Override inherited' | translate }}\">\n <input type=\"checkbox\" formControlName=\"overrideOnCreationSubscriptions\" />\n <span></span>\n <span>\n {{ 'Override inherited' | translate }}\n </span>\n </label>\n </div>\n </div>\n <div class=\"col-sm-6 col-xs-6\">\n <p><strong translate>Subscribed on platform upgrade</strong></p>\n <div>\n <label class=\"c8y-switch\" title=\"{{ 'Override inherited' | translate }}\">\n <input type=\"checkbox\" formControlName=\"overrideOnUpgradeSubscriptions\" />\n <span></span>\n <span>\n {{ 'Override inherited' | translate }}\n </span>\n </label>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n <div class=\"card-block\" *ngIf=\"loading\"></div>\n <div class=\"card-block card-block d-flex a-i-center j-c-center d-col\" *ngIf=\"loading\">\n <c8y-loading></c8y-loading>\n </div>\n <div class=\"card-block\" *ngIf=\"loading\"></div>\n\n <ng-container formArrayName=\"appRows\">\n <div class=\"bg-level-1\" *ngIf=\"!loading && isEmptyView()\"></div>\n <div class=\"card-block bg-level-0\" *ngIf=\"!loading && isEmptyView()\">\n <c8y-ui-empty-state\n [icon]=\"'c8y-c8y-data'\"\n [title]=\"'No application subscriptions yet.' | translate\"\n [subtitle]=\"\n 'Select "Override inherited" to define the list of subscribed applications.'\n | translate\n \"\n ></c8y-ui-empty-state>\n </div>\n <div class=\"bg-level-1\" *ngIf=\"!loading && isEmptyView()\"></div>\n\n <div *ngFor=\"let appRowControl of form.get('appRows')['controls']; let i = index\">\n <ng-container\n *ngIf=\"shouldShowAppRow(appRowControl.getRawValue())\"\n formArrayName=\"{{ i }}\"\n >\n <div class=\"d-flex a-i-stretch\">\n <div class=\"col-sm-6 col-xs-6 separator-bottom\">\n <div class=\"c8y-list__item__block\">\n <div class=\"c8y-list__item__appicon\">\n <c8y-app-icon\n [app]=\"appRowControl.value.app\"\n [name]=\"appRowControl.value.app.name\"\n [contextPath]=\"appRowControl.value.app.contextPath\"\n ></c8y-app-icon>\n </div>\n <div class=\"c8y-list__item__body\" data-cy=\"defaultSubscriptionForm--c8y-list_item\">\n <div class=\"content-flex-30\">\n <div class=\"col-6\">\n <p\n class=\"text-truncate\"\n title=\"{{ appRowControl.value.app | humanizeAppName | async }}\"\n >\n {{ appRowControl.value.app | humanizeAppName | async }}\n </p>\n <small class=\"text-muted\">{{ appRowControl.value.app.contextPath }}</small>\n </div>\n <div class=\"col-6 text-right-sm\">\n <p>\n <span class=\"text-label-small m-r-4\" translate>Tenant ID</span>\n {{ appRowControl.value.app.owner.tenant.id }}\n </p>\n <!-- TODO: uncomment when company name is available\n <p>\n <span class=\"text-label-small m-r-4\" translate>Company</span>\n <small class=\"text-muted\">company name</small>\n </p> -->\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <div\n class=\"col-sm-3 col-xs-3 bg-level-1 separator-bottom d-flex j-c-center a-i-center\"\n >\n <label\n class=\"c8y-checkbox\"\n [ngClass]=\"{ disabled: appRowControl.controls.subscribedOnCreation.disabled }\"\n >\n <input type=\"checkbox\" formControlName=\"subscribedOnCreation\" />\n <span *ngIf=\"!appRowControl.controls.subscribedOnCreation.disabled\"></span>\n <span\n *ngIf=\"appRowControl.controls.subscribedOnCreation.disabled\"\n title=\"{{ disabledCheckboxHint | translate }}\"\n ></span>\n <span class=\"sr-only\">{{ 'Subscribed on tenant creation' | translate }}</span>\n </label>\n </div>\n\n <div\n class=\"col-sm-3 col-xs-3 bg-level-1 separator-bottom d-flex j-c-center a-i-center\"\n >\n <label\n class=\"c8y-checkbox\"\n [ngClass]=\"{ disabled: appRowControl.controls.subscribedOnUpgrade.disabled }\"\n >\n <input type=\"checkbox\" formControlName=\"subscribedOnUpgrade\" />\n <span *ngIf=\"!appRowControl.controls.subscribedOnUpgrade.disabled\"></span>\n <span\n *ngIf=\"appRowControl.controls.subscribedOnUpgrade.disabled\"\n title=\"{{ disabledCheckboxHint | translate }}\"\n ></span>\n <span class=\"sr-only\">{{ 'Subscribed on platform upgrade' | translate }}</span>\n </label>\n </div>\n </div>\n </ng-container>\n </div>\n </ng-container>\n </div>\n <div class=\"card-footer separator\">\n <button\n class=\"btn btn-primary\"\n type=\"submit\"\n title=\"{{ 'Save default subscriptions' | translate }}\"\n [disabled]=\"form.invalid || form.pristine\"\n >\n {{ 'Save' | translate }}\n </button>\n </div>\n </div>\n</form>\n" }]
}], ctorParameters: () => [{ type: i1.FormBuilder }, { type: i2.DefaultSubscriptionsService }, { type: i3.AlertService }] });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVmYXVsdC1zdWJzY3JpcHRpb25zLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL2RlZmF1bHQtc3Vic2NyaXB0aW9ucy9kZWZhdWx0LXN1YnNjcmlwdGlvbnMuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vZGVmYXVsdC1zdWJzY3JpcHRpb25zL2RlZmF1bHQtc3Vic2NyaXB0aW9ucy5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQzFDLE9BQU8sRUFBYSxXQUFXLEVBQWEsTUFBTSxnQkFBZ0IsQ0FBQztBQUVuRSxPQUFPLEVBQUUsWUFBWSxFQUFFLE9BQU8sRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBRTVELE9BQU8sRUFBRSwyQkFBMkIsRUFBRSxNQUFNLGlDQUFpQyxDQUFDOzs7Ozs7QUFFOUU7O0dBRUc7QUFLSCxNQUFNLE9BQU8sNkJBQTZCO0lBWXhDLFlBQ1UsRUFBZSxFQUNmLDJCQUF3RCxFQUN4RCxZQUEwQjtRQUYxQixPQUFFLEdBQUYsRUFBRSxDQUFhO1FBQ2YsZ0NBQTJCLEdBQTNCLDJCQUEyQixDQUE2QjtRQUN4RCxpQkFBWSxHQUFaLFlBQVksQ0FBYztRQU5wQyx5Q0FBeUM7UUFDekMseUJBQW9CLEdBQUcsT0FBTyxDQUFDLHdDQUF3QyxDQUFDLENBQUM7SUFNdEUsQ0FBQztJQUVKLG9FQUFvRTtJQUNwRSxLQUFLLENBQUMsUUFBUTtRQUNaLElBQUksQ0FBQyxPQUFPLEdBQUcsSUFBSSxDQUFDO1FBQ3BCLE1BQU0sSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDO1FBQ3RCLE1BQU0sSUFBSSxDQUFDLHdCQUF3QixFQUFFLENBQUM7UUFDdEMsSUFBSSxDQUFDLE9BQU8sR0FBRyxLQUFLLENBQUM7SUFDdkIsQ0FBQztJQUVELG1HQUFtRztJQUNuRyxLQUFLLENBQUMsUUFBUTtRQUNaLElBQUksQ0FBQyxJQUFJ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LENBQUM7YUFDeEYsQ0FBQyxDQUFDO1FBQ0wsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRU8sOEJBQThCO1FBQ3BDLE1BQU0sRUFBRSxLQUFLLEVBQUUsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDO1FBQzVCLE9BQU87WUFDTCwrQkFBK0IsRUFBRSxLQUFLLENBQUMsK0JBQStCO1lBQ3RFLHVCQUF1QixFQUFFLEtBQUssQ0FBQywrQkFBK0I7Z0JBQzVELENBQUMsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUM7Z0JBQzNFLENBQUMsQ0FBQyxJQUFJO1lBQ1IsOEJBQThCLEVBQUUsS0FBSyxDQUFDLDhCQUE4QjtZQUNwRSxzQkFBc0IsRUFBRSxLQUFLLENBQUMsOEJBQThCO2dCQUMxRCxDQUFDLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsbUJBQW1CLENBQUMsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDO2dCQUMxRSxDQUFDLENBQUMsSUFBSTtTQUNULENBQUM7SUFDSixDQUFDOytHQWxOVSw2QkFBNkI7bUdBQTdCLDZCQUE2QixpRUNkMUMsdTdPQXVLQTs7NEZEekphLDZCQUE2QjtrQkFKekMsU0FBUzsrQkFDRSwyQkFBMkIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb21wb25lbnQgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IEZvcm1BcnJheSwgRm9ybUJ1aWxkZXIsIEZvcm1Hcm91cCB9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcbmltcG9ydCB7IElBcHBsaWNhdGlvbiB9IGZyb20gJ0BjOHkvY2xpZW50JztcbmltcG9ydCB7IEFsZXJ0U2VydmljZSwgZ2V0dGV4dCB9IGZyb20gJ0BjOHkvbmd4LWNvbXBvbmVudHMnO1xuaW1wb3J0IHsgRGVmYXVsdFN1YnNjcmlwdGlvbnMsIFBhcnRpYWxBcHBzTGlzdCB9IGZyb20gJy4vZGVmYXVsdC1zdWJzY3JpcHRpb25zLm1vZGVsJztcbmltcG9ydCB7IERlZmF1bHRTdWJzY3JpcHRpb25zU2VydmljZSB9IGZyb20gJy4vZGVmYXVsdC1zdWJzY3JpcHRpb25zLnNlcnZpY2UnO1xuXG4vKipcbiAqIFRoZSBjb21wb25lbnQgc2hvd3MgdGhlIG1haW4gdmlldyBmb3IgbWFuYWdpbmcgZGVmYXVsdCBzdWJzY3JpcHRpb25zIGNvbmZpZ3VyYXRpb24uXG4gKi9cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ2M4eS1kZWZhdWx0LXN1YnNjcmlwdGlvbnMnLFxuICB0ZW1wbGF0ZVVybDogJy4vZGVmYXVsdC1zdWJzY3JpcHRpb25zLmNvbXBvbmVudC5odG1sJ1xufSlcbmV4cG9ydCBjbGFzcyBEZWZhdWx0U3Vic2NyaXB0aW9uc0NvbXBvbmVudCB7XG4gIC8qKiBEZWZhdWx0IHN1YnNjcmlwdGlvbnMgaW5oZXJpdGVkIGZyb20gcGFyZW50IHRlbmFudC4gKi9cbiAgcGFyZW50RGVmYXVsdFN1YnNjcmlwdGlvbnM6IERlZmF1bHRTdWJzY3JpcHRpb25zO1xuICAvKiogRGVmYXVsdCBzdWJzY3JpcHRpb25zIGRlZmluZWQgaW4gdGhlIGN1cnJlbnQgdGVuYW50LiAqL1xuICBjdXJyZW50RGVmYXVsdFN1YnNjcmlwdGlvbnM6IERlZmF1bHRTdWJzY3JpcHRpb25zO1xuICAvKiogRm9ybSBvYmplY3QuICovXG4gIGZvcm06IEZvcm1Hcm91cDtcbiAgLyoqIFdoZXRoZXIgdGhlIGNvbmZpZ3VyYXRpb24gaXMgYmVpbmcgbG9hZGVkLiAqL1xuICBsb2FkaW5nOiBib29sZWFuO1xuICAvKiogSGludCB0ZXh0IGZvciBkaXNhYmxlZCBjaGVja2JveGVzLiAqL1xuICBkaXNhYmxlZENoZWNrYm94SGludCA9IGdldHRleHQoJ1NlbGVjdCBcIk92ZXJyaWRlIGluaGVyaXRlZFwiIHRvIGVuYWJsZS4nKTtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIGZiOiBGb3JtQnVpbGRlcixcbiAgICBwcml2YXRlIGRlZmF1bHRTdWJzY3JpcHRpb25zU2VydmljZTogRGVmYXVsdFN1YnNjcmlwdGlvbnNTZXJ2aWNlLFxuICAgIHByaXZhdGUgYWxlcnRTZXJ2aWNlOiBBbGVydFNlcnZpY2VcbiAgKSB7fVxuXG4gIC8qKiBJbml0aWFsaXplcyB0aGUgbG9hZGluZyBvZiB0aGUgZm9ybSBhbmQgdGhlIGN1cnJlbnQgc2V0dGluZ3MuICovXG4gIGFzeW5jIG5nT25Jbml0KCkge1xuICAgIHRoaXMubG9hZGluZyA9IHRydWU7XG4gICAgYXdhaXQgdGhpcy5pbml0Rm9ybSgpO1xuICAgIGF3YWl0IHRoaXMubG9hZERlZmF1bHRTdWJzY3JpcHRpb25zKCk7XG4gICAgdGhpcy5sb2FkaW5nID0gZmFsc2U7XG4gIH1cblxuICAvKiogTG9hZHMgdGhlIGxpc3Qgb2YgYXBwcywgYnVpbGRzIHRoZSBmb3JtIGFuZCBob29rcyB2YWx1ZSBjaGFuZ2UgZXZlbnRzIGZvciBvdmVycmlkZSBzd2l0Y2hlcy4gKi9cbiAgYXN5bmMgaW5pdEZvcm0oKSB7XG4gICAgdGhpcy5mb3JtID0gdGhpcy5mYi5ncm91cCh7XG4gICAgICBvdmVycmlkZU9uQ3JlYXRpb25TdWJzY3JpcHRpb25zOiBbJyddLFxuICAgICAgb3ZlcnJpZGVPblVwZ3JhZGVTdWJzY3JpcHRpb25zOiBbJyddLFxuICAgICAgYXBwUm93czogdGhpcy5mYi5hcnJheShbXSlcbiAgICB9KTtcblxuICAgIGNvbnN0IGFwcHMgPSBhd2FpdCB0aGlzLmRlZmF1bHRTdWJzY3JpcHRpb25zU2VydmljZS5nZXRTdWJzY3JpYmFibGVUZW5hbnRBcHBzKCk7XG4gICAgY29uc3QgYXBwUm93cyA9IHRoaXMuZm9ybS5jb250cm9scy5hcHBSb3dzIGFzIEZvcm1BcnJheTtcbiAgICBhcHBzLmZvckVhY2goYXBwID0+IHtcbiAgICAgIGFwcFJvd3MucHVzaChcbiAgICAgICAgdGhpcy5mYi5ncm91cCh7XG4gICAgICAgICAgYXBwOiBbYXBwXSxcbiAgICAgICAgICBzdWJzY3JpYmVkT25DcmVhdGlvbjogWycnXSxcbiAgICAgICAgICBzdWJzY3JpYmVkT25VcGdyYWRlOiBbJyddXG4gICAgICAgIH0pXG4gICAgICApO1xuICAgIH0pO1xuXG4gICAgdGhpcy5mb3JtXG4gICAgICAuZ2V0KCdvdmVycmlkZU9uQ3JlYXRpb25TdWJzY3JpcHRpb25zJylcbiAgICAgIC52YWx1ZUNoYW5nZXMuc3Vic2NyaWJlKHZhbHVlID0+IHRoaXMub25PdmVycmlkZU9uQ3JlYXRpb25TdWJzY3JpcHRpb25zQ2hhbmdlKHZhbHVlKSk7XG5cbiAgICB0aGlzLmZvcm1cbiAgICAgIC5nZXQoJ292ZXJyaWRlT25VcGdyYWRlU3Vic2NyaXB0aW9ucycpXG4gICAgICAudmFsdWVDaGFuZ2VzLnN1YnNjcmliZSh2YWx1ZSA9PiB0aGlzLm9uT3ZlcnJpZGVPblVwZ3JhZGVTdWJzY3JpcHRpb25zQ2hhbmdlKHZhbHVlKSk7XG4gIH1cblxuICAvKipcbiAgICogQ2hlY2tzIGlmIGdpdmVuIGFwcGxpY2F0aW9uIHJvdyBzaG91bGQgYmUgZGlzcGxheWVkLlxuICAgKiBUaGUgcm93IGlzIGRpc3BsYXllZCB3aGVuIGFueSBvZiBpdHMgY2hlY2tib3hlcyBpcyBzZWxlY3RlZCBvciBhbnkgb2YgdGhlIGxpc3RzIGlzIGJlaW5nIG92ZXJyaWRkZW4uXG4gICAqL1xuICBzaG91bGRTaG93QXBwUm93KGFwcFJvd1Jhd1ZhbHVlKTogYm9vbGVhbiB7XG4gICAgY29uc3QgeyBzdWJzY3JpYmVkT25DcmVhdGlvbiwgc3Vic2NyaWJlZE9uVXBncmFkZSB9ID0gYXBwUm93UmF3VmFsdWU7XG4gICAgY29uc3QgeyBvdmVycmlkZU9uQ3JlYXRpb25TdWJzY3JpcHRpb25zLCBvdmVycmlkZU9uVXBncmFkZVN1YnNjcmlwdGlvbnMgfSA9IHRoaXMuZm9ybS52YWx1ZTtcblxuICAgIHJldHVybiAoXG4gICAgICBzdWJzY3JpYmVkT25DcmVhdGlvbiB8fFxuICAgICAgc3Vic2NyaWJlZE9uVXBncmFkZSB8fFxuICAgICAgb3ZlcnJpZGVPbkNyZWF0aW9uU3Vic2NyaXB0aW9ucyB8fFxuICAgICAgb3ZlcnJpZGVPblVwZ3JhZGVTdWJzY3JpcHRpb25zXG4gICAgKTtcbiAgfVxuXG4gIC8qKiBDaGVja3MgaWYgdGhlcmUgYXJlIG5vIGFwcGxpY2F0aW9uIHJvd3MgdG8gYmUgZGlzcGxheWVkLiAqL1xuICBpc0VtcHR5VmlldygpOiBib29sZWFuIHtcbiAgICByZXR1cm4gIXRoaXMuZm9ybVxuICAgICAgLmdldFJhd1ZhbHVlKClcbiAgICAgIC5hcHBSb3dzLnNvbWUoYXBwUm93UmF3VmFsdWUgPT4gdGhpcy5zaG91bGRTaG93QXBwUm93KGFwcFJvd1Jhd1ZhbHVlKSk7XG4gIH1cblxuICAvKipcbiAgICogQ2hlY2tzIGlmIGdpdmVuIGFwcGxpY2F0aW9uIGlzIHN1YnNjcmliZWQgKHByZXNlbnQgaW4gdGhlIGdpdmVuIGxpc3Qgb2YgYXBwbGljYXRpb25zKS5cbiAgICogQHBhcmFtIGFwcCBBcHBsaWNhdGlvbiBvYmplY3QgdG8gY2hlY2suXG4gICAqIEBwYXJhbSBzdWJzY3JpYmVkQXBwcyBUaGUgbGlzdCBvZiBhcHBsaWNhdGlvbiBvYmplY3RzIHRvIGNoZWNrIGFnYWluc3QuXG4gICAqIEByZXR1cm5zIFRydWUsIGlmIHRoZSBhcHBsaWNhdGlvbiBpcyBwcmVzZW50IGluIHRoZSBsaXN0LlxuICAgKi9cbiAgaXNTdWJzY3JpYmVkKGFwcDogSUFwcGxpY2F0aW9uLCBzdWJzY3JpYmVkQXBwczogUGFydGlhbEFwcHNMaXN0KTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHN1YnNjcmliZWRBcHBzICYmIHN1YnNjcmliZWRBcHBzLnNvbWUoc3Vic2NyaWJlZEFwcCA9PiBzdWJzY3JpYmVkQXBwLm5hbWUgPT09IGFwcC5uYW1lKTtcbiAgfVxuXG4gIC8qKiBTYXZlcyB0aGUgY3VycmVudCB2YWx1ZSBvZiBmb3JtIG9iamVjdCB0byBiYWNrZW5kLiAqL1xuICBhc3luYyBzYXZlKCkge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBkZWZhdWx0U3Vic2NyaXB0aW9ucyA9IHRoaXMuZ2V0RGVmYXVsdFN1YnNjcmlwdGlvbnNGb3JTYXZlKCk7XG4gICAgICBhd2FpdCB0aGlzLmRlZmF1bHRTdWJzY3JpcHRpb25zU2VydmljZS5zYXZlRGVmYXVsdFN1YnNjcmlwdGlvbnNUb0N1cnJlbnRUZW5hbnQoXG4gICAgICAgIGRlZmF1bHRTdWJzY3JpcHRpb25zXG4gICAgICApO1xuICAgICAgdGhpcy5hbGVydFNlcnZpY2Uuc3VjY2VzcyhnZXR0ZXh0KCdTYXZlZC4nKSk7XG4gICAgfSBjYXRjaCAoZXgpIHtcbiAgICAgIHRoaXMuYWxlcnRTZXJ2aWNlLmFkZFNlcnZlckZhaWx1cmUoZXgpO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgb25PdmVycmlkZU9uQ3JlYXRpb25TdWJzY3JpcHRpb25zQ2hhbmdlKG92ZXJyaWRlT25DcmVhdGlvblN1YnNjcmlwdGlvbnM6IGJvb2xlYW4pIHtcbiAgICBpZiAob3ZlcnJpZGVPbkNyZWF0aW9uU3Vic2NyaXB0aW9ucykge1xuICAgICAgdGhpcy5lbmFibGVTdWJzY3JpYmVPbkNyZWF0aW9uQ2hlY2tib3hlcygpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICB0aGlzLmRpc2FibGVTdWJzY3JpYmVPbkNyZWF0aW9uQ2hlY2tib3hlcygpO1xuICAgIHRoaXMucmVzdG9yZVN1YnNjcmliZU9uQ3JlYXRpb25Gcm9tUGFyZW50KCk7XG4gIH1cblxuICBwcml2YXRlIGVuYWJsZVN1YnNjcmliZU9uQ3JlYXRpb25DaGVja2JveGVzKCkge1xuICAgIGNvbnN0IGFwcFJvd3NDb250cm9scyA9ICh0aGlzLmZvcm0uY29udHJvbHMuYXBwUm93cyBhcyBGb3JtQXJyYXkpLmNvbnRyb2xzO1xuICAgIGFwcFJvd3NDb250cm9scy5mb3JFYWNoKGFwcFJvd0NvbnRyb2wgPT4ge1xuICAgICAgYXBwUm93Q29udHJvbC5nZXQoJ3N1YnNjcmliZWRPbkNyZWF0aW9uJykuZW5hYmxlKHsgZW1pdEV2ZW50OiBmYWxzZSB9KTtcbiAgICB9KTtcbiAgfVxuXG4gIHByaXZhdGUgZGlzYWJsZVN1YnNjcmliZU9uQ3JlYXRpb25DaGVja2JveGVzKCkge1xuICAgIGNvbnN0IGFwcFJvd3NDb250cm9scyA9ICh0aGlzLmZvcm0uY29udHJvbHMuYXBwUm93cyBhcyBGb3JtQXJyYXkpLmNvbnRyb2xzO1xuICAgIGFwcFJvd3NDb250cm9scy5mb3JFYWNoKGFwcFJvd0NvbnRyb2wgPT4ge1xuICAgICAgYXBwUm93Q29udHJvbC5nZXQoJ3N1YnNjcmliZWRPbkNyZWF0aW9uJykuZGlzYWJsZSh7IGVtaXRFdmVudDogZmFsc2UgfSk7XG4gICAgfSk7XG4gIH1cblxuICBwcml2YXRlIHJlc3RvcmVTdWJzY3JpYmVPbkNyZWF0aW9uRnJvbVBhcmVudCgpIHtcbiAgICBjb25zdCBhcHBSb3dzQ29udHJvbHMgPSAodGhpcy5mb3JtLmNvbnRyb2xzLmFwcFJvd3MgYXMgRm9ybUFycmF5KS5jb250cm9scztcbiAgICBhcHBSb3dzQ29udHJvbHMuZm9yRWFjaChhcHBSb3dDb250cm9sID0+IHtcbiAgICAgIGFwcFJvd0NvbnRyb2wucGF0Y2hWYWx1ZSh7XG4gICAgICAgIHN1YnNjcmliZWRPbkNyZWF0aW9uOiB0aGlzLmlzU3Vic2NyaWJlZChcbiAgICAgICAgICBhcHBSb3dDb250cm9sLnZhbHVlLmFwcCxcbiAgICAgICAgICB0aGlzLnBhcmVudERlZmF1bHRTdWJzY3JpcHRpb25zLm9uQ3JlYXRpb25TdWJzY3JpcHRpb25zXG4gICAgICAgIClcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBvbk92ZXJyaWRlT25VcGdyYWRlU3Vic2NyaXB0aW9uc0NoYW5nZShvdmVycmlkZU9uVXBncmFkZVN1YnNjcmlwdGlvbnM6IGJvb2xlYW4pIHtcbiAgICBpZiAob3ZlcnJpZGVPblVwZ3JhZGVTdWJzY3JpcHRpb25zKSB7XG4gICAgICB0aGlzLmVuYWJsZVN1YnNjcmliZU9uVXBncmFkZUNoZWNrYm94ZXMoKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdGhpcy5kaXNhYmxlU3Vic2NyaWJlT25VcGdyYWRlQ2hlY2tib3hlcygpO1xuICAgIHRoaXMucmVzdG9yZVN1YnNjcmliZU9uVXBncmFkZUZyb21QYXJlbnQoKTtcbiAgfVxuXG4gIHByaXZhdGUgZW5hYmxlU3Vic2NyaWJlT25VcGdyYWRlQ2hlY2tib3hlcygpIHtcbiAgICBjb25zdCBhcHBSb3dzQ29udHJvbHMgPSAodGhpcy5mb3JtLmNvbnRyb2xzLmFwcFJvd3MgYXMgRm9ybUFycmF5KS5jb250cm9scztcbiAgICBhcHBSb3dzQ29udHJvbHMuZm9yRWFjaChhcHBSb3dDb250cm9sID0+IHtcbiAgICAgIGFwcFJvd0NvbnRyb2wuZ2V0KCdzdWJzY3JpYmVkT25VcGdyYWRlJykuZW5hYmxlKHsgZW1pdEV2ZW50OiBmYWxzZSB9KTtcbiAgICB9KTtcbiAgfVxuXG4gIHByaXZhdGUgZGlzYWJsZVN1YnNjcmliZU9uVXBncmFkZUNoZWNrYm94ZXMoKSB7XG4gICAgY29uc3QgYXBwUm93c0NvbnRyb2xzID0gKHRoaXMuZm9ybS5jb250cm9scy5hcHBSb3dzIGFzIEZvcm1BcnJheSkuY29udHJvbHM7XG4gICAgYXBwUm93c0NvbnRyb2xzLmZvckVhY2goYXBwUm93Q29udHJvbCA9PiB7XG4gICAgICBhcHBSb3dDb250cm9sLmdldCgnc3Vic2NyaWJlZE9uVXBncmFkZScpLmRpc2FibGUoeyBlbWl0RXZlbnQ6IGZhbHNlIH0pO1xuICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSByZXN0b3JlU3Vic2NyaWJlT25VcGdyYWRlRnJvbVBhcmVudCgpIHtcbiAgICBjb25zdCBhcHBSb3dzQ29udHJvbHMgPSAodGhpcy5mb3JtLmNvbnRyb2xzLmFwcFJvd3MgYXMgRm9ybUFycmF5KS5jb250cm9scztcbiAgICBhcHBSb3dzQ29udHJvbHMuZm9yRWFjaChhcHBSb3dDb250cm9sID0+IHtcbiAgICAgIGFwcFJvd0NvbnRyb2wucGF0Y2hWYWx1ZSh7XG4gICAgICAgIHN1YnNjcmliZWRPblVwZ3JhZGU6IHRoaXMuaXNTdWJzY3JpYmVkKFxuICAgICAgICAgIGFwcFJvd0NvbnRyb2wudmFsdWUuYXBwLFxuICAgICAgICAgIHRoaXMucGFyZW50RGVmYXVsdFN1YnNjcmlwdGlvbnMub25VcGdyYWRlU3Vic2NyaXB0aW9uc1xuICAgICAgICApXG4gICAgICB9KTtcbiAgICB9KTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgbG9hZERlZmF1bHRTdWJzY3JpcHRpb25zKCkge1xuICAgIHRoaXMucGFyZW50RGVmYXVsdFN1YnNjcmlwdGlvbnMgPVxuICAgICAgYXdhaXQgdGhpcy5kZWZhdWx0U3Vic2NyaXB0aW9uc1NlcnZpY2UuZ2V0RGVmYXVsdFN1YnNjcmlwdGlvbnNFdmFsdWF0ZWRGcm9tUGFyZW50VGVuYW50KCk7XG4gICAgdGhpcy5jdXJyZW50RGVmYXVsdFN1YnNjcmlwdGlvbnMgPVxuICAgICAgYXdhaXQgdGhpcy5kZWZhdWx0U3Vic2NyaXB0aW9uc1NlcnZpY2UuZ2V0RGVmYXVsdFN1YnNjcmlwdGlvbnNGcm9tQ3VycmVudFRlbmFudCgpO1xuXG4gICAgY29uc3QgeyBvdmVycmlkZU9uQ3JlYXRpb25TdWJzY3JpcHRpb25zLCBvdmVycmlkZU9uVXBncmFkZVN1YnNjcmlwdGlvbnMgfSA9XG4gICAgICB0aGlzLmN1cnJlbnREZWZhdWx0U3Vic2NyaXB0aW9ucztcbiAgICBjb25zdCBvbkNyZWF0aW9uU3Vic2NyaXB0aW9ucyA9IG92ZXJyaWRlT25DcmVhdGlvblN1YnNjcmlwdGlvbnNcbiAgICAgID8gdGhpcy5jdXJyZW50RGVmYXVsdFN1YnNjcmlwdGlvbnMub25DcmVhdGlvblN1YnNjcmlwdGlvbnNcbiAgICAgIDogdGhpcy5wYXJlbnREZWZhdWx0U3Vic2NyaXB0aW9ucy5vbkNyZWF0aW9uU3Vic2NyaXB0aW9ucztcbiAgICBjb25zdCBvblVwZ3JhZGVTdWJzY3JpcHRpb25zID0gb3ZlcnJpZGVPblVwZ3JhZGVTdWJzY3JpcHRpb25zXG4gICAgICA/IHRoaXMuY3VycmVudERlZmF1bHRTdWJzY3JpcHRpb25zLm9uVXBncmFkZVN1YnNjcmlwdGlvbnNcbiAgICAgIDogdGhpcy5wYXJlbnREZWZhdWx0U3Vic2NyaXB0aW9ucy5vblVwZ3JhZGVTdWJzY3JpcHRpb25zO1xuXG4gICAgdGhpcy5mb3JtLnBhdGNoVmFsdWUoe1xuICAgICAgb3ZlcnJpZGVPbkNyZWF0aW9uU3Vic2NyaXB0aW9ucyxcbiAgICAgIG92ZXJyaWRlT25VcGdyYWRlU3Vic2NyaXB0aW9uc1xuICAgIH0pO1xuICAgICh0aGlzLmZvcm0uY29udHJvbHMuYXBwUm93cyBhcyBGb3JtQXJyYXkpLmNvbnRyb2xzLmZvckVhY2goYXBwUm93Q29udHJvbCA9PiB7XG4gICAgICBhcHBSb3dDb250cm9sLnBhdGNoVmFsdWUoe1xuICAgICAgICBzdWJzY3JpYmVkT25DcmVhdGlvbjogdGhpcy5pc1N1YnNjcmliZWQoYXBwUm93Q29udHJvbC52YWx1ZS5hcHAsIG9uQ3JlYXRpb25TdWJzY3JpcHRpb25zKSxcbiAgICAgICAgc3Vic2NyaWJlZE9uVXBncmFkZTogdGhpcy5pc1N1YnNjcmliZWQoYXBwUm93Q29udHJvbC52YWx1ZS5hcHAsIG9uVXBncmFkZVN1YnNjcmlwdGlvbnMpXG4gICAgICB9KTtcbiAgICB9KTtcbiAgfVxuXG4gIHByaXZhdGUgZ2V0RGVmYXVsdFN1YnNjcmlwdGlvbnNGb3JTYXZlKCk6IERlZmF1bHRTdWJzY3JpcHRpb25zIHtcbiAgICBjb25zdCB7IHZhbHVlIH0gPSB0aGlzLmZvcm07XG4gICAgcmV0dXJuIHtcbiAgICAgIG92ZXJyaWRlT25DcmVhdGlvblN1YnNjcmlwdGlvbnM6IHZhbHVlLm92ZXJyaWRlT25DcmVhdGlvblN1YnNjcmlwdGlvbnMsXG4gICAgICBvbkNyZWF0aW9uU3Vic2NyaXB0aW9uczogdmFsdWUub3ZlcnJpZGVPbkNyZWF0aW9uU3Vic2NyaXB0aW9uc1xuICAgICAgICA/IHZhbHVlLmFwcFJvd3MuZmlsdGVyKGFwcCA9PiBhcHAuc3Vic2NyaWJlZE9uQ3JlYXRpb24pLm1hcChhcHAgPT4gYXBwLmFwcClcbiAgICAgICAgOiBudWxsLFxuICAgICAgb3ZlcnJpZGVPblVwZ3JhZGVTdWJzY3JpcHRpb25zOiB2YWx1ZS5vdmVycmlkZU9uVXBncmFkZVN1YnNjcmlwdGlvbnMsXG4gICAgICBvblVwZ3JhZGVTdWJzY3JpcHRpb25zOiB2YWx1ZS5vdmVycmlkZU9uVXBncmFkZVN1YnNjcmlwdGlvbnNcbiAgICAgICAgPyB2YWx1ZS5hcHBSb3dzLmZpbHRlcihhcHAgPT4gYXBwLnN1YnNjcmliZWRPblVwZ3JhZGUpLm1hcChhcHAgPT4gYXBwLmFwcClcbiAgICAgICAgOiBudWxsXG4gICAgfTtcbiAgfVxufVxuIiwiPGM4eS10aXRsZT57eyAnRGVmYXVsdCBzdWJzY3JpcHRpb25zJyB8IHRyYW5zbGF0ZSB9fTwvYzh5LXRpdGxlPlxuXG48Yzh5LWJyZWFkY3J1bWI+XG4gIDxjOHktYnJlYWRjcnVtYi1pdGVtIFtsYWJlbF09XCInRWNvc3lzdGVtJyB8IHRyYW5zbGF0ZVwiIFtpY29uXT1cIidjOHktYXRvbSdcIj48L2M4eS1icmVhZGNydW1iLWl0ZW0+XG4gIDxjOHktYnJlYWRjcnVtYi1pdGVtXG4gICAgW2xhYmVsXT1cIidEZWZhdWx0IHN1YnNjcmlwdGlvbnMnIHwgdHJhbnNsYXRlXCJcbiAgICBbaWNvbl09XCInYzh5LWF0b20nXCJcbiAgPjwvYzh5LWJyZWFkY3J1bWItaXRlbT5cbjwvYzh5LWJyZWFkY3J1bWI+XG5cbjxmb3JtIFtmb3JtR3JvdXBdPVwiZm9ybVwiIChuZ1N1Ym1pdCk9XCJzYXZlKClcIj5cbiAgPGRpdiBjbGFzcz1cImNhcmQgY2FyZC0tZnVsbHBhZ2UgY29sLWxnLW1heFwiPlxuICAgIDxkaXYgY2xhc3M9XCJjYXJkLWhlYWRlciBzZXBhcmF0b3JcIj5cbiAgICAgIDxkaXYgY2xhc3M9XCJjYXJkLXRpdGxlXCIgdHJhbnNsYXRlPkFwcGxpY2F0aW9uczwvZGl2PlxuICAgIDwvZGl2PlxuICAgIDxkaXYgY2xhc3M9XCJpbm5lci1zY3JvbGxcIj5cbiAgICAgIDxkaXYgY2xhc3M9XCJzdGlja3ktdG9wIHNlcGFyYXRvci1ib3R0b21cIj5cbiAgICAgICAgPGRpdiBjbGFzcz1cImQtZmxleFwiPlxuICAgICAgICAgIDxkaXYgY2xhc3M9XCJjb2wtc20tNiBjb2wteHMtNiBwLTI0IHAtdC0xNiBwLWwteHMtMTZcIj5cbiAgICAgICAgICAgIDxwIHRyYW5zbGF0ZT5cbiAgICAgICAgICAgICAgQ29uZmlndXJlIGRlZmF1bHQgc3Vic2NyaXB0aW9ucyBpbiB0aGUgcGxhdGZvcm0sIGJvdGggZm9yIHRlbmFudCBjcmVhdGlvbiBhbmQgZm9yXG4gICAgICAgICAgICAgIHBsYXRmb3JtIHVwZ3JhZGUuIFRvIGRpc3BsYXkgYSBmdWxsIGxpc3Qgb2YgYXZhaWxhYmxlIGFwcGxpY2F0aW9ucywgb3ZlcnJpZGUgaW5oZXJpdGVkXG4gICAgICAgICAgICAgIHNldHRpbmdzLlxuICAgICAgICAgICAgPC9wPlxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgIDxkaXYgY2xhc3M9XCJjb2wtc20tNiBjb2wteHMtNiBiZy1sZXZlbC0xIHAtMTYgdGV4dC1jZW50ZXIgc2VwYXJhdG9yLWJvdHRvbVwiPlxuICAgICAgICAgICAgPGRpdiBjbGFzcz1cInJvd1wiPlxuICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwiY29sLXNtLTYgY29sLXhzLTZcIj5cbiAgICAgICAgICAgICAgICA8cD48c3Ryb25nIHRyYW5zbGF0ZT5TdWJzY3JpYmVkIG9uIHRlbmFudCBjcmVhdGlvbjwvc3Ryb25nPjwvcD5cbiAgICAgICAgICAgICAgICA8ZGl2PlxuICAgICAgICAgICAgICAgICAgPGxhYmVsIGNsYXNzPVwiYzh5LXN3aXRjaFwiIHRpdGxlPVwie3sgJ092ZXJyaWRlIGluaGVyaXRlZCcgfCB0cmFuc2xhdGUgfX1cIj5cbiAgICAgICAgICAgICAgICAgICAgPGlucHV0IHR5cGU9XCJjaGVja2JveFwiIGZvcm1Db250cm9sTmFtZT1cIm92ZXJyaWRlT25DcmVhdGlvblN1YnNjcmlwdGlvbnNcIiAvPlxuICAgICAgICAgICAgICAgICAgICA8c3Bhbj48L3NwYW4+XG4gICAgICAgICAgICAgICAgICAgIDxzcGFuPlxuICAgICAgICAgICAgICAgICAgICAgIHt7ICdPdmVycmlkZSBpbmhlcml0ZWQnIHwgdHJhbnNsYXRlIH19XG4gICAgICAgICAgICAgICAgICAgIDwvc3Bhbj5cbiAgICAgICAgICAgICAgICAgIDwvbGFiZWw+XG4gICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwiY29sLXNtLTYgY29sLXhzLTZcIj5cbiAgICAgICAgICAgICAgICA8cD48c3Ryb25nIHRyYW5zbGF0ZT5TdWJzY3JpYmVkIG9uIHBsYXRmb3JtIHVwZ3JhZGU8L3N0cm9uZz48L3A+XG4gICAgICAgICAgICAgICAgPGRpdj5cbiAgICAgICAgICAgICAgICAgIDxsYWJlbCBjbGFzcz1cImM4eS1zd2l0Y2hcIiB0aXRsZT1cInt7ICdPdmVycmlkZSBpbmhlcml0ZWQnIHwgdHJhbnNsYXRlIH19XCI+XG4gICAgICAgICAgICAgICAgICAgIDxpbnB1dCB0eXBlPVwiY2hlY2tib3hcIiBmb3JtQ29udHJvbE5hbWU9XCJvdmVycmlkZU9uVXBncmFkZVN1YnNjcmlwdGlvbnNcIiAvPlxuICAgICAgICAgICAgICAgICAgICA8c3Bhbj48L3NwYW4+XG4gICAgICAgICAgICAgICAgICAgIDxzcGFuPlxuICAgICAgICAgICAgICAgICAgICAgIHt7ICdPdmVycmlkZSBpbmhlcml0ZWQnIHwgdHJhbnNsYXRlIH19XG4gICAgICAgICAgICAgICAgICAgIDwvc3Bhbj5cbiAgICAgICAgICAgICAgICAgIDwvbGFiZWw+XG4gICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgIDwvZGl2PlxuICAgICAgPC9kaXY+XG4gICAgICA8ZGl2IGNsYXNzPVwiY2FyZC1ibG9ja1wiICpuZ0lmPVwibG9hZGluZ1wiPjwvZGl2PlxuICAgICAgPGRpdiBjbGFzcz1cImNhcmQtYmxvY2sgY2FyZC1ibG9jayBkLWZsZXggYS1pLWNlbnRlciBqLWMtY2VudGVyIGQtY29sXCIgKm5nSWY9XCJsb2FkaW5nXCI+XG4gICAgICAgIDxjOHktbG9hZGluZz48L2M4eS1sb2FkaW5nPlxuICAg