UNPKG

@spartacus/cart

Version:

`@spartacus/cart` is a package that you can include in your application, which allows you to use various cart features.

196 lines 54.3 kB
import { ChangeDetectionStrategy, Component, HostListener, } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
import { DeleteSavedCartEvent, DeleteSavedCartFailEvent, DeleteSavedCartSuccessEvent, SavedCartFormType, } from '@spartacus/cart/saved-cart/root';
import { GlobalMessageType, } from '@spartacus/core';
import { ICON_TYPE, } from '@spartacus/storefront';
import { combineLatest, merge, Subscription } from 'rxjs';
import { map, mapTo, take } from 'rxjs/operators';
import * as i0 from "@angular/core";
import * as i1 from "@spartacus/storefront";
import * as i2 from "@spartacus/cart/saved-cart/root";
import * as i3 from "@spartacus/core";
import * as i4 from "@angular/common";
import * as i5 from "@angular/forms";
export class SavedCartFormDialogComponent {
    constructor(launchDialogService, el, savedCartService, eventService, routingService, globalMessageService) {
        this.launchDialogService = launchDialogService;
        this.el = el;
        this.savedCartService = savedCartService;
        this.eventService = eventService;
        this.routingService = routingService;
        this.globalMessageService = globalMessageService;
        this.subscription = new Subscription();
        this.savedCartFormType = SavedCartFormType;
        this.iconTypes = ICON_TYPE;
        this.descriptionMaxLength = 250;
        this.nameMaxLength = 50;
        this.isCloneSavedCart = false;
        this.focusConfig = {
            trap: true,
            block: true,
            autofocus: 'button',
            focusOnEscape: true,
        };
    }
    get descriptionsCharacterLeft() {
        var _a, _b;
        return (this.descriptionMaxLength -
            (((_b = (_a = this.form.get('description')) === null || _a === void 0 ? void 0 : _a.value) === null || _b === void 0 ? void 0 : _b.length) || 0));
    }
    handleClick(event) {
        // Close on click outside the dialog window
        if (event.target.tagName === this.el.nativeElement.tagName) {
            this.close('Cross click');
        }
    }
    ngOnInit() {
        this.resetSavedCartStates();
        this.isLoading$ = this.savedCartService.getSaveCartProcessLoading();
        this.isDisableDeleteButton$ = merge(this.eventService.get(DeleteSavedCartEvent).pipe(take(1), mapTo(true)), this.eventService
            .get(DeleteSavedCartFailEvent)
            .pipe(take(1), mapTo(false)));
        this.isDisableRestoreButton$ = combineLatest([
            this.savedCartService.getCloneSavedCartProcessLoading(),
            this.savedCartService.getRestoreSavedCartProcessLoading(),
        ]).pipe(map(([isCloneLoading, isRestoreLoading]) => isCloneLoading || isRestoreLoading));
        this.subscription.add(this.launchDialogService.data$.subscribe((data) => {
            this.cart = data.cart;
            this.layoutOption = data.layoutOption;
            this.build(this.cart);
        }));
        this.subscription.add(this.savedCartService
            .getSaveCartProcessSuccess()
            .subscribe((success) => this.onComplete(success)));
        this.subscription.add(this.eventService
            .get(DeleteSavedCartSuccessEvent)
            .pipe(take(1), mapTo(true))
            .subscribe((success) => this.onComplete(success)));
        this.subscription.add(this.savedCartService
            .getRestoreSavedCartProcessSuccess()
            .subscribe((success) => this.onComplete(success)));
    }
    saveOrEditCart(cartId) {
        var _a, _b;
        const name = (_a = this.form.get('name')) === null || _a === void 0 ? void 0 : _a.value;
        // TODO(#12660): Remove default value once backend is updated
        const description = ((_b = this.form.get('description')) === null || _b === void 0 ? void 0 : _b.value) || '-';
        switch (this.layoutOption) {
            case SavedCartFormType.SAVE: {
                this.savedCartService.saveCart({
                    cartId,
                    saveCartName: name,
                    saveCartDescription: description,
                });
                break;
            }
            case SavedCartFormType.EDIT: {
                this.savedCartService.editSavedCart({
                    cartId,
                    saveCartName: name,
                    saveCartDescription: description,
                });
                break;
            }
        }
    }
    deleteCart(cartId) {
        this.savedCartService.deleteSavedCart(cartId);
    }
    restoreSavedCart(cartId) {
        var _a;
        if (this.isCloneSavedCart) {
            this.savedCartService.cloneSavedCart(cartId, (_a = this.form.get('cloneName')) === null || _a === void 0 ? void 0 : _a.value);
        }
        else {
            this.savedCartService.restoreSavedCart(cartId);
        }
    }
    close(reason) {
        this.launchDialogService.closeDialog(reason);
    }
    onComplete(success) {
        var _a, _b, _c, _d;
        if (success) {
            switch (this.layoutOption) {
                case SavedCartFormType.DELETE: {
                    this.routingService.go({ cxRoute: 'savedCarts' });
                    this.globalMessageService.add({
                        key: 'savedCartDialog.deleteCartSuccess',
                    }, GlobalMessageType.MSG_TYPE_CONFIRMATION);
                    this.close('Successfully deleted a saved cart');
                    break;
                }
                case SavedCartFormType.SAVE: {
                    this.close('Successfully saved cart');
                    this.savedCartService.clearSaveCart();
                    this.globalMessageService.add({
                        key: 'savedCartCartPage.messages.cartSaved',
                        params: {
                            cartName: ((_a = this.form.get('name')) === null || _a === void 0 ? void 0 : _a.value) || ((_b = this.cart) === null || _b === void 0 ? void 0 : _b.code),
                        },
                    }, GlobalMessageType.MSG_TYPE_CONFIRMATION);
                    break;
                }
                case SavedCartFormType.EDIT: {
                    this.close('Successfully edited saved cart');
                    this.savedCartService.clearSaveCart();
                    this.globalMessageService.add({
                        key: 'savedCartDialog.editCartSuccess',
                        params: {
                            cartName: ((_c = this.form.get('name')) === null || _c === void 0 ? void 0 : _c.value) || ((_d = this.cart) === null || _d === void 0 ? void 0 : _d.code),
                        },
                    }, GlobalMessageType.MSG_TYPE_CONFIRMATION);
                    break;
                }
                case SavedCartFormType.RESTORE: {
                    this.close('Successfully restored saved cart');
                    this.routingService.go({ cxRoute: 'savedCarts' });
                    this.resetSavedCartStates();
                    break;
                }
            }
        }
    }
    toggleIsCloneSavedCart() {
        return (this.isCloneSavedCart = !this.isCloneSavedCart);
    }
    build(cart) {
        const form = new FormGroup({});
        form.setControl('name', new FormControl('', [
            Validators.required,
            Validators.maxLength(this.nameMaxLength),
        ]));
        form.setControl('description', new FormControl('', [Validators.maxLength(this.descriptionMaxLength)]));
        form.setControl('isCloneSavedCart', new FormControl(''));
        form.setControl('cloneName', new FormControl(''));
        this.form = form;
        this.patchData(cart);
    }
    patchData(item) {
        this.form.patchValue(Object.assign({}, item));
    }
    resetSavedCartStates() {
        this.savedCartService.clearCloneSavedCart();
        this.savedCartService.clearSaveCart();
        this.savedCartService.clearRestoreSavedCart();
    }
    ngOnDestroy() {
        var _a;
        (_a = this.subscription) === null || _a === void 0 ? void 0 : _a.unsubscribe();
        this.close('close dialog');
    }
}
SavedCartFormDialogComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.0.5", ngImport: i0, type: SavedCartFormDialogComponent, deps: [{ token: i1.LaunchDialogService }, { token: i0.ElementRef }, { token: i2.SavedCartFacade }, { token: i3.EventService }, { token: i3.RoutingService }, { token: i3.GlobalMessageService }], target: i0.ɵɵFactoryTarget.Component });
SavedCartFormDialogComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.0.5", type: SavedCartFormDialogComponent, selector: "cx-saved-cart-form-dialog", host: { listeners: { "click": "handleClick($event)" } }, ngImport: i0, template: "<ng-container *ngIf=\"cart\">\n  <div\n    [cxFocus]=\"focusConfig\"\n    (esc)=\"close('Escape clicked')\"\n    class=\"cx-saved-cart-form-dialog\"\n  >\n    <form [formGroup]=\"form\" class=\"cx-saved-cart-form-container\">\n      <!-- Modal Header -->\n      <div class=\"modal-header cx-saved-cart-form-header\">\n        <ng-container [ngSwitch]=\"layoutOption\">\n          <div class=\"cx-saved-cart-form-title modal-title\">\n            <ng-container *ngSwitchCase=\"savedCartFormType.EDIT\">\n              {{ 'savedCartDialog.editSavedCart' | cxTranslate }}\n            </ng-container>\n            <ng-container *ngSwitchCase=\"savedCartFormType.DELETE\">\n              {{ 'savedCartDialog.deleteSavedCart' | cxTranslate }}\n            </ng-container>\n            <ng-container *ngSwitchCase=\"savedCartFormType.SAVE\">\n              {{ 'savedCartDialog.saveForLater' | cxTranslate }}\n            </ng-container>\n            <ng-container *ngSwitchCase=\"savedCartFormType.RESTORE\">\n              {{ 'savedCartDialog.restoreSavedCart' | cxTranslate }}\n            </ng-container>\n          </div>\n        </ng-container>\n\n        <button\n          (click)=\"close('Close Save Cart Dialog')\"\n          [disabled]=\"isLoading$ | async\"\n          [attr.aria-label]=\"'common.close' | cxTranslate\"\n          class=\"cx-saved-cart-form-close close\"\n          type=\"button\"\n        >\n          <span aria-hidden=\"true\">\n            <cx-icon [type]=\"iconTypes.CLOSE\"></cx-icon>\n          </span>\n        </button>\n      </div>\n\n      <!-- Modal Body -->\n      <div class=\"cx-saved-cart-form-body\">\n        <!-- start DELETE and RESTORE form -->\n        <ng-container\n          *ngIf=\"\n            layoutOption === savedCartFormType.DELETE ||\n              layoutOption === savedCartFormType.RESTORE;\n            else saveAndEditCart\n          \"\n        >\n          <p class=\"cx-saved-cart-form-subtitle\">\n            {{\n              (layoutOption === savedCartFormType.DELETE\n                ? 'savedCartDialog.followingCartDelete'\n                : 'savedCartDialog.followingCartRestore'\n              ) | cxTranslate\n            }}\n          </p>\n\n          <div class=\"cx-saved-cart-form-row\">\n            <div class=\"cx-saved-cart-values-container\">\n              <div class=\"cx-saved-cart-label\">\n                {{ 'savedCartDialog.name' | cxTranslate }}\n              </div>\n              <div class=\"cx-saved-cart-value\">\n                {{ cart?.name }}\n              </div>\n            </div>\n\n            <div class=\"cx-saved-cart-values-container\">\n              <div class=\"cx-saved-cart-label\">\n                {{ 'savedCartDialog.id' | cxTranslate }}\n              </div>\n              <div class=\"cx-saved-cart-value\">\n                {{ cart?.code }}\n              </div>\n            </div>\n\n            <div class=\"cx-saved-cart-values-container\">\n              <div class=\"cx-saved-cart-label\">\n                {{ 'savedCartDialog.description' | cxTranslate }}\n              </div>\n              <div class=\"cx-saved-cart-value\">\n                {{ cart?.description }}\n              </div>\n            </div>\n\n            <div class=\"cx-saved-cart-values-container\">\n              <div class=\"cx-saved-cart-label\">\n                {{ 'savedCartDialog.quantity' | cxTranslate }}\n              </div>\n              <div class=\"cx-saved-cart-value\">\n                {{ cart?.totalItems }}\n              </div>\n            </div>\n\n            <div class=\"cx-saved-cart-values-container\">\n              <div class=\"cx-saved-cart-label\">\n                {{ 'savedCartDialog.total' | cxTranslate }}\n              </div>\n              <div class=\"cx-saved-cart-value\">\n                {{ cart?.totalPriceWithTax?.formattedValue }}\n              </div>\n            </div>\n          </div>\n\n          <ng-container *ngIf=\"layoutOption === savedCartFormType.RESTORE\">\n            <div class=\"cx-copy-saved-cart-row form-check\">\n              <input\n                id=\"cx-copy-saved-cart\"\n                type=\"checkbox\"\n                class=\"cx-copy-saved-cart-input\"\n                [checked]=\"isCloneSavedCart\"\n                (change)=\"toggleIsCloneSavedCart()\"\n              />\n              <label\n                for=\"cx-copy-saved-cart\"\n                class=\"cx-copy-saved-cart-label\"\n                >{{ 'savedCartDialog.keepCopySavedCart' | cxTranslate }}</label\n              >\n            </div>\n\n            <div *ngIf=\"isCloneSavedCart\" class=\"cx-copy-saved-cart-row\">\n              <label>\n                <span class=\"label-content\">\n                  {{ 'savedCartDialog.nameOfCloneCart' | cxTranslate }}\n                </span>\n\n                <input\n                  [maxLength]=\"nameMaxLength\"\n                  class=\"form-control\"\n                  formControlName=\"cloneName\"\n                  type=\"text\"\n                  placeholder=\"{{\n                    'savedCartDialog.defaultCloneCartName'\n                      | cxTranslate: { name: form.get('name')?.value }\n                  }}\"\n                />\n              </label>\n            </div>\n          </ng-container>\n\n          <div class=\"cx-saved-cart-form-footer\">\n            <button\n              (click)=\"close('Close Save Cart Dialog')\"\n              [attr.aria-label]=\"'common.close' | cxTranslate\"\n              class=\"mr-2 btn btn-action\"\n              type=\"button\"\n            >\n              {{ 'savedCartDialog.cancel' | cxTranslate }}\n            </button>\n\n            <ng-container\n              *ngIf=\"\n                layoutOption === savedCartFormType.DELETE;\n                else isRestoreSavedCart\n              \"\n            >\n              <button\n                *ngIf=\"cart.code\"\n                (click)=\"deleteCart(cart.code)\"\n                [attr.aria-label]=\"'common.delete' | cxTranslate\"\n                [disabled]=\"isDisableDeleteButton$ | async\"\n                class=\"ml-2 btn btn-primary\"\n                type=\"button\"\n              >\n                {{ 'savedCartDialog.delete' | cxTranslate }}\n              </button>\n            </ng-container>\n\n            <ng-template #isRestoreSavedCart>\n              <button\n                *ngIf=\"cart.code\"\n                (click)=\"restoreSavedCart(cart.code)\"\n                [disabled]=\"isDisableRestoreButton$ | async\"\n                [attr.aria-label]=\"'common.restore' | cxTranslate\"\n                class=\"ml-2 btn btn-primary\"\n                type=\"button\"\n              >\n                {{ 'savedCartDialog.restore' | cxTranslate }}\n              </button>\n            </ng-template>\n          </div>\n        </ng-container>\n        <!-- end DELETE form -->\n\n        <!-- start SAVE and EDIT form -->\n        <ng-template #saveAndEditCart>\n          <ng-container *ngIf=\"layoutOption === savedCartFormType.SAVE\">\n            <p class=\"cx-saved-cart-form-subtitle\">\n              {{ 'savedCartDialog.itemsSavedForLater' | cxTranslate }}\n            </p>\n          </ng-container>\n\n          <div class=\"cx-saved-cart-form-row\">\n            <ng-container>\n              <label>\n                <span class=\"cx-saved-carts-label label-content\">{{\n                  'savedCartDialog.savedCartName' | cxTranslate\n                }}</span>\n                <input\n                  aria-required=\"true\"\n                  [maxLength]=\"nameMaxLength\"\n                  class=\"form-control\"\n                  formControlName=\"name\"\n                  required\n                  type=\"text\"\n                />\n                <cx-form-errors\n                  aria-live=\"assertive\"\n                  aria-atomic=\"true\"\n                  [control]=\"form.get('name')\"\n                ></cx-form-errors>\n              </label>\n            </ng-container>\n          </div>\n\n          <div class=\"cx-saved-cart-form-row\">\n            <label>\n              <span class=\"cx-saved-carts-label label-content\"\n                >{{ 'savedCartDialog.savedCartDescription' | cxTranslate }}\n                <span class=\"cx-saved-carts-label-optional\">\n                  ({{ 'savedCartDialog.optional' | cxTranslate }})\n                </span></span\n              >\n              <textarea\n                [maxLength]=\"descriptionMaxLength\"\n                class=\"form-control\"\n                formControlName=\"description\"\n                rows=\"5\"\n              ></textarea>\n              <cx-form-errors\n                aria-live=\"assertive\"\n                aria-atomic=\"true\"\n                [control]=\"form.get('description')\"\n              ></cx-form-errors>\n\n              <p class=\"cx-saved-carts-input-hint\">\n                {{\n                  'savedCartDialog.charactersLeft'\n                    | cxTranslate: { count: descriptionsCharacterLeft }\n                }}\n              </p>\n            </label>\n          </div>\n          <div class=\"cx-saved-cart-form-footer\">\n            <button\n              (click)=\"close('Close Save Cart Dialog')\"\n              [attr.aria-label]=\"'common.close' | cxTranslate\"\n              [disabled]=\"isLoading$ | async\"\n              class=\"btn btn-action\"\n              type=\"button\"\n            >\n              {{ 'savedCartDialog.cancel' | cxTranslate }}\n            </button>\n            <button\n              (click)=\"saveOrEditCart(cart?.code)\"\n              [attr.aria-label]=\"'common.save' | cxTranslate\"\n              [disabled]=\"form.invalid || (isLoading$ | async)\"\n              class=\"btn btn-primary\"\n              type=\"button\"\n            >\n              {{ 'savedCartDialog.save' | cxTranslate }}\n            </button>\n          </div>\n        </ng-template>\n        <!-- end SAVE and EDIT form -->\n      </div>\n    </form>\n  </div>\n</ng-container>\n", components: [{ type: i1.IconComponent, selector: "cx-icon,[cxIcon]", inputs: ["cxIcon", "type"] }, { type: i1.FormErrorsComponent, selector: "cx-form-errors", inputs: ["prefix", "translationParams", "control"] }], directives: [{ type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i1.FocusDirective, selector: "[cxFocus]", inputs: ["cxFocus"] }, { type: i5.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { type: i5.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i5.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i4.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { type: i4.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { type: i5.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: i5.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i5.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i5.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }], pipes: { "cxTranslate": i3.TranslatePipe, "async": i4.AsyncPipe }, changeDetection: i0.ChangeDetectionStrategy.OnPush });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.0.5", ngImport: i0, type: SavedCartFormDialogComponent, decorators: [{
            type: Component,
            args: [{
                    selector: 'cx-saved-cart-form-dialog',
                    templateUrl: './saved-cart-form-dialog.component.html',
                    changeDetection: ChangeDetectionStrategy.OnPush,
                }]
        }], ctorParameters: function () { return [{ type: i1.LaunchDialogService }, { type: i0.ElementRef }, { type: i2.SavedCartFacade }, { type: i3.EventService }, { type: i3.RoutingService }, { type: i3.GlobalMessageService }]; }, propDecorators: { handleClick: [{
                type: HostListener,
                args: ['click', ['$event']]
            }] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2F2ZWQtY2FydC1mb3JtLWRpYWxvZy5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9mZWF0dXJlLWxpYnMvY2FydC9zYXZlZC1jYXJ0L2NvbXBvbmVudHMvc2F2ZWQtY2FydC1mb3JtLWRpYWxvZy9zYXZlZC1jYXJ0LWZvcm0tZGlhbG9nLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uLy4uL2ZlYXR1cmUtbGlicy9jYXJ0L3NhdmVkLWNhcnQvY29tcG9uZW50cy9zYXZlZC1jYXJ0LWZvcm0tZGlhbG9nL3NhdmVkLWNhcnQtZm9ybS1kaWFsb2cuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUNMLHVCQUF1QixFQUN2QixTQUFTLEVBRVQsWUFBWSxHQUdiLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBRSxXQUFXLEVBQUUsU0FBUyxFQUFFLFVBQVUsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQ3BFLE9BQU8sRUFDTCxvQkFBb0IsRUFDcEIsd0JBQXdCLEVBQ3hCLDJCQUEyQixFQUUzQixpQkFBaUIsR0FDbEIsTUFBTSxpQ0FBaUMsQ0FBQztBQUN6QyxPQUFPLEVBSUwsaUJBQWlCLEdBRWxCLE1BQU0saUJBQWlCLENBQUM7QUFDekIsT0FBTyxFQUVMLFNBQVMsR0FFVixNQUFNLHVCQUF1QixDQUFDO0FBQy9CLE9BQU8sRUFBRSxhQUFhLEVBQUUsS0FBSyxFQUFjLFlBQVksRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUN0RSxPQUFPLEVBQUUsR0FBRyxFQUFFLEtBQUssRUFBRSxJQUFJLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQzs7Ozs7OztBQVlsRCxNQUFNLE9BQU8sNEJBQTRCO0lBc0N2QyxZQUNZLG1CQUF3QyxFQUN4QyxFQUFjLEVBQ2QsZ0JBQWlDLEVBQ2pDLFlBQTBCLEVBQzFCLGNBQThCLEVBQzlCLG9CQUEwQztRQUwxQyx3QkFBbUIsR0FBbkIs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QyxtQkFBbUIsRUFBRSxDQUFDO1FBQzVDLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxhQUFhLEVBQUUsQ0FBQztRQUN0QyxJQUFJLENBQUMsZ0JBQWdCLENBQUMscUJBQXFCLEVBQUUsQ0FBQztJQUNoRCxDQUFDO0lBRUQsV0FBVzs7UUFDVCxNQUFBLElBQUksQ0FBQyxZQUFZLDBDQUFFLFdBQVcsRUFBRSxDQUFDO1FBQ2pDLElBQUksQ0FBQyxLQUFLLENBQUMsY0FBYyxDQUFDLENBQUM7SUFDN0IsQ0FBQzs7eUhBclBVLDRCQUE0Qjs2R0FBNUIsNEJBQTRCLDBIQ3pDekMsKzRUQThRQTsyRkRyT2EsNEJBQTRCO2tCQUx4QyxTQUFTO21CQUFDO29CQUNULFFBQVEsRUFBRSwyQkFBMkI7b0JBQ3JDLFdBQVcsRUFBRSx5Q0FBeUM7b0JBQ3RELGVBQWUsRUFBRSx1QkFBdUIsQ0FBQyxNQUFNO2lCQUNoRDs0UEFnQ0MsV0FBVztzQkFEVixZQUFZO3VCQUFDLE9BQU8sRUFBRSxDQUFDLFFBQVEsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIENoYW5nZURldGVjdGlvblN0cmF0ZWd5LFxuICBDb21wb25lbnQsXG4gIEVsZW1lbnRSZWYsXG4gIEhvc3RMaXN0ZW5lcixcbiAgT25EZXN0cm95LFxuICBPbkluaXQsXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgRm9ybUNvbnRyb2wsIEZvcm1Hcm91cCwgVmFsaWRhdG9ycyB9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcbmltcG9ydCB7XG4gIERlbGV0ZVNhdmVkQ2FydEV2ZW50LFxuICBEZWxldGVTYXZlZENhcnRGYWlsRXZlbnQsXG4gIERlbGV0ZVNhdmVkQ2FydFN1Y2Nlc3NFdmVudCxcbiAgU2F2ZWRDYXJ0RmFjYWRlLFxuICBTYXZlZENhcnRGb3JtVHlwZSxcbn0gZnJvbSAnQHNwYXJ0YWN1cy9jYXJ0L3NhdmVkLWNhcnQvcm9vdCc7XG5pbXBvcnQge1xuICBDYXJ0LFxuICBFdmVudFNlcnZpY2UsXG4gIEdsb2JhbE1lc3NhZ2VTZXJ2aWNlLFxuICBHbG9iYWxNZXNzYWdlVHlwZSxcbiAgUm91dGluZ1NlcnZpY2UsXG59IGZyb20gJ0BzcGFydGFjdXMvY29yZSc7XG5pbXBvcnQge1xuICBGb2N1c0NvbmZpZyxcbiAgSUNPTl9UWVBFLFxuICBMYXVuY2hEaWFsb2dTZXJ2aWNlLFxufSBmcm9tICdAc3BhcnRhY3VzL3N0b3JlZnJvbnQnO1xuaW1wb3J0IHsgY29tYmluZUxhdGVzdCwgbWVyZ2UsIE9ic2VydmFibGUsIFN1YnNjcmlwdGlvbiB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgbWFwLCBtYXBUbywgdGFrZSB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcblxuZXhwb3J0IGludGVyZmFjZSBTYXZlZENhcnRGb3JtRGlhbG9nT3B0aW9ucyB7XG4gIGNhcnQ6IENhcnQ7XG4gIGxheW91dE9wdGlvbj86IHN0cmluZztcbn1cblxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnY3gtc2F2ZWQtY2FydC1mb3JtLWRpYWxvZycsXG4gIHRlbXBsYXRlVXJsOiAnLi9zYXZlZC1jYXJ0LWZvcm0tZGlhbG9nLmNvbXBvbmVudC5odG1sJyxcbiAgY2hhbmdlRGV0ZWN0aW9uOiBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneS5PblB1c2gsXG59KVxuZXhwb3J0IGNsYXNzIFNhdmVkQ2FydEZvcm1EaWFsb2dDb21wb25lbnQgaW1wbGVtZW50cyBPbkluaXQsIE9uRGVzdHJveSB7XG4gIHByaXZhdGUgc3Vic2NyaXB0aW9uID0gbmV3IFN1YnNjcmlwdGlvbigpO1xuICBzYXZlZENhcnRGb3JtVHlwZSA9IFNhdmVkQ2FydEZvcm1UeXBlO1xuICBmb3JtOiBGb3JtR3JvdXA7XG4gIGljb25UeXBlcyA9IElDT05fVFlQRTtcbiAgY2FydDogQ2FydDtcbiAgbGF5b3V0T3B0aW9uOiBzdHJpbmcgfCB1bmRlZmluZWQ7XG5cbiAgZGVzY3JpcHRpb25NYXhMZW5ndGg6IG51bWJlciA9IDI1MDtcbiAgbmFtZU1heExlbmd0aDogbnVtYmVyID0gNTA7XG4gIGlzQ2xvbmVTYXZlZENhcnQgPSBmYWxzZTtcblxuICBmb2N1c0NvbmZpZzogRm9jdXNDb25maWcgPSB7XG4gICAgdHJhcDogdHJ1ZSxcbiAgICBibG9jazogdHJ1ZSxcbiAgICBhdXRvZm9jdXM6ICdidXR0b24nLFxuICAgIGZvY3VzT25Fc2NhcGU6IHRydWUsXG4gIH07XG5cbiAgaXNMb2FkaW5nJDogT2JzZXJ2YWJsZTxib29sZWFuPjtcbiAgaXNEaXNhYmxlRGVsZXRlQnV0dG9uJDogT2JzZXJ2YWJsZTxib29sZWFuPjtcbiAgaXNEaXNhYmxlUmVzdG9yZUJ1dHRvbiQ6IE9ic2VydmFibGU8Ym9vbGVhbj47XG5cbiAgZ2V0IGRlc2NyaXB0aW9uc0NoYXJhY3RlckxlZnQoKTogbnVtYmVyIHtcbiAgICByZXR1cm4gKFxuICAgICAgdGhpcy5kZXNjcmlwdGlvbk1heExlbmd0aCAtXG4gICAgICAodGhpcy5mb3JtLmdldCgnZGVzY3JpcHRpb24nKT8udmFsdWU/Lmxlbmd0aCB8fCAwKVxuICAgICk7XG4gIH1cblxuICBASG9zdExpc3RlbmVyKCdjbGljaycsIFsnJGV2ZW50J10pXG4gIGhhbmRsZUNsaWNrKGV2ZW50OiBVSUV2ZW50KTogdm9pZCB7XG4gICAgLy8gQ2xvc2Ugb24gY2xpY2sgb3V0c2lkZSB0aGUgZGlhbG9nIHdpbmRvd1xuICAgIGlmICgoZXZlbnQudGFyZ2V0IGFzIGFueSkudGFnTmFtZSA9PT0gdGhpcy5lbC5uYXRpdmVFbGVtZW50LnRhZ05hbWUpIHtcbiAgICAgIHRoaXMuY2xvc2UoJ0Nyb3NzIGNsaWNrJyk7XG4gICAgfVxuICB9XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJvdGVjdGVkIGxhdW5jaERpYWxvZ1NlcnZpY2U6IExhdW5jaERpYWxvZ1NlcnZpY2UsXG4gICAgcHJvdGVjdGVkIGVsOiBFbGVtZW50UmVmLFxuICAgIHByb3RlY3RlZCBzYXZlZENhcnRTZXJ2aWNlOiBTYXZlZENhcnRGYWNhZGUsXG4gICAgcHJvdGVjdGVkIGV2ZW50U2VydmljZTogRXZlbnRTZXJ2aWNlLFxuICAgIHByb3RlY3RlZCByb3V0aW5nU2VydmljZTogUm91dGluZ1NlcnZpY2UsXG4gICAgcHJvdGVjdGVkIGdsb2JhbE1lc3NhZ2VTZXJ2aWNlOiBHbG9iYWxNZXNzYWdlU2VydmljZVxuICApIHt9XG5cbiAgbmdPbkluaXQoKTogdm9pZCB7XG4gICAgdGhpcy5yZXNldFNhdmVkQ2FydFN0YXRlcygpO1xuXG4gICAgdGhpcy5pc0xvYWRpbmckID0gdGhpcy5zYXZlZENhcnRTZXJ2aWNlLmdldFNhdmVDYXJ0UHJvY2Vzc0xvYWRpbmcoKTtcblxuICAgIHRoaXMuaXNEaXNhYmxlRGVsZXRlQnV0dG9uJCA9IG1lcmdlKFxuICAgICAgdGhpcy5ldmVudFNlcnZpY2UuZ2V0KERlbGV0ZVNhdmVkQ2FydEV2ZW50KS5waXBlKHRha2UoMSksIG1hcFRvKHRydWUpKSxcbiAgICAgIHRoaXMuZXZlbnRTZXJ2aWNlXG4gICAgICAgIC5nZXQoRGVsZXRlU2F2ZWRDYXJ0RmFpbEV2ZW50KVxuICAgICAgICAucGlwZSh0YWtlKDEpLCBtYXBUbyhmYWxzZSkpXG4gICAgKTtcblxuICAgIHRoaXMuaXNEaXNhYmxlUmVzdG9yZUJ1dHRvbiQgPSBjb21iaW5lTGF0ZXN0KFtcbiAgICAgIHRoaXMuc2F2ZWRDYXJ0U2VydmljZS5nZXRDbG9uZVNhdmVkQ2FydFByb2Nlc3NMb2FkaW5nKCksXG4gICAgICB0aGlzLnNhdmVkQ2FydFNlcnZpY2UuZ2V0UmVzdG9yZVNhdmVkQ2FydFByb2Nlc3NMb2FkaW5nKCksXG4gICAgXSkucGlwZShcbiAgICAgIG1hcChcbiAgICAgICAgKFtpc0Nsb25lTG9hZGluZywgaXNSZXN0b3JlTG9hZGluZ10pID0+XG4gICAgICAgICAgaXNDbG9uZUxvYWRpbmcgfHwgaXNSZXN0b3JlTG9hZGluZ1xuICAgICAgKVxuICAgICk7XG5cbiAgICB0aGlzLnN1YnNjcmlwdGlvbi5hZGQoXG4gICAgICB0aGlzLmxhdW5jaERpYWxvZ1NlcnZpY2UuZGF0YSQuc3Vic2NyaWJlKFxuICAgICAgICAoZGF0YTogU2F2ZWRDYXJ0Rm9ybURpYWxvZ09wdGlvbnMpID0+IHtcbiAgICAgICAgICB0aGlzLmNhcnQgPSBkYXRhLmNhcnQ7XG4gICAgICAgICAgdGhpcy5sYXlvdXRPcHRpb24gPSBkYXRhLmxheW91dE9wdGlvbjtcblxuICAgICAgICAgIHRoaXMuYnVpbGQodGhpcy5jYXJ0KTtcbiAgICAgICAgfVxuICAgICAgKVxuICAgICk7XG5cbiAgICB0aGlzLnN1YnNjcmlwdGlvbi5hZGQoXG4gICAgICB0aGlzLnNhdmVkQ2FydFNlcnZpY2VcbiAgICAgICAgLmdldFNhdmVDYXJ0UHJvY2Vzc1N1Y2Nlc3MoKVxuICAgICAgICAuc3Vic2NyaWJlKChzdWNjZXNzKSA9PiB0aGlzLm9uQ29tcGxldGUoc3VjY2VzcykpXG4gICAgKTtcblxuICAgIHRoaXMuc3Vic2NyaXB0aW9uLmFkZChcbiAgICAgIHRoaXMuZXZlbnRTZXJ2aWNlXG4gICAgICAgIC5nZXQoRGVsZXRlU2F2ZWRDYXJ0U3VjY2Vzc0V2ZW50KVxuICAgICAgICAucGlwZSh0YWtlKDEpLCBtYXBUbyh0cnVlKSlcbiAgICAgICAgLnN1YnNjcmliZSgoc3VjY2VzcykgPT4gdGhpcy5vbkNvbXBsZXRlKHN1Y2Nlc3MpKVxuICAgICk7XG5cbiAgICB0aGlzLnN1YnNjcmlwdGlvbi5hZGQoXG4gICAgICB0aGlzLnNhdmVkQ2FydFNlcnZpY2VcbiAgICAgICAgLmdldFJlc3RvcmVTYXZlZENhcnRQcm9jZXNzU3VjY2VzcygpXG4gICAgICAgIC5zdWJzY3JpYmUoKHN1Y2Nlc3MpID0+IHRoaXMub25Db21wbGV0ZShzdWNjZXNzKSlcbiAgICApO1xuICB9XG5cbiAgc2F2ZU9yRWRpdENhcnQoY2FydElkOiBzdHJpbmcpOiB2b2lkIHtcbiAgICBjb25zdCBuYW1lID0gdGhpcy5mb3JtLmdldCgnbmFtZScpPy52YWx1ZTtcbiAgICAvLyBUT0RPKCMxMjY2MCk6IFJlbW92ZSBkZWZhdWx0IHZhbHVlIG9uY2UgYmFja2VuZCBpcyB1cGRhdGVkXG4gICAgY29uc3QgZGVzY3JpcHRpb24gPSB0aGlzLmZvcm0uZ2V0KCdkZXNjcmlwdGlvbicpPy52YWx1ZSB8fCAnLSc7XG5cbiAgICBzd2l0Y2ggKHRoaXMubGF5b3V0T3B0aW9uKSB7XG4gICAgICBjYXNlIFNhdmVkQ2FydEZvcm1UeXBlLlNBVkU6IHtcbiAgICAgICAgdGhpcy5zYXZlZENhcnRTZXJ2aWNlLnNhdmVDYXJ0KHtcbiAgICAgICAgICBjYXJ0SWQsXG4gICAgICAgICAgc2F2ZUNhcnROYW1lOiBuYW1lLFxuICAgICAgICAgIHNhdmVDYXJ0RGVzY3JpcHRpb246IGRlc2NyaXB0aW9uLFxuICAgICAgICB9KTtcblxuICAgICAgICBicmVhaztcbiAgICAgIH1cblxuICAgICAgY2FzZSBTYXZlZENhcnRGb3JtVHlwZS5FRElUOiB7XG4gICAgICAgIHRoaXMuc2F2ZWRDYXJ0U2VydmljZS5lZGl0U2F2ZWRDYXJ0KHtcbiAgICAgICAgICBjYXJ0SWQsXG4gICAgICAgICAgc2F2ZUNhcnROYW1lOiBuYW1lLFxuICAgICAgICAgIHNhdmVDYXJ0RGVzY3JpcHRpb246IGRlc2NyaXB0aW9uLFxuICAgICAgICB9KTtcblxuICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBkZWxldGVDYXJ0KGNhcnRJZDogc3RyaW5nKTogdm9pZCB7XG4gICAgdGhpcy5zYXZlZENhcnRTZXJ2aWNlLmRlbGV0ZVNhdmVkQ2FydChjYXJ0SWQpO1xuICB9XG5cbiAgcmVzdG9yZVNhdmVkQ2FydChjYXJ0SWQ6IHN0cmluZyk6IHZvaWQge1xuICAgIGlmICh0aGlzLmlzQ2xvbmVTYXZlZENhcnQpIHtcbiAgICAgIHRoaXMuc2F2ZWRDYXJ0U2VydmljZS5jbG9uZVNhdmVkQ2FydChcbiAgICAgICAgY2FydElkLFxuICAgICAgICB0aGlzLmZvcm0uZ2V0KCdjbG9uZU5hbWUnKT8udmFsdWVcbiAgICAgICk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuc2F2ZWRDYXJ0U2VydmljZS5yZXN0b3JlU2F2ZWRDYXJ0KGNhcnRJZCk7XG4gICAgfVxuICB9XG5cbiAgY2xvc2UocmVhc29uOiBzdHJpbmcpOiB2b2lkIHtcbiAgICB0aGlzLmxhdW5jaERpYWxvZ1NlcnZpY2UuY2xvc2VEaWFsb2cocmVhc29uKTtcbiAgfVxuXG4gIG9uQ29tcGxldGUoc3VjY2VzczogYm9vbGVhbik6IHZvaWQge1xuICAgIGlmIChzdWNjZXNzKSB7XG4gICAgICBzd2l0Y2ggKHRoaXMubGF5b3V0T3B0aW9uKSB7XG4gICAgICAgIGNhc2UgU2F2ZWRDYXJ0Rm9ybVR5cGUuREVMRVRFOiB7XG4gICAgICAgICAgdGhpcy5yb3V0aW5nU2VydmljZS5nbyh7IGN4Um91dGU6ICdzYXZlZENhcnRzJyB9KTtcbiAgICAgICAgICB0aGlzLmdsb2JhbE1lc3NhZ2VTZXJ2aWNlLmFkZChcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAga2V5OiAnc2F2ZWRDYXJ0RGlhbG9nLmRlbGV0ZUNhcnRTdWNjZXNzJyxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBHbG9iYWxNZXNzYWdlVHlwZS5NU0dfVFlQRV9DT05GSVJNQVRJT05cbiAgICAgICAgICApO1xuICAgICAgICAgIHRoaXMuY2xvc2UoJ1N1Y2Nlc3NmdWxseSBkZWxldGVkIGEgc2F2ZWQgY2FydCcpO1xuXG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cblxuICAgICAgICBjYXNlIFNhdmVkQ2FydEZvcm1UeXBlLlNBVkU6IHtcbiAgICAgICAgICB0aGlzLmNsb3NlKCdTdWNjZXNzZnVsbHkgc2F2ZWQgY2FydCcpO1xuICAgICAgICAgIHRoaXMuc2F2ZWRDYXJ0U2VydmljZS5jbGVhclNhdmVDYXJ0KCk7XG5cbiAgICAgICAgICB0aGlzLmdsb2JhbE1lc3NhZ2VTZXJ2aWNlLmFkZChcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAga2V5OiAnc2F2ZWRDYXJ0Q2FydFBhZ2UubWVzc2FnZXMuY2FydFNhdmVkJyxcbiAgICAgICAgICAgICAgcGFyYW1zOiB7XG4gICAgICAgICAgICAgICAgY2FydE5hbWU6IHRoaXMuZm9ybS5nZXQoJ25hbWUnKT8udmFsdWUgfHwgdGhpcy5jYXJ0Py5jb2RlLFxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIEdsb2JhbE1lc3NhZ2VUeXBlLk1TR19UWVBFX0NPTkZJUk1BVElPTlxuICAgICAgICAgICk7XG5cbiAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuXG4gICAgICAgIGNhc2UgU2F2ZWRDYXJ0Rm9ybVR5cGUuRURJVDoge1xuICAgICAgICAgIHRoaXMuY2xvc2UoJ1N1Y2Nlc3NmdWxseSBlZGl0ZWQgc2F2ZWQgY2FydCcpO1xuICAgICAgICAgIHRoaXMuc2F2ZWRDYXJ0U2VydmljZS5jbGVhclNhdmVDYXJ0KCk7XG4gICAgICAgICAgdGhpcy5nbG9iYWxNZXNzYWdlU2VydmljZS5hZGQoXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgIGtleTogJ3NhdmVkQ2FydERpYWxvZy5lZGl0Q2FydFN1Y2Nlc3MnLFxuICAgICAgICAgICAgICBwYXJhbXM6IHtcbiAgICAgICAgICAgICAgICBjYXJ0TmFtZTogdGhpcy5mb3JtLmdldCgnbmFtZScpPy52YWx1ZSB8fCB0aGlzLmNhcnQ/LmNvZGUsXG4gICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB9LFxuXG4gICAgICAgICAgICBHbG9iYWxNZXNzYWdlVHlwZS5NU0dfVFlQRV9DT05GSVJNQVRJT05cbiAgICAgICAgICApO1xuXG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cblxuICAgICAgICBjYXNlIFNhdmVkQ2FydEZvcm1UeXBlLlJFU1RPUkU6IHtcbiAgICAgICAgICB0aGlzLmNsb3NlKCdTdWNjZXNzZnVsbHkgcmVzdG9yZWQgc2F2ZWQgY2FydCcpO1xuICAgICAgICAgIHRoaXMucm91dGluZ1NlcnZpY2UuZ28oeyBjeFJvdXRlOiAnc2F2ZWRDYXJ0cycgfSk7XG5cbiAgICAgICAgICB0aGlzLnJlc2V0U2F2ZWRDYXJ0U3RhdGVzKCk7XG5cbiAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHRvZ2dsZUlzQ2xvbmVTYXZlZENhcnQoKSB7XG4gICAgcmV0dXJuICh0aGlzLmlzQ2xvbmVTYXZlZENhcnQgPSAhdGhpcy5pc0Nsb25lU2F2ZWRDYXJ0KTtcbiAgfVxuXG4gIHByb3RlY3RlZCBidWlsZChjYXJ0PzogQ2FydCkge1xuICAgIGNvbnN0IGZvcm0gPSBuZXcgRm9ybUdyb3VwKHt9KTtcbiAgICBmb3JtLnNldENvbnRyb2woXG4gICAgICAnbmFtZScsXG4gICAgICBuZXcgRm9ybUNvbnRyb2woJycsIFtcbiAgICAgICAgVmFsaWRhdG9ycy5yZXF1aXJlZCxcbiAgICAgICAgVmFsaWRhdG9ycy5tYXhMZW5ndGgodGhpcy5uYW1lTWF4TGVuZ3RoKSxcbiAgICAgIF0pXG4gICAgKTtcbiAgICBmb3JtLnNldENvbnRyb2woXG4gICAgICAnZGVzY3JpcHRpb24nLFxuICAgICAgbmV3IEZvcm1Db250cm9sKCcnLCBbVmFsaWRhdG9ycy5tYXhMZW5ndGgodGhpcy5kZXNjcmlwdGlvbk1heExlbmd0aCldKVxuICAgICk7XG4gICAgZm9ybS5zZXRDb250cm9sKCdpc0Nsb25lU2F2ZWRDYXJ0JywgbmV3IEZvcm1Db250cm9sKCcnKSk7XG4gICAgZm9ybS5zZXRDb250cm9sKCdjbG9uZU5hbWUnLCBuZXcgRm9ybUNvbnRyb2woJycpKTtcbiAgICB0aGlzLmZvcm0gPSBmb3JtO1xuICAgIHRoaXMucGF0Y2hEYXRhKGNhcnQpO1xuICB9XG5cbiAgcHJvdGVjdGVkIHBhdGNoRGF0YShpdGVtPzogYW55KTogdm9pZCB7XG4gICAgdGhpcy5mb3JtLnBhdGNoVmFsdWUoeyAuLi5pdGVtIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSByZXNldFNhdmVkQ2FydFN0YXRlcygpOiB2b2lkIHtcbiAgICB0aGlzLnNhdmVkQ2FydFNlcnZpY2UuY2xlYXJDbG9uZVNhdmVkQ2FydCgpO1xuICAgIHRoaXMuc2F2ZWRDYXJ0U2VydmljZS5jbGVhclNhdmVDYXJ0KCk7XG4gICAgdGhpcy5zYXZlZENhcnRTZXJ2aWNlLmNsZWFyUmVzdG9yZVNhdmVkQ2FydCgpO1xuICB9XG5cbiAgbmdPbkRlc3Ryb3koKTogdm9pZCB7XG4gICAgdGhpcy5zdWJzY3JpcHRpb24/LnVuc3Vic2NyaWJlKCk7XG4gICAgdGhpcy5jbG9zZSgnY2xvc2UgZGlhbG9nJyk7XG4gIH1cbn1cbiIsIjxuZy1jb250YWluZXIgKm5nSWY9XCJjYXJ0XCI+XG4gIDxkaXZcbiAgICBbY3hGb2N1c109XCJmb2N1c0NvbmZpZ1wiXG4gICAgKGVzYyk9XCJjbG9zZSgnRXNjYXBlIGNsaWNrZWQnKVwiXG4gICAgY2xhc3M9XCJjeC1zYXZlZC1jYXJ0LWZvcm0tZGlhbG9nXCJcbiAgPlxuICAgIDxmb3JtIFtmb3JtR3JvdXBdPVwiZm9ybVwiIGNsYXNzPVwiY3gtc2F2ZWQtY2FydC1mb3JtLWNvbnRhaW5lclwiPlxuICAgICAgPCEtLSBNb2RhbCBIZWFkZXIgLS0+XG4gICAgICA8ZGl2IGNsYXNzPVwibW9kYWwtaGVhZGVyIGN4LXNhdmVkLWNhcnQtZm9ybS1oZWFkZXJcIj5cbiAgICAgICAgPG5nLWNvbnRhaW5lciBbbmdTd2l0Y2hdPVwibGF5b3V0T3B0aW9uXCI+XG4gICAgICAgICAgPGRpdiBjbGFzcz1cImN4LXNhdmVkLWNhcnQtZm9ybS10aXRsZSBtb2RhbC10aXRsZVwiPlxuICAgICAgICAgICAgPG5nLWNvbnRhaW5lciAqbmdTd2l0Y2hDYXNlPVwic2F2ZWRDYXJ0Rm9ybVR5cGUuRURJVFwiPlxuICAgICAgICAgICAgICB7eyAnc2F2ZWRDYXJ0RGlhbG9nLmVkaXRTYXZlZENhcnQnIHwgY3hUcmFuc2xhdGUgfX1cbiAgICAgICAgICAgIDwvbmctY29udGFpbmVyPlxuICAgICAgICAgICAgPG5nLWNvbnRhaW5lciAqbmdTd2l0Y2hDYXNlPVwic2F2ZWRDYXJ0Rm9ybVR5cGUuREVMRVRFXCI+XG4gICAgICAgICAgICAgIHt7ICdzYXZlZENhcnREaWFsb2cuZGVsZXRlU2F2ZWRDYXJ0JyB8IGN4VHJhbnNsYXRlIH19XG4gICAgICAgICAgICA8L25nLWNvbnRhaW5lcj5cbiAgICAgICAgICAgIDxuZy1jb250YWluZXIgKm5nU3dpdGNoQ2FzZT1cInNhdmVkQ2FydEZvcm1UeXBlLlNBVkVcIj5cbiAgICAgICAgICAgICAge3sgJ3NhdmVkQ2FydERpYWxvZy5zYXZlRm9yTGF0ZXInIHwgY3hUcmFuc2xhdGUgfX1cbiAgICAgICAgICAgIDwvbmctY29udGFpbmVyPlxuICAgICAgICAgICAgPG5nLWNvbnRhaW5lciAqbmdTd2l0Y2hDYXNlPVwic2F2ZWRDYXJ0Rm9ybVR5cGUuUkVTVE9SRVwiPlxuICAgICAgICAgICAgICB7eyAnc2F2ZWRDYXJ0RGlhbG9nLnJlc3RvcmVTYXZlZENhcnQnIHwgY3hUcmFuc2xhdGUgfX1cbiAgICAgICAgICAgIDwvbmctY29udGFpbmVyPlxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICA8L25nLWNvbnRhaW5lcj5cblxuICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgKGNsaWNrKT1cImNsb3NlKCdDbG9zZSBTYXZlIENhcnQgRGlhbG9nJylcIlxuICAgICAgICAgIFtkaXNhYmxlZF09XCJpc0xvYWRpbmckIHwgYXN5bmNcIlxuICAgICAgICAgIFthdHRyLmFyaWEtbGFiZWxdPVwiJ2NvbW1vbi5jbG9zZScgfCBjeFRyYW5zbGF0ZVwiXG4gICAgICAgICAgY2xhc3M9XCJjeC1zYXZlZC1jYXJ0LWZvcm0tY2xvc2UgY2xvc2VcIlxuICAgICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICA+XG4gICAgICAgICAgPHNwYW4gYXJpYS1oaWRkZW49XCJ0cnVlXCI+XG4gICAgICAgICAgICA8Y3gtaWNvbiBbdHlwZV09XCJpY29uVHlwZXMuQ0xPU0VcIj48L2N4LWljb24+XG4gICAgICAgICAgPC9zcGFuPlxuICAgICAgICA8L2J1dHRvbj5cbiAgICAgIDwvZGl2PlxuXG4gICAgICA8IS0tIE1vZGFsIEJvZHkgLS0+XG4gICAgICA8ZGl2IGNsYXNzPVwiY3gtc2F2ZWQtY2FydC1mb3JtLWJvZHlcIj5cbiAgICAgICAgPCEtLSBzdGFydCBERUxFVEUgYW5kIFJFU1RPUkUgZm9ybSAtLT5cbiAgICAgICAgPG5nLWNvbnRhaW5lclxuICAgICAgICAgICpuZ0lmPVwiXG4gICAgICAgICAgICBsYXlvdXRPcHRpb24gPT09IHNhdmVkQ2FydEZvcm1UeXBlLkRFTEVURSB8fFxuICAgICAgICAgICAgICBsYXlvdXRPcHRpb24gPT09IHNhdmVkQ2FydEZvcm1UeXBlLlJFU1RPUkU7XG4gICAgICAgICAgICBlbHNlIHNhdmVBbmRFZGl0Q2FydFxuICAgICAgICAgIFwiXG4gICAgICAgID5cbiAgICAgICAgICA8cCBjbGFzcz1cImN4LXNhdmVkLWNhcnQtZm9ybS1zdWJ0aXRsZVwiPlxuICAgICAgICAgICAge3tcbiAgICAgICAgICAgICAgKGxheW91dE9wdGlvbiA9PT0gc2F2ZWRDYXJ0Rm9ybVR5cGUuREVMRVRFXG4gICAgICAgICAgICAgICAgPyAnc2F2ZWRDYXJ0RGlhbG9nLmZvbGxvd2luZ0NhcnREZWxldGUnXG4gICAgICAgICAgICAgICAgOiAnc2F2ZWRDYXJ0RGlhbG9nLmZvbGxvd2luZ0NhcnRSZXN0b3JlJ1xuICAgICAgICAgICAgICApIHwgY3hUcmFuc2xhdGVcbiAgICAgICAgICAgIH19XG4gICAgICAgICAgPC9wPlxuXG4gICAgICAgICAgPGRpdiBjbGFzcz1cImN4LXNhdmVkLWNhcnQtZm9ybS1yb3dcIj5cbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJjeC1zYXZlZC1jYXJ0LXZhbHVlcy1jb250YWluZXJcIj5cbiAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cImN4LXNhdmVkLWNhcnQtbGFiZWxcIj5cbiAgICAgICAgICAgICAgICB7eyAnc2F2ZWRDYXJ0RGlhbG9nLm5hbWUnIHwgY3hUcmFuc2xhdGUgfX1cbiAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJjeC1zYXZlZC1jYXJ0LXZhbHVlXCI+XG4gICAgICAgICAgICAgICAge3sgY2FydD8ubmFtZSB9fVxuICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgIDwvZGl2PlxuXG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwiY3gtc2F2ZWQtY2FydC12YWx1ZXMtY29udGFpbmVyXCI+XG4gICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJjeC1zYXZlZC1jYXJ0LWxhYmVsXCI+XG4gICAgICAgICAgICAgICAge3sgJ3NhdmVkQ2FydERpYWxvZy5pZCcgfCBjeFRyYW5zbGF0ZSB9fVxuICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cImN4LXNhdmVkLWNhcnQtdmFsdWVcIj5cbiAgICAgICAgICAgICAgICB7eyBjYXJ0Py5jb2RlIH19XG4gICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJjeC1zYXZlZC1jYXJ0LXZhbHVlcy1jb250YWluZXJcIj5cbiAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cImN4LXNhdmVkLWNhcnQtbGFiZWxcIj5cbiAgICAgICAgICAgICAgICB7eyAnc2F2ZWRDYXJ0RGlhbG9nLmRlc2NyaXB0aW9uJyB8IGN4VHJhbnNsYXRlIH19XG4gICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwiY3gtc2F2ZWQtY2FydC12YWx1ZVwiPlxuICAgICAgICAgICAgICAgIHt7IGNhcnQ/LmRlc2NyaXB0aW9uIH19XG4gICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJjeC1zYXZlZC1jYXJ0LXZhbHVlcy1jb250YWluZXJcIj5cbiAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cImN4LXNhdmVkLWNhcnQtbGFiZWxcIj5cbiAgICAgICAgICAgICAgICB7eyAnc2F2ZWRDYXJ0RGlhbG9nLnF1YW50aXR5JyB8IGN4VHJhbnNsYXRlIH19XG4gICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwiY3gtc2F2ZWQtY2FydC12YWx1ZVwiPlxuICAgICAgICAgICAgICAgIHt7IGNhcnQ/LnRvdGFsSXRlbXMgfX1cbiAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICA8L2Rpdj5cblxuICAgICAgICAgICAgPGRpdiBjbGFzcz1cImN4LXNhdmVkLWNhcnQtdmFsdWVzLWNvbnRhaW5lclwiPlxuICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwiY3gtc2F2ZWQtY2FydC1sYWJlbFwiPlxuICAgICAgICAgICAgICAgIHt7ICdzYXZlZENhcnREaWFsb2cudG90YWwnIHwgY3hUcmFuc2xhdGUgfX1cbiAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJjeC1zYXZlZC1jYXJ0LXZhbHVlXCI+XG4gICAgICAgICAgICAgICAge3sgY2FydD8udG90YWxQcmljZVdpdGhUYXg/LmZvcm1hdHRlZFZhbHVlIH19XG4gICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgICA8bmctY29udGFpbmVyICpuZ0lmPVwibGF5b3V0T3B0aW9uID09PSBzYXZlZENhcnRGb3JtVHlwZS5SRVNUT1JFXCI+XG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwiY3gtY29weS1zYXZlZC1jYXJ0LXJvdyBmb3JtLWNoZWNrXCI+XG4gICAgICAgICAgICAgIDxpbnB1dFxuICAgICAgICAgICAgICAgIGlkPVwiY3gtY29weS1zYXZlZC1jYXJ0XCJcbiAgICAgICAgICAgICAgICB0eXBlPVwiY2hlY2tib3hcIlxuICAgICAgICAgICAgICAgIGNsYXNzPVwiY3gtY29weS1zYXZlZC1jYXJ0LWlucHV0XCJcbiAgICAgICAgICAgICAgICBbY2hlY2tlZF09XCJpc0Nsb25lU2F2ZWRDYXJ0XCJcbiAgICAgICAgICAgICAgICAoY2hhbmdlKT1cInRvZ2dsZUlzQ2xvbmVTYXZlZENhcnQoKVwiXG4gICAgICAgICAgICAgIC8+XG4gICAgICAgICAgICAgIDxsYWJlbFxuICAgICAgICAgICAgICAgIGZvcj1cImN4LWNvcHktc2F2ZWQtY2FydFwiXG4gICAgICAgICAgICAgICAgY2xhc3M9XCJjeC1jb3B5LXNhdmVkLWNhcnQtbGFiZWxcIlxuICAgICAgICAgICAgICAgID57eyAnc2F2ZWRDYXJ0RGlhbG9nLmtlZXBDb3B5U2F2ZWRDYXJ0JyB8IGN4VHJhbnNsYXRlIH19PC9sYWJlbFxuICAgICAgICAgICAgICA+XG4gICAgICAgICAgICA8L2Rpdj5cblxuICAgICAgICAgICAgPGRpdiAqbmdJZj1cImlzQ2xvbmVTYXZlZENhcnRcIiBjbGFzcz1cImN4LWNvcHktc2F2ZWQtY2FydC1yb3dcIj5cbiAgICAgICAgICAgICAgPGxhYmVsPlxuICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwibGFiZWwtY29udGVudFwiPlxuICAgICAgICAgICAgICAgICAge3sgJ3NhdmVkQ2FydERpYWxvZy5uYW1lT2ZDbG9uZUNhcnQnIHwgY3hUcmFuc2xhdGUgfX1cbiAgICAgICAgICAgICAgICA8L3NwYW4+XG5cbiAgICAgICAgICAgICAgICA8aW5wdXRcbiAgICAgICAgICAgICAgICAgIFttYXhMZW5ndGhdPVwibmFtZU1heExlbmd0aFwiXG4gICAgICAgICAgICAgICAgICBjbGFzcz1cImZvcm0tY29udHJvbFwiXG4gICAgICAgICAgICAgICAgICBmb3JtQ29udHJvbE5hbWU9XCJjbG9uZU5hbWVcIlxuICAgICAgICAgICAgICAgICAgdHlwZT1cInRleHRcIlxuICAgICAgICAgICAgICAgICAgcGxhY2Vob2xkZXI9XCJ7e1xuICAgICAgICAgICAgICAgICAgICAnc2F2ZWRDYXJ0RGlhbG9nLmRlZmF1bHRDbG9uZUNhcnROYW1lJ1xuICAgICAgICAgICAgICAgICAgICAgIHwgY3hUcmFuc2xhdGU6IHsgbmFtZTogZm9ybS5nZXQoJ25hbWUnKT8udmFsdWUgfVxuICAgICAgICAgICAgICAgICAgfX1cIlxuICAgICAgICAgICAgICAgIC8+XG4gICAgICAgICAgICAgIDwvbGFiZWw+XG4gICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICA8L25nLWNvbnRhaW5lcj5cblxuICAgICAgICAgIDxkaXYgY2xhc3M9XCJjeC1zYXZlZC1jYXJ0LWZvcm0tZm9vdGVyXCI+XG4gICAgICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgICAgIChjbGljayk9XCJjbG9zZSgnQ2xvc2UgU2F2ZSBDYXJ0IERpYWxvZycpXCJcbiAgICAgICAgICAgICAgW2F0dHIuYXJpYS1sYWJlbF09XCInY29tbW9uLmNsb3NlJyB8IGN4VHJhbnNsYXRlXCJcbiAgICAgICAgICAgICAgY2xhc3M9XCJtci0yIGJ0biBidG4tYWN0aW9uXCJcbiAgICAgICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgICA+XG4gICAgICAgICAgICAgIHt7ICdzYXZlZENhcnREaWFsb2cuY2FuY2VsJyB8IGN4VHJhbnNsYXRlIH19XG4gICAgICAgICAgICA8L2J1dHRvbj5cblxuICAgICAgICAgICAgPG5nLWNvbnRhaW5lclxuICAgICAgICAgICAgICAqbmdJZj1cIlxuICAgICAgICAgICAgICAgIGxheW91dE9wdGlvbiA9PT0gc2F2ZWRDYXJ0Rm9ybVR5cGUuREVMRVRFO1xuICAgICAgICAgICAgICAgIGVsc2UgaXNSZXN0b3JlU2F2ZWRDYXJ0XG4gICAgICAgICAgICAgIFwiXG4gICAgICAgICAgICA+XG4gICAgICAgICAgICAgIDxidXR0b25cbiAgICAgICAgICAgICAgICAqbmdJZj1cImNhcnQuY29kZVwiXG4gICAgICAgICAgICAgICAgKGNsaWNrKT1cImRlbGV0ZUNhcnQoY2FydC5jb2RlKVwiXG4gICAgICAgICAgICAgICAgW2F0dHIuYXJpYS1sYWJlbF09XCInY29tbW9uLmRlbGV0ZScgfCBjeFRyYW5zbGF0ZVwiXG4gICAgICAgICAgICAgICAgW2Rpc2FibGVkXT1cImlzRGlzYWJsZURlbGV0ZUJ1dHRvbiQgfCBhc3luY1wiXG4gICAgICAgICAgICAgICAgY2xhc3M9XCJtbC0yIGJ0biBidG4tcHJpbWFyeVwiXG4gICAgICAgICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgICB7eyAnc2F2ZWRDYXJ0RGlhbG9nLmRlbGV0ZScgfCBjeFRyYW5zbGF0ZSB9fVxuICAgICAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgICAgIDwvbmctY29udGFpbmVyPlxuXG4gICAgICAgICAgICA8bmctdGVtcGxhdGUgI2lzUmVzdG9yZVNhdmVkQ2FydD5cbiAgICAgICAgICAgICAgPGJ1dHRvblxuICAgICAgICAgICAgICAgICpuZ0lmPVwiY2FydC5jb2RlXCJcbiAgICAgICAgICAgICAgICAoY2xpY2spPVwicmVzdG9yZVNhdmVkQ2FydChjYXJ0LmNvZGUpXCJcbiAgICAgICAgICAgICAgICBbZGlzYWJsZWRdPVwiaXNEaXNhYmxlUmVzdG9yZUJ1dHRvbiQgfCBhc3luY1wiXG4gICAgICAgICAgICAgICAgW2F0dHIuYXJpYS1sYWJlbF09XCInY29tbW9uLnJlc3RvcmUnIHwgY3hUcmFuc2xhdGVcIlxuICAgICAgICAgICAgICAgIGNsYXNzPVwibWwtMiBidG4gYnRuLXByaW1hcnlcIlxuICAgICAgICAgICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICAgICAgICA+XG4gICAgICAgICAgICAgICAge3sgJ3NhdmVkQ2FydERpYWxvZy5yZXN0b3JlJyB8IGN4VHJhbnNsYXRlIH19XG4gICAgICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICAgICAgPC9uZy10ZW1wbGF0ZT5cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgPC9uZy1jb250YWluZXI+XG4gICAgICAgIDwhLS0gZW5kIERFTEVURSBmb3JtIC0tPlxuXG4gICAgICAgIDwhLS0gc3RhcnQgU0FWRSBhbmQgRURJVCBmb3JtIC0tPlxuICAgICAgICA8bmctdGVtcGxhdGUgI3NhdmVBbmRFZGl0Q2FydD5cbiAgICAgICAgICA8bmctY29udGFpbmVyICpuZ0lmPVwibGF5b3V0T3B0aW9uID09PSBzYXZlZENhcnRGb3JtVHlwZS5TQVZFXCI+XG4gICAgICAgICAgICA8cCBjbGFzcz1cImN4LXNhdmVkLWNhcnQtZm9ybS1zdWJ0aXRsZVwiPlxuICAgICAgICAgICAgICB7eyAnc2F2ZWRDYXJ0RGlhbG9nLml0ZW1zU2F2ZWRGb3JMYXRlcicgfCBjeFRyYW5zbGF0ZSB9fVxuICAgICAgICAgICAgPC9wPlxuICAgICAgICAgIDwvbmctY29udGFpbmVyPlxuXG4gICAgICAgICAgPGRpdiBjbGFzcz1cImN4LXNhdmVkLWNhcnQtZm9ybS1yb3dcIj5cbiAgICAgICAgICAgIDxuZy1jb250YWluZXI+XG4gICAgICAgICAgICAgIDxsYWJlbD5cbiAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cImN4LXNhdmVkLWNhcnRzLWxhYmVsIGxhYmVsLWNvbnRlbnRcIj57e1xuICAgICAgICAgICAgICAgICAgJ3NhdmVkQ2FydERpYWxvZy5zYXZlZENhcnROYW1lJyB8IGN4VHJhbnNsYXRlXG4gICAgICAgICAgICAgICAgfX08L3NwYW4+XG4gICAgICAgICAgICAgICAgPGlucHV0XG4gICAgICAgICAgICAgICAgICBhcmlhLXJlcXVpcmVkPVwidHJ1ZVwiXG4gICAgICAgICAgICAgICAgICBbbWF4TGVuZ3RoXT1cIm5hbWVNYXhMZW5ndGhcIlxuICAgICAgICAgICAgICAgICAgY2xhc3M9XCJmb3JtLWNvbnRyb2xcIlxuICAgICAgICAgICAgICAgICAgZm9ybUNvbnRyb2xOYW1lPVwibmFtZVwiXG4gICAgICAgICAgICAgICAgICByZXF1aXJlZFxuICAgICAgICAgICAgICAgICAgdHlwZT1cInRleHRcIlxuICAgICAgICAgICAgICAgIC8+XG4gICAgICAgICAgICAgICAgPGN4LWZvcm0tZXJyb3JzXG4gICAgICAgICAgICAgICAgICBhcmlhLWxpdmU9XCJhc3NlcnRpdmVcIlxuICAgICAgICAgICAgICAgICAgYXJpYS1hdG9taWM9XCJ0cnVlXCJcbiAgICAgICAgICAgICAgICAgIFtjb250cm9sXT1cImZvcm0uZ2V0KCduYW1lJylcIlxuICAgICAgICAgICAgICAgID48L2N4LWZvcm0tZXJyb3JzPlxuICAgICAgICAgICAgICA8L2xhYmVsPlxuICAgICAgICAgICAgPC9uZy1jb250YWluZXI+XG4gICAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgICA8ZGl2IGNsYXNzPVwiY3gtc2F2ZWQtY2FydC1mb3JtLXJvd1wiPlxuICAgICAgICAgICAgPGxhYmVsPlxuICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cImN4LXNhdmVkLWNhcnRzLWxhYmVsIGxhYmVsLWNvbnRlbnRcIlxuICAgICAgICAgICAgICAgID57eyAnc2F2ZWRDYXJ0RGlhbG9nLnNhdmVkQ2FydERlc2NyaXB0aW9uJyB8IGN4VHJhbnNsYXRlIH19XG4gICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJjeC1zYXZlZC1jYXJ0cy1sYWJlbC1vcHRpb25hbFwiPlxuICAgICAgICAgICAgICAgICAgKHt7ICdzYXZlZENhcnREaWFsb2cub3B0aW9uYWwnIHwgY3hUcmFuc2xhdGUgfX0pXG4gICAgICAgICAgICAgICAgPC9zcGFuPjwvc3BhblxuICAgICAgICAgICAgICA+XG4gICAgICAgICAgICAgIDx0ZXh0YXJlYVxuICAgICAgICAgICAgICAgIFttYXhMZW5ndGhdPVwiZGVzY3JpcHRpb25NYXhMZW5ndGhcIlxuICAgICAgICAgICAgICAgIGNsYXNzPVwiZm9ybS1jb250cm9sXCJcbiAgICAgICAgICAgICAgICBmb3JtQ29udHJvbE5hbWU9XCJkZXNjcmlwdGlvblwiXG4gICAgICAgICAgICAgICAgcm93cz1cIjVcIlxuICAgICAgICAgICAgICA+PC90ZXh0YXJlYT5cbiAgICAgICAgICAgICAgPGN4LWZvcm0tZXJyb3JzXG4gICAgICAgICAgICAgICAgYXJpYS1saXZlPVwiYXNzZXJ0aXZlXCJcbiAgICAgICAgICAgICAgICBhcmlhLWF0b21pYz1cInRydWVcIlxuICAgICAgICAgICAgICAgIFtjb250cm9sXT1cImZvcm0uZ2V0KCdkZXNjcmlwdGlvbicpXCJcbiAgICAgICAgICAgICAgPjwvY3gtZm9ybS1lcnJvcnM+XG5cbiAgICAgICAgICAgICAgPHAgY2xhc3M9XCJjeC1zYXZlZC1jYXJ0cy1pbnB1dC1oaW50XCI+XG4gICAgICAgICAgICAgICAge3tcbiAgICAgICAgICAgICAgICAgICdzYXZlZENhcnREaWFsb2cuY2hhcmFjdGVyc0xlZnQnXG4gICAgICAgICAgICAgICAgICAgIHwgY3hUcmFuc2xhdGU6IHsgY291bnQ6IGRlc2NyaXB0aW9uc0NoYXJhY3RlckxlZnQgfVxuICAgICAgICAgICAgICAgIH19XG4gICAgICAgICAgICAgIDwvcD5cbiAgICAgICAgICAgIDwvbGFiZWw+XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgPGRpdiBjbGFzcz1cImN4LXNhdmVkLWNhcnQtZm9ybS1mb290ZXJcIj5cbiAgICAgICAgICAgIDxidXR0b25cbiAgICAgICAgICAgICAgKGNsaWNrKT1cImNsb3NlKCdDbG9zZSBTYXZlIENhcnQgRGlhbG9nJylcIlxuICAgICAgICAgICAgICBbYXR0ci5hcmlhLWxhYmVsXT1cIidjb21tb24uY2xvc2UnIHwgY3hUcmFuc2xhdGVcIlxuICAgICAgICAgICAgICBbZGlzYWJsZWRdPVwiaXNMb2FkaW5nJCB8IGFzeW5jXCJcbiAgICAgICAgICAgICAgY2xhc3M9XCJidG4gYnRuLWFjdGlvblwiXG4gICAgICAgICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICAgICAgPlxuICAgICAgICAgICAgICB7eyAnc2F2ZWRDYXJ0RGlhbG9nLmNhbmNlbCcgfCBjeFRyYW5zbGF0ZSB9fVxuICAgICAgICAgICAgPC9idXR0b24+XG4gICAgICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgICAgIChjbGljayk9XCJzYXZlT3JFZGl0Q2FydChjYXJ0Py5jb2RlKVwiXG4gICAgICAgICAgICAgIFthdHRyLmFyaWEtbGFiZWxdPVwiJ2NvbW1vbi5zYXZlJyB8IGN4VHJhbnNsYXRlXCJcbiAgICAgICAgICAgICAgW2Rpc2FibGVkXT1cImZvcm0uaW52YWxpZCB8fCAoaXNMb2FkaW5nJCB8IGFzeW5jKVwiXG4gICAgICAgICAgICAgIGNsYXNzPVwiYnRuIGJ0bi1wcmltYXJ5XCJcbiAgICAgICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgICA+XG4gICAgICAgICAgICAgIHt7ICdzYXZlZENhcnREaWFsb2cuc2F2ZScgfCBjeFRyYW5zbGF0ZSB9fVxuICAgICAgICAgICAgPC9idXR0b24+XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgIDwvbmctdGVtcGxhdGU+XG4gICAgICAgIDwhLS0gZW5kIFNBVkUgYW5kIEVESVQgZm9ybSAtLT5cbiAgICAgIDwvZGl2PlxuICAgIDwvZm9ybT5cbiAgPC9kaXY+XG48L25nLWNvbnRhaW5lcj5cbiJdfQ==