ngx-auth-firebaseui-updated
Version:
From ngx-auth-firbaseui but updated to fix dependency issues with Angular 16. Open Source Library for Angular Web Apps to integrate a material user interface for firebase authentication
136 lines • 40.1 kB
JavaScript
import { Component, EventEmitter, Inject, Input, Output, PLATFORM_ID, ViewEncapsulation } from '@angular/core';
import { Validators } from '@angular/forms';
import { AuthProvider } from '../../services/auth-process.service';
import { NgxAuthFirebaseuiAnimations } from '../../animations';
import { isPlatformBrowser } from '@angular/common';
import * as i0 from "@angular/core";
import * as i1 from "../../services/auth-process.service";
import * as i2 from "@angular/forms";
import * as i3 from "@angular/common";
import * as i4 from "@angular/material/input";
import * as i5 from "@angular/material/form-field";
import * as i6 from "@angular/material/button";
import * as i7 from "@angular/material/icon";
import * as i8 from "../providers/auth.providers.component";
export class NgxAuthFirebaseuiLoginComponent {
constructor(
// eslint-disable-next-line @typescript-eslint/ban-types
platformId, authProcess, formBuilder) {
this.platformId = platformId;
this.authProcess = authProcess;
this.formBuilder = formBuilder;
this.providers = AuthProvider.ALL; // google, facebook, twitter, github as array or all as one single string
this.registrationEnabled = true;
this.resetPasswordEnabled = true;
// i18n
this.titleText = 'LOGIN TO YOUR ACCOUNT';
this.rememberMeText = 'Remember Me';
this.loginButtonText = 'LOGIN';
this.orLabelText = 'OR';
this.forgotPasswordText = 'Forgot Password?';
this.dontHaveAnAccountText = 'Don\'t have an account?';
this.createAccountButtonText = 'Create an account';
// i18n email
this.emailText = 'Email';
this.emailErrorRequiredText = 'Email is required';
this.emailErrorPatternText = 'Please enter a valid email address';
// i18n password
this.passwordText = 'Password';
this.passwordErrorRequiredText = 'Password is required';
// eslint-disable-next-line @angular-eslint/no-output-on-prefix
this.onCreateAccountRequested = new EventEmitter();
// eslint-disable-next-line @angular-eslint/no-output-on-prefix
this.onResetPasswordRequested = new EventEmitter();
this.onLoginButtonClicked = new EventEmitter();
this.authProviders = AuthProvider;
this.authenticationError = false;
this.onSuccess = authProcess.onSuccessEmitter;
this.onError = authProcess.onErrorEmitter;
}
get color() {
return this.authenticationError ? 'warn' : 'primary';
}
get colorAccent() {
return this.authenticationError ? 'warn' : 'accent';
}
ngOnInit() {
if (isPlatformBrowser(this.platformId)) {
this.onErrorSubscription = this.onError.subscribe(() => this.authenticationError = true);
}
this.updateAuthSnackbarMessages();
this.loginForm = this.formBuilder.group({
email: ['', [Validators.required, Validators.email]],
password: ['', Validators.required]
});
}
updateAuthSnackbarMessages() {
this.authProcess.messageOnAuthSuccess = this.messageOnAuthSuccess;
this.authProcess.messageOnAuthError = this.messageOnAuthError;
}
async login() {
// Emit event for button click
this.onLoginButtonClicked.emit();
return await this.authProcess.signInWith(this.authProviders.EmailAndPassword, {
email: this.loginForm.controls.email.value,
password: this.loginForm.controls.password.value
});
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: NgxAuthFirebaseuiLoginComponent, deps: [{ token: PLATFORM_ID }, { token: i1.AuthProcessService }, { token: i2.UntypedFormBuilder }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: NgxAuthFirebaseuiLoginComponent, selector: "ngx-auth-firebaseui-login", inputs: { logoUrl: "logoUrl", providers: "providers", appearance: "appearance", registrationEnabled: "registrationEnabled", resetPasswordEnabled: "resetPasswordEnabled", messageOnAuthSuccess: "messageOnAuthSuccess", messageOnAuthError: "messageOnAuthError", titleText: "titleText", rememberMeText: "rememberMeText", loginButtonText: "loginButtonText", orLabelText: "orLabelText", forgotPasswordText: "forgotPasswordText", dontHaveAnAccountText: "dontHaveAnAccountText", createAccountButtonText: "createAccountButtonText", emailText: "emailText", emailErrorRequiredText: "emailErrorRequiredText", emailErrorPatternText: "emailErrorPatternText", passwordText: "passwordText", passwordErrorRequiredText: "passwordErrorRequiredText" }, outputs: { onSuccess: "onSuccess", onError: "onError", onCreateAccountRequested: "onCreateAccountRequested", onResetPasswordRequested: "onResetPasswordRequested", onLoginButtonClicked: "onLoginButtonClicked" }, ngImport: i0, template: "<div style=\"flex-direction: column\" id=\"login\">\n\n <div style=\"flex-direction: column\" fxLayoutAlign=\"center center\" id=\"login-form-wrapper\">\n\n <div [@animateStagger]=\"{ value: '50' }\" id=\"login-form\">\n\n <div *ngIf=\"logoUrl\" class=\"logo\">\n <img [@animate]=\"{ value: '*', params: { x: '50px' } }\" [src]=\"logoUrl\" alt=\"logo\">\n </div>\n\n <div [@animate]=\"{ value: '*', params: { x: '-50px' } }\" class=\"title\">{{titleText}}</div>\n\n <form [@animate]=\"{value:'*',params:{duration:'300ms',y:'100px'}}\" [formGroup]=\"loginForm\" name=\"loginForm\"\n novalidate>\n\n <mat-form-field [@animate]=\"{ value: '*', params: { x: '50px' } }\" [appearance]=\"appearance\">\n <input [placeholder]=\"emailText\" formControlName=\"email\" matInput autocomplete=\"username\">\n <mat-icon [color]=\"color\" matSuffix>email</mat-icon>\n <mat-error *ngIf=\"loginForm.get('email')?.hasError('required')\">\n {{emailErrorRequiredText}}\n </mat-error>\n <mat-error\n *ngIf=\"!loginForm.get('email')?.hasError('required') &&\n loginForm.get('email')?.hasError('email')\">\n {{emailErrorPatternText}}\n </mat-error>\n </mat-form-field>\n\n <mat-form-field [@animate]=\"{ value: '*', params: { x: '50px' } }\" [appearance]=\"appearance\">\n <input [placeholder]=\"passwordText\" formControlName=\"password\" matInput type=\"password\" autocomplete=\"current-password\">\n <mat-icon [color]=\"color\" matSuffix>lock</mat-icon>\n <mat-error>\n {{passwordErrorRequiredText}}\n </mat-error>\n </mat-form-field>\n\n <div [@animate]=\"{ value: '*', params: { x: '50px' } }\"\n class=\"remember-forgot-password\" style=\"flex-direction: row\"\n fxLayout.xs=\"column\"\n fxLayoutAlign=\"space-between center\">\n <!-- <mat-checkbox class=\"remember-me\" aria-label=\"Remember Me\">-->\n <!-- {{rememberMeText}}-->\n <!-- </mat-checkbox>-->\n\n <button (click)=\"onResetPasswordRequested.emit()\"\n *ngIf=\"resetPasswordEnabled\"\n [@animate]=\"{ value: '*', params: { x: '-50px' } }\"\n [color]=\"color\"\n class=\"forgot-password\"\n mat-button\n type=\"button\">\n {{forgotPasswordText}}\n </button>\n </div>\n\n <button (click)=\"login()\"\n [color]=\"colorAccent\"\n [disabled]=\"loginForm.invalid\"\n aria-label=\"LOG IN\"\n class=\"submit-button\"\n id=\"loginButton\"\n mat-raised-button>\n {{loginButtonText}}\n </button>\n\n </form>\n\n <div *ngIf=\"providers.length > 0\"\n [@animate]=\"{ value: '*', params: { z: '50px', delay: '50ms', scale: '0.2' } }\"\n class=\"separator\">\n <span class=\"text\">{{orLabelText}}</span>\n </div>\n\n <ngx-auth-firebaseui-providers [providers]=\"providers\"\n fxLayoutAlign=\"center center\"\n layout=\"column\"\n theme=\"raised\"></ngx-auth-firebaseui-providers>\n\n <div *ngIf=\"registrationEnabled\"\n [@animateStagger]=\"{ value: '100' }\"\n class=\"register\"\n style=\"flex-direction: column\" fxLayoutAlign=\"center center\">\n <span [@animate]=\"{ value: '*', params: { x: '100px' } }\" class=\"text\">\n {{dontHaveAnAccountText}}\n </span>\n <button (click)=\"onCreateAccountRequested.emit()\"\n [@animate]=\"{ value: '*', params: { x: '-100px' } }\"\n [color]=\"color\"\n id=\"createAccountButton\"\n mat-button\n type=\"button\">{{createAccountButtonText}}</button>\n </div>\n </div>\n </div>\n</div>\n", styles: ["ngx-auth-firebaseui-login #login-form-wrapper{flex:1 0 auto;padding:32px}@media screen and (max-width: 599px){ngx-auth-firebaseui-login #login-form-wrapper{padding:16px}}ngx-auth-firebaseui-login #login-form-wrapper #login-form{width:384px;max-width:384px;padding:32px;text-align:center}@media screen and (max-width: 599px){ngx-auth-firebaseui-login #login-form-wrapper #login-form{padding:24px;width:100%}}ngx-auth-firebaseui-login #login-form-wrapper #login-form .logo{width:150px;height:150px;margin:32px auto}ngx-auth-firebaseui-login #login-form-wrapper #login-form .title{font-size:20px;margin:16px 0 32px}ngx-auth-firebaseui-login #login-form-wrapper #login-form form{width:100%;text-align:left}ngx-auth-firebaseui-login #login-form-wrapper #login-form form mat-form-field{width:100%}ngx-auth-firebaseui-login #login-form-wrapper #login-form form mat-checkbox{margin:0}ngx-auth-firebaseui-login #login-form-wrapper #login-form form .remember-forgot-password{font-size:13px;margin-top:8px}ngx-auth-firebaseui-login #login-form-wrapper #login-form form .remember-forgot-password .remember-me{margin-bottom:16px}ngx-auth-firebaseui-login #login-form-wrapper #login-form form .remember-forgot-password .forgot-password{font-size:13px;font-weight:500;margin-bottom:16px}ngx-auth-firebaseui-login #login-form-wrapper #login-form form .submit-button{width:220px;margin:16px auto;display:block}@media screen and (max-width: 599px){ngx-auth-firebaseui-login #login-form-wrapper #login-form form .submit-button{width:90%}}ngx-auth-firebaseui-login #login-form-wrapper #login-form .register{margin:32px auto 24px;font-weight:500}ngx-auth-firebaseui-login #login-form-wrapper #login-form .register .text{margin-right:8px}ngx-auth-firebaseui-login #login-form-wrapper #login-form .separator{font-size:15px;font-weight:600;margin:24px auto;position:relative;overflow:hidden;width:100px}ngx-auth-firebaseui-login #login-form-wrapper #login-form .separator .text{display:inline-flex;position:relative;padding:0 8px;z-index:9999}ngx-auth-firebaseui-login #login-form-wrapper #login-form .separator .text:before,ngx-auth-firebaseui-login #login-form-wrapper #login-form .separator .text:after{content:\"\";display:block;width:30px;position:absolute;top:10px;border-top:1px solid}ngx-auth-firebaseui-login #login-form-wrapper #login-form .separator .text:before{right:100%}ngx-auth-firebaseui-login #login-form-wrapper #login-form .separator .text:after{left:100%}ngx-auth-firebaseui-login #login-form-wrapper #login-form button.google-raised,ngx-auth-firebaseui-login #login-form-wrapper #login-form button.apple-raised,ngx-auth-firebaseui-login #login-form-wrapper #login-form button.facebook-raised,ngx-auth-firebaseui-login #login-form-wrapper #login-form button.twitter-raised,ngx-auth-firebaseui-login #login-form-wrapper #login-form button.github-raised,ngx-auth-firebaseui-login #login-form-wrapper #login-form button.microsoft-raised,ngx-auth-firebaseui-login #login-form-wrapper #login-form button.yahoo-raised{width:192px;text-transform:none;color:#fff;font-size:13px;margin-bottom:8px}@media screen and (max-width: 599px){ngx-auth-firebaseui-login #login-form-wrapper #login-form button{width:80%}}\n"], dependencies: [{ kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.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: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i4.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "component", type: i5.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i5.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "directive", type: i5.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "component", type: i6.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { kind: "component", type: i7.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i8.AuthProvidersComponent, selector: "ngx-auth-firebaseui-providers", inputs: ["theme", "layout", "providers", "tosUrl", "privacyPolicyUrl"], outputs: ["onSuccess", "onError"] }], animations: NgxAuthFirebaseuiAnimations, encapsulation: i0.ViewEncapsulation.None }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: NgxAuthFirebaseuiLoginComponent, decorators: [{
type: Component,
args: [{ selector: 'ngx-auth-firebaseui-login', encapsulation: ViewEncapsulation.None, animations: NgxAuthFirebaseuiAnimations, template: "<div style=\"flex-direction: column\" id=\"login\">\n\n <div style=\"flex-direction: column\" fxLayoutAlign=\"center center\" id=\"login-form-wrapper\">\n\n <div [@animateStagger]=\"{ value: '50' }\" id=\"login-form\">\n\n <div *ngIf=\"logoUrl\" class=\"logo\">\n <img [@animate]=\"{ value: '*', params: { x: '50px' } }\" [src]=\"logoUrl\" alt=\"logo\">\n </div>\n\n <div [@animate]=\"{ value: '*', params: { x: '-50px' } }\" class=\"title\">{{titleText}}</div>\n\n <form [@animate]=\"{value:'*',params:{duration:'300ms',y:'100px'}}\" [formGroup]=\"loginForm\" name=\"loginForm\"\n novalidate>\n\n <mat-form-field [@animate]=\"{ value: '*', params: { x: '50px' } }\" [appearance]=\"appearance\">\n <input [placeholder]=\"emailText\" formControlName=\"email\" matInput autocomplete=\"username\">\n <mat-icon [color]=\"color\" matSuffix>email</mat-icon>\n <mat-error *ngIf=\"loginForm.get('email')?.hasError('required')\">\n {{emailErrorRequiredText}}\n </mat-error>\n <mat-error\n *ngIf=\"!loginForm.get('email')?.hasError('required') &&\n loginForm.get('email')?.hasError('email')\">\n {{emailErrorPatternText}}\n </mat-error>\n </mat-form-field>\n\n <mat-form-field [@animate]=\"{ value: '*', params: { x: '50px' } }\" [appearance]=\"appearance\">\n <input [placeholder]=\"passwordText\" formControlName=\"password\" matInput type=\"password\" autocomplete=\"current-password\">\n <mat-icon [color]=\"color\" matSuffix>lock</mat-icon>\n <mat-error>\n {{passwordErrorRequiredText}}\n </mat-error>\n </mat-form-field>\n\n <div [@animate]=\"{ value: '*', params: { x: '50px' } }\"\n class=\"remember-forgot-password\" style=\"flex-direction: row\"\n fxLayout.xs=\"column\"\n fxLayoutAlign=\"space-between center\">\n <!-- <mat-checkbox class=\"remember-me\" aria-label=\"Remember Me\">-->\n <!-- {{rememberMeText}}-->\n <!-- </mat-checkbox>-->\n\n <button (click)=\"onResetPasswordRequested.emit()\"\n *ngIf=\"resetPasswordEnabled\"\n [@animate]=\"{ value: '*', params: { x: '-50px' } }\"\n [color]=\"color\"\n class=\"forgot-password\"\n mat-button\n type=\"button\">\n {{forgotPasswordText}}\n </button>\n </div>\n\n <button (click)=\"login()\"\n [color]=\"colorAccent\"\n [disabled]=\"loginForm.invalid\"\n aria-label=\"LOG IN\"\n class=\"submit-button\"\n id=\"loginButton\"\n mat-raised-button>\n {{loginButtonText}}\n </button>\n\n </form>\n\n <div *ngIf=\"providers.length > 0\"\n [@animate]=\"{ value: '*', params: { z: '50px', delay: '50ms', scale: '0.2' } }\"\n class=\"separator\">\n <span class=\"text\">{{orLabelText}}</span>\n </div>\n\n <ngx-auth-firebaseui-providers [providers]=\"providers\"\n fxLayoutAlign=\"center center\"\n layout=\"column\"\n theme=\"raised\"></ngx-auth-firebaseui-providers>\n\n <div *ngIf=\"registrationEnabled\"\n [@animateStagger]=\"{ value: '100' }\"\n class=\"register\"\n style=\"flex-direction: column\" fxLayoutAlign=\"center center\">\n <span [@animate]=\"{ value: '*', params: { x: '100px' } }\" class=\"text\">\n {{dontHaveAnAccountText}}\n </span>\n <button (click)=\"onCreateAccountRequested.emit()\"\n [@animate]=\"{ value: '*', params: { x: '-100px' } }\"\n [color]=\"color\"\n id=\"createAccountButton\"\n mat-button\n type=\"button\">{{createAccountButtonText}}</button>\n </div>\n </div>\n </div>\n</div>\n", styles: ["ngx-auth-firebaseui-login #login-form-wrapper{flex:1 0 auto;padding:32px}@media screen and (max-width: 599px){ngx-auth-firebaseui-login #login-form-wrapper{padding:16px}}ngx-auth-firebaseui-login #login-form-wrapper #login-form{width:384px;max-width:384px;padding:32px;text-align:center}@media screen and (max-width: 599px){ngx-auth-firebaseui-login #login-form-wrapper #login-form{padding:24px;width:100%}}ngx-auth-firebaseui-login #login-form-wrapper #login-form .logo{width:150px;height:150px;margin:32px auto}ngx-auth-firebaseui-login #login-form-wrapper #login-form .title{font-size:20px;margin:16px 0 32px}ngx-auth-firebaseui-login #login-form-wrapper #login-form form{width:100%;text-align:left}ngx-auth-firebaseui-login #login-form-wrapper #login-form form mat-form-field{width:100%}ngx-auth-firebaseui-login #login-form-wrapper #login-form form mat-checkbox{margin:0}ngx-auth-firebaseui-login #login-form-wrapper #login-form form .remember-forgot-password{font-size:13px;margin-top:8px}ngx-auth-firebaseui-login #login-form-wrapper #login-form form .remember-forgot-password .remember-me{margin-bottom:16px}ngx-auth-firebaseui-login #login-form-wrapper #login-form form .remember-forgot-password .forgot-password{font-size:13px;font-weight:500;margin-bottom:16px}ngx-auth-firebaseui-login #login-form-wrapper #login-form form .submit-button{width:220px;margin:16px auto;display:block}@media screen and (max-width: 599px){ngx-auth-firebaseui-login #login-form-wrapper #login-form form .submit-button{width:90%}}ngx-auth-firebaseui-login #login-form-wrapper #login-form .register{margin:32px auto 24px;font-weight:500}ngx-auth-firebaseui-login #login-form-wrapper #login-form .register .text{margin-right:8px}ngx-auth-firebaseui-login #login-form-wrapper #login-form .separator{font-size:15px;font-weight:600;margin:24px auto;position:relative;overflow:hidden;width:100px}ngx-auth-firebaseui-login #login-form-wrapper #login-form .separator .text{display:inline-flex;position:relative;padding:0 8px;z-index:9999}ngx-auth-firebaseui-login #login-form-wrapper #login-form .separator .text:before,ngx-auth-firebaseui-login #login-form-wrapper #login-form .separator .text:after{content:\"\";display:block;width:30px;position:absolute;top:10px;border-top:1px solid}ngx-auth-firebaseui-login #login-form-wrapper #login-form .separator .text:before{right:100%}ngx-auth-firebaseui-login #login-form-wrapper #login-form .separator .text:after{left:100%}ngx-auth-firebaseui-login #login-form-wrapper #login-form button.google-raised,ngx-auth-firebaseui-login #login-form-wrapper #login-form button.apple-raised,ngx-auth-firebaseui-login #login-form-wrapper #login-form button.facebook-raised,ngx-auth-firebaseui-login #login-form-wrapper #login-form button.twitter-raised,ngx-auth-firebaseui-login #login-form-wrapper #login-form button.github-raised,ngx-auth-firebaseui-login #login-form-wrapper #login-form button.microsoft-raised,ngx-auth-firebaseui-login #login-form-wrapper #login-form button.yahoo-raised{width:192px;text-transform:none;color:#fff;font-size:13px;margin-bottom:8px}@media screen and (max-width: 599px){ngx-auth-firebaseui-login #login-form-wrapper #login-form button{width:80%}}\n"] }]
}], ctorParameters: function () { return [{ type: Object, decorators: [{
type: Inject,
args: [PLATFORM_ID]
}] }, { type: i1.AuthProcessService }, { type: i2.UntypedFormBuilder }]; }, propDecorators: { logoUrl: [{
type: Input
}], providers: [{
type: Input
}], appearance: [{
type: Input
}], registrationEnabled: [{
type: Input
}], resetPasswordEnabled: [{
type: Input
}], messageOnAuthSuccess: [{
type: Input
}], messageOnAuthError: [{
type: Input
}], titleText: [{
type: Input
}], rememberMeText: [{
type: Input
}], loginButtonText: [{
type: Input
}], orLabelText: [{
type: Input
}], forgotPasswordText: [{
type: Input
}], dontHaveAnAccountText: [{
type: Input
}], createAccountButtonText: [{
type: Input
}], emailText: [{
type: Input
}], emailErrorRequiredText: [{
type: Input
}], emailErrorPatternText: [{
type: Input
}], passwordText: [{
type: Input
}], passwordErrorRequiredText: [{
type: Input
}], onSuccess: [{
type: Output
}], onError: [{
type: Output
}], onCreateAccountRequested: [{
type: Output
}], onResetPasswordRequested: [{
type: Output
}], onLoginButtonClicked: [{
type: Output
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmd4LWF1dGgtZmlyZWJhc2V1aS1sb2dpbi5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9uZ3gtYXV0aC1maXJlYmFzZXVpL3NyYy9saWIvY29tcG9uZW50cy9uZ3gtYXV0aC1maXJlYmFzZXVpLWxvZ2luL25neC1hdXRoLWZpcmViYXNldWktbG9naW4uY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvbmd4LWF1dGgtZmlyZWJhc2V1aS9zcmMvbGliL2NvbXBvbmVudHMvbmd4LWF1dGgtZmlyZWJhc2V1aS1sb2dpbi9uZ3gtYXV0aC1maXJlYmFzZXVpLWxvZ2luLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBQyxTQUFTLEVBQUUsWUFBWSxFQUFFLE1BQU0sRUFBRSxLQUFLLEVBQVUsTUFBTSxFQUFFLFdBQVcsRUFBRSxpQkFBaUIsRUFBQyxNQUFNLGVBQWUsQ0FBQztBQUNySCxPQUFPLEVBQXVDLFVBQVUsRUFBQyxNQUFNLGdCQUFnQixDQUFDO0FBQ2hGLE9BQU8sRUFBcUIsWUFBWSxFQUFDLE1BQU0scUNBQXFDLENBQUM7QUFFckYsT0FBTyxFQUFDLDJCQUEyQixFQUFDLE1BQU0sa0JBQWtCLENBQUM7QUFDN0QsT0FBTyxFQUFDLGlCQUFpQixFQUFDLE1BQU0saUJBQWlCLENBQUM7Ozs7Ozs7Ozs7QUFXbEQsTUFBTSxPQUFPLCtCQUErQjtJQTZDMUM7SUFDRSx3REFBd0Q7SUFDM0IsVUFBa0IsRUFDeEMsV0FBK0IsRUFDOUIsV0FBK0I7UUFGVixlQUFVLEdBQVYsVUFBVSxDQUFRO1FBQ3hDLGdCQUFXLEdBQVgsV0FBVyxDQUFvQjtRQUM5QixnQkFBVyxHQUFYLFdBQVcsQ0FBb0I7UUE5Q2hDLGNBQVMsR0FBc0IsWUFBWSxDQUFDLEdBQUcsQ0FBQyxDQUFDLDBFQUEwRTtRQUUzSCx3QkFBbUIsR0FBRyxJQUFJ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L0NWLCtCQUErQixnL0JDaEI1Qyx5aklBK0ZBLG1nTERqRmMsMkJBQTJCOzs0RkFFNUIsK0JBQStCO2tCQVAzQyxTQUFTOytCQUNFLDJCQUEyQixpQkFHdEIsaUJBQWlCLENBQUMsSUFBSSxjQUN6QiwyQkFBMkI7OzBCQWlEcEMsTUFBTTsyQkFBQyxXQUFXOzhHQTdDWixPQUFPO3NCQUFmLEtBQUs7Z0JBQ0csU0FBUztzQkFBakIsS0FBSztnQkFDRyxVQUFVO3NCQUFsQixLQUFLO2dCQUNHLG1CQUFtQjtzQkFBM0IsS0FBSztnQkFDRyxvQkFBb0I7c0JBQTVCLEtBQUs7Z0JBQ0csb0JBQW9CO3NCQUE1QixLQUFLO2dCQUNHLGtCQUFrQjtzQkFBMUIsS0FBSztnQkFHRyxTQUFTO3NCQUFqQixLQUFLO2dCQUNHLGNBQWM7c0JBQXRCLEtBQUs7Z0JBQ0csZUFBZTtzQkFBdkIsS0FBSztnQkFDRyxXQUFXO3NCQUFuQixLQUFLO2dCQUNHLGtCQUFrQjtzQkFBMUIsS0FBSztnQkFDRyxxQkFBcUI7c0JBQTdCLEtBQUs7Z0JBQ0csdUJBQXVCO3NCQUEvQixLQUFLO2dCQUdHLFNBQVM7c0JBQWpCLEtBQUs7Z0JBQ0csc0JBQXNCO3NCQUE5QixLQUFLO2dCQUNHLHFCQUFxQjtzQkFBN0IsS0FBSztnQkFHRyxZQUFZO3NCQUFwQixLQUFLO2dCQUNHLHlCQUF5QjtzQkFBakMsS0FBSztnQkFJSSxTQUFTO3NCQUFsQixNQUFNO2dCQUVHLE9BQU87c0JBQWhCLE1BQU07Z0JBRUcsd0JBQXdCO3NCQUFqQyxNQUFNO2dCQUVHLHdCQUF3QjtzQkFBakMsTUFBTTtnQkFFRyxvQkFBb0I7c0JBQTdCLE1BQU0iLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge0NvbXBvbmVudCwgRXZlbnRFbWl0dGVyLCBJbmplY3QsIElucHV0LCBPbkluaXQsIE91dHB1dCwgUExBVEZPUk1fSUQsIFZpZXdFbmNhcHN1bGF0aW9ufSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7VW50eXBlZEZvcm1CdWlsZGVyLCBVbnR5cGVkRm9ybUdyb3VwLCBWYWxpZGF0b3JzfSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XG5pbXBvcnQge0F1dGhQcm9jZXNzU2VydmljZSwgQXV0aFByb3ZpZGVyfSBmcm9tICcuLi8uLi9zZXJ2aWNlcy9hdXRoLXByb2Nlc3Muc2VydmljZSc7XG5pbXBvcnQge1N1YnNjcmlwdGlvbn0gZnJvbSAncnhqcyc7XG5pbXBvcnQge05neEF1dGhGaXJlYmFzZXVpQW5pbWF0aW9uc30gZnJvbSAnLi4vLi4vYW5pbWF0aW9ucyc7XG5pbXBvcnQge2lzUGxhdGZvcm1Ccm93c2VyfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuaW1wb3J0IHtNYXRGb3JtRmllbGRBcHBlYXJhbmNlfSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbC9mb3JtLWZpZWxkJztcbmltcG9ydCB7VGhlbWVQYWxldHRlfSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbC9jb3JlJztcblxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnbmd4LWF1dGgtZmlyZWJhc2V1aS1sb2dpbicsXG4gIHRlbXBsYXRlVXJsOiAnLi9uZ3gtYXV0aC1maXJlYmFzZXVpLWxvZ2luLmNvbXBvbmVudC5odG1sJyxcbiAgc3R5bGVVcmxzOiBbJy4vbmd4LWF1dGgtZmlyZWJhc2V1aS1sb2dpbi5jb21wb25lbnQuc2NzcyddLFxuICBlbmNhcHN1bGF0aW9uOiBWaWV3RW5jYXBzdWxhdGlvbi5Ob25lLFxuICBhbmltYXRpb25zOiBOZ3hBdXRoRmlyZWJhc2V1aUFuaW1hdGlvbnNcbn0pXG5leHBvcnQgY2xhc3MgTmd4QXV0aEZpcmViYXNldWlMb2dpbkNvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCB7XG5cbiAgQElucHV0KCkgbG9nb1VybDogc3RyaW5nO1xuICBASW5wdXQoKSBwcm92aWRlcnM6IHN0cmluZ1tdIHwgc3RyaW5nID0gQXV0aFByb3ZpZGVyLkFMTDsgLy8gIGdvb2dsZSwgZmFjZWJvb2ssIHR3aXR0ZXIsIGdpdGh1YiBhcyBhcnJheSBvciBhbGwgYXMgb25lIHNpbmdsZSBzdHJpbmdcbiAgQElucHV0KCkgYXBwZWFyYW5jZTogTWF0Rm9ybUZpZWxkQXBwZWFyYW5jZTtcbiAgQElucHV0KCkgcmVnaXN0cmF0aW9uRW5hYmxlZCA9IHRydWU7XG4gIEBJbnB1dCgpIHJlc2V0UGFzc3dvcmRFbmFibGVkID0gdHJ1ZTtcbiAgQElucHV0KCkgbWVzc2FnZU9uQXV0aFN1Y2Nlc3M6IHN0cmluZztcbiAgQElucHV0KCkgbWVzc2FnZU9uQXV0aEVycm9yOiBzdHJpbmc7XG5cbiAgLy8gaTE4blxuICBASW5wdXQoKSB0aXRsZVRleHQgPSAnTE9HSU4gVE8gWU9VUiBBQ0NPVU5UJztcbiAgQElucHV0KCkgcmVtZW1iZXJNZVRleHQgPSAnUmVtZW1iZXIgTWUnO1xuICBASW5wdXQoKSBsb2dpbkJ1dHRvblRleHQgPSAnTE9HSU4nO1xuICBASW5wdXQoKSBvckxhYmVsVGV4dCA9ICdPUic7XG4gIEBJbnB1dCgpIGZvcmdvdFBhc3N3b3JkVGV4dCA9ICdGb3Jnb3QgUGFzc3dvcmQ/JztcbiAgQElucHV0KCkgZG9udEhhdmVBbkFjY291bnRUZXh0ID0gJ0RvblxcJ3QgaGF2ZSBhbiBhY2NvdW50Pyc7XG4gIEBJbnB1dCgpIGNyZWF0ZUFjY291bnRCdXR0b25UZXh0ID0gJ0NyZWF0ZSBhbiBhY2NvdW50JztcblxuICAvLyBpMThuIGVtYWlsXG4gIEBJbnB1dCgpIGVtYWlsVGV4dCA9ICdFbWFpbCc7XG4gIEBJbnB1dCgpIGVtYWlsRXJyb3JSZXF1aXJlZFRleHQgPSAnRW1haWwgaXMgcmVxdWlyZWQnO1xuICBASW5wdXQoKSBlbWFpbEVycm9yUGF0dGVyblRleHQgPSAnUGxlYXNlIGVudGVyIGEgdmFsaWQgZW1haWwgYWRkcmVzcyc7XG5cbiAgLy8gaTE4biBwYXNzd29yZFxuICBASW5wdXQoKSBwYXNzd29yZFRleHQgPSAnUGFzc3dvcmQnO1xuICBASW5wdXQoKSBwYXNzd29yZEVycm9yUmVxdWlyZWRUZXh0ID0gJ1Bhc3N3b3JkIGlzIHJlcXVpcmVkJztcblxuICAvLyBFdmVudHNcbiAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEBhbmd1bGFyLWVzbGludC9uby1vdXRwdXQtb24tcHJlZml4XG4gIEBPdXRwdXQoKSBvblN1Y2Nlc3M6IGFueTtcbiAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEBhbmd1bGFyLWVzbGludC9uby1vdXRwdXQtb24tcHJlZml4XG4gIEBPdXRwdXQoKSBvbkVycm9yOiBhbnk7XG4gIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAYW5ndWxhci1lc2xpbnQvbm8tb3V0cHV0LW9uLXByZWZpeFxuICBAT3V0cHV0KCkgb25DcmVhdGVBY2NvdW50UmVxdWVzdGVkOiBFdmVudEVtaXR0ZXI8dm9pZD4gPSBuZXcgRXZlbnRFbWl0dGVyPHZvaWQ+KCk7XG4gIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAYW5ndWxhci1lc2xpbnQvbm8tb3V0cHV0LW9uLXByZWZpeFxuICBAT3V0cHV0KCkgb25SZXNldFBhc3N3b3JkUmVxdWVzdGVkOiBFdmVudEVtaXR0ZXI8dm9pZD4gPSBuZXcgRXZlbnRFbWl0dGVyPHZvaWQ+KCk7XG5cbiAgQE91dHB1dCgpIG9uTG9naW5CdXR0b25DbGlja2VkOiBFdmVudEVtaXR0ZXI8dm9pZD4gPSBuZXcgRXZlbnRFbWl0dGVyPHZvaWQ+KCk7XG5cbiAgbG9naW5Gb3JtOiBVbnR5cGVkRm9ybUdyb3VwO1xuICBhdXRoUHJvdmlkZXJzID0gQXV0aFByb3ZpZGVyO1xuICBvbkVycm9yU3Vic2NyaXB0aW9uOiBTdWJzY3JpcHRpb247XG4gIGF1dGhlbnRpY2F0aW9uRXJyb3IgPSBmYWxzZTtcblxuICBjb25zdHJ1Y3RvcihcbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L2Jhbi10eXBlc1xuICAgIEBJbmplY3QoUExBVEZPUk1fSUQpIHByaXZhdGUgcGxhdGZvcm1JZDogT2JqZWN0LFxuICAgIHB1YmxpYyBhdXRoUHJvY2VzczogQXV0aFByb2Nlc3NTZXJ2aWNlLFxuICAgIHByaXZhdGUgZm9ybUJ1aWxkZXI6IFVudHlwZWRGb3JtQnVpbGRlcikge1xuICAgIHRoaXMub25TdWNjZXNzID0gYXV0aFByb2Nlc3Mub25TdWNjZXNzRW1pdHRlcjtcbiAgICB0aGlzLm9uRXJyb3IgPSBhdXRoUHJvY2Vzcy5vbkVycm9yRW1pdHRlcjtcbiAgfVxuXG4gIGdldCBjb2xvcigpOiBzdHJpbmcgfCBUaGVtZVBhbGV0dGUge1xuICAgIHJldHVybiB0aGlzLmF1dGhlbnRpY2F0aW9uRXJyb3IgPyAnd2FybicgOiAncHJpbWFyeSc7XG4gIH1cblxuICBnZXQgY29sb3JBY2NlbnQoKTogc3RyaW5nIHwgVGhlbWVQYWxldHRlIHtcbiAgICByZXR1cm4gdGhpcy5hdXRoZW50aWNhdGlvbkVycm9yID8gJ3dhcm4nIDogJ2FjY2VudCc7XG4gIH1cblxuICBuZ09uSW5pdCgpIHtcblxuICAgIGlmIChpc1BsYXRmb3JtQnJvd3Nlcih0aGlzLnBsYXRmb3JtSWQpKSB7XG4gICAgICB0aGlzLm9uRXJyb3JTdWJzY3JpcHRpb24gPSB0aGlzLm9uRXJyb3Iuc3Vic2NyaWJlKCgpID0+IHRoaXMuYXV0aGVudGljYXRpb25FcnJvciA9IHRydWUpO1xuICAgIH1cblxuICAgIHRoaXMudXBkYXRlQXV0aFNuYWNrYmFyTWVzc2FnZXMoKTtcblxuICAgIHRoaXMubG9naW5Gb3JtID0gdGhpcy5mb3JtQnVpbGRlci5ncm91cCh7XG4gICAgICBlbWFpbDogWycnLCBbVmFsaWRhdG9ycy5yZXF1aXJlZCwgVmFsaWRhdG9ycy5lbWFpbF1dLFxuICAgICAgcGFzc3dvcmQ6IFsnJywgVmFsaWRhdG9ycy5yZXF1aXJlZF1cbiAgICB9KTtcbiAgfVxuXG4gIHB1YmxpYyB1cGRhdGVBdXRoU25hY2tiYXJNZXNzYWdlcygpOiB2b2lkIHtcbiAgICB0aGlzLmF1dGhQcm9jZXNzLm1lc3NhZ2VPbkF1dGhTdWNjZXNzID0gdGhpcy5tZXNzYWdlT25BdXRoU3VjY2VzcztcbiAgICB0aGlzLmF1dGhQcm9jZXNzLm1lc3NhZ2VPbkF1dGhFcnJvciA9IHRoaXMubWVzc2FnZU9uQXV0aEVycm9yO1xuICB9XG5cbiAgYXN5bmMgbG9naW4oKSB7XG4gICAgLy8gRW1pdCBldmVudCBmb3IgYnV0dG9uIGNsaWNrXG4gICAgdGhpcy5vbkxvZ2luQnV0dG9uQ2xpY2tlZC5lbWl0KCk7XG5cbiAgICByZXR1cm4gYXdhaXQgdGhpcy5hdXRoUHJvY2Vzcy5zaWduSW5XaXRoKHRoaXMuYXV0aFByb3ZpZGVycy5FbWFpbEFuZFBhc3N3b3JkLFxuICAgICAge1xuICAgICAgICBlbWFpbDogdGhpcy5sb2dpbkZvcm0uY29udHJvbHMuZW1haWwudmFsdWUsXG4gICAgICAgIHBhc3N3b3JkOiB0aGlzLmxvZ2luRm9ybS5jb250cm9scy5wYXNzd29yZC52YWx1ZVxuICAgICAgfVxuICAgICk7XG4gIH1cbn1cbiIsIjxkaXYgc3R5bGU9XCJmbGV4LWRpcmVjdGlvbjogY29sdW1uXCIgaWQ9XCJsb2dpblwiPlxuXG4gIDxkaXYgc3R5bGU9XCJmbGV4LWRpcmVjdGlvbjogY29sdW1uXCIgZnhMYXlvdXRBbGlnbj1cImNlbnRlciBjZW50ZXJcIiBpZD1cImxvZ2luLWZvcm0td3JhcHBlclwiPlxuXG4gICAgPGRpdiBbQGFuaW1hdGVTdGFnZ2VyXT1cInsgdmFsdWU6ICc1MCcgfVwiIGlkPVwibG9naW4tZm9ybVwiPlxuXG4gICAgICA8ZGl2ICpuZ0lmPVwibG9nb1VybFwiIGNsYXNzPVwibG9nb1wiPlxuICAgICAgICA8aW1nIFtAYW5pbWF0ZV09XCJ7IHZhbHVlOiAnKicsIHBhcmFtczogeyB4OiAnNTBweCcgfSB9XCIgW3NyY109XCJsb2dvVXJsXCIgYWx0PVwibG9nb1wiPlxuICAgICAgPC9kaXY+XG5cbiAgICAgIDxkaXYgW0BhbmltYXRlXT1cInsgdmFsdWU6ICcqJywgcGFyYW1zOiB7IHg6ICctNTBweCcgfSB9XCIgY2xhc3M9XCJ0aXRsZVwiPnt7dGl0bGVUZXh0fX08L2Rpdj5cblxuICAgICAgPGZvcm0gW0BhbmltYXRlXT1cInt2YWx1ZTonKicscGFyYW1zOntkdXJhdGlvbjonMzAwbXMnLHk6JzEwMHB4J319XCIgW2Zvcm1Hcm91cF09XCJsb2dpbkZvcm1cIiBuYW1lPVwibG9naW5Gb3JtXCJcbiAgICAgICAgICAgIG5vdmFsaWRhdGU+XG5cbiAgICAgICAgPG1hdC1mb3JtLWZpZWxkIFtAYW5pbWF0ZV09XCJ7IHZhbHVlOiAnKicsIHBhcmFtczogeyB4OiAnNTBweCcgfSB9XCIgW2FwcGVhcmFuY2VdPVwiYXBwZWFyYW5jZVwiPlxuICAgICAgICAgIDxpbnB1dCBbcGxhY2Vob2xkZXJdPVwiZW1haWxUZXh0XCIgZm9ybUNvbnRyb2xOYW1lPVwiZW1haWxcIiBtYXRJbnB1dCBhdXRvY29tcGxldGU9XCJ1c2VybmFtZVwiPlxuICAgICAgICAgIDxtYXQtaWNvbiBbY29sb3JdPVwiY29sb3JcIiBtYXRTdWZmaXg+ZW1haWw8L21hdC1pY29uPlxuICAgICAgICAgIDxtYXQtZXJyb3IgKm5nSWY9XCJsb2dpbkZvcm0uZ2V0KCdlbWFpbCcpPy5oYXNFcnJvcigncmVxdWlyZWQnKVwiPlxuICAgICAgICAgICAge3tlbWFpbEVycm9yUmVxdWlyZWRUZXh0fX1cbiAgICAgICAgICA8L21hdC1lcnJvcj5cbiAgICAgICAgICA8bWF0LWVycm9yXG4gICAgICAgICAgICAqbmdJZj1cIiFsb2dpbkZvcm0uZ2V0KCdlbWFpbCcpPy5oYXNFcnJvcigncmVxdWlyZWQnKSAmJlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb2dpbkZvcm0uZ2V0KCdlbWFpbCcpPy5oYXNFcnJvcignZW1haWwnKVwiPlxuICAgICAgICAgICAge3tlbWFpbEVycm9yUGF0dGVyblRleHR9fVxuICAgICAgICAgIDwvbWF0LWVycm9yPlxuICAgICAgICA8L21hdC1mb3JtLWZpZWxkPlxuXG4gICAgICAgIDxtYXQtZm9ybS1maWVsZCBbQGFuaW1hdGVdPVwieyB2YWx1ZTogJyonLCBwYXJhbXM6IHsgeDogJzUwcHgnIH0gfVwiIFthcHBlYXJhbmNlXT1cImFwcGVhcmFuY2VcIj5cbiAgICAgICAgICA8aW5wdXQgW3BsYWNlaG9sZGVyXT1cInBhc3N3b3JkVGV4dFwiIGZvcm1Db250cm9sTmFtZT1cInBhc3N3b3JkXCIgbWF0SW5wdXQgdHlwZT1cInBhc3N3b3JkXCIgYXV0b2NvbXBsZXRlPVwiY3VycmVudC1wYXNzd29yZFwiPlxuICAgICAgICAgIDxtYXQtaWNvbiBbY29sb3JdPVwiY29sb3JcIiBtYXRTdWZmaXg+bG9jazwvbWF0LWljb24+XG4gICAgICAgICAgPG1hdC1lcnJvcj5cbiAgICAgICAgICAgIHt7cGFzc3dvcmRFcnJvclJlcXVpcmVkVGV4dH19XG4gICAgICAgICAgPC9tYXQtZXJyb3I+XG4gICAgICAgIDwvbWF0LWZvcm0tZmllbGQ+XG5cbiAgICAgICAgPGRpdiBbQGFuaW1hdGVdPVwieyB2YWx1ZTogJyonLCBwYXJhbXM6IHsgeDogJzUwcHgnIH0gfVwiXG4gICAgICAgICAgICAgY2xhc3M9XCJyZW1lbWJlci1mb3Jnb3QtcGFzc3dvcmRcIiBzdHlsZT1cImZsZXgtZGlyZWN0aW9uOiByb3dcIlxuICAgICAgICAgICAgIGZ4TGF5b3V0LnhzPVwiY29sdW1uXCJcbiAgICAgICAgICAgICBmeExheW91dEFsaWduPVwic3BhY2UtYmV0d2VlbiBjZW50ZXJcIj5cbiAgICAgICAgICA8IS0tICAgICAgICAgIDxtYXQtY2hlY2tib3ggY2xhc3M9XCJyZW1lbWJlci1tZVwiIGFyaWEtbGFiZWw9XCJSZW1lbWJlciBNZVwiPi0tPlxuICAgICAgICAgIDwhLS0gICAgICAgICAgICB7e3JlbWVtYmVyTWVUZXh0fX0tLT5cbiAgICAgICAgICA8IS0tICAgICAgICAgIDwvbWF0LWNoZWNrYm94Pi0tPlxuXG4gICAgICAgICAgPGJ1dHRvbiAoY2xpY2spPVwib25SZXNldFBhc3N3b3JkUmVxdWVzdGVkLmVtaXQoKVwiXG4gICAgICAgICAgICAgICAgICAqbmdJZj1cInJlc2V0UGFzc3dvcmRFbmFibGVkXCJcbiAgICAgICAgICAgICAgICAgIFtAYW5pbWF0ZV09XCJ7IHZhbHVlOiAnKicsIHBhcmFtczogeyB4OiAnLTUwcHgnIH0gfVwiXG4gICAgICAgICAgICAgICAgICBbY29sb3JdPVwiY29sb3JcIlxuICAgICAgICAgICAgICAgICAgY2xhc3M9XCJmb3Jnb3QtcGFzc3dvcmRcIlxuICAgICAgICAgICAgICAgICAgbWF0LWJ1dHRvblxuICAgICAgICAgICAgICAgICAgdHlwZT1cImJ1dHRvblwiPlxuICAgICAgICAgICAge3tmb3Jnb3RQYXNzd29yZFRleHR9fVxuICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICA8L2Rpdj5cblxuICAgICAgICA8YnV0dG9uIChjbGljayk9XCJsb2dpbigpXCJcbiAgICAgICAgICAgICAgICBbY29sb3JdPVwiY29sb3JBY2NlbnRcIlxuICAgICAgICAgICAgICAgIFtkaXNhYmxlZF09XCJsb2dpbkZvcm0uaW52YWxpZFwiXG4gICAgICAgICAgICAgICAgYXJpYS1sYWJlbD1cIkxPRyBJTlwiXG4gICAgICAgICAgICAgICAgY2xhc3M9XCJzdWJtaXQtYnV0dG9uXCJcbiAgICAgICAgICAgICAgICBpZD1cImxvZ2luQnV0dG9uXCJcbiAgICAgICAgICAgICAgICBtYXQtcmFpc2VkLWJ1dHRvbj5cbiAgICAgICAgICB7e2xvZ2luQnV0dG9uVGV4dH19XG4gICAgICAgIDwvYnV0dG9uPlxuXG4gICAgICA8L2Zvcm0+XG5cbiAgICAgIDxkaXYgKm5nSWY9XCJwcm92aWRlcnMubGVuZ3RoID4gMFwiXG4gICAgICAgICAgIFtAYW5pbWF0ZV09XCJ7IHZhbHVlOiAnKicsIHBhcmFtczogeyB6OiAnNTBweCcsIGRlbGF5OiAnNTBtcycsIHNjYWxlOiAnMC4yJyB9IH1cIlxuICAgICAgICAgICBjbGFzcz1cInNlcGFyYXRvclwiPlxuICAgICAgICA8c3BhbiBjbGFzcz1cInRleHRcIj57e29yTGFiZWxUZXh0fX08L3NwYW4+XG4gICAgICA8L2Rpdj5cblxuICAgICAgPG5neC1hdXRoLWZpcmViYXNldWktcHJvdmlkZXJzIFtwcm92aWRlcnNdPVwicHJvdmlkZXJzXCJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmeExheW91dEFsaWduPVwiY2VudGVyIGNlbnRlclwiXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGF5b3V0PVwiY29sdW1uXCJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZT1cInJhaXNlZFwiPjwvbmd4LWF1dGgtZmlyZWJhc2V1aS1wcm92aWRlcnM+XG5cbiAgICAgIDxkaXYgKm5nSWY9XCJyZWdpc3RyYXRpb25FbmFibGVkXCJcbiAgICAgICAgICAgW0BhbmltYXRlU3RhZ2dlcl09XCJ7IHZhbHVlOiAnMTAwJyB9XCJcbiAgICAgICAgICAgY2xhc3M9XCJyZWdpc3RlclwiXG4gICAgICAgICAgIHN0eWxlPVwiZmxleC1kaXJlY3Rpb246IGNvbHVtblwiIGZ4TGF5b3V0QWxpZ249XCJjZW50ZXIgY2VudGVyXCI+XG4gICAgICAgIDxzcGFuIFtAYW5pbWF0ZV09XCJ7IHZhbHVlOiAnKicsIHBhcmFtczogeyB4OiAnMTAwcHgnIH0gfVwiIGNsYXNzPVwidGV4dFwiPlxuICAgICAgICAgIHt7ZG9udEhhdmVBbkFjY291bnRUZXh0fX1cbiAgICAgICAgPC9zcGFuPlxuICAgICAgICA8YnV0dG9uIChjbGljayk9XCJvbkNyZWF0ZUFjY291bnRSZXF1ZXN0ZWQuZW1pdCgpXCJcbiAgICAgICAgICAgICAgICBbQGFuaW1hdGVdPVwieyB2YWx1ZTogJyonLCBwYXJhbXM6IHsgeDogJy0xMDBweCcgfSB9XCJcbiAgICAgICAgICAgICAgICBbY29sb3JdPVwiY29sb3JcIlxuICAgICAgICAgICAgICAgIGlkPVwiY3JlYXRlQWNjb3VudEJ1dHRvblwiXG4gICAgICAgICAgICAgICAgbWF0LWJ1dHRvblxuICAgICAgICAgICAgICAgIHR5cGU9XCJidXR0b25cIj57e2NyZWF0ZUFjY291bnRCdXR0b25UZXh0fX08L2J1dHRvbj5cbiAgICAgIDwvZGl2PlxuICAgIDwvZGl2PlxuICA8L2Rpdj5cbjwvZGl2PlxuIl19