@c8y/ngx-components
Version:
Angular modules for Cumulocity IoT applications
69 lines • 32.6 kB
JavaScript
import { Component, Input } from '@angular/core';
import { gettext } from '@c8y/ngx-components';
import { ControlContainer, NgForm } from '@angular/forms';
import { TenantUiService } from '@c8y/ngx-components';
import { TenantLoginOptionType } from '@c8y/client';
import * as i0 from "@angular/core";
import * as i1 from "@c8y/ngx-components";
import * as i2 from "@angular/common";
import * as i3 from "@angular/forms";
import * as i4 from "ngx-bootstrap/popover";
export class LoginSettingsComponent {
constructor(tenantUiService) {
this.tenantUiService = tenantUiService;
this.PREFERRED_LOGIN_MODE_POPOVER = gettext('Main difference is the storage of the authentication information. With Basic Auth, it is saved in a session storage and with OAI-Secure in a HttpOnly cookie. OAI-Secure grant is recommended as the authentication information is not accessible via JavaScript. Single sign-on redirect allows a user to login with a single 3rd-party authorization server using the OAuth2 protocol.');
this.ENFORCED_BY_PLATFORM_POPOVER = gettext('The setting is enforced on the platform level.');
this.IGNORE_CASE_SENSITIVITY_POPOVER = gettext('If selected, the letter case of the username does not matter during login.');
this.tenantLoginOptionTypeEnum = TenantLoginOptionType;
this.PASSWORD_CATEGORY = 'password';
this.LIMIT_VALIDITY_KEY = 'limit.validity';
this.TENANT_STRENGTH_VALIDITY_KEY = 'strength.validity';
this.SYSTEM_STRENGTH_VALIDITY_KEY = 'enforce.strength';
}
ngOnChanges(changes) {
if (changes.authConfiguration && changes.authConfiguration.currentValue) {
this.isOauth2 = !!changes.authConfiguration.currentValue.loginOptions.find(this.tenantUiService.isOauth2);
}
}
get systemPasswordLimitValidity() {
return this.authConfiguration.systemOptions[this.PASSWORD_CATEGORY][this.LIMIT_VALIDITY_KEY];
}
get passwordLimitValidity() {
return this.systemPasswordLimitValidity !== null
? this.systemPasswordLimitValidity
: this.authConfiguration.tenantOptions[this.PASSWORD_CATEGORY][this.LIMIT_VALIDITY_KEY];
}
set passwordLimitValidity(value) {
if (this.systemPasswordLimitValidity === null) {
this.authConfiguration.tenantOptions[this.PASSWORD_CATEGORY][this.LIMIT_VALIDITY_KEY] = value;
}
}
get systemPasswordEnforceStrength() {
return this.authConfiguration.systemOptions[this.PASSWORD_CATEGORY][this.SYSTEM_STRENGTH_VALIDITY_KEY];
}
get passwordEnforceStrength() {
return this.systemPasswordEnforceStrength
? this.systemPasswordEnforceStrength
: this.authConfiguration.tenantOptions[this.PASSWORD_CATEGORY][this.TENANT_STRENGTH_VALIDITY_KEY];
}
set passwordEnforceStrength(value) {
if (!this.systemPasswordEnforceStrength) {
this.authConfiguration.tenantOptions[this.PASSWORD_CATEGORY][this.TENANT_STRENGTH_VALIDITY_KEY] = value;
}
}
get tenantLoginIgnoreCase() {
return this.authConfiguration.tenantOptions['configuration']['tenant.login.ignore-case'];
}
set tenantLoginIgnoreCase(value) {
this.authConfiguration.tenantOptions['configuration']['tenant.login.ignore-case'] = value;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: LoginSettingsComponent, deps: [{ token: i1.TenantUiService }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: LoginSettingsComponent, selector: "c8y-login-settings", inputs: { authConfiguration: "authConfiguration" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"card-block separator-top overflow-auto\" *ngIf=\"authConfiguration\">\n <div class=\"col-sm-2\">\n <div class=\"h4 text-normal text-right text-left-xs\">{{ 'Login settings' | translate }}</div>\n </div>\n\n <div class=\"col-sm-9\">\n <div class=\"row m-b-8\">\n <c8y-form-group class=\"col-sm-6\">\n <label>\n {{ 'Preferred login mode' | translate }}\n <button\n class=\"btn-help btn-help--sm\"\n type=\"button\"\n [attr.aria-label]=\"'Help' | translate\"\n popover=\"{{ PREFERRED_LOGIN_MODE_POPOVER | translate }}\"\n placement=\"right\"\n triggers=\"focus\"\n container=\"body\"\n ></button>\n </label>\n <div class=\"c8y-select-wrapper\">\n <select\n [attr.aria-label]=\"'Auth type' | translate\"\n class=\"form-control\"\n id=\"preferredLoginOptionType\"\n name=\"preferredLoginOptionType\"\n [(ngModel)]=\"authConfiguration.preferredLoginOptionType\"\n >\n <option value=\"{{ tenantLoginOptionTypeEnum.BASIC }}\" translate>Basic Auth</option>\n <option value=\"{{ tenantLoginOptionTypeEnum.OAUTH2_INTERNAL }}\" translate>\n OAI-Secure\n </option>\n <option value=\"{{ tenantLoginOptionTypeEnum.OAUTH2 }}\" [disabled]=\"!isOauth2\" translate>\n Single sign-on redirect\n </option>\n </select>\n </div>\n </c8y-form-group>\n </div>\n <div class=\"row\">\n <div class=\"col-sm-6\">\n <c8y-form-group>\n <label title=\"{{ 'Password validity limit' | translate }}\">\n {{ 'Password validity limit' | translate }}\n <button\n class=\"btn-help btn-help--sm\"\n type=\"button\"\n [attr.aria-label]=\"'Help' | translate\"\n popover=\"{{ ENFORCED_BY_PLATFORM_POPOVER | translate }}\"\n placement=\"bottom\"\n triggers=\"focus\"\n *ngIf=\"systemPasswordLimitValidity\"\n ></button>\n </label>\n <div class=\"input-group\">\n <input\n type=\"number\"\n name=\"passwordLimitValidity\"\n class=\"form-control text-right\"\n [(ngModel)]=\"passwordLimitValidity\"\n min=\"0\"\n max=\"999999\"\n step=\"1\"\n required\n [disabled]=\"systemPasswordLimitValidity\"\n />\n <span class=\"input-group-addon\" translate>days</span>\n </div>\n <p class=\"help-block\">\n {{ 'Default: 0 (unlimited validity)' | translate }}\n </p>\n </c8y-form-group>\n </div>\n <div class=\"col-sm-6\">\n <c8y-form-group>\n <label title=\"{{ 'Password strength' | translate }}\">\n {{ 'Password strength' | translate }}\n <button\n class=\"btn-help btn-help--sm\"\n type=\"button\"\n [attr.aria-label]=\"'Help' | translate\"\n popover=\"{{ ENFORCED_BY_PLATFORM_POPOVER | translate }}\"\n placement=\"bottom\"\n triggers=\"focus\"\n *ngIf=\"systemPasswordEnforceStrength\"\n ></button>\n </label>\n <div>\n <label\n title=\"{{ 'Enforce that all passwords are strong' | translate }}\"\n class=\"c8y-switch\"\n >\n <input\n type=\"checkbox\"\n name=\"passwordEnforceStrength\"\n data-cy=\"c8y-form-group--password-enforce-toggle-btn\"\n [(ngModel)]=\"passwordEnforceStrength\"\n [disabled]=\"systemPasswordEnforceStrength\"\n />\n <span></span>\n <span>{{ 'Enforce strong passwords (green)' | translate }}</span>\n </label>\n </div>\n </c8y-form-group>\n </div>\n </div>\n <div class=\"row\">\n <div class=\"col-sm-6\">\n <c8y-form-group>\n <label\n title=\"{{ 'Ignore case when logging in' | translate }}\"\n data-cy=\"c8y-authentication-configuration--ignore-case-when-logging-in\"\n class=\"c8y-switch\"\n >\n <input\n type=\"checkbox\"\n name=\"tenantLoginIgnoreCase\"\n [(ngModel)]=\"tenantLoginIgnoreCase\"\n />\n <span></span>\n <span>{{ 'Ignore case when logging in' | translate }}</span>\n <button\n class=\"btn-help btn-help--sm\"\n type=\"button\"\n [attr.aria-label]=\"'Help' | translate\"\n popover=\"{{ IGNORE_CASE_SENSITIVITY_POPOVER | translate }}\"\n placement=\"right\"\n triggers=\"focus\"\n container=\"body\"\n ></button>\n </label>\n </c8y-form-group>\n </div>\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "directive", type: i1.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.MinValidationDirective, selector: "[min]", inputs: ["min"] }, { kind: "directive", type: i1.MaxValidationDirective, selector: "[max]", inputs: ["max"] }, { kind: "directive", type: i3.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i3.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i3.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i3.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i3.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i3.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { kind: "directive", type: i3.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }, { kind: "directive", type: i3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i1.FormGroupComponent, selector: "c8y-form-group", inputs: ["hasError", "hasWarning", "hasSuccess", "novalidation", "status"] }, { kind: "directive", type: i1.RequiredInputPlaceholderDirective, selector: "input[required], input[formControlName]" }, { kind: "directive", type: i4.PopoverDirective, selector: "[popover]", inputs: ["adaptivePosition", "boundariesElement", "popover", "popoverContext", "popoverTitle", "placement", "outsideClick", "triggers", "container", "containerClass", "isOpen", "delay"], outputs: ["onShown", "onHidden"], exportAs: ["bs-popover"] }, { kind: "pipe", type: i1.C8yTranslatePipe, name: "translate" }], viewProviders: [{ provide: ControlContainer, useExisting: NgForm }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: LoginSettingsComponent, decorators: [{
type: Component,
args: [{ selector: 'c8y-login-settings', viewProviders: [{ provide: ControlContainer, useExisting: NgForm }], template: "<div class=\"card-block separator-top overflow-auto\" *ngIf=\"authConfiguration\">\n <div class=\"col-sm-2\">\n <div class=\"h4 text-normal text-right text-left-xs\">{{ 'Login settings' | translate }}</div>\n </div>\n\n <div class=\"col-sm-9\">\n <div class=\"row m-b-8\">\n <c8y-form-group class=\"col-sm-6\">\n <label>\n {{ 'Preferred login mode' | translate }}\n <button\n class=\"btn-help btn-help--sm\"\n type=\"button\"\n [attr.aria-label]=\"'Help' | translate\"\n popover=\"{{ PREFERRED_LOGIN_MODE_POPOVER | translate }}\"\n placement=\"right\"\n triggers=\"focus\"\n container=\"body\"\n ></button>\n </label>\n <div class=\"c8y-select-wrapper\">\n <select\n [attr.aria-label]=\"'Auth type' | translate\"\n class=\"form-control\"\n id=\"preferredLoginOptionType\"\n name=\"preferredLoginOptionType\"\n [(ngModel)]=\"authConfiguration.preferredLoginOptionType\"\n >\n <option value=\"{{ tenantLoginOptionTypeEnum.BASIC }}\" translate>Basic Auth</option>\n <option value=\"{{ tenantLoginOptionTypeEnum.OAUTH2_INTERNAL }}\" translate>\n OAI-Secure\n </option>\n <option value=\"{{ tenantLoginOptionTypeEnum.OAUTH2 }}\" [disabled]=\"!isOauth2\" translate>\n Single sign-on redirect\n </option>\n </select>\n </div>\n </c8y-form-group>\n </div>\n <div class=\"row\">\n <div class=\"col-sm-6\">\n <c8y-form-group>\n <label title=\"{{ 'Password validity limit' | translate }}\">\n {{ 'Password validity limit' | translate }}\n <button\n class=\"btn-help btn-help--sm\"\n type=\"button\"\n [attr.aria-label]=\"'Help' | translate\"\n popover=\"{{ ENFORCED_BY_PLATFORM_POPOVER | translate }}\"\n placement=\"bottom\"\n triggers=\"focus\"\n *ngIf=\"systemPasswordLimitValidity\"\n ></button>\n </label>\n <div class=\"input-group\">\n <input\n type=\"number\"\n name=\"passwordLimitValidity\"\n class=\"form-control text-right\"\n [(ngModel)]=\"passwordLimitValidity\"\n min=\"0\"\n max=\"999999\"\n step=\"1\"\n required\n [disabled]=\"systemPasswordLimitValidity\"\n />\n <span class=\"input-group-addon\" translate>days</span>\n </div>\n <p class=\"help-block\">\n {{ 'Default: 0 (unlimited validity)' | translate }}\n </p>\n </c8y-form-group>\n </div>\n <div class=\"col-sm-6\">\n <c8y-form-group>\n <label title=\"{{ 'Password strength' | translate }}\">\n {{ 'Password strength' | translate }}\n <button\n class=\"btn-help btn-help--sm\"\n type=\"button\"\n [attr.aria-label]=\"'Help' | translate\"\n popover=\"{{ ENFORCED_BY_PLATFORM_POPOVER | translate }}\"\n placement=\"bottom\"\n triggers=\"focus\"\n *ngIf=\"systemPasswordEnforceStrength\"\n ></button>\n </label>\n <div>\n <label\n title=\"{{ 'Enforce that all passwords are strong' | translate }}\"\n class=\"c8y-switch\"\n >\n <input\n type=\"checkbox\"\n name=\"passwordEnforceStrength\"\n data-cy=\"c8y-form-group--password-enforce-toggle-btn\"\n [(ngModel)]=\"passwordEnforceStrength\"\n [disabled]=\"systemPasswordEnforceStrength\"\n />\n <span></span>\n <span>{{ 'Enforce strong passwords (green)' | translate }}</span>\n </label>\n </div>\n </c8y-form-group>\n </div>\n </div>\n <div class=\"row\">\n <div class=\"col-sm-6\">\n <c8y-form-group>\n <label\n title=\"{{ 'Ignore case when logging in' | translate }}\"\n data-cy=\"c8y-authentication-configuration--ignore-case-when-logging-in\"\n class=\"c8y-switch\"\n >\n <input\n type=\"checkbox\"\n name=\"tenantLoginIgnoreCase\"\n [(ngModel)]=\"tenantLoginIgnoreCase\"\n />\n <span></span>\n <span>{{ 'Ignore case when logging in' | translate }}</span>\n <button\n class=\"btn-help btn-help--sm\"\n type=\"button\"\n [attr.aria-label]=\"'Help' | translate\"\n popover=\"{{ IGNORE_CASE_SENSITIVITY_POPOVER | translate }}\"\n placement=\"right\"\n triggers=\"focus\"\n container=\"body\"\n ></button>\n </label>\n </c8y-form-group>\n </div>\n </div>\n </div>\n</div>\n" }]
}], ctorParameters: () => [{ type: i1.TenantUiService }], propDecorators: { authConfiguration: [{
type: Input
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibG9naW4tc2V0dGluZ3MuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vYXV0aC1jb25maWd1cmF0aW9uL2Jhc2ljLXNldHRpbmdzL2xvZ2luLXNldHRpbmdzLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uL2F1dGgtY29uZmlndXJhdGlvbi9iYXNpYy1zZXR0aW5ncy9sb2dpbi1zZXR0aW5ncy5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFFLEtBQUssRUFBaUIsTUFBTSxlQUFlLENBQUM7QUFDaEUsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQzlDLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUUxRCxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDdEQsT0FBTyxFQUFFLHFCQUFxQixFQUFFLE1BQU0sYUFBYSxDQUFDOzs7Ozs7QUFPcEQsTUFBTSxPQUFPLHNCQUFzQjtJQW9CakMsWUFBb0IsZUFBZ0M7UUFBaEMsb0JBQWUsR0FBZixlQUFlLENBQWlCO1FBbkJwRCxpQ0FBNEIsR0FBRyxPQUFPLENBQ3BDLDBYQUEwWCxDQUMzWCxDQUFDO1FBQ0YsaUNBQTRCLEdBQUcsT0FBTyxDQUFDLGdEQUFnRCxDQUFDLENBQUM7UUFDekYsb0NBQStCLEdBQUcsT0FBTyxDQUN2Qyw0RUFBNEUsQ0FDN0UsQ0FBQztRQU1GLDhCQUF5QixHQUFHLHFCQUFxQixDQUFDO1FBRTFDLHNCQUFpQixHQUFHLFVBQVUsQ0FBQztRQUMvQix1QkFBa0IsR0FBRyxnQkFBZ0IsQ0FBQztRQUN0QyxpQ0FBNEIsR0FBRyxtQkFBbUIsQ0FBQztRQUNuRCxpQ0FBNEIsR0FBRyxrQkFBa0IsQ0FBQztJQUVILENBQUM7SUFFeEQsV0FBVyxDQUFDLE9BQXNCO1FBQ2hDLElBQUksT0FBTyxDQUFDLGlCQUFpQixJQUFJLE9BQU8sQ0FBQyxpQkFBaUIsQ0FBQyxZQUFZLEVBQUUsQ0FBQztZQUN4RSxJQUFJLENBQUMsUUFBUSxHQUFHLENBQUMsQ0FBQyxPQUFPLENBQUMsaUJBQWlCLENBQUMsWUFBWSxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQ3hFLElBQUksQ0FBQyxlQUFlLENBQUMsUUFBUSxDQUM5QixDQUFDO1FBQ0osQ0FBQztJQUNILENBQUM7SUFFRCxJQUFJLDJCQUEyQjtRQUM3QixPQUFPLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLGlCQUFpQixDQUFDLENBQUMsSUFBSSxDQUFDLGtCQUFrQixDQUFDLENBQUM7SUFDL0YsQ0FBQztJQUVELElBQUkscUJBQXFCO1FBQ3ZCLE9BQU8sSUFBSSxDQUFDLDJCQUEyQixLQUFLLElBQUk7WUFDOUMsQ0FBQyxDQUFDLElBQUksQ0FBQywyQkFBMkI7WUFDbEMsQ0FBQyxDQUFDLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLGlCQUFpQixDQUFDLENBQUMsSUFBSSxDQUFDLGtCQUFrQixDQUFDLENBQUM7SUFDNUYsQ0FBQztJQUVELElBQUkscUJBQXFCLENBQUMsS0FBSztRQUM3QixJQUFJLElBQUksQ0FBQywyQkFBMkIsS0FBSyxJQUFJLEVBQUUsQ0FBQztZQUM5QyxJQUFJLENBQUMsaUJBQWlCLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxHQUFHLEtBQUssQ0FBQztRQUNoRyxDQUFDO0lBQ0gsQ0FBQztJQUVELElBQUksNkJBQTZCO1FBQy9CLE9BQU8sSUFBSSxDQUFDLGlCQUFpQixDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsaUJBQWlCLENBQUMsQ0FDakUsSUFBSSxDQUFDLDRCQUE0QixDQUNsQyxDQUFDO0lBQ0osQ0FBQztJQUVELElBQUksdUJBQXVCO1FBQ3pCLE9BQU8sSUFBSSxDQUFDLDZCQUE2QjtZQUN2QyxDQUFDLENBQUMsSUFBSSxDQUFDLDZCQUE2QjtZQUNwQyxDQUFDLENBQUMsSUFBSSxDQUFDLGlCQUFpQixDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsaUJBQWlCLENBQUMsQ0FDMUQsSUFBSSxDQUFDLDRCQUE0QixDQUNsQyxDQUFDO0lBQ1IsQ0FBQztJQUVELElBQUksdUJBQXVCLENBQUMsS0FBSztRQUMvQixJQUFJLENBQUMsSUFBSSxDQUFDLDZCQUE2QixFQUFFLENBQUM7WUFDeEMsSUFBSSxDQUFDLGlCQUFpQixDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsaUJBQWlCLENBQUMsQ0FDMUQsSUFBSSxDQUFDLDRCQUE0QixDQUNsQyxHQUFHLEtBQUssQ0FBQztRQUNaLENBQUM7SUFDSCxDQUFDO0lBRUQsSUFBSSxxQkFBcUI7UUFDdkIsT0FBTyxJQUFJLENBQUMsaUJBQWlCLENBQUMsYUFBYSxDQUFDLGVBQWUsQ0FBQyxDQUFDLDBCQUEwQixDQUFDLENBQUM7SUFDM0YsQ0FBQztJQUVELElBQUkscUJBQXFCLENBQUMsS0FBSztRQUM3QixJQUFJLENBQUMsaUJBQWlCLENBQUMsYUFBYSxDQUFDLGVBQWUsQ0FBQyxDQUFDLDBCQUEwQixDQUFDLEdBQUcsS0FBSyxDQUFDO0lBQzVGLENBQUM7K0dBMUVVLHNCQUFzQjttR0FBdEIsc0JBQXNCLG1JQ1puQyx5Z0tBd0lBLGs4RkQ5SGlCLENBQUMsRUFBRSxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsV0FBVyxFQUFFLE1BQU0sRUFBRSxDQUFDOzs0RkFFeEQsc0JBQXNCO2tCQUxsQyxTQUFTOytCQUNFLG9CQUFvQixpQkFFZixDQUFDLEVBQUUsT0FBTyxFQUFFLGdCQUFnQixFQUFFLFdBQVcsRUFBRSxNQUFNLEVBQUUsQ0FBQztvRkFZbkUsaUJBQWlCO3NCQURoQixLQUFLIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29tcG9uZW50LCBJbnB1dCwgU2ltcGxlQ2hhbmdlcyB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgZ2V0dGV4dCB9IGZyb20gJ0BjOHkvbmd4LWNvbXBvbmVudHMnO1xuaW1wb3J0IHsgQ29udHJvbENvbnRhaW5lciwgTmdGb3JtIH0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xuaW1wb3J0IHsgQXV0aENvbmZpZ3VyYXRpb24gfSBmcm9tICcuL2F1dGgtY29uZmlndXJhdGlvbi5tb2RlbCc7XG5pbXBvcnQgeyBUZW5hbnRVaVNlcnZpY2UgfSBmcm9tICdAYzh5L25neC1jb21wb25lbnRzJztcbmltcG9ydCB7IFRlbmFudExvZ2luT3B0aW9uVHlwZSB9IGZyb20gJ0BjOHkvY2xpZW50JztcblxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnYzh5LWxvZ2luLXNldHRpbmdzJyxcbiAgdGVtcGxhdGVVcmw6ICcuL2xvZ2luLXNldHRpbmdzLmNvbXBvbmVudC5odG1sJyxcbiAgdmlld1Byb3ZpZGVyczogW3sgcHJvdmlkZTogQ29udHJvbENvbnRhaW5lciwgdXNlRXhpc3Rpbmc6IE5nRm9ybSB9XVxufSlcbmV4cG9ydCBjbGFzcyBMb2dpblNldHRpbmdzQ29tcG9uZW50IHtcbiAgUFJFRkVSUkVEX0xPR0lOX01PREVfUE9QT1ZFUiA9IGdldHRleHQoXG4gICAgJ01haW4gZGlmZmVyZW5jZSBpcyB0aGUgc3RvcmFnZSBvZiB0aGUgYXV0aGVudGljYXRpb24gaW5mb3JtYXRpb24uIFdpdGggQmFzaWMgQXV0aCwgaXQgaXMgc2F2ZWQgaW4gYSBzZXNzaW9uIHN0b3JhZ2UgYW5kIHdpdGggT0FJLVNlY3VyZSBpbiBhIEh0dHBPbmx5IGNvb2tpZS4gT0FJLVNlY3VyZSBncmFudCBpcyByZWNvbW1lbmRlZCBhcyB0aGUgYXV0aGVudGljYXRpb24gaW5mb3JtYXRpb24gaXMgbm90IGFjY2Vzc2libGUgdmlhIEphdmFTY3JpcHQuIFNpbmdsZSBzaWduLW9uIHJlZGlyZWN0IGFsbG93cyBhIHVzZXIgdG8gbG9naW4gd2l0aCBhIHNpbmdsZSAzcmQtcGFydHkgYXV0aG9yaXphdGlvbiBzZXJ2ZXIgdXNpbmcgdGhlIE9BdXRoMiBwcm90b2NvbC4nXG4gICk7XG4gIEVORk9SQ0VEX0JZX1BMQVRGT1JNX1BPUE9WRVIgPSBnZXR0ZXh0KCdUaGUgc2V0dGluZyBpcyBlbmZvcmNlZCBvbiB0aGUgcGxhdGZvcm0gbGV2ZWwuJyk7XG4gIElHTk9SRV9DQVNFX1NFTlNJVElWSVRZX1BPUE9WRVIgPSBnZXR0ZXh0KFxuICAgICdJZiBzZWxlY3RlZCwgdGhlIGxldHRlciBjYXNlIG9mIHRoZSB1c2VybmFtZSBkb2VzIG5vdCBtYXR0ZXIgZHVyaW5nIGxvZ2luLidcbiAgKTtcblxuICBASW5wdXQoKVxuICBhdXRoQ29uZmlndXJhdGlvbjogQXV0aENvbmZpZ3VyYXRpb247XG5cbiAgaXNPYXV0aDI6IGJvb2xlYW47XG4gIHRlbmFudExvZ2luT3B0aW9uVHlwZUVudW0gPSBUZW5hbnRMb2dpbk9wdGlvblR5cGU7XG5cbiAgcHJpdmF0ZSBQQVNTV09SRF9DQVRFR09SWSA9ICdwYXNzd29yZCc7XG4gIHByaXZhdGUgTElNSVRfVkFMSURJVFlfS0VZID0gJ2xpbWl0LnZhbGlkaXR5JztcbiAgcHJpdmF0ZSBURU5BTlRfU1RSRU5HVEhfVkFMSURJVFlfS0VZID0gJ3N0cmVuZ3RoLnZhbGlkaXR5JztcbiAgcHJpdmF0ZSBTWVNURU1fU1RSRU5HVEhfVkFMSURJVFlfS0VZID0gJ2VuZm9yY2Uuc3RyZW5ndGgnO1xuXG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgdGVuYW50VWlTZXJ2aWNlOiBUZW5hbnRVaVNlcnZpY2UpIHt9XG5cbiAgbmdPbkNoYW5nZXMoY2hhbmdlczogU2ltcGxlQ2hhbmdlcyk6IHZvaWQge1xuICAgIGlmIChjaGFuZ2VzLmF1dGhDb25maWd1cmF0aW9uICYmIGNoYW5nZXMuYXV0aENvbmZpZ3VyYXRpb24uY3VycmVudFZhbHVlKSB7XG4gICAgICB0aGlzLmlzT2F1dGgyID0gISFjaGFuZ2VzLmF1dGhDb25maWd1cmF0aW9uLmN1cnJlbnRWYWx1ZS5sb2dpbk9wdGlvbnMuZmluZChcbiAgICAgICAgdGhpcy50ZW5hbnRVaVNlcnZpY2UuaXNPYXV0aDJcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgZ2V0IHN5c3RlbVBhc3N3b3JkTGltaXRWYWxpZGl0eSgpIHtcbiAgICByZXR1cm4gdGhpcy5hdXRoQ29uZmlndXJhdGlvbi5zeXN0ZW1PcHRpb25zW3RoaXMuUEFTU1dPUkRfQ0FURUdPUlldW3RoaXMuTElNSVRfVkFMSURJVFlfS0VZXTtcbiAgfVxuXG4gIGdldCBwYXNzd29yZExpbWl0VmFsaWRpdHkoKSB7XG4gICAgcmV0dXJuIHRoaXMuc3lzdGVtUGFzc3dvcmRMaW1pdFZhbGlkaXR5ICE9PSBudWxsXG4gICAgICA/IHRoaXMuc3lzdGVtUGFzc3dvcmRMaW1pdFZhbGlkaXR5XG4gICAgICA6IHRoaXMuYXV0aENvbmZpZ3VyYXRpb24udGVuYW50T3B0aW9uc1t0aGlzLlBBU1NXT1JEX0NBVEVHT1JZXVt0aGlzLkxJTUlUX1ZBTElESVRZX0tFWV07XG4gIH1cblxuICBzZXQgcGFzc3dvcmRMaW1pdFZhbGlkaXR5KHZhbHVlKSB7XG4gICAgaWYgKHRoaXMuc3lzdGVtUGFzc3dvcmRMaW1pdFZhbGlkaXR5ID09PSBudWxsKSB7XG4gICAgICB0aGlzLmF1dGhDb25maWd1cmF0aW9uLnRlbmFudE9wdGlvbnNbdGhpcy5QQVNTV09SRF9DQVRFR09SWV1bdGhpcy5MSU1JVF9WQUxJRElUWV9LRVldID0gdmFsdWU7XG4gICAgfVxuICB9XG5cbiAgZ2V0IHN5c3RlbVBhc3N3b3JkRW5mb3JjZVN0cmVuZ3RoKCkge1xuICAgIHJldHVybiB0aGlzLmF1dGhDb25maWd1cmF0aW9uLnN5c3RlbU9wdGlvbnNbdGhpcy5QQVNTV09SRF9DQVRFR09SWV1bXG4gICAgICB0aGlzLlNZU1RFTV9TVFJFTkdUSF9WQUxJRElUWV9LRVlcbiAgICBdO1xuICB9XG5cbiAgZ2V0IHBhc3N3b3JkRW5mb3JjZVN0cmVuZ3RoKCkge1xuICAgIHJldHVybiB0aGlzLnN5c3RlbVBhc3N3b3JkRW5mb3JjZVN0cmVuZ3RoXG4gICAgICA/IHRoaXMuc3lzdGVtUGFzc3dvcmRFbmZvcmNlU3RyZW5ndGhcbiAgICAgIDogdGhpcy5hdXRoQ29uZmlndXJhdGlvbi50ZW5hbnRPcHRpb25zW3RoaXMuUEFTU1dPUkRfQ0FURUdPUlldW1xuICAgICAgICAgIHRoaXMuVEVOQU5UX1NUUkVOR1RIX1ZBTElESVRZX0tFWVxuICAgICAgICBdO1xuICB9XG5cbiAgc2V0IHBhc3N3b3JkRW5mb3JjZVN0cmVuZ3RoKHZhbHVlKSB7XG4gICAgaWYgKCF0aGlzLnN5c3RlbVBhc3N3b3JkRW5mb3JjZVN0cmVuZ3RoKSB7XG4gICAgICB0aGlzLmF1dGhDb25maWd1cmF0aW9uLnRlbmFudE9wdGlvbnNbdGhpcy5QQVNTV09SRF9DQVRFR09SWV1bXG4gICAgICAgIHRoaXMuVEVOQU5UX1NUUkVOR1RIX1ZBTElESVRZX0tFWVxuICAgICAgXSA9IHZhbHVlO1xuICAgIH1cbiAgfVxuXG4gIGdldCB0ZW5hbnRMb2dpbklnbm9yZUNhc2UoKSB7XG4gICAgcmV0dXJuIHRoaXMuYXV0aENvbmZpZ3VyYXRpb24udGVuYW50T3B0aW9uc1snY29uZmlndXJhdGlvbiddWyd0ZW5hbnQubG9naW4uaWdub3JlLWNhc2UnXTtcbiAgfVxuXG4gIHNldCB0ZW5hbnRMb2dpbklnbm9yZUNhc2UodmFsdWUpIHtcbiAgICB0aGlzLmF1dGhDb25maWd1cmF0aW9uLnRlbmFudE9wdGlvbnNbJ2NvbmZpZ3VyYXRpb24nXVsndGVuYW50LmxvZ2luLmlnbm9yZS1jYXNlJ10gPSB2YWx1ZTtcbiAgfVxufVxuIiwiPGRpdiBjbGFzcz1cImNhcmQtYmxvY2sgc2VwYXJhdG9yLXRvcCBvdmVyZmxvdy1hdXRvXCIgKm5nSWY9XCJhdXRoQ29uZmlndXJhdGlvblwiPlxuICA8ZGl2IGNsYXNzPVwiY29sLXNtLTJcIj5cbiAgICA8ZGl2IGNsYXNzPVwiaDQgdGV4dC1ub3JtYWwgdGV4dC1yaWdodCB0ZXh0LWxlZnQteHNcIj57eyAnTG9naW4gc2V0dGluZ3MnIHwgdHJhbnNsYXRlIH19PC9kaXY+XG4gIDwvZGl2PlxuXG4gIDxkaXYgY2xhc3M9XCJjb2wtc20tOVwiPlxuICAgIDxkaXYgY2xhc3M9XCJyb3cgbS1iLThcIj5cbiAgICAgIDxjOHktZm9ybS1ncm91cCBjbGFzcz1cImNvbC1zbS02XCI+XG4gICAgICAgIDxsYWJlbD5cbiAgICAgICAgICB7eyAnUHJlZmVycmVkIGxvZ2luIG1vZGUnIHwgdHJhbnNsYXRlIH19XG4gICAgICAgICAgPGJ1dHRvblxuICAgICAgICAgICAgY2xhc3M9XCJidG4taGVscCBidG4taGVscC0tc21cIlxuICAgICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgICBbYXR0ci5hcmlhLWxhYmVsXT1cIidIZWxwJyB8IHRyYW5zbGF0ZVwiXG4gICAgICAgICAgICBwb3BvdmVyPVwie3sgUFJFRkVSUkVEX0xPR0lOX01PREVfUE9QT1ZFUiB8IHRyYW5zbGF0ZSB9fVwiXG4gICAgICAgICAgICBwbGFjZW1lbnQ9XCJyaWdodFwiXG4gICAgICAgICAgICB0cmlnZ2Vycz1cImZvY3VzXCJcbiAgICAgICAgICAgIGNvbnRhaW5lcj1cImJvZHlcIlxuICAgICAgICAgID48L2J1dHRvbj5cbiAgICAgICAgPC9sYWJlbD5cbiAgICAgICAgPGRpdiBjbGFzcz1cImM4eS1zZWxlY3Qtd3JhcHBlclwiPlxuICAgICAgICAgIDxzZWxlY3RcbiAgICAgICAgICAgIFthdHRyLmFyaWEtbGFiZWxdPVwiJ0F1dGggdHlwZScgfCB0cmFuc2xhdGVcIlxuICAgICAgICAgICAgY2xhc3M9XCJmb3JtLWNvbnRyb2xcIlxuICAgICAgICAgICAgaWQ9XCJwcmVmZXJyZWRMb2dpbk9wdGlvblR5cGVcIlxuICAgICAgICAgICAgbmFtZT1cInByZWZlcnJlZExvZ2luT3B0aW9uVHlwZVwiXG4gICAgICAgICAgICBbKG5nTW9kZWwpXT1cImF1dGhDb25maWd1cmF0aW9uLnByZWZlcnJlZExvZ2luT3B0aW9uVHlwZVwiXG4gICAgICAgICAgPlxuICAgICAgICAgICAgPG9wdGlvbiB2YWx1ZT1cInt7IHRlbmFudExvZ2luT3B0aW9uVHlwZUVudW0uQkFTSUMgfX1cIiB0cmFuc2xhdGU+QmFzaWMgQXV0aDwvb3B0aW9uPlxuICAgICAgICAgICAgPG9wdGlvbiB2YWx1ZT1cInt7IHRlbmFudExvZ2luT3B0aW9uVHlwZUVudW0uT0FVVEgyX0lOVEVSTkFMIH19XCIgdHJhbnNsYXRlPlxuICAgICAgICAgICAgICBPQUktU2VjdXJlXG4gICAgICAgICAgICA8L29wdGlvbj5cbiAgICAgICAgICAgIDxvcHRpb24gdmFsdWU9XCJ7eyB0ZW5hbnRMb2dpbk9wdGlvblR5cGVFbnVtLk9BVVRIMiB9fVwiIFtkaXNhYmxlZF09XCIhaXNPYXV0aDJcIiB0cmFuc2xhdGU+XG4gICAgICAgICAgICAgIFNpbmdsZSBzaWduLW9uIHJlZGlyZWN0XG4gICAgICAgICAgICA8L29wdGlvbj5cbiAgICAgICAgICA8L3NlbGVjdD5cbiAgICAgICAgPC9kaXY+XG4gICAgICA8L2M4eS1mb3JtLWdyb3VwPlxuICAgIDwvZGl2PlxuICAgIDxkaXYgY2xhc3M9XCJyb3dcIj5cbiAgICAgIDxkaXYgY2xhc3M9XCJjb2wtc20tNlwiPlxuICAgICAgICA8Yzh5LWZvcm0tZ3JvdXA+XG4gICAgICAgICAgPGxhYmVsIHRpdGxlPVwie3sgJ1Bhc3N3b3JkIHZhbGlkaXR5IGxpbWl0JyB8IHRyYW5zbGF0ZSB9fVwiPlxuICAgICAgICAgICAge3sgJ1Bhc3N3b3JkIHZhbGlkaXR5IGxpbWl0JyB8IHRyYW5zbGF0ZSB9fVxuICAgICAgICAgICAgPGJ1dHRvblxuICAgICAgICAgICAgICBjbGFzcz1cImJ0bi1oZWxwIGJ0bi1oZWxwLS1zbVwiXG4gICAgICAgICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICAgICAgICBbYXR0ci5hcmlhLWxhYmVsXT1cIidIZWxwJyB8IHRyYW5zbGF0ZVwiXG4gICAgICAgICAgICAgIHBvcG92ZXI9XCJ7eyBFTkZPUkNFRF9CWV9QTEFURk9STV9QT1BPVkVSIHwgdHJhbnNsYXRlIH19XCJcbiAgICAgICAgICAgICAgcGxhY2VtZW50PVwiYm90dG9tXCJcbiAgICAgICAgICAgICAgdHJpZ2dlcnM9XCJmb2N1c1wiXG4gICAgICAgICAgICAgICpuZ0lmPVwic3lzdGVtUGFzc3dvcmRMaW1pdFZhbGlkaXR5XCJcbiAgICAgICAgICAgID48L2J1dHRvbj5cbiAgICAgICAgICA8L2xhYmVsPlxuICAgICAgICAgIDxkaXYgY2xhc3M9XCJpbnB1dC1ncm91cFwiPlxuICAgICAgICAgICAgPGlucHV0XG4gICAgICAgICAgICAgIHR5cGU9XCJudW1iZXJcIlxuICAgICAgICAgICAgICBuYW1lPVwicGFzc3dvcmRMaW1pdFZhbGlkaXR5XCJcbiAgICAgICAgICAgICAgY2xhc3M9XCJmb3JtLWNvbnRyb2wgdGV4dC1yaWdodFwiXG4gICAgICAgICAgICAgIFsobmdNb2RlbCldPVwicGFzc3dvcmRMaW1pdFZhbGlkaXR5XCJcbiAgICAgICAgICAgICAgbWluPVwiMFwiXG4gICAgICAgICAgICAgIG1heD1cIjk5OTk5OVwiXG4gICAgICAgICAgICAgIHN0ZXA9XCIxXCJcbiAgICAgICAgICAgICAgcmVxdWlyZWRcbiAgICAgICAgICAgICAgW2Rpc2FibGVkXT1cInN5c3RlbVBhc3N3b3JkTGltaXRWYWxpZGl0eVwiXG4gICAgICAgICAgICAvPlxuICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJpbnB1dC1ncm91cC1hZGRvblwiIHRyYW5zbGF0ZT5kYXlzPC9zcGFuPlxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgIDxwIGNsYXNzPVwiaGVscC1ibG9ja1wiPlxuICAgICAgICAgICAge3sgJ0RlZmF1bHQ6IDAgKHVubGltaXRlZCB2YWxpZGl0eSknIHwgdHJhbnNsYXRlIH19XG4gICAgICAgICAgPC9wPlxuICAgICAgICA8L2M4eS1mb3JtLWdyb3VwPlxuICAgICAgPC9kaXY+XG4gICAgICA8ZGl2IGNsYXNzPVwiY29sLXNtLTZcIj5cbiAgICAgICAgPGM4eS1mb3JtLWdyb3VwPlxuICAgICAgICAgIDxsYWJlbCB0aXRsZT1cInt7ICdQYXNzd29yZCBzdHJlbmd0aCcgfCB0cmFuc2xhdGUgfX1cIj5cbiAgICAgICAgICAgIHt7ICdQYXNzd29yZCBzdHJlbmd0aCcgfCB0cmFuc2xhdGUgfX1cbiAgICAgICAgICAgIDxidXR0b25cbiAgICAgICAgICAgICAgY2xhc3M9XCJidG4taGVscCBidG4taGVscC0tc21cIlxuICAgICAgICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgICAgICAgW2F0dHIuYXJpYS1sYWJlbF09XCInSGVscCcgfCB0cmFuc2xhdGVcIlxuICAgICAgICAgICAgICBwb3BvdmVyPVwie3sgRU5GT1JDRURfQllfUExBVEZPUk1fUE9QT1ZFUiB8IHRyYW5zbGF0ZSB9fVwiXG4gICAgICAgICAgICAgIHBsYWNlbWVudD1cImJvdHRvbVwiXG4gICAgICAgICAgICAgIHRyaWdnZXJzPVwiZm9jdXNcIlxuICAgICAgICAgICAgICAqbmdJZj1cInN5c3RlbVBhc3N3b3JkRW5mb3JjZVN0cmVuZ3RoXCJcbiAgICAgICAgICAgID48L2J1dHRvbj5cbiAgICAgICAgICA8L2xhYmVsPlxuICAgICAgICAgIDxkaXY+XG4gICAgICAgICAgICA8bGFiZWxcbiAgICAgICAgICAgICAgdGl0bGU9XCJ7eyAnRW5mb3JjZSB0aGF0IGFsbCBwYXNzd29yZHMgYXJlIHN0cm9uZycgfCB0cmFuc2xhdGUgfX1cIlxuICAgICAgICAgICAgICBjbGFzcz1cImM4eS1zd2l0Y2hcIlxuICAgICAgICAgICAgPlxuICAgICAgICAgICAgICA8aW5wdXRcbiAgICAgICAgICAgICAgICB0eXBlPVwiY2hlY2tib3hcIlxuICAgICAgICAgICAgICAgIG5hbWU9XCJwYXNzd29yZEVuZm9yY2VTdHJlbmd0aFwiXG4gICAgICAgICAgICAgICAgZGF0YS1jeT1cImM4eS1mb3JtLWdyb3VwLS1wYXNzd29yZC1lbmZvcmNlLXRvZ2dsZS1idG5cIlxuICAgICAgICAgICAgICAgIFsobmdNb2RlbCldPVwicGFzc3dvcmRFbmZvcmNlU3RyZW5ndGhcIlxuICAgICAgICAgICAgICAgIFtkaXNhYmxlZF09XCJzeXN0ZW1QYXNzd29yZEVuZm9yY2VTdHJlbmd0aFwiXG4gICAgICAgICAgICAgIC8+XG4gICAgICAgICAgICAgIDxzcGFuPjwvc3Bhbj5cbiAgICAgICAgICAgICAgPHNwYW4+e3sgJ0VuZm9yY2Ugc3Ryb25nIHBhc3N3b3JkcyAoZ3JlZW4pJyB8IHRyYW5zbGF0ZSB9fTwvc3Bhbj5cbiAgICAgICAgICAgIDwvbGFiZWw+XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgIDwvYzh5LWZvcm0tZ3JvdXA+XG4gICAgICA8L2Rpdj5cbiAgICA8L2Rpdj5cbiAgICA8ZGl2IGNsYXNzPVwicm93XCI+XG4gICAgICA8ZGl2IGNsYXNzPVwiY29sLXNtLTZcIj5cbiAgICAgICAgPGM4eS1mb3JtLWdyb3VwPlxuICAgICAgICAgIDxsYWJlbFxuICAgICAgICAgICAgdGl0bGU9XCJ7eyAnSWdub3JlIGNhc2Ugd2hlbiBsb2dnaW5nIGluJyB8IHRyYW5zbGF0ZSB9fVwiXG4gICAgICAgICAgICBkYXRhLWN5PVwiYzh5LWF1dGhlbnRpY2F0aW9uLWNvbmZpZ3VyYXRpb24tLWlnbm9yZS1jYXNlLXdoZW4tbG9nZ2luZy1pblwiXG4gICAgICAgICAgICBjbGFzcz1cImM4eS1zd2l0Y2hcIlxuICAgICAgICAgID5cbiAgICAgICAgICAgIDxpbnB1dFxuICAgICAgICAgICAgICB0eXBlPVwiY2hlY2tib3hcIlxuICAgICAgICAgICAgICBuYW1lPVwidGVuYW50TG9naW5JZ25vcmVDYXNlXCJcbiAgICAgICAgICAgICAgWyhuZ01vZGVsKV09XCJ0ZW5hbnRMb2dpbklnbm9yZUNhc2VcIlxuICAgICAgICAgICAgLz5cbiAgICAgICAgICAgIDxzcGFuPjwvc3Bhbj5cbiAgICAgICAgICAgIDxzcGFuPnt7ICdJZ25vcmUgY2FzZSB3aGVuIGxvZ2dpbmcgaW4nIHwgdHJhbnNsYXRlIH19PC9zcGFuPlxuICAgICAgICAgICAgPGJ1dHRvblxuICAgICAgICAgICAgICBjbGFzcz1cImJ0bi1oZWxwIGJ0bi1oZWxwLS1zbVwiXG4gICAgICAgICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICAgICAgICBbYXR0ci5hcmlhLWxhYmVsXT1cIidIZWxwJyB8IHRyYW5zbGF0ZVwiXG4gICAgICAgICAgICAgIHBvcG92ZXI9XCJ7eyBJR05PUkVfQ0FTRV9TRU5TSVRJVklUWV9QT1BPVkVSIHwgdHJhbnNsYXRlIH19XCJcbiAgICAgICAgICAgICAgcGxhY2VtZW50PVwicmlnaHRcIlxuICAgICAgICAgICAgICB0cmlnZ2Vycz1cImZvY3VzXCJcbiAgICAgICAgICAgICAgY29udGFpbmVyPVwiYm9keVwiXG4gICAgICAgICAgICA+PC9idXR0b24+XG4gICAgICAgICAgPC9sYWJlbD5cbiAgICAgICAgPC9jOHktZm9ybS1ncm91cD5cbiAgICAgIDwvZGl2PlxuICAgIDwvZGl2PlxuICA8L2Rpdj5cbjwvZGl2PlxuIl19