UNPKG

angular-dynamic-forms-ai

Version:

AI-enhanced dynamic form generator for Angular using Template-Driven Forms

313 lines (297 loc) 36 kB
import { Component, Input, Output, EventEmitter } from '@angular/core'; import * as i0 from "@angular/core"; import * as i1 from "../services/ai-validation.service"; import * as i2 from "@angular/common"; import * as i3 from "@angular/forms"; class DynamicFormComponent { aiValidationService; formConfig; formSubmit = new EventEmitter(); constructor(aiValidationService) { this.aiValidationService = aiValidationService; } ngOnInit() { // Apply AI-based validation rules to each field this.formConfig.fields = this.formConfig.fields.map(field => this.aiValidationService.suggestValidations(field)); } isFieldVisible(field) { if (!field.conditionalDisplay) { return true; } const dependentField = this.formConfig.fields.find(f => f.name === field.conditionalDisplay?.dependsOn); return dependentField?.value === field.conditionalDisplay.showWhen; } onSubmit(form) { if (form.valid) { const formData = this.formConfig.fields.reduce((acc, field) => { if (this.isFieldVisible(field)) { acc[field.name] = field.value; } return acc; }, {}); this.formSubmit.emit(formData); } } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.6", ngImport: i0, type: DynamicFormComponent, deps: [{ token: i1.AiValidationService }], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.0.6", type: DynamicFormComponent, selector: "lib-dynamic-form", inputs: { formConfig: "formConfig" }, outputs: { formSubmit: "formSubmit" }, ngImport: i0, template: ` <form #form="ngForm" (ngSubmit)="onSubmit(form)" class="dynamic-form" [attr.aria-label]="formConfig.fields[0]?.label + ' form'"> <div *ngFor="let field of formConfig.fields" class="form-field" [ngClass]="{'hidden': !isFieldVisible(field)}"> <label [for]="field.name" class="form-label"> {{ field.label }} <span *ngIf="field.validations?.required" class="required-marker">*</span> </label> <ng-container [ngSwitch]="field.type"> <!-- Text, Email, Number, Password inputs --> <input *ngSwitchCase="'text'" [type]="field.type" [id]="field.name" [name]="field.name" [placeholder]="field.placeholder || ''" [(ngModel)]="field.value" #fieldModel="ngModel" [required]="field.validations?.required" [minlength]="field.validations?.minLength" [maxlength]="field.validations?.maxLength" [pattern]="field.validations?.pattern" [email]="field.validations?.email" class="form-input" [ngClass]="{'error': fieldModel.invalid && (fieldModel.dirty || fieldModel.touched)}" [attr.aria-invalid]="fieldModel.invalid && (fieldModel.dirty || fieldModel.touched)" [attr.aria-describedby]="field.name + '-error'"> <input *ngSwitchCase="'email'" type="email" [id]="field.name" [name]="field.name" [placeholder]="field.placeholder || ''" [(ngModel)]="field.value" #fieldModel="ngModel" [required]="field.validations?.required" [email]="true" class="form-input" [ngClass]="{'error': fieldModel.invalid && (fieldModel.dirty || fieldModel.touched)}" [attr.aria-invalid]="fieldModel.invalid && (fieldModel.dirty || fieldModel.touched)" [attr.aria-describedby]="field.name + '-error'"> <input *ngSwitchCase="'number'" type="number" [id]="field.name" [name]="field.name" [placeholder]="field.placeholder || ''" [(ngModel)]="field.value" #fieldModel="ngModel" [required]="field.validations?.required" class="form-input" [ngClass]="{'error': fieldModel.invalid && (fieldModel.dirty || fieldModel.touched)}" [attr.aria-invalid]="fieldModel.invalid && (fieldModel.dirty || fieldModel.touched)" [attr.aria-describedby]="field.name + '-error'"> <input *ngSwitchCase="'password'" type="password" [id]="field.name" [name]="field.name" [placeholder]="field.placeholder || ''" [(ngModel)]="field.value" #fieldModel="ngModel" [required]="field.validations?.required" [minlength]="field.validations?.minLength" [pattern]="field.validations?.pattern" class="form-input" [ngClass]="{'error': fieldModel.invalid && (fieldModel.dirty || fieldModel.touched)}" [attr.aria-invalid]="fieldModel.invalid && (fieldModel.dirty || fieldModel.touched)" [attr.aria-describedby]="field.name + '-error'"> <!-- Select dropdown --> <select *ngSwitchCase="'select'" [id]="field.name" [name]="field.name" [(ngModel)]="field.value" #fieldModel="ngModel" [required]="field.validations?.required" class="form-select" [ngClass]="{'error': fieldModel.invalid && (fieldModel.dirty || fieldModel.touched)}" [attr.aria-invalid]="fieldModel.invalid && (fieldModel.dirty || fieldModel.touched)" [attr.aria-describedby]="field.name + '-error'"> <option value="">Select {{ field.label }}</option> <option *ngFor="let option of field.options" [value]="option.value"> {{ option.label }} </option> </select> <!-- Textarea --> <textarea *ngSwitchCase="'textarea'" [id]="field.name" [name]="field.name" [placeholder]="field.placeholder || ''" [(ngModel)]="field.value" #fieldModel="ngModel" [required]="field.validations?.required" [minlength]="field.validations?.minLength" [maxlength]="field.validations?.maxLength" class="form-textarea" [ngClass]="{'error': fieldModel.invalid && (fieldModel.dirty || fieldModel.touched)}" [attr.aria-invalid]="fieldModel.invalid && (fieldModel.dirty || fieldModel.touched)" [attr.aria-describedby]="field.name + '-error'"> </textarea> </ng-container> <!-- Error messages --> <div *ngIf="fieldModel.invalid && (fieldModel.dirty || fieldModel.touched)" class="error-messages" [id]="field.name + '-error'" role="alert"> <div *ngIf="fieldModel.errors?.required"> {{ field.errorMessages?.required }} </div> <div *ngIf="fieldModel.errors?.minlength"> {{ field.errorMessages?.minlength }} </div> <div *ngIf="fieldModel.errors?.maxlength"> {{ field.errorMessages?.maxlength }} </div> <div *ngIf="fieldModel.errors?.email"> {{ field.errorMessages?.email }} </div> <div *ngIf="fieldModel.errors?.pattern"> {{ field.errorMessages?.pattern }} </div> </div> </div> <button type="submit" [disabled]="!form.valid" [class]="formConfig.submitButton?.class || 'submit-button'" [attr.aria-disabled]="!form.valid"> {{ formConfig.submitButton?.text || 'Submit' }} </button> </form> `, isInline: true, styles: [".dynamic-form{max-width:600px;margin:0 auto;padding:20px;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif}.form-field{margin-bottom:20px}.form-label{display:block;margin-bottom:8px;font-weight:500;color:#333}.required-marker{color:#dc3545;margin-left:4px}.form-input,.form-select,.form-textarea{width:100%;padding:8px 12px;border:1px solid #ced4da;border-radius:4px;font-size:16px;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}.form-textarea{min-height:100px;resize:vertical}.form-input:focus,.form-select:focus,.form-textarea:focus{border-color:#80bdff;outline:0;box-shadow:0 0 0 .2rem #007bff40}.error{border-color:#dc3545}.error:focus{border-color:#dc3545;box-shadow:0 0 0 .2rem #dc354540}.error-messages{margin-top:5px;color:#dc3545;font-size:14px}.hidden{display:none}.submit-button{background-color:#007bff;color:#fff;padding:10px 20px;border:none;border-radius:4px;font-size:16px;cursor:pointer;transition:background-color .15s ease-in-out}.submit-button:hover:not(:disabled){background-color:#0056b3}.submit-button:disabled{background-color:#6c757d;cursor:not-allowed;opacity:.65}@media (max-width: 768px){.dynamic-form{padding:15px}}\n"], dependencies: [{ kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i2.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "directive", type: i3.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { 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.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.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { 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.MinLengthValidator, selector: "[minlength][formControlName],[minlength][formControl],[minlength][ngModel]", inputs: ["minlength"] }, { kind: "directive", type: i3.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i3.PatternValidator, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: ["pattern"] }, { kind: "directive", type: i3.EmailValidator, selector: "[email][formControlName],[email][formControl],[email][ngModel]", inputs: ["email"] }, { kind: "directive", type: i3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i3.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }] }); } export { DynamicFormComponent }; i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.6", ngImport: i0, type: DynamicFormComponent, decorators: [{ type: Component, args: [{ selector: 'lib-dynamic-form', template: ` <form #form="ngForm" (ngSubmit)="onSubmit(form)" class="dynamic-form" [attr.aria-label]="formConfig.fields[0]?.label + ' form'"> <div *ngFor="let field of formConfig.fields" class="form-field" [ngClass]="{'hidden': !isFieldVisible(field)}"> <label [for]="field.name" class="form-label"> {{ field.label }} <span *ngIf="field.validations?.required" class="required-marker">*</span> </label> <ng-container [ngSwitch]="field.type"> <!-- Text, Email, Number, Password inputs --> <input *ngSwitchCase="'text'" [type]="field.type" [id]="field.name" [name]="field.name" [placeholder]="field.placeholder || ''" [(ngModel)]="field.value" #fieldModel="ngModel" [required]="field.validations?.required" [minlength]="field.validations?.minLength" [maxlength]="field.validations?.maxLength" [pattern]="field.validations?.pattern" [email]="field.validations?.email" class="form-input" [ngClass]="{'error': fieldModel.invalid && (fieldModel.dirty || fieldModel.touched)}" [attr.aria-invalid]="fieldModel.invalid && (fieldModel.dirty || fieldModel.touched)" [attr.aria-describedby]="field.name + '-error'"> <input *ngSwitchCase="'email'" type="email" [id]="field.name" [name]="field.name" [placeholder]="field.placeholder || ''" [(ngModel)]="field.value" #fieldModel="ngModel" [required]="field.validations?.required" [email]="true" class="form-input" [ngClass]="{'error': fieldModel.invalid && (fieldModel.dirty || fieldModel.touched)}" [attr.aria-invalid]="fieldModel.invalid && (fieldModel.dirty || fieldModel.touched)" [attr.aria-describedby]="field.name + '-error'"> <input *ngSwitchCase="'number'" type="number" [id]="field.name" [name]="field.name" [placeholder]="field.placeholder || ''" [(ngModel)]="field.value" #fieldModel="ngModel" [required]="field.validations?.required" class="form-input" [ngClass]="{'error': fieldModel.invalid && (fieldModel.dirty || fieldModel.touched)}" [attr.aria-invalid]="fieldModel.invalid && (fieldModel.dirty || fieldModel.touched)" [attr.aria-describedby]="field.name + '-error'"> <input *ngSwitchCase="'password'" type="password" [id]="field.name" [name]="field.name" [placeholder]="field.placeholder || ''" [(ngModel)]="field.value" #fieldModel="ngModel" [required]="field.validations?.required" [minlength]="field.validations?.minLength" [pattern]="field.validations?.pattern" class="form-input" [ngClass]="{'error': fieldModel.invalid && (fieldModel.dirty || fieldModel.touched)}" [attr.aria-invalid]="fieldModel.invalid && (fieldModel.dirty || fieldModel.touched)" [attr.aria-describedby]="field.name + '-error'"> <!-- Select dropdown --> <select *ngSwitchCase="'select'" [id]="field.name" [name]="field.name" [(ngModel)]="field.value" #fieldModel="ngModel" [required]="field.validations?.required" class="form-select" [ngClass]="{'error': fieldModel.invalid && (fieldModel.dirty || fieldModel.touched)}" [attr.aria-invalid]="fieldModel.invalid && (fieldModel.dirty || fieldModel.touched)" [attr.aria-describedby]="field.name + '-error'"> <option value="">Select {{ field.label }}</option> <option *ngFor="let option of field.options" [value]="option.value"> {{ option.label }} </option> </select> <!-- Textarea --> <textarea *ngSwitchCase="'textarea'" [id]="field.name" [name]="field.name" [placeholder]="field.placeholder || ''" [(ngModel)]="field.value" #fieldModel="ngModel" [required]="field.validations?.required" [minlength]="field.validations?.minLength" [maxlength]="field.validations?.maxLength" class="form-textarea" [ngClass]="{'error': fieldModel.invalid && (fieldModel.dirty || fieldModel.touched)}" [attr.aria-invalid]="fieldModel.invalid && (fieldModel.dirty || fieldModel.touched)" [attr.aria-describedby]="field.name + '-error'"> </textarea> </ng-container> <!-- Error messages --> <div *ngIf="fieldModel.invalid && (fieldModel.dirty || fieldModel.touched)" class="error-messages" [id]="field.name + '-error'" role="alert"> <div *ngIf="fieldModel.errors?.required"> {{ field.errorMessages?.required }} </div> <div *ngIf="fieldModel.errors?.minlength"> {{ field.errorMessages?.minlength }} </div> <div *ngIf="fieldModel.errors?.maxlength"> {{ field.errorMessages?.maxlength }} </div> <div *ngIf="fieldModel.errors?.email"> {{ field.errorMessages?.email }} </div> <div *ngIf="fieldModel.errors?.pattern"> {{ field.errorMessages?.pattern }} </div> </div> </div> <button type="submit" [disabled]="!form.valid" [class]="formConfig.submitButton?.class || 'submit-button'" [attr.aria-disabled]="!form.valid"> {{ formConfig.submitButton?.text || 'Submit' }} </button> </form> `, styles: [".dynamic-form{max-width:600px;margin:0 auto;padding:20px;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif}.form-field{margin-bottom:20px}.form-label{display:block;margin-bottom:8px;font-weight:500;color:#333}.required-marker{color:#dc3545;margin-left:4px}.form-input,.form-select,.form-textarea{width:100%;padding:8px 12px;border:1px solid #ced4da;border-radius:4px;font-size:16px;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}.form-textarea{min-height:100px;resize:vertical}.form-input:focus,.form-select:focus,.form-textarea:focus{border-color:#80bdff;outline:0;box-shadow:0 0 0 .2rem #007bff40}.error{border-color:#dc3545}.error:focus{border-color:#dc3545;box-shadow:0 0 0 .2rem #dc354540}.error-messages{margin-top:5px;color:#dc3545;font-size:14px}.hidden{display:none}.submit-button{background-color:#007bff;color:#fff;padding:10px 20px;border:none;border-radius:4px;font-size:16px;cursor:pointer;transition:background-color .15s ease-in-out}.submit-button:hover:not(:disabled){background-color:#0056b3}.submit-button:disabled{background-color:#6c757d;cursor:not-allowed;opacity:.65}@media (max-width: 768px){.dynamic-form{padding:15px}}\n"] }] }], ctorParameters: function () { return [{ type: i1.AiValidationService }]; }, propDecorators: { formConfig: [{ type: Input }], formSubmit: [{ type: Output }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZHluYW1pYy1mb3JtLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2R5bmFtaWMtZm9ybXMvc3JjL2xpYi9jb21wb25lbnRzL2R5bmFtaWMtZm9ybS5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFNBQVMsRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLFlBQVksRUFBVSxNQUFNLGVBQWUsQ0FBQzs7Ozs7QUFLL0UsTUF1T2Esb0JBQW9CO0lBSVg7SUFIWCxVQUFVLENBQWM7SUFDdkIsVUFBVSxHQUFHLElBQUksWUFBWSxFQUFPLENBQUM7SUFFL0MsWUFBb0IsbUJBQXdDO1FBQXhDLHdCQUFtQixHQUFuQixtQkFBbUIsQ0FBcUI7SUFBRyxDQUFDO0lBRWhFLFFBQVE7UUFDTixnREFBZ0Q7UUFDaEQsSUFBSSxDQUFDLFVBQVUsQ0FBQyxNQUFNLEdBQUcsSUFBSSxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQzFELElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxrQkFBa0IsQ0FBQyxLQUFLLENBQUMsQ0FDbkQsQ0FBQztJQUNKLENBQUM7SUFFRCxjQUFjLENBQUMsS0FBc0I7UUFDbkMsSUFBSSxDQUFDLEtBQUssQ0FBQyxrQkFBa0IsRUFBRTtZQUM3QixPQUFPLElBQUksQ0FBQztTQUNiO1FBRUQsTUFBTSxjQUFjLEdBQUcsSUFBSSxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUNoRCxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLEtBQUssS0FBSyxDQUFDLGtCQUFrQixFQUFFLFNBQVMsQ0FDcEQsQ0FBQztRQUVGLE9BQU8sY0FBYyxFQUFFLEtBQUssS0FBSyxLQUFLLENBQUMsa0JBQWtCLENBQUMsUUFBUSxDQUFDO0lBQ3JFLENBQUM7SUFFRCxRQUFRLENBQUMsSUFBWTtRQUNuQixJQUFJLElBQUksQ0FBQyxLQUFLLEVBQUU7WUFDZCxNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsVUFBVSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQyxHQUFHLEVBQUUsS0FBSyxFQUFFLEVBQUU7Z0JBQzVELElBQUksSUFBSSxDQUFDLGNBQWMsQ0FBQyxLQUFLLENBQUMsRUFBRTtvQkFDOUIsR0FBRyxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsR0FBRyxLQUFLLENBQUMsS0FBSyxDQUFDO2lCQUMvQjtnQkFDRCxPQUFPLEdBQUcsQ0FBQztZQUNiLENBQUMsRUFBRSxFQUFTLENBQUMsQ0FBQztZQUVkLElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1NBQ2hDO0lBQ0gsQ0FBQzt1R0FwQ1Usb0JBQW9COzJGQUFwQixvQkFBb0IscUlBck9yQjs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXFJVDs7U0FnR1Usb0JBQW9COzJGQUFwQixvQkFBb0I7a0JBdk9oQyxTQUFTOytCQUNFLGtCQUFrQixZQUNsQjs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXFJVDswR0FpR1EsVUFBVTtzQkFBbEIsS0FBSztnQkFDSSxVQUFVO3NCQUFuQixNQUFNIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29tcG9uZW50LCBJbnB1dCwgT3V0cHV0LCBFdmVudEVtaXR0ZXIsIE9uSW5pdCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgTmdGb3JtIH0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xuaW1wb3J0IHsgRm9ybUNvbmZpZywgRm9ybUZpZWxkQ29uZmlnIH0gZnJvbSAnLi4vaW50ZXJmYWNlcy9mb3JtLWZpZWxkLmludGVyZmFjZSc7XG5pbXBvcnQgeyBBaVZhbGlkYXRpb25TZXJ2aWNlIH0gZnJvbSAnLi4vc2VydmljZXMvYWktdmFsaWRhdGlvbi5zZXJ2aWNlJztcblxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnbGliLWR5bmFtaWMtZm9ybScsXG4gIHRlbXBsYXRlOiBgXG4gICAgPGZvcm0gI2Zvcm09XCJuZ0Zvcm1cIiAobmdTdWJtaXQpPVwib25TdWJtaXQoZm9ybSlcIiBjbGFzcz1cImR5bmFtaWMtZm9ybVwiIFthdHRyLmFyaWEtbGFiZWxdPVwiZm9ybUNvbmZpZy5maWVsZHNbMF0/LmxhYmVsICsgJyBmb3JtJ1wiPlxuICAgICAgPGRpdiAqbmdGb3I9XCJsZXQgZmllbGQgb2YgZm9ybUNvbmZpZy5maWVsZHNcIiBjbGFzcz1cImZvcm0tZmllbGRcIiBbbmdDbGFzc109XCJ7J2hpZGRlbic6ICFpc0ZpZWxkVmlzaWJsZShmaWVsZCl9XCI+XG4gICAgICAgIDxsYWJlbCBbZm9yXT1cImZpZWxkLm5hbWVcIiBjbGFzcz1cImZvcm0tbGFiZWxcIj5cbiAgICAgICAgICB7eyBmaWVsZC5sYWJlbCB9fVxuICAgICAgICAgIDxzcGFuICpuZ0lmPVwiZmllbGQudmFsaWRhdGlvbnM/LnJlcXVpcmVkXCIgY2xhc3M9XCJyZXF1aXJlZC1tYXJrZXJcIj4qPC9zcGFuPlxuICAgICAgICA8L2xhYmVsPlxuXG4gICAgICAgIDxuZy1jb250YWluZXIgW25nU3dpdGNoXT1cImZpZWxkLnR5cGVcIj5cbiAgICAgICAgICA8IS0tIFRleHQsIEVtYWlsLCBOdW1iZXIsIFBhc3N3b3JkIGlucHV0cyAtLT5cbiAgICAgICAgICA8aW5wdXQgKm5nU3dpdGNoQ2FzZT1cIid0ZXh0J1wiIFxuICAgICAgICAgICAgICAgICBbdHlwZV09XCJmaWVsZC50eXBlXCJcbiAgICAgICAgICAgICAgICAgW2lkXT1cImZpZWxkLm5hbWVcIlxuICAgICAgICAgICAgICAgICBbbmFtZV09XCJmaWVsZC5uYW1lXCJcbiAgICAgICAgICAgICAgICAgW3BsYWNlaG9sZGVyXT1cImZpZWxkLnBsYWNlaG9sZGVyIHx8ICcnXCJcbiAgICAgICAgICAgICAgICAgWyhuZ01vZGVsKV09XCJmaWVsZC52YWx1ZVwiXG4gICAgICAgICAgICAgICAgICNmaWVsZE1vZGVsPVwibmdNb2RlbFwiXG4gICAgICAgICAgICAgICAgIFtyZXF1aXJlZF09XCJmaWVsZC52YWxpZGF0aW9ucz8ucmVxdWlyZWRcIlxuICAgICAgICAgICAgICAgICBbbWlubGVuZ3RoXT1cImZpZWxkLnZhbGlkYXRpb25zPy5taW5MZW5ndGhcIlxuICAgICAgICAgICAgICAgICBbbWF4bGVuZ3RoXT1cImZpZWxkLnZhbGlkYXRpb25zPy5tYXhMZW5ndGhcIlxuICAgICAgICAgICAgICAgICBbcGF0dGVybl09XCJmaWVsZC52YWxpZGF0aW9ucz8ucGF0dGVyblwiXG4gICAgICAgICAgICAgICAgIFtlbWFpbF09XCJmaWVsZC52YWxpZGF0aW9ucz8uZW1haWxcIlxuICAgICAgICAgICAgICAgICBjbGFzcz1cImZvcm0taW5wdXRcIlxuICAgICAgICAgICAgICAgICBbbmdDbGFzc109XCJ7J2Vycm9yJzogZmllbGRNb2RlbC5pbnZhbGlkICYmIChmaWVsZE1vZGVsLmRpcnR5IHx8IGZpZWxkTW9kZWwudG91Y2hlZCl9XCJcbiAgICAgICAgICAgICAgICAgW2F0dHIuYXJpYS1pbnZhbGlkXT1cImZpZWxkTW9kZWwuaW52YWxpZCAmJiAoZmllbGRNb2RlbC5kaXJ0eSB8fCBmaWVsZE1vZGVsLnRvdWNoZWQpXCJcbiAgICAgICAgICAgICAgICAgW2F0dHIuYXJpYS1kZXNjcmliZWRieV09XCJmaWVsZC5uYW1lICsgJy1lcnJvcidcIj5cblxuICAgICAgICAgIDxpbnB1dCAqbmdTd2l0Y2hDYXNlPVwiJ2VtYWlsJ1wiXG4gICAgICAgICAgICAgICAgIHR5cGU9XCJlbWFpbFwiXG4gICAgICAgICAgICAgICAgIFtpZF09XCJmaWVsZC5uYW1lXCJcbiAgICAgICAgICAgICAgICAgW25hbWVdPVwiZmllbGQubmFtZVwiXG4gICAgICAgICAgICAgICAgIFtwbGFjZWhvbGRlcl09XCJmaWVsZC5wbGFjZWhvbGRlciB8fCAnJ1wiXG4gICAgICAgICAgICAgICAgIFsobmdNb2RlbCldPVwiZmllbGQudmFsdWVcIlxuICAgICAgICAgICAgICAgICAjZmllbGRNb2RlbD1cIm5nTW9kZWxcIlxuICAgICAgICAgICAgICAgICBbcmVxdWlyZWRdPVwiZmllbGQudmFsaWRhdGlvbnM/LnJlcXVpcmVkXCJcbiAgICAgICAgICAgICAgICAgW2VtYWlsXT1cInRydWVcIlxuICAgICAgICAgICAgICAgICBjbGFzcz1cImZvcm0taW5wdXRcIlxuICAgICAgICAgICAgICAgICBbbmdDbGFzc109XCJ7J2Vycm9yJzogZmllbGRNb2RlbC5pbnZhbGlkICYmIChmaWVsZE1vZGVsLmRpcnR5IHx8IGZpZWxkTW9kZWwudG91Y2hlZCl9XCJcbiAgICAgICAgICAgICAgICAgW2F0dHIuYXJpYS1pbnZhbGlkXT1cImZpZWxkTW9kZWwuaW52YWxpZCAmJiAoZmllbGRNb2RlbC5kaXJ0eSB8fCBmaWVsZE1vZGVsLnRvdWNoZWQpXCJcbiAgICAgICAgICAgICAgICAgW2F0dHIuYXJpYS1kZXNjcmliZWRieV09XCJmaWVsZC5uYW1lICsgJy1lcnJvcidcIj5cblxuICAgICAgICAgIDxpbnB1dCAqbmdTd2l0Y2hDYXNlPVwiJ251bWJlcidcIlxuICAgICAgICAgICAgICAgICB0eXBlPVwibnVtYmVyXCJcbiAgICAgICAgICAgICAgICAgW2lkXT1cImZpZWxkLm5hbWVcIlxuICAgICAgICAgICAgICAgICBbbmFtZV09XCJmaWVsZC5uYW1lXCJcbiAgICAgICAgICAgICAgICAgW3BsYWNlaG9sZGVyXT1cImZpZWxkLnBsYWNlaG9sZGVyIHx8ICcnXCJcbiAgICAgICAgICAgICAgICAgWyhuZ01vZGVsKV09XCJmaWVsZC52YWx1ZVwiXG4gICAgICAgICAgICAgICAgICNmaWVsZE1vZGVsPVwibmdNb2RlbFwiXG4gICAgICAgICAgICAgICAgIFtyZXF1aXJlZF09XCJmaWVsZC52YWxpZGF0aW9ucz8ucmVxdWlyZWRcIlxuICAgICAgICAgICAgICAgICBjbGFzcz1cImZvcm0taW5wdXRcIlxuICAgICAgICAgICAgICAgICBbbmdDbGFzc109XCJ7J2Vycm9yJzogZmllbGRNb2RlbC5pbnZhbGlkICYmIChmaWVsZE1vZGVsLmRpcnR5IHx8IGZpZWxkTW9kZWwudG91Y2hlZCl9XCJcbiAgICAgICAgICAgICAgICAgW2F0dHIuYXJpYS1pbnZhbGlkXT1cImZpZWxkTW9kZWwuaW52YWxpZCAmJiAoZmllbGRNb2RlbC5kaXJ0eSB8fCBmaWVsZE1vZGVsLnRvdWNoZWQpXCJcbiAgICAgICAgICAgICAgICAgW2F0dHIuYXJpYS1kZXNjcmliZWRieV09XCJmaWVsZC5uYW1lICsgJy1lcnJvcidcIj5cblxuICAgICAgICAgIDxpbnB1dCAqbmdTd2l0Y2hDYXNlPVwiJ3Bhc3N3b3JkJ1wiXG4gICAgICAgICAgICAgICAgIHR5cGU9XCJwYXNzd29yZFwiXG4gICAgICAgICAgICAgICAgIFtpZF09XCJmaWVsZC5uYW1lXCJcbiAgICAgICAgICAgICAgICAgW25hbWVdPVwiZmllbGQubmFtZVwiXG4gICAgICAgICAgICAgICAgIFtwbGFjZWhvbGRlcl09XCJmaWVsZC5wbGFjZWhvbGRlciB8fCAnJ1wiXG4gICAgICAgICAgICAgICAgIFsobmdNb2RlbCldPVwiZmllbGQudmFsdWVcIlxuICAgICAgICAgICAgICAgICAjZmllbGRNb2RlbD1cIm5nTW9kZWxcIlxuICAgICAgICAgICAgICAgICBbcmVxdWlyZWRdPVwiZmllbGQudmFsaWRhdGlvbnM/LnJlcXVpcmVkXCJcbiAgICAgICAgICAgICAgICAgW21pbmxlbmd0aF09XCJmaWVsZC52YWxpZGF0aW9ucz8ubWluTGVuZ3RoXCJcbiAgICAgICAgICAgICAgICAgW3BhdHRlcm5dPVwiZmllbGQudmFsaWRhdGlvbnM/LnBhdHRlcm5cIlxuICAgICAgICAgICAgICAgICBjbGFzcz1cImZvcm0taW5wdXRcIlxuICAgICAgICAgICAgICAgICBbbmdDbGFzc109XCJ7J2Vycm9yJzogZmllbGRNb2RlbC5pbnZhbGlkICYmIChmaWVsZE1vZGVsLmRpcnR5IHx8IGZpZWxkTW9kZWwudG91Y2hlZCl9XCJcbiAgICAgICAgICAgICAgICAgW2F0dHIuYXJpYS1pbnZhbGlkXT1cImZpZWxkTW9kZWwuaW52YWxpZCAmJiAoZmllbGRNb2RlbC5kaXJ0eSB8fCBmaWVsZE1vZGVsLnRvdWNoZWQpXCJcbiAgICAgICAgICAgICAgICAgW2F0dHIuYXJpYS1kZXNjcmliZWRieV09XCJmaWVsZC5uYW1lICsgJy1lcnJvcidcIj5cblxuICAgICAgICAgIDwhLS0gU2VsZWN0IGRyb3Bkb3duIC0tPlxuICAgICAgICAgIDxzZWxlY3QgKm5nU3dpdGNoQ2FzZT1cIidzZWxlY3QnXCJcbiAgICAgICAgICAgICAgICAgIFtpZF09XCJmaWVsZC5uYW1lXCJcbiAgICAgICAgICAgICAgICAgIFtuYW1lXT1cImZpZWxkLm5hbWVcIlxuICAgICAgICAgICAgICAgICAgWyhuZ01vZGVsKV09XCJmaWVsZC52YWx1ZVwiXG4gICAgICAgICAgICAgICAgICAjZmllbGRNb2RlbD1cIm5nTW9kZWxcIlxuICAgICAgICAgICAgICAgICAgW3JlcXVpcmVkXT1cImZpZWxkLnZhbGlkYXRpb25zPy5yZXF1aXJlZFwiXG4gICAgICAgICAgICAgICAgICBjbGFzcz1cImZvcm0tc2VsZWN0XCJcbiAgICAgICAgICAgICAgICAgIFtuZ0NsYXNzXT1cInsnZXJyb3InOiBmaWVsZE1vZGVsLmludmFsaWQgJiYgKGZpZWxkTW9kZWwuZGlydHkgfHwgZmllbGRNb2RlbC50b3VjaGVkKX1cIlxuICAgICAgICAgICAgICAgICAgW2F0dHIuYXJpYS1pbnZhbGlkXT1cImZpZWxkTW9kZWwuaW52YWxpZCAmJiAoZmllbGRNb2RlbC5kaXJ0eSB8fCBmaWVsZE1vZGVsLnRvdWNoZWQpXCJcbiAgICAgICAgICAgICAgICAgIFthdHRyLmFyaWEtZGVzY3JpYmVkYnldPVwiZmllbGQubmFtZSArICctZXJyb3InXCI+XG4gICAgICAgICAgICA8b3B0aW9uIHZhbHVlPVwiXCI+U2VsZWN0IHt7IGZpZWxkLmxhYmVsIH19PC9vcHRpb24+XG4gICAgICAgICAgICA8b3B0aW9uICpuZ0Zvcj1cImxldCBvcHRpb24gb2YgZmllbGQub3B0aW9uc1wiIFt2YWx1ZV09XCJvcHRpb24udmFsdWVcIj5cbiAgICAgICAgICAgICAge3sgb3B0aW9uLmxhYmVsIH19XG4gICAgICAgICAgICA8L29wdGlvbj5cbiAgICAgICAgICA8L3NlbGVjdD5cblxuICAgICAgICAgIDwhLS0gVGV4dGFyZWEgLS0+XG4gICAgICAgICAgPHRleHRhcmVhICpuZ1N3aXRjaENhc2U9XCIndGV4dGFyZWEnXCJcbiAgICAgICAgICAgICAgICAgICAgW2lkXT1cImZpZWxkLm5hbWVcIlxuICAgICAgICAgICAgICAgICAgICBbbmFtZV09XCJmaWVsZC5uYW1lXCJcbiAgICAgICAgICAgICAgICAgICAgW3BsYWNlaG9sZGVyXT1cImZpZWxkLnBsYWNlaG9sZGVyIHx8ICcnXCJcbiAgICAgICAgICAgICAgICAgICAgWyhuZ01vZGVsKV09XCJmaWVsZC52YWx1ZVwiXG4gICAgICAgICAgICAgICAgICAgICNmaWVsZE1vZGVsPVwibmdNb2RlbFwiXG4gICAgICAgICAgICAgICAgICAgIFtyZXF1aXJlZF09XCJmaWVsZC52YWxpZGF0aW9ucz8ucmVxdWlyZWRcIlxuICAgICAgICAgICAgICAgICAgICBbbWlubGVuZ3RoXT1cImZpZWxkLnZhbGlkYXRpb25zPy5taW5MZW5ndGhcIlxuICAgICAgICAgICAgICAgICAgICBbbWF4bGVuZ3RoXT1cImZpZWxkLnZhbGlkYXRpb25zPy5tYXhMZW5ndGhcIlxuICAgICAgICAgICAgICAgICAgICBjbGFzcz1cImZvcm0tdGV4dGFyZWFcIlxuICAgICAgICAgICAgICAgICAgICBbbmdDbGFzc109XCJ7J2Vycm9yJzogZmllbGRNb2RlbC5pbnZhbGlkICYmIChmaWVsZE1vZGVsLmRpcnR5IHx8IGZpZWxkTW9kZWwudG91Y2hlZCl9XCJcbiAgICAgICAgICAgICAgICAgICAgW2F0dHIuYXJpYS1pbnZhbGlkXT1cImZpZWxkTW9kZWwuaW52YWxpZCAmJiAoZmllbGRNb2RlbC5kaXJ0eSB8fCBmaWVsZE1vZGVsLnRvdWNoZWQpXCJcbiAgICAgICAgICAgICAgICAgICAgW2F0dHIuYXJpYS1kZXNjcmliZWRieV09XCJmaWVsZC5uYW1lICsgJy1lcnJvcidcIj5cbiAgICAgICAgICA8L3RleHRhcmVhPlxuICAgICAgICA8L25nLWNvbnRhaW5lcj5cblxuICAgICAgICA8IS0tIEVycm9yIG1lc3NhZ2VzIC0tPlxuICAgICAgICA8ZGl2ICpuZ0lmPVwiZmllbGRNb2RlbC5pbnZhbGlkICYmIChmaWVsZE1vZGVsLmRpcnR5IHx8IGZpZWxkTW9kZWwudG91Y2hlZClcIlxuICAgICAgICAgICAgIGNsYXNzPVwiZXJyb3ItbWVzc2FnZXNcIlxuICAgICAgICAgICAgIFtpZF09XCJmaWVsZC5uYW1lICsgJy1lcnJvcidcIlxuICAgICAgICAgICAgIHJvbGU9XCJhbGVydFwiPlxuICAgICAgICAgIDxkaXYgKm5nSWY9XCJmaWVsZE1vZGVsLmVycm9ycz8ucmVxdWlyZWRcIj5cbiAgICAgICAgICAgIHt7IGZpZWxkLmVycm9yTWVzc2FnZXM/LnJlcXVpcmVkIH19XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgPGRpdiAqbmdJZj1cImZpZWxkTW9kZWwuZXJyb3JzPy5taW5sZW5ndGhcIj5cbiAgICAgICAgICAgIHt7IGZpZWxkLmVycm9yTWVzc2FnZXM/Lm1pbmxlbmd0aCB9fVxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgIDxkaXYgKm5nSWY9XCJmaWVsZE1vZGVsLmVycm9ycz8ubWF4bGVuZ3RoXCI+XG4gICAgICAgICAgICB7eyBmaWVsZC5lcnJvck1lc3NhZ2VzPy5tYXhsZW5ndGggfX1cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICA8ZGl2ICpuZ0lmPVwiZmllbGRNb2RlbC5lcnJvcnM/LmVtYWlsXCI+XG4gICAgICAgICAgICB7eyBmaWVsZC5lcnJvck1lc3NhZ2VzPy5lbWFpbCB9fVxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgIDxkaXYgKm5nSWY9XCJmaWVsZE1vZGVsLmVycm9ycz8ucGF0dGVyblwiPlxuICAgICAgICAgICAge3sgZmllbGQuZXJyb3JNZXNzYWdlcz8ucGF0dGVybiB9fVxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICA8L2Rpdj5cbiAgICAgIDwvZGl2PlxuXG4gICAgICA8YnV0dG9uIHR5cGU9XCJzdWJtaXRcIlxuICAgICAgICAgICAgICBbZGlzYWJsZWRdPVwiIWZvcm0udmFsaWRcIlxuICAgICAgICAgICAgICBbY2xhc3NdPVwiZm9ybUNvbmZpZy5zdWJtaXRCdXR0b24/LmNsYXNzIHx8ICdzdWJtaXQtYnV0dG9uJ1wiXG4gICAgICAgICAgICAgIFthdHRyLmFyaWEtZGlzYWJsZWRdPVwiIWZvcm0udmFsaWRcIj5cbiAgICAgICAge3sgZm9ybUNvbmZpZy5zdWJtaXRCdXR0b24/LnRleHQgfHwgJ1N1Ym1pdCcgfX1cbiAgICAgIDwvYnV0dG9uPlxuICAgIDwvZm9ybT5cbiAgYCxcbiAgc3R5bGVzOiBbYFxuICAgIC5keW5hbWljLWZvcm0ge1xuICAgICAgbWF4LXdpZHRoOiA2MDBweDtcbiAgICAgIG1hcmdpbjogMCBhdXRvO1xuICAgICAgcGFkZGluZzogMjBweDtcbiAgICAgIGZvbnQtZmFtaWx5OiAtYXBwbGUtc3lzdGVtLCBCbGlua01hY1N5c3RlbUZvbnQsICdTZWdvZSBVSScsIFJvYm90bywgJ0hlbHZldGljYSBOZXVlJywgQXJpYWwsIHNhbnMtc2VyaWY7XG4gICAgfVxuXG4gICAgLmZvcm0tZmllbGQge1xuICAgICAgbWFyZ2luLWJvdHRvbTogMjBweDtcbiAgICB9XG5cbiAgICAuZm9ybS1sYWJlbCB7XG4gICAgICBkaXNwbGF5OiBibG9jaztcbiAgICAgIG1hcmdpbi1ib3R0b206IDhweDtcbiAgICAgIGZvbnQtd2VpZ2h0OiA1MDA7XG4gICAgICBjb2xvcjogIzMzMztcbiAgICB9XG5cbiAgICAucmVxdWlyZWQtbWFya2VyIHtcbiAgICAgIGNvbG9yOiAjZGMzNTQ1O1xuICAgICAgbWFyZ2luLWxlZnQ6IDRweDtcbiAgICB9XG5cbiAgICAuZm9ybS1pbnB1dCxcbiAgICAuZm9ybS1zZWxlY3QsXG4gICAgLmZvcm0tdGV4dGFyZWEge1xuICAgICAgd2lkdGg6IDEwMCU7XG4gICAgICBwYWRkaW5nOiA4cHggMTJweDtcbiAgICAgIGJvcmRlcjogMXB4IHNvbGlkICNjZWQ0ZGE7XG4gICAgICBib3JkZXItcmFkaXVzOiA0cHg7XG4gICAgICBmb250LXNpemU6IDE2cHg7XG4gICAgICB0cmFuc2l0aW9uOiBib3JkZXItY29sb3IgMC4xNXMgZWFzZS1pbi1vdXQsIGJveC1zaGFkb3cgMC4xNXMgZWFzZS1pbi1vdXQ7XG4gICAgfVxuXG4gICAgLmZvcm0tdGV4dGFyZWEge1xuICAgICAgbWluLWhlaWdodDogMTAwcHg7XG4gICAgICByZXNpemU6IHZlcnRpY2FsO1xuICAgIH1cblxuICAgIC5mb3JtLWlucHV0OmZvY3VzLFxuICAgIC5mb3JtLXNlbGVjdDpmb2N1cyxcbiAgICAuZm9ybS10ZXh0YXJlYTpmb2N1cyB7XG4gICAgICBib3JkZXItY29sb3I6ICM4MGJkZmY7XG4gICAgICBvdXRsaW5lOiAwO1xuICAgICAgYm94LXNoYWRvdzogMCAwIDAgMC4ycmVtIHJnYmEoMCwgMTIzLCAyNTUsIDAuMjUpO1xuICAgIH1cblxuICAgIC5lcnJvciB7XG4gICAgICBib3JkZXItY29sb3I6ICNkYzM1NDU7XG4gICAgfVxuXG4gICAgLmVycm9yOmZvY3VzIHtcbiAgICAgIGJvcmRlci1jb2xvcjogI2RjMzU0NTtcbiAgICAgIGJveC1zaGFkb3c6IDAgMCAwIDAuMnJlbSByZ2JhKDIyMCwgNTMsIDY5LCAwLjI1KTtcbiAgICB9XG5cbiAgICAuZXJyb3ItbWVzc2FnZXMge1xuICAgICAgbWFyZ2luLXRvcDogNXB4O1xuICAgICAgY29sb3I6ICNkYzM1NDU7XG4gICAgICBmb250LXNpemU6IDE0cHg7XG4gICAgfVxuXG4gICAgLmhpZGRlbiB7XG4gICAgICBkaXNwbGF5OiBub25lO1xuICAgIH1cblxuICAgIC5zdWJtaXQtYnV0dG9uIHtcbiAgICAgIGJhY2tncm91bmQtY29sb3I6ICMwMDdiZmY7XG4gICAgICBjb2xvcjogd2hpdGU7XG4gICAgICBwYWRkaW5nOiAxMHB4IDIwcHg7XG4gICAgICBib3JkZXI6IG5vbmU7XG4gICAgICBib3JkZXItcmFkaXVzOiA0cHg7XG4gICAgICBmb250LXNpemU6IDE2cHg7XG4gICAgICBjdXJzb3I6IHBvaW50ZXI7XG4gICAgICB0cmFuc2l0aW9uOiBiYWNrZ3JvdW5kLWNvbG9yIDAuMTVzIGVhc2UtaW4tb3V0O1xuICAgIH1cblxuICAgIC5zdWJtaXQtYnV0dG9uOmhvdmVyOm5vdCg6ZGlzYWJsZWQpIHtcbiAgICAgIGJhY2tncm91bmQtY29sb3I6ICMwMDU2YjM7XG4gICAgfVxuXG4gICAgLnN1Ym1pdC1idXR0b246ZGlzYWJsZWQge1xuICAgICAgYmFja2dyb3VuZC1jb2xvcjogIzZjNzU3ZDtcbiAgICAgIGN1cnNvcjogbm90LWFsbG93ZWQ7XG4gICAgICBvcGFjaXR5OiAwLjY1O1xuICAgIH1cblxuICAgIEBtZWRpYSAobWF4LXdpZHRoOiA3NjhweCkge1xuICAgICAgLmR5bmFtaWMtZm9ybSB7XG4gICAgICAgIHBhZGRpbmc6IDE1cHg7XG4gICAgICB9XG4gICAgfVxuICBgXVxufSlcbmV4cG9ydCBjbGFzcyBEeW5hbWljRm9ybUNvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCB7XG4gIEBJbnB1dCgpIGZvcm1Db25maWchOiBGb3JtQ29uZmlnO1xuICBAT3V0cHV0KCkgZm9ybVN1Ym1pdCA9IG5ldyBFdmVudEVtaXR0ZXI8YW55PigpO1xuXG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgYWlWYWxpZGF0aW9uU2VydmljZTogQWlWYWxpZGF0aW9uU2VydmljZSkge31cblxuICBuZ09uSW5pdCgpIHtcbiAgICAvLyBBcHBseSBBSS1iYXNlZCB2YWxpZGF0aW9uIHJ1bGVzIHRvIGVhY2ggZmllbGRcbiAgICB0aGlzLmZvcm1Db25maWcuZmllbGRzID0gdGhpcy5mb3JtQ29uZmlnLmZpZWxkcy5tYXAoZmllbGQgPT4gXG4gICAgICB0aGlzLmFpVmFsaWRhdGlvblNlcnZpY2Uuc3VnZ2VzdFZhbGlkYXRpb25zKGZpZWxkKVxuICAgICk7XG4gIH1cblxuICBpc0ZpZWxkVmlzaWJsZShmaWVsZDogRm9ybUZpZWxkQ29uZmlnKTogYm9vbGVhbiB7XG4gICAgaWYgKCFmaWVsZC5jb25kaXRpb25hbERpc3BsYXkpIHtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cblxuICAgIGNvbnN0IGRlcGVuZGVudEZpZWxkID0gdGhpcy5mb3JtQ29uZmlnLmZpZWxkcy5maW5kKFxuICAgICAgZiA9PiBmLm5hbWUgPT09IGZpZWxkLmNvbmRpdGlvbmFsRGlzcGxheT8uZGVwZW5kc09uXG4gICAgKTtcblxuICAgIHJldHVybiBkZXBlbmRlbnRGaWVsZD8udmFsdWUgPT09IGZpZWxkLmNvbmRpdGlvbmFsRGlzcGxheS5zaG93V2hlbjtcbiAgfVxuXG4gIG9uU3VibWl0KGZvcm06IE5nRm9ybSkge1xuICAgIGlmIChmb3JtLnZhbGlkKSB7XG4gICAgICBjb25zdCBmb3JtRGF0YSA9IHRoaXMuZm9ybUNvbmZpZy5maWVsZHMucmVkdWNlKChhY2MsIGZpZWxkKSA9PiB7XG4gICAgICAgIGlmICh0aGlzLmlzRmllbGRWaXNpYmxlKGZpZWxkKSkge1xuICAgICAgICAgIGFjY1tmaWVsZC5uYW1lXSA9IGZpZWxkLnZhbHVlO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBhY2M7XG4gICAgICB9LCB7fSBhcyBhbnkpO1xuXG4gICAgICB0aGlzLmZvcm1TdWJtaXQuZW1pdChmb3JtRGF0YSk7XG4gICAgfVxuICB9XG59XG4iXX0=