@c8y/ngx-components
Version:
Angular modules for Cumulocity IoT applications
131 lines • 36.5 kB
JavaScript
import { moveItemInArray } from '@angular/cdk/drag-drop';
import { Component, HostListener, Input } from '@angular/core';
import { AlertService, gettext } from '@c8y/ngx-components';
import { IconSelectorService } from '@c8y/ngx-components/icon-selector';
import { cloneDeep } from 'lodash-es';
import { BsModalRef } from 'ngx-bootstrap/modal';
import { BookmarkService } from '../bookmarks.service';
import * as i0 from "@angular/core";
import * as i1 from "ngx-bootstrap/modal";
import * as i2 from "@c8y/ngx-components";
import * as i3 from "../bookmarks.service";
import * as i4 from "@c8y/ngx-components/icon-selector";
import * as i5 from "@angular/common";
import * as i6 from "@angular/forms";
import * as i7 from "@angular/cdk/drag-drop";
import * as i8 from "ngx-bootstrap/tooltip";
export class EditBookmarksComponent {
constructor(bsModalRef, alertService, bookmarkService, iconSelector) {
this.bsModalRef = bsModalRef;
this.alertService = alertService;
this.bookmarkService = bookmarkService;
this.iconSelector = iconSelector;
this.confirmRemoveColumnButtons = [
{
label: gettext('Cancel'),
action: () => Promise.resolve(false)
},
{
label: gettext('Delete'),
status: 'danger',
action: () => Promise.resolve(true)
}
];
this.result = new Promise(resolve => {
this._close = resolve;
});
}
ngOnInit() {
this.bookmarksToUpdate = cloneDeep(this.bookmarks);
}
handleKeyboardEvent(event) {
if (event.key === 'Escape') {
this.close();
}
}
close() {
if (this.bookmarkService.updatedBookmarks) {
this._close(this.bookmarkService.updatedBookmarks);
}
this.bsModalRef.hide();
}
async drop(event) {
try {
moveItemInArray(this.bookmarks, event.previousIndex, event.currentIndex);
moveItemInArray(this.bookmarksToUpdate, event.previousIndex, event.currentIndex);
await this.bookmarkService.updateBookmarksInStorage(this.bookmarksToUpdate);
this.alertService.success(gettext('Bookmarks order updated.'));
}
catch {
this.alertService.success(gettext('Bookmarks order failed to update.'));
}
}
async updateBookmark(updatedBookmark, type) {
try {
this.bookmarksToUpdate = this.updateBookmarkProperty(updatedBookmark, type);
await this.bookmarkService.updateBookmarksInStorage(this.bookmarksToUpdate);
if (type !== 'markToRemove') {
this.alertService.success(gettext('Bookmark updated.'));
}
}
catch {
if (type !== 'markToRemove') {
this.alertService.warning(gettext('Bookmark update failed'));
}
}
}
updateBookmarkProperty(updatedBookmark, type) {
const update = {
icon: (bookmark) => ({ ...bookmark, icon: updatedBookmark.icon }),
label: (bookmark) => ({ ...bookmark, label: updatedBookmark.label }),
markToRemove: (bookmark) => ({ ...bookmark, markToRemove: true })
}[type];
return this.bookmarksToUpdate.map(bookmark => bookmark.id === updatedBookmark.id ? update(bookmark) : bookmark);
}
async changeBookmarkIcon(updatedBookmark) {
try {
const newIcon = await this.iconSelector.selectIcon();
updatedBookmark.icon = newIcon;
await this.updateBookmark(updatedBookmark, 'icon');
}
catch {
// nothing to do
}
}
async removeBookmark(poConfirm, bookmarkToDelete) {
poConfirm.message = gettext('This action is irreversible.');
try {
const remove = await poConfirm.show(this.confirmRemoveColumnButtons);
if (!remove) {
return;
}
await this.updateBookmark(bookmarkToDelete, 'markToRemove');
const bookmarkIndex = this.bookmarks.findIndex(bookmark => bookmark.id === bookmarkToDelete.id);
if (bookmarkIndex === -1) {
return;
}
this.bookmarks.splice(bookmarkIndex, 1);
this.alertService.success(gettext('Bookmark removed.'));
}
catch (err) {
/**
* Prevents an alert message from being displayed if the user clicks outside of a popover.
*/
if (err) {
this.alertService.warning(gettext('Bookmarks deletion failed.'));
}
}
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: EditBookmarksComponent, deps: [{ token: i1.BsModalRef }, { token: i2.AlertService }, { token: i3.BookmarkService }, { token: i4.IconSelectorService }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: EditBookmarksComponent, selector: "c8y-edit-bookmarks", inputs: { bookmarks: "bookmarks" }, host: { listeners: { "document:keydown": "handleKeyboardEvent($event)" } }, ngImport: i0, template: "<div class=\"viewport-modal\">\n <div class=\"modal-header dialog-header\">\n <i [c8yIcon]=\"'bookmark'\"></i>\n <div\n class=\"h4\"\n id=\"modal-title\"\n translate\n >\n Bookmarks\n </div>\n </div>\n <div\n class=\"inner-scroll\"\n id=\"modal-body\"\n >\n <div class=\"p-16 text-center separator-bottom sticky-top bg-component\">\n <p class=\"text-medium text-16\">\n {{ 'Reorder, edit or delete bookmarks.' | translate }}\n </p>\n </div>\n <c8y-list-group\n class=\"cdk-droplist no-border-last\"\n *ngIf=\"bookmarks.length; else emptyList\"\n cdkDropList\n (cdkDropListDropped)=\"drop($event)\"\n [cdkDropListDisabled]=\"bookmarks?.length < 2\"\n >\n <c8y-li\n *ngFor=\"let bookmark of bookmarks\"\n cdkDrag\n >\n <c8y-li-drag-handle\n title=\"{{ 'Drag to reorder' | translate }}\"\n cdkDragHandle\n >\n <i c8yIcon=\"drag-reorder\"></i>\n </c8y-li-drag-handle>\n <c8y-li-icon\n class=\"icon-24 p-relative changeIcon a-s-stretch\"\n style=\"{{ bookmarks?.length < 2 ? 'padding-left: 16px!important' : '' }}\"\n *ngIf=\"bookmark.icon\"\n >\n <i [c8yIcon]=\"bookmark.icon\"></i>\n <button\n class=\"btn btn-default btn-xs\"\n [attr.aria-label]=\"'Change icon' | translate\"\n tooltip=\"{{ 'Change icon' | translate }}\"\n placement=\"top\"\n container=\"body\"\n type=\"button\"\n [delay]=\"500\"\n [adaptivePosition]=\"false\"\n (click)=\"changeBookmarkIcon(bookmark)\"\n >\n <i c8yIcon=\"replace\"></i>\n </button>\n </c8y-li-icon>\n\n <div class=\"d-flex gap-8 a-i-center\">\n <form\n class=\"d-flex flex-grow\"\n name=\"bookmarksForm\"\n #bookmarksForm=\"ngForm\"\n >\n <div class=\"input-group input-group-editable\">\n <input\n class=\"form-control fit-w\"\n title=\"{{ bookmark.label }}\"\n id=\"label\"\n name=\"label\"\n type=\"text\"\n [(ngModel)]=\"bookmark.label\"\n #label=\"ngModel\"\n maxlength=\"50\"\n [placeholder]=\"'e.g. My bookmark' | translate\"\n />\n <span></span>\n <div class=\"input-group-btn\">\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Save' | translate }}\"\n type=\"submit\"\n (click)=\"updateBookmark(bookmark, 'label'); label.control.markAsPristine()\"\n [disabled]=\"label.invalid\"\n >\n {{ 'Save' | translate }}\n </button>\n </div>\n </div>\n </form>\n <c8y-popover-confirm\n class=\"d-block\"\n [title]=\"'Delete bookmark' | translate\"\n [placement]=\"'left'\"\n [outsideClick]=\"true\"\n [adaptivePosition]=\"true\"\n [container]=\"''\"\n #poConfirm\n >\n <button\n class=\"btn btn-dot btn-dot--danger m-l-auto\"\n title=\"{{ 'Delete' | translate }}\"\n type=\"button\"\n (click)=\"removeBookmark(poConfirm, bookmark)\"\n >\n <i c8yIcon=\"minus-circle\"></i>\n </button>\n </c8y-popover-confirm>\n </div>\n </c8y-li>\n </c8y-list-group>\n </div>\n <div class=\"modal-footer\">\n <button\n class=\"btn btn-default\"\n title=\"{{ 'Cancel' | translate }}\"\n type=\"button\"\n (click)=\"close()\"\n >\n {{ 'Close' | translate }}\n </button>\n </div>\n</div>\n<ng-template #emptyList>\n <c8y-ui-empty-state\n [icon]=\"'bookmark'\"\n [title]=\"'No bookmarks yet' | translate\"\n [subtitle]=\"\n 'Navigate to the desired page, open the right drawer and click the "Add current page" button.'\n | translate\n \"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n</ng-template>\n", dependencies: [{ kind: "component", type: i2.EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "directive", type: i2.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i2.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i5.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2.PopoverConfirmComponent, selector: "c8y-popover-confirm", inputs: ["buttons", "message", "title", "isOpen", "containerClass", "placement", "outsideClick", "adaptivePosition", "container"] }, { kind: "directive", type: i6.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i6.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: i6.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i6.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i6.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i6.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i6.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: i2.ListGroupComponent, selector: "c8y-list-group" }, { kind: "component", type: i2.ListItemComponent, selector: "c8y-list-item, c8y-li", inputs: ["active", "highlighted", "emptyActions", "dense", "collapsed", "selectable"], outputs: ["collapsedChange"] }, { kind: "component", type: i2.ListItemIconComponent, selector: "c8y-list-item-icon, c8y-li-icon", inputs: ["icon", "status"] }, { kind: "component", type: i2.ListItemDragHandleComponent, selector: "c8y-list-item-drag-handle, c8y-li-drag-handle" }, { kind: "directive", type: i7.CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: i7.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: i7.CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "directive", type: i8.TooltipDirective, selector: "[tooltip], [tooltipHtml]", inputs: ["adaptivePosition", "tooltip", "placement", "triggers", "container", "containerClass", "boundariesElement", "isOpen", "isDisabled", "delay", "tooltipHtml", "tooltipPlacement", "tooltipIsOpen", "tooltipEnable", "tooltipAppendToBody", "tooltipAnimation", "tooltipClass", "tooltipContext", "tooltipPopupDelay", "tooltipFadeDuration", "tooltipTrigger"], outputs: ["tooltipChange", "onShown", "onHidden", "tooltipStateChanged"], exportAs: ["bs-tooltip"] }, { kind: "pipe", type: i2.C8yTranslatePipe, name: "translate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: EditBookmarksComponent, decorators: [{
type: Component,
args: [{ selector: 'c8y-edit-bookmarks', template: "<div class=\"viewport-modal\">\n <div class=\"modal-header dialog-header\">\n <i [c8yIcon]=\"'bookmark'\"></i>\n <div\n class=\"h4\"\n id=\"modal-title\"\n translate\n >\n Bookmarks\n </div>\n </div>\n <div\n class=\"inner-scroll\"\n id=\"modal-body\"\n >\n <div class=\"p-16 text-center separator-bottom sticky-top bg-component\">\n <p class=\"text-medium text-16\">\n {{ 'Reorder, edit or delete bookmarks.' | translate }}\n </p>\n </div>\n <c8y-list-group\n class=\"cdk-droplist no-border-last\"\n *ngIf=\"bookmarks.length; else emptyList\"\n cdkDropList\n (cdkDropListDropped)=\"drop($event)\"\n [cdkDropListDisabled]=\"bookmarks?.length < 2\"\n >\n <c8y-li\n *ngFor=\"let bookmark of bookmarks\"\n cdkDrag\n >\n <c8y-li-drag-handle\n title=\"{{ 'Drag to reorder' | translate }}\"\n cdkDragHandle\n >\n <i c8yIcon=\"drag-reorder\"></i>\n </c8y-li-drag-handle>\n <c8y-li-icon\n class=\"icon-24 p-relative changeIcon a-s-stretch\"\n style=\"{{ bookmarks?.length < 2 ? 'padding-left: 16px!important' : '' }}\"\n *ngIf=\"bookmark.icon\"\n >\n <i [c8yIcon]=\"bookmark.icon\"></i>\n <button\n class=\"btn btn-default btn-xs\"\n [attr.aria-label]=\"'Change icon' | translate\"\n tooltip=\"{{ 'Change icon' | translate }}\"\n placement=\"top\"\n container=\"body\"\n type=\"button\"\n [delay]=\"500\"\n [adaptivePosition]=\"false\"\n (click)=\"changeBookmarkIcon(bookmark)\"\n >\n <i c8yIcon=\"replace\"></i>\n </button>\n </c8y-li-icon>\n\n <div class=\"d-flex gap-8 a-i-center\">\n <form\n class=\"d-flex flex-grow\"\n name=\"bookmarksForm\"\n #bookmarksForm=\"ngForm\"\n >\n <div class=\"input-group input-group-editable\">\n <input\n class=\"form-control fit-w\"\n title=\"{{ bookmark.label }}\"\n id=\"label\"\n name=\"label\"\n type=\"text\"\n [(ngModel)]=\"bookmark.label\"\n #label=\"ngModel\"\n maxlength=\"50\"\n [placeholder]=\"'e.g. My bookmark' | translate\"\n />\n <span></span>\n <div class=\"input-group-btn\">\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Save' | translate }}\"\n type=\"submit\"\n (click)=\"updateBookmark(bookmark, 'label'); label.control.markAsPristine()\"\n [disabled]=\"label.invalid\"\n >\n {{ 'Save' | translate }}\n </button>\n </div>\n </div>\n </form>\n <c8y-popover-confirm\n class=\"d-block\"\n [title]=\"'Delete bookmark' | translate\"\n [placement]=\"'left'\"\n [outsideClick]=\"true\"\n [adaptivePosition]=\"true\"\n [container]=\"''\"\n #poConfirm\n >\n <button\n class=\"btn btn-dot btn-dot--danger m-l-auto\"\n title=\"{{ 'Delete' | translate }}\"\n type=\"button\"\n (click)=\"removeBookmark(poConfirm, bookmark)\"\n >\n <i c8yIcon=\"minus-circle\"></i>\n </button>\n </c8y-popover-confirm>\n </div>\n </c8y-li>\n </c8y-list-group>\n </div>\n <div class=\"modal-footer\">\n <button\n class=\"btn btn-default\"\n title=\"{{ 'Cancel' | translate }}\"\n type=\"button\"\n (click)=\"close()\"\n >\n {{ 'Close' | translate }}\n </button>\n </div>\n</div>\n<ng-template #emptyList>\n <c8y-ui-empty-state\n [icon]=\"'bookmark'\"\n [title]=\"'No bookmarks yet' | translate\"\n [subtitle]=\"\n 'Navigate to the desired page, open the right drawer and click the "Add current page" button.'\n | translate\n \"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n</ng-template>\n" }]
}], ctorParameters: () => [{ type: i1.BsModalRef }, { type: i2.AlertService }, { type: i3.BookmarkService }, { type: i4.IconSelectorService }], propDecorators: { bookmarks: [{
type: Input
}], handleKeyboardEvent: [{
type: HostListener,
args: ['document:keydown', ['$event']]
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZWRpdC1ib29rbWFya3MuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vYm9va21hcmtzL2VkaXQtYm9va21hcmtzL2VkaXQtYm9va21hcmtzLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uL2Jvb2ttYXJrcy9lZGl0LWJvb2ttYXJrcy9lZGl0LWJvb2ttYXJrcy5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQWUsZUFBZSxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDdEUsT0FBTyxFQUFFLFNBQVMsRUFBRSxZQUFZLEVBQUUsS0FBSyxFQUFVLE1BQU0sZUFBZSxDQUFDO0FBQ3ZFLE9BQU8sRUFDTCxZQUFZLEVBQ1osT0FBTyxFQUdSLE1BQU0scUJBQXFCLENBQUM7QUFDN0IsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sbUNBQW1DLENBQUM7QUFDeEUsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUN0QyxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFFakQsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLHNCQUFzQixDQUFDOzs7Ozs7Ozs7O0FBTXZELE1BQU0sT0FBTyxzQkFBc0I7SUFzQmpDLFlBQ1UsVUFBc0IsRUFDdEIsWUFBMEIsRUFDMUIsZUFBZ0MsRUFDaEMsWUFBaUM7UUFIakMsZUFBVSxHQUFWLFVBQVUsQ0FBWTtRQUN0QixpQkFBWSxHQUFaLFlBQVksQ0FBYztRQUMxQixvQkFBZSxHQUFmLGVBQWUsQ0FBaUI7UUFDaEMsaUJBQVksR0FBWixZQUFZLENBQXFCO1FBdEIzQywrQkFBMEIsR0FBNEI7WUFDcEQ7Z0JBQ0UsS0FBSyxFQUFFLE9BQU8sQ0FBQyxRQUFRLENBQUM7Z0JBQ3hCLE1BQU0sRUFBRSxHQUFHLEVBQUUsQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQzthQUNyQztZQUNEO2dCQUNF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QUFJLENBQUMsU0FBUyxDQUFDLFNBQVMsQ0FDNUMsUUFBUSxDQUFDLEVBQUUsQ0FBQyxRQUFRLENBQUMsRUFBRSxLQUFLLGdCQUFnQixDQUFDLEVBQUUsQ0FDaEQsQ0FBQztZQUVGLElBQUksYUFBYSxLQUFLLENBQUMsQ0FBQyxFQUFFLENBQUM7Z0JBQ3pCLE9BQU87WUFDVCxDQUFDO1lBRUQsSUFBSSxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUMsYUFBYSxFQUFFLENBQUMsQ0FBQyxDQUFDO1lBQ3hDLElBQUksQ0FBQyxZQUFZLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDLENBQUM7UUFDMUQsQ0FBQztRQUFDLE9BQU8sR0FBRyxFQUFFLENBQUM7WUFDYjs7ZUFFRztZQUNILElBQUksR0FBRyxFQUFFLENBQUM7Z0JBQ1IsSUFBSSxDQUFDLFlBQVksQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLDRCQUE0QixDQUFDLENBQUMsQ0FBQztZQUNuRSxDQUFDO1FBQ0gsQ0FBQztJQUNILENBQUM7K0dBcklVLHNCQUFzQjttR0FBdEIsc0JBQXNCLDBLQ2xCbkMseXRJQXNJQTs7NEZEcEhhLHNCQUFzQjtrQkFKbEMsU0FBUzsrQkFDRSxvQkFBb0I7MEtBSXJCLFNBQVM7c0JBQWpCLEtBQUs7Z0JBaUNOLG1CQUFtQjtzQkFEbEIsWUFBWTt1QkFBQyxrQkFBa0IsRUFBRSxDQUFDLFFBQVEsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENka0RyYWdEcm9wLCBtb3ZlSXRlbUluQXJyYXkgfSBmcm9tICdAYW5ndWxhci9jZGsvZHJhZy1kcm9wJztcbmltcG9ydCB7IENvbXBvbmVudCwgSG9zdExpc3RlbmVyLCBJbnB1dCwgT25Jbml0IH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQge1xuICBBbGVydFNlcnZpY2UsXG4gIGdldHRleHQsXG4gIFBvcG92ZXJDb25maXJtQnV0dG9ucyxcbiAgUG9wb3ZlckNvbmZpcm1Db21wb25lbnRcbn0gZnJvbSAnQGM4eS9uZ3gtY29tcG9uZW50cyc7XG5pbXBvcnQgeyBJY29uU2VsZWN0b3JTZXJ2aWNlIH0gZnJvbSAnQGM4eS9uZ3gtY29tcG9uZW50cy9pY29uLXNlbGVjdG9yJztcbmltcG9ydCB7IGNsb25lRGVlcCB9IGZyb20gJ2xvZGFzaC1lcyc7XG5pbXBvcnQgeyBCc01vZGFsUmVmIH0gZnJvbSAnbmd4LWJvb3RzdHJhcC9tb2RhbCc7XG5pbXBvcnQgeyBCb29rbWFyayB9IGZyb20gJy4uL2Jvb2ttYXJrLm1vZGVsJztcbmltcG9ydCB7IEJvb2ttYXJrU2VydmljZSB9IGZyb20gJy4uL2Jvb2ttYXJrcy5zZXJ2aWNlJztcblxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnYzh5LWVkaXQtYm9va21hcmtzJyxcbiAgdGVtcGxhdGVVcmw6ICcuL2VkaXQtYm9va21hcmtzLmNvbXBvbmVudC5odG1sJ1xufSlcbmV4cG9ydCBjbGFzcyBFZGl0Qm9va21hcmtzQ29tcG9uZW50IGltcGxlbWVudHMgT25Jbml0IHtcbiAgQElucHV0KCkgYm9va21hcmtzOiBCb29rbWFya1tdO1xuICBwcml2YXRlIGJvb2ttYXJrc1RvVXBkYXRlOiBCb29rbWFya1tdO1xuXG4gIGNvbmZpcm1SZW1vdmVDb2x1bW5CdXR0b25zOiBQb3BvdmVyQ29uZmlybUJ1dHRvbnNbXSA9IFtcbiAgICB7XG4gICAgICBsYWJlbDogZ2V0dGV4dCgnQ2FuY2VsJyksXG4gICAgICBhY3Rpb246ICgpID0+IFByb21pc2UucmVzb2x2ZShmYWxzZSlcbiAgICB9LFxuICAgIHtcbiAgICAgIGxhYmVsOiBnZXR0ZXh0KCdEZWxldGUnKSxcbiAgICAgIHN0YXR1czogJ2RhbmdlcicsXG4gICAgICBhY3Rpb246ICgpID0+IFByb21pc2UucmVzb2x2ZSh0cnVlKVxuICAgIH1cbiAgXTtcblxuICByZXN1bHQ6IFByb21pc2U8Qm9va21hcmtbXT4gPSBuZXcgUHJvbWlzZShyZXNvbHZlID0+IHtcbiAgICB0aGlzLl9jbG9zZSA9IHJlc29sdmU7XG4gIH0pO1xuXG4gIHByaXZhdGUgX2Nsb3NlOiAodmFsdWU6IEJvb2ttYXJrW10pID0+IHZvaWQ7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSBic01vZGFsUmVmOiBCc01vZGFsUmVmLFxuICAgIHByaXZhdGUgYWxlcnRTZXJ2aWNlOiBBbGVydFNlcnZpY2UsXG4gICAgcHJpdmF0ZSBib29rbWFya1NlcnZpY2U6IEJvb2ttYXJrU2VydmljZSxcbiAgICBwcml2YXRlIGljb25TZWxlY3RvcjogSWNvblNlbGVjdG9yU2VydmljZVxuICApIHt9XG5cbiAgbmdPbkluaXQoKTogdm9pZCB7XG4gICAgdGhpcy5ib29rbWFya3NUb1VwZGF0ZSA9IGNsb25lRGVlcCh0aGlzLmJvb2ttYXJrcyk7XG4gIH1cblxuICBASG9zdExpc3RlbmVyKCdkb2N1bWVudDprZXlkb3duJywgWyckZXZlbnQnXSlcbiAgaGFuZGxlS2V5Ym9hcmRFdmVudChldmVudDogS2V5Ym9hcmRFdmVudCkge1xuICAgIGlmIChldmVudC5rZXkgPT09ICdFc2NhcGUnKSB7XG4gICAgICB0aGlzLmNsb3NlKCk7XG4gICAgfVxuICB9XG5cbiAgY2xvc2UoKTogdm9pZCB7XG4gICAgaWYgKHRoaXMuYm9va21hcmtTZXJ2aWNlLnVwZGF0ZWRCb29rbWFya3MpIHtcbiAgICAgIHRoaXMuX2Nsb3NlKHRoaXMuYm9va21hcmtTZXJ2aWNlLnVwZGF0ZWRCb29rbWFya3MpO1xuICAgIH1cbiAgICB0aGlzLmJzTW9kYWxSZWYuaGlkZSgpO1xuICB9XG5cbiAgYXN5bmMgZHJvcChldmVudDogQ2RrRHJhZ0Ryb3A8Qm9va21hcmtbXT4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB0cnkge1xuICAgICAgbW92ZUl0ZW1JbkFycmF5KHRoaXMuYm9va21hcmtzLCBldmVudC5wcmV2aW91c0luZGV4LCBldmVudC5jdXJyZW50SW5kZXgpO1xuICAgICAgbW92ZUl0ZW1JbkFycmF5KHRoaXMuYm9va21hcmtzVG9VcGRhdGUsIGV2ZW50LnByZXZpb3VzSW5kZXgsIGV2ZW50LmN1cnJlbnRJbmRleCk7XG5cbiAgICAgIGF3YWl0IHRoaXMuYm9va21hcmtTZXJ2aWNlLnVwZGF0ZUJvb2ttYXJrc0luU3RvcmFnZSh0aGlzLmJvb2ttYXJrc1RvVXBkYXRlKTtcbiAgICAgIHRoaXMuYWxlcnRTZXJ2aWNlLnN1Y2Nlc3MoZ2V0dGV4dCgnQm9va21hcmtzIG9yZGVyIHVwZGF0ZWQuJykpO1xuICAgIH0gY2F0Y2gge1xuICAgICAgdGhpcy5hbGVydFNlcnZpY2Uuc3VjY2VzcyhnZXR0ZXh0KCdCb29rbWFya3Mgb3JkZXIgZmFpbGVkIHRvIHVwZGF0ZS4nKSk7XG4gICAgfVxuICB9XG5cbiAgYXN5bmMgdXBkYXRlQm9va21hcmsoXG4gICAgdXBkYXRlZEJvb2ttYXJrOiBCb29rbWFyayxcbiAgICB0eXBlOiBrZXlvZiBQaWNrPEJvb2ttYXJrLCAnaWNvbicgfCAnbGFiZWwnIHwgJ21hcmtUb1JlbW92ZSc+XG4gICk6IFByb21pc2U8dm9pZD4ge1xuICAgIHRyeSB7XG4gICAgICB0aGlzLmJvb2ttYXJrc1RvVXBkYXRlID0gdGhpcy51cGRhdGVCb29rbWFya1Byb3BlcnR5KHVwZGF0ZWRCb29rbWFyaywgdHlwZSk7XG4gICAgICBhd2FpdCB0aGlzLmJvb2ttYXJrU2VydmljZS51cGRhdGVCb29rbWFya3NJblN0b3JhZ2UodGhpcy5ib29rbWFya3NUb1VwZGF0ZSk7XG4gICAgICBpZiAodHlwZSAhPT0gJ21hcmtUb1JlbW92ZScpIHtcbiAgICAgICAgdGhpcy5hbGVydFNlcnZpY2Uuc3VjY2VzcyhnZXR0ZXh0KCdCb29rbWFyayB1cGRhdGVkLicpKTtcbiAgICAgIH1cbiAgICB9IGNhdGNoIHtcbiAgICAgIGlmICh0eXBlICE9PSAnbWFya1RvUmVtb3ZlJykge1xuICAgICAgICB0aGlzLmFsZXJ0U2VydmljZS53YXJuaW5nKGdldHRleHQoJ0Jvb2ttYXJrIHVwZGF0ZSBmYWlsZWQnKSk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgdXBkYXRlQm9va21hcmtQcm9wZXJ0eShcbiAgICB1cGRhdGVkQm9va21hcms6IEJvb2ttYXJrLFxuICAgIHR5cGU6IGtleW9mIFBpY2s8Qm9va21hcmssICdpY29uJyB8ICdsYWJlbCcgfCAnbWFya1RvUmVtb3ZlJz5cbiAgKTogQm9va21hcmtbXSB7XG4gICAgY29uc3QgdXBkYXRlID0ge1xuICAgICAgaWNvbjogKGJvb2ttYXJrOiBCb29rbWFyaykgPT4gKHsgLi4uYm9va21hcmssIGljb246IHVwZGF0ZWRCb29rbWFyay5pY29uIH0pLFxuICAgICAgbGFiZWw6IChib29rbWFyazogQm9va21hcmspID0+ICh7IC4uLmJvb2ttYXJrLCBsYWJlbDogdXBkYXRlZEJvb2ttYXJrLmxhYmVsIH0pLFxuICAgICAgbWFya1RvUmVtb3ZlOiAoYm9va21hcms6IEJvb2ttYXJrKSA9PiAoeyAuLi5ib29rbWFyaywgbWFya1RvUmVtb3ZlOiB0cnVlIH0pXG4gICAgfVt0eXBlXTtcblxuICAgIHJldHVybiB0aGlzLmJvb2ttYXJrc1RvVXBkYXRlLm1hcChib29rbWFyayA9PlxuICAgICAgYm9va21hcmsuaWQgPT09IHVwZGF0ZWRCb29rbWFyay5pZCA/IHVwZGF0ZShib29rbWFyaykgOiBib29rbWFya1xuICAgICk7XG4gIH1cblxuICBhc3luYyBjaGFuZ2VCb29rbWFya0ljb24odXBkYXRlZEJvb2ttYXJrOiBCb29rbWFyayk6IFByb21pc2U8dm9pZD4ge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBuZXdJY29uID0gYXdhaXQgdGhpcy5pY29uU2VsZWN0b3Iuc2VsZWN0SWNvbigpO1xuICAgICAgdXBkYXRlZEJvb2ttYXJrLmljb24gPSBuZXdJY29uO1xuICAgICAgYXdhaXQgdGhpcy51cGRhdGVCb29rbWFyayh1cGRhdGVkQm9va21hcmssICdpY29uJyk7XG4gICAgfSBjYXRjaCB7XG4gICAgICAvLyBub3RoaW5nIHRvIGRvXG4gICAgfVxuICB9XG5cbiAgYXN5bmMgcmVtb3ZlQm9va21hcmsoXG4gICAgcG9Db25maXJtOiBQb3BvdmVyQ29uZmlybUNvbXBvbmVudCxcbiAgICBib29rbWFya1RvRGVsZXRlOiBCb29rbWFya1xuICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBwb0NvbmZpcm0ubWVzc2FnZSA9IGdldHRleHQoJ1RoaXMgYWN0aW9uIGlzIGlycmV2ZXJzaWJsZS4nKTtcblxuICAgIHRyeSB7XG4gICAgICBjb25zdCByZW1vdmUgPSBhd2FpdCBwb0NvbmZpcm0uc2hvdyh0aGlzLmNvbmZpcm1SZW1vdmVDb2x1bW5CdXR0b25zKTtcbiAgICAgIGlmICghcmVtb3ZlKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgYXdhaXQgdGhpcy51cGRhdGVCb29rbWFyayhib29rbWFya1RvRGVsZXRlLCAnbWFya1RvUmVtb3ZlJyk7XG5cbiAgICAgIGNvbnN0IGJvb2ttYXJrSW5kZXggPSB0aGlzLmJvb2ttYXJrcy5maW5kSW5kZXgoXG4gICAgICAgIGJvb2ttYXJrID0+IGJvb2ttYXJrLmlkID09PSBib29rbWFya1RvRGVsZXRlLmlkXG4gICAgICApO1xuXG4gICAgICBpZiAoYm9va21hcmtJbmRleCA9PT0gLTEpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICB0aGlzLmJvb2ttYXJrcy5zcGxpY2UoYm9va21hcmtJbmRleCwgMSk7XG4gICAgICB0aGlzLmFsZXJ0U2VydmljZS5zdWNjZXNzKGdldHRleHQoJ0Jvb2ttYXJrIHJlbW92ZWQuJykpO1xuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgLyoqXG4gICAgICAgKiBQcmV2ZW50cyBhbiBhbGVydCBtZXNzYWdlIGZyb20gYmVpbmcgZGlzcGxheWVkIGlmIHRoZSB1c2VyIGNsaWNrcyBvdXRzaWRlIG9mIGEgcG9wb3Zlci5cbiAgICAgICAqL1xuICAgICAgaWYgKGVycikge1xuICAgICAgICB0aGlzLmFsZXJ0U2VydmljZS53YXJuaW5nKGdldHRleHQoJ0Jvb2ttYXJrcyBkZWxldGlvbiBmYWlsZWQuJykpO1xuICAgICAgfVxuICAgIH1cbiAgfVxufVxuIiwiPGRpdiBjbGFzcz1cInZpZXdwb3J0LW1vZGFsXCI+XG4gIDxkaXYgY2xhc3M9XCJtb2RhbC1oZWFkZXIgZGlhbG9nLWhlYWRlclwiPlxuICAgIDxpIFtjOHlJY29uXT1cIidib29rbWFyaydcIj48L2k+XG4gICAgPGRpdlxuICAgICAgY2xhc3M9XCJoNFwiXG4gICAgICBpZD1cIm1vZGFsLXRpdGxlXCJcbiAgICAgIHRyYW5zbGF0ZVxuICAgID5cbiAgICAgIEJvb2ttYXJrc1xuICAgIDwvZGl2PlxuICA8L2Rpdj5cbiAgPGRpdlxuICAgIGNsYXNzPVwiaW5uZXItc2Nyb2xsXCJcbiAgICBpZD1cIm1vZGFsLWJvZHlcIlxuICA+XG4gICAgPGRpdiBjbGFzcz1cInAtMTYgdGV4dC1jZW50ZXIgc2VwYXJhdG9yLWJvdHRvbSBzdGlja3ktdG9wIGJnLWNvbXBvbmVudFwiPlxuICAgICAgPHAgY2xhc3M9XCJ0ZXh0LW1lZGl1bSB0ZXh0LTE2XCI+XG4gICAgICAgIHt7ICdSZW9yZGVyLCBlZGl0IG9yIGRlbGV0ZSBib29rbWFya3MuJyB8IHRyYW5zbGF0ZSB9fVxuICAgICAgPC9wPlxuICAgIDwvZGl2PlxuICAgIDxjOHktbGlzdC1ncm91cFxuICAgICAgY2xhc3M9XCJjZGstZHJvcGxpc3Qgbm8tYm9yZGVyLWxhc3RcIlxuICAgICAgKm5nSWY9XCJib29rbWFya3MubGVuZ3RoOyBlbHNlIGVtcHR5TGlzdFwiXG4gICAgICBjZGtEcm9wTGlzdFxuICAgICAgKGNka0Ryb3BMaXN0RHJvcHBlZCk9XCJkcm9wKCRldmVudClcIlxuICAgICAgW2Nka0Ryb3BMaXN0RGlzYWJsZWRdPVwiYm9va21hcmtzPy5sZW5ndGggPCAyXCJcbiAgICA+XG4gICAgICA8Yzh5LWxpXG4gICAgICAgICpuZ0Zvcj1cImxldCBib29rbWFyayBvZiBib29rbWFya3NcIlxuICAgICAgICBjZGtEcmFnXG4gICAgICA+XG4gICAgICAgIDxjOHktbGktZHJhZy1oYW5kbGVcbiAgICAgICAgICB0aXRsZT1cInt7ICdEcmFnIHRvIHJlb3JkZXInIHwgdHJhbnNsYXRlIH19XCJcbiAgICAgICAgICBjZGtEcmFnSGFuZGxlXG4gICAgICAgID5cbiAgICAgICAgICA8aSBjOHlJY29uPVwiZHJhZy1yZW9yZGVyXCI+PC9pPlxuICAgICAgICA8L2M4eS1saS1kcmFnLWhhbmRsZT5cbiAgICAgICAgPGM4eS1saS1pY29uXG4gICAgICAgICAgY2xhc3M9XCJpY29uLTI0IHAtcmVsYXRpdmUgY2hhbmdlSWNvbiBhLXMtc3RyZXRjaFwiXG4gICAgICAgICAgc3R5bGU9XCJ7eyBib29rbWFya3M/Lmxlbmd0aCA8IDIgPyAncGFkZGluZy1sZWZ0OiAxNnB4IWltcG9ydGFudCcgOiAnJyB9fVwiXG4gICAgICAgICAgKm5nSWY9XCJib29rbWFyay5pY29uXCJcbiAgICAgICAgPlxuICAgICAgICAgIDxpIFtjOHlJY29uXT1cImJvb2ttYXJrLmljb25cIj48L2k+XG4gICAgICAgICAgPGJ1dHRvblxuICAgICAgICAgICAgY2xhc3M9XCJidG4gYnRuLWRlZmF1bHQgYnRuLXhzXCJcbiAgICAgICAgICAgIFthdHRyLmFyaWEtbGFiZWxdPVwiJ0NoYW5nZSBpY29uJyB8IHRyYW5zbGF0ZVwiXG4gICAgICAgICAgICB0b29sdGlwPVwie3sgJ0NoYW5nZSBpY29uJyB8IHRyYW5zbGF0ZSB9fVwiXG4gICAgICAgICAgICBwbGFjZW1lbnQ9XCJ0b3BcIlxuICAgICAgICAgICAgY29udGFpbmVyPVwiYm9keVwiXG4gICAgICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgICAgIFtkZWxheV09XCI1MDBcIlxuICAgICAgICAgICAgW2FkYXB0aXZlUG9zaXRpb25dPVwiZmFsc2VcIlxuICAgICAgICAgICAgKGNsaWNrKT1cImNoYW5nZUJvb2ttYXJrSWNvbihib29rbWFyaylcIlxuICAgICAgICAgID5cbiAgICAgICAgICAgIDxpIGM4eUljb249XCJyZXBsYWNlXCI+PC9pPlxuICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICA8L2M4eS1saS1pY29uPlxuXG4gICAgICAgIDxkaXYgY2xhc3M9XCJkLWZsZXggZ2FwLTggYS1pLWNlbnRlclwiPlxuICAgICAgICAgIDxmb3JtXG4gICAgICAgICAgICBjbGFzcz1cImQtZmxleCBmbGV4LWdyb3dcIlxuICAgICAgICAgICAgbmFtZT1cImJvb2ttYXJrc0Zvcm1cIlxuICAgICAgICAgICAgI2Jvb2ttYXJrc0Zvcm09XCJuZ0Zvcm1cIlxuICAgICAgICAgID5cbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJpbnB1dC1ncm91cCBpbnB1dC1ncm91cC1lZGl0YWJsZVwiPlxuICAgICAgICAgICAgICA8aW5wdXRcbiAgICAgICAgICAgICAgICBjbGFzcz1cImZvcm0tY29udHJvbCBmaXQtd1wiXG4gICAgICAgICAgICAgICAgdGl0bGU9XCJ7eyBib29rbWFyay5sYWJlbCB9fVwiXG4gICAgICAgICAgICAgICAgaWQ9XCJsYWJlbFwiXG4gICAgICAgICAgICAgICAgbmFtZT1cImxhYmVsXCJcbiAgICAgICAgICAgICAgICB0eXBlPVwidGV4dFwiXG4gICAgICAgICAgICAgICAgWyhuZ01vZGVsKV09XCJib29rbWFyay5sYWJlbFwiXG4gICAgICAgICAgICAgICAgI2xhYmVsPVwibmdNb2RlbFwiXG4gICAgICAgICAgICAgICAgbWF4bGVuZ3RoPVwiNTBcIlxuICAgICAgICAgICAgICAgIFtwbGFjZWhvbGRlcl09XCInZS5nLiBNeSBib29rbWFyaycgfCB0cmFuc2xhdGVcIlxuICAgICAgICAgICAgICAvPlxuICAgICAgICAgICAgICA8c3Bhbj48L3NwYW4+XG4gICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJpbnB1dC1ncm91cC1idG5cIj5cbiAgICAgICAgICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgICAgICAgICBjbGFzcz1cImJ0biBidG4tcHJpbWFyeVwiXG4gICAgICAgICAgICAgICAgICB0aXRsZT1cInt7ICdTYXZlJyB8IHRyYW5zbGF0ZSB9fVwiXG4gICAgICAgICAgICAgICAgICB0eXBlPVwic3VibWl0XCJcbiAgICAgICAgICAgICAgICAgIChjbGljayk9XCJ1cGRhdGVCb29rbWFyayhib29rbWFyaywgJ2xhYmVsJyk7IGxhYmVsLmNvbnRyb2wubWFya0FzUHJpc3RpbmUoKVwiXG4gICAgICAgICAgICAgICAgICBbZGlzYWJsZWRdPVwibGFiZWwuaW52YWxpZFwiXG4gICAgICAgICAgICAgICAgPlxuICAgICAgICAgICAgICAgICAge3sgJ1NhdmUnIHwgdHJhbnNsYXRlIH19XG4gICAgICAgICAgICAgICAgPC9idXR0b24+XG4gICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgPC9mb3JtPlxuICAgICAgICAgIDxjOHktcG9wb3Zlci1jb25maXJtXG4gICAgICAgICAgICBjbGFzcz1cImQtYmxvY2tcIlxuICAgICAgICAgICAgW3RpdGxlXT1cIidEZWxldGUgYm9va21hcmsnIHwgdHJhbnNsYXRlXCJcbiAgICAgICAgICAgIFtwbGFjZW1lbnRdPVwiJ2xlZnQnXCJcbiAgICAgICAgICAgIFtvdXRzaWRlQ2xpY2tdPVwidHJ1ZVwiXG4gICAgICAgICAgICBbYWRhcHRpdmVQb3NpdGlvbl09XCJ0cnVlXCJcbiAgICAgICAgICAgIFtjb250YWluZXJdPVwiJydcIlxuICAgICAgICAgICAgI3BvQ29uZmlybVxuICAgICAgICAgID5cbiAgICAgICAgICAgIDxidXR0b25cbiAgICAgICAgICAgICAgY2xhc3M9XCJidG4gYnRuLWRvdCBidG4tZG90LS1kYW5nZXIgbS1sLWF1dG9cIlxuICAgICAgICAgICAgICB0aXRsZT1cInt7ICdEZWxldGUnIHwgdHJhbnNsYXRlIH19XCJcbiAgICAgICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgICAgIChjbGljayk9XCJyZW1vdmVCb29rbWFyayhwb0NvbmZpcm0sIGJvb2ttYXJrKVwiXG4gICAgICAgICAgICA+XG4gICAgICAgICAgICAgIDxpIGM4eUljb249XCJtaW51cy1jaXJjbGVcIj48L2k+XG4gICAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgICA8L2M4eS1wb3BvdmVyLWNvbmZpcm0+XG4gICAgICAgIDwvZGl2PlxuICAgICAgPC9jOHktbGk+XG4gICAgPC9jOHktbGlzdC1ncm91cD5cbiAgPC9kaXY+XG4gIDxkaXYgY2xhc3M9XCJtb2RhbC1mb290ZXJcIj5cbiAgICA8YnV0dG9uXG4gICAgICBjbGFzcz1cImJ0biBidG4tZGVmYXVsdFwiXG4gICAgICB0aXRsZT1cInt7ICdDYW5jZWwnIHwgdHJhbnNsYXRlIH19XCJcbiAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgKGNsaWNrKT1cImNsb3NlKClcIlxuICAgID5cbiAgICAgIHt7ICdDbG9zZScgfCB0cmFuc2xhdGUgfX1cbiAgICA8L2J1dHRvbj5cbiAgPC9kaXY+XG48L2Rpdj5cbjxuZy10ZW1wbGF0ZSAjZW1wdHlMaXN0PlxuICA8Yzh5LXVpLWVtcHR5LXN0YXRlXG4gICAgW2ljb25dPVwiJ2Jvb2ttYXJrJ1wiXG4gICAgW3RpdGxlXT1cIidObyBib29rbWFya3MgeWV0JyB8IHRyYW5zbGF0ZVwiXG4gICAgW3N1YnRpdGxlXT1cIlxuICAgICAgJ05hdmlnYXRlIHRvIHRoZSBkZXNpcmVkIHBhZ2UsIG9wZW4gdGhlIHJpZ2h0IGRyYXdlciBhbmQgY2xpY2sgdGhlICZxdW90O0FkZCBjdXJyZW50IHBhZ2UmcXVvdDsgYnV0dG9uLidcbiAgICAgICAgfCB0cmFuc2xhdGVcbiAgICBcIlxuICAgIFtob3Jpem9udGFsXT1cInRydWVcIlxuICA+PC9jOHktdWktZW1wdHktc3RhdGU+XG48L25nLXRlbXBsYXRlPlxuIl19