@vendasta/store
Version:
Components and data for Store
77 lines • 41.2 kB
JavaScript
import { Input, Component, ViewChild } from '@angular/core';
import { FormGroup } from '@angular/forms';
import * as i0 from "@angular/core";
import * as i1 from "@vendasta/galaxy/form-field";
import * as i2 from "@angular/material/select";
import * as i3 from "@angular/material/core";
import * as i4 from "@vendasta/forms";
import * as i5 from "@angular/material/checkbox";
import * as i6 from "@vendasta/galaxy/uploader";
import * as i7 from "@angular/common";
import * as i8 from "@angular/forms";
import * as i9 from "@angular/material/input";
import * as i10 from "@angular/cdk/text-field";
import * as i11 from "@ngx-translate/core";
export class FieldComponent {
get isValid() {
return this.form.controls[this.field.id].valid || this.form.controls[this.field.id].pristine;
}
showCheckboxError(field) {
return (this.form.controls[field].errors && this.form.controls[field].errors.required && this.form.controls[field].touched);
}
getValue() {
return this.form.controls[this.field.id].value;
}
dropdownAnswer() {
const answer = this.getValue();
return ((this.field.options || []).find((option) => option.value === answer) || { label: answer }).label;
}
multidropdownAnswer() {
const answer = this.getValue();
return (answer || [])
.map((a) => ((this.field.options || []).find((option) => option.value === a) || { name: a }).name)
.join(', ');
}
checkboxAnswer() {
const answer = this.getValue();
return answer ? 'Yes' : 'No';
}
fileUploadAnswer() {
const answer = this.getValue();
return answer.map((a) => (a.name ? a.name : a.url ? a.url : a)).join(', ');
}
// Load form values into galaxy uploader to get any cached values
uploadedFiles() {
return this.form.controls[this.field.id].value;
}
// Handle deleting file from both galaxy uploader component, and order-form form values
deleteFile(event) {
const filterOutDeletedFile = this.form.controls[this.field.id].value.filter((file) => file.name !== event.name && file.url !== event.url);
this.form.controls[this.field.id].setValue(filterOutDeletedFile);
// Tell galaxy uploader about delete so it can handle maxFiles properly
this.glxyUploader.deleteFile(event);
}
// Manually update order-form form with events from galaxy file uploader
onUpload(event) {
const uploadedFiles = this.form.controls[this.field.id].value;
uploadedFiles.push({
name: event.name,
url: event.url,
});
this.form.controls[this.field.id].setValue(uploadedFiles);
}
}
FieldComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.0.2", ngImport: i0, type: FieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
FieldComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.0.2", type: FieldComponent, selector: "app-order-field", inputs: { field: "field", form: "form" }, viewQueries: [{ propertyName: "glxyUploader", first: true, predicate: ["glxyUploader"], descendants: true }], ngImport: i0, template: "<ng-container [ngSwitch]=\"field.controlType\" [formGroup]=\"form\">\n <ng-container *ngIf=\"!field.hidden\">\n <div class=\"office-text\" *ngIf=\"field.forOfficeUseOnly\">\n * {{ 'FRONTEND.STORE.ORDER_FORM.HIDDEN_FROM_END_USERS' | translate }}:\n </div>\n <div class=\"office-text\" *ngIf=\"field.officeEditableOnly\">\n * {{ 'FRONTEND.STORE.ORDER_FORM.OFFICE_EDITABLE_ONLY' | translate }}:\n </div>\n\n <ng-container *ngSwitchCase=\"'dropdown'\">\n <ng-container *ngIf=\"!field.allowMultiples\">\n <div class=\"display\">\n <glxy-form-field>\n <glxy-label>\n {{ field.label | translate }}{{ field.required ? '*' : '' }}\n </glxy-label>\n <mat-select matInput [formControlName]=\"field.id\" [id]=\"field.id\">\n <mat-option\n *ngFor=\"let option of field.options\"\n [value]=\"option.value\"\n >\n {{ option.label }}\n </mat-option>\n </mat-select>\n <glxy-hint position=\"below\" *ngIf=\"field.description\">\n {{ field.description }}\n </glxy-hint>\n </glxy-form-field>\n </div>\n <div class=\"print\">\n <div class=\"label\">{{ field.label | translate }}:</div>\n <div class=\"answer\">{{ dropdownAnswer() }}</div>\n </div>\n </ng-container>\n <ng-container *ngIf=\"field.allowMultiples\">\n <div class=\"display\">\n <glxy-input-tags\n [id]=\"field.id\"\n [formControlName]=\"field.id\"\n label=\"{{ field.label | translate }}{{\n field.required ? ' *' : ''\n }}\"\n [hint]=\"field.description\"\n [required]=\"field.required\"\n [options]=\"field.options\"\n [allowDuplicates]=\"field.allowDuplicates\"\n [maxFields]=\"field.maxChoices\"\n ></glxy-input-tags>\n </div>\n <div class=\"print\">\n <div class=\"label\">{{ field.label | translate }}:</div>\n <div class=\"answer\">{{ multidropdownAnswer() }}</div>\n </div>\n </ng-container>\n </ng-container>\n\n <ng-container *ngSwitchCase=\"'textbox'\">\n <div class=\"display\">\n <glxy-form-field\n [prefixText]=\"field.prefix\"\n [suffixText]=\"field.suffix\"\n >\n <glxy-label>\n {{ field.label | translate }}{{ field.required ? ' *' : '' }}\n </glxy-label>\n <input\n matInput\n [type]=\"field.textboxType\"\n [id]=\"field.id\"\n [formControlName]=\"field.id\"\n [pattern]=\"field.regexValidator || ''\"\n [readonly]=\"field.displayOnly\"\n [ngClass]=\"{ 'display-only': field.displayOnly }\"\n />\n <glxy-hint position=\"below\" *ngIf=\"field.description\">\n {{ field.description }}\n </glxy-hint>\n <glxy-error *ngIf=\"form.controls[field.id].hasError('pattern')\">\n {{ field.regexErrorMessage }}\n </glxy-error>\n </glxy-form-field>\n </div>\n <div class=\"print\">\n <div class=\"label\">{{ field.label | translate }}:</div>\n <div class=\"answer\">{{ getValue() }}</div>\n </div>\n </ng-container>\n\n <ng-container *ngSwitchCase=\"'checkbox'\">\n <div class=\"display\">\n <glxy-form-field>\n <mat-checkbox\n [formControlName]=\"field.id\"\n [id]=\"field.id\"\n ngControlDefault\n >\n {{ field.label | translate }}{{ field.required ? ' *' : '' }}\n <extended *ngIf=\"field.description\">\n {{ field.description }}\n </extended>\n </mat-checkbox>\n <glxy-error *ngIf=\"showCheckboxError(field.id)\" class=\"checkboxError\">\n {{ 'FRONTEND.STORE.REQUIRED' | translate }}\n </glxy-error>\n </glxy-form-field>\n </div>\n <div class=\"print\">\n <div class=\"label\">{{ field.label | translate }}:</div>\n <div class=\"answer\">{{ checkboxAnswer() }}</div>\n </div>\n </ng-container>\n\n <ng-container *ngSwitchCase=\"'textarea'\">\n <span class=\"display\">\n <glxy-form-field>\n <glxy-label>\n {{ field.label | translate }}{{ field.required ? ' *' : '' }}\n </glxy-label>\n <textarea\n matInput\n [formControlName]=\"field.id\"\n [id]=\"field.id\"\n cdkTextareaAutosize\n ></textarea>\n <glxy-hint position=\"below\" *ngIf=\"field.description\">\n {{ field.description }}\n </glxy-hint>\n </glxy-form-field>\n </span>\n <div class=\"print\">\n <div class=\"label\">{{ field.label | translate }}:</div>\n <div class=\"answer\">{{ getValue() }}</div>\n </div>\n </ng-container>\n\n <ng-container *ngSwitchCase=\"'file'\">\n <span class=\"display\">\n <glxy-form-field>\n <glxy-label>\n {{ field.label | translate }}{{ field.required ? ' *' : '' }}\n </glxy-label>\n <glxy-hint position=\"below\" *ngIf=\"field.description\">\n {{ field.description }}\n </glxy-hint>\n <ng-container *ngIf=\"!field.disabled\">\n <glxy-uploader\n #glxyUploader\n [uploadUrl]=\"field.uploadUrl\"\n [maxFiles]=\"field.numFiles\"\n (fileUploaded)=\"onUpload($event)\"\n ></glxy-uploader>\n <glxy-uploader-list\n [files]=\"uploadedFiles() || []\"\n (fileDeleted)=\"deleteFile($event)\"\n ></glxy-uploader-list>\n </ng-container>\n <ng-container *ngIf=\"field.disabled\">\n <ng-container *ngIf=\"!uploadedFiles().length\">—</ng-container>\n <ng-container *ngIf=\"uploadedFiles().length\">\n <ul class=\"file-static-list\">\n <li *ngFor=\"let file of uploadedFiles()\">\n <a href=\"{{ file.url }}\" target=\"_blank\">{{ file.name }}</a>\n </li>\n </ul>\n </ng-container>\n </ng-container>\n </glxy-form-field>\n </span>\n <div class=\"print\">\n <div class=\"label\">{{ field.label | translate }}:</div>\n <div class=\"answer\">{{ fileUploadAnswer() }}</div>\n </div>\n </ng-container>\n\n <ng-container *ngSwitchCase=\"'vbcuser'\">\n <div class=\"display\">\n <glxy-form-field>\n <glxy-label>\n {{ field.label | translate }}{{ field.required ? ' *' : '' }}\n </glxy-label>\n <mat-select matInput [formControlName]=\"field.id\" [id]=\"field.id\">\n <mat-option\n *ngFor=\"let option of field.options\"\n [value]=\"option.value\"\n [disabled]=\"option.disabled\"\n >\n {{ option.label | translate }}\n </mat-option>\n </mat-select>\n <glxy-hint position=\"below\" *ngIf=\"field.description\">\n {{ field.description }}\n </glxy-hint>\n </glxy-form-field>\n </div>\n <div class=\"print\">\n <div class=\"label\">{{ field.label | translate }}:</div>\n <div class=\"answer\">{{ dropdownAnswer() }}</div>\n </div>\n </ng-container>\n </ng-container>\n</ng-container>\n", styles: [".office-text{font-size:13px;color:#9e9e9e;color:var(--tertiary-text-color, #9e9e9e);margin-bottom:-24px}.office-text+.office-text{margin-top:24px}@media print{.office-text{margin:0}}.display-only{color:rgba(0,0,0,.38)}.file-static-list{margin:0;padding:0;list-style:none}@media print{.display{display:none}}.print{display:none}@media print{.print{display:flex;outline:1px solid;margin-top:1px;margin-left:1px;page-break-inside:avoid}.print .label{flex-basis:30%;padding:8px;font-weight:500;border-right:1px solid black}.print .answer{flex-basis:70%;padding:8px}}\n"], components: [{ type: i1.FormFieldComponent, selector: "glxy-form-field", inputs: ["label", "disabled", "required", "clearable", "maxWidth", "minWidth", "hasMargins", "smallMargin", "hideInputDecoration", "showLabel", "horizontalLayout", "prefixIcon", "suffixIcon", "prefixText", "suffixText"] }, { type: i2.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i3.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { type: i4.GlxyInputTagsComponent, selector: "glxy-input-tags", inputs: ["options", "hint", "label", "required", "maxFields", "allowDuplicates", "allowCustomTags", "customTagLength", "loading", "disabled", "appearance"] }, { type: i5.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "aria-describedby", "id", "required", "labelPosition", "name", "value", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: i6.GalaxyUploaderComponent, selector: "glxy-uploader", inputs: ["maxFiles", "maxFileSize", "accept", "uploadUrl", "numParallel", "autoUpload", "files", "hintText", "buttonText", "descriptionText"], outputs: ["fileUploadErrored", "fileUploaded", "filesChanged"] }, { type: i6.GalaxyUploaderListComponent, selector: "glxy-uploader-list", inputs: ["files"], outputs: ["fileDeleted"] }], directives: [{ type: i7.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { type: i8.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i8.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i7.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i7.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { type: i1.LabelDirective, selector: "glxy-label, [glxyLabel]" }, { type: i8.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i8.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { type: i7.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i1.HintDirective, selector: "glxy-hint, [glxyHint]", inputs: ["align"] }, { type: i8.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i9.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { type: i8.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i8.PatternValidator, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: ["pattern"] }, { type: i7.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { type: i1.ErrorDirective, selector: "glxy-error, [glxyError]" }, { type: i1.ExtendedDirective, selector: "extended, [glxyExtended]" }, { type: i10.CdkTextareaAutosize, selector: "textarea[cdkTextareaAutosize]", inputs: ["cdkAutosizeMinRows", "cdkAutosizeMaxRows", "cdkTextareaAutosize", "placeholder"], exportAs: ["cdkTextareaAutosize"] }], pipes: { "translate": i11.TranslatePipe } });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.0.2", ngImport: i0, type: FieldComponent, decorators: [{
type: Component,
args: [{ selector: 'app-order-field', template: "<ng-container [ngSwitch]=\"field.controlType\" [formGroup]=\"form\">\n <ng-container *ngIf=\"!field.hidden\">\n <div class=\"office-text\" *ngIf=\"field.forOfficeUseOnly\">\n * {{ 'FRONTEND.STORE.ORDER_FORM.HIDDEN_FROM_END_USERS' | translate }}:\n </div>\n <div class=\"office-text\" *ngIf=\"field.officeEditableOnly\">\n * {{ 'FRONTEND.STORE.ORDER_FORM.OFFICE_EDITABLE_ONLY' | translate }}:\n </div>\n\n <ng-container *ngSwitchCase=\"'dropdown'\">\n <ng-container *ngIf=\"!field.allowMultiples\">\n <div class=\"display\">\n <glxy-form-field>\n <glxy-label>\n {{ field.label | translate }}{{ field.required ? '*' : '' }}\n </glxy-label>\n <mat-select matInput [formControlName]=\"field.id\" [id]=\"field.id\">\n <mat-option\n *ngFor=\"let option of field.options\"\n [value]=\"option.value\"\n >\n {{ option.label }}\n </mat-option>\n </mat-select>\n <glxy-hint position=\"below\" *ngIf=\"field.description\">\n {{ field.description }}\n </glxy-hint>\n </glxy-form-field>\n </div>\n <div class=\"print\">\n <div class=\"label\">{{ field.label | translate }}:</div>\n <div class=\"answer\">{{ dropdownAnswer() }}</div>\n </div>\n </ng-container>\n <ng-container *ngIf=\"field.allowMultiples\">\n <div class=\"display\">\n <glxy-input-tags\n [id]=\"field.id\"\n [formControlName]=\"field.id\"\n label=\"{{ field.label | translate }}{{\n field.required ? ' *' : ''\n }}\"\n [hint]=\"field.description\"\n [required]=\"field.required\"\n [options]=\"field.options\"\n [allowDuplicates]=\"field.allowDuplicates\"\n [maxFields]=\"field.maxChoices\"\n ></glxy-input-tags>\n </div>\n <div class=\"print\">\n <div class=\"label\">{{ field.label | translate }}:</div>\n <div class=\"answer\">{{ multidropdownAnswer() }}</div>\n </div>\n </ng-container>\n </ng-container>\n\n <ng-container *ngSwitchCase=\"'textbox'\">\n <div class=\"display\">\n <glxy-form-field\n [prefixText]=\"field.prefix\"\n [suffixText]=\"field.suffix\"\n >\n <glxy-label>\n {{ field.label | translate }}{{ field.required ? ' *' : '' }}\n </glxy-label>\n <input\n matInput\n [type]=\"field.textboxType\"\n [id]=\"field.id\"\n [formControlName]=\"field.id\"\n [pattern]=\"field.regexValidator || ''\"\n [readonly]=\"field.displayOnly\"\n [ngClass]=\"{ 'display-only': field.displayOnly }\"\n />\n <glxy-hint position=\"below\" *ngIf=\"field.description\">\n {{ field.description }}\n </glxy-hint>\n <glxy-error *ngIf=\"form.controls[field.id].hasError('pattern')\">\n {{ field.regexErrorMessage }}\n </glxy-error>\n </glxy-form-field>\n </div>\n <div class=\"print\">\n <div class=\"label\">{{ field.label | translate }}:</div>\n <div class=\"answer\">{{ getValue() }}</div>\n </div>\n </ng-container>\n\n <ng-container *ngSwitchCase=\"'checkbox'\">\n <div class=\"display\">\n <glxy-form-field>\n <mat-checkbox\n [formControlName]=\"field.id\"\n [id]=\"field.id\"\n ngControlDefault\n >\n {{ field.label | translate }}{{ field.required ? ' *' : '' }}\n <extended *ngIf=\"field.description\">\n {{ field.description }}\n </extended>\n </mat-checkbox>\n <glxy-error *ngIf=\"showCheckboxError(field.id)\" class=\"checkboxError\">\n {{ 'FRONTEND.STORE.REQUIRED' | translate }}\n </glxy-error>\n </glxy-form-field>\n </div>\n <div class=\"print\">\n <div class=\"label\">{{ field.label | translate }}:</div>\n <div class=\"answer\">{{ checkboxAnswer() }}</div>\n </div>\n </ng-container>\n\n <ng-container *ngSwitchCase=\"'textarea'\">\n <span class=\"display\">\n <glxy-form-field>\n <glxy-label>\n {{ field.label | translate }}{{ field.required ? ' *' : '' }}\n </glxy-label>\n <textarea\n matInput\n [formControlName]=\"field.id\"\n [id]=\"field.id\"\n cdkTextareaAutosize\n ></textarea>\n <glxy-hint position=\"below\" *ngIf=\"field.description\">\n {{ field.description }}\n </glxy-hint>\n </glxy-form-field>\n </span>\n <div class=\"print\">\n <div class=\"label\">{{ field.label | translate }}:</div>\n <div class=\"answer\">{{ getValue() }}</div>\n </div>\n </ng-container>\n\n <ng-container *ngSwitchCase=\"'file'\">\n <span class=\"display\">\n <glxy-form-field>\n <glxy-label>\n {{ field.label | translate }}{{ field.required ? ' *' : '' }}\n </glxy-label>\n <glxy-hint position=\"below\" *ngIf=\"field.description\">\n {{ field.description }}\n </glxy-hint>\n <ng-container *ngIf=\"!field.disabled\">\n <glxy-uploader\n #glxyUploader\n [uploadUrl]=\"field.uploadUrl\"\n [maxFiles]=\"field.numFiles\"\n (fileUploaded)=\"onUpload($event)\"\n ></glxy-uploader>\n <glxy-uploader-list\n [files]=\"uploadedFiles() || []\"\n (fileDeleted)=\"deleteFile($event)\"\n ></glxy-uploader-list>\n </ng-container>\n <ng-container *ngIf=\"field.disabled\">\n <ng-container *ngIf=\"!uploadedFiles().length\">—</ng-container>\n <ng-container *ngIf=\"uploadedFiles().length\">\n <ul class=\"file-static-list\">\n <li *ngFor=\"let file of uploadedFiles()\">\n <a href=\"{{ file.url }}\" target=\"_blank\">{{ file.name }}</a>\n </li>\n </ul>\n </ng-container>\n </ng-container>\n </glxy-form-field>\n </span>\n <div class=\"print\">\n <div class=\"label\">{{ field.label | translate }}:</div>\n <div class=\"answer\">{{ fileUploadAnswer() }}</div>\n </div>\n </ng-container>\n\n <ng-container *ngSwitchCase=\"'vbcuser'\">\n <div class=\"display\">\n <glxy-form-field>\n <glxy-label>\n {{ field.label | translate }}{{ field.required ? ' *' : '' }}\n </glxy-label>\n <mat-select matInput [formControlName]=\"field.id\" [id]=\"field.id\">\n <mat-option\n *ngFor=\"let option of field.options\"\n [value]=\"option.value\"\n [disabled]=\"option.disabled\"\n >\n {{ option.label | translate }}\n </mat-option>\n </mat-select>\n <glxy-hint position=\"below\" *ngIf=\"field.description\">\n {{ field.description }}\n </glxy-hint>\n </glxy-form-field>\n </div>\n <div class=\"print\">\n <div class=\"label\">{{ field.label | translate }}:</div>\n <div class=\"answer\">{{ dropdownAnswer() }}</div>\n </div>\n </ng-container>\n </ng-container>\n</ng-container>\n", styles: [".office-text{font-size:13px;color:#9e9e9e;color:var(--tertiary-text-color, #9e9e9e);margin-bottom:-24px}.office-text+.office-text{margin-top:24px}@media print{.office-text{margin:0}}.display-only{color:rgba(0,0,0,.38)}.file-static-list{margin:0;padding:0;list-style:none}@media print{.display{display:none}}.print{display:none}@media print{.print{display:flex;outline:1px solid;margin-top:1px;margin-left:1px;page-break-inside:avoid}.print .label{flex-basis:30%;padding:8px;font-weight:500;border-right:1px solid black}.print .answer{flex-basis:70%;padding:8px}}\n"] }]
}], propDecorators: { field: [{
type: Input
}], form: [{
type: Input
}], glxyUploader: [{
type: ViewChild,
args: ['glxyUploader']
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmllbGQuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vbGlicy9zdG9yZS9zcmMvbGliL29yZGVyLWZvcm0vZmllbGRzL2ZpZWxkLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uLy4uLy4uL2xpYnMvc3RvcmUvc3JjL2xpYi9vcmRlci1mb3JtL2ZpZWxkcy9maWVsZC5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsS0FBSyxFQUFFLFNBQVMsRUFBRSxTQUFTLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDNUQsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLGdCQUFnQixDQUFDOzs7Ozs7Ozs7Ozs7O0FBTzNDLE1BQU0sT0FBTyxjQUFjO0lBTXpCLElBQUksT0FBTztRQUNULE9BQU8sSUFBSSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsQ0FBQyxLQUFLLElBQUksSUFBSSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsQ0FBQyxRQUFRLENBQUM7SUFDL0YsQ0FBQztJQUVELGlCQUFpQixDQUFDLEtBQUs7UUFDckIsT0FBTyxDQUNMLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxDQUFDLE1BQU0sSUFBSSxJQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsQ0FBQyxNQUFNLENBQUMsUUFBUSxJQUFJLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxDQUFDLE9BQU8sQ0FDbkgsQ0FBQztJQUNKLENBQUM7SUFFRCxRQUFRO1FBQ04sT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxDQUFDLEtBQUssQ0FBQztJQUNqRCxDQUFDO0lBRUQsY0FBYztRQUNaLE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQztRQUMvQixPQUFPLENBQUMsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sSUFBSSxFQUFFLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDLE1BQU0sQ0FBQyxLQUFLLEtBQUssTUFBTSxDQUFDLElBQUksRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLENBQUMsQ0FBQyxLQUFLLENBQUM7SUFDM0csQ0FBQztJQUVELG1CQUFtQjtRQUNqQixNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUM7UUFDL0IsT0FBTyxDQUFDLE1BQU0sSUFBSSxFQUFFLENBQUM7YUFDbEIsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLElBQUksRUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsTUFBTSxFQUFFLEVBQUUsQ0FBQyxNQUFNLENBQUMsS0FBSyxLQUFLLENBQUMsQ0FBQyxJQUFJLEVBQUUsSUFBSSxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDO2FBQ2pHLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUNoQixDQUFDO0lBRUQsY0FBYztRQUNaLE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQztRQUMvQixPQUFPLE1BQU0sQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUM7SUFDL0IsQ0FBQztJQUVELGdCQUFnQjtRQUNkLE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQztRQUMvQixPQUFPLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDN0UsQ0FBQztJQUVELGlFQUFpRTtJQUNqRSxhQUFhO1FBQ1gsT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxDQUFDLEtBQUssQ0FBQztJQUNqRCxDQUFDO0lBRUQsdUZBQXVGO0lBQ3ZGLFVBQVUsQ0FBQyxLQUFVO1FBQ25CLE1BQU0sb0JBQW9CLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUN6RSxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLElBQUksS0FBSyxLQUFLLENBQUMsSUFBSSxJQUFJLElBQUksQ0FBQyxHQUFHLEtBQUssS0FBSyxDQUFDLEdBQUcsQ0FDN0QsQ0FBQztRQUVGLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLENBQUMsUUFBUSxDQUFDLG9CQUFvQixDQUFDLENBQUM7UUFDakUsdUVBQXVFO1FBQ3ZFLElBQUksQ0FBQyxZQUFZLENBQUMsVUFBVSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ3RDLENBQUM7SUFFRCx3RUFBd0U7SUFDeEUsUUFBUSxDQUFDLEtBQVU7UUFDakIsTUFBTSxhQUFhLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsQ0FBQyxLQUFLLENBQUM7UUFFOUQsYUFBYSxDQUFDLElBQUksQ0FBQztZQUNqQixJQUFJLEVBQUUsS0FBSyxDQUFDLElBQUk7WUFDaEIsR0FBRyxFQUFFLEtBQUssQ0FBQyxHQUFHO1NBQ2YsQ0FBQyxDQUFDO1FBRUgsSUFBSSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsQ0FBQyxRQUFRLENBQUMsYUFBYSxDQUFDLENBQUM7SUFDNUQsQ0FBQzs7MkdBcEVVLGNBQWM7K0ZBQWQsY0FBYywrTUNSM0IsczZPQXlNQTsyRkRqTWEsY0FBYztrQkFMMUIsU0FBUzsrQkFDRSxpQkFBaUI7OEJBS2xCLEtBQUs7c0JBQWIsS0FBSztnQkFDRyxJQUFJO3NCQUFaLEtBQUs7Z0JBRXFCLFlBQVk7c0JBQXRDLFNBQVM7dUJBQUMsY0FBYyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IElucHV0LCBDb21wb25lbnQsIFZpZXdDaGlsZCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgRm9ybUdyb3VwIH0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xuXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICdhcHAtb3JkZXItZmllbGQnLFxuICBzdHlsZVVybHM6IFsnLi9maWVsZC5jb21wb25lbnQuc2NzcyddLFxuICB0ZW1wbGF0ZVVybDogJy4vZmllbGQuY29tcG9uZW50Lmh0bWwnLFxufSlcbmV4cG9ydCBjbGFzcyBGaWVsZENvbXBvbmVudCB7XG4gIEBJbnB1dCgpIGZpZWxkOiBhbnk7IC8vIGF2b2lkIGNoZWNraW5nIHVuaW9uIHR5cGUgaW4gdGVtcGxhdGVcbiAgQElucHV0KCkgZm9ybTogRm9ybUdyb3VwO1xuXG4gIEBWaWV3Q2hpbGQoJ2dseHlVcGxvYWRlcicpIGdseHlVcGxvYWRlcjtcblxuICBnZXQgaXNWYWxpZCgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5mb3JtLmNvbnRyb2xzW3RoaXMuZmllbGQuaWRdLnZhbGlkIHx8IHRoaXMuZm9ybS5jb250cm9sc1t0aGlzLmZpZWxkLmlkXS5wcmlzdGluZTtcbiAgfVxuXG4gIHNob3dDaGVja2JveEVycm9yKGZpZWxkKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIChcbiAgICAgIHRoaXMuZm9ybS5jb250cm9sc1tmaWVsZF0uZXJyb3JzICYmIHRoaXMuZm9ybS5jb250cm9sc1tmaWVsZF0uZXJyb3JzLnJlcXVpcmVkICYmIHRoaXMuZm9ybS5jb250cm9sc1tmaWVsZF0udG91Y2hlZFxuICAgICk7XG4gIH1cblxuICBnZXRWYWx1ZSgpOiBhbnkge1xuICAgIHJldHVybiB0aGlzLmZvcm0uY29udHJvbHNbdGhpcy5maWVsZC5pZF0udmFsdWU7XG4gIH1cblxuICBkcm9wZG93bkFuc3dlcigpOiBzdHJpbmcge1xuICAgIGNvbnN0IGFuc3dlciA9IHRoaXMuZ2V0VmFsdWUoKTtcbiAgICByZXR1cm4gKCh0aGlzLmZpZWxkLm9wdGlvbnMgfHwgW10pLmZpbmQoKG9wdGlvbikgPT4gb3B0aW9uLnZhbHVlID09PSBhbnN3ZXIpIHx8IHsgbGFiZWw6IGFuc3dlciB9KS5sYWJlbDtcbiAgfVxuXG4gIG11bHRpZHJvcGRvd25BbnN3ZXIoKTogc3RyaW5nIHtcbiAgICBjb25zdCBhbnN3ZXIgPSB0aGlzLmdldFZhbHVlKCk7XG4gICAgcmV0dXJuIChhbnN3ZXIgfHwgW10pXG4gICAgICAubWFwKChhKSA9PiAoKHRoaXMuZmllbGQub3B0aW9ucyB8fCBbXSkuZmluZCgob3B0aW9uKSA9PiBvcHRpb24udmFsdWUgPT09IGEpIHx8IHsgbmFtZTogYSB9KS5uYW1lKVxuICAgICAgLmpvaW4oJywgJyk7XG4gIH1cblxuICBjaGVja2JveEFuc3dlcigpOiBzdHJpbmcge1xuICAgIGNvbnN0IGFuc3dlciA9IHRoaXMuZ2V0VmFsdWUoKTtcbiAgICByZXR1cm4gYW5zd2VyID8gJ1llcycgOiAnTm8nO1xuICB9XG5cbiAgZmlsZVVwbG9hZEFuc3dlcigpOiBzdHJpbmcge1xuICAgIGNvbnN0IGFuc3dlciA9IHRoaXMuZ2V0VmFsdWUoKTtcbiAgICByZXR1cm4gYW5zd2VyLm1hcCgoYSkgPT4gKGEubmFtZSA/IGEubmFtZSA6IGEudXJsID8gYS51cmwgOiBhKSkuam9pbignLCAnKTtcbiAgfVxuXG4gIC8vIExvYWQgZm9ybSB2YWx1ZXMgaW50byBnYWxheHkgdXBsb2FkZXIgdG8gZ2V0IGFueSBjYWNoZWQgdmFsdWVzXG4gIHVwbG9hZGVkRmlsZXMoKTogYW55W10ge1xuICAgIHJldHVybiB0aGlzLmZvcm0uY29udHJvbHNbdGhpcy5maWVsZC5pZF0udmFsdWU7XG4gIH1cblxuICAvLyBIYW5kbGUgZGVsZXRpbmcgZmlsZSBmcm9tIGJvdGggZ2FsYXh5IHVwbG9hZGVyIGNvbXBvbmVudCwgYW5kIG9yZGVyLWZvcm0gZm9ybSB2YWx1ZXNcbiAgZGVsZXRlRmlsZShldmVudDogYW55KTogdm9pZCB7XG4gICAgY29uc3QgZmlsdGVyT3V0RGVsZXRlZEZpbGUgPSB0aGlzLmZvcm0uY29udHJvbHNbdGhpcy5maWVsZC5pZF0udmFsdWUuZmlsdGVyKFxuICAgICAgKGZpbGUpID0+IGZpbGUubmFtZSAhPT0gZXZlbnQubmFtZSAmJiBmaWxlLnVybCAhPT0gZXZlbnQudXJsLFxuICAgICk7XG5cbiAgICB0aGlzLmZvcm0uY29udHJvbHNbdGhpcy5maWVsZC5pZF0uc2V0VmFsdWUoZmlsdGVyT3V0RGVsZXRlZEZpbGUpO1xuICAgIC8vIFRlbGwgZ2FsYXh5IHVwbG9hZGVyIGFib3V0IGRlbGV0ZSBzbyBpdCBjYW4gaGFuZGxlIG1heEZpbGVzIHByb3Blcmx5XG4gICAgdGhpcy5nbHh5VXBsb2FkZXIuZGVsZXRlRmlsZShldmVudCk7XG4gIH1cblxuICAvLyBNYW51YWxseSB1cGRhdGUgb3JkZXItZm9ybSBmb3JtIHdpdGggZXZlbnRzIGZyb20gZ2FsYXh5IGZpbGUgdXBsb2FkZXJcbiAgb25VcGxvYWQoZXZlbnQ6IGFueSk6IHZvaWQge1xuICAgIGNvbnN0IHVwbG9hZGVkRmlsZXMgPSB0aGlzLmZvcm0uY29udHJvbHNbdGhpcy5maWVsZC5pZF0udmFsdWU7XG5cbiAgICB1cGxvYWRlZEZpbGVzLnB1c2goe1xuICAgICAgbmFtZTogZXZlbnQubmFtZSxcbiAgICAgIHVybDogZXZlbnQudXJsLFxuICAgIH0pO1xuXG4gICAgdGhpcy5mb3JtLmNvbnRyb2xzW3RoaXMuZmllbGQuaWRdLnNldFZhbHVlKHVwbG9hZGVkRmlsZXMpO1xuICB9XG59XG4iLCI8bmctY29udGFpbmVyIFtuZ1N3aXRjaF09XCJmaWVsZC5jb250cm9sVHlwZVwiIFtmb3JtR3JvdXBdPVwiZm9ybVwiPlxuICA8bmctY29udGFpbmVyICpuZ0lmPVwiIWZpZWxkLmhpZGRlblwiPlxuICAgIDxkaXYgY2xhc3M9XCJvZmZpY2UtdGV4dFwiICpuZ0lmPVwiZmllbGQuZm9yT2ZmaWNlVXNlT25seVwiPlxuICAgICAgKiB7eyAnRlJPTlRFTkQuU1RPUkUuT1JERVJfRk9STS5ISURERU5fRlJPTV9FTkRfVVNFUlMnIHwgdHJhbnNsYXRlIH19OlxuICAgIDwvZGl2PlxuICAgIDxkaXYgY2xhc3M9XCJvZmZpY2UtdGV4dFwiICpuZ0lmPVwiZmllbGQub2ZmaWNlRWRpdGFibGVPbmx5XCI+XG4gICAgICAqIHt7ICdGUk9OVEVORC5TVE9SRS5PUkRFUl9GT1JNLk9GRklDRV9FRElUQUJMRV9PTkxZJyB8IHRyYW5zbGF0ZSB9fTpcbiAgICA8L2Rpdj5cblxuICAgIDxuZy1jb250YWluZXIgKm5nU3dpdGNoQ2FzZT1cIidkcm9wZG93bidcIj5cbiAgICAgIDxuZy1jb250YWluZXIgKm5nSWY9XCIhZmllbGQuYWxsb3dNdWx0aXBsZXNcIj5cbiAgICAgICAgPGRpdiBjbGFzcz1cImRpc3BsYXlcIj5cbiAgICAgICAgICA8Z2x4eS1mb3JtLWZpZWxkPlxuICAgICAgICAgICAgPGdseHktbGFiZWw+XG4gICAgICAgICAgICAgIHt7IGZpZWxkLmxhYmVsIHwgdHJhbnNsYXRlIH19e3sgZmllbGQucmVxdWlyZWQgPyAnKicgOiAnJyB9fVxuICAgICAgICAgICAgPC9nbHh5LWxhYmVsPlxuICAgICAgICAgICAgPG1hdC1zZWxlY3QgbWF0SW5wdXQgW2Zvcm1Db250cm9sTmFtZV09XCJmaWVsZC5pZFwiIFtpZF09XCJmaWVsZC5pZFwiPlxuICAgICAgICAgICAgICA8bWF0LW9wdGlvblxuICAgICAgICAgICAgICAgICpuZ0Zvcj1cImxldCBvcHRpb24gb2YgZmllbGQub3B0aW9uc1wiXG4gICAgICAgICAgICAgICAgW3ZhbHVlXT1cIm9wdGlvbi52YWx1ZVwiXG4gICAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgICB7eyBvcHRpb24ubGFiZWwgfX1cbiAgICAgICAgICAgICAgPC9tYXQtb3B0aW9uPlxuICAgICAgICAgICAgPC9tYXQtc2VsZWN0PlxuICAgICAgICAgICAgPGdseHktaGludCBwb3NpdGlvbj1cImJlbG93XCIgKm5nSWY9XCJmaWVsZC5kZXNjcmlwdGlvblwiPlxuICAgICAgICAgICAgICB7eyBmaWVsZC5kZXNjcmlwdGlvbiB9fVxuICAgICAgICAgICAgPC9nbHh5LWhpbnQ+XG4gICAgICAgICAgPC9nbHh5LWZvcm0tZmllbGQ+XG4gICAgICAgIDwvZGl2PlxuICAgICAgICA8ZGl2IGNsYXNzPVwicHJpbnRcIj5cbiAgICAgICAgICA8ZGl2IGNsYXNzPVwibGFiZWxcIj57eyBmaWVsZC5sYWJlbCB8IHRyYW5zbGF0ZSB9fTo8L2Rpdj5cbiAgICAgICAgICA8ZGl2IGNsYXNzPVwiYW5zd2VyXCI+e3sgZHJvcGRvd25BbnN3ZXIoKSB9fTwvZGl2PlxuICAgICAgICA8L2Rpdj5cbiAgICAgIDwvbmctY29udGFpbmVyPlxuICAgICAgPG5nLWNvbnRhaW5lciAqbmdJZj1cImZpZWxkLmFsbG93TXVsdGlwbGVzXCI+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJkaXNwbGF5XCI+XG4gICAgICAgICAgPGdseHktaW5wdXQtdGFnc1xuICAgICAgICAgICAgW2lkXT1cImZpZWxkLmlkXCJcbiAgICAgICAgICAgIFtmb3JtQ29udHJvbE5hbWVdPVwiZmllbGQuaWRcIlxuICAgICAgICAgICAgbGFiZWw9XCJ7eyBmaWVsZC5sYWJlbCB8IHRyYW5zbGF0ZSB9fXt7XG4gICAgICAgICAgICAgIGZpZWxkLnJlcXVpcmVkID8gJyAqJyA6ICcnXG4gICAgICAgICAgICB9fVwiXG4gICAgICAgICAgICBbaGludF09XCJmaWVsZC5kZXNjcmlwdGlvblwiXG4gICAgICAgICAgICBbcmVxdWlyZWRdPVwiZmllbGQucmVxdWlyZWRcIlxuICAgICAgICAgICAgW29wdGlvbnNdPVwiZmllbGQub3B0aW9uc1wiXG4gICAgICAgICAgICBbYWxsb3dEdXBsaWNhdGVzXT1cImZpZWxkLmFsbG93RHVwbGljYXRlc1wiXG4gICAgICAgICAgICBbbWF4RmllbGRzXT1cImZpZWxkLm1heENob2ljZXNcIlxuICAgICAgICAgID48L2dseHktaW5wdXQtdGFncz5cbiAgICAgICAgPC9kaXY+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJwcmludFwiPlxuICAgICAgICAgIDxkaXYgY2xhc3M9XCJsYWJlbFwiPnt7IGZpZWxkLmxhYmVsIHwgdHJhbnNsYXRlIH19OjwvZGl2PlxuICAgICAgICAgIDxkaXYgY2xhc3M9XCJhbnN3ZXJcIj57eyBtdWx0aWRyb3Bkb3duQW5zd2VyKCkgfX08L2Rpdj5cbiAgICAgICAgPC9kaXY+XG4gICAgICA8L25nLWNvbnRhaW5lcj5cbiAgICA8L25nLWNvbnRhaW5lcj5cblxuICAgIDxuZy1jb250YWluZXIgKm5nU3dpdGNoQ2FzZT1cIid0ZXh0Ym94J1wiPlxuICAgICAgPGRpdiBjbGFzcz1cImRpc3BsYXlcIj5cbiAgICAgICAgPGdseHktZm9ybS1maWVsZFxuICAgICAgICAgIFtwcmVmaXhUZXh0XT1cImZpZWxkLnByZWZpeFwiXG4gICAgICAgICAgW3N1ZmZpeFRleHRdPVwiZmllbGQuc3VmZml4XCJcbiAgICAgICAgPlxuICAgICAgICAgIDxnbHh5LWxhYmVsPlxuICAgICAgICAgICAge3sgZmllbGQubGFiZWwgfCB0cmFuc2xhdGUgfX17eyBmaWVsZC5yZXF1aXJlZCA/ICcgKicgOiAnJyB9fVxuICAgICAgICAgIDwvZ2x4eS1sYWJlbD5cbiAgICAgICAgICA8aW5wdXRcbiAgICAgICAgICAgIG1hdElucHV0XG4gICAgICAgICAgICBbdHlwZV09XCJmaWVsZC50ZXh0Ym94VHlwZVwiXG4gICAgICAgICAgICBbaWRdPVwiZmllbGQuaWRcIlxuICAgICAgICAgICAgW2Zvcm1Db250cm9sTmFtZV09XCJmaWVsZC5pZFwiXG4gICAgICAgICAgICBbcGF0dGVybl09XCJmaWVsZC5yZWdleFZhbGlkYXRvciB8fCAnJ1wiXG4gICAgICAgICAgICBbcmVhZG9ubHldPVwiZmllbGQuZGlzcGxheU9ubHlcIlxuICAgICAgICAgICAgW25nQ2xhc3NdPVwieyAnZGlzcGxheS1vbmx5JzogZmllbGQuZGlzcGxheU9ubHkgfVwiXG4gICAgICAgICAgLz5cbiAgICAgICAgICA8Z2x4eS1oaW50IHBvc2l0aW9uPVwiYmVsb3dcIiAqbmdJZj1cImZpZWxkLmRlc2NyaXB0aW9uXCI+XG4gICAgICAgICAgICB7eyBmaWVsZC5kZXNjcmlwdGlvbiB9fVxuICAgICAgICAgIDwvZ2x4eS1oaW50PlxuICAgICAgICAgIDxnbHh5LWVycm9yICpuZ0lmPVwiZm9ybS5jb250cm9sc1tmaWVsZC5pZF0uaGFzRXJyb3IoJ3BhdHRlcm4nKVwiPlxuICAgICAgICAgICAge3sgZmllbGQucmVnZXhFcnJvck1lc3NhZ2UgfX1cbiAgICAgICAgICA8L2dseHktZXJyb3I+XG4gICAgICAgIDwvZ2x4eS1mb3JtLWZpZWxkPlxuICAgICAgPC9kaXY+XG4gICAgICA8ZGl2IGNsYXNzPVwicHJpbnRcIj5cbiAgICAgICAgPGRpdiBjbGFzcz1cImxhYmVsXCI+e3sgZmllbGQubGFiZWwgfCB0cmFuc2xhdGUgfX06PC9kaXY+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJhbnN3ZXJcIj57eyBnZXRWYWx1ZSgpIH19PC9kaXY+XG4gICAgICA8L2Rpdj5cbiAgICA8L25nLWNvbnRhaW5lcj5cblxuICAgIDxuZy1jb250YWluZXIgKm5nU3dpdGNoQ2FzZT1cIidjaGVja2JveCdcIj5cbiAgICAgIDxkaXYgY2xhc3M9XCJkaXNwbGF5XCI+XG4gICAgICAgIDxnbHh5LWZvcm0tZmllbGQ+XG4gICAgICAgICAgPG1hdC1jaGVja2JveFxuICAgICAgICAgICAgW2Zvcm1Db250cm9sTmFtZV09XCJmaWVsZC5pZFwiXG4gICAgICAgICAgICBbaWRdPVwiZmllbGQuaWRcIlxuICAgICAgICAgICAgbmdDb250cm9sRGVmYXVsdFxuICAgICAgICAgID5cbiAgICAgICAgICAgIHt7IGZpZWxkLmxhYmVsIHwgdHJhbnNsYXRlIH19e3sgZmllbGQucmVxdWlyZWQgPyAnIConIDogJycgfX1cbiAgICAgICAgICAgIDxleHRlbmRlZCAqbmdJZj1cImZpZWxkLmRlc2NyaXB0aW9uXCI+XG4gICAgICAgICAgICAgIHt7IGZpZWxkLmRlc2NyaXB0aW9uIH19XG4gICAgICAgICAgICA8L2V4dGVuZGVkPlxuICAgICAgICAgIDwvbWF0LWNoZWNrYm94PlxuICAgICAgICAgIDxnbHh5LWVycm9yICpuZ0lmPVwic2hvd0NoZWNrYm94RXJyb3IoZmllbGQuaWQpXCIgY2xhc3M9XCJjaGVja2JveEVycm9yXCI+XG4gICAgICAgICAgICB7eyAnRlJPTlRFTkQuU1RPUkUuUkVRVUlSRUQnIHwgdHJhbnNsYXRlIH19XG4gICAgICAgICAgPC9nbHh5LWVycm9yPlxuICAgICAgICA8L2dseHktZm9ybS1maWVsZD5cbiAgICAgIDwvZGl2PlxuICAgICAgPGRpdiBjbGFzcz1cInByaW50XCI+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJsYWJlbFwiPnt7IGZpZWxkLmxhYmVsIHwgdHJhbnNsYXRlIH19OjwvZGl2PlxuICAgICAgICA8ZGl2IGNsYXNzPVwiYW5zd2VyXCI+e3sgY2hlY2tib3hBbnN3ZXIoKSB9fTwvZGl2PlxuICAgICAgPC9kaXY+XG4gICAgPC9uZy1jb250YWluZXI+XG5cbiAgICA8bmctY29udGFpbmVyICpuZ1N3aXRjaENhc2U9XCIndGV4dGFyZWEnXCI+XG4gICAgICA8c3BhbiBjbGFzcz1cImRpc3BsYXlcIj5cbiAgICAgICAgPGdseHktZm9ybS1maWVsZD5cbiAgICAgICAgICA8Z2x4eS1sYWJlbD5cbiAgICAgICAgICAgIHt7IGZpZWxkLmxhYmVsIHwgdHJhbnNsYXRlIH19e3sgZmllbGQucmVxdWlyZWQgPyAnIConIDogJycgfX1cbiAgICAgICAgICA8L2dseHktbGFiZWw+XG4gICAgICAgICAgPHRleHRhcmVhXG4gICAgICAgICAgICBtYXRJbnB1dFxuICAgICAgICAgICAgW2Zvcm1Db250cm9sTmFtZV09XCJmaWVsZC5pZFwiXG4gICAgICAgICAgICBbaWRdPVwiZmllbGQuaWRcIlxuICAgICAgICAgICAgY2RrVGV4dGFyZWFBdXRvc2l6ZVxuICAgICAgICAgID48L3RleHRhcmVhPlxuICAgICAgICAgIDxnbHh5LWhpbnQgcG9zaXRpb249XCJiZWxvd1wiICpuZ0lmPVwiZmllbGQuZGVzY3JpcHRpb25cIj5cbiAgICAgICAgICAgIHt7IGZpZWxkLmRlc2NyaXB0aW9uIH19XG4gICAgICAgICAgPC9nbHh5LWhpbnQ+XG4gICAgICAgIDwvZ2x4eS1mb3JtLWZpZWxkPlxuICAgICAgPC9zcGFuPlxuICAgICAgPGRpdiBjbGFzcz1cInByaW50XCI+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJsYWJlbFwiPnt7IGZpZWxkLmxhYmVsIHwgdHJhbnNsYXRlIH19OjwvZGl2PlxuICAgICAgICA8ZGl2IGNsYXNzPVwiYW5zd2VyXCI+e3sgZ2V0VmFsdWUoKSB9fTwvZGl2PlxuICAgICAgPC9kaXY+XG4gICAgPC9uZy1jb250YWluZXI+XG5cbiAgICA8bmctY29udGFpbmVyICpuZ1N3aXRjaENhc2U9XCInZmlsZSdcIj5cbiAgICAgIDxzcGFuIGNsYXNzPVwiZGlzcGxheVwiPlxuICAgICAgICA8Z2x4eS1mb3JtLWZpZWxkPlxuICAgICAgICAgIDxnbHh5LWxhYmVsPlxuICAgICAgICAgICAge3sgZmllbGQubGFiZWwgfCB0cmFuc2xhdGUgfX17eyBmaWVsZC5yZXF1aXJlZCA/ICcgKicgOiAnJyB9fVxuICAgICAgICAgIDwvZ2x4eS1sYWJlbD5cbiAgICAgICAgICA8Z2x4eS1oaW50IHBvc2l0aW9uPVwiYmVsb3dcIiAqbmdJZj1cImZpZWxkLmRlc2NyaXB0aW9uXCI+XG4gICAgICAgICAgICB7eyBmaWVsZC5kZXNjcmlwdGlvbiB9fVxuICAgICAgICAgIDwvZ2x4eS1oaW50PlxuICAgICAgICAgIDxuZy1jb250YWluZXIgKm5nSWY9XCIhZmllbGQuZGlzYWJsZWRcIj5cbiAgICAgICAgICAgIDxnbHh5LXVwbG9hZGVyXG4gICAgICAgICAgICAgICNnbHh5VXBsb2FkZXJcbiAgICAgICAgICAgICAgW3VwbG9hZFVybF09XCJmaWVsZC51cGxvYWRVcmxcIlxuICAgICAgICAgICAgICBbbWF4RmlsZXNdPVwiZmllbGQubnVtRmlsZXNcIlxuICAgICAgICAgICAgICAoZmlsZVVwbG9hZGVkKT1cIm9uVXBsb2FkKCRldmVudClcIlxuICAgICAgICAgICAgPjwvZ2x4eS11cGxvYWRlcj5cbiAgICAgICAgICAgIDxnbHh5LXVwbG9hZGVyLWxpc3RcbiAgICAgICAgICAgICAgW2ZpbGVzXT1cInVwbG9hZGVkRmlsZXMoKSB8fCBbXVwiXG4gICAgICAgICAgICAgIChmaWxlRGVsZXRlZCk9XCJkZWxldGVGaWxlKCRldmVudClcIlxuICAgICAgICAgICAgPjwvZ2x4eS11cGxvYWRlci1saXN0PlxuICAgICAgICAgIDwvbmctY29udGFpbmVyPlxuICAgICAgICAgIDxuZy1jb250YWluZXIgKm5nSWY9XCJmaWVsZC5kaXNhYmxlZFwiPlxuICAgICAgICAgICAgPG5nLWNvbnRhaW5lciAqbmdJZj1cIiF1cGxvYWRlZEZpbGVzKCkubGVuZ3RoXCI+Jm1kYXNoOzwvbmctY29udGFpbmVyPlxuICAgICAgICAgICAgPG5nLWNvbnRhaW5lciAqbmdJZj1cInVwbG9hZGVkRmlsZXMoKS5sZW5ndGhcIj5cbiAgICAgICAgICAgICAgPHVsIGNsYXNzPVwiZmlsZS1zdGF0aWMtbGlzdFwiPlxuICAgICAgICAgICAgICAgIDxsaSAqbmdGb3I9XCJsZXQgZmlsZSBvZiB1cGxvYWRlZEZpbGVzKClcIj5cbiAgICAgICAgICAgICAgICAgIDxhIGhyZWY9XCJ7eyBmaWxlLnVybCB9fVwiIHRhcmdldD1cIl9ibGFua1wiPnt7IGZpbGUubmFtZSB9fTwvYT5cbiAgICAgICAgICAgICAgICA8L2xpPlxuICAgICAgICAgICAgICA8L3VsPlxuICAgICAgICAgICAgPC9uZy1jb250YWluZXI+XG4gICAgICAgICAgPC9uZy1jb250YWluZXI+XG4gICAgICAgIDwvZ2x4eS1mb3JtLWZpZWxkPlxuICAgICAgPC9zcGFuPlxuICAgICAgPGRpdiBjbGFzcz1cInByaW50XCI+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJsYWJlbFwiPnt7IGZpZWxkLmxhYmVsIHwgdHJhbnNsYXRlIH19OjwvZGl2PlxuICAgICAgICA8ZGl2IGNsYXNzPVwiYW5zd2VyXCI+e3sgZmlsZVVwbG9hZEFuc3dlcigpIH19PC9kaXY+XG4gICAgICA8L2Rpdj5cbiAgICA8L25nLWNvbnRhaW5lcj5cblxuICAgIDxuZy1jb250YWluZXIgKm5nU3dpdGNoQ2FzZT1cIid2YmN1c2VyJ1wiPlxuICAgICAgPGRpdiBjbGFzcz1cImRpc3BsYXlcIj5cbiAgICAgICAgPGdseHktZm9ybS1maWVsZD5cbiAgICAgICAgICA8Z2x4eS1sYWJlbD5cbiAgICAgICAgICAgIHt7IGZpZWxkLmxhYmVsIHwgdHJhbnNsYXRlIH19e3sgZmllbGQucmVxdWlyZWQgPyAnIConIDogJycgfX1cbiAgICAgICAgICA8L2dseHktbGFiZWw+XG4gICAgICAgICAgPG1hdC1zZWxlY3QgbWF0SW5wdXQgW2Zvcm1Db250cm9sTmFtZV09XCJmaWVsZC5pZFwiIFtpZF09XCJmaWVsZC5pZFwiPlxuICAgICAgICAgICAgPG1hdC1vcHRpb25cbiAgICAgICAgICAgICAgKm5nRm9yPVwibGV0IG9wdGlvbiBvZiBmaWVsZC5vcHRpb25zXCJcbiAgICAgICAgICAgICAgW3ZhbHVlXT1cIm9wdGlvbi52YWx1ZVwiXG4gICAgICAgICAgICAgIFtkaXNhYmxlZF09XCJvcHRpb24uZGlzYWJsZWRcIlxuICAgICAgICAgICAgPlxuICAgICAgICAgICAgICB7eyBvcHRpb24ubGFiZWwgfCB0cmFuc2xhdGUgfX1cbiAgICAgICAgICAgIDwvbWF0LW9wdGlvbj5cbiAgICAgICAgICA8L21hdC1zZWxlY3Q+XG4gICAgICAgICAgPGdseHktaGludCBwb3NpdGlvbj1cImJlbG93XCIgKm5nSWY9XCJmaWVsZC5kZXNjcmlwdGlvblwiPlxuICAgICAgICAgICAge3sgZmllbGQuZGVzY3JpcHRpb24gfX1cbiAgICAgICAgICA8L2dseHktaGludD5cbiAgICAgICAgPC9nbHh5LWZvcm0tZmllbGQ+XG4gICAgICA8L2Rpdj5cbiAgICAgIDxkaXYgY2xhc3M9XCJwcmludFwiPlxuICAgICAgICA8ZGl2IGNsYXNzPVwibGFiZWxcIj57eyBmaWVsZC5sYWJlbCB8IHRyYW5zbGF0ZSB9fTo8L2Rpdj5cbiAgICAgICAgPGRpdiBjbGFzcz1cImFuc3dlclwiPnt7IGRyb3Bkb3duQW5zd2VyKCkgfX08L2Rpdj5cbiAgICAgIDwvZGl2PlxuICAgIDwvbmctY29udGFpbmVyPlxuICA8L25nLWNvbnRhaW5lcj5cbjwvbmctY29udGFpbmVyPlxuIl19