@libs-ui/services-grid-layout 0.2.357-21 → 0.2.357-23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +116 -1
- package/canvas/grid-layout-canvas.component.d.ts +1 -0
- package/defines/collision.define.d.ts +26 -1
- package/drag-controller.d.ts +34 -0
- package/esm2022/canvas/grid-layout-canvas.component.mjs +6 -3
- package/esm2022/defines/collision.define.mjs +75 -1
- package/esm2022/drag-controller.mjs +89 -0
- package/esm2022/grid-layout.service.mjs +130 -2
- package/esm2022/index.mjs +2 -1
- package/esm2022/interfaces/grid-layout.interface.mjs +1 -1
- package/fesm2022/libs-ui-services-grid-layout.mjs +295 -4
- package/fesm2022/libs-ui-services-grid-layout.mjs.map +1 -1
- package/grid-layout.service.d.ts +54 -0
- package/index.d.ts +1 -0
- package/interfaces/grid-layout.interface.d.ts +16 -0
- package/package.json +3 -3
|
@@ -246,6 +246,9 @@ export class LibsUiGridLayoutCanvasComponent {
|
|
|
246
246
|
this.service.FunctionsControl.setZoom(val, this.storageKey());
|
|
247
247
|
this.syncZoomOut();
|
|
248
248
|
},
|
|
249
|
+
// Vùng cuộn của mặt phẳng — nơi dùng cần nó để tự cuộn tới một khối, hoặc đo toạ độ khi kéo.
|
|
250
|
+
// Không mở ở đây thì nơi dùng phải dò bằng tên lớp CSS nội bộ, và tên đó đổi lúc nào không hay.
|
|
251
|
+
scrollArea: () => this.scrollAreaRef()?.nativeElement,
|
|
249
252
|
};
|
|
250
253
|
}
|
|
251
254
|
handlerZoomIn() {
|
|
@@ -554,11 +557,11 @@ export class LibsUiGridLayoutCanvasComponent {
|
|
|
554
557
|
}
|
|
555
558
|
}
|
|
556
559
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: LibsUiGridLayoutCanvasComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
557
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: LibsUiGridLayoutCanvasComponent, isStandalone: true, selector: "libs_ui-services-grid_layout-canvas", inputs: { node: { classPropertyName: "node", publicName: "node", isSignal: true, isRequired: false, transformFunction: null }, depth: { classPropertyName: "depth", publicName: "depth", isSignal: true, isRequired: false, transformFunction: null }, hiddenToolbar: { classPropertyName: "hiddenToolbar", publicName: "hiddenToolbar", isSignal: true, isRequired: false, transformFunction: null }, templateToolbar: { classPropertyName: "templateToolbar", publicName: "templateToolbar", isSignal: true, isRequired: false, transformFunction: null }, enableZoom: { classPropertyName: "enableZoom", publicName: "enableZoom", isSignal: true, isRequired: false, transformFunction: null }, zoom: { classPropertyName: "zoom", publicName: "zoom", isSignal: true, isRequired: false, transformFunction: null }, zoomMin: { classPropertyName: "zoomMin", publicName: "zoomMin", isSignal: true, isRequired: false, transformFunction: null }, zoomMax: { classPropertyName: "zoomMax", publicName: "zoomMax", isSignal: true, isRequired: false, transformFunction: null }, zoomStep: { classPropertyName: "zoomStep", publicName: "zoomStep", isSignal: true, isRequired: false, transformFunction: null }, stageWidth: { classPropertyName: "stageWidth", publicName: "stageWidth", isSignal: true, isRequired: false, transformFunction: null }, stageMinHeight: { classPropertyName: "stageMinHeight", publicName: "stageMinHeight", isSignal: true, isRequired: false, transformFunction: null }, storageKey: { classPropertyName: "storageKey", publicName: "storageKey", isSignal: true, isRequired: false, transformFunction: null }, showZoomDock: { classPropertyName: "showZoomDock", publicName: "showZoomDock", isSignal: true, isRequired: false, transformFunction: null }, autoFitOnLoad: { classPropertyName: "autoFitOnLoad", publicName: "autoFitOnLoad", isSignal: true, isRequired: false, transformFunction: null }, enableExternalDrop: { classPropertyName: "enableExternalDrop", publicName: "enableExternalDrop", isSignal: true, isRequired: false, transformFunction: null }, showGridLines: { classPropertyName: "showGridLines", publicName: "showGridLines", isSignal: true, isRequired: false, transformFunction: null }, selectedNodeId: { classPropertyName: "selectedNodeId", publicName: "selectedNodeId", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { outChange: "outChange", outRemoveNode: "outRemoveNode", outAddBlockInside: "outAddBlockInside", outToggleType: "outToggleType", zoom: "zoomChange", outZoomChange: "outZoomChange", selectedNodeId: "selectedNodeIdChange", outDropNode: "outDropNode", outSelectNode: "outSelectNode", outConfigNode: "outConfigNode" }, host: { listeners: { "document:keydown": "handlerDocumentKeyDown($event)", "document:click": "handlerDocumentClick($event)" } }, viewQueries: [{ propertyName: "gridsterRef", first: true, predicate: GridsterComponent, descendants: true, isSignal: true }, { propertyName: "scrollAreaRef", first: true, predicate: ["scrollArea"], descendants: true, isSignal: true }, { propertyName: "zoomDockRef", first: true, predicate: ["zoomDock"], descendants: true, isSignal: true }, { propertyName: "itemHosts", predicate: ["itemHost"], descendants: true, read: ViewContainerRef, isSignal: true }], ngImport: i0, template: "@if (isZoomActive()) {\n <!-- Khu v\u1EF1c cu\u1ED9n ch\u1EE9a canvas stage thu ph\u00F3ng -->\n <div\n #scrollArea\n class=\"libs-ui-grid-layout-scroll-area relative h-full min-h-0 w-full min-w-0 overflow-auto p-6 flex justify-center items-start\"\n (mousedown)=\"handlerMouseDownTrongLuoi($event)\"\n (wheel)=\"handlerWheel($event)\"\n (dragover)=\"handlerDragOver($event)\"\n (dragleave)=\"handlerDragLeave($event)\"\n (drop)=\"handlerDrop($event)\">\n <div\n #canvasStage\n id=\"bi-canvas-stage\"\n class=\"libs-ui-grid-layout-stage relative flex flex-col transition-[zoom] duration-150 origin-top shrink-0 bg-white/80 border border-slate-200/80 rounded-2xl shadow-sm p-4\"\n [style.zoom]=\"currentZoom()\"\n [style.width.px]=\"stageWidth()\"\n [style.min-width.px]=\"stageWidth()\"\n [style.min-height.px]=\"stageMinHeight()\">\n <!-- Snapped Drop Ghost Preview -->\n @if (dropGhost(); as ghost) {\n <div\n class=\"pointer-events-none absolute z-30 flex flex-col items-center justify-center overflow-hidden rounded-lg border-2 border-dashed border-blue-500 bg-blue-500/15 p-1 shadow-sm transition-all duration-75 ease-out backdrop-blur-[0.5px] select-none\"\n [style.left.px]=\"ghost.pixelLeft\"\n [style.top.px]=\"ghost.pixelTop\"\n [style.width.px]=\"ghost.pixelWidth\"\n [style.height.px]=\"ghost.pixelHeight\">\n <div class=\"inline-flex max-w-[95%] items-center gap-1 truncate rounded-md bg-blue-600 px-2 py-0.5 text-[11px] font-semibold text-white shadow-xs\">\n @if (ghost.cardIconClass) {\n <i [class]=\"ghost.cardIconClass + ' text-xs'\"></i>\n } @else if (ghost.cardIconText) {\n <span class=\"text-[10px] font-bold\">{{ ghost.cardIconText }}</span>\n } @else {\n <span class=\"text-xs font-bold\">{{ ghost.isInsideGroup ? '\u21B3' : '+' }}</span>\n }\n <span class=\"truncate\">{{ ghost.cardTitle }}</span>\n <span class=\"text-[9px] font-mono opacity-75\">({{ ghost.cols }}c)</span>\n </div>\n\n @if (ghost.pixelHeight >= 80) {\n <div class=\"mt-1 flex max-w-[95%] items-center gap-1.5 truncate rounded border border-blue-100 bg-white/95 px-2 py-0.5 text-[10px] font-medium text-blue-700 shadow-xs\">\n @if (ghost.isInsideGroup) {\n <span class=\"truncate font-bold text-blue-900\">\u21B3 {{ ghost.groupTitle }}</span>\n <span class=\"text-blue-300\">\u2022</span>\n }\n <span>C\u1ED9t {{ ghost.col + 1 }}-{{ ghost.col + ghost.cols }}</span>\n </div>\n }\n </div>\n }\n <gridster class=\"h-full w-full\" [class.display-grid]=\"showGridLines()\" [options]=\"gridOptions()\">\n @for (item of children(); track item.id; let itemIndex = $index) {\n <!-- \uD83D\uDD34 Ch\u1EB7n `mousedown` t\u1EA1i \u0110\u00C2Y cho l\u01B0\u1EDBi l\u1ED3ng \u2014 C\u1EA4M b\u1ECF v\u00E0 C\u1EA4M chuy\u1EC3n sang ch\u1ED7 kh\u00E1c.\n `ignoreContentClass` m\u1ED9t m\u00ECnh KH\u00D4NG \u0111\u1EE7: `delayStart: 160` l\u00E0m M\u1ED6I l\u01B0\u1EDBi l\u00EAn l\u1ECBch\n `dragStart` b\u1EB1ng `setTimeout` ngay t\u1EA1i `mousedown`, c\u00F2n `stopPropagation` m\u00E0 lib g\u1ECDi b\u00EAn\n trong `dragStart` ch\u1EA1y sau 160ms n\u00EAn qu\u00E1 mu\u1ED9n \u2014 l\u01B0\u1EDBi CHA \u0111\u00E3 k\u1ECBp nh\u1EADn (\u0111o 28/08/2026: k\u00E9o\n d\u1EA3i kh\u1ED1i con, chu\u1ED7i class duy\u1EC7t l\u00EAn \u0110\u00DANG m\u00E0 container v\u1EABn nh\u1EA3y 0,0 \u2192 0,1).\n G\u1EAFn \u1EDF `gridster-item` l\u00E0 \u0111\u00FAng bi\u00EAn: l\u01B0\u1EDBi con nghe tr\u00EAn ch\u00EDnh ph\u1EA7n t\u1EED n\u00E0y n\u00EAn \u0111\u00E3 nh\u1EADn xong,\n l\u01B0\u1EDBi cha \u1EDF ngo\u00E0i b\u1ECB ch\u1EB7n. -->\n <gridster-item\n [item]=\"item\"\n [class.libs-ui-grid-layout-selected]=\"selectedNodeId() === item.id\"\n (click)=\"handlerSelectNode(item, $event)\"\n (mousedown)=\"handlerBlockParentDrag($event)\">\n <!-- \uD83D\uDD34 V\u1ECF n\u00E0y mang `dragHandleClass` \u2014 C\u1EA4M b\u1ECF.\n `ignoreContent: true` b\u1EAFt gridster CH\u1EC8 cho k\u00E9o khi ch\u1ED7 b\u1EA5m n\u1EB1m d\u01B0\u1EDBi m\u1ED9t ph\u1EA7n t\u1EED c\u00F3\n `dragHandleClass`. Kh\u00F4ng c\u00F3 v\u1ECF n\u00E0y th\u00EC component c\u1EE7a n\u01A1i d\u00F9ng (th\u01B0 vi\u1EC7n kh\u00F4ng ki\u1EC3m so\u00E1t\n \u0111\u01B0\u1EE3c class c\u1EE7a n\u00F3) s\u1EBD kh\u00F4ng c\u00F3 tay c\u1EA7m n\u00E0o, v\u00E0 KH\u00D4NG kh\u1ED1i n\u00E0o k\u00E9o \u0111\u01B0\u1EE3c \u2014 \u0111o 28/08/2026:\n k\u00E9o 320px, to\u1EA1 \u0111\u1ED9 kh\u1ED1i gi\u1EEF nguy\u00EAn x=3,y=0.\n T\u00EAn class theo c\u1EA5p: l\u01B0\u1EDBi trang v\u00E0 l\u01B0\u1EDBi l\u1ED3ng d\u00F9ng hai t\u00EAn KH\u00C1C nhau, n\u1EBFu kh\u00F4ng l\u01B0\u1EDBi cha\n c\u0169ng nh\u1EADn ra tay c\u1EA7m c\u1EE7a kh\u1ED1i con v\u00E0 nh\u1EA5c lu\u00F4n container. -->\n <!-- \uD83D\uDD34 V\u1ECF KH\u00D4NG mang `dragHandleClass` \u2014 C\u1EA4M th\u00EAm l\u1EA1i.\n K\u00E9o ch\u1EC9 \u0111\u01B0\u1EE3c ph\u00E9p b\u1EAFt \u0111\u1EA7u t\u1EEB D\u1EA2I XANH (ng\u01B0\u1EDDi d\u00F9ng ch\u1ED1t 28/08/2026: \"ph\u1EA3i hover v\u00E0o v\u00F9ng\n m\u00E0u xanh th\u00EC m\u1EDBi k\u00E9o th\u1EA3 \u0111\u01B0\u1EE3c cho \u0111\u1ED3ng nh\u1EA5t\"). Cho c\u1EA3 v\u1ECF l\u00E0m tay c\u1EA7m th\u00EC b\u1EA5m \u0111\u00E2u c\u0169ng\n k\u00E9o, v\u00E0 kh\u1ED1i con n\u1EB1m trong container s\u1EBD nh\u1EA5c lu\u00F4n container v\u00EC l\u01B0\u1EDBi cha duy\u1EC7t l\u00EAn g\u1EB7p\n tay c\u1EA7m c\u1EE7a v\u1ECF container tr\u01B0\u1EDBc.\n V\u1ECF kh\u1ED1i con v\u1EABn gi\u1EEF class CH\u1EB6N \u0111\u1EC3 l\u01B0\u1EDBi cha d\u1EEBng \u0111\u00FAng \u1EDF bi\u00EAn. -->\n <div\n class=\"libs-ui-grid-layout-block-shell group relative h-full w-full min-w-0\"\n [class.libs-ui-grid-layout-block-parent-drag]=\"isNestedCanvas()\">\n <!-- D\u1EA3i k\u00E9o: hi\u1EC7n khi r\u00EA chu\u1ED9t v\u00E0o kh\u1ED1i, ba ch\u1EA5m l\u00E0 d\u1EA5u hi\u1EC7u k\u00E9o quen thu\u1ED9c.\n Ng\u01B0\u1EDDi d\u00F9ng c\u1EA7n m\u1ED9t ch\u1ED7 b\u00E1m R\u00D5 R\u00C0NG thay v\u00EC \u0111o\u00E1n xem b\u1EA5m \u0111\u00E2u th\u00EC k\u00E9o \u0111\u01B0\u1EE3c\n (ch\u1ED1t 28/08/2026, theo \u0111\u00FAng d\u1EA3i \u0111ang d\u00F9ng \u1EDF m\u00E0n Customer 360 c\u1EE7a mobio-web). -->\n @if (isEditMode()) {\n <!-- \uD83D\uDD34 D\u1EA3i PH\u1EA2I mang tay c\u1EA7m \u0110\u00DANG C\u1EA4P c\u1EE7a n\u00F3. D\u1EA3i nh\u1EADn chu\u1ED9t (`pointer-events: auto`),\n n\u00EAn n\u1EBFu kh\u00F4ng mang tay c\u1EA7m th\u00EC `checkDragHandleClass` duy\u1EC7t l\u00EAn g\u1EB7p tay c\u1EA7m c\u1EE7a\n container v\u00E0 nh\u1EA5c container thay v\u00EC kh\u1ED1i con (\u0111o 28/08/2026: k\u00E9o d\u1EA3i kh\u1ED1i con,\n container nh\u1EA3y 0,0 \u2192 0,1 c\u00F2n kh\u1ED1i con \u0111\u1EE9ng im).\n \uD83D\uDD34 D\u1EA3i CH\u1EC8 mang tay c\u1EA7m, C\u1EA4M mang th\u00EAm class ch\u1EB7n: `checkDragHandleClass` x\u00E9t hai\n class \u0111\u00F3 tr\u00EAn C\u00D9NG m\u1ED9t node n\u00EAn \u0111\u1EC3 chung l\u00E0 k\u00E9o h\u1ECFng (\u0111o 28/08/2026: b\u1EA5m d\u1EA3i kh\u1ED1i\n con k\u00E9o 140px, kh\u1ED1i \u0111\u1EE9ng im). Vi\u1EC7c ch\u1EB7n l\u01B0\u1EDBi cha do V\u1ECE KH\u1ED0I lo. -->\n <div\n class=\"libs-ui-grid-layout-drag-bar\"\n [class.libs-ui-grid-layout-drag-bar-child]=\"isNestedCanvas()\"\n [class.libs-ui-grid-layout-drag-handle]=\"!isNestedCanvas()\"\n [class.libs-ui-grid-layout-drag-handle-child]=\"isNestedCanvas()\">\n <span class=\"libs-ui-grid-layout-drag-bar-dots\">\n @for (dot of dragBarDots; track dot) {\n <span class=\"libs-ui-grid-layout-drag-bar-dot\"></span>\n }\n </span>\n </div>\n }\n\n <!-- Khung ch\u1EE9a component c\u1EE7a n\u01A1i d\u00F9ng.\n \uD83D\uDD34 PH\u1EA2I c\u00F3 khung th\u1EADt (kh\u00F4ng ph\u1EA3i `ng-container` tr\u1ED1ng): n\u00F3 lo h\u1ED9 n\u01A1i d\u00F9ng ph\u1EA7n l\u1EA5p \u0111\u1EA7y\n \u00F4 v\u00E0 vi\u1EC1n b\u00E1o ch\u1EBF \u0111\u1ED9 s\u1EEDa. Kh\u00F4ng c\u00F3 khung th\u00EC m\u1ED7i component n\u1ED9i dung l\u1EA1i ph\u1EA3i t\u1EF1 vi\u1EBFt\n `:host { width/height: 100% }` + vi\u1EC1n \u0111\u1EE9t \u2014 \u0111\u00F3 l\u00E0 vi\u1EC7c c\u1EE7a th\u01B0 vi\u1EC7n, kh\u00F4ng ph\u1EA3i c\u1EE7a\n ng\u01B0\u1EDDi d\u00F9ng (ng\u01B0\u1EDDi d\u00F9ng ch\u1ED1t 28/08/2026).\n M\u1ED7i kh\u1ED1i m\u1ED9t ViewContainerRef ri\u00EAng n\u00EAn component n\u1EB1m \u0111\u00FAng \u00F4 c\u1EE7a n\u00F3. -->\n <div\n class=\"libs-ui-grid-layout-content-frame\"\n [class.libs-ui-grid-layout-content-frame-edit]=\"isEditMode() && !isContainer(item)\"\n [class.libs-ui-grid-layout-content-frame-empty]=\"isContainer(item)\">\n <ng-container #itemHost />\n </div>\n\n <!-- D\u1EA5u hi\u1EC7u CONTAINER: nh\u00E3n g\u00F3c tr\u00EAn-ph\u1EA3i + vi\u1EC1n \u0111\u1EE9t bao ru\u1ED9t. Kh\u00F4ng c\u00F3 d\u1EA5u hi\u1EC7u th\u00EC\n ng\u01B0\u1EDDi d\u00F9ng kh\u00F4ng bi\u1EBFt kh\u1ED1i n\u00E0o ch\u1EE9a \u0111\u01B0\u1EE3c kh\u1ED1i kh\u00E1c (ch\u1ED1t 28/08/2026, theo \u0111\u00FAng c\u00E1ch\n m\u00E0n Customer 360 c\u1EE7a mobio-web \u0111ang l\u00E0m). -->\n @if (isEditMode() && isContainer(item)) {\n <div class=\"libs-ui-grid-layout-container-label\">{{ 'i18n_container_block' | translate }}</div>\n <div class=\"libs-ui-grid-layout-container-border\"></div>\n }\n\n <!-- Thanh c\u00F4ng c\u1EE5: hi\u1EC7n khi r\u00EA chu\u1ED9t v\u00E0o kh\u1ED1i.\n \uD83D\uDD34 D\u00F9ng `libs_ui-components-buttons-button` \u2014 C\u1EA4M t\u1EF1 d\u1EF1ng th\u1EBB `<button>`.\n Component n\u00E0y \u0111\u00E3 c\u00F3 s\u1EB5n ki\u1EC3u n\u00FAt, c\u1EE1 n\u00FAt v\u00E0 bong b\u00F3ng ch\u00FA th\u00EDch theo \u0111\u00FAng b\u1ED9 giao di\u1EC7n\n c\u1EE7a s\u1EA3n ph\u1EA9m; t\u1EF1 d\u1EF1ng l\u00E0 m\u1ED7i n\u01A1i m\u1ED9t ki\u1EC3u v\u00E0 m\u1EA5t lu\u00F4n tooltip. -->\n @if (isEditMode() && !hiddenToolbar()) {\n @if (templateToolbar()) {\n <!-- N\u01A1i d\u00F9ng t\u1EF1 v\u1EBD thanh c\u00F4ng c\u1EE5: nh\u1EADn kh\u1ED1i + c\u00E1c h\u00E0m ph\u00E1t event qua context.\n\n \uD83D\uDD34 Kh\u1ED1i b\u1ECDc t\u1EF1 ch\u1EB7n `mousedown`/`click` n\u1ED5i l\u00EAn gridster. Thanh c\u00F4ng c\u1EE5 n\u1EB1m trong\n v\u00F9ng mang `dragHandleClass`; kh\u00F4ng ch\u1EB7n th\u00EC c\u00FA b\u1EA5m b\u1ECB hi\u1EC3u l\u00E0 b\u1EAFt \u0111\u1EA7u k\u00E9o v\u00E0\n `delayStart: 160` nu\u1ED1t lu\u00F4n `click` \u2014 n\u00FAt trong template ngo\u00E0i b\u1EA5m kh\u00F4ng \u0103n\n (\u0111o 09/09/2026: b\u1EA5m b\u1EB1ng `.click()` c\u1EE7a DOM th\u00EC m\u1EDF, b\u1EA5m chu\u1ED9t th\u1EADt th\u00EC kh\u00F4ng).\n Ch\u1EB7n \u1EDF \u0110\u00C2Y \u0111\u1EC3 n\u01A1i d\u00F9ng kh\u00F4ng ph\u1EA3i bi\u1EBFt b\u1EABy n\u00E0y. -->\n <div\n class=\"libs-ui-grid-layout-toolbar\"\n role=\"toolbar\"\n tabindex=\"0\"\n [class.libs-ui-grid-layout-toolbar-child]=\"isNestedCanvas()\"\n (mousedown)=\"handlerStopEvent($event)\"\n (keydown)=\"handlerStopEvent($event)\"\n (click)=\"handlerStopEvent($event)\">\n <ng-container\n *ngTemplateOutlet=\"templateToolbar()!; context: toolbarContexts()[itemIndex]\" />\n </div>\n } @else {\n <div\n class=\"libs-ui-grid-layout-toolbar\"\n [class.libs-ui-grid-layout-toolbar-child]=\"isNestedCanvas()\">\n <span class=\"libs-ui-grid-layout-dim-badge\">\n {{ item.rows }} h\u00E0ng \u00D7 {{ item.cols }} c\u1ED9t\n </span>\n @if (canAddInside(item)) {\n <libs_ui-components-buttons-button\n [type]=\"'button-third'\"\n [iconOnlyType]=\"true\"\n [sizeButton]=\"'smaller'\"\n [classIconLeft]=\"'libs-ui-icon-add'\"\n [popover]=\"{ config: { content: 'Th\u00EAm kh\u1ED1i v\u00E0o trong', zIndex: 1300 } }\"\n (outClick)=\"handlerAddInside($event, item)\" />\n }\n @if (canToggleType(item)) {\n <libs_ui-components-buttons-button\n [type]=\"'button-third'\"\n [iconOnlyType]=\"true\"\n [sizeButton]=\"'smaller'\"\n [classIconLeft]=\"isContainer(item) ? 'libs-ui-icon-split-cell' : 'libs-ui-icon-merge-cell'\"\n [popover]=\"{ config: { content: isContainer(item) ? '\u0110\u01B0a v\u1EC1 kh\u1ED1i \u0111\u01A1n' : 'Chuy\u1EC3n th\u00E0nh kh\u1ED1i gh\u00E9p', zIndex: 1300 } }\"\n (outClick)=\"handlerToggleType($event, item)\" />\n }\n <libs_ui-components-buttons-button\n [type]=\"'button-third'\"\n [iconOnlyType]=\"true\"\n [sizeButton]=\"'smaller'\"\n [classIconLeft]=\"'libs-ui-icon-setting'\"\n [popover]=\"{ config: { content: 'C\u1EA5u h\u00ECnh th\u1EBB', zIndex: 1300 } }\"\n (outClick)=\"handlerConfig($event, item)\" />\n <libs_ui-components-buttons-button\n [type]=\"'button-third-hover-danger'\"\n [iconOnlyType]=\"true\"\n [sizeButton]=\"'smaller'\"\n [classIconLeft]=\"'libs-ui-icon-remove'\"\n [popover]=\"{ config: { content: isContainer(item) ? 'Xo\u00E1 c\u1EA3 kh\u1ED1i gh\u00E9p' : 'Xo\u00E1 kh\u1ED1i', zIndex: 1300 } }\"\n (outClick)=\"handlerRemove($event, item)\" />\n </div>\n }\n }\n\n @if (item.children && item.children.length > 0) {\n <!-- Kh\u1ED1i c\u00F3 con \u2192 ru\u1ED9t n\u00F3 l\u1EA1i l\u00E0 m\u1ED9t m\u1EB7t ph\u1EB3ng n\u1EEFa. \u0110\u1EC7 quy \u1EDF \u0111\u00E2y, n\u01A1i d\u00F9ng kh\u00F4ng ph\u1EA3i lo.\n L\u1EC1 \u0111\u1EB7t \u1EDF \u0110\u00C2Y (v\u1ECF container), kh\u00F4ng \u0111\u1EB7t v\u00E0o l\u01B0\u1EDBi con \u2014 l\u01B0\u1EDBi con gi\u1EEF nguy\u00EAn khe 2px. -->\n <libs_ui-services-grid_layout-canvas\n class=\"block h-full w-full\"\n [style.padding]=\"containerPadding()\"\n [node]=\"item\"\n [depth]=\"depth() + 1\"\n [hiddenToolbar]=\"hiddenToolbar()\"\n [templateToolbar]=\"templateToolbar()\"\n [selectedNodeId]=\"selectedNodeId()\"\n (outSelectNode)=\"outSelectNode.emit($event)\"\n (outConfigNode)=\"outConfigNode.emit($event)\"\n (outChange)=\"outChange.emit($event)\"\n (outRemoveNode)=\"outRemoveNode.emit($event)\"\n (outAddBlockInside)=\"outAddBlockInside.emit($event)\"\n (outToggleType)=\"outToggleType.emit($event)\" />\n }\n </div>\n </gridster-item>\n }\n </gridster>\n </div>\n </div>\n\n <!-- Thanh dock \u0111i\u1EC1u khi\u1EC3n thu ph\u00F3ng n\u1ED5i \u1EDF g\u00F3c d\u01B0\u1EDBi ph\u1EA3i -->\n @if (showZoomDock()) {\n <div\n #zoomDock\n id=\"canvas-zoom-dock\"\n role=\"toolbar\"\n tabindex=\"0\"\n class=\"absolute bottom-4 right-6 z-30 flex items-center bg-white/95 backdrop-blur-md rounded-full shadow-lg border border-slate-300/80 p-1 space-x-1 select-none\"\n (mousedown)=\"$event.stopPropagation()\"\n (keydown)=\"$event.stopPropagation()\"\n (click)=\"$event.stopPropagation()\">\n <!-- Thu nh\u1ECF (-) -->\n <button\n type=\"button\"\n class=\"w-7 h-7 flex items-center justify-center rounded-full text-slate-600 hover:text-slate-900 hover:bg-slate-100 disabled:opacity-30 disabled:hover:bg-transparent transition-colors cursor-pointer\"\n [disabled]=\"currentZoom() <= zoomMin()\"\n [title]=\"'i18n_zoom_out' | translate\"\n (click)=\"handlerZoomOut()\">\n <svg class=\"w-3.5 h-3.5\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\"><line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\"/></svg>\n </button>\n\n <!-- T\u1EF7 l\u1EC7 % v\u00E0 menu preset -->\n <div class=\"relative\">\n <button\n type=\"button\"\n class=\"h-7 px-2 flex items-center gap-1 rounded-full text-xs font-semibold text-slate-700 hover:bg-slate-100 transition-colors cursor-pointer\"\n [title]=\"'i18n_zoom_options' | translate\"\n (click)=\"handlerToggleMenu()\">\n <span>{{ zoomPercent() }}%</span>\n <svg class=\"w-3 h-3 text-slate-400 transition-transform duration-150\" [class.rotate-180]=\"isMenuOpen()\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"6 9 12 15 18 9\"/></svg>\n </button>\n\n <!-- Menu dropdown c\u00E1c m\u1ED1c thu ph\u00F3ng -->\n @if (isMenuOpen()) {\n <div class=\"absolute bottom-full mb-2 right-0 w-64 bg-white rounded-xl shadow-xl border border-slate-200 py-1.5 z-40 text-xs select-none\">\n <div class=\"px-3 py-1 text-[11px] font-semibold text-slate-400 uppercase tracking-wider\">\n {{ 'i18n_zoom_canvas_width' | translate: { width: stageWidth() } }}\n </div>\n <button\n type=\"button\"\n class=\"w-full px-3 py-2 text-left flex items-center justify-between hover:bg-slate-50 transition-colors cursor-pointer\"\n (click)=\"handlerFitScreen()\">\n <span class=\"flex items-center gap-2 text-slate-700 font-medium\">\n <svg class=\"w-3.5 h-3.5 text-slate-500\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><polyline points=\"15 3 21 3 21 9\"/><polyline points=\"9 21 3 21 3 15\"/><line x1=\"21\" y1=\"3\" x2=\"14\" y2=\"10\"/><line x1=\"3\" y1=\"21\" x2=\"10\" y2=\"14\"/></svg>\n {{ 'i18n_zoom_fit_screen' | translate }}\n </span>\n <span class=\"text-[10px] bg-blue-50 text-blue-600 px-1.5 py-0.5 rounded font-medium\">{{ 'i18n_auto' | translate }}</span>\n </button>\n <div class=\"h-px bg-slate-100 my-1\"></div>\n @for (preset of zoomPresets; track preset.value) {\n <button\n type=\"button\"\n class=\"w-full px-3 py-1.5 text-left flex items-center justify-between hover:bg-slate-50 transition-colors cursor-pointer\"\n [class.text-blue-600]=\"isCurrentPreset(preset.value)\"\n [class.font-semibold]=\"isCurrentPreset(preset.value)\"\n [class.bg-blue-50]=\"isCurrentPreset(preset.value)\"\n (click)=\"handlerSelectPreset(preset.value)\">\n <span class=\"text-slate-700\" [class.text-blue-600]=\"isCurrentPreset(preset.value)\">\n {{ preset.label | translate }}\n </span>\n @if (isCurrentPreset(preset.value)) {\n <svg class=\"w-3.5 h-3.5 text-blue-600\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"/></svg>\n }\n </button>\n }\n </div>\n }\n </div>\n\n <!-- Ph\u00F3ng to (+) -->\n <button\n type=\"button\"\n class=\"w-7 h-7 flex items-center justify-center rounded-full text-slate-600 hover:text-slate-900 hover:bg-slate-100 disabled:opacity-30 disabled:hover:bg-transparent transition-colors cursor-pointer\"\n [disabled]=\"currentZoom() >= zoomMax()\"\n [title]=\"'i18n_zoom_in' | translate\"\n (click)=\"handlerZoomIn()\">\n <svg class=\"w-3.5 h-3.5\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\"><line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\"/><line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\"/></svg>\n </button>\n\n <!-- Ph\u00E2n c\u00E1ch -->\n <div class=\"h-4 w-px bg-slate-200\"></div>\n\n <!-- N\u00FAt V\u1EEBa m\u00E0n h\u00ECnh nhanh -->\n <button\n type=\"button\"\n class=\"h-7 px-2.5 flex items-center gap-1 rounded-full text-xs text-slate-600 hover:text-slate-900 hover:bg-slate-100 transition-colors cursor-pointer\"\n [title]=\"'i18n_zoom_fit_screen_tooltip' | translate\"\n (click)=\"handlerFitScreen()\">\n <svg class=\"w-3.5 h-3.5\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><polyline points=\"15 3 21 3 21 9\"/><polyline points=\"9 21 3 21 3 15\"/><line x1=\"21\" y1=\"3\" x2=\"14\" y2=\"10\"/><line x1=\"3\" y1=\"21\" x2=\"10\" y2=\"14\"/></svg>\n <span class=\"font-medium\">{{ 'i18n_zoom_fit_screen' | translate }}</span>\n </button>\n\n <!-- N\u00FAt \u0110\u1EB7t l\u1EA1i 100% (ch\u1EC9 hi\u1EC7n khi kh\u00E1c 100%) -->\n @if (zoomPercent() !== 100) {\n <button\n type=\"button\"\n class=\"h-7 px-2 flex items-center gap-1 rounded-full text-xs font-semibold text-blue-600 hover:bg-blue-50 transition-colors cursor-pointer\"\n [title]=\"'i18n_zoom_reset_tooltip' | translate: { width: stageWidth(), height: stageMinHeight() }\"\n (click)=\"handlerResetZoom()\">\n <svg class=\"w-3 h-3\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"1 4 1 10 7 10\"/><path d=\"M3.51 15a9 9 0 1 0 2.13-9.36L1 10\"/></svg>\n <span>100%</span>\n </button>\n }\n </div>\n }\n} @else {\n <!-- \uD83D\uDD34 `relative` l\u00E0 B\u1EAET BU\u1ED8C, C\u1EA4M b\u1ECF.\n gridster \u0111\u1ED5i v\u1ECB tr\u00ED chu\u1ED9t th\u00E0nh \u00F4 l\u01B0\u1EDBi b\u1EB1ng `e.clientY + (el.scrollTop - el.offsetTop)` \u2014 c\u00F4ng\n th\u1EE9c \u0111\u00F3 ch\u1EC9 \u0111\u00FAng khi `offsetParent` c\u1EE7a <gridster> CH\u00CDNH L\u00C0 kh\u1ED1i cu\u1ED9n n\u00E0y. Thi\u1EBFu `relative` th\u00EC\n `offsetParent` nh\u1EA3y l\u00EAn kh\u1ED1i bao ngo\u00E0i: `offsetTop` tr\u1EA3 16 trong khi l\u1EC7ch th\u1EADt l\u00E0 65 \u2192 gridster\n t\u00EDnh \u00F4 sai 49px, \u00F4 ch\u1EDD \u0111\u1EB7t hi\u1EC7n l\u1EC7ch kh\u1ECFi con tr\u1ECF n\u00EAn k\u00E9o th\u1EA3 kh\u00F4ng \u0111\u1ED5i \u0111\u01B0\u1EE3c v\u1ECB tr\u00ED, v\u00E0 k\u00E9o m\u00E9p\n c\u0169ng t\u00EDnh sai \u0111i\u1EC3m d\u1EEBng. -->\n <div\n #scrollArea\n class=\"libs-ui-grid-layout-scroll-area relative h-full min-h-0 w-full min-w-0\"\n [class.overflow-y-auto]=\"!isNestedCanvas()\"\n (mousedown)=\"handlerMouseDownTrongLuoi($event)\"\n (dragover)=\"handlerDragOver($event)\"\n (dragleave)=\"handlerDragLeave($event)\"\n (drop)=\"handlerDrop($event)\">\n <!-- Snapped Drop Ghost Preview -->\n @if (dropGhost(); as ghost) {\n <div\n class=\"pointer-events-none absolute z-30 flex flex-col items-center justify-center overflow-hidden rounded-lg border-2 border-dashed border-blue-500 bg-blue-500/15 p-1 shadow-sm transition-all duration-75 ease-out backdrop-blur-[0.5px] select-none\"\n [style.left.px]=\"ghost.pixelLeft\"\n [style.top.px]=\"ghost.pixelTop\"\n [style.width.px]=\"ghost.pixelWidth\"\n [style.height.px]=\"ghost.pixelHeight\">\n <div class=\"inline-flex max-w-[95%] items-center gap-1 truncate rounded-md bg-blue-600 px-2 py-0.5 text-[11px] font-semibold text-white shadow-xs\">\n @if (ghost.cardIconClass) {\n <i [class]=\"ghost.cardIconClass + ' text-xs'\"></i>\n } @else if (ghost.cardIconText) {\n <span class=\"text-[10px] font-bold\">{{ ghost.cardIconText }}</span>\n } @else {\n <span class=\"text-xs font-bold\">{{ ghost.isInsideGroup ? '\u21B3' : '+' }}</span>\n }\n <span class=\"truncate\">{{ ghost.cardTitle }}</span>\n <span class=\"text-[9px] font-mono opacity-75\">({{ ghost.cols }}c)</span>\n </div>\n\n @if (ghost.pixelHeight >= 80) {\n <div class=\"mt-1 flex max-w-[95%] items-center gap-1.5 truncate rounded border border-blue-100 bg-white/95 px-2 py-0.5 text-[10px] font-medium text-blue-700 shadow-xs\">\n @if (ghost.isInsideGroup) {\n <span class=\"truncate font-bold text-blue-900\">\u21B3 {{ ghost.groupTitle }}</span>\n <span class=\"text-blue-300\">\u2022</span>\n }\n <span>C\u1ED9t {{ ghost.col + 1 }}-{{ ghost.col + ghost.cols }}</span>\n </div>\n }\n </div>\n }\n <gridster class=\"h-full w-full\" [class.display-grid]=\"showGridLines()\" [options]=\"gridOptions()\">\n @for (item of children(); track item.id; let itemIndex = $index) {\n <!-- \uD83D\uDD34 Ch\u1EB7n `mousedown` t\u1EA1i \u0110\u00C2Y cho l\u01B0\u1EDBi l\u1ED3ng \u2014 C\u1EA4M b\u1ECF v\u00E0 C\u1EA4M chuy\u1EC3n sang ch\u1ED7 kh\u00E1c.\n `ignoreContentClass` m\u1ED9t m\u00ECnh KH\u00D4NG \u0111\u1EE7: `delayStart: 160` l\u00E0m M\u1ED6I l\u01B0\u1EDBi l\u00EAn l\u1ECBch\n `dragStart` b\u1EB1ng `setTimeout` ngay t\u1EA1i `mousedown`, c\u00F2n `stopPropagation` m\u00E0 lib g\u1ECDi b\u00EAn\n trong `dragStart` ch\u1EA1y sau 160ms n\u00EAn qu\u00E1 mu\u1ED9n \u2014 l\u01B0\u1EDBi CHA \u0111\u00E3 k\u1ECBp nh\u1EADn (\u0111o 28/08/2026: k\u00E9o\n d\u1EA3i kh\u1ED1i con, chu\u1ED7i class duy\u1EC7t l\u00EAn \u0110\u00DANG m\u00E0 container v\u1EABn nh\u1EA3y 0,0 \u2192 0,1).\n G\u1EAFn \u1EDF `gridster-item` l\u00E0 \u0111\u00FAng bi\u00EAn: l\u01B0\u1EDBi con nghe tr\u00EAn ch\u00EDnh ph\u1EA7n t\u1EED n\u00E0y n\u00EAn \u0111\u00E3 nh\u1EADn xong,\n l\u01B0\u1EDBi cha \u1EDF ngo\u00E0i b\u1ECB ch\u1EB7n. -->\n <gridster-item\n [item]=\"item\"\n [class.libs-ui-grid-layout-selected]=\"selectedNodeId() === item.id\"\n (click)=\"handlerSelectNode(item, $event)\"\n (mousedown)=\"handlerBlockParentDrag($event)\">\n <!-- \uD83D\uDD34 V\u1ECF n\u00E0y mang `dragHandleClass` \u2014 C\u1EA4M b\u1ECF.\n `ignoreContent: true` b\u1EAFt gridster CH\u1EC8 cho k\u00E9o khi ch\u1ED7 b\u1EA5m n\u1EB1m d\u01B0\u1EDBi m\u1ED9t ph\u1EA7n t\u1EED c\u00F3\n `dragHandleClass`. Kh\u00F4ng c\u00F3 v\u1ECF n\u00E0y th\u00EC component c\u1EE7a n\u01A1i d\u00F9ng (th\u01B0 vi\u1EC7n kh\u00F4ng ki\u1EC3m so\u00E1t\n \u0111\u01B0\u1EE3c class c\u1EE7a n\u00F3) s\u1EBD kh\u00F4ng c\u00F3 tay c\u1EA7m n\u00E0o, v\u00E0 KH\u00D4NG kh\u1ED1i n\u00E0o k\u00E9o \u0111\u01B0\u1EE3c \u2014 \u0111o 28/08/2026:\n k\u00E9o 320px, to\u1EA1 \u0111\u1ED9 kh\u1ED1i gi\u1EEF nguy\u00EAn x=3,y=0.\n T\u00EAn class theo c\u1EA5p: l\u01B0\u1EDBi trang v\u00E0 l\u01B0\u1EDBi l\u1ED3ng d\u00F9ng hai t\u00EAn KH\u00C1C nhau, n\u1EBFu kh\u00F4ng l\u01B0\u1EDBi cha\n c\u0169ng nh\u1EADn ra tay c\u1EA7m c\u1EE7a kh\u1ED1i con v\u00E0 nh\u1EA5c lu\u00F4n container. -->\n <!-- \uD83D\uDD34 V\u1ECF KH\u00D4NG mang `dragHandleClass` \u2014 C\u1EA4M th\u00EAm l\u1EA1i.\n K\u00E9o ch\u1EC9 \u0111\u01B0\u1EE3c ph\u00E9p b\u1EAFt \u0111\u1EA7u t\u1EEB D\u1EA2I XANH (ng\u01B0\u1EDDi d\u00F9ng ch\u1ED1t 28/08/2026: \"ph\u1EA3i hover v\u00E0o v\u00F9ng\n m\u00E0u xanh th\u00EC m\u1EDBi k\u00E9o th\u1EA3 \u0111\u01B0\u1EE3c cho \u0111\u1ED3ng nh\u1EA5t\"). Cho c\u1EA3 v\u1ECF l\u00E0m tay c\u1EA7m th\u00EC b\u1EA5m \u0111\u00E2u c\u0169ng\n k\u00E9o, v\u00E0 kh\u1ED1i con n\u1EB1m trong container s\u1EBD nh\u1EA5c lu\u00F4n container v\u00EC l\u01B0\u1EDBi cha duy\u1EC7t l\u00EAn g\u1EB7p\n tay c\u1EA7m c\u1EE7a v\u1ECF container tr\u01B0\u1EDBc.\n V\u1ECF kh\u1ED1i con v\u1EABn gi\u1EEF class CH\u1EB6N \u0111\u1EC3 l\u01B0\u1EDBi cha d\u1EEBng \u0111\u00FAng \u1EDF bi\u00EAn. -->\n <div\n class=\"libs-ui-grid-layout-block-shell group relative h-full w-full min-w-0\"\n [class.libs-ui-grid-layout-block-parent-drag]=\"isNestedCanvas()\">\n <!-- D\u1EA3i k\u00E9o: hi\u1EC7n khi r\u00EA chu\u1ED9t v\u00E0o kh\u1ED1i, ba ch\u1EA5m l\u00E0 d\u1EA5u hi\u1EC7u k\u00E9o quen thu\u1ED9c.\n Ng\u01B0\u1EDDi d\u00F9ng c\u1EA7n m\u1ED9t ch\u1ED7 b\u00E1m R\u00D5 R\u00C0NG thay v\u00EC \u0111o\u00E1n xem b\u1EA5m \u0111\u00E2u th\u00EC k\u00E9o \u0111\u01B0\u1EE3c\n (ch\u1ED1t 28/08/2026, theo \u0111\u00FAng d\u1EA3i \u0111ang d\u00F9ng \u1EDF m\u00E0n Customer 360 c\u1EE7a mobio-web). -->\n @if (isEditMode()) {\n <!-- \uD83D\uDD34 D\u1EA3i PH\u1EA2I mang tay c\u1EA7m \u0110\u00DANG C\u1EA4P c\u1EE7a n\u00F3. D\u1EA3i nh\u1EADn chu\u1ED9t (`pointer-events: auto`),\n n\u00EAn n\u1EBFu kh\u00F4ng mang tay c\u1EA7m th\u00EC `checkDragHandleClass` duy\u1EC7t l\u00EAn g\u1EB7p tay c\u1EA7m c\u1EE7a\n container v\u00E0 nh\u1EA5c container thay v\u00EC kh\u1ED1i con (\u0111o 28/08/2026: k\u00E9o d\u1EA3i kh\u1ED1i con,\n container nh\u1EA3y 0,0 \u2192 0,1 c\u00F2n kh\u1ED1i con \u0111\u1EE9ng im).\n \uD83D\uDD34 D\u1EA3i CH\u1EC8 mang tay c\u1EA7m, C\u1EA4M mang th\u00EAm class ch\u1EB7n: `checkDragHandleClass` x\u00E9t hai\n class \u0111\u00F3 tr\u00EAn C\u00D9NG m\u1ED9t node n\u00EAn \u0111\u1EC3 chung l\u00E0 k\u00E9o h\u1ECFng (\u0111o 28/08/2026: b\u1EA5m d\u1EA3i kh\u1ED1i\n con k\u00E9o 140px, kh\u1ED1i \u0111\u1EE9ng im). Vi\u1EC7c ch\u1EB7n l\u01B0\u1EDBi cha do V\u1ECE KH\u1ED0I lo. -->\n <div\n class=\"libs-ui-grid-layout-drag-bar\"\n [class.libs-ui-grid-layout-drag-bar-child]=\"isNestedCanvas()\"\n [class.libs-ui-grid-layout-drag-handle]=\"!isNestedCanvas()\"\n [class.libs-ui-grid-layout-drag-handle-child]=\"isNestedCanvas()\">\n <span class=\"libs-ui-grid-layout-drag-bar-dots\">\n @for (dot of dragBarDots; track dot) {\n <span class=\"libs-ui-grid-layout-drag-bar-dot\"></span>\n }\n </span>\n </div>\n }\n\n <!-- Khung ch\u1EE9a component c\u1EE7a n\u01A1i d\u00F9ng.\n \uD83D\uDD34 PH\u1EA2I c\u00F3 khung th\u1EADt (kh\u00F4ng ph\u1EA3i `ng-container` tr\u1ED1ng): n\u00F3 lo h\u1ED9 n\u01A1i d\u00F9ng ph\u1EA7n l\u1EA5p \u0111\u1EA7y\n \u00F4 v\u00E0 vi\u1EC1n b\u00E1o ch\u1EBF \u0111\u1ED9 s\u1EEDa. Kh\u00F4ng c\u00F3 khung th\u00EC m\u1ED7i component n\u1ED9i dung l\u1EA1i ph\u1EA3i t\u1EF1 vi\u1EBFt\n `:host { width/height: 100% }` + vi\u1EC1n \u0111\u1EE9t \u2014 \u0111\u00F3 l\u00E0 vi\u1EC7c c\u1EE7a th\u01B0 vi\u1EC7n, kh\u00F4ng ph\u1EA3i c\u1EE7a\n ng\u01B0\u1EDDi d\u00F9ng (ng\u01B0\u1EDDi d\u00F9ng ch\u1ED1t 28/08/2026).\n M\u1ED7i kh\u1ED1i m\u1ED9t ViewContainerRef ri\u00EAng n\u00EAn component n\u1EB1m \u0111\u00FAng \u00F4 c\u1EE7a n\u00F3. -->\n <div\n class=\"libs-ui-grid-layout-content-frame\"\n [class.libs-ui-grid-layout-content-frame-edit]=\"isEditMode() && !isContainer(item)\"\n [class.libs-ui-grid-layout-content-frame-empty]=\"isContainer(item)\">\n <ng-container #itemHost />\n </div>\n\n <!-- D\u1EA5u hi\u1EC7u CONTAINER: nh\u00E3n g\u00F3c tr\u00EAn-ph\u1EA3i + vi\u1EC1n \u0111\u1EE9t bao ru\u1ED9t. Kh\u00F4ng c\u00F3 d\u1EA5u hi\u1EC7u th\u00EC\n ng\u01B0\u1EDDi d\u00F9ng kh\u00F4ng bi\u1EBFt kh\u1ED1i n\u00E0o ch\u1EE9a \u0111\u01B0\u1EE3c kh\u1ED1i kh\u00E1c (ch\u1ED1t 28/08/2026, theo \u0111\u00FAng c\u00E1ch\n m\u00E0n Customer 360 c\u1EE7a mobio-web \u0111ang l\u00E0m). -->\n @if (isEditMode() && isContainer(item)) {\n <div class=\"libs-ui-grid-layout-container-label\">{{ 'i18n_container_block' | translate }}</div>\n <div class=\"libs-ui-grid-layout-container-border\"></div>\n }\n\n <!-- Thanh c\u00F4ng c\u1EE5: hi\u1EC7n khi r\u00EA chu\u1ED9t v\u00E0o kh\u1ED1i.\n \uD83D\uDD34 D\u00F9ng `libs_ui-components-buttons-button` \u2014 C\u1EA4M t\u1EF1 d\u1EF1ng th\u1EBB `<button>`.\n Component n\u00E0y \u0111\u00E3 c\u00F3 s\u1EB5n ki\u1EC3u n\u00FAt, c\u1EE1 n\u00FAt v\u00E0 bong b\u00F3ng ch\u00FA th\u00EDch theo \u0111\u00FAng b\u1ED9 giao di\u1EC7n\n c\u1EE7a s\u1EA3n ph\u1EA9m; t\u1EF1 d\u1EF1ng l\u00E0 m\u1ED7i n\u01A1i m\u1ED9t ki\u1EC3u v\u00E0 m\u1EA5t lu\u00F4n tooltip. -->\n @if (isEditMode() && !hiddenToolbar()) {\n @if (templateToolbar()) {\n <!-- N\u01A1i d\u00F9ng t\u1EF1 v\u1EBD thanh c\u00F4ng c\u1EE5: nh\u1EADn kh\u1ED1i + c\u00E1c h\u00E0m ph\u00E1t event qua context.\n\n \uD83D\uDD34 Kh\u1ED1i b\u1ECDc t\u1EF1 ch\u1EB7n `mousedown`/`click` n\u1ED5i l\u00EAn gridster. Thanh c\u00F4ng c\u1EE5 n\u1EB1m trong\n v\u00F9ng mang `dragHandleClass`; kh\u00F4ng ch\u1EB7n th\u00EC c\u00FA b\u1EA5m b\u1ECB hi\u1EC3u l\u00E0 b\u1EAFt \u0111\u1EA7u k\u00E9o v\u00E0\n `delayStart: 160` nu\u1ED1t lu\u00F4n `click` \u2014 n\u00FAt trong template ngo\u00E0i b\u1EA5m kh\u00F4ng \u0103n\n (\u0111o 09/09/2026: b\u1EA5m b\u1EB1ng `.click()` c\u1EE7a DOM th\u00EC m\u1EDF, b\u1EA5m chu\u1ED9t th\u1EADt th\u00EC kh\u00F4ng).\n Ch\u1EB7n \u1EDF \u0110\u00C2Y \u0111\u1EC3 n\u01A1i d\u00F9ng kh\u00F4ng ph\u1EA3i bi\u1EBFt b\u1EABy n\u00E0y. -->\n <div\n class=\"libs-ui-grid-layout-toolbar\"\n role=\"toolbar\"\n tabindex=\"0\"\n [class.libs-ui-grid-layout-toolbar-child]=\"isNestedCanvas()\"\n (mousedown)=\"handlerStopEvent($event)\"\n (keydown)=\"handlerStopEvent($event)\"\n (click)=\"handlerStopEvent($event)\">\n <ng-container\n *ngTemplateOutlet=\"templateToolbar()!; context: toolbarContexts()[itemIndex]\" />\n </div>\n } @else {\n <div\n class=\"libs-ui-grid-layout-toolbar\"\n [class.libs-ui-grid-layout-toolbar-child]=\"isNestedCanvas()\">\n <span class=\"libs-ui-grid-layout-dim-badge\">\n {{ item.rows }} h\u00E0ng \u00D7 {{ item.cols }} c\u1ED9t\n </span>\n @if (canAddInside(item)) {\n <libs_ui-components-buttons-button\n [type]=\"'button-third'\"\n [iconOnlyType]=\"true\"\n [sizeButton]=\"'smaller'\"\n [classIconLeft]=\"'libs-ui-icon-add'\"\n [popover]=\"{ config: { content: 'Th\u00EAm kh\u1ED1i v\u00E0o trong', zIndex: 1300 } }\"\n (outClick)=\"handlerAddInside($event, item)\" />\n }\n @if (canToggleType(item)) {\n <libs_ui-components-buttons-button\n [type]=\"'button-third'\"\n [iconOnlyType]=\"true\"\n [sizeButton]=\"'smaller'\"\n [classIconLeft]=\"isContainer(item) ? 'libs-ui-icon-split-cell' : 'libs-ui-icon-merge-cell'\"\n [popover]=\"{ config: { content: isContainer(item) ? '\u0110\u01B0a v\u1EC1 kh\u1ED1i \u0111\u01A1n' : 'Chuy\u1EC3n th\u00E0nh kh\u1ED1i gh\u00E9p', zIndex: 1300 } }\"\n (outClick)=\"handlerToggleType($event, item)\" />\n }\n <libs_ui-components-buttons-button\n [type]=\"'button-third'\"\n [iconOnlyType]=\"true\"\n [sizeButton]=\"'smaller'\"\n [classIconLeft]=\"'libs-ui-icon-setting'\"\n [popover]=\"{ config: { content: 'C\u1EA5u h\u00ECnh th\u1EBB', zIndex: 1300 } }\"\n (outClick)=\"handlerConfig($event, item)\" />\n <libs_ui-components-buttons-button\n [type]=\"'button-third-hover-danger'\"\n [iconOnlyType]=\"true\"\n [sizeButton]=\"'smaller'\"\n [classIconLeft]=\"'libs-ui-icon-remove'\"\n [popover]=\"{ config: { content: isContainer(item) ? 'Xo\u00E1 c\u1EA3 kh\u1ED1i gh\u00E9p' : 'Xo\u00E1 kh\u1ED1i', zIndex: 1300 } }\"\n (outClick)=\"handlerRemove($event, item)\" />\n </div>\n }\n }\n\n @if (item.children && item.children.length > 0) {\n <!-- Kh\u1ED1i c\u00F3 con \u2192 ru\u1ED9t n\u00F3 l\u1EA1i l\u00E0 m\u1ED9t m\u1EB7t ph\u1EB3ng n\u1EEFa. \u0110\u1EC7 quy \u1EDF \u0111\u00E2y, n\u01A1i d\u00F9ng kh\u00F4ng ph\u1EA3i lo.\n L\u1EC1 \u0111\u1EB7t \u1EDF \u0110\u00C2Y (v\u1ECF container), kh\u00F4ng \u0111\u1EB7t v\u00E0o l\u01B0\u1EDBi con \u2014 l\u01B0\u1EDBi con gi\u1EEF nguy\u00EAn khe 2px. -->\n <libs_ui-services-grid_layout-canvas\n class=\"block h-full w-full\"\n [style.padding]=\"containerPadding()\"\n [node]=\"item\"\n [depth]=\"depth() + 1\"\n [hiddenToolbar]=\"hiddenToolbar()\"\n [templateToolbar]=\"templateToolbar()\"\n [selectedNodeId]=\"selectedNodeId()\"\n (outSelectNode)=\"outSelectNode.emit($event)\"\n (outConfigNode)=\"outConfigNode.emit($event)\"\n (outChange)=\"outChange.emit($event)\"\n (outRemoveNode)=\"outRemoveNode.emit($event)\"\n (outAddBlockInside)=\"outAddBlockInside.emit($event)\"\n (outToggleType)=\"outToggleType.emit($event)\" />\n }\n </div>\n </gridster-item>\n }\n </gridster>\n </div>\n}\n", styles: [":host{display:block;position:relative;box-sizing:border-box;width:100%;height:100%;min-width:0;min-height:0}.libs-ui-grid-layout-block-shell{container-type:inline-size;display:block;box-sizing:border-box;height:100%}.libs-ui-grid-layout-drag-bar{position:absolute;top:2px;left:50%;z-index:15;display:flex;align-items:center;justify-content:center;width:64px;height:16px;background:transparent;transform:translate(-50%);opacity:1;transition:opacity .12s ease;pointer-events:auto;cursor:move}.libs-ui-grid-layout-drag-bar-dots{display:grid;grid-template-columns:repeat(3,3px);gap:3px;color:#9ca2ad}.libs-ui-grid-layout-drag-bar-dot{width:3px;height:3px;background:currentColor;border-radius:50%}.libs-ui-grid-layout-drag-bar:hover .libs-ui-grid-layout-drag-bar-dots{color:#3d6ef5}.libs-ui-grid-layout-drag-bar:not(.libs-ui-grid-layout-drag-bar-child){opacity:1}.libs-ui-grid-layout-drag-bar-child{top:auto;bottom:0;background:#d9f2e4;border-radius:4px 4px 0 0}.libs-ui-grid-layout-drag-bar-child .libs-ui-grid-layout-drag-bar-dots{color:#9ca2ad}.libs-ui-grid-layout-drag-bar-child:hover .libs-ui-grid-layout-drag-bar-dots{color:#00a757}.libs-ui-grid-layout-drag-bar-child{opacity:0}.libs-ui-grid-layout-block-shell:hover>.libs-ui-grid-layout-drag-bar-child{opacity:1}.libs-ui-grid-layout-block-shell:has(>.libs-ui-grid-layout-drag-bar:not(.libs-ui-grid-layout-drag-bar-child):hover){outline:2px solid #3d6ef5;outline-offset:-2px;border-radius:8px}.libs-ui-grid-layout-block-shell:has(>.libs-ui-grid-layout-drag-bar-child:hover){outline:2px solid #00a757;outline-offset:-2px;border-radius:8px}.libs-ui-grid-layout-container-label{position:absolute;left:6px;top:2px;display:flex;height:20px;align-items:center;z-index:3;padding:0 6px;color:#3d6ef5;font-weight:500;font-size:10px;line-height:14px;background:#dbe4ff;border-radius:4px;pointer-events:none}.libs-ui-grid-layout-content-frame{box-sizing:border-box;width:100%;height:100%;overflow:hidden;border-radius:6px}.libs-ui-grid-layout-content-frame ::ng-deep>*{display:block;box-sizing:border-box;width:100%;height:100%}.libs-ui-grid-layout-content-frame-empty{height:0}.libs-ui-grid-layout-content-frame-edit{border:1px dashed #c3cede}.libs-ui-grid-layout-container-border{position:absolute;inset:0;border:1px dashed #9db4f0;border-radius:8px;pointer-events:none}.libs-ui-grid-layout-toolbar{position:absolute;top:6px;right:8px;z-index:24;display:flex;gap:2px;align-items:center;height:20px;background:#fff;border-radius:4px;box-shadow:0 2px 8px #0716311f;opacity:0;transition:opacity .12s ease}.libs-ui-grid-layout-toolbar-child{top:50%;right:8px;left:auto;transform:translateY(-50%)}.libs-ui-grid-layout-block-shell:hover>.libs-ui-grid-layout-toolbar{opacity:1}:host ::ng-deep gridster{background:transparent}:host ::ng-deep .gridster-item-resizable-handler.handle-n,:host ::ng-deep .gridster-item-resizable-handler.handle-s{height:16px}:host ::ng-deep .gridster-item-resizable-handler.handle-e,:host ::ng-deep .gridster-item-resizable-handler.handle-w{width:16px}:host ::ng-deep .gridster-item-resizable-handler.handle-n{top:0}:host ::ng-deep .gridster-item-resizable-handler.handle-s{bottom:0}:host ::ng-deep .gridster-item-resizable-handler.handle-e{right:0}:host ::ng-deep .gridster-item-resizable-handler.handle-w{left:0}:host ::ng-deep gridster-item.gridster-item-moving,:host ::ng-deep gridster-item.gridster-item-resizing{z-index:30!important}:host ::ng-deep gridster-item.gridster-item-moving>.libs-ui-grid-layout-block-shell,:host ::ng-deep gridster-item.gridster-item-resizing>.libs-ui-grid-layout-block-shell{outline:2px solid #3d6ef5;outline-offset:-2px;border-radius:8px}:host ::ng-deep gridster gridster gridster-item.gridster-item-moving>.libs-ui-grid-layout-block-shell,:host ::ng-deep gridster gridster gridster-item.gridster-item-resizing>.libs-ui-grid-layout-block-shell{outline-color:#00a757}:host ::ng-deep gridster-item.libs-ui-grid-layout-selected>.libs-ui-grid-layout-block-shell{outline:2px solid #2563eb!important;outline-offset:-2px!important;border-radius:8px!important;box-shadow:0 0 0 4px #2563eb26!important}:host ::ng-deep gridster.display-grid .gridster-column,:host ::ng-deep gridster gridster.display-grid .gridster-column{border-right:1px solid rgba(226,232,240,.7)!important;border-left:none!important;pointer-events:none!important;height:100%!important;min-height:100%!important}:host ::ng-deep gridster.display-grid .gridster-column:first-child,:host ::ng-deep gridster gridster.display-grid .gridster-column:first-child{border-left:1px solid rgba(226,232,240,.7)!important}:host ::ng-deep gridster.display-grid .gridster-row,:host ::ng-deep gridster gridster.display-grid .gridster-row{border-bottom:1px solid rgba(226,232,240,.7)!important;border-top:none!important;pointer-events:none!important}:host ::ng-deep gridster.display-grid .gridster-row:first-child,:host ::ng-deep gridster gridster.display-grid .gridster-row:first-child{border-top:1px solid rgba(226,232,240,.7)!important}:host ::ng-deep gridster gridster.display-grid{background-color:#f8fafc80!important}:host ::ng-deep gridster-preview{background:#2563eb1f!important;border:1.5px dashed #2563eb!important;border-radius:6px!important;z-index:25!important}.libs-ui-grid-layout-dim-badge{display:inline-flex;align-items:center;height:20px;padding:0 6px;background-color:#f1f5f9;border:1px solid #e2e8f0;border-radius:4px;color:#64748b;font-size:10px;font-weight:500;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;pointer-events:none;white-space:nowrap}@container (max-width: 80px){.libs-ui-grid-layout-drag-bar{top:26px}}.libs-ui-grid-layout-stage{box-sizing:border-box;transform-origin:top center;transition:zoom .15s ease-out}#canvas-zoom-dock{box-shadow:0 10px 25px -5px #0000001a,0 8px 10px -6px #0000001a}\n"], dependencies: [{ kind: "component", type: LibsUiGridLayoutCanvasComponent, selector: "libs_ui-services-grid_layout-canvas", inputs: ["node", "depth", "hiddenToolbar", "templateToolbar", "enableZoom", "zoom", "zoomMin", "zoomMax", "zoomStep", "stageWidth", "stageMinHeight", "storageKey", "showZoomDock", "autoFitOnLoad", "enableExternalDrop", "showGridLines", "selectedNodeId"], outputs: ["outChange", "outRemoveNode", "outAddBlockInside", "outToggleType", "zoomChange", "outZoomChange", "selectedNodeIdChange", "outDropNode", "outSelectNode", "outConfigNode"] }, { kind: "ngmodule", type: GridsterModule }, { kind: "component", type: i1.GridsterComponent, selector: "gridster", inputs: ["options"] }, { kind: "component", type: i1.GridsterItemComponent, selector: "gridster-item", inputs: ["item"], outputs: ["itemInit", "itemChange", "itemResize"] }, { kind: "component", type: LibsUiComponentsButtonsButtonComponent, selector: "libs_ui-components-buttons-button", inputs: ["flagMouse", "type", "buttonCustom", "sizeButton", "label", "disable", "isPending", "imageLeft", "classInclude", "classIconLeft", "classIconRight", "classLabel", "iconOnlyType", "popover", "ignoreStopPropagationEvent", "zIndex", "widthLabelPopover", "styleIconLeft", "styleButton", "ignoreFocusWhenInputTab", "ignoreSetClickWhenShowPopover", "ignorePointerEvent", "isActive", "isHandlerEnterDocumentClickButton"], outputs: ["outClick", "outPopoverEvent", "outFunctionsControl"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i2.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
560
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: LibsUiGridLayoutCanvasComponent, isStandalone: true, selector: "libs_ui-services-grid_layout-canvas", inputs: { node: { classPropertyName: "node", publicName: "node", isSignal: true, isRequired: false, transformFunction: null }, depth: { classPropertyName: "depth", publicName: "depth", isSignal: true, isRequired: false, transformFunction: null }, hiddenToolbar: { classPropertyName: "hiddenToolbar", publicName: "hiddenToolbar", isSignal: true, isRequired: false, transformFunction: null }, templateToolbar: { classPropertyName: "templateToolbar", publicName: "templateToolbar", isSignal: true, isRequired: false, transformFunction: null }, enableZoom: { classPropertyName: "enableZoom", publicName: "enableZoom", isSignal: true, isRequired: false, transformFunction: null }, zoom: { classPropertyName: "zoom", publicName: "zoom", isSignal: true, isRequired: false, transformFunction: null }, zoomMin: { classPropertyName: "zoomMin", publicName: "zoomMin", isSignal: true, isRequired: false, transformFunction: null }, zoomMax: { classPropertyName: "zoomMax", publicName: "zoomMax", isSignal: true, isRequired: false, transformFunction: null }, zoomStep: { classPropertyName: "zoomStep", publicName: "zoomStep", isSignal: true, isRequired: false, transformFunction: null }, stageWidth: { classPropertyName: "stageWidth", publicName: "stageWidth", isSignal: true, isRequired: false, transformFunction: null }, stageMinHeight: { classPropertyName: "stageMinHeight", publicName: "stageMinHeight", isSignal: true, isRequired: false, transformFunction: null }, storageKey: { classPropertyName: "storageKey", publicName: "storageKey", isSignal: true, isRequired: false, transformFunction: null }, showZoomDock: { classPropertyName: "showZoomDock", publicName: "showZoomDock", isSignal: true, isRequired: false, transformFunction: null }, autoFitOnLoad: { classPropertyName: "autoFitOnLoad", publicName: "autoFitOnLoad", isSignal: true, isRequired: false, transformFunction: null }, enableExternalDrop: { classPropertyName: "enableExternalDrop", publicName: "enableExternalDrop", isSignal: true, isRequired: false, transformFunction: null }, showGridLines: { classPropertyName: "showGridLines", publicName: "showGridLines", isSignal: true, isRequired: false, transformFunction: null }, selectedNodeId: { classPropertyName: "selectedNodeId", publicName: "selectedNodeId", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { outChange: "outChange", outRemoveNode: "outRemoveNode", outAddBlockInside: "outAddBlockInside", outToggleType: "outToggleType", zoom: "zoomChange", outZoomChange: "outZoomChange", selectedNodeId: "selectedNodeIdChange", outDropNode: "outDropNode", outSelectNode: "outSelectNode", outConfigNode: "outConfigNode" }, host: { listeners: { "document:keydown": "handlerDocumentKeyDown($event)", "document:click": "handlerDocumentClick($event)" } }, viewQueries: [{ propertyName: "gridsterRef", first: true, predicate: GridsterComponent, descendants: true, isSignal: true }, { propertyName: "scrollAreaRef", first: true, predicate: ["scrollArea"], descendants: true, isSignal: true }, { propertyName: "zoomDockRef", first: true, predicate: ["zoomDock"], descendants: true, isSignal: true }, { propertyName: "itemHosts", predicate: ["itemHost"], descendants: true, read: ViewContainerRef, isSignal: true }], ngImport: i0, template: "@if (isZoomActive()) {\n <!-- Khu v\u1EF1c cu\u1ED9n ch\u1EE9a canvas stage thu ph\u00F3ng -->\n <div\n #scrollArea\n class=\"libs-ui-grid-layout-scroll-area relative h-full min-h-0 w-full min-w-0 overflow-auto p-6 flex justify-center items-start\"\n (mousedown)=\"handlerMouseDownTrongLuoi($event)\"\n (wheel)=\"handlerWheel($event)\"\n (dragover)=\"handlerDragOver($event)\"\n (dragleave)=\"handlerDragLeave($event)\"\n (drop)=\"handlerDrop($event)\">\n <div\n #canvasStage\n id=\"bi-canvas-stage\"\n class=\"libs-ui-grid-layout-stage relative flex flex-col transition-[zoom] duration-150 origin-top shrink-0 bg-white/80 border border-slate-200/80 rounded-2xl shadow-sm p-4\"\n [style.zoom]=\"currentZoom()\"\n [style.width.px]=\"stageWidth()\"\n [style.min-width.px]=\"stageWidth()\"\n [style.min-height.px]=\"stageMinHeight()\">\n <!-- Snapped Drop Ghost Preview -->\n @if (dropGhost(); as ghost) {\n <div\n class=\"pointer-events-none absolute z-30 flex flex-col items-center justify-center overflow-hidden rounded-lg border-2 border-dashed border-blue-500 bg-blue-500/15 p-1 shadow-sm transition-all duration-75 ease-out backdrop-blur-[0.5px] select-none\"\n [style.left.px]=\"ghost.pixelLeft\"\n [style.top.px]=\"ghost.pixelTop\"\n [style.width.px]=\"ghost.pixelWidth\"\n [style.height.px]=\"ghost.pixelHeight\">\n <div class=\"inline-flex max-w-[95%] items-center gap-1 truncate rounded-md bg-blue-600 px-2 py-0.5 text-[11px] font-semibold text-white shadow-xs\">\n @if (ghost.cardIconClass) {\n <i [class]=\"ghost.cardIconClass + ' text-xs'\"></i>\n } @else if (ghost.cardIconText) {\n <span class=\"text-[10px] font-bold\">{{ ghost.cardIconText }}</span>\n } @else {\n <span class=\"text-xs font-bold\">{{ ghost.isInsideGroup ? '\u21B3' : '+' }}</span>\n }\n <span class=\"truncate\">{{ ghost.cardTitle }}</span>\n <span class=\"text-[9px] font-mono opacity-75\">({{ ghost.cols }}c)</span>\n </div>\n\n @if (ghost.pixelHeight >= 80) {\n <div class=\"mt-1 flex max-w-[95%] items-center gap-1.5 truncate rounded border border-blue-100 bg-white/95 px-2 py-0.5 text-[10px] font-medium text-blue-700 shadow-xs\">\n @if (ghost.isInsideGroup) {\n <span class=\"truncate font-bold text-blue-900\">\u21B3 {{ ghost.groupTitle }}</span>\n <span class=\"text-blue-300\">\u2022</span>\n }\n <span>C\u1ED9t {{ ghost.col + 1 }}-{{ ghost.col + ghost.cols }}</span>\n </div>\n }\n </div>\n }\n <gridster class=\"h-full w-full\" [class.display-grid]=\"showGridLines()\" [options]=\"gridOptions()\">\n @for (item of children(); track item.id; let itemIndex = $index) {\n <!-- \uD83D\uDD34 Ch\u1EB7n `mousedown` t\u1EA1i \u0110\u00C2Y cho l\u01B0\u1EDBi l\u1ED3ng \u2014 C\u1EA4M b\u1ECF v\u00E0 C\u1EA4M chuy\u1EC3n sang ch\u1ED7 kh\u00E1c.\n `ignoreContentClass` m\u1ED9t m\u00ECnh KH\u00D4NG \u0111\u1EE7: `delayStart: 160` l\u00E0m M\u1ED6I l\u01B0\u1EDBi l\u00EAn l\u1ECBch\n `dragStart` b\u1EB1ng `setTimeout` ngay t\u1EA1i `mousedown`, c\u00F2n `stopPropagation` m\u00E0 lib g\u1ECDi b\u00EAn\n trong `dragStart` ch\u1EA1y sau 160ms n\u00EAn qu\u00E1 mu\u1ED9n \u2014 l\u01B0\u1EDBi CHA \u0111\u00E3 k\u1ECBp nh\u1EADn (\u0111o 28/08/2026: k\u00E9o\n d\u1EA3i kh\u1ED1i con, chu\u1ED7i class duy\u1EC7t l\u00EAn \u0110\u00DANG m\u00E0 container v\u1EABn nh\u1EA3y 0,0 \u2192 0,1).\n G\u1EAFn \u1EDF `gridster-item` l\u00E0 \u0111\u00FAng bi\u00EAn: l\u01B0\u1EDBi con nghe tr\u00EAn ch\u00EDnh ph\u1EA7n t\u1EED n\u00E0y n\u00EAn \u0111\u00E3 nh\u1EADn xong,\n l\u01B0\u1EDBi cha \u1EDF ngo\u00E0i b\u1ECB ch\u1EB7n. -->\n <gridster-item\n [item]=\"item\"\n [class.libs-ui-grid-layout-selected]=\"selectedNodeId() === item.id\"\n (click)=\"handlerSelectNode(item, $event)\"\n (mousedown)=\"handlerBlockParentDrag($event)\">\n <!-- \uD83D\uDD34 V\u1ECF n\u00E0y mang `dragHandleClass` \u2014 C\u1EA4M b\u1ECF.\n `ignoreContent: true` b\u1EAFt gridster CH\u1EC8 cho k\u00E9o khi ch\u1ED7 b\u1EA5m n\u1EB1m d\u01B0\u1EDBi m\u1ED9t ph\u1EA7n t\u1EED c\u00F3\n `dragHandleClass`. Kh\u00F4ng c\u00F3 v\u1ECF n\u00E0y th\u00EC component c\u1EE7a n\u01A1i d\u00F9ng (th\u01B0 vi\u1EC7n kh\u00F4ng ki\u1EC3m so\u00E1t\n \u0111\u01B0\u1EE3c class c\u1EE7a n\u00F3) s\u1EBD kh\u00F4ng c\u00F3 tay c\u1EA7m n\u00E0o, v\u00E0 KH\u00D4NG kh\u1ED1i n\u00E0o k\u00E9o \u0111\u01B0\u1EE3c \u2014 \u0111o 28/08/2026:\n k\u00E9o 320px, to\u1EA1 \u0111\u1ED9 kh\u1ED1i gi\u1EEF nguy\u00EAn x=3,y=0.\n T\u00EAn class theo c\u1EA5p: l\u01B0\u1EDBi trang v\u00E0 l\u01B0\u1EDBi l\u1ED3ng d\u00F9ng hai t\u00EAn KH\u00C1C nhau, n\u1EBFu kh\u00F4ng l\u01B0\u1EDBi cha\n c\u0169ng nh\u1EADn ra tay c\u1EA7m c\u1EE7a kh\u1ED1i con v\u00E0 nh\u1EA5c lu\u00F4n container. -->\n <!-- \uD83D\uDD34 V\u1ECF KH\u00D4NG mang `dragHandleClass` \u2014 C\u1EA4M th\u00EAm l\u1EA1i.\n K\u00E9o ch\u1EC9 \u0111\u01B0\u1EE3c ph\u00E9p b\u1EAFt \u0111\u1EA7u t\u1EEB D\u1EA2I XANH (ng\u01B0\u1EDDi d\u00F9ng ch\u1ED1t 28/08/2026: \"ph\u1EA3i hover v\u00E0o v\u00F9ng\n m\u00E0u xanh th\u00EC m\u1EDBi k\u00E9o th\u1EA3 \u0111\u01B0\u1EE3c cho \u0111\u1ED3ng nh\u1EA5t\"). Cho c\u1EA3 v\u1ECF l\u00E0m tay c\u1EA7m th\u00EC b\u1EA5m \u0111\u00E2u c\u0169ng\n k\u00E9o, v\u00E0 kh\u1ED1i con n\u1EB1m trong container s\u1EBD nh\u1EA5c lu\u00F4n container v\u00EC l\u01B0\u1EDBi cha duy\u1EC7t l\u00EAn g\u1EB7p\n tay c\u1EA7m c\u1EE7a v\u1ECF container tr\u01B0\u1EDBc.\n V\u1ECF kh\u1ED1i con v\u1EABn gi\u1EEF class CH\u1EB6N \u0111\u1EC3 l\u01B0\u1EDBi cha d\u1EEBng \u0111\u00FAng \u1EDF bi\u00EAn. -->\n <div\n class=\"libs-ui-grid-layout-block-shell group relative h-full w-full min-w-0\"\n [class.libs-ui-grid-layout-block-parent-drag]=\"isNestedCanvas()\">\n <!-- D\u1EA3i k\u00E9o: hi\u1EC7n khi r\u00EA chu\u1ED9t v\u00E0o kh\u1ED1i, ba ch\u1EA5m l\u00E0 d\u1EA5u hi\u1EC7u k\u00E9o quen thu\u1ED9c.\n Ng\u01B0\u1EDDi d\u00F9ng c\u1EA7n m\u1ED9t ch\u1ED7 b\u00E1m R\u00D5 R\u00C0NG thay v\u00EC \u0111o\u00E1n xem b\u1EA5m \u0111\u00E2u th\u00EC k\u00E9o \u0111\u01B0\u1EE3c\n (ch\u1ED1t 28/08/2026, theo \u0111\u00FAng d\u1EA3i \u0111ang d\u00F9ng \u1EDF m\u00E0n Customer 360 c\u1EE7a mobio-web). -->\n @if (isEditMode()) {\n <!-- \uD83D\uDD34 D\u1EA3i PH\u1EA2I mang tay c\u1EA7m \u0110\u00DANG C\u1EA4P c\u1EE7a n\u00F3. D\u1EA3i nh\u1EADn chu\u1ED9t (`pointer-events: auto`),\n n\u00EAn n\u1EBFu kh\u00F4ng mang tay c\u1EA7m th\u00EC `checkDragHandleClass` duy\u1EC7t l\u00EAn g\u1EB7p tay c\u1EA7m c\u1EE7a\n container v\u00E0 nh\u1EA5c container thay v\u00EC kh\u1ED1i con (\u0111o 28/08/2026: k\u00E9o d\u1EA3i kh\u1ED1i con,\n container nh\u1EA3y 0,0 \u2192 0,1 c\u00F2n kh\u1ED1i con \u0111\u1EE9ng im).\n \uD83D\uDD34 D\u1EA3i CH\u1EC8 mang tay c\u1EA7m, C\u1EA4M mang th\u00EAm class ch\u1EB7n: `checkDragHandleClass` x\u00E9t hai\n class \u0111\u00F3 tr\u00EAn C\u00D9NG m\u1ED9t node n\u00EAn \u0111\u1EC3 chung l\u00E0 k\u00E9o h\u1ECFng (\u0111o 28/08/2026: b\u1EA5m d\u1EA3i kh\u1ED1i\n con k\u00E9o 140px, kh\u1ED1i \u0111\u1EE9ng im). Vi\u1EC7c ch\u1EB7n l\u01B0\u1EDBi cha do V\u1ECE KH\u1ED0I lo. -->\n <div\n class=\"libs-ui-grid-layout-drag-bar\"\n [class.libs-ui-grid-layout-drag-bar-child]=\"isNestedCanvas()\"\n [class.libs-ui-grid-layout-drag-handle]=\"!isNestedCanvas()\"\n [class.libs-ui-grid-layout-drag-handle-child]=\"isNestedCanvas()\">\n <span class=\"libs-ui-grid-layout-drag-bar-dots\">\n @for (dot of dragBarDots; track dot) {\n <span class=\"libs-ui-grid-layout-drag-bar-dot\"></span>\n }\n </span>\n </div>\n }\n\n <!-- Khung ch\u1EE9a component c\u1EE7a n\u01A1i d\u00F9ng.\n \uD83D\uDD34 PH\u1EA2I c\u00F3 khung th\u1EADt (kh\u00F4ng ph\u1EA3i `ng-container` tr\u1ED1ng): n\u00F3 lo h\u1ED9 n\u01A1i d\u00F9ng ph\u1EA7n l\u1EA5p \u0111\u1EA7y\n \u00F4 v\u00E0 vi\u1EC1n b\u00E1o ch\u1EBF \u0111\u1ED9 s\u1EEDa. Kh\u00F4ng c\u00F3 khung th\u00EC m\u1ED7i component n\u1ED9i dung l\u1EA1i ph\u1EA3i t\u1EF1 vi\u1EBFt\n `:host { width/height: 100% }` + vi\u1EC1n \u0111\u1EE9t \u2014 \u0111\u00F3 l\u00E0 vi\u1EC7c c\u1EE7a th\u01B0 vi\u1EC7n, kh\u00F4ng ph\u1EA3i c\u1EE7a\n ng\u01B0\u1EDDi d\u00F9ng (ng\u01B0\u1EDDi d\u00F9ng ch\u1ED1t 28/08/2026).\n M\u1ED7i kh\u1ED1i m\u1ED9t ViewContainerRef ri\u00EAng n\u00EAn component n\u1EB1m \u0111\u00FAng \u00F4 c\u1EE7a n\u00F3. -->\n <div\n class=\"libs-ui-grid-layout-content-frame\"\n [class.libs-ui-grid-layout-content-frame-edit]=\"isEditMode() && !isContainer(item)\"\n [class.libs-ui-grid-layout-content-frame-empty]=\"isContainer(item)\">\n <ng-container #itemHost />\n </div>\n\n <!-- D\u1EA5u hi\u1EC7u CONTAINER: nh\u00E3n g\u00F3c tr\u00EAn-ph\u1EA3i + vi\u1EC1n \u0111\u1EE9t bao ru\u1ED9t. Kh\u00F4ng c\u00F3 d\u1EA5u hi\u1EC7u th\u00EC\n ng\u01B0\u1EDDi d\u00F9ng kh\u00F4ng bi\u1EBFt kh\u1ED1i n\u00E0o ch\u1EE9a \u0111\u01B0\u1EE3c kh\u1ED1i kh\u00E1c (ch\u1ED1t 28/08/2026, theo \u0111\u00FAng c\u00E1ch\n m\u00E0n Customer 360 c\u1EE7a mobio-web \u0111ang l\u00E0m). -->\n @if (isEditMode() && isContainer(item)) {\n <div class=\"libs-ui-grid-layout-container-label\">{{ 'i18n_container_block' | translate }}</div>\n <div class=\"libs-ui-grid-layout-container-border\"></div>\n }\n\n <!-- Thanh c\u00F4ng c\u1EE5: hi\u1EC7n khi r\u00EA chu\u1ED9t v\u00E0o kh\u1ED1i.\n \uD83D\uDD34 D\u00F9ng `libs_ui-components-buttons-button` \u2014 C\u1EA4M t\u1EF1 d\u1EF1ng th\u1EBB `<button>`.\n Component n\u00E0y \u0111\u00E3 c\u00F3 s\u1EB5n ki\u1EC3u n\u00FAt, c\u1EE1 n\u00FAt v\u00E0 bong b\u00F3ng ch\u00FA th\u00EDch theo \u0111\u00FAng b\u1ED9 giao di\u1EC7n\n c\u1EE7a s\u1EA3n ph\u1EA9m; t\u1EF1 d\u1EF1ng l\u00E0 m\u1ED7i n\u01A1i m\u1ED9t ki\u1EC3u v\u00E0 m\u1EA5t lu\u00F4n tooltip. -->\n @if (isEditMode() && !hiddenToolbar()) {\n @if (templateToolbar()) {\n <!-- N\u01A1i d\u00F9ng t\u1EF1 v\u1EBD thanh c\u00F4ng c\u1EE5: nh\u1EADn kh\u1ED1i + c\u00E1c h\u00E0m ph\u00E1t event qua context.\n\n \uD83D\uDD34 Kh\u1ED1i b\u1ECDc t\u1EF1 ch\u1EB7n `mousedown`/`click` n\u1ED5i l\u00EAn gridster. Thanh c\u00F4ng c\u1EE5 n\u1EB1m trong\n v\u00F9ng mang `dragHandleClass`; kh\u00F4ng ch\u1EB7n th\u00EC c\u00FA b\u1EA5m b\u1ECB hi\u1EC3u l\u00E0 b\u1EAFt \u0111\u1EA7u k\u00E9o v\u00E0\n `delayStart: 160` nu\u1ED1t lu\u00F4n `click` \u2014 n\u00FAt trong template ngo\u00E0i b\u1EA5m kh\u00F4ng \u0103n\n (\u0111o 09/09/2026: b\u1EA5m b\u1EB1ng `.click()` c\u1EE7a DOM th\u00EC m\u1EDF, b\u1EA5m chu\u1ED9t th\u1EADt th\u00EC kh\u00F4ng).\n Ch\u1EB7n \u1EDF \u0110\u00C2Y \u0111\u1EC3 n\u01A1i d\u00F9ng kh\u00F4ng ph\u1EA3i bi\u1EBFt b\u1EABy n\u00E0y. -->\n <div\n class=\"libs-ui-grid-layout-toolbar\"\n role=\"toolbar\"\n tabindex=\"0\"\n [class.libs-ui-grid-layout-toolbar-child]=\"isNestedCanvas()\"\n (mousedown)=\"handlerStopEvent($event)\"\n (keydown)=\"handlerStopEvent($event)\"\n (click)=\"handlerStopEvent($event)\">\n <ng-container\n *ngTemplateOutlet=\"templateToolbar()!; context: toolbarContexts()[itemIndex]\" />\n </div>\n } @else {\n <div\n class=\"libs-ui-grid-layout-toolbar\"\n [class.libs-ui-grid-layout-toolbar-child]=\"isNestedCanvas()\">\n <span class=\"libs-ui-grid-layout-dim-badge\">\n {{ item.rows }} h\u00E0ng \u00D7 {{ item.cols }} c\u1ED9t\n </span>\n @if (canAddInside(item)) {\n <libs_ui-components-buttons-button\n [type]=\"'button-third'\"\n [iconOnlyType]=\"true\"\n [sizeButton]=\"'smaller'\"\n [classIconLeft]=\"'libs-ui-icon-add'\"\n [popover]=\"{ config: { content: 'Th\u00EAm kh\u1ED1i v\u00E0o trong', zIndex: 1300 } }\"\n (outClick)=\"handlerAddInside($event, item)\" />\n }\n @if (canToggleType(item)) {\n <libs_ui-components-buttons-button\n [type]=\"'button-third'\"\n [iconOnlyType]=\"true\"\n [sizeButton]=\"'smaller'\"\n [classIconLeft]=\"isContainer(item) ? 'libs-ui-icon-split-cell' : 'libs-ui-icon-merge-cell'\"\n [popover]=\"{ config: { content: isContainer(item) ? '\u0110\u01B0a v\u1EC1 kh\u1ED1i \u0111\u01A1n' : 'Chuy\u1EC3n th\u00E0nh kh\u1ED1i gh\u00E9p', zIndex: 1300 } }\"\n (outClick)=\"handlerToggleType($event, item)\" />\n }\n <libs_ui-components-buttons-button\n [type]=\"'button-third'\"\n [iconOnlyType]=\"true\"\n [sizeButton]=\"'smaller'\"\n [classIconLeft]=\"'libs-ui-icon-setting'\"\n [popover]=\"{ config: { content: 'C\u1EA5u h\u00ECnh th\u1EBB', zIndex: 1300 } }\"\n (outClick)=\"handlerConfig($event, item)\" />\n <libs_ui-components-buttons-button\n [type]=\"'button-third-hover-danger'\"\n [iconOnlyType]=\"true\"\n [sizeButton]=\"'smaller'\"\n [classIconLeft]=\"'libs-ui-icon-remove'\"\n [popover]=\"{ config: { content: isContainer(item) ? 'Xo\u00E1 c\u1EA3 kh\u1ED1i gh\u00E9p' : 'Xo\u00E1 kh\u1ED1i', zIndex: 1300 } }\"\n (outClick)=\"handlerRemove($event, item)\" />\n </div>\n }\n }\n\n @if (item.children && item.children.length > 0) {\n <!-- Kh\u1ED1i c\u00F3 con \u2192 ru\u1ED9t n\u00F3 l\u1EA1i l\u00E0 m\u1ED9t m\u1EB7t ph\u1EB3ng n\u1EEFa. \u0110\u1EC7 quy \u1EDF \u0111\u00E2y, n\u01A1i d\u00F9ng kh\u00F4ng ph\u1EA3i lo.\n L\u1EC1 \u0111\u1EB7t \u1EDF \u0110\u00C2Y (v\u1ECF container), kh\u00F4ng \u0111\u1EB7t v\u00E0o l\u01B0\u1EDBi con \u2014 l\u01B0\u1EDBi con gi\u1EEF nguy\u00EAn khe 2px. -->\n <libs_ui-services-grid_layout-canvas\n class=\"block h-full w-full\"\n [style.padding]=\"containerPadding()\"\n [node]=\"item\"\n [depth]=\"depth() + 1\"\n [hiddenToolbar]=\"hiddenToolbar()\"\n [templateToolbar]=\"templateToolbar()\"\n [selectedNodeId]=\"selectedNodeId()\"\n (outSelectNode)=\"outSelectNode.emit($event)\"\n (outConfigNode)=\"outConfigNode.emit($event)\"\n (outChange)=\"outChange.emit($event)\"\n (outRemoveNode)=\"outRemoveNode.emit($event)\"\n (outAddBlockInside)=\"outAddBlockInside.emit($event)\"\n (outToggleType)=\"outToggleType.emit($event)\" />\n }\n </div>\n </gridster-item>\n }\n </gridster>\n </div>\n </div>\n\n <!-- Thanh dock \u0111i\u1EC1u khi\u1EC3n thu ph\u00F3ng n\u1ED5i \u1EDF g\u00F3c d\u01B0\u1EDBi tr\u00E1i -->\n @if (showZoomDock()) {\n <div\n #zoomDock\n id=\"canvas-zoom-dock\"\n role=\"toolbar\"\n tabindex=\"0\"\n class=\"absolute bottom-4 left-6 z-30 flex items-center bg-white rounded-full shadow-2xl border-2 border-slate-400 p-1 space-x-1 select-none\"\n (mousedown)=\"$event.stopPropagation()\"\n (keydown)=\"$event.stopPropagation()\"\n (click)=\"$event.stopPropagation()\">\n <!-- Thu nh\u1ECF (-) -->\n <button\n type=\"button\"\n class=\"w-[28px] h-[28px] flex items-center justify-center rounded-full text-slate-700 hover:text-slate-900 hover:bg-slate-200 disabled:opacity-30 disabled:hover:bg-transparent transition-colors cursor-pointer\"\n [disabled]=\"currentZoom() <= zoomMin()\"\n [title]=\"'i18n_zoom_out' | translate\"\n (click)=\"handlerZoomOut()\">\n <svg class=\"w-3.5 h-3.5\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\"><line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\"/></svg>\n </button>\n\n <!-- T\u1EF7 l\u1EC7 % v\u00E0 menu preset -->\n <div class=\"relative\">\n <button\n type=\"button\"\n class=\"h-[28px] px-2 flex items-center gap-1 rounded-full text-xs font-semibold text-slate-700 hover:bg-slate-200 transition-colors cursor-pointer\"\n [title]=\"'i18n_zoom_options' | translate\"\n (click)=\"handlerToggleMenu()\">\n <span>{{ zoomPercent() }}%</span>\n <svg class=\"w-[12px] h-[12px] text-slate-400 transition-transform duration-150\" [class.rotate-180]=\"isMenuOpen()\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"6 9 12 15 18 9\"/></svg>\n </button>\n\n <!-- Menu dropdown c\u00E1c m\u1ED1c thu ph\u00F3ng -->\n @if (isMenuOpen()) {\n <div class=\"absolute bottom-full mb-2 left-0 w-[256px] bg-white rounded-xl shadow-xl border border-slate-200 py-1.5 z-40 text-xs select-none\">\n <div class=\"px-3 py-1 text-[11px] font-semibold text-slate-400 uppercase tracking-wider\">\n {{ 'i18n_zoom_canvas_width' | translate: { width: stageWidth() } }}\n </div>\n <button\n type=\"button\"\n class=\"w-full px-3 py-2 text-left flex items-center justify-between hover:bg-slate-50 transition-colors cursor-pointer\"\n (click)=\"handlerFitScreen()\">\n <span class=\"flex items-center gap-2 text-slate-700 font-medium\">\n <svg class=\"w-3.5 h-3.5 text-slate-600\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><polyline points=\"15 3 21 3 21 9\"/><polyline points=\"9 21 3 21 3 15\"/><line x1=\"21\" y1=\"3\" x2=\"14\" y2=\"10\"/><line x1=\"3\" y1=\"21\" x2=\"10\" y2=\"14\"/></svg>\n {{ 'i18n_zoom_fit_screen' | translate }}\n </span>\n <span class=\"text-[10px] bg-blue-50 text-blue-600 px-1.5 py-0.5 rounded font-medium\">{{ 'i18n_auto' | translate }}</span>\n </button>\n <div class=\"h-px bg-slate-100 my-1\"></div>\n @for (preset of zoomPresets; track preset.value) {\n <button\n type=\"button\"\n class=\"w-full px-3 py-1.5 text-left flex items-center justify-between hover:bg-slate-50 transition-colors cursor-pointer\"\n [class.text-blue-600]=\"isCurrentPreset(preset.value)\"\n [class.font-semibold]=\"isCurrentPreset(preset.value)\"\n [class.bg-blue-50]=\"isCurrentPreset(preset.value)\"\n (click)=\"handlerSelectPreset(preset.value)\">\n <span class=\"text-slate-700\" [class.text-blue-600]=\"isCurrentPreset(preset.value)\">\n {{ preset.label | translate }}\n </span>\n @if (isCurrentPreset(preset.value)) {\n <svg class=\"w-3.5 h-3.5 text-blue-600\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"/></svg>\n }\n </button>\n }\n </div>\n }\n </div>\n\n <!-- Ph\u00F3ng to (+) -->\n <button\n type=\"button\"\n class=\"w-[28px] h-[28px] flex items-center justify-center rounded-full text-slate-700 hover:text-slate-900 hover:bg-slate-200 disabled:opacity-30 disabled:hover:bg-transparent transition-colors cursor-pointer\"\n [disabled]=\"currentZoom() >= zoomMax()\"\n [title]=\"'i18n_zoom_in' | translate\"\n (click)=\"handlerZoomIn()\">\n <svg class=\"w-3.5 h-3.5\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\"><line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\"/><line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\"/></svg>\n </button>\n\n <!-- Ph\u00E2n c\u00E1ch -->\n <div class=\"h-[16px] w-px bg-slate-200\"></div>\n\n <!-- N\u00FAt V\u1EEBa m\u00E0n h\u00ECnh nhanh -->\n <button\n type=\"button\"\n class=\"h-[28px] shrink-0 px-2.5 flex items-center gap-1 rounded-full text-xs text-slate-700 hover:text-slate-900 hover:bg-slate-200 transition-colors cursor-pointer\"\n [title]=\"'i18n_zoom_fit_screen_tooltip' | translate\"\n (click)=\"handlerFitScreen()\">\n <svg class=\"w-3.5 h-3.5\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><polyline points=\"15 3 21 3 21 9\"/><polyline points=\"9 21 3 21 3 15\"/><line x1=\"21\" y1=\"3\" x2=\"14\" y2=\"10\"/><line x1=\"3\" y1=\"21\" x2=\"10\" y2=\"14\"/></svg>\n <span class=\"whitespace-nowrap font-medium\">{{ 'i18n_zoom_fit_screen' | translate }}</span>\n </button>\n\n <!-- N\u00FAt \u0110\u1EB7t l\u1EA1i 100% (ch\u1EC9 hi\u1EC7n khi kh\u00E1c 100%) -->\n @if (zoomPercent() !== 100) {\n <button\n type=\"button\"\n class=\"h-[28px] px-2 flex items-center gap-1 rounded-full text-xs font-semibold text-blue-600 hover:bg-blue-50 transition-colors cursor-pointer\"\n [title]=\"'i18n_zoom_reset_tooltip' | translate: { width: stageWidth(), height: stageMinHeight() }\"\n (click)=\"handlerResetZoom()\">\n <svg class=\"w-[12px] h-[12px]\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"1 4 1 10 7 10\"/><path d=\"M3.51 15a9 9 0 1 0 2.13-9.36L1 10\"/></svg>\n <span>100%</span>\n </button>\n }\n </div>\n }\n} @else {\n <!-- \uD83D\uDD34 `relative` l\u00E0 B\u1EAET BU\u1ED8C, C\u1EA4M b\u1ECF.\n gridster \u0111\u1ED5i v\u1ECB tr\u00ED chu\u1ED9t th\u00E0nh \u00F4 l\u01B0\u1EDBi b\u1EB1ng `e.clientY + (el.scrollTop - el.offsetTop)` \u2014 c\u00F4ng\n th\u1EE9c \u0111\u00F3 ch\u1EC9 \u0111\u00FAng khi `offsetParent` c\u1EE7a <gridster> CH\u00CDNH L\u00C0 kh\u1ED1i cu\u1ED9n n\u00E0y. Thi\u1EBFu `relative` th\u00EC\n `offsetParent` nh\u1EA3y l\u00EAn kh\u1ED1i bao ngo\u00E0i: `offsetTop` tr\u1EA3 16 trong khi l\u1EC7ch th\u1EADt l\u00E0 65 \u2192 gridster\n t\u00EDnh \u00F4 sai 49px, \u00F4 ch\u1EDD \u0111\u1EB7t hi\u1EC7n l\u1EC7ch kh\u1ECFi con tr\u1ECF n\u00EAn k\u00E9o th\u1EA3 kh\u00F4ng \u0111\u1ED5i \u0111\u01B0\u1EE3c v\u1ECB tr\u00ED, v\u00E0 k\u00E9o m\u00E9p\n c\u0169ng t\u00EDnh sai \u0111i\u1EC3m d\u1EEBng. -->\n <div\n #scrollArea\n class=\"libs-ui-grid-layout-scroll-area relative h-full min-h-0 w-full min-w-0\"\n [class.overflow-y-auto]=\"!isNestedCanvas()\"\n (mousedown)=\"handlerMouseDownTrongLuoi($event)\"\n (dragover)=\"handlerDragOver($event)\"\n (dragleave)=\"handlerDragLeave($event)\"\n (drop)=\"handlerDrop($event)\">\n <!-- Snapped Drop Ghost Preview -->\n @if (dropGhost(); as ghost) {\n <div\n class=\"pointer-events-none absolute z-30 flex flex-col items-center justify-center overflow-hidden rounded-lg border-2 border-dashed border-blue-500 bg-blue-500/15 p-1 shadow-sm transition-all duration-75 ease-out backdrop-blur-[0.5px] select-none\"\n [style.left.px]=\"ghost.pixelLeft\"\n [style.top.px]=\"ghost.pixelTop\"\n [style.width.px]=\"ghost.pixelWidth\"\n [style.height.px]=\"ghost.pixelHeight\">\n <div class=\"inline-flex max-w-[95%] items-center gap-1 truncate rounded-md bg-blue-600 px-2 py-0.5 text-[11px] font-semibold text-white shadow-xs\">\n @if (ghost.cardIconClass) {\n <i [class]=\"ghost.cardIconClass + ' text-xs'\"></i>\n } @else if (ghost.cardIconText) {\n <span class=\"text-[10px] font-bold\">{{ ghost.cardIconText }}</span>\n } @else {\n <span class=\"text-xs font-bold\">{{ ghost.isInsideGroup ? '\u21B3' : '+' }}</span>\n }\n <span class=\"truncate\">{{ ghost.cardTitle }}</span>\n <span class=\"text-[9px] font-mono opacity-75\">({{ ghost.cols }}c)</span>\n </div>\n\n @if (ghost.pixelHeight >= 80) {\n <div class=\"mt-1 flex max-w-[95%] items-center gap-1.5 truncate rounded border border-blue-100 bg-white/95 px-2 py-0.5 text-[10px] font-medium text-blue-700 shadow-xs\">\n @if (ghost.isInsideGroup) {\n <span class=\"truncate font-bold text-blue-900\">\u21B3 {{ ghost.groupTitle }}</span>\n <span class=\"text-blue-300\">\u2022</span>\n }\n <span>C\u1ED9t {{ ghost.col + 1 }}-{{ ghost.col + ghost.cols }}</span>\n </div>\n }\n </div>\n }\n <gridster class=\"h-full w-full\" [class.display-grid]=\"showGridLines()\" [options]=\"gridOptions()\">\n @for (item of children(); track item.id; let itemIndex = $index) {\n <!-- \uD83D\uDD34 Ch\u1EB7n `mousedown` t\u1EA1i \u0110\u00C2Y cho l\u01B0\u1EDBi l\u1ED3ng \u2014 C\u1EA4M b\u1ECF v\u00E0 C\u1EA4M chuy\u1EC3n sang ch\u1ED7 kh\u00E1c.\n `ignoreContentClass` m\u1ED9t m\u00ECnh KH\u00D4NG \u0111\u1EE7: `delayStart: 160` l\u00E0m M\u1ED6I l\u01B0\u1EDBi l\u00EAn l\u1ECBch\n `dragStart` b\u1EB1ng `setTimeout` ngay t\u1EA1i `mousedown`, c\u00F2n `stopPropagation` m\u00E0 lib g\u1ECDi b\u00EAn\n trong `dragStart` ch\u1EA1y sau 160ms n\u00EAn qu\u00E1 mu\u1ED9n \u2014 l\u01B0\u1EDBi CHA \u0111\u00E3 k\u1ECBp nh\u1EADn (\u0111o 28/08/2026: k\u00E9o\n d\u1EA3i kh\u1ED1i con, chu\u1ED7i class duy\u1EC7t l\u00EAn \u0110\u00DANG m\u00E0 container v\u1EABn nh\u1EA3y 0,0 \u2192 0,1).\n G\u1EAFn \u1EDF `gridster-item` l\u00E0 \u0111\u00FAng bi\u00EAn: l\u01B0\u1EDBi con nghe tr\u00EAn ch\u00EDnh ph\u1EA7n t\u1EED n\u00E0y n\u00EAn \u0111\u00E3 nh\u1EADn xong,\n l\u01B0\u1EDBi cha \u1EDF ngo\u00E0i b\u1ECB ch\u1EB7n. -->\n <gridster-item\n [item]=\"item\"\n [class.libs-ui-grid-layout-selected]=\"selectedNodeId() === item.id\"\n (click)=\"handlerSelectNode(item, $event)\"\n (mousedown)=\"handlerBlockParentDrag($event)\">\n <!-- \uD83D\uDD34 V\u1ECF n\u00E0y mang `dragHandleClass` \u2014 C\u1EA4M b\u1ECF.\n `ignoreContent: true` b\u1EAFt gridster CH\u1EC8 cho k\u00E9o khi ch\u1ED7 b\u1EA5m n\u1EB1m d\u01B0\u1EDBi m\u1ED9t ph\u1EA7n t\u1EED c\u00F3\n `dragHandleClass`. Kh\u00F4ng c\u00F3 v\u1ECF n\u00E0y th\u00EC component c\u1EE7a n\u01A1i d\u00F9ng (th\u01B0 vi\u1EC7n kh\u00F4ng ki\u1EC3m so\u00E1t\n \u0111\u01B0\u1EE3c class c\u1EE7a n\u00F3) s\u1EBD kh\u00F4ng c\u00F3 tay c\u1EA7m n\u00E0o, v\u00E0 KH\u00D4NG kh\u1ED1i n\u00E0o k\u00E9o \u0111\u01B0\u1EE3c \u2014 \u0111o 28/08/2026:\n k\u00E9o 320px, to\u1EA1 \u0111\u1ED9 kh\u1ED1i gi\u1EEF nguy\u00EAn x=3,y=0.\n T\u00EAn class theo c\u1EA5p: l\u01B0\u1EDBi trang v\u00E0 l\u01B0\u1EDBi l\u1ED3ng d\u00F9ng hai t\u00EAn KH\u00C1C nhau, n\u1EBFu kh\u00F4ng l\u01B0\u1EDBi cha\n c\u0169ng nh\u1EADn ra tay c\u1EA7m c\u1EE7a kh\u1ED1i con v\u00E0 nh\u1EA5c lu\u00F4n container. -->\n <!-- \uD83D\uDD34 V\u1ECF KH\u00D4NG mang `dragHandleClass` \u2014 C\u1EA4M th\u00EAm l\u1EA1i.\n K\u00E9o ch\u1EC9 \u0111\u01B0\u1EE3c ph\u00E9p b\u1EAFt \u0111\u1EA7u t\u1EEB D\u1EA2I XANH (ng\u01B0\u1EDDi d\u00F9ng ch\u1ED1t 28/08/2026: \"ph\u1EA3i hover v\u00E0o v\u00F9ng\n m\u00E0u xanh th\u00EC m\u1EDBi k\u00E9o th\u1EA3 \u0111\u01B0\u1EE3c cho \u0111\u1ED3ng nh\u1EA5t\"). Cho c\u1EA3 v\u1ECF l\u00E0m tay c\u1EA7m th\u00EC b\u1EA5m \u0111\u00E2u c\u0169ng\n k\u00E9o, v\u00E0 kh\u1ED1i con n\u1EB1m trong container s\u1EBD nh\u1EA5c lu\u00F4n container v\u00EC l\u01B0\u1EDBi cha duy\u1EC7t l\u00EAn g\u1EB7p\n tay c\u1EA7m c\u1EE7a v\u1ECF container tr\u01B0\u1EDBc.\n V\u1ECF kh\u1ED1i con v\u1EABn gi\u1EEF class CH\u1EB6N \u0111\u1EC3 l\u01B0\u1EDBi cha d\u1EEBng \u0111\u00FAng \u1EDF bi\u00EAn. -->\n <div\n class=\"libs-ui-grid-layout-block-shell group relative h-full w-full min-w-0\"\n [class.libs-ui-grid-layout-block-parent-drag]=\"isNestedCanvas()\">\n <!-- D\u1EA3i k\u00E9o: hi\u1EC7n khi r\u00EA chu\u1ED9t v\u00E0o kh\u1ED1i, ba ch\u1EA5m l\u00E0 d\u1EA5u hi\u1EC7u k\u00E9o quen thu\u1ED9c.\n Ng\u01B0\u1EDDi d\u00F9ng c\u1EA7n m\u1ED9t ch\u1ED7 b\u00E1m R\u00D5 R\u00C0NG thay v\u00EC \u0111o\u00E1n xem b\u1EA5m \u0111\u00E2u th\u00EC k\u00E9o \u0111\u01B0\u1EE3c\n (ch\u1ED1t 28/08/2026, theo \u0111\u00FAng d\u1EA3i \u0111ang d\u00F9ng \u1EDF m\u00E0n Customer 360 c\u1EE7a mobio-web). -->\n @if (isEditMode()) {\n <!-- \uD83D\uDD34 D\u1EA3i PH\u1EA2I mang tay c\u1EA7m \u0110\u00DANG C\u1EA4P c\u1EE7a n\u00F3. D\u1EA3i nh\u1EADn chu\u1ED9t (`pointer-events: auto`),\n n\u00EAn n\u1EBFu kh\u00F4ng mang tay c\u1EA7m th\u00EC `checkDragHandleClass` duy\u1EC7t l\u00EAn g\u1EB7p tay c\u1EA7m c\u1EE7a\n container v\u00E0 nh\u1EA5c container thay v\u00EC kh\u1ED1i con (\u0111o 28/08/2026: k\u00E9o d\u1EA3i kh\u1ED1i con,\n container nh\u1EA3y 0,0 \u2192 0,1 c\u00F2n kh\u1ED1i con \u0111\u1EE9ng im).\n \uD83D\uDD34 D\u1EA3i CH\u1EC8 mang tay c\u1EA7m, C\u1EA4M mang th\u00EAm class ch\u1EB7n: `checkDragHandleClass` x\u00E9t hai\n class \u0111\u00F3 tr\u00EAn C\u00D9NG m\u1ED9t node n\u00EAn \u0111\u1EC3 chung l\u00E0 k\u00E9o h\u1ECFng (\u0111o 28/08/2026: b\u1EA5m d\u1EA3i kh\u1ED1i\n con k\u00E9o 140px, kh\u1ED1i \u0111\u1EE9ng im). Vi\u1EC7c ch\u1EB7n l\u01B0\u1EDBi cha do V\u1ECE KH\u1ED0I lo. -->\n <div\n class=\"libs-ui-grid-layout-drag-bar\"\n [class.libs-ui-grid-layout-drag-bar-child]=\"isNestedCanvas()\"\n [class.libs-ui-grid-layout-drag-handle]=\"!isNestedCanvas()\"\n [class.libs-ui-grid-layout-drag-handle-child]=\"isNestedCanvas()\">\n <span class=\"libs-ui-grid-layout-drag-bar-dots\">\n @for (dot of dragBarDots; track dot) {\n <span class=\"libs-ui-grid-layout-drag-bar-dot\"></span>\n }\n </span>\n </div>\n }\n\n <!-- Khung ch\u1EE9a component c\u1EE7a n\u01A1i d\u00F9ng.\n \uD83D\uDD34 PH\u1EA2I c\u00F3 khung th\u1EADt (kh\u00F4ng ph\u1EA3i `ng-container` tr\u1ED1ng): n\u00F3 lo h\u1ED9 n\u01A1i d\u00F9ng ph\u1EA7n l\u1EA5p \u0111\u1EA7y\n \u00F4 v\u00E0 vi\u1EC1n b\u00E1o ch\u1EBF \u0111\u1ED9 s\u1EEDa. Kh\u00F4ng c\u00F3 khung th\u00EC m\u1ED7i component n\u1ED9i dung l\u1EA1i ph\u1EA3i t\u1EF1 vi\u1EBFt\n `:host { width/height: 100% }` + vi\u1EC1n \u0111\u1EE9t \u2014 \u0111\u00F3 l\u00E0 vi\u1EC7c c\u1EE7a th\u01B0 vi\u1EC7n, kh\u00F4ng ph\u1EA3i c\u1EE7a\n ng\u01B0\u1EDDi d\u00F9ng (ng\u01B0\u1EDDi d\u00F9ng ch\u1ED1t 28/08/2026).\n M\u1ED7i kh\u1ED1i m\u1ED9t ViewContainerRef ri\u00EAng n\u00EAn component n\u1EB1m \u0111\u00FAng \u00F4 c\u1EE7a n\u00F3. -->\n <div\n class=\"libs-ui-grid-layout-content-frame\"\n [class.libs-ui-grid-layout-content-frame-edit]=\"isEditMode() && !isContainer(item)\"\n [class.libs-ui-grid-layout-content-frame-empty]=\"isContainer(item)\">\n <ng-container #itemHost />\n </div>\n\n <!-- D\u1EA5u hi\u1EC7u CONTAINER: nh\u00E3n g\u00F3c tr\u00EAn-ph\u1EA3i + vi\u1EC1n \u0111\u1EE9t bao ru\u1ED9t. Kh\u00F4ng c\u00F3 d\u1EA5u hi\u1EC7u th\u00EC\n ng\u01B0\u1EDDi d\u00F9ng kh\u00F4ng bi\u1EBFt kh\u1ED1i n\u00E0o ch\u1EE9a \u0111\u01B0\u1EE3c kh\u1ED1i kh\u00E1c (ch\u1ED1t 28/08/2026, theo \u0111\u00FAng c\u00E1ch\n m\u00E0n Customer 360 c\u1EE7a mobio-web \u0111ang l\u00E0m). -->\n @if (isEditMode() && isContainer(item)) {\n <div class=\"libs-ui-grid-layout-container-label\">{{ 'i18n_container_block' | translate }}</div>\n <div class=\"libs-ui-grid-layout-container-border\"></div>\n }\n\n <!-- Thanh c\u00F4ng c\u1EE5: hi\u1EC7n khi r\u00EA chu\u1ED9t v\u00E0o kh\u1ED1i.\n \uD83D\uDD34 D\u00F9ng `libs_ui-components-buttons-button` \u2014 C\u1EA4M t\u1EF1 d\u1EF1ng th\u1EBB `<button>`.\n Component n\u00E0y \u0111\u00E3 c\u00F3 s\u1EB5n ki\u1EC3u n\u00FAt, c\u1EE1 n\u00FAt v\u00E0 bong b\u00F3ng ch\u00FA th\u00EDch theo \u0111\u00FAng b\u1ED9 giao di\u1EC7n\n c\u1EE7a s\u1EA3n ph\u1EA9m; t\u1EF1 d\u1EF1ng l\u00E0 m\u1ED7i n\u01A1i m\u1ED9t ki\u1EC3u v\u00E0 m\u1EA5t lu\u00F4n tooltip. -->\n @if (isEditMode() && !hiddenToolbar()) {\n @if (templateToolbar()) {\n <!-- N\u01A1i d\u00F9ng t\u1EF1 v\u1EBD thanh c\u00F4ng c\u1EE5: nh\u1EADn kh\u1ED1i + c\u00E1c h\u00E0m ph\u00E1t event qua context.\n\n \uD83D\uDD34 Kh\u1ED1i b\u1ECDc t\u1EF1 ch\u1EB7n `mousedown`/`click` n\u1ED5i l\u00EAn gridster. Thanh c\u00F4ng c\u1EE5 n\u1EB1m trong\n v\u00F9ng mang `dragHandleClass`; kh\u00F4ng ch\u1EB7n th\u00EC c\u00FA b\u1EA5m b\u1ECB hi\u1EC3u l\u00E0 b\u1EAFt \u0111\u1EA7u k\u00E9o v\u00E0\n `delayStart: 160` nu\u1ED1t lu\u00F4n `click` \u2014 n\u00FAt trong template ngo\u00E0i b\u1EA5m kh\u00F4ng \u0103n\n (\u0111o 09/09/2026: b\u1EA5m b\u1EB1ng `.click()` c\u1EE7a DOM th\u00EC m\u1EDF, b\u1EA5m chu\u1ED9t th\u1EADt th\u00EC kh\u00F4ng).\n Ch\u1EB7n \u1EDF \u0110\u00C2Y \u0111\u1EC3 n\u01A1i d\u00F9ng kh\u00F4ng ph\u1EA3i bi\u1EBFt b\u1EABy n\u00E0y. -->\n <div\n class=\"libs-ui-grid-layout-toolbar\"\n role=\"toolbar\"\n tabindex=\"0\"\n [class.libs-ui-grid-layout-toolbar-child]=\"isNestedCanvas()\"\n (mousedown)=\"handlerStopEvent($event)\"\n (keydown)=\"handlerStopEvent($event)\"\n (click)=\"handlerStopEvent($event)\">\n <ng-container\n *ngTemplateOutlet=\"templateToolbar()!; context: toolbarContexts()[itemIndex]\" />\n </div>\n } @else {\n <div\n class=\"libs-ui-grid-layout-toolbar\"\n [class.libs-ui-grid-layout-toolbar-child]=\"isNestedCanvas()\">\n <span class=\"libs-ui-grid-layout-dim-badge\">\n {{ item.rows }} h\u00E0ng \u00D7 {{ item.cols }} c\u1ED9t\n </span>\n @if (canAddInside(item)) {\n <libs_ui-components-buttons-button\n [type]=\"'button-third'\"\n [iconOnlyType]=\"true\"\n [sizeButton]=\"'smaller'\"\n [classIconLeft]=\"'libs-ui-icon-add'\"\n [popover]=\"{ config: { content: 'Th\u00EAm kh\u1ED1i v\u00E0o trong', zIndex: 1300 } }\"\n (outClick)=\"handlerAddInside($event, item)\" />\n }\n @if (canToggleType(item)) {\n <libs_ui-components-buttons-button\n [type]=\"'button-third'\"\n [iconOnlyType]=\"true\"\n [sizeButton]=\"'smaller'\"\n [classIconLeft]=\"isContainer(item) ? 'libs-ui-icon-split-cell' : 'libs-ui-icon-merge-cell'\"\n [popover]=\"{ config: { content: isContainer(item) ? '\u0110\u01B0a v\u1EC1 kh\u1ED1i \u0111\u01A1n' : 'Chuy\u1EC3n th\u00E0nh kh\u1ED1i gh\u00E9p', zIndex: 1300 } }\"\n (outClick)=\"handlerToggleType($event, item)\" />\n }\n <libs_ui-components-buttons-button\n [type]=\"'button-third'\"\n [iconOnlyType]=\"true\"\n [sizeButton]=\"'smaller'\"\n [classIconLeft]=\"'libs-ui-icon-setting'\"\n [popover]=\"{ config: { content: 'C\u1EA5u h\u00ECnh th\u1EBB', zIndex: 1300 } }\"\n (outClick)=\"handlerConfig($event, item)\" />\n <libs_ui-components-buttons-button\n [type]=\"'button-third-hover-danger'\"\n [iconOnlyType]=\"true\"\n [sizeButton]=\"'smaller'\"\n [classIconLeft]=\"'libs-ui-icon-remove'\"\n [popover]=\"{ config: { content: isContainer(item) ? 'Xo\u00E1 c\u1EA3 kh\u1ED1i gh\u00E9p' : 'Xo\u00E1 kh\u1ED1i', zIndex: 1300 } }\"\n (outClick)=\"handlerRemove($event, item)\" />\n </div>\n }\n }\n\n @if (item.children && item.children.length > 0) {\n <!-- Kh\u1ED1i c\u00F3 con \u2192 ru\u1ED9t n\u00F3 l\u1EA1i l\u00E0 m\u1ED9t m\u1EB7t ph\u1EB3ng n\u1EEFa. \u0110\u1EC7 quy \u1EDF \u0111\u00E2y, n\u01A1i d\u00F9ng kh\u00F4ng ph\u1EA3i lo.\n L\u1EC1 \u0111\u1EB7t \u1EDF \u0110\u00C2Y (v\u1ECF container), kh\u00F4ng \u0111\u1EB7t v\u00E0o l\u01B0\u1EDBi con \u2014 l\u01B0\u1EDBi con gi\u1EEF nguy\u00EAn khe 2px. -->\n <libs_ui-services-grid_layout-canvas\n class=\"block h-full w-full\"\n [style.padding]=\"containerPadding()\"\n [node]=\"item\"\n [depth]=\"depth() + 1\"\n [hiddenToolbar]=\"hiddenToolbar()\"\n [templateToolbar]=\"templateToolbar()\"\n [selectedNodeId]=\"selectedNodeId()\"\n (outSelectNode)=\"outSelectNode.emit($event)\"\n (outConfigNode)=\"outConfigNode.emit($event)\"\n (outChange)=\"outChange.emit($event)\"\n (outRemoveNode)=\"outRemoveNode.emit($event)\"\n (outAddBlockInside)=\"outAddBlockInside.emit($event)\"\n (outToggleType)=\"outToggleType.emit($event)\" />\n }\n </div>\n </gridster-item>\n }\n </gridster>\n </div>\n}\n", styles: [":host{display:block;position:relative;box-sizing:border-box;width:100%;height:100%;min-width:0;min-height:0}.libs-ui-grid-layout-block-shell{container-type:inline-size;display:block;box-sizing:border-box;height:100%}.libs-ui-grid-layout-drag-bar{position:absolute;top:2px;left:50%;z-index:15;display:flex;align-items:center;justify-content:center;width:64px;height:16px;background:transparent;transform:translate(-50%);opacity:1;transition:opacity .12s ease;pointer-events:auto;cursor:move}.libs-ui-grid-layout-drag-bar-dots{display:grid;grid-template-columns:repeat(3,3px);gap:3px;color:#9ca2ad}.libs-ui-grid-layout-drag-bar-dot{width:3px;height:3px;background:currentColor;border-radius:50%}.libs-ui-grid-layout-drag-bar:hover .libs-ui-grid-layout-drag-bar-dots{color:#3d6ef5}.libs-ui-grid-layout-drag-bar:not(.libs-ui-grid-layout-drag-bar-child){opacity:1}.libs-ui-grid-layout-drag-bar-child{top:auto;bottom:0;background:#d9f2e4;border-radius:4px 4px 0 0}.libs-ui-grid-layout-drag-bar-child .libs-ui-grid-layout-drag-bar-dots{color:#9ca2ad}.libs-ui-grid-layout-drag-bar-child:hover .libs-ui-grid-layout-drag-bar-dots{color:#00a757}.libs-ui-grid-layout-drag-bar-child{opacity:0}.libs-ui-grid-layout-block-shell:hover>.libs-ui-grid-layout-drag-bar-child{opacity:1}.libs-ui-grid-layout-block-shell:has(>.libs-ui-grid-layout-drag-bar:not(.libs-ui-grid-layout-drag-bar-child):hover){outline:2px solid #3d6ef5;outline-offset:-2px;border-radius:8px}.libs-ui-grid-layout-block-shell:has(>.libs-ui-grid-layout-drag-bar-child:hover){outline:2px solid #00a757;outline-offset:-2px;border-radius:8px}.libs-ui-grid-layout-container-label{position:absolute;left:6px;top:2px;display:flex;height:20px;align-items:center;z-index:3;padding:0 6px;color:#3d6ef5;font-weight:500;font-size:10px;line-height:14px;background:#dbe4ff;border-radius:4px;pointer-events:none}.libs-ui-grid-layout-content-frame{box-sizing:border-box;width:100%;height:100%;overflow:hidden;border-radius:6px}.libs-ui-grid-layout-content-frame ::ng-deep>*{display:block;box-sizing:border-box;width:100%;height:100%}.libs-ui-grid-layout-content-frame-empty{height:0}.libs-ui-grid-layout-content-frame-edit{border:1px dashed #c3cede}.libs-ui-grid-layout-container-border{position:absolute;inset:0;border:1px dashed #9db4f0;border-radius:8px;pointer-events:none}.libs-ui-grid-layout-toolbar{position:absolute;top:6px;right:8px;z-index:24;display:flex;gap:2px;align-items:center;height:20px;background:#fff;border-radius:4px;box-shadow:0 2px 8px #0716311f;opacity:0;transition:opacity .12s ease}.libs-ui-grid-layout-toolbar-child{top:50%;right:8px;left:auto;transform:translateY(-50%)}.libs-ui-grid-layout-block-shell:hover>.libs-ui-grid-layout-toolbar{opacity:1}:host ::ng-deep gridster{background:transparent}:host ::ng-deep .gridster-item-resizable-handler.handle-n,:host ::ng-deep .gridster-item-resizable-handler.handle-s{height:16px}:host ::ng-deep .gridster-item-resizable-handler.handle-e,:host ::ng-deep .gridster-item-resizable-handler.handle-w{width:16px}:host ::ng-deep .gridster-item-resizable-handler.handle-n{top:0}:host ::ng-deep .gridster-item-resizable-handler.handle-s{bottom:0}:host ::ng-deep .gridster-item-resizable-handler.handle-e{right:0}:host ::ng-deep .gridster-item-resizable-handler.handle-w{left:0}:host ::ng-deep gridster-item.gridster-item-moving,:host ::ng-deep gridster-item.gridster-item-resizing{z-index:30!important}:host ::ng-deep gridster-item.gridster-item-moving>.libs-ui-grid-layout-block-shell,:host ::ng-deep gridster-item.gridster-item-resizing>.libs-ui-grid-layout-block-shell{outline:2px solid #3d6ef5;outline-offset:-2px;border-radius:8px}:host ::ng-deep gridster gridster gridster-item.gridster-item-moving>.libs-ui-grid-layout-block-shell,:host ::ng-deep gridster gridster gridster-item.gridster-item-resizing>.libs-ui-grid-layout-block-shell{outline-color:#00a757}:host ::ng-deep gridster-item.libs-ui-grid-layout-selected>.libs-ui-grid-layout-block-shell{outline:2px solid #2563eb!important;outline-offset:-2px!important;border-radius:8px!important;box-shadow:0 0 0 4px #2563eb26!important}:host ::ng-deep gridster.display-grid .gridster-column,:host ::ng-deep gridster gridster.display-grid .gridster-column{border-right:1px solid rgba(226,232,240,.7)!important;border-left:none!important;pointer-events:none!important;height:100%!important;min-height:100%!important}:host ::ng-deep gridster.display-grid .gridster-column:first-child,:host ::ng-deep gridster gridster.display-grid .gridster-column:first-child{border-left:1px solid rgba(226,232,240,.7)!important}:host ::ng-deep gridster.display-grid .gridster-row,:host ::ng-deep gridster gridster.display-grid .gridster-row{border-bottom:1px solid rgba(226,232,240,.7)!important;border-top:none!important;pointer-events:none!important}:host ::ng-deep gridster.display-grid .gridster-row:first-child,:host ::ng-deep gridster gridster.display-grid .gridster-row:first-child{border-top:1px solid rgba(226,232,240,.7)!important}:host ::ng-deep gridster gridster.display-grid{background-color:#f8fafc80!important}:host ::ng-deep gridster-preview{background:#2563eb1f!important;border:1.5px dashed #2563eb!important;border-radius:6px!important;z-index:25!important}.libs-ui-grid-layout-dim-badge{display:inline-flex;align-items:center;height:20px;padding:0 6px;background-color:#f1f5f9;border:1px solid #e2e8f0;border-radius:4px;color:#64748b;font-size:10px;font-weight:500;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;pointer-events:none;white-space:nowrap}@container (max-width: 80px){.libs-ui-grid-layout-drag-bar{top:26px}}.libs-ui-grid-layout-stage{box-sizing:border-box;transform-origin:top center;transition:zoom .15s ease-out}#canvas-zoom-dock{box-shadow:0 10px 25px -5px #0000001a,0 8px 10px -6px #0000001a}\n"], dependencies: [{ kind: "component", type: LibsUiGridLayoutCanvasComponent, selector: "libs_ui-services-grid_layout-canvas", inputs: ["node", "depth", "hiddenToolbar", "templateToolbar", "enableZoom", "zoom", "zoomMin", "zoomMax", "zoomStep", "stageWidth", "stageMinHeight", "storageKey", "showZoomDock", "autoFitOnLoad", "enableExternalDrop", "showGridLines", "selectedNodeId"], outputs: ["outChange", "outRemoveNode", "outAddBlockInside", "outToggleType", "zoomChange", "outZoomChange", "selectedNodeIdChange", "outDropNode", "outSelectNode", "outConfigNode"] }, { kind: "ngmodule", type: GridsterModule }, { kind: "component", type: i1.GridsterComponent, selector: "gridster", inputs: ["options"] }, { kind: "component", type: i1.GridsterItemComponent, selector: "gridster-item", inputs: ["item"], outputs: ["itemInit", "itemChange", "itemResize"] }, { kind: "component", type: LibsUiComponentsButtonsButtonComponent, selector: "libs_ui-components-buttons-button", inputs: ["flagMouse", "type", "buttonCustom", "sizeButton", "label", "disable", "isPending", "imageLeft", "classInclude", "classIconLeft", "classIconRight", "classLabel", "iconOnlyType", "popover", "ignoreStopPropagationEvent", "zIndex", "widthLabelPopover", "styleIconLeft", "styleButton", "ignoreFocusWhenInputTab", "ignoreSetClickWhenShowPopover", "ignorePointerEvent", "isActive", "isHandlerEnterDocumentClickButton"], outputs: ["outClick", "outPopoverEvent", "outFunctionsControl"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i2.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
558
561
|
}
|
|
559
562
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: LibsUiGridLayoutCanvasComponent, decorators: [{
|
|
560
563
|
type: Component,
|
|
561
|
-
args: [{ selector: 'libs_ui-services-grid_layout-canvas', standalone: true, imports: [GridsterModule, LibsUiComponentsButtonsButtonComponent, NgTemplateOutlet, TranslateModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (isZoomActive()) {\n <!-- Khu v\u1EF1c cu\u1ED9n ch\u1EE9a canvas stage thu ph\u00F3ng -->\n <div\n #scrollArea\n class=\"libs-ui-grid-layout-scroll-area relative h-full min-h-0 w-full min-w-0 overflow-auto p-6 flex justify-center items-start\"\n (mousedown)=\"handlerMouseDownTrongLuoi($event)\"\n (wheel)=\"handlerWheel($event)\"\n (dragover)=\"handlerDragOver($event)\"\n (dragleave)=\"handlerDragLeave($event)\"\n (drop)=\"handlerDrop($event)\">\n <div\n #canvasStage\n id=\"bi-canvas-stage\"\n class=\"libs-ui-grid-layout-stage relative flex flex-col transition-[zoom] duration-150 origin-top shrink-0 bg-white/80 border border-slate-200/80 rounded-2xl shadow-sm p-4\"\n [style.zoom]=\"currentZoom()\"\n [style.width.px]=\"stageWidth()\"\n [style.min-width.px]=\"stageWidth()\"\n [style.min-height.px]=\"stageMinHeight()\">\n <!-- Snapped Drop Ghost Preview -->\n @if (dropGhost(); as ghost) {\n <div\n class=\"pointer-events-none absolute z-30 flex flex-col items-center justify-center overflow-hidden rounded-lg border-2 border-dashed border-blue-500 bg-blue-500/15 p-1 shadow-sm transition-all duration-75 ease-out backdrop-blur-[0.5px] select-none\"\n [style.left.px]=\"ghost.pixelLeft\"\n [style.top.px]=\"ghost.pixelTop\"\n [style.width.px]=\"ghost.pixelWidth\"\n [style.height.px]=\"ghost.pixelHeight\">\n <div class=\"inline-flex max-w-[95%] items-center gap-1 truncate rounded-md bg-blue-600 px-2 py-0.5 text-[11px] font-semibold text-white shadow-xs\">\n @if (ghost.cardIconClass) {\n <i [class]=\"ghost.cardIconClass + ' text-xs'\"></i>\n } @else if (ghost.cardIconText) {\n <span class=\"text-[10px] font-bold\">{{ ghost.cardIconText }}</span>\n } @else {\n <span class=\"text-xs font-bold\">{{ ghost.isInsideGroup ? '\u21B3' : '+' }}</span>\n }\n <span class=\"truncate\">{{ ghost.cardTitle }}</span>\n <span class=\"text-[9px] font-mono opacity-75\">({{ ghost.cols }}c)</span>\n </div>\n\n @if (ghost.pixelHeight >= 80) {\n <div class=\"mt-1 flex max-w-[95%] items-center gap-1.5 truncate rounded border border-blue-100 bg-white/95 px-2 py-0.5 text-[10px] font-medium text-blue-700 shadow-xs\">\n @if (ghost.isInsideGroup) {\n <span class=\"truncate font-bold text-blue-900\">\u21B3 {{ ghost.groupTitle }}</span>\n <span class=\"text-blue-300\">\u2022</span>\n }\n <span>C\u1ED9t {{ ghost.col + 1 }}-{{ ghost.col + ghost.cols }}</span>\n </div>\n }\n </div>\n }\n <gridster class=\"h-full w-full\" [class.display-grid]=\"showGridLines()\" [options]=\"gridOptions()\">\n @for (item of children(); track item.id; let itemIndex = $index) {\n <!-- \uD83D\uDD34 Ch\u1EB7n `mousedown` t\u1EA1i \u0110\u00C2Y cho l\u01B0\u1EDBi l\u1ED3ng \u2014 C\u1EA4M b\u1ECF v\u00E0 C\u1EA4M chuy\u1EC3n sang ch\u1ED7 kh\u00E1c.\n `ignoreContentClass` m\u1ED9t m\u00ECnh KH\u00D4NG \u0111\u1EE7: `delayStart: 160` l\u00E0m M\u1ED6I l\u01B0\u1EDBi l\u00EAn l\u1ECBch\n `dragStart` b\u1EB1ng `setTimeout` ngay t\u1EA1i `mousedown`, c\u00F2n `stopPropagation` m\u00E0 lib g\u1ECDi b\u00EAn\n trong `dragStart` ch\u1EA1y sau 160ms n\u00EAn qu\u00E1 mu\u1ED9n \u2014 l\u01B0\u1EDBi CHA \u0111\u00E3 k\u1ECBp nh\u1EADn (\u0111o 28/08/2026: k\u00E9o\n d\u1EA3i kh\u1ED1i con, chu\u1ED7i class duy\u1EC7t l\u00EAn \u0110\u00DANG m\u00E0 container v\u1EABn nh\u1EA3y 0,0 \u2192 0,1).\n G\u1EAFn \u1EDF `gridster-item` l\u00E0 \u0111\u00FAng bi\u00EAn: l\u01B0\u1EDBi con nghe tr\u00EAn ch\u00EDnh ph\u1EA7n t\u1EED n\u00E0y n\u00EAn \u0111\u00E3 nh\u1EADn xong,\n l\u01B0\u1EDBi cha \u1EDF ngo\u00E0i b\u1ECB ch\u1EB7n. -->\n <gridster-item\n [item]=\"item\"\n [class.libs-ui-grid-layout-selected]=\"selectedNodeId() === item.id\"\n (click)=\"handlerSelectNode(item, $event)\"\n (mousedown)=\"handlerBlockParentDrag($event)\">\n <!-- \uD83D\uDD34 V\u1ECF n\u00E0y mang `dragHandleClass` \u2014 C\u1EA4M b\u1ECF.\n `ignoreContent: true` b\u1EAFt gridster CH\u1EC8 cho k\u00E9o khi ch\u1ED7 b\u1EA5m n\u1EB1m d\u01B0\u1EDBi m\u1ED9t ph\u1EA7n t\u1EED c\u00F3\n `dragHandleClass`. Kh\u00F4ng c\u00F3 v\u1ECF n\u00E0y th\u00EC component c\u1EE7a n\u01A1i d\u00F9ng (th\u01B0 vi\u1EC7n kh\u00F4ng ki\u1EC3m so\u00E1t\n \u0111\u01B0\u1EE3c class c\u1EE7a n\u00F3) s\u1EBD kh\u00F4ng c\u00F3 tay c\u1EA7m n\u00E0o, v\u00E0 KH\u00D4NG kh\u1ED1i n\u00E0o k\u00E9o \u0111\u01B0\u1EE3c \u2014 \u0111o 28/08/2026:\n k\u00E9o 320px, to\u1EA1 \u0111\u1ED9 kh\u1ED1i gi\u1EEF nguy\u00EAn x=3,y=0.\n T\u00EAn class theo c\u1EA5p: l\u01B0\u1EDBi trang v\u00E0 l\u01B0\u1EDBi l\u1ED3ng d\u00F9ng hai t\u00EAn KH\u00C1C nhau, n\u1EBFu kh\u00F4ng l\u01B0\u1EDBi cha\n c\u0169ng nh\u1EADn ra tay c\u1EA7m c\u1EE7a kh\u1ED1i con v\u00E0 nh\u1EA5c lu\u00F4n container. -->\n <!-- \uD83D\uDD34 V\u1ECF KH\u00D4NG mang `dragHandleClass` \u2014 C\u1EA4M th\u00EAm l\u1EA1i.\n K\u00E9o ch\u1EC9 \u0111\u01B0\u1EE3c ph\u00E9p b\u1EAFt \u0111\u1EA7u t\u1EEB D\u1EA2I XANH (ng\u01B0\u1EDDi d\u00F9ng ch\u1ED1t 28/08/2026: \"ph\u1EA3i hover v\u00E0o v\u00F9ng\n m\u00E0u xanh th\u00EC m\u1EDBi k\u00E9o th\u1EA3 \u0111\u01B0\u1EE3c cho \u0111\u1ED3ng nh\u1EA5t\"). Cho c\u1EA3 v\u1ECF l\u00E0m tay c\u1EA7m th\u00EC b\u1EA5m \u0111\u00E2u c\u0169ng\n k\u00E9o, v\u00E0 kh\u1ED1i con n\u1EB1m trong container s\u1EBD nh\u1EA5c lu\u00F4n container v\u00EC l\u01B0\u1EDBi cha duy\u1EC7t l\u00EAn g\u1EB7p\n tay c\u1EA7m c\u1EE7a v\u1ECF container tr\u01B0\u1EDBc.\n V\u1ECF kh\u1ED1i con v\u1EABn gi\u1EEF class CH\u1EB6N \u0111\u1EC3 l\u01B0\u1EDBi cha d\u1EEBng \u0111\u00FAng \u1EDF bi\u00EAn. -->\n <div\n class=\"libs-ui-grid-layout-block-shell group relative h-full w-full min-w-0\"\n [class.libs-ui-grid-layout-block-parent-drag]=\"isNestedCanvas()\">\n <!-- D\u1EA3i k\u00E9o: hi\u1EC7n khi r\u00EA chu\u1ED9t v\u00E0o kh\u1ED1i, ba ch\u1EA5m l\u00E0 d\u1EA5u hi\u1EC7u k\u00E9o quen thu\u1ED9c.\n Ng\u01B0\u1EDDi d\u00F9ng c\u1EA7n m\u1ED9t ch\u1ED7 b\u00E1m R\u00D5 R\u00C0NG thay v\u00EC \u0111o\u00E1n xem b\u1EA5m \u0111\u00E2u th\u00EC k\u00E9o \u0111\u01B0\u1EE3c\n (ch\u1ED1t 28/08/2026, theo \u0111\u00FAng d\u1EA3i \u0111ang d\u00F9ng \u1EDF m\u00E0n Customer 360 c\u1EE7a mobio-web). -->\n @if (isEditMode()) {\n <!-- \uD83D\uDD34 D\u1EA3i PH\u1EA2I mang tay c\u1EA7m \u0110\u00DANG C\u1EA4P c\u1EE7a n\u00F3. D\u1EA3i nh\u1EADn chu\u1ED9t (`pointer-events: auto`),\n n\u00EAn n\u1EBFu kh\u00F4ng mang tay c\u1EA7m th\u00EC `checkDragHandleClass` duy\u1EC7t l\u00EAn g\u1EB7p tay c\u1EA7m c\u1EE7a\n container v\u00E0 nh\u1EA5c container thay v\u00EC kh\u1ED1i con (\u0111o 28/08/2026: k\u00E9o d\u1EA3i kh\u1ED1i con,\n container nh\u1EA3y 0,0 \u2192 0,1 c\u00F2n kh\u1ED1i con \u0111\u1EE9ng im).\n \uD83D\uDD34 D\u1EA3i CH\u1EC8 mang tay c\u1EA7m, C\u1EA4M mang th\u00EAm class ch\u1EB7n: `checkDragHandleClass` x\u00E9t hai\n class \u0111\u00F3 tr\u00EAn C\u00D9NG m\u1ED9t node n\u00EAn \u0111\u1EC3 chung l\u00E0 k\u00E9o h\u1ECFng (\u0111o 28/08/2026: b\u1EA5m d\u1EA3i kh\u1ED1i\n con k\u00E9o 140px, kh\u1ED1i \u0111\u1EE9ng im). Vi\u1EC7c ch\u1EB7n l\u01B0\u1EDBi cha do V\u1ECE KH\u1ED0I lo. -->\n <div\n class=\"libs-ui-grid-layout-drag-bar\"\n [class.libs-ui-grid-layout-drag-bar-child]=\"isNestedCanvas()\"\n [class.libs-ui-grid-layout-drag-handle]=\"!isNestedCanvas()\"\n [class.libs-ui-grid-layout-drag-handle-child]=\"isNestedCanvas()\">\n <span class=\"libs-ui-grid-layout-drag-bar-dots\">\n @for (dot of dragBarDots; track dot) {\n <span class=\"libs-ui-grid-layout-drag-bar-dot\"></span>\n }\n </span>\n </div>\n }\n\n <!-- Khung ch\u1EE9a component c\u1EE7a n\u01A1i d\u00F9ng.\n \uD83D\uDD34 PH\u1EA2I c\u00F3 khung th\u1EADt (kh\u00F4ng ph\u1EA3i `ng-container` tr\u1ED1ng): n\u00F3 lo h\u1ED9 n\u01A1i d\u00F9ng ph\u1EA7n l\u1EA5p \u0111\u1EA7y\n \u00F4 v\u00E0 vi\u1EC1n b\u00E1o ch\u1EBF \u0111\u1ED9 s\u1EEDa. Kh\u00F4ng c\u00F3 khung th\u00EC m\u1ED7i component n\u1ED9i dung l\u1EA1i ph\u1EA3i t\u1EF1 vi\u1EBFt\n `:host { width/height: 100% }` + vi\u1EC1n \u0111\u1EE9t \u2014 \u0111\u00F3 l\u00E0 vi\u1EC7c c\u1EE7a th\u01B0 vi\u1EC7n, kh\u00F4ng ph\u1EA3i c\u1EE7a\n ng\u01B0\u1EDDi d\u00F9ng (ng\u01B0\u1EDDi d\u00F9ng ch\u1ED1t 28/08/2026).\n M\u1ED7i kh\u1ED1i m\u1ED9t ViewContainerRef ri\u00EAng n\u00EAn component n\u1EB1m \u0111\u00FAng \u00F4 c\u1EE7a n\u00F3. -->\n <div\n class=\"libs-ui-grid-layout-content-frame\"\n [class.libs-ui-grid-layout-content-frame-edit]=\"isEditMode() && !isContainer(item)\"\n [class.libs-ui-grid-layout-content-frame-empty]=\"isContainer(item)\">\n <ng-container #itemHost />\n </div>\n\n <!-- D\u1EA5u hi\u1EC7u CONTAINER: nh\u00E3n g\u00F3c tr\u00EAn-ph\u1EA3i + vi\u1EC1n \u0111\u1EE9t bao ru\u1ED9t. Kh\u00F4ng c\u00F3 d\u1EA5u hi\u1EC7u th\u00EC\n ng\u01B0\u1EDDi d\u00F9ng kh\u00F4ng bi\u1EBFt kh\u1ED1i n\u00E0o ch\u1EE9a \u0111\u01B0\u1EE3c kh\u1ED1i kh\u00E1c (ch\u1ED1t 28/08/2026, theo \u0111\u00FAng c\u00E1ch\n m\u00E0n Customer 360 c\u1EE7a mobio-web \u0111ang l\u00E0m). -->\n @if (isEditMode() && isContainer(item)) {\n <div class=\"libs-ui-grid-layout-container-label\">{{ 'i18n_container_block' | translate }}</div>\n <div class=\"libs-ui-grid-layout-container-border\"></div>\n }\n\n <!-- Thanh c\u00F4ng c\u1EE5: hi\u1EC7n khi r\u00EA chu\u1ED9t v\u00E0o kh\u1ED1i.\n \uD83D\uDD34 D\u00F9ng `libs_ui-components-buttons-button` \u2014 C\u1EA4M t\u1EF1 d\u1EF1ng th\u1EBB `<button>`.\n Component n\u00E0y \u0111\u00E3 c\u00F3 s\u1EB5n ki\u1EC3u n\u00FAt, c\u1EE1 n\u00FAt v\u00E0 bong b\u00F3ng ch\u00FA th\u00EDch theo \u0111\u00FAng b\u1ED9 giao di\u1EC7n\n c\u1EE7a s\u1EA3n ph\u1EA9m; t\u1EF1 d\u1EF1ng l\u00E0 m\u1ED7i n\u01A1i m\u1ED9t ki\u1EC3u v\u00E0 m\u1EA5t lu\u00F4n tooltip. -->\n @if (isEditMode() && !hiddenToolbar()) {\n @if (templateToolbar()) {\n <!-- N\u01A1i d\u00F9ng t\u1EF1 v\u1EBD thanh c\u00F4ng c\u1EE5: nh\u1EADn kh\u1ED1i + c\u00E1c h\u00E0m ph\u00E1t event qua context.\n\n \uD83D\uDD34 Kh\u1ED1i b\u1ECDc t\u1EF1 ch\u1EB7n `mousedown`/`click` n\u1ED5i l\u00EAn gridster. Thanh c\u00F4ng c\u1EE5 n\u1EB1m trong\n v\u00F9ng mang `dragHandleClass`; kh\u00F4ng ch\u1EB7n th\u00EC c\u00FA b\u1EA5m b\u1ECB hi\u1EC3u l\u00E0 b\u1EAFt \u0111\u1EA7u k\u00E9o v\u00E0\n `delayStart: 160` nu\u1ED1t lu\u00F4n `click` \u2014 n\u00FAt trong template ngo\u00E0i b\u1EA5m kh\u00F4ng \u0103n\n (\u0111o 09/09/2026: b\u1EA5m b\u1EB1ng `.click()` c\u1EE7a DOM th\u00EC m\u1EDF, b\u1EA5m chu\u1ED9t th\u1EADt th\u00EC kh\u00F4ng).\n Ch\u1EB7n \u1EDF \u0110\u00C2Y \u0111\u1EC3 n\u01A1i d\u00F9ng kh\u00F4ng ph\u1EA3i bi\u1EBFt b\u1EABy n\u00E0y. -->\n <div\n class=\"libs-ui-grid-layout-toolbar\"\n role=\"toolbar\"\n tabindex=\"0\"\n [class.libs-ui-grid-layout-toolbar-child]=\"isNestedCanvas()\"\n (mousedown)=\"handlerStopEvent($event)\"\n (keydown)=\"handlerStopEvent($event)\"\n (click)=\"handlerStopEvent($event)\">\n <ng-container\n *ngTemplateOutlet=\"templateToolbar()!; context: toolbarContexts()[itemIndex]\" />\n </div>\n } @else {\n <div\n class=\"libs-ui-grid-layout-toolbar\"\n [class.libs-ui-grid-layout-toolbar-child]=\"isNestedCanvas()\">\n <span class=\"libs-ui-grid-layout-dim-badge\">\n {{ item.rows }} h\u00E0ng \u00D7 {{ item.cols }} c\u1ED9t\n </span>\n @if (canAddInside(item)) {\n <libs_ui-components-buttons-button\n [type]=\"'button-third'\"\n [iconOnlyType]=\"true\"\n [sizeButton]=\"'smaller'\"\n [classIconLeft]=\"'libs-ui-icon-add'\"\n [popover]=\"{ config: { content: 'Th\u00EAm kh\u1ED1i v\u00E0o trong', zIndex: 1300 } }\"\n (outClick)=\"handlerAddInside($event, item)\" />\n }\n @if (canToggleType(item)) {\n <libs_ui-components-buttons-button\n [type]=\"'button-third'\"\n [iconOnlyType]=\"true\"\n [sizeButton]=\"'smaller'\"\n [classIconLeft]=\"isContainer(item) ? 'libs-ui-icon-split-cell' : 'libs-ui-icon-merge-cell'\"\n [popover]=\"{ config: { content: isContainer(item) ? '\u0110\u01B0a v\u1EC1 kh\u1ED1i \u0111\u01A1n' : 'Chuy\u1EC3n th\u00E0nh kh\u1ED1i gh\u00E9p', zIndex: 1300 } }\"\n (outClick)=\"handlerToggleType($event, item)\" />\n }\n <libs_ui-components-buttons-button\n [type]=\"'button-third'\"\n [iconOnlyType]=\"true\"\n [sizeButton]=\"'smaller'\"\n [classIconLeft]=\"'libs-ui-icon-setting'\"\n [popover]=\"{ config: { content: 'C\u1EA5u h\u00ECnh th\u1EBB', zIndex: 1300 } }\"\n (outClick)=\"handlerConfig($event, item)\" />\n <libs_ui-components-buttons-button\n [type]=\"'button-third-hover-danger'\"\n [iconOnlyType]=\"true\"\n [sizeButton]=\"'smaller'\"\n [classIconLeft]=\"'libs-ui-icon-remove'\"\n [popover]=\"{ config: { content: isContainer(item) ? 'Xo\u00E1 c\u1EA3 kh\u1ED1i gh\u00E9p' : 'Xo\u00E1 kh\u1ED1i', zIndex: 1300 } }\"\n (outClick)=\"handlerRemove($event, item)\" />\n </div>\n }\n }\n\n @if (item.children && item.children.length > 0) {\n <!-- Kh\u1ED1i c\u00F3 con \u2192 ru\u1ED9t n\u00F3 l\u1EA1i l\u00E0 m\u1ED9t m\u1EB7t ph\u1EB3ng n\u1EEFa. \u0110\u1EC7 quy \u1EDF \u0111\u00E2y, n\u01A1i d\u00F9ng kh\u00F4ng ph\u1EA3i lo.\n L\u1EC1 \u0111\u1EB7t \u1EDF \u0110\u00C2Y (v\u1ECF container), kh\u00F4ng \u0111\u1EB7t v\u00E0o l\u01B0\u1EDBi con \u2014 l\u01B0\u1EDBi con gi\u1EEF nguy\u00EAn khe 2px. -->\n <libs_ui-services-grid_layout-canvas\n class=\"block h-full w-full\"\n [style.padding]=\"containerPadding()\"\n [node]=\"item\"\n [depth]=\"depth() + 1\"\n [hiddenToolbar]=\"hiddenToolbar()\"\n [templateToolbar]=\"templateToolbar()\"\n [selectedNodeId]=\"selectedNodeId()\"\n (outSelectNode)=\"outSelectNode.emit($event)\"\n (outConfigNode)=\"outConfigNode.emit($event)\"\n (outChange)=\"outChange.emit($event)\"\n (outRemoveNode)=\"outRemoveNode.emit($event)\"\n (outAddBlockInside)=\"outAddBlockInside.emit($event)\"\n (outToggleType)=\"outToggleType.emit($event)\" />\n }\n </div>\n </gridster-item>\n }\n </gridster>\n </div>\n </div>\n\n <!-- Thanh dock \u0111i\u1EC1u khi\u1EC3n thu ph\u00F3ng n\u1ED5i \u1EDF g\u00F3c d\u01B0\u1EDBi ph\u1EA3i -->\n @if (showZoomDock()) {\n <div\n #zoomDock\n id=\"canvas-zoom-dock\"\n role=\"toolbar\"\n tabindex=\"0\"\n class=\"absolute bottom-4 right-6 z-30 flex items-center bg-white/95 backdrop-blur-md rounded-full shadow-lg border border-slate-300/80 p-1 space-x-1 select-none\"\n (mousedown)=\"$event.stopPropagation()\"\n (keydown)=\"$event.stopPropagation()\"\n (click)=\"$event.stopPropagation()\">\n <!-- Thu nh\u1ECF (-) -->\n <button\n type=\"button\"\n class=\"w-7 h-7 flex items-center justify-center rounded-full text-slate-600 hover:text-slate-900 hover:bg-slate-100 disabled:opacity-30 disabled:hover:bg-transparent transition-colors cursor-pointer\"\n [disabled]=\"currentZoom() <= zoomMin()\"\n [title]=\"'i18n_zoom_out' | translate\"\n (click)=\"handlerZoomOut()\">\n <svg class=\"w-3.5 h-3.5\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\"><line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\"/></svg>\n </button>\n\n <!-- T\u1EF7 l\u1EC7 % v\u00E0 menu preset -->\n <div class=\"relative\">\n <button\n type=\"button\"\n class=\"h-7 px-2 flex items-center gap-1 rounded-full text-xs font-semibold text-slate-700 hover:bg-slate-100 transition-colors cursor-pointer\"\n [title]=\"'i18n_zoom_options' | translate\"\n (click)=\"handlerToggleMenu()\">\n <span>{{ zoomPercent() }}%</span>\n <svg class=\"w-3 h-3 text-slate-400 transition-transform duration-150\" [class.rotate-180]=\"isMenuOpen()\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"6 9 12 15 18 9\"/></svg>\n </button>\n\n <!-- Menu dropdown c\u00E1c m\u1ED1c thu ph\u00F3ng -->\n @if (isMenuOpen()) {\n <div class=\"absolute bottom-full mb-2 right-0 w-64 bg-white rounded-xl shadow-xl border border-slate-200 py-1.5 z-40 text-xs select-none\">\n <div class=\"px-3 py-1 text-[11px] font-semibold text-slate-400 uppercase tracking-wider\">\n {{ 'i18n_zoom_canvas_width' | translate: { width: stageWidth() } }}\n </div>\n <button\n type=\"button\"\n class=\"w-full px-3 py-2 text-left flex items-center justify-between hover:bg-slate-50 transition-colors cursor-pointer\"\n (click)=\"handlerFitScreen()\">\n <span class=\"flex items-center gap-2 text-slate-700 font-medium\">\n <svg class=\"w-3.5 h-3.5 text-slate-500\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><polyline points=\"15 3 21 3 21 9\"/><polyline points=\"9 21 3 21 3 15\"/><line x1=\"21\" y1=\"3\" x2=\"14\" y2=\"10\"/><line x1=\"3\" y1=\"21\" x2=\"10\" y2=\"14\"/></svg>\n {{ 'i18n_zoom_fit_screen' | translate }}\n </span>\n <span class=\"text-[10px] bg-blue-50 text-blue-600 px-1.5 py-0.5 rounded font-medium\">{{ 'i18n_auto' | translate }}</span>\n </button>\n <div class=\"h-px bg-slate-100 my-1\"></div>\n @for (preset of zoomPresets; track preset.value) {\n <button\n type=\"button\"\n class=\"w-full px-3 py-1.5 text-left flex items-center justify-between hover:bg-slate-50 transition-colors cursor-pointer\"\n [class.text-blue-600]=\"isCurrentPreset(preset.value)\"\n [class.font-semibold]=\"isCurrentPreset(preset.value)\"\n [class.bg-blue-50]=\"isCurrentPreset(preset.value)\"\n (click)=\"handlerSelectPreset(preset.value)\">\n <span class=\"text-slate-700\" [class.text-blue-600]=\"isCurrentPreset(preset.value)\">\n {{ preset.label | translate }}\n </span>\n @if (isCurrentPreset(preset.value)) {\n <svg class=\"w-3.5 h-3.5 text-blue-600\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"/></svg>\n }\n </button>\n }\n </div>\n }\n </div>\n\n <!-- Ph\u00F3ng to (+) -->\n <button\n type=\"button\"\n class=\"w-7 h-7 flex items-center justify-center rounded-full text-slate-600 hover:text-slate-900 hover:bg-slate-100 disabled:opacity-30 disabled:hover:bg-transparent transition-colors cursor-pointer\"\n [disabled]=\"currentZoom() >= zoomMax()\"\n [title]=\"'i18n_zoom_in' | translate\"\n (click)=\"handlerZoomIn()\">\n <svg class=\"w-3.5 h-3.5\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\"><line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\"/><line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\"/></svg>\n </button>\n\n <!-- Ph\u00E2n c\u00E1ch -->\n <div class=\"h-4 w-px bg-slate-200\"></div>\n\n <!-- N\u00FAt V\u1EEBa m\u00E0n h\u00ECnh nhanh -->\n <button\n type=\"button\"\n class=\"h-7 px-2.5 flex items-center gap-1 rounded-full text-xs text-slate-600 hover:text-slate-900 hover:bg-slate-100 transition-colors cursor-pointer\"\n [title]=\"'i18n_zoom_fit_screen_tooltip' | translate\"\n (click)=\"handlerFitScreen()\">\n <svg class=\"w-3.5 h-3.5\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><polyline points=\"15 3 21 3 21 9\"/><polyline points=\"9 21 3 21 3 15\"/><line x1=\"21\" y1=\"3\" x2=\"14\" y2=\"10\"/><line x1=\"3\" y1=\"21\" x2=\"10\" y2=\"14\"/></svg>\n <span class=\"font-medium\">{{ 'i18n_zoom_fit_screen' | translate }}</span>\n </button>\n\n <!-- N\u00FAt \u0110\u1EB7t l\u1EA1i 100% (ch\u1EC9 hi\u1EC7n khi kh\u00E1c 100%) -->\n @if (zoomPercent() !== 100) {\n <button\n type=\"button\"\n class=\"h-7 px-2 flex items-center gap-1 rounded-full text-xs font-semibold text-blue-600 hover:bg-blue-50 transition-colors cursor-pointer\"\n [title]=\"'i18n_zoom_reset_tooltip' | translate: { width: stageWidth(), height: stageMinHeight() }\"\n (click)=\"handlerResetZoom()\">\n <svg class=\"w-3 h-3\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"1 4 1 10 7 10\"/><path d=\"M3.51 15a9 9 0 1 0 2.13-9.36L1 10\"/></svg>\n <span>100%</span>\n </button>\n }\n </div>\n }\n} @else {\n <!-- \uD83D\uDD34 `relative` l\u00E0 B\u1EAET BU\u1ED8C, C\u1EA4M b\u1ECF.\n gridster \u0111\u1ED5i v\u1ECB tr\u00ED chu\u1ED9t th\u00E0nh \u00F4 l\u01B0\u1EDBi b\u1EB1ng `e.clientY + (el.scrollTop - el.offsetTop)` \u2014 c\u00F4ng\n th\u1EE9c \u0111\u00F3 ch\u1EC9 \u0111\u00FAng khi `offsetParent` c\u1EE7a <gridster> CH\u00CDNH L\u00C0 kh\u1ED1i cu\u1ED9n n\u00E0y. Thi\u1EBFu `relative` th\u00EC\n `offsetParent` nh\u1EA3y l\u00EAn kh\u1ED1i bao ngo\u00E0i: `offsetTop` tr\u1EA3 16 trong khi l\u1EC7ch th\u1EADt l\u00E0 65 \u2192 gridster\n t\u00EDnh \u00F4 sai 49px, \u00F4 ch\u1EDD \u0111\u1EB7t hi\u1EC7n l\u1EC7ch kh\u1ECFi con tr\u1ECF n\u00EAn k\u00E9o th\u1EA3 kh\u00F4ng \u0111\u1ED5i \u0111\u01B0\u1EE3c v\u1ECB tr\u00ED, v\u00E0 k\u00E9o m\u00E9p\n c\u0169ng t\u00EDnh sai \u0111i\u1EC3m d\u1EEBng. -->\n <div\n #scrollArea\n class=\"libs-ui-grid-layout-scroll-area relative h-full min-h-0 w-full min-w-0\"\n [class.overflow-y-auto]=\"!isNestedCanvas()\"\n (mousedown)=\"handlerMouseDownTrongLuoi($event)\"\n (dragover)=\"handlerDragOver($event)\"\n (dragleave)=\"handlerDragLeave($event)\"\n (drop)=\"handlerDrop($event)\">\n <!-- Snapped Drop Ghost Preview -->\n @if (dropGhost(); as ghost) {\n <div\n class=\"pointer-events-none absolute z-30 flex flex-col items-center justify-center overflow-hidden rounded-lg border-2 border-dashed border-blue-500 bg-blue-500/15 p-1 shadow-sm transition-all duration-75 ease-out backdrop-blur-[0.5px] select-none\"\n [style.left.px]=\"ghost.pixelLeft\"\n [style.top.px]=\"ghost.pixelTop\"\n [style.width.px]=\"ghost.pixelWidth\"\n [style.height.px]=\"ghost.pixelHeight\">\n <div class=\"inline-flex max-w-[95%] items-center gap-1 truncate rounded-md bg-blue-600 px-2 py-0.5 text-[11px] font-semibold text-white shadow-xs\">\n @if (ghost.cardIconClass) {\n <i [class]=\"ghost.cardIconClass + ' text-xs'\"></i>\n } @else if (ghost.cardIconText) {\n <span class=\"text-[10px] font-bold\">{{ ghost.cardIconText }}</span>\n } @else {\n <span class=\"text-xs font-bold\">{{ ghost.isInsideGroup ? '\u21B3' : '+' }}</span>\n }\n <span class=\"truncate\">{{ ghost.cardTitle }}</span>\n <span class=\"text-[9px] font-mono opacity-75\">({{ ghost.cols }}c)</span>\n </div>\n\n @if (ghost.pixelHeight >= 80) {\n <div class=\"mt-1 flex max-w-[95%] items-center gap-1.5 truncate rounded border border-blue-100 bg-white/95 px-2 py-0.5 text-[10px] font-medium text-blue-700 shadow-xs\">\n @if (ghost.isInsideGroup) {\n <span class=\"truncate font-bold text-blue-900\">\u21B3 {{ ghost.groupTitle }}</span>\n <span class=\"text-blue-300\">\u2022</span>\n }\n <span>C\u1ED9t {{ ghost.col + 1 }}-{{ ghost.col + ghost.cols }}</span>\n </div>\n }\n </div>\n }\n <gridster class=\"h-full w-full\" [class.display-grid]=\"showGridLines()\" [options]=\"gridOptions()\">\n @for (item of children(); track item.id; let itemIndex = $index) {\n <!-- \uD83D\uDD34 Ch\u1EB7n `mousedown` t\u1EA1i \u0110\u00C2Y cho l\u01B0\u1EDBi l\u1ED3ng \u2014 C\u1EA4M b\u1ECF v\u00E0 C\u1EA4M chuy\u1EC3n sang ch\u1ED7 kh\u00E1c.\n `ignoreContentClass` m\u1ED9t m\u00ECnh KH\u00D4NG \u0111\u1EE7: `delayStart: 160` l\u00E0m M\u1ED6I l\u01B0\u1EDBi l\u00EAn l\u1ECBch\n `dragStart` b\u1EB1ng `setTimeout` ngay t\u1EA1i `mousedown`, c\u00F2n `stopPropagation` m\u00E0 lib g\u1ECDi b\u00EAn\n trong `dragStart` ch\u1EA1y sau 160ms n\u00EAn qu\u00E1 mu\u1ED9n \u2014 l\u01B0\u1EDBi CHA \u0111\u00E3 k\u1ECBp nh\u1EADn (\u0111o 28/08/2026: k\u00E9o\n d\u1EA3i kh\u1ED1i con, chu\u1ED7i class duy\u1EC7t l\u00EAn \u0110\u00DANG m\u00E0 container v\u1EABn nh\u1EA3y 0,0 \u2192 0,1).\n G\u1EAFn \u1EDF `gridster-item` l\u00E0 \u0111\u00FAng bi\u00EAn: l\u01B0\u1EDBi con nghe tr\u00EAn ch\u00EDnh ph\u1EA7n t\u1EED n\u00E0y n\u00EAn \u0111\u00E3 nh\u1EADn xong,\n l\u01B0\u1EDBi cha \u1EDF ngo\u00E0i b\u1ECB ch\u1EB7n. -->\n <gridster-item\n [item]=\"item\"\n [class.libs-ui-grid-layout-selected]=\"selectedNodeId() === item.id\"\n (click)=\"handlerSelectNode(item, $event)\"\n (mousedown)=\"handlerBlockParentDrag($event)\">\n <!-- \uD83D\uDD34 V\u1ECF n\u00E0y mang `dragHandleClass` \u2014 C\u1EA4M b\u1ECF.\n `ignoreContent: true` b\u1EAFt gridster CH\u1EC8 cho k\u00E9o khi ch\u1ED7 b\u1EA5m n\u1EB1m d\u01B0\u1EDBi m\u1ED9t ph\u1EA7n t\u1EED c\u00F3\n `dragHandleClass`. Kh\u00F4ng c\u00F3 v\u1ECF n\u00E0y th\u00EC component c\u1EE7a n\u01A1i d\u00F9ng (th\u01B0 vi\u1EC7n kh\u00F4ng ki\u1EC3m so\u00E1t\n \u0111\u01B0\u1EE3c class c\u1EE7a n\u00F3) s\u1EBD kh\u00F4ng c\u00F3 tay c\u1EA7m n\u00E0o, v\u00E0 KH\u00D4NG kh\u1ED1i n\u00E0o k\u00E9o \u0111\u01B0\u1EE3c \u2014 \u0111o 28/08/2026:\n k\u00E9o 320px, to\u1EA1 \u0111\u1ED9 kh\u1ED1i gi\u1EEF nguy\u00EAn x=3,y=0.\n T\u00EAn class theo c\u1EA5p: l\u01B0\u1EDBi trang v\u00E0 l\u01B0\u1EDBi l\u1ED3ng d\u00F9ng hai t\u00EAn KH\u00C1C nhau, n\u1EBFu kh\u00F4ng l\u01B0\u1EDBi cha\n c\u0169ng nh\u1EADn ra tay c\u1EA7m c\u1EE7a kh\u1ED1i con v\u00E0 nh\u1EA5c lu\u00F4n container. -->\n <!-- \uD83D\uDD34 V\u1ECF KH\u00D4NG mang `dragHandleClass` \u2014 C\u1EA4M th\u00EAm l\u1EA1i.\n K\u00E9o ch\u1EC9 \u0111\u01B0\u1EE3c ph\u00E9p b\u1EAFt \u0111\u1EA7u t\u1EEB D\u1EA2I XANH (ng\u01B0\u1EDDi d\u00F9ng ch\u1ED1t 28/08/2026: \"ph\u1EA3i hover v\u00E0o v\u00F9ng\n m\u00E0u xanh th\u00EC m\u1EDBi k\u00E9o th\u1EA3 \u0111\u01B0\u1EE3c cho \u0111\u1ED3ng nh\u1EA5t\"). Cho c\u1EA3 v\u1ECF l\u00E0m tay c\u1EA7m th\u00EC b\u1EA5m \u0111\u00E2u c\u0169ng\n k\u00E9o, v\u00E0 kh\u1ED1i con n\u1EB1m trong container s\u1EBD nh\u1EA5c lu\u00F4n container v\u00EC l\u01B0\u1EDBi cha duy\u1EC7t l\u00EAn g\u1EB7p\n tay c\u1EA7m c\u1EE7a v\u1ECF container tr\u01B0\u1EDBc.\n V\u1ECF kh\u1ED1i con v\u1EABn gi\u1EEF class CH\u1EB6N \u0111\u1EC3 l\u01B0\u1EDBi cha d\u1EEBng \u0111\u00FAng \u1EDF bi\u00EAn. -->\n <div\n class=\"libs-ui-grid-layout-block-shell group relative h-full w-full min-w-0\"\n [class.libs-ui-grid-layout-block-parent-drag]=\"isNestedCanvas()\">\n <!-- D\u1EA3i k\u00E9o: hi\u1EC7n khi r\u00EA chu\u1ED9t v\u00E0o kh\u1ED1i, ba ch\u1EA5m l\u00E0 d\u1EA5u hi\u1EC7u k\u00E9o quen thu\u1ED9c.\n Ng\u01B0\u1EDDi d\u00F9ng c\u1EA7n m\u1ED9t ch\u1ED7 b\u00E1m R\u00D5 R\u00C0NG thay v\u00EC \u0111o\u00E1n xem b\u1EA5m \u0111\u00E2u th\u00EC k\u00E9o \u0111\u01B0\u1EE3c\n (ch\u1ED1t 28/08/2026, theo \u0111\u00FAng d\u1EA3i \u0111ang d\u00F9ng \u1EDF m\u00E0n Customer 360 c\u1EE7a mobio-web). -->\n @if (isEditMode()) {\n <!-- \uD83D\uDD34 D\u1EA3i PH\u1EA2I mang tay c\u1EA7m \u0110\u00DANG C\u1EA4P c\u1EE7a n\u00F3. D\u1EA3i nh\u1EADn chu\u1ED9t (`pointer-events: auto`),\n n\u00EAn n\u1EBFu kh\u00F4ng mang tay c\u1EA7m th\u00EC `checkDragHandleClass` duy\u1EC7t l\u00EAn g\u1EB7p tay c\u1EA7m c\u1EE7a\n container v\u00E0 nh\u1EA5c container thay v\u00EC kh\u1ED1i con (\u0111o 28/08/2026: k\u00E9o d\u1EA3i kh\u1ED1i con,\n container nh\u1EA3y 0,0 \u2192 0,1 c\u00F2n kh\u1ED1i con \u0111\u1EE9ng im).\n \uD83D\uDD34 D\u1EA3i CH\u1EC8 mang tay c\u1EA7m, C\u1EA4M mang th\u00EAm class ch\u1EB7n: `checkDragHandleClass` x\u00E9t hai\n class \u0111\u00F3 tr\u00EAn C\u00D9NG m\u1ED9t node n\u00EAn \u0111\u1EC3 chung l\u00E0 k\u00E9o h\u1ECFng (\u0111o 28/08/2026: b\u1EA5m d\u1EA3i kh\u1ED1i\n con k\u00E9o 140px, kh\u1ED1i \u0111\u1EE9ng im). Vi\u1EC7c ch\u1EB7n l\u01B0\u1EDBi cha do V\u1ECE KH\u1ED0I lo. -->\n <div\n class=\"libs-ui-grid-layout-drag-bar\"\n [class.libs-ui-grid-layout-drag-bar-child]=\"isNestedCanvas()\"\n [class.libs-ui-grid-layout-drag-handle]=\"!isNestedCanvas()\"\n [class.libs-ui-grid-layout-drag-handle-child]=\"isNestedCanvas()\">\n <span class=\"libs-ui-grid-layout-drag-bar-dots\">\n @for (dot of dragBarDots; track dot) {\n <span class=\"libs-ui-grid-layout-drag-bar-dot\"></span>\n }\n </span>\n </div>\n }\n\n <!-- Khung ch\u1EE9a component c\u1EE7a n\u01A1i d\u00F9ng.\n \uD83D\uDD34 PH\u1EA2I c\u00F3 khung th\u1EADt (kh\u00F4ng ph\u1EA3i `ng-container` tr\u1ED1ng): n\u00F3 lo h\u1ED9 n\u01A1i d\u00F9ng ph\u1EA7n l\u1EA5p \u0111\u1EA7y\n \u00F4 v\u00E0 vi\u1EC1n b\u00E1o ch\u1EBF \u0111\u1ED9 s\u1EEDa. Kh\u00F4ng c\u00F3 khung th\u00EC m\u1ED7i component n\u1ED9i dung l\u1EA1i ph\u1EA3i t\u1EF1 vi\u1EBFt\n `:host { width/height: 100% }` + vi\u1EC1n \u0111\u1EE9t \u2014 \u0111\u00F3 l\u00E0 vi\u1EC7c c\u1EE7a th\u01B0 vi\u1EC7n, kh\u00F4ng ph\u1EA3i c\u1EE7a\n ng\u01B0\u1EDDi d\u00F9ng (ng\u01B0\u1EDDi d\u00F9ng ch\u1ED1t 28/08/2026).\n M\u1ED7i kh\u1ED1i m\u1ED9t ViewContainerRef ri\u00EAng n\u00EAn component n\u1EB1m \u0111\u00FAng \u00F4 c\u1EE7a n\u00F3. -->\n <div\n class=\"libs-ui-grid-layout-content-frame\"\n [class.libs-ui-grid-layout-content-frame-edit]=\"isEditMode() && !isContainer(item)\"\n [class.libs-ui-grid-layout-content-frame-empty]=\"isContainer(item)\">\n <ng-container #itemHost />\n </div>\n\n <!-- D\u1EA5u hi\u1EC7u CONTAINER: nh\u00E3n g\u00F3c tr\u00EAn-ph\u1EA3i + vi\u1EC1n \u0111\u1EE9t bao ru\u1ED9t. Kh\u00F4ng c\u00F3 d\u1EA5u hi\u1EC7u th\u00EC\n ng\u01B0\u1EDDi d\u00F9ng kh\u00F4ng bi\u1EBFt kh\u1ED1i n\u00E0o ch\u1EE9a \u0111\u01B0\u1EE3c kh\u1ED1i kh\u00E1c (ch\u1ED1t 28/08/2026, theo \u0111\u00FAng c\u00E1ch\n m\u00E0n Customer 360 c\u1EE7a mobio-web \u0111ang l\u00E0m). -->\n @if (isEditMode() && isContainer(item)) {\n <div class=\"libs-ui-grid-layout-container-label\">{{ 'i18n_container_block' | translate }}</div>\n <div class=\"libs-ui-grid-layout-container-border\"></div>\n }\n\n <!-- Thanh c\u00F4ng c\u1EE5: hi\u1EC7n khi r\u00EA chu\u1ED9t v\u00E0o kh\u1ED1i.\n \uD83D\uDD34 D\u00F9ng `libs_ui-components-buttons-button` \u2014 C\u1EA4M t\u1EF1 d\u1EF1ng th\u1EBB `<button>`.\n Component n\u00E0y \u0111\u00E3 c\u00F3 s\u1EB5n ki\u1EC3u n\u00FAt, c\u1EE1 n\u00FAt v\u00E0 bong b\u00F3ng ch\u00FA th\u00EDch theo \u0111\u00FAng b\u1ED9 giao di\u1EC7n\n c\u1EE7a s\u1EA3n ph\u1EA9m; t\u1EF1 d\u1EF1ng l\u00E0 m\u1ED7i n\u01A1i m\u1ED9t ki\u1EC3u v\u00E0 m\u1EA5t lu\u00F4n tooltip. -->\n @if (isEditMode() && !hiddenToolbar()) {\n @if (templateToolbar()) {\n <!-- N\u01A1i d\u00F9ng t\u1EF1 v\u1EBD thanh c\u00F4ng c\u1EE5: nh\u1EADn kh\u1ED1i + c\u00E1c h\u00E0m ph\u00E1t event qua context.\n\n \uD83D\uDD34 Kh\u1ED1i b\u1ECDc t\u1EF1 ch\u1EB7n `mousedown`/`click` n\u1ED5i l\u00EAn gridster. Thanh c\u00F4ng c\u1EE5 n\u1EB1m trong\n v\u00F9ng mang `dragHandleClass`; kh\u00F4ng ch\u1EB7n th\u00EC c\u00FA b\u1EA5m b\u1ECB hi\u1EC3u l\u00E0 b\u1EAFt \u0111\u1EA7u k\u00E9o v\u00E0\n `delayStart: 160` nu\u1ED1t lu\u00F4n `click` \u2014 n\u00FAt trong template ngo\u00E0i b\u1EA5m kh\u00F4ng \u0103n\n (\u0111o 09/09/2026: b\u1EA5m b\u1EB1ng `.click()` c\u1EE7a DOM th\u00EC m\u1EDF, b\u1EA5m chu\u1ED9t th\u1EADt th\u00EC kh\u00F4ng).\n Ch\u1EB7n \u1EDF \u0110\u00C2Y \u0111\u1EC3 n\u01A1i d\u00F9ng kh\u00F4ng ph\u1EA3i bi\u1EBFt b\u1EABy n\u00E0y. -->\n <div\n class=\"libs-ui-grid-layout-toolbar\"\n role=\"toolbar\"\n tabindex=\"0\"\n [class.libs-ui-grid-layout-toolbar-child]=\"isNestedCanvas()\"\n (mousedown)=\"handlerStopEvent($event)\"\n (keydown)=\"handlerStopEvent($event)\"\n (click)=\"handlerStopEvent($event)\">\n <ng-container\n *ngTemplateOutlet=\"templateToolbar()!; context: toolbarContexts()[itemIndex]\" />\n </div>\n } @else {\n <div\n class=\"libs-ui-grid-layout-toolbar\"\n [class.libs-ui-grid-layout-toolbar-child]=\"isNestedCanvas()\">\n <span class=\"libs-ui-grid-layout-dim-badge\">\n {{ item.rows }} h\u00E0ng \u00D7 {{ item.cols }} c\u1ED9t\n </span>\n @if (canAddInside(item)) {\n <libs_ui-components-buttons-button\n [type]=\"'button-third'\"\n [iconOnlyType]=\"true\"\n [sizeButton]=\"'smaller'\"\n [classIconLeft]=\"'libs-ui-icon-add'\"\n [popover]=\"{ config: { content: 'Th\u00EAm kh\u1ED1i v\u00E0o trong', zIndex: 1300 } }\"\n (outClick)=\"handlerAddInside($event, item)\" />\n }\n @if (canToggleType(item)) {\n <libs_ui-components-buttons-button\n [type]=\"'button-third'\"\n [iconOnlyType]=\"true\"\n [sizeButton]=\"'smaller'\"\n [classIconLeft]=\"isContainer(item) ? 'libs-ui-icon-split-cell' : 'libs-ui-icon-merge-cell'\"\n [popover]=\"{ config: { content: isContainer(item) ? '\u0110\u01B0a v\u1EC1 kh\u1ED1i \u0111\u01A1n' : 'Chuy\u1EC3n th\u00E0nh kh\u1ED1i gh\u00E9p', zIndex: 1300 } }\"\n (outClick)=\"handlerToggleType($event, item)\" />\n }\n <libs_ui-components-buttons-button\n [type]=\"'button-third'\"\n [iconOnlyType]=\"true\"\n [sizeButton]=\"'smaller'\"\n [classIconLeft]=\"'libs-ui-icon-setting'\"\n [popover]=\"{ config: { content: 'C\u1EA5u h\u00ECnh th\u1EBB', zIndex: 1300 } }\"\n (outClick)=\"handlerConfig($event, item)\" />\n <libs_ui-components-buttons-button\n [type]=\"'button-third-hover-danger'\"\n [iconOnlyType]=\"true\"\n [sizeButton]=\"'smaller'\"\n [classIconLeft]=\"'libs-ui-icon-remove'\"\n [popover]=\"{ config: { content: isContainer(item) ? 'Xo\u00E1 c\u1EA3 kh\u1ED1i gh\u00E9p' : 'Xo\u00E1 kh\u1ED1i', zIndex: 1300 } }\"\n (outClick)=\"handlerRemove($event, item)\" />\n </div>\n }\n }\n\n @if (item.children && item.children.length > 0) {\n <!-- Kh\u1ED1i c\u00F3 con \u2192 ru\u1ED9t n\u00F3 l\u1EA1i l\u00E0 m\u1ED9t m\u1EB7t ph\u1EB3ng n\u1EEFa. \u0110\u1EC7 quy \u1EDF \u0111\u00E2y, n\u01A1i d\u00F9ng kh\u00F4ng ph\u1EA3i lo.\n L\u1EC1 \u0111\u1EB7t \u1EDF \u0110\u00C2Y (v\u1ECF container), kh\u00F4ng \u0111\u1EB7t v\u00E0o l\u01B0\u1EDBi con \u2014 l\u01B0\u1EDBi con gi\u1EEF nguy\u00EAn khe 2px. -->\n <libs_ui-services-grid_layout-canvas\n class=\"block h-full w-full\"\n [style.padding]=\"containerPadding()\"\n [node]=\"item\"\n [depth]=\"depth() + 1\"\n [hiddenToolbar]=\"hiddenToolbar()\"\n [templateToolbar]=\"templateToolbar()\"\n [selectedNodeId]=\"selectedNodeId()\"\n (outSelectNode)=\"outSelectNode.emit($event)\"\n (outConfigNode)=\"outConfigNode.emit($event)\"\n (outChange)=\"outChange.emit($event)\"\n (outRemoveNode)=\"outRemoveNode.emit($event)\"\n (outAddBlockInside)=\"outAddBlockInside.emit($event)\"\n (outToggleType)=\"outToggleType.emit($event)\" />\n }\n </div>\n </gridster-item>\n }\n </gridster>\n </div>\n}\n", styles: [":host{display:block;position:relative;box-sizing:border-box;width:100%;height:100%;min-width:0;min-height:0}.libs-ui-grid-layout-block-shell{container-type:inline-size;display:block;box-sizing:border-box;height:100%}.libs-ui-grid-layout-drag-bar{position:absolute;top:2px;left:50%;z-index:15;display:flex;align-items:center;justify-content:center;width:64px;height:16px;background:transparent;transform:translate(-50%);opacity:1;transition:opacity .12s ease;pointer-events:auto;cursor:move}.libs-ui-grid-layout-drag-bar-dots{display:grid;grid-template-columns:repeat(3,3px);gap:3px;color:#9ca2ad}.libs-ui-grid-layout-drag-bar-dot{width:3px;height:3px;background:currentColor;border-radius:50%}.libs-ui-grid-layout-drag-bar:hover .libs-ui-grid-layout-drag-bar-dots{color:#3d6ef5}.libs-ui-grid-layout-drag-bar:not(.libs-ui-grid-layout-drag-bar-child){opacity:1}.libs-ui-grid-layout-drag-bar-child{top:auto;bottom:0;background:#d9f2e4;border-radius:4px 4px 0 0}.libs-ui-grid-layout-drag-bar-child .libs-ui-grid-layout-drag-bar-dots{color:#9ca2ad}.libs-ui-grid-layout-drag-bar-child:hover .libs-ui-grid-layout-drag-bar-dots{color:#00a757}.libs-ui-grid-layout-drag-bar-child{opacity:0}.libs-ui-grid-layout-block-shell:hover>.libs-ui-grid-layout-drag-bar-child{opacity:1}.libs-ui-grid-layout-block-shell:has(>.libs-ui-grid-layout-drag-bar:not(.libs-ui-grid-layout-drag-bar-child):hover){outline:2px solid #3d6ef5;outline-offset:-2px;border-radius:8px}.libs-ui-grid-layout-block-shell:has(>.libs-ui-grid-layout-drag-bar-child:hover){outline:2px solid #00a757;outline-offset:-2px;border-radius:8px}.libs-ui-grid-layout-container-label{position:absolute;left:6px;top:2px;display:flex;height:20px;align-items:center;z-index:3;padding:0 6px;color:#3d6ef5;font-weight:500;font-size:10px;line-height:14px;background:#dbe4ff;border-radius:4px;pointer-events:none}.libs-ui-grid-layout-content-frame{box-sizing:border-box;width:100%;height:100%;overflow:hidden;border-radius:6px}.libs-ui-grid-layout-content-frame ::ng-deep>*{display:block;box-sizing:border-box;width:100%;height:100%}.libs-ui-grid-layout-content-frame-empty{height:0}.libs-ui-grid-layout-content-frame-edit{border:1px dashed #c3cede}.libs-ui-grid-layout-container-border{position:absolute;inset:0;border:1px dashed #9db4f0;border-radius:8px;pointer-events:none}.libs-ui-grid-layout-toolbar{position:absolute;top:6px;right:8px;z-index:24;display:flex;gap:2px;align-items:center;height:20px;background:#fff;border-radius:4px;box-shadow:0 2px 8px #0716311f;opacity:0;transition:opacity .12s ease}.libs-ui-grid-layout-toolbar-child{top:50%;right:8px;left:auto;transform:translateY(-50%)}.libs-ui-grid-layout-block-shell:hover>.libs-ui-grid-layout-toolbar{opacity:1}:host ::ng-deep gridster{background:transparent}:host ::ng-deep .gridster-item-resizable-handler.handle-n,:host ::ng-deep .gridster-item-resizable-handler.handle-s{height:16px}:host ::ng-deep .gridster-item-resizable-handler.handle-e,:host ::ng-deep .gridster-item-resizable-handler.handle-w{width:16px}:host ::ng-deep .gridster-item-resizable-handler.handle-n{top:0}:host ::ng-deep .gridster-item-resizable-handler.handle-s{bottom:0}:host ::ng-deep .gridster-item-resizable-handler.handle-e{right:0}:host ::ng-deep .gridster-item-resizable-handler.handle-w{left:0}:host ::ng-deep gridster-item.gridster-item-moving,:host ::ng-deep gridster-item.gridster-item-resizing{z-index:30!important}:host ::ng-deep gridster-item.gridster-item-moving>.libs-ui-grid-layout-block-shell,:host ::ng-deep gridster-item.gridster-item-resizing>.libs-ui-grid-layout-block-shell{outline:2px solid #3d6ef5;outline-offset:-2px;border-radius:8px}:host ::ng-deep gridster gridster gridster-item.gridster-item-moving>.libs-ui-grid-layout-block-shell,:host ::ng-deep gridster gridster gridster-item.gridster-item-resizing>.libs-ui-grid-layout-block-shell{outline-color:#00a757}:host ::ng-deep gridster-item.libs-ui-grid-layout-selected>.libs-ui-grid-layout-block-shell{outline:2px solid #2563eb!important;outline-offset:-2px!important;border-radius:8px!important;box-shadow:0 0 0 4px #2563eb26!important}:host ::ng-deep gridster.display-grid .gridster-column,:host ::ng-deep gridster gridster.display-grid .gridster-column{border-right:1px solid rgba(226,232,240,.7)!important;border-left:none!important;pointer-events:none!important;height:100%!important;min-height:100%!important}:host ::ng-deep gridster.display-grid .gridster-column:first-child,:host ::ng-deep gridster gridster.display-grid .gridster-column:first-child{border-left:1px solid rgba(226,232,240,.7)!important}:host ::ng-deep gridster.display-grid .gridster-row,:host ::ng-deep gridster gridster.display-grid .gridster-row{border-bottom:1px solid rgba(226,232,240,.7)!important;border-top:none!important;pointer-events:none!important}:host ::ng-deep gridster.display-grid .gridster-row:first-child,:host ::ng-deep gridster gridster.display-grid .gridster-row:first-child{border-top:1px solid rgba(226,232,240,.7)!important}:host ::ng-deep gridster gridster.display-grid{background-color:#f8fafc80!important}:host ::ng-deep gridster-preview{background:#2563eb1f!important;border:1.5px dashed #2563eb!important;border-radius:6px!important;z-index:25!important}.libs-ui-grid-layout-dim-badge{display:inline-flex;align-items:center;height:20px;padding:0 6px;background-color:#f1f5f9;border:1px solid #e2e8f0;border-radius:4px;color:#64748b;font-size:10px;font-weight:500;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;pointer-events:none;white-space:nowrap}@container (max-width: 80px){.libs-ui-grid-layout-drag-bar{top:26px}}.libs-ui-grid-layout-stage{box-sizing:border-box;transform-origin:top center;transition:zoom .15s ease-out}#canvas-zoom-dock{box-shadow:0 10px 25px -5px #0000001a,0 8px 10px -6px #0000001a}\n"] }]
|
|
564
|
+
args: [{ selector: 'libs_ui-services-grid_layout-canvas', standalone: true, imports: [GridsterModule, LibsUiComponentsButtonsButtonComponent, NgTemplateOutlet, TranslateModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (isZoomActive()) {\n <!-- Khu v\u1EF1c cu\u1ED9n ch\u1EE9a canvas stage thu ph\u00F3ng -->\n <div\n #scrollArea\n class=\"libs-ui-grid-layout-scroll-area relative h-full min-h-0 w-full min-w-0 overflow-auto p-6 flex justify-center items-start\"\n (mousedown)=\"handlerMouseDownTrongLuoi($event)\"\n (wheel)=\"handlerWheel($event)\"\n (dragover)=\"handlerDragOver($event)\"\n (dragleave)=\"handlerDragLeave($event)\"\n (drop)=\"handlerDrop($event)\">\n <div\n #canvasStage\n id=\"bi-canvas-stage\"\n class=\"libs-ui-grid-layout-stage relative flex flex-col transition-[zoom] duration-150 origin-top shrink-0 bg-white/80 border border-slate-200/80 rounded-2xl shadow-sm p-4\"\n [style.zoom]=\"currentZoom()\"\n [style.width.px]=\"stageWidth()\"\n [style.min-width.px]=\"stageWidth()\"\n [style.min-height.px]=\"stageMinHeight()\">\n <!-- Snapped Drop Ghost Preview -->\n @if (dropGhost(); as ghost) {\n <div\n class=\"pointer-events-none absolute z-30 flex flex-col items-center justify-center overflow-hidden rounded-lg border-2 border-dashed border-blue-500 bg-blue-500/15 p-1 shadow-sm transition-all duration-75 ease-out backdrop-blur-[0.5px] select-none\"\n [style.left.px]=\"ghost.pixelLeft\"\n [style.top.px]=\"ghost.pixelTop\"\n [style.width.px]=\"ghost.pixelWidth\"\n [style.height.px]=\"ghost.pixelHeight\">\n <div class=\"inline-flex max-w-[95%] items-center gap-1 truncate rounded-md bg-blue-600 px-2 py-0.5 text-[11px] font-semibold text-white shadow-xs\">\n @if (ghost.cardIconClass) {\n <i [class]=\"ghost.cardIconClass + ' text-xs'\"></i>\n } @else if (ghost.cardIconText) {\n <span class=\"text-[10px] font-bold\">{{ ghost.cardIconText }}</span>\n } @else {\n <span class=\"text-xs font-bold\">{{ ghost.isInsideGroup ? '\u21B3' : '+' }}</span>\n }\n <span class=\"truncate\">{{ ghost.cardTitle }}</span>\n <span class=\"text-[9px] font-mono opacity-75\">({{ ghost.cols }}c)</span>\n </div>\n\n @if (ghost.pixelHeight >= 80) {\n <div class=\"mt-1 flex max-w-[95%] items-center gap-1.5 truncate rounded border border-blue-100 bg-white/95 px-2 py-0.5 text-[10px] font-medium text-blue-700 shadow-xs\">\n @if (ghost.isInsideGroup) {\n <span class=\"truncate font-bold text-blue-900\">\u21B3 {{ ghost.groupTitle }}</span>\n <span class=\"text-blue-300\">\u2022</span>\n }\n <span>C\u1ED9t {{ ghost.col + 1 }}-{{ ghost.col + ghost.cols }}</span>\n </div>\n }\n </div>\n }\n <gridster class=\"h-full w-full\" [class.display-grid]=\"showGridLines()\" [options]=\"gridOptions()\">\n @for (item of children(); track item.id; let itemIndex = $index) {\n <!-- \uD83D\uDD34 Ch\u1EB7n `mousedown` t\u1EA1i \u0110\u00C2Y cho l\u01B0\u1EDBi l\u1ED3ng \u2014 C\u1EA4M b\u1ECF v\u00E0 C\u1EA4M chuy\u1EC3n sang ch\u1ED7 kh\u00E1c.\n `ignoreContentClass` m\u1ED9t m\u00ECnh KH\u00D4NG \u0111\u1EE7: `delayStart: 160` l\u00E0m M\u1ED6I l\u01B0\u1EDBi l\u00EAn l\u1ECBch\n `dragStart` b\u1EB1ng `setTimeout` ngay t\u1EA1i `mousedown`, c\u00F2n `stopPropagation` m\u00E0 lib g\u1ECDi b\u00EAn\n trong `dragStart` ch\u1EA1y sau 160ms n\u00EAn qu\u00E1 mu\u1ED9n \u2014 l\u01B0\u1EDBi CHA \u0111\u00E3 k\u1ECBp nh\u1EADn (\u0111o 28/08/2026: k\u00E9o\n d\u1EA3i kh\u1ED1i con, chu\u1ED7i class duy\u1EC7t l\u00EAn \u0110\u00DANG m\u00E0 container v\u1EABn nh\u1EA3y 0,0 \u2192 0,1).\n G\u1EAFn \u1EDF `gridster-item` l\u00E0 \u0111\u00FAng bi\u00EAn: l\u01B0\u1EDBi con nghe tr\u00EAn ch\u00EDnh ph\u1EA7n t\u1EED n\u00E0y n\u00EAn \u0111\u00E3 nh\u1EADn xong,\n l\u01B0\u1EDBi cha \u1EDF ngo\u00E0i b\u1ECB ch\u1EB7n. -->\n <gridster-item\n [item]=\"item\"\n [class.libs-ui-grid-layout-selected]=\"selectedNodeId() === item.id\"\n (click)=\"handlerSelectNode(item, $event)\"\n (mousedown)=\"handlerBlockParentDrag($event)\">\n <!-- \uD83D\uDD34 V\u1ECF n\u00E0y mang `dragHandleClass` \u2014 C\u1EA4M b\u1ECF.\n `ignoreContent: true` b\u1EAFt gridster CH\u1EC8 cho k\u00E9o khi ch\u1ED7 b\u1EA5m n\u1EB1m d\u01B0\u1EDBi m\u1ED9t ph\u1EA7n t\u1EED c\u00F3\n `dragHandleClass`. Kh\u00F4ng c\u00F3 v\u1ECF n\u00E0y th\u00EC component c\u1EE7a n\u01A1i d\u00F9ng (th\u01B0 vi\u1EC7n kh\u00F4ng ki\u1EC3m so\u00E1t\n \u0111\u01B0\u1EE3c class c\u1EE7a n\u00F3) s\u1EBD kh\u00F4ng c\u00F3 tay c\u1EA7m n\u00E0o, v\u00E0 KH\u00D4NG kh\u1ED1i n\u00E0o k\u00E9o \u0111\u01B0\u1EE3c \u2014 \u0111o 28/08/2026:\n k\u00E9o 320px, to\u1EA1 \u0111\u1ED9 kh\u1ED1i gi\u1EEF nguy\u00EAn x=3,y=0.\n T\u00EAn class theo c\u1EA5p: l\u01B0\u1EDBi trang v\u00E0 l\u01B0\u1EDBi l\u1ED3ng d\u00F9ng hai t\u00EAn KH\u00C1C nhau, n\u1EBFu kh\u00F4ng l\u01B0\u1EDBi cha\n c\u0169ng nh\u1EADn ra tay c\u1EA7m c\u1EE7a kh\u1ED1i con v\u00E0 nh\u1EA5c lu\u00F4n container. -->\n <!-- \uD83D\uDD34 V\u1ECF KH\u00D4NG mang `dragHandleClass` \u2014 C\u1EA4M th\u00EAm l\u1EA1i.\n K\u00E9o ch\u1EC9 \u0111\u01B0\u1EE3c ph\u00E9p b\u1EAFt \u0111\u1EA7u t\u1EEB D\u1EA2I XANH (ng\u01B0\u1EDDi d\u00F9ng ch\u1ED1t 28/08/2026: \"ph\u1EA3i hover v\u00E0o v\u00F9ng\n m\u00E0u xanh th\u00EC m\u1EDBi k\u00E9o th\u1EA3 \u0111\u01B0\u1EE3c cho \u0111\u1ED3ng nh\u1EA5t\"). Cho c\u1EA3 v\u1ECF l\u00E0m tay c\u1EA7m th\u00EC b\u1EA5m \u0111\u00E2u c\u0169ng\n k\u00E9o, v\u00E0 kh\u1ED1i con n\u1EB1m trong container s\u1EBD nh\u1EA5c lu\u00F4n container v\u00EC l\u01B0\u1EDBi cha duy\u1EC7t l\u00EAn g\u1EB7p\n tay c\u1EA7m c\u1EE7a v\u1ECF container tr\u01B0\u1EDBc.\n V\u1ECF kh\u1ED1i con v\u1EABn gi\u1EEF class CH\u1EB6N \u0111\u1EC3 l\u01B0\u1EDBi cha d\u1EEBng \u0111\u00FAng \u1EDF bi\u00EAn. -->\n <div\n class=\"libs-ui-grid-layout-block-shell group relative h-full w-full min-w-0\"\n [class.libs-ui-grid-layout-block-parent-drag]=\"isNestedCanvas()\">\n <!-- D\u1EA3i k\u00E9o: hi\u1EC7n khi r\u00EA chu\u1ED9t v\u00E0o kh\u1ED1i, ba ch\u1EA5m l\u00E0 d\u1EA5u hi\u1EC7u k\u00E9o quen thu\u1ED9c.\n Ng\u01B0\u1EDDi d\u00F9ng c\u1EA7n m\u1ED9t ch\u1ED7 b\u00E1m R\u00D5 R\u00C0NG thay v\u00EC \u0111o\u00E1n xem b\u1EA5m \u0111\u00E2u th\u00EC k\u00E9o \u0111\u01B0\u1EE3c\n (ch\u1ED1t 28/08/2026, theo \u0111\u00FAng d\u1EA3i \u0111ang d\u00F9ng \u1EDF m\u00E0n Customer 360 c\u1EE7a mobio-web). -->\n @if (isEditMode()) {\n <!-- \uD83D\uDD34 D\u1EA3i PH\u1EA2I mang tay c\u1EA7m \u0110\u00DANG C\u1EA4P c\u1EE7a n\u00F3. D\u1EA3i nh\u1EADn chu\u1ED9t (`pointer-events: auto`),\n n\u00EAn n\u1EBFu kh\u00F4ng mang tay c\u1EA7m th\u00EC `checkDragHandleClass` duy\u1EC7t l\u00EAn g\u1EB7p tay c\u1EA7m c\u1EE7a\n container v\u00E0 nh\u1EA5c container thay v\u00EC kh\u1ED1i con (\u0111o 28/08/2026: k\u00E9o d\u1EA3i kh\u1ED1i con,\n container nh\u1EA3y 0,0 \u2192 0,1 c\u00F2n kh\u1ED1i con \u0111\u1EE9ng im).\n \uD83D\uDD34 D\u1EA3i CH\u1EC8 mang tay c\u1EA7m, C\u1EA4M mang th\u00EAm class ch\u1EB7n: `checkDragHandleClass` x\u00E9t hai\n class \u0111\u00F3 tr\u00EAn C\u00D9NG m\u1ED9t node n\u00EAn \u0111\u1EC3 chung l\u00E0 k\u00E9o h\u1ECFng (\u0111o 28/08/2026: b\u1EA5m d\u1EA3i kh\u1ED1i\n con k\u00E9o 140px, kh\u1ED1i \u0111\u1EE9ng im). Vi\u1EC7c ch\u1EB7n l\u01B0\u1EDBi cha do V\u1ECE KH\u1ED0I lo. -->\n <div\n class=\"libs-ui-grid-layout-drag-bar\"\n [class.libs-ui-grid-layout-drag-bar-child]=\"isNestedCanvas()\"\n [class.libs-ui-grid-layout-drag-handle]=\"!isNestedCanvas()\"\n [class.libs-ui-grid-layout-drag-handle-child]=\"isNestedCanvas()\">\n <span class=\"libs-ui-grid-layout-drag-bar-dots\">\n @for (dot of dragBarDots; track dot) {\n <span class=\"libs-ui-grid-layout-drag-bar-dot\"></span>\n }\n </span>\n </div>\n }\n\n <!-- Khung ch\u1EE9a component c\u1EE7a n\u01A1i d\u00F9ng.\n \uD83D\uDD34 PH\u1EA2I c\u00F3 khung th\u1EADt (kh\u00F4ng ph\u1EA3i `ng-container` tr\u1ED1ng): n\u00F3 lo h\u1ED9 n\u01A1i d\u00F9ng ph\u1EA7n l\u1EA5p \u0111\u1EA7y\n \u00F4 v\u00E0 vi\u1EC1n b\u00E1o ch\u1EBF \u0111\u1ED9 s\u1EEDa. Kh\u00F4ng c\u00F3 khung th\u00EC m\u1ED7i component n\u1ED9i dung l\u1EA1i ph\u1EA3i t\u1EF1 vi\u1EBFt\n `:host { width/height: 100% }` + vi\u1EC1n \u0111\u1EE9t \u2014 \u0111\u00F3 l\u00E0 vi\u1EC7c c\u1EE7a th\u01B0 vi\u1EC7n, kh\u00F4ng ph\u1EA3i c\u1EE7a\n ng\u01B0\u1EDDi d\u00F9ng (ng\u01B0\u1EDDi d\u00F9ng ch\u1ED1t 28/08/2026).\n M\u1ED7i kh\u1ED1i m\u1ED9t ViewContainerRef ri\u00EAng n\u00EAn component n\u1EB1m \u0111\u00FAng \u00F4 c\u1EE7a n\u00F3. -->\n <div\n class=\"libs-ui-grid-layout-content-frame\"\n [class.libs-ui-grid-layout-content-frame-edit]=\"isEditMode() && !isContainer(item)\"\n [class.libs-ui-grid-layout-content-frame-empty]=\"isContainer(item)\">\n <ng-container #itemHost />\n </div>\n\n <!-- D\u1EA5u hi\u1EC7u CONTAINER: nh\u00E3n g\u00F3c tr\u00EAn-ph\u1EA3i + vi\u1EC1n \u0111\u1EE9t bao ru\u1ED9t. Kh\u00F4ng c\u00F3 d\u1EA5u hi\u1EC7u th\u00EC\n ng\u01B0\u1EDDi d\u00F9ng kh\u00F4ng bi\u1EBFt kh\u1ED1i n\u00E0o ch\u1EE9a \u0111\u01B0\u1EE3c kh\u1ED1i kh\u00E1c (ch\u1ED1t 28/08/2026, theo \u0111\u00FAng c\u00E1ch\n m\u00E0n Customer 360 c\u1EE7a mobio-web \u0111ang l\u00E0m). -->\n @if (isEditMode() && isContainer(item)) {\n <div class=\"libs-ui-grid-layout-container-label\">{{ 'i18n_container_block' | translate }}</div>\n <div class=\"libs-ui-grid-layout-container-border\"></div>\n }\n\n <!-- Thanh c\u00F4ng c\u1EE5: hi\u1EC7n khi r\u00EA chu\u1ED9t v\u00E0o kh\u1ED1i.\n \uD83D\uDD34 D\u00F9ng `libs_ui-components-buttons-button` \u2014 C\u1EA4M t\u1EF1 d\u1EF1ng th\u1EBB `<button>`.\n Component n\u00E0y \u0111\u00E3 c\u00F3 s\u1EB5n ki\u1EC3u n\u00FAt, c\u1EE1 n\u00FAt v\u00E0 bong b\u00F3ng ch\u00FA th\u00EDch theo \u0111\u00FAng b\u1ED9 giao di\u1EC7n\n c\u1EE7a s\u1EA3n ph\u1EA9m; t\u1EF1 d\u1EF1ng l\u00E0 m\u1ED7i n\u01A1i m\u1ED9t ki\u1EC3u v\u00E0 m\u1EA5t lu\u00F4n tooltip. -->\n @if (isEditMode() && !hiddenToolbar()) {\n @if (templateToolbar()) {\n <!-- N\u01A1i d\u00F9ng t\u1EF1 v\u1EBD thanh c\u00F4ng c\u1EE5: nh\u1EADn kh\u1ED1i + c\u00E1c h\u00E0m ph\u00E1t event qua context.\n\n \uD83D\uDD34 Kh\u1ED1i b\u1ECDc t\u1EF1 ch\u1EB7n `mousedown`/`click` n\u1ED5i l\u00EAn gridster. Thanh c\u00F4ng c\u1EE5 n\u1EB1m trong\n v\u00F9ng mang `dragHandleClass`; kh\u00F4ng ch\u1EB7n th\u00EC c\u00FA b\u1EA5m b\u1ECB hi\u1EC3u l\u00E0 b\u1EAFt \u0111\u1EA7u k\u00E9o v\u00E0\n `delayStart: 160` nu\u1ED1t lu\u00F4n `click` \u2014 n\u00FAt trong template ngo\u00E0i b\u1EA5m kh\u00F4ng \u0103n\n (\u0111o 09/09/2026: b\u1EA5m b\u1EB1ng `.click()` c\u1EE7a DOM th\u00EC m\u1EDF, b\u1EA5m chu\u1ED9t th\u1EADt th\u00EC kh\u00F4ng).\n Ch\u1EB7n \u1EDF \u0110\u00C2Y \u0111\u1EC3 n\u01A1i d\u00F9ng kh\u00F4ng ph\u1EA3i bi\u1EBFt b\u1EABy n\u00E0y. -->\n <div\n class=\"libs-ui-grid-layout-toolbar\"\n role=\"toolbar\"\n tabindex=\"0\"\n [class.libs-ui-grid-layout-toolbar-child]=\"isNestedCanvas()\"\n (mousedown)=\"handlerStopEvent($event)\"\n (keydown)=\"handlerStopEvent($event)\"\n (click)=\"handlerStopEvent($event)\">\n <ng-container\n *ngTemplateOutlet=\"templateToolbar()!; context: toolbarContexts()[itemIndex]\" />\n </div>\n } @else {\n <div\n class=\"libs-ui-grid-layout-toolbar\"\n [class.libs-ui-grid-layout-toolbar-child]=\"isNestedCanvas()\">\n <span class=\"libs-ui-grid-layout-dim-badge\">\n {{ item.rows }} h\u00E0ng \u00D7 {{ item.cols }} c\u1ED9t\n </span>\n @if (canAddInside(item)) {\n <libs_ui-components-buttons-button\n [type]=\"'button-third'\"\n [iconOnlyType]=\"true\"\n [sizeButton]=\"'smaller'\"\n [classIconLeft]=\"'libs-ui-icon-add'\"\n [popover]=\"{ config: { content: 'Th\u00EAm kh\u1ED1i v\u00E0o trong', zIndex: 1300 } }\"\n (outClick)=\"handlerAddInside($event, item)\" />\n }\n @if (canToggleType(item)) {\n <libs_ui-components-buttons-button\n [type]=\"'button-third'\"\n [iconOnlyType]=\"true\"\n [sizeButton]=\"'smaller'\"\n [classIconLeft]=\"isContainer(item) ? 'libs-ui-icon-split-cell' : 'libs-ui-icon-merge-cell'\"\n [popover]=\"{ config: { content: isContainer(item) ? '\u0110\u01B0a v\u1EC1 kh\u1ED1i \u0111\u01A1n' : 'Chuy\u1EC3n th\u00E0nh kh\u1ED1i gh\u00E9p', zIndex: 1300 } }\"\n (outClick)=\"handlerToggleType($event, item)\" />\n }\n <libs_ui-components-buttons-button\n [type]=\"'button-third'\"\n [iconOnlyType]=\"true\"\n [sizeButton]=\"'smaller'\"\n [classIconLeft]=\"'libs-ui-icon-setting'\"\n [popover]=\"{ config: { content: 'C\u1EA5u h\u00ECnh th\u1EBB', zIndex: 1300 } }\"\n (outClick)=\"handlerConfig($event, item)\" />\n <libs_ui-components-buttons-button\n [type]=\"'button-third-hover-danger'\"\n [iconOnlyType]=\"true\"\n [sizeButton]=\"'smaller'\"\n [classIconLeft]=\"'libs-ui-icon-remove'\"\n [popover]=\"{ config: { content: isContainer(item) ? 'Xo\u00E1 c\u1EA3 kh\u1ED1i gh\u00E9p' : 'Xo\u00E1 kh\u1ED1i', zIndex: 1300 } }\"\n (outClick)=\"handlerRemove($event, item)\" />\n </div>\n }\n }\n\n @if (item.children && item.children.length > 0) {\n <!-- Kh\u1ED1i c\u00F3 con \u2192 ru\u1ED9t n\u00F3 l\u1EA1i l\u00E0 m\u1ED9t m\u1EB7t ph\u1EB3ng n\u1EEFa. \u0110\u1EC7 quy \u1EDF \u0111\u00E2y, n\u01A1i d\u00F9ng kh\u00F4ng ph\u1EA3i lo.\n L\u1EC1 \u0111\u1EB7t \u1EDF \u0110\u00C2Y (v\u1ECF container), kh\u00F4ng \u0111\u1EB7t v\u00E0o l\u01B0\u1EDBi con \u2014 l\u01B0\u1EDBi con gi\u1EEF nguy\u00EAn khe 2px. -->\n <libs_ui-services-grid_layout-canvas\n class=\"block h-full w-full\"\n [style.padding]=\"containerPadding()\"\n [node]=\"item\"\n [depth]=\"depth() + 1\"\n [hiddenToolbar]=\"hiddenToolbar()\"\n [templateToolbar]=\"templateToolbar()\"\n [selectedNodeId]=\"selectedNodeId()\"\n (outSelectNode)=\"outSelectNode.emit($event)\"\n (outConfigNode)=\"outConfigNode.emit($event)\"\n (outChange)=\"outChange.emit($event)\"\n (outRemoveNode)=\"outRemoveNode.emit($event)\"\n (outAddBlockInside)=\"outAddBlockInside.emit($event)\"\n (outToggleType)=\"outToggleType.emit($event)\" />\n }\n </div>\n </gridster-item>\n }\n </gridster>\n </div>\n </div>\n\n <!-- Thanh dock \u0111i\u1EC1u khi\u1EC3n thu ph\u00F3ng n\u1ED5i \u1EDF g\u00F3c d\u01B0\u1EDBi tr\u00E1i -->\n @if (showZoomDock()) {\n <div\n #zoomDock\n id=\"canvas-zoom-dock\"\n role=\"toolbar\"\n tabindex=\"0\"\n class=\"absolute bottom-4 left-6 z-30 flex items-center bg-white rounded-full shadow-2xl border-2 border-slate-400 p-1 space-x-1 select-none\"\n (mousedown)=\"$event.stopPropagation()\"\n (keydown)=\"$event.stopPropagation()\"\n (click)=\"$event.stopPropagation()\">\n <!-- Thu nh\u1ECF (-) -->\n <button\n type=\"button\"\n class=\"w-[28px] h-[28px] flex items-center justify-center rounded-full text-slate-700 hover:text-slate-900 hover:bg-slate-200 disabled:opacity-30 disabled:hover:bg-transparent transition-colors cursor-pointer\"\n [disabled]=\"currentZoom() <= zoomMin()\"\n [title]=\"'i18n_zoom_out' | translate\"\n (click)=\"handlerZoomOut()\">\n <svg class=\"w-3.5 h-3.5\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\"><line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\"/></svg>\n </button>\n\n <!-- T\u1EF7 l\u1EC7 % v\u00E0 menu preset -->\n <div class=\"relative\">\n <button\n type=\"button\"\n class=\"h-[28px] px-2 flex items-center gap-1 rounded-full text-xs font-semibold text-slate-700 hover:bg-slate-200 transition-colors cursor-pointer\"\n [title]=\"'i18n_zoom_options' | translate\"\n (click)=\"handlerToggleMenu()\">\n <span>{{ zoomPercent() }}%</span>\n <svg class=\"w-[12px] h-[12px] text-slate-400 transition-transform duration-150\" [class.rotate-180]=\"isMenuOpen()\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"6 9 12 15 18 9\"/></svg>\n </button>\n\n <!-- Menu dropdown c\u00E1c m\u1ED1c thu ph\u00F3ng -->\n @if (isMenuOpen()) {\n <div class=\"absolute bottom-full mb-2 left-0 w-[256px] bg-white rounded-xl shadow-xl border border-slate-200 py-1.5 z-40 text-xs select-none\">\n <div class=\"px-3 py-1 text-[11px] font-semibold text-slate-400 uppercase tracking-wider\">\n {{ 'i18n_zoom_canvas_width' | translate: { width: stageWidth() } }}\n </div>\n <button\n type=\"button\"\n class=\"w-full px-3 py-2 text-left flex items-center justify-between hover:bg-slate-50 transition-colors cursor-pointer\"\n (click)=\"handlerFitScreen()\">\n <span class=\"flex items-center gap-2 text-slate-700 font-medium\">\n <svg class=\"w-3.5 h-3.5 text-slate-600\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><polyline points=\"15 3 21 3 21 9\"/><polyline points=\"9 21 3 21 3 15\"/><line x1=\"21\" y1=\"3\" x2=\"14\" y2=\"10\"/><line x1=\"3\" y1=\"21\" x2=\"10\" y2=\"14\"/></svg>\n {{ 'i18n_zoom_fit_screen' | translate }}\n </span>\n <span class=\"text-[10px] bg-blue-50 text-blue-600 px-1.5 py-0.5 rounded font-medium\">{{ 'i18n_auto' | translate }}</span>\n </button>\n <div class=\"h-px bg-slate-100 my-1\"></div>\n @for (preset of zoomPresets; track preset.value) {\n <button\n type=\"button\"\n class=\"w-full px-3 py-1.5 text-left flex items-center justify-between hover:bg-slate-50 transition-colors cursor-pointer\"\n [class.text-blue-600]=\"isCurrentPreset(preset.value)\"\n [class.font-semibold]=\"isCurrentPreset(preset.value)\"\n [class.bg-blue-50]=\"isCurrentPreset(preset.value)\"\n (click)=\"handlerSelectPreset(preset.value)\">\n <span class=\"text-slate-700\" [class.text-blue-600]=\"isCurrentPreset(preset.value)\">\n {{ preset.label | translate }}\n </span>\n @if (isCurrentPreset(preset.value)) {\n <svg class=\"w-3.5 h-3.5 text-blue-600\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"/></svg>\n }\n </button>\n }\n </div>\n }\n </div>\n\n <!-- Ph\u00F3ng to (+) -->\n <button\n type=\"button\"\n class=\"w-[28px] h-[28px] flex items-center justify-center rounded-full text-slate-700 hover:text-slate-900 hover:bg-slate-200 disabled:opacity-30 disabled:hover:bg-transparent transition-colors cursor-pointer\"\n [disabled]=\"currentZoom() >= zoomMax()\"\n [title]=\"'i18n_zoom_in' | translate\"\n (click)=\"handlerZoomIn()\">\n <svg class=\"w-3.5 h-3.5\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\"><line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\"/><line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\"/></svg>\n </button>\n\n <!-- Ph\u00E2n c\u00E1ch -->\n <div class=\"h-[16px] w-px bg-slate-200\"></div>\n\n <!-- N\u00FAt V\u1EEBa m\u00E0n h\u00ECnh nhanh -->\n <button\n type=\"button\"\n class=\"h-[28px] shrink-0 px-2.5 flex items-center gap-1 rounded-full text-xs text-slate-700 hover:text-slate-900 hover:bg-slate-200 transition-colors cursor-pointer\"\n [title]=\"'i18n_zoom_fit_screen_tooltip' | translate\"\n (click)=\"handlerFitScreen()\">\n <svg class=\"w-3.5 h-3.5\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><polyline points=\"15 3 21 3 21 9\"/><polyline points=\"9 21 3 21 3 15\"/><line x1=\"21\" y1=\"3\" x2=\"14\" y2=\"10\"/><line x1=\"3\" y1=\"21\" x2=\"10\" y2=\"14\"/></svg>\n <span class=\"whitespace-nowrap font-medium\">{{ 'i18n_zoom_fit_screen' | translate }}</span>\n </button>\n\n <!-- N\u00FAt \u0110\u1EB7t l\u1EA1i 100% (ch\u1EC9 hi\u1EC7n khi kh\u00E1c 100%) -->\n @if (zoomPercent() !== 100) {\n <button\n type=\"button\"\n class=\"h-[28px] px-2 flex items-center gap-1 rounded-full text-xs font-semibold text-blue-600 hover:bg-blue-50 transition-colors cursor-pointer\"\n [title]=\"'i18n_zoom_reset_tooltip' | translate: { width: stageWidth(), height: stageMinHeight() }\"\n (click)=\"handlerResetZoom()\">\n <svg class=\"w-[12px] h-[12px]\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"1 4 1 10 7 10\"/><path d=\"M3.51 15a9 9 0 1 0 2.13-9.36L1 10\"/></svg>\n <span>100%</span>\n </button>\n }\n </div>\n }\n} @else {\n <!-- \uD83D\uDD34 `relative` l\u00E0 B\u1EAET BU\u1ED8C, C\u1EA4M b\u1ECF.\n gridster \u0111\u1ED5i v\u1ECB tr\u00ED chu\u1ED9t th\u00E0nh \u00F4 l\u01B0\u1EDBi b\u1EB1ng `e.clientY + (el.scrollTop - el.offsetTop)` \u2014 c\u00F4ng\n th\u1EE9c \u0111\u00F3 ch\u1EC9 \u0111\u00FAng khi `offsetParent` c\u1EE7a <gridster> CH\u00CDNH L\u00C0 kh\u1ED1i cu\u1ED9n n\u00E0y. Thi\u1EBFu `relative` th\u00EC\n `offsetParent` nh\u1EA3y l\u00EAn kh\u1ED1i bao ngo\u00E0i: `offsetTop` tr\u1EA3 16 trong khi l\u1EC7ch th\u1EADt l\u00E0 65 \u2192 gridster\n t\u00EDnh \u00F4 sai 49px, \u00F4 ch\u1EDD \u0111\u1EB7t hi\u1EC7n l\u1EC7ch kh\u1ECFi con tr\u1ECF n\u00EAn k\u00E9o th\u1EA3 kh\u00F4ng \u0111\u1ED5i \u0111\u01B0\u1EE3c v\u1ECB tr\u00ED, v\u00E0 k\u00E9o m\u00E9p\n c\u0169ng t\u00EDnh sai \u0111i\u1EC3m d\u1EEBng. -->\n <div\n #scrollArea\n class=\"libs-ui-grid-layout-scroll-area relative h-full min-h-0 w-full min-w-0\"\n [class.overflow-y-auto]=\"!isNestedCanvas()\"\n (mousedown)=\"handlerMouseDownTrongLuoi($event)\"\n (dragover)=\"handlerDragOver($event)\"\n (dragleave)=\"handlerDragLeave($event)\"\n (drop)=\"handlerDrop($event)\">\n <!-- Snapped Drop Ghost Preview -->\n @if (dropGhost(); as ghost) {\n <div\n class=\"pointer-events-none absolute z-30 flex flex-col items-center justify-center overflow-hidden rounded-lg border-2 border-dashed border-blue-500 bg-blue-500/15 p-1 shadow-sm transition-all duration-75 ease-out backdrop-blur-[0.5px] select-none\"\n [style.left.px]=\"ghost.pixelLeft\"\n [style.top.px]=\"ghost.pixelTop\"\n [style.width.px]=\"ghost.pixelWidth\"\n [style.height.px]=\"ghost.pixelHeight\">\n <div class=\"inline-flex max-w-[95%] items-center gap-1 truncate rounded-md bg-blue-600 px-2 py-0.5 text-[11px] font-semibold text-white shadow-xs\">\n @if (ghost.cardIconClass) {\n <i [class]=\"ghost.cardIconClass + ' text-xs'\"></i>\n } @else if (ghost.cardIconText) {\n <span class=\"text-[10px] font-bold\">{{ ghost.cardIconText }}</span>\n } @else {\n <span class=\"text-xs font-bold\">{{ ghost.isInsideGroup ? '\u21B3' : '+' }}</span>\n }\n <span class=\"truncate\">{{ ghost.cardTitle }}</span>\n <span class=\"text-[9px] font-mono opacity-75\">({{ ghost.cols }}c)</span>\n </div>\n\n @if (ghost.pixelHeight >= 80) {\n <div class=\"mt-1 flex max-w-[95%] items-center gap-1.5 truncate rounded border border-blue-100 bg-white/95 px-2 py-0.5 text-[10px] font-medium text-blue-700 shadow-xs\">\n @if (ghost.isInsideGroup) {\n <span class=\"truncate font-bold text-blue-900\">\u21B3 {{ ghost.groupTitle }}</span>\n <span class=\"text-blue-300\">\u2022</span>\n }\n <span>C\u1ED9t {{ ghost.col + 1 }}-{{ ghost.col + ghost.cols }}</span>\n </div>\n }\n </div>\n }\n <gridster class=\"h-full w-full\" [class.display-grid]=\"showGridLines()\" [options]=\"gridOptions()\">\n @for (item of children(); track item.id; let itemIndex = $index) {\n <!-- \uD83D\uDD34 Ch\u1EB7n `mousedown` t\u1EA1i \u0110\u00C2Y cho l\u01B0\u1EDBi l\u1ED3ng \u2014 C\u1EA4M b\u1ECF v\u00E0 C\u1EA4M chuy\u1EC3n sang ch\u1ED7 kh\u00E1c.\n `ignoreContentClass` m\u1ED9t m\u00ECnh KH\u00D4NG \u0111\u1EE7: `delayStart: 160` l\u00E0m M\u1ED6I l\u01B0\u1EDBi l\u00EAn l\u1ECBch\n `dragStart` b\u1EB1ng `setTimeout` ngay t\u1EA1i `mousedown`, c\u00F2n `stopPropagation` m\u00E0 lib g\u1ECDi b\u00EAn\n trong `dragStart` ch\u1EA1y sau 160ms n\u00EAn qu\u00E1 mu\u1ED9n \u2014 l\u01B0\u1EDBi CHA \u0111\u00E3 k\u1ECBp nh\u1EADn (\u0111o 28/08/2026: k\u00E9o\n d\u1EA3i kh\u1ED1i con, chu\u1ED7i class duy\u1EC7t l\u00EAn \u0110\u00DANG m\u00E0 container v\u1EABn nh\u1EA3y 0,0 \u2192 0,1).\n G\u1EAFn \u1EDF `gridster-item` l\u00E0 \u0111\u00FAng bi\u00EAn: l\u01B0\u1EDBi con nghe tr\u00EAn ch\u00EDnh ph\u1EA7n t\u1EED n\u00E0y n\u00EAn \u0111\u00E3 nh\u1EADn xong,\n l\u01B0\u1EDBi cha \u1EDF ngo\u00E0i b\u1ECB ch\u1EB7n. -->\n <gridster-item\n [item]=\"item\"\n [class.libs-ui-grid-layout-selected]=\"selectedNodeId() === item.id\"\n (click)=\"handlerSelectNode(item, $event)\"\n (mousedown)=\"handlerBlockParentDrag($event)\">\n <!-- \uD83D\uDD34 V\u1ECF n\u00E0y mang `dragHandleClass` \u2014 C\u1EA4M b\u1ECF.\n `ignoreContent: true` b\u1EAFt gridster CH\u1EC8 cho k\u00E9o khi ch\u1ED7 b\u1EA5m n\u1EB1m d\u01B0\u1EDBi m\u1ED9t ph\u1EA7n t\u1EED c\u00F3\n `dragHandleClass`. Kh\u00F4ng c\u00F3 v\u1ECF n\u00E0y th\u00EC component c\u1EE7a n\u01A1i d\u00F9ng (th\u01B0 vi\u1EC7n kh\u00F4ng ki\u1EC3m so\u00E1t\n \u0111\u01B0\u1EE3c class c\u1EE7a n\u00F3) s\u1EBD kh\u00F4ng c\u00F3 tay c\u1EA7m n\u00E0o, v\u00E0 KH\u00D4NG kh\u1ED1i n\u00E0o k\u00E9o \u0111\u01B0\u1EE3c \u2014 \u0111o 28/08/2026:\n k\u00E9o 320px, to\u1EA1 \u0111\u1ED9 kh\u1ED1i gi\u1EEF nguy\u00EAn x=3,y=0.\n T\u00EAn class theo c\u1EA5p: l\u01B0\u1EDBi trang v\u00E0 l\u01B0\u1EDBi l\u1ED3ng d\u00F9ng hai t\u00EAn KH\u00C1C nhau, n\u1EBFu kh\u00F4ng l\u01B0\u1EDBi cha\n c\u0169ng nh\u1EADn ra tay c\u1EA7m c\u1EE7a kh\u1ED1i con v\u00E0 nh\u1EA5c lu\u00F4n container. -->\n <!-- \uD83D\uDD34 V\u1ECF KH\u00D4NG mang `dragHandleClass` \u2014 C\u1EA4M th\u00EAm l\u1EA1i.\n K\u00E9o ch\u1EC9 \u0111\u01B0\u1EE3c ph\u00E9p b\u1EAFt \u0111\u1EA7u t\u1EEB D\u1EA2I XANH (ng\u01B0\u1EDDi d\u00F9ng ch\u1ED1t 28/08/2026: \"ph\u1EA3i hover v\u00E0o v\u00F9ng\n m\u00E0u xanh th\u00EC m\u1EDBi k\u00E9o th\u1EA3 \u0111\u01B0\u1EE3c cho \u0111\u1ED3ng nh\u1EA5t\"). Cho c\u1EA3 v\u1ECF l\u00E0m tay c\u1EA7m th\u00EC b\u1EA5m \u0111\u00E2u c\u0169ng\n k\u00E9o, v\u00E0 kh\u1ED1i con n\u1EB1m trong container s\u1EBD nh\u1EA5c lu\u00F4n container v\u00EC l\u01B0\u1EDBi cha duy\u1EC7t l\u00EAn g\u1EB7p\n tay c\u1EA7m c\u1EE7a v\u1ECF container tr\u01B0\u1EDBc.\n V\u1ECF kh\u1ED1i con v\u1EABn gi\u1EEF class CH\u1EB6N \u0111\u1EC3 l\u01B0\u1EDBi cha d\u1EEBng \u0111\u00FAng \u1EDF bi\u00EAn. -->\n <div\n class=\"libs-ui-grid-layout-block-shell group relative h-full w-full min-w-0\"\n [class.libs-ui-grid-layout-block-parent-drag]=\"isNestedCanvas()\">\n <!-- D\u1EA3i k\u00E9o: hi\u1EC7n khi r\u00EA chu\u1ED9t v\u00E0o kh\u1ED1i, ba ch\u1EA5m l\u00E0 d\u1EA5u hi\u1EC7u k\u00E9o quen thu\u1ED9c.\n Ng\u01B0\u1EDDi d\u00F9ng c\u1EA7n m\u1ED9t ch\u1ED7 b\u00E1m R\u00D5 R\u00C0NG thay v\u00EC \u0111o\u00E1n xem b\u1EA5m \u0111\u00E2u th\u00EC k\u00E9o \u0111\u01B0\u1EE3c\n (ch\u1ED1t 28/08/2026, theo \u0111\u00FAng d\u1EA3i \u0111ang d\u00F9ng \u1EDF m\u00E0n Customer 360 c\u1EE7a mobio-web). -->\n @if (isEditMode()) {\n <!-- \uD83D\uDD34 D\u1EA3i PH\u1EA2I mang tay c\u1EA7m \u0110\u00DANG C\u1EA4P c\u1EE7a n\u00F3. D\u1EA3i nh\u1EADn chu\u1ED9t (`pointer-events: auto`),\n n\u00EAn n\u1EBFu kh\u00F4ng mang tay c\u1EA7m th\u00EC `checkDragHandleClass` duy\u1EC7t l\u00EAn g\u1EB7p tay c\u1EA7m c\u1EE7a\n container v\u00E0 nh\u1EA5c container thay v\u00EC kh\u1ED1i con (\u0111o 28/08/2026: k\u00E9o d\u1EA3i kh\u1ED1i con,\n container nh\u1EA3y 0,0 \u2192 0,1 c\u00F2n kh\u1ED1i con \u0111\u1EE9ng im).\n \uD83D\uDD34 D\u1EA3i CH\u1EC8 mang tay c\u1EA7m, C\u1EA4M mang th\u00EAm class ch\u1EB7n: `checkDragHandleClass` x\u00E9t hai\n class \u0111\u00F3 tr\u00EAn C\u00D9NG m\u1ED9t node n\u00EAn \u0111\u1EC3 chung l\u00E0 k\u00E9o h\u1ECFng (\u0111o 28/08/2026: b\u1EA5m d\u1EA3i kh\u1ED1i\n con k\u00E9o 140px, kh\u1ED1i \u0111\u1EE9ng im). Vi\u1EC7c ch\u1EB7n l\u01B0\u1EDBi cha do V\u1ECE KH\u1ED0I lo. -->\n <div\n class=\"libs-ui-grid-layout-drag-bar\"\n [class.libs-ui-grid-layout-drag-bar-child]=\"isNestedCanvas()\"\n [class.libs-ui-grid-layout-drag-handle]=\"!isNestedCanvas()\"\n [class.libs-ui-grid-layout-drag-handle-child]=\"isNestedCanvas()\">\n <span class=\"libs-ui-grid-layout-drag-bar-dots\">\n @for (dot of dragBarDots; track dot) {\n <span class=\"libs-ui-grid-layout-drag-bar-dot\"></span>\n }\n </span>\n </div>\n }\n\n <!-- Khung ch\u1EE9a component c\u1EE7a n\u01A1i d\u00F9ng.\n \uD83D\uDD34 PH\u1EA2I c\u00F3 khung th\u1EADt (kh\u00F4ng ph\u1EA3i `ng-container` tr\u1ED1ng): n\u00F3 lo h\u1ED9 n\u01A1i d\u00F9ng ph\u1EA7n l\u1EA5p \u0111\u1EA7y\n \u00F4 v\u00E0 vi\u1EC1n b\u00E1o ch\u1EBF \u0111\u1ED9 s\u1EEDa. Kh\u00F4ng c\u00F3 khung th\u00EC m\u1ED7i component n\u1ED9i dung l\u1EA1i ph\u1EA3i t\u1EF1 vi\u1EBFt\n `:host { width/height: 100% }` + vi\u1EC1n \u0111\u1EE9t \u2014 \u0111\u00F3 l\u00E0 vi\u1EC7c c\u1EE7a th\u01B0 vi\u1EC7n, kh\u00F4ng ph\u1EA3i c\u1EE7a\n ng\u01B0\u1EDDi d\u00F9ng (ng\u01B0\u1EDDi d\u00F9ng ch\u1ED1t 28/08/2026).\n M\u1ED7i kh\u1ED1i m\u1ED9t ViewContainerRef ri\u00EAng n\u00EAn component n\u1EB1m \u0111\u00FAng \u00F4 c\u1EE7a n\u00F3. -->\n <div\n class=\"libs-ui-grid-layout-content-frame\"\n [class.libs-ui-grid-layout-content-frame-edit]=\"isEditMode() && !isContainer(item)\"\n [class.libs-ui-grid-layout-content-frame-empty]=\"isContainer(item)\">\n <ng-container #itemHost />\n </div>\n\n <!-- D\u1EA5u hi\u1EC7u CONTAINER: nh\u00E3n g\u00F3c tr\u00EAn-ph\u1EA3i + vi\u1EC1n \u0111\u1EE9t bao ru\u1ED9t. Kh\u00F4ng c\u00F3 d\u1EA5u hi\u1EC7u th\u00EC\n ng\u01B0\u1EDDi d\u00F9ng kh\u00F4ng bi\u1EBFt kh\u1ED1i n\u00E0o ch\u1EE9a \u0111\u01B0\u1EE3c kh\u1ED1i kh\u00E1c (ch\u1ED1t 28/08/2026, theo \u0111\u00FAng c\u00E1ch\n m\u00E0n Customer 360 c\u1EE7a mobio-web \u0111ang l\u00E0m). -->\n @if (isEditMode() && isContainer(item)) {\n <div class=\"libs-ui-grid-layout-container-label\">{{ 'i18n_container_block' | translate }}</div>\n <div class=\"libs-ui-grid-layout-container-border\"></div>\n }\n\n <!-- Thanh c\u00F4ng c\u1EE5: hi\u1EC7n khi r\u00EA chu\u1ED9t v\u00E0o kh\u1ED1i.\n \uD83D\uDD34 D\u00F9ng `libs_ui-components-buttons-button` \u2014 C\u1EA4M t\u1EF1 d\u1EF1ng th\u1EBB `<button>`.\n Component n\u00E0y \u0111\u00E3 c\u00F3 s\u1EB5n ki\u1EC3u n\u00FAt, c\u1EE1 n\u00FAt v\u00E0 bong b\u00F3ng ch\u00FA th\u00EDch theo \u0111\u00FAng b\u1ED9 giao di\u1EC7n\n c\u1EE7a s\u1EA3n ph\u1EA9m; t\u1EF1 d\u1EF1ng l\u00E0 m\u1ED7i n\u01A1i m\u1ED9t ki\u1EC3u v\u00E0 m\u1EA5t lu\u00F4n tooltip. -->\n @if (isEditMode() && !hiddenToolbar()) {\n @if (templateToolbar()) {\n <!-- N\u01A1i d\u00F9ng t\u1EF1 v\u1EBD thanh c\u00F4ng c\u1EE5: nh\u1EADn kh\u1ED1i + c\u00E1c h\u00E0m ph\u00E1t event qua context.\n\n \uD83D\uDD34 Kh\u1ED1i b\u1ECDc t\u1EF1 ch\u1EB7n `mousedown`/`click` n\u1ED5i l\u00EAn gridster. Thanh c\u00F4ng c\u1EE5 n\u1EB1m trong\n v\u00F9ng mang `dragHandleClass`; kh\u00F4ng ch\u1EB7n th\u00EC c\u00FA b\u1EA5m b\u1ECB hi\u1EC3u l\u00E0 b\u1EAFt \u0111\u1EA7u k\u00E9o v\u00E0\n `delayStart: 160` nu\u1ED1t lu\u00F4n `click` \u2014 n\u00FAt trong template ngo\u00E0i b\u1EA5m kh\u00F4ng \u0103n\n (\u0111o 09/09/2026: b\u1EA5m b\u1EB1ng `.click()` c\u1EE7a DOM th\u00EC m\u1EDF, b\u1EA5m chu\u1ED9t th\u1EADt th\u00EC kh\u00F4ng).\n Ch\u1EB7n \u1EDF \u0110\u00C2Y \u0111\u1EC3 n\u01A1i d\u00F9ng kh\u00F4ng ph\u1EA3i bi\u1EBFt b\u1EABy n\u00E0y. -->\n <div\n class=\"libs-ui-grid-layout-toolbar\"\n role=\"toolbar\"\n tabindex=\"0\"\n [class.libs-ui-grid-layout-toolbar-child]=\"isNestedCanvas()\"\n (mousedown)=\"handlerStopEvent($event)\"\n (keydown)=\"handlerStopEvent($event)\"\n (click)=\"handlerStopEvent($event)\">\n <ng-container\n *ngTemplateOutlet=\"templateToolbar()!; context: toolbarContexts()[itemIndex]\" />\n </div>\n } @else {\n <div\n class=\"libs-ui-grid-layout-toolbar\"\n [class.libs-ui-grid-layout-toolbar-child]=\"isNestedCanvas()\">\n <span class=\"libs-ui-grid-layout-dim-badge\">\n {{ item.rows }} h\u00E0ng \u00D7 {{ item.cols }} c\u1ED9t\n </span>\n @if (canAddInside(item)) {\n <libs_ui-components-buttons-button\n [type]=\"'button-third'\"\n [iconOnlyType]=\"true\"\n [sizeButton]=\"'smaller'\"\n [classIconLeft]=\"'libs-ui-icon-add'\"\n [popover]=\"{ config: { content: 'Th\u00EAm kh\u1ED1i v\u00E0o trong', zIndex: 1300 } }\"\n (outClick)=\"handlerAddInside($event, item)\" />\n }\n @if (canToggleType(item)) {\n <libs_ui-components-buttons-button\n [type]=\"'button-third'\"\n [iconOnlyType]=\"true\"\n [sizeButton]=\"'smaller'\"\n [classIconLeft]=\"isContainer(item) ? 'libs-ui-icon-split-cell' : 'libs-ui-icon-merge-cell'\"\n [popover]=\"{ config: { content: isContainer(item) ? '\u0110\u01B0a v\u1EC1 kh\u1ED1i \u0111\u01A1n' : 'Chuy\u1EC3n th\u00E0nh kh\u1ED1i gh\u00E9p', zIndex: 1300 } }\"\n (outClick)=\"handlerToggleType($event, item)\" />\n }\n <libs_ui-components-buttons-button\n [type]=\"'button-third'\"\n [iconOnlyType]=\"true\"\n [sizeButton]=\"'smaller'\"\n [classIconLeft]=\"'libs-ui-icon-setting'\"\n [popover]=\"{ config: { content: 'C\u1EA5u h\u00ECnh th\u1EBB', zIndex: 1300 } }\"\n (outClick)=\"handlerConfig($event, item)\" />\n <libs_ui-components-buttons-button\n [type]=\"'button-third-hover-danger'\"\n [iconOnlyType]=\"true\"\n [sizeButton]=\"'smaller'\"\n [classIconLeft]=\"'libs-ui-icon-remove'\"\n [popover]=\"{ config: { content: isContainer(item) ? 'Xo\u00E1 c\u1EA3 kh\u1ED1i gh\u00E9p' : 'Xo\u00E1 kh\u1ED1i', zIndex: 1300 } }\"\n (outClick)=\"handlerRemove($event, item)\" />\n </div>\n }\n }\n\n @if (item.children && item.children.length > 0) {\n <!-- Kh\u1ED1i c\u00F3 con \u2192 ru\u1ED9t n\u00F3 l\u1EA1i l\u00E0 m\u1ED9t m\u1EB7t ph\u1EB3ng n\u1EEFa. \u0110\u1EC7 quy \u1EDF \u0111\u00E2y, n\u01A1i d\u00F9ng kh\u00F4ng ph\u1EA3i lo.\n L\u1EC1 \u0111\u1EB7t \u1EDF \u0110\u00C2Y (v\u1ECF container), kh\u00F4ng \u0111\u1EB7t v\u00E0o l\u01B0\u1EDBi con \u2014 l\u01B0\u1EDBi con gi\u1EEF nguy\u00EAn khe 2px. -->\n <libs_ui-services-grid_layout-canvas\n class=\"block h-full w-full\"\n [style.padding]=\"containerPadding()\"\n [node]=\"item\"\n [depth]=\"depth() + 1\"\n [hiddenToolbar]=\"hiddenToolbar()\"\n [templateToolbar]=\"templateToolbar()\"\n [selectedNodeId]=\"selectedNodeId()\"\n (outSelectNode)=\"outSelectNode.emit($event)\"\n (outConfigNode)=\"outConfigNode.emit($event)\"\n (outChange)=\"outChange.emit($event)\"\n (outRemoveNode)=\"outRemoveNode.emit($event)\"\n (outAddBlockInside)=\"outAddBlockInside.emit($event)\"\n (outToggleType)=\"outToggleType.emit($event)\" />\n }\n </div>\n </gridster-item>\n }\n </gridster>\n </div>\n}\n", styles: [":host{display:block;position:relative;box-sizing:border-box;width:100%;height:100%;min-width:0;min-height:0}.libs-ui-grid-layout-block-shell{container-type:inline-size;display:block;box-sizing:border-box;height:100%}.libs-ui-grid-layout-drag-bar{position:absolute;top:2px;left:50%;z-index:15;display:flex;align-items:center;justify-content:center;width:64px;height:16px;background:transparent;transform:translate(-50%);opacity:1;transition:opacity .12s ease;pointer-events:auto;cursor:move}.libs-ui-grid-layout-drag-bar-dots{display:grid;grid-template-columns:repeat(3,3px);gap:3px;color:#9ca2ad}.libs-ui-grid-layout-drag-bar-dot{width:3px;height:3px;background:currentColor;border-radius:50%}.libs-ui-grid-layout-drag-bar:hover .libs-ui-grid-layout-drag-bar-dots{color:#3d6ef5}.libs-ui-grid-layout-drag-bar:not(.libs-ui-grid-layout-drag-bar-child){opacity:1}.libs-ui-grid-layout-drag-bar-child{top:auto;bottom:0;background:#d9f2e4;border-radius:4px 4px 0 0}.libs-ui-grid-layout-drag-bar-child .libs-ui-grid-layout-drag-bar-dots{color:#9ca2ad}.libs-ui-grid-layout-drag-bar-child:hover .libs-ui-grid-layout-drag-bar-dots{color:#00a757}.libs-ui-grid-layout-drag-bar-child{opacity:0}.libs-ui-grid-layout-block-shell:hover>.libs-ui-grid-layout-drag-bar-child{opacity:1}.libs-ui-grid-layout-block-shell:has(>.libs-ui-grid-layout-drag-bar:not(.libs-ui-grid-layout-drag-bar-child):hover){outline:2px solid #3d6ef5;outline-offset:-2px;border-radius:8px}.libs-ui-grid-layout-block-shell:has(>.libs-ui-grid-layout-drag-bar-child:hover){outline:2px solid #00a757;outline-offset:-2px;border-radius:8px}.libs-ui-grid-layout-container-label{position:absolute;left:6px;top:2px;display:flex;height:20px;align-items:center;z-index:3;padding:0 6px;color:#3d6ef5;font-weight:500;font-size:10px;line-height:14px;background:#dbe4ff;border-radius:4px;pointer-events:none}.libs-ui-grid-layout-content-frame{box-sizing:border-box;width:100%;height:100%;overflow:hidden;border-radius:6px}.libs-ui-grid-layout-content-frame ::ng-deep>*{display:block;box-sizing:border-box;width:100%;height:100%}.libs-ui-grid-layout-content-frame-empty{height:0}.libs-ui-grid-layout-content-frame-edit{border:1px dashed #c3cede}.libs-ui-grid-layout-container-border{position:absolute;inset:0;border:1px dashed #9db4f0;border-radius:8px;pointer-events:none}.libs-ui-grid-layout-toolbar{position:absolute;top:6px;right:8px;z-index:24;display:flex;gap:2px;align-items:center;height:20px;background:#fff;border-radius:4px;box-shadow:0 2px 8px #0716311f;opacity:0;transition:opacity .12s ease}.libs-ui-grid-layout-toolbar-child{top:50%;right:8px;left:auto;transform:translateY(-50%)}.libs-ui-grid-layout-block-shell:hover>.libs-ui-grid-layout-toolbar{opacity:1}:host ::ng-deep gridster{background:transparent}:host ::ng-deep .gridster-item-resizable-handler.handle-n,:host ::ng-deep .gridster-item-resizable-handler.handle-s{height:16px}:host ::ng-deep .gridster-item-resizable-handler.handle-e,:host ::ng-deep .gridster-item-resizable-handler.handle-w{width:16px}:host ::ng-deep .gridster-item-resizable-handler.handle-n{top:0}:host ::ng-deep .gridster-item-resizable-handler.handle-s{bottom:0}:host ::ng-deep .gridster-item-resizable-handler.handle-e{right:0}:host ::ng-deep .gridster-item-resizable-handler.handle-w{left:0}:host ::ng-deep gridster-item.gridster-item-moving,:host ::ng-deep gridster-item.gridster-item-resizing{z-index:30!important}:host ::ng-deep gridster-item.gridster-item-moving>.libs-ui-grid-layout-block-shell,:host ::ng-deep gridster-item.gridster-item-resizing>.libs-ui-grid-layout-block-shell{outline:2px solid #3d6ef5;outline-offset:-2px;border-radius:8px}:host ::ng-deep gridster gridster gridster-item.gridster-item-moving>.libs-ui-grid-layout-block-shell,:host ::ng-deep gridster gridster gridster-item.gridster-item-resizing>.libs-ui-grid-layout-block-shell{outline-color:#00a757}:host ::ng-deep gridster-item.libs-ui-grid-layout-selected>.libs-ui-grid-layout-block-shell{outline:2px solid #2563eb!important;outline-offset:-2px!important;border-radius:8px!important;box-shadow:0 0 0 4px #2563eb26!important}:host ::ng-deep gridster.display-grid .gridster-column,:host ::ng-deep gridster gridster.display-grid .gridster-column{border-right:1px solid rgba(226,232,240,.7)!important;border-left:none!important;pointer-events:none!important;height:100%!important;min-height:100%!important}:host ::ng-deep gridster.display-grid .gridster-column:first-child,:host ::ng-deep gridster gridster.display-grid .gridster-column:first-child{border-left:1px solid rgba(226,232,240,.7)!important}:host ::ng-deep gridster.display-grid .gridster-row,:host ::ng-deep gridster gridster.display-grid .gridster-row{border-bottom:1px solid rgba(226,232,240,.7)!important;border-top:none!important;pointer-events:none!important}:host ::ng-deep gridster.display-grid .gridster-row:first-child,:host ::ng-deep gridster gridster.display-grid .gridster-row:first-child{border-top:1px solid rgba(226,232,240,.7)!important}:host ::ng-deep gridster gridster.display-grid{background-color:#f8fafc80!important}:host ::ng-deep gridster-preview{background:#2563eb1f!important;border:1.5px dashed #2563eb!important;border-radius:6px!important;z-index:25!important}.libs-ui-grid-layout-dim-badge{display:inline-flex;align-items:center;height:20px;padding:0 6px;background-color:#f1f5f9;border:1px solid #e2e8f0;border-radius:4px;color:#64748b;font-size:10px;font-weight:500;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;pointer-events:none;white-space:nowrap}@container (max-width: 80px){.libs-ui-grid-layout-drag-bar{top:26px}}.libs-ui-grid-layout-stage{box-sizing:border-box;transform-origin:top center;transition:zoom .15s ease-out}#canvas-zoom-dock{box-shadow:0 10px 25px -5px #0000001a,0 8px 10px -6px #0000001a}\n"] }]
|
|
562
565
|
}], ctorParameters: () => [], propDecorators: { handlerDocumentKeyDown: [{
|
|
563
566
|
type: HostListener,
|
|
564
567
|
args: ['document:keydown', ['$event']]
|
|
@@ -566,4 +569,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
566
569
|
type: HostListener,
|
|
567
570
|
args: ['document:click', ['$event']]
|
|
568
571
|
}] } });
|
|
569
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ3JpZC1sYXlvdXQtY2FudmFzLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL2xpYnMtdWkvc2VydmljZXMvZ3JpZC1sYXlvdXQvc3JjL2NhbnZhcy9ncmlkLWxheW91dC1jYW52YXMuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vLi4vbGlicy11aS9zZXJ2aWNlcy9ncmlkLWxheW91dC9zcmMvY2FudmFzL2dyaWQtbGF5b3V0LWNhbnZhcy5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBRUwsdUJBQXVCLEVBQ3ZCLFNBQVMsRUFFVCxZQUFZLEVBR1osZ0JBQWdCLEVBQ2hCLFFBQVEsRUFDUixNQUFNLEVBQ04sTUFBTSxFQUNOLEtBQUssRUFDTCxLQUFLLEVBQ0wsTUFBTSxFQUNOLE1BQU0sRUFDTixTQUFTLEVBQ1QsWUFBWSxHQUNiLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQ25ELE9BQU8sRUFBRSxzQ0FBc0MsRUFBRSxNQUFNLG9DQUFvQyxDQUFDO0FBQzVGLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxjQUFjLEVBQUUsTUFBTSxZQUFZLENBQUM7QUFDL0QsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQ3RELE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxtQ0FBbUMsQ0FBQztBQUNsRSxPQUFPLEVBQUUsdUJBQXVCLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQWFqRSxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQzs7OztBQUVuRjs7Ozs7R0FLRztBQVNILE1BQU0sT0FBTywrQkFBK0I7SUFDMUM7Ozs7O09BS0c7SUFDTSxJQUFJLEdBQUcsS0FBSyxFQUFxQixDQUFDO0lBQzNDLDhEQUE4RDtJQUNyRCxLQUFLLEdB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Z0JBQWdCLEVBQUUsQ0FBQyxRQUFRLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBBZnRlclZpZXdJbml0LFxuICBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneSxcbiAgQ29tcG9uZW50LFxuICBFbGVtZW50UmVmLFxuICBIb3N0TGlzdGVuZXIsXG4gIE9uRGVzdHJveSxcbiAgVGVtcGxhdGVSZWYsXG4gIFZpZXdDb250YWluZXJSZWYsXG4gIGNvbXB1dGVkLFxuICBlZmZlY3QsXG4gIGluamVjdCxcbiAgaW5wdXQsXG4gIG1vZGVsLFxuICBvdXRwdXQsXG4gIHNpZ25hbCxcbiAgdmlld0NoaWxkLFxuICB2aWV3Q2hpbGRyZW4sXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgTmdUZW1wbGF0ZU91dGxldCB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XG5pbXBvcnQgeyBMaWJzVWlDb21wb25lbnRzQnV0dG9uc0J1dHRvbkNvbXBvbmVudCB9IGZyb20gJ0BsaWJzLXVpL2NvbXBvbmVudHMtYnV0dG9ucy1idXR0b24nO1xuaW1wb3J0IHsgR3JpZHN0ZXJDb21wb25lbnQsIEdyaWRzdGVyTW9kdWxlIH0gZnJvbSAnZ3JpZHN0ZXIxOCc7XG5pbXBvcnQgeyBUcmFuc2xhdGVNb2R1bGUgfSBmcm9tICdAbmd4LXRyYW5zbGF0ZS9jb3JlJztcbmltcG9ydCB7IGVtcHR5Um9vdE5vZGUgfSBmcm9tICcuLi9kZWZpbmVzL2dyaWRzdGVyLWNvbmZpZy5kZWZpbmUnO1xuaW1wb3J0IHsgTGlic1VpR3JpZExheW91dFNlcnZpY2UgfSBmcm9tICcuLi9ncmlkLWxheW91dC5zZXJ2aWNlJztcbmltcG9ydCB7XG4gIFRfZ3JpZExheW91dF9hY3Rpb25FdmVudCxcbiAgVF9ncmlkTGF5b3V0X2FkZEV2ZW50LFxuICBUX2dyaWRMYXlvdXRfY2hhbmdlRXZlbnQsXG4gIFRfZ3JpZExheW91dF9kcm9wRXZlbnQsXG4gIFRfZ3JpZExheW91dF9kcm9wR2hvc3QsXG4gIFRfZ3JpZExheW91dF9leHRlcm5hbERyYWdQYXlsb2FkLFxuICBUX2dyaWRMYXlvdXRfbmV3Tm9kZSxcbiAgVF9ncmlkTGF5b3V0X25vZGUsXG4gIFRfZ3JpZExheW91dF90b29sYmFyQ29udGV4dCxcbiAgVF9ncmlkTGF5b3V0X3pvb21QcmVzZXQsXG59IGZyb20gJy4uL2ludGVyZmFjZXMvZ3JpZC1sYXlvdXQuaW50ZXJmYWNlJztcbmltcG9ydCB7IGNhbGN1bGF0ZURyb3BHaG9zdCwgcGFyc2VEcm9wUGF5bG9hZCB9IGZyb20gJy4uL2RlZmluZXMvY29sbGlzaW9uLmRlZmluZSc7XG5cbi8qKlxuICogTeG6t3QgcGjhurNuZyBrw6lvIHRo4bqjLiDEkOG7hyBxdXk6IGto4buRaSBjw7MgYGNoaWxkcmVuYCB0aMOsIHJ14buZdCBuw7MgbOG6oWkgbMOgIG3hu5l0IG3hurd0IHBo4bqzbmcgbuG7r2EuXG4gKlxuICogTsahaSBkw7luZyBLSMOUTkcgZOG7sW5nIGNvbXBvbmVudCBuw6B5IHRy4buxYyB0aeG6v3AgY2hvIHThu6tuZyBraOG7kWkg4oCUIGNo4buJIMSR4bq3dCBN4buYVCB0aOG6uyDhu58gZ+G7kWMgdsOgIHRydXnhu4FuXG4gKiBgbm9kZUNvbXBvbmVudFR5cGVgIHF1YSBgTGlic1VpR3JpZExheW91dFNlcnZpY2UuaW5pdCgpYC4gVGjGsCB2aeG7h24gdOG7sSBn4bqvbiBjb21wb25lbnQgY2hvIG3hu41pIGto4buRaS5cbiAqL1xuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnbGlic191aS1zZXJ2aWNlcy1ncmlkX2xheW91dC1jYW52YXMnLFxuICBzdGFuZGFsb25lOiB0cnVlLFxuICBpbXBvcnRzOiBbR3JpZHN0ZXJNb2R1bGUsIExpYnNVaUNvbXBvbmVudHNCdXR0b25zQnV0dG9uQ29tcG9uZW50LCBOZ1RlbXBsYXRlT3V0bGV0LCBUcmFuc2xhdGVNb2R1bGVdLFxuICB0ZW1wbGF0ZVVybDogJy4vZ3JpZC1sYXlvdXQtY2FudmFzLmNvbXBvbmVudC5odG1sJyxcbiAgc3R5bGVVcmw6ICcuL2dyaWQtbGF5b3V0LWNhbnZhcy5jb21wb25lbnQuc2NzcycsXG4gIGNoYW5nZURldGVjdGlvbjogQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3kuT25QdXNoLFxufSlcbmV4cG9ydCBjbGFzcyBMaWJzVWlHcmlkTGF5b3V0Q2FudmFzQ29tcG9uZW50IGltcGxlbWVudHMgQWZ0ZXJWaWV3SW5pdCwgT25EZXN0cm95IHtcbiAgLyoqXG4gICAqIEBpbnRlcm5hbCBDaOG7iSBt4bq3dCBwaOG6s25nIEzhu5JORyBkw7luZyDigJQgdGjGsCB2aeG7h24gdOG7sSB0cnV54buBbiBraGkgduG6vSBydeG7mXQgY29udGFpbmVyLlxuICAgKlxuICAgKiBOxqFpIGTDuW5nIEtIw5RORyB0cnV54buBbjogbeG6t3QgcGjhurNuZyBn4buRYyDEkeG7jWMgY8OieSB04burIHNlcnZpY2UgKMSRw6MgxJHGsGEgdsOgbyBxdWEgYGluaXQoKWApLCB0cnV54buBbiB0aMOqbVxuICAgKiDhu58gxJHDonkgbMOgIGtoYWkgaGFpIGzhuqduIGPDuW5nIG3hu5l0IHRo4bupIChuZ8aw4budaSBkw7luZyBjaOG7kXQgMjgvMDgvMjAyNikuXG4gICAqL1xuICByZWFkb25seSBub2RlID0gaW5wdXQ8VF9ncmlkTGF5b3V0X25vZGU+KCk7XG4gIC8qKiBAaW50ZXJuYWwgQ2jhu4kgbeG6t3QgcGjhurNuZyBM4buSTkcgZMO5bmcg4oCUIHRoxrAgdmnhu4duIHThu7EgdHJ1eeG7gW4uICovXG4gIHJlYWRvbmx5IGRlcHRoID0gaW5wdXQ8bnVtYmVyPigwKTtcblxuICAvKipcbiAgICog4bqobiBo4bqzbiB0aGFuaCBjw7RuZyBj4bulIG3hurdjIMSR4buLbmggKHRow6ptLXbDoG8tdHJvbmcgwrcgZ+G7mXAvdMOhY2ggwrcgeG/DoSkgY+G7p2EgTeG7jEkga2jhu5FpLlxuICAgKlxuICAgKiBEw7luZyBraGkgc+G6o24gcGjhuqltIGdvbSBjw6FjIGjDoG5oIMSR4buZbmcgxJHDsyB2w6BvIGNo4buXIGtow6FjIOKAlCB2ZCBt4buZdCBuw7p0IOKLriBu4bqxbSB0cm9uZyBjaMOtbmggbuG7mWkgZHVuZ1xuICAgKiBraOG7kWkuIOG6qG4gcuG7k2kgdGjDrCBgb3V0UmVtb3ZlTm9kZWAgwrcgYG91dEFkZEJsb2NrSW5zaWRlYCDCtyBgb3V0VG9nZ2xlVHlwZWAga2jDtG5nIGPDsm4gbmd14buTbiBwaMOhdFxuICAgKiB04burIHRoxrAgdmnhu4duOyBuxqFpIGTDuW5nIHThu7EgZ+G7jWkgYHJlbW92ZUJsb2NrYCDCtyBgYWRkQmxvY2tgIMK3IGB0b2dnbGVUeXBlYCBj4bunYSBzZXJ2aWNlLlxuICAgKi9cbiAgcmVhZG9ubHkgaGlkZGVuVG9vbGJhciA9IGlucHV0PGJvb2xlYW4sIGJvb2xlYW4gfCB1bmRlZmluZWQ+KGZhbHNlLCB7IHRyYW5zZm9ybTogKHZhbHVlKSA9PiB2YWx1ZSA/PyBmYWxzZSB9KTtcblxuICAvKipcbiAgICogVGVtcGxhdGUgdOG7sSB24bq9IHRoYW5oIGPDtG5nIGPhu6UsIHRoYXkgY2hvIGLhu5kgbsO6dCBt4bq3YyDEkeG7i25oLlxuICAgKlxuICAgKiBOaOG6rW4gY29udGV4dCBgeyAkaW1wbGljaXQ6IG5vZGUsIGlzQ29udGFpbmVyLCBjYW5BZGRJbnNpZGUsIGNhblRvZ2dsZVR5cGUgfWAgxJHhu4MgbsahaSBkw7luZyB24bq9IMSRw7puZ1xuICAgKiBuw7p0IGNobyB04burbmcga2jhu5FpLCBy4buTaSBn4buNaSBuZ8aw4bujYyBxdWEgYG91dFJlbW92ZU5vZGVgIMK3IGBvdXRBZGRCbG9ja0luc2lkZWAgwrcgYG91dFRvZ2dsZVR5cGVgXG4gICAqIGLhurFuZyBjaMOtbmggY8OhYyBow6BtIHRyb25nIGNvbnRleHQuIFRydXnhu4FuIGPhuqMgYGhpZGRlblRvb2xiYXJgIHbDoCBgdGVtcGxhdGVUb29sYmFyYCB0aMOsXG4gICAqIGBoaWRkZW5Ub29sYmFyYCB0aOG6r25nIOKAlCBraMO0bmcgduG6vSBnw6wuXG4gICAqL1xuICByZWFkb25seSB0ZW1wbGF0ZVRvb2xiYXIgPSBpbnB1dDxUZW1wbGF0ZVJlZjxUX2dyaWRMYXlvdXRfdG9vbGJhckNvbnRleHQ+IHwgdW5kZWZpbmVkPih1bmRlZmluZWQpO1xuXG4gIC8qKlxuICAgKiBC4buRIGPhu6VjIHbhu6thIMSR4buVaSBkbyBOR8av4bucSSBEw5lORyBrw6lvIGhv4bq3YyDEkeG7lWkga8OtY2ggdGjGsOG7m2Mga2jhu5FpLlxuICAgKlxuICAgKiBOxqFpIGTDuW5nIHThu7EgZ+G7jWkgYGFkZEJsb2NrYCDCtyBgcmVtb3ZlQmxvY2tgIMK3IGBjb21wYWN0YCB0aMOsIEtIw5RORyBi4bqvbiDigJQgaOG7jSB24burYSBn4buNaSB0aMOsIMSRw6MgYmnhur90LFxuICAgKiBi4bqvbiBuZ8aw4bujYyBs4bqhaSBsw6AgdGjhu6thIChuZ8aw4budaSBkw7luZyBjaOG7kXQgMjgvMDgvMjAyNikuXG4gICAqL1xuICByZWFkb25seSBvdXRDaGFuZ2UgPSBvdXRwdXQ8VF9ncmlkTGF5b3V0X2NoYW5nZUV2ZW50PigpO1xuICAvKipcbiAgICogTmfGsOG7nWkgZMO5bmcgYuG6pW0gbsO6dCBYT8OBIHRyw6puIG3hu5l0IGto4buRaS4gVGjGsCB2aeG7h24gQ0jGr0EgeG/DoSDigJQgZ+G7jWkgYGV2ZW50LmNvbmZpcm0oKWAgxJHhu4MgeG/DoSB0aOG6rXQuXG4gICAqIEPhuqduIGjhu49pIHRyxrDhu5tjIHRow6wgaOG7j2kgeG9uZyBt4bubaSBn4buNaTsga2jDtG5nIGNobyBwaMOpcCB0aMOsIMSR4burbmcgZ+G7jWkuXG4gICAqL1xuICByZWFkb25seSBvdXRSZW1vdmVOb2RlID0gb3V0cHV0PFRfZ3JpZExheW91dF9hY3Rpb25FdmVudD4oKTtcbiAgLyoqXG4gICAqIE5nxrDhu51pIGTDuW5nIGLhuqVtIG7DunQgVEjDik0gdHLDqm4gbeG7mXQgY29udGFpbmVyLiBUaMawIHZp4buHbiBLSMOUTkcgdOG7sSB0aMOqbSDigJQgbsOzIGtow7RuZyBiaeG6v3QgYuG6oW4gY8OzXG4gICAqIG5o4buvbmcgbG/huqFpIGto4buRaSBuw6BvLiBN4bufIG1lbnUgY2jhu41uIGxv4bqhaSBy4buTaSBn4buNaSBgZXZlbnQuY29uZmlybShpdGVtKWAgduG7m2kga2jhu5FpIGLhuqFuIG114buRbiB0aMOqbS5cbiAgICovXG4gIHJlYWRvbmx5IG91dEFkZEJsb2NrSW5zaWRlID0gb3V0cHV0PFRfZ3JpZExheW91dF9hZGRFdmVudD4oKTtcbiAgLyoqIE5nxrDhu51pIGTDuW5nIGLhuqVtIG7DunQgR+G7mFAvVMOBQ0guIFRoxrAgdmnhu4duIGNoxrBhIGzDoG0gZ8OsIOKAlCBn4buNaSBgZXZlbnQuY29uZmlybSgpYCDEkeG7gyB0aOG7sWMgaGnhu4duLiAqL1xuICByZWFkb25seSBvdXRUb2dnbGVUeXBlID0gb3V0cHV0PFRfZ3JpZExheW91dF9hY3Rpb25FdmVudD4oKTtcblxuICAvKiogQuG6rXQgdMOtbmggbsSDbmcgdGh1IHBow7NuZyAoem9vbSkgY2FudmFzLiBDaOG7iSDDoXAgZOG7pW5nIGNobyBjYW52YXMgZ+G7kWMgKGRlcHRoIDApLiAqL1xuICByZWFkb25seSBlbmFibGVab29tID0gaW5wdXQ8Ym9vbGVhbiwgYm9vbGVhbiB8IHVuZGVmaW5lZD4oZmFsc2UsIHsgdHJhbnNmb3JtOiAodmFsdWUpID0+IHZhbHVlID8/IGZhbHNlIH0pO1xuXG4gIC8qKiBU4bu3IGzhu4cgdGh1IHBow7NuZyBoaeG7h24gdOG6oWkgKGjhu5cgdHLhu6MgdHdvLXdheSBiaW5kaW5nIFsoem9vbSldPVwibXlab29tXCIpLiAqL1xuICByZWFkb25seSB6b29tID0gbW9kZWw8bnVtYmVyIHwgdW5kZWZpbmVkPih1bmRlZmluZWQpO1xuXG4gIC8qKiBHaeG7m2kgaOG6oW4gdGh1IHBow7NuZyB04buRaSB0aGnhu4N1LiBN4bq3YyDEkeG7i25oIDAuNCAoNDAlKS4gKi9cbiAgcmVhZG9ubHkgem9vbU1pbiA9IGlucHV0PG51bWJlcj4oMC40KTtcblxuICAvKiogR2nhu5tpIGjhuqFuIHRodSBwaMOzbmcgdOG7kWkgxJFhLiBN4bq3YyDEkeG7i25oIDEuNSAoMTUwJSkuICovXG4gIHJlYWRvbmx5IHpvb21NYXggPSBpbnB1dDxudW1iZXI+KDEuNSk7XG5cbiAgLyoqIELGsOG7m2MgbmjhuqN5IHRodSBwaMOzbmcgbeG7l2kgbOG6p24gYuG6pW0gKy8tIGhv4bq3YyBsxINuIGNodeG7mXQuIE3hurdjIMSR4buLbmggMC4wNSAoNSUpLiAqL1xuICByZWFkb25seSB6b29tU3RlcCA9IGlucHV0PG51bWJlcj4oMC4wNSk7XG5cbiAgLyoqIENoaeG7gXUgcuG7mW5nIGNodeG6qW4gY+G7p2EgY2FudmFzIHN0YWdlIHTDrW5oIGLhurFuZyBweC4gTeG6t2MgxJHhu4tuaCAxNjY4LiAqL1xuICByZWFkb25seSBzdGFnZVdpZHRoID0gaW5wdXQ8bnVtYmVyPigxNjY4KTtcblxuICAvKiogQ2hp4buBdSBjYW8gdOG7kWkgdGhp4buDdSBj4bunYSBjYW52YXMgc3RhZ2UgdMOtbmggYuG6sW5nIHB4LiBN4bq3YyDEkeG7i25oIDkzNy4gKi9cbiAgcmVhZG9ubHkgc3RhZ2VNaW5IZWlnaHQgPSBpbnB1dDxudW1iZXI+KDkzNyk7XG5cbiAgLyoqIEtow7NhIGzGsHUgdOG7tyBs4buHIHRodSBwaMOzbmcgdsOgbyBsb2NhbFN0b3JhZ2UuIE3hurdjIMSR4buLbmggJ29jYl9iaV9jYW52YXNfem9vbScuICovXG4gIHJlYWRvbmx5IHN0b3JhZ2VLZXkgPSBpbnB1dDxzdHJpbmcgfCB1bmRlZmluZWQ+KCdvY2JfYmlfY2FudmFzX3pvb20nKTtcblxuICAvKiogSGnhu4NuIHRo4buLIHRoYW5oIGRvY2sgxJFp4buBdSBraGnhu4NuIHRodSBwaMOzbmcgbuG7lWkg4bufIGfDs2MgZMaw4bubaSBwaOG6o2kuIE3hurdjIMSR4buLbmggdHJ1ZS4gKi9cbiAgcmVhZG9ubHkgc2hvd1pvb21Eb2NrID0gaW5wdXQ8Ym9vbGVhbiwgYm9vbGVhbiB8IHVuZGVmaW5lZD4odHJ1ZSwgeyB0cmFuc2Zvcm06ICh2YWx1ZSkgPT4gdmFsdWUgPz8gdHJ1ZSB9KTtcblxuICAvKiogVOG7sSDEkeG7mW5nIHbhu6thIG3DoG4gaMOsbmgga2hpIHThuqNpIHRyYW5nIGzhuqduIMSR4bqndSBu4bq/dSBraHVuZyBuaMOsbiBuaOG7jyBoxqFuIHN0YWdlV2lkdGguIE3hurdjIMSR4buLbmggdHJ1ZS4gKi9cbiAgcmVhZG9ubHkgYXV0b0ZpdE9uTG9hZCA9IGlucHV0PGJvb2xlYW4sIGJvb2xlYW4gfCB1bmRlZmluZWQ+KHRydWUsIHsgdHJhbnNmb3JtOiAodmFsdWUpID0+IHZhbHVlID8/IHRydWUgfSk7XG5cbiAgLyoqIFBow6F0IHJhIGtoaSB04bu3IGzhu4cgdGh1IHBow7NuZyB0aGF5IMSR4buVaS4gKi9cbiAgcmVhZG9ubHkgb3V0Wm9vbUNoYW5nZSA9IG91dHB1dDxudW1iZXI+KCk7XG5cbiAgLyoqIELhuq10IHTDrW5oIG7Eg25nIGvDqW8gdGjhuqMgdGjhursgdOG7qyBiw6puIG5nb8OgaSB2w6BvIGNhbnZhcyAobeG6t2MgxJHhu4tuaCB0cnVlKSAqL1xuICByZWFkb25seSBlbmFibGVFeHRlcm5hbERyb3AgPSBpbnB1dDxib29sZWFuLCBib29sZWFuIHwgdW5kZWZpbmVkPih0cnVlLCB7IHRyYW5zZm9ybTogKHZhbHVlKSA9PiB2YWx1ZSA/PyB0cnVlIH0pO1xuXG4gIC8qKiBMdcO0biBoaeG7g24gdGjhu4sgxJHGsOG7nW5nIGvhursgbMaw4bubaSAyNCBj4buZdCAqL1xuICByZWFkb25seSBzaG93R3JpZExpbmVzID0gaW5wdXQ8Ym9vbGVhbiwgYm9vbGVhbiB8IHVuZGVmaW5lZD4oZmFsc2UsIHsgdHJhbnNmb3JtOiAodmFsdWUpID0+IHZhbHVlID8/IGZhbHNlIH0pO1xuXG4gIC8qKiBNw6MgaWQgY+G7p2Ega2jhu5FpIMSRYW5nIMSRxrDhu6NjIGNo4buNbiAqL1xuICByZWFkb25seSBzZWxlY3RlZE5vZGVJZCA9IG1vZGVsPHN0cmluZyB8IG51bGwgfCB1bmRlZmluZWQ+KHVuZGVmaW5lZCk7XG5cbiAgLyoqIFBow6F0IHJhIGtoaSB0aOG6oyBt4buZdCB0aOG6uyBt4bubaSB04burIGLDqm4gbmdvw6BpIHbDoG8gY2FudmFzICovXG4gIHJlYWRvbmx5IG91dERyb3BOb2RlID0gb3V0cHV0PFRfZ3JpZExheW91dF9kcm9wRXZlbnQ+KCk7XG5cbiAgLyoqIFBow6F0IHJhIGtoaSBuZ8aw4budaSBkw7luZyBjbGljayBjaOG7jW4gbeG7mXQga2jhu5FpICovXG4gIHJlYWRvbmx5IG91dFNlbGVjdE5vZGUgPSBvdXRwdXQ8VF9ncmlkTGF5b3V0X25vZGU+KCk7XG5cbiAgLyoqIFBow6F0IHJhIGtoaSBuZ8aw4budaSBkw7luZyBi4bqlbSBuw7p0IGPhuqV1IGjDrG5oIHRyw6puIHRoYW5oIGPDtG5nIGPhu6UgY+G7p2Ega2jhu5FpICovXG4gIHJlYWRvbmx5IG91dENvbmZpZ05vZGUgPSBvdXRwdXQ8VF9ncmlkTGF5b3V0X2FjdGlvbkV2ZW50PigpO1xuXG4gIHByaXZhdGUgcmVhZG9ubHkgZ3JpZHN0ZXJSZWYgPSB2aWV3Q2hpbGQoR3JpZHN0ZXJDb21wb25lbnQpO1xuICBwcml2YXRlIHJlYWRvbmx5IHNjcm9sbEFyZWFSZWYgPSB2aWV3Q2hpbGQ8RWxlbWVudFJlZjxIVE1MRWxlbWVudD4+KCdzY3JvbGxBcmVhJyk7XG4gIHByaXZhdGUgcmVhZG9ubHkgem9vbURvY2tSZWYgPSB2aWV3Q2hpbGQ8RWxlbWVudFJlZjxIVE1MRWxlbWVudD4+KCd6b29tRG9jaycpO1xuICAvKiogbeG7l2kgw7QgbeG7mXQgY2jhu5cgZ+G6r24gcmnDqm5nIOKAlCBjw7luZyB0aOG7qSB04buxIHbhu5tpIGBjaGlsZHJlbigpYCAqL1xuICBwcml2YXRlIHJlYWRvbmx5IGl0ZW1Ib3N0cyA9IHZpZXdDaGlsZHJlbignaXRlbUhvc3QnLCB7IHJlYWQ6IFZpZXdDb250YWluZXJSZWYgfSk7XG5cbiAgLyoqIEtodW5nIHhlbSB0csaw4bubYyB24buLIHRyw60gdGjhuqMgdGjhursgdOG7qyBiw6puIG5nb8OgaSAoc25hcHBlZCBnaG9zdCBwcmV2aWV3KSAqL1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgZHJvcEdob3N0ID0gc2lnbmFsPFRfZ3JpZExheW91dF9kcm9wR2hvc3QgfCB1bmRlZmluZWQ+KHVuZGVmaW5lZCk7XG5cbiAgcHJpdmF0ZSBhY3RpdmVIb3ZlcmVkRWw/OiBIVE1MRWxlbWVudDtcbiAgcHJpdmF0ZSByb290R3JpZHN0ZXJFbD86IEhUTUxFbGVtZW50O1xuXG4gIC8qKiBNZW51IGNo4buNbiBwcmVzZXQgdGh1IHBow7NuZyDEkWFuZyBt4bufIGhheSDEkcOzbmcgKi9cbiAgcHJvdGVjdGVkIHJlYWRvbmx5IGlzTWVudU9wZW4gPSBzaWduYWw8Ym9vbGVhbj4oZmFsc2UpO1xuXG4gIC8qKiBDw6FjIG3hu5FjIHRodSBwaMOzbmcgxJHhu4tuaCBz4bq1biAqL1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgem9vbVByZXNldHM6IEFycmF5PFRfZ3JpZExheW91dF96b29tUHJlc2V0PiA9IFtcbiAgICB7IGxhYmVsOiAnaTE4bl96b29tX3ByZXNldF9vdmVydmlldycsIHZhbHVlOiAwLjUgfSxcbiAgICB7IGxhYmVsOiAnaTE4bl96b29tX3ByZXNldF9zbWFsbF9sYXB0b3AnLCB2YWx1ZTogMC42NyB9LFxuICAgIHsgbGFiZWw6ICdpMThuX3pvb21fcHJlc2V0X2xhcHRvcF8xMDgwcCcsIHZhbHVlOiAwLjc1IH0sXG4gICAgeyBsYWJlbDogJ2kxOG5fem9vbV9wcmVzZXRfc2NyZWVuXzEwODBwJywgdmFsdWU6IDAuODUgfSxcbiAgICB7IGxhYmVsOiAnaTE4bl96b29tX3ByZXNldF9zdGFuZGFyZCcsIHZhbHVlOiAwLjkgfSxcbiAgICB7IGxhYmVsOiAnaTE4bl96b29tX3ByZXNldF9vcmlnaW5hbF9zaXplJywgdmFsdWU6IDEgfSxcbiAgICB7IGxhYmVsOiAnaTE4bl96b29tX3ByZXNldF9sYXJnZV9zY3JlZW4nLCB2YWx1ZTogMS4xIH0sXG4gICAgeyBsYWJlbDogJ2kxOG5fem9vbV9wcmVzZXRfaGlnaF9kcGlfMmsnLCB2YWx1ZTogMS4yNSB9LFxuICBdO1xuXG4gIC8qKiBTw6F1IGNo4bqlbSBj4bunYSB0YXkgY+G6p20ga8OpbyDigJQgY2jhu4kgxJHhu4MgYEBmb3JgIGThu7FuZyDEkeG7pyA2IHRo4bq7LCBnacOhIHRy4buLIGtow7RuZyBkw7luZyB04bubaS4gKi9cbiAgcHJvdGVjdGVkIHJlYWRvbmx5IGRyYWdCYXJEb3RzID0gWzAsIDEsIDIsIDMsIDQsIDVdO1xuXG4gIHByaXZhdGUgcmVhZG9ubHkgc2VydmljZSA9IGluamVjdChMaWJzVWlHcmlkTGF5b3V0U2VydmljZSk7XG5cbiAgLyoqIENo4bq/IMSR4buZIHRodSBwaMOzbmcgY8OzIMSRYW5nIGhv4bqhdCDEkeG7mW5nIHRyw6puIGNhbnZhcyBuw6B5IGtow7RuZyAoY2jhu4kgcm9vdCBjYW52YXMgZGVwdGggMCkgKi9cbiAgcHJvdGVjdGVkIHJlYWRvbmx5IGlzWm9vbUFjdGl2ZSA9IGNvbXB1dGVkKCgpID0+IHtcbiAgICByZXR1cm4gdGhpcy5kZXB0aCgpID09PSAwICYmICh0aGlzLmVuYWJsZVpvb20oKSB8fCB0aGlzLnNlcnZpY2UuRnVuY3Rpb25zQ29udHJvbC5pc1pvb21FbmFibGVkKCkpO1xuICB9KTtcblxuICBwcm90ZWN0ZWQgcmVhZG9ubHkgY3VycmVudFpvb20gPSBjb21wdXRlZCgoKSA9PiB0aGlzLnNlcnZpY2UuWm9vbSgpKTtcbiAgcHJvdGVjdGVkIHJlYWRvbmx5IHpvb21QZXJjZW50ID0gY29tcHV0ZWQoKCkgPT4gTWF0aC5yb3VuZCh0aGlzLmN1cnJlbnRab29tKCkgKiAxMDApKTtcblxuICAvKipcbiAgICogTm9kZSBUSOG6rFQgY+G7p2EgbeG6t3QgcGjhurNuZyBuw6B5LlxuICAgKlxuICAgKiDwn5S0IE3hurd0IHBo4bqzbmcgR+G7kEMgKGRlcHRoIDApIMSR4buNYyBjw6J5IHThu6sgU0VSVklDRSwga2jDtG5nIGTDuW5nIGlucHV0LlxuICAgKiBOxqFpIGTDuW5nIHRoxrDhu51uZyBz4butYSBjw6J5IFThuqBJIENI4buWIChgdHJlZVNlcnZpY2UuY29tcGFjdCh0cmVlKWApIHLhu5NpIGfhu41pIGByZWZyZXNoKClgLCBuw6puIHNpZ25hbFxuICAgKiBgcm9vdCgpYCBj4bunYSBo4buNIGdp4buvIG5ndXnDqm4gdGhhbSBjaGnhur91IHbDoCBpbnB1dCBgbm9kZWAga2jDtG5nIGjhu4EgxJHhu5VpIOKAlCBgQGZvcmAga2jDtG5nIGThu7FuZyBs4bqhaVxuICAgKiBgZ3JpZHN0ZXItaXRlbWAsIGzGsOG7m2kgxJHhu6luZyBpbSBkw7kgZOG7ryBsaeG7h3UgxJHDoyBraMOhYyAoxJFvIDI4LzA4LzIwMjY6IGLhuqVtIFwiU+G6r3AgZ+G7jW5cIiBraMO0bmcgdMOhYyBk4bulbmcpLlxuICAgKiBgcmVmcmVzaCgpYCBj4bunYSBzZXJ2aWNlIHRoYXkgdGhhbSBjaGnhur91IGPDonksIG7Dqm4gxJHhu41jIHThu6sgxJHDsyBt4bubaSB0aOG6pXkgdGhheSDEkeG7lWkuXG4gICAqXG4gICAqIE3hurd0IHBo4bqzbmcgTOG7kk5HIHbhuqtuIGTDuW5nIGlucHV0OiBuw7Mgbmjhuq1uIG5vZGUgY29uIHThu6sgbeG6t3QgcGjhurNuZyBjaGEsIHbhu5FuIMSRw6MgbMOgIG9iamVjdCBt4bubaS5cbiAgICovXG4gIHByb3RlY3RlZCByZWFkb25seSBjdXJyZW50Tm9kZSA9IGNvbXB1dGVkKCgpID0+IHtcbiAgICB0aGlzLnNlcnZpY2UuVmVyc2lvbigpO1xuXG4gICAgaWYgKHRoaXMuZGVwdGgoKSA+IDApIHtcbiAgICAgIHJldHVybiB0aGlzLm5vZGUoKSA/PyBlbXB0eVJvb3ROb2RlKCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXMuc2VydmljZS5Sb290KCkgPz8gZW1wdHlSb290Tm9kZSgpO1xuICB9KTtcblxuICBwcm90ZWN0ZWQgcmVhZG9ubHkgY2hpbGRyZW4gPSBjb21wdXRlZCgoKSA9PiB0aGlzLmN1cnJlbnROb2RlKCkuY2hpbGRyZW4gPz8gW10pO1xuXG4gIC8qKlxuICAgKiBC4buRaSBj4bqjbmggY2hvIGB0ZW1wbGF0ZVRvb2xiYXJgLCBk4buxbmcgc+G6tW4gdGhlbyB04burbmcga2jhu5FpLlxuICAgKlxuICAgKiBE4buxbmcg4bufIGBjb21wdXRlZGAgY2jhu6kga2jDtG5nIGfhu41pIGjDoG0gdHLDqm4gdGVtcGxhdGU6IGfhu41pIGjDoG0gdHJvbmcgdGVtcGxhdGUgY2jhuqF5IGzhuqFpIG3hu5dpIHbDsm5nXG4gICAqIGTDsiB0aGF5IMSR4buVaSAocnVsZSBgZmUtY29kaW5nLWNvbnZlbnRpb24tdGVtcGxhdGVzYCBt4bulYyA2KS5cbiAgICovXG4gIHByb3RlY3RlZCByZWFkb25seSB0b29sYmFyQ29udGV4dHMgPSBjb21wdXRlZDxBcnJheTxUX2dyaWRMYXlvdXRfdG9vbGJhckNvbnRleHQ+PigoKSA9PlxuICAgIHRoaXMuY2hpbGRyZW4oKS5tYXAoKGl0ZW0pID0+ICh7XG4gICAgICAkaW1wbGljaXQ6IGl0ZW0sXG4gICAgICBpc0NvbnRhaW5lcjogdGhpcy5pc0NvbnRhaW5lcihpdGVtKSxcbiAgICAgIGNhbkFkZEluc2lkZTogdGhpcy5jYW5BZGRJbnNpZGUoaXRlbSksXG4gICAgICBjYW5Ub2dnbGVUeXBlOiB0aGlzLmNhblRvZ2dsZVR5cGUoaXRlbSksXG4gICAgICByZW1vdmU6ICgpID0+IHRoaXMub3V0UmVtb3ZlTm9kZS5lbWl0KHsgbm9kZUlkOiBpdGVtLmlkLCBub2RlOiBpdGVtLCBjb25maXJtOiAoKSA9PiB0aGlzLnNlcnZpY2UucmVtb3ZlQmxvY2soaXRlbS5pZCkgfSksXG4gICAgICBhZGRJbnNpZGU6ICgpID0+IHRoaXMuZW1pdEFkZEluc2lkZShpdGVtKSxcbiAgICAgIHRvZ2dsZVR5cGU6ICgpID0+IHRoaXMuZW1pdFRvZ2dsZVR5cGUoaXRlbSksXG4gICAgfSkpXG4gICk7XG5cbiAgcHJvdGVjdGVkIHJlYWRvbmx5IGlzTmVzdGVkQ2FudmFzID0gY29tcHV0ZWQoKCkgPT4gdGhpcy5kZXB0aCgpID4gMCk7XG5cbiAgLyoqIHRy4bqnbiBs4buTbmcgY29udGFpbmVyIOKAlCBraOG7kWkgxJHDoyBjaOG6oW0gdHLhuqduIHRow6wga2jDtG5nIGNobyBjaHV54buDbiB0aMOgbmggY29udGFpbmVyICovXG4gIHByb3RlY3RlZCByZWFkb25seSBtYXhDb250YWluZXJEZXB0aCA9IGNvbXB1dGVkKCgpID0+IHRoaXMuc2VydmljZS5GdW5jdGlvbnNDb250cm9sLm1heENvbnRhaW5lckRlcHRoKCkpO1xuXG4gIC8qKlxuICAgKiBM4buBIHRyb25nIGPhu6dhIGNvbnRhaW5lciwgcHguXG4gICAqXG4gICAqIPCflLQgxJDhurd0IHRyw6puIFbhu44gY29udGFpbmVyLCBraMO0bmcgxJHhurd0IHbDoG8gbMaw4bubaSBjb24uIEzGsOG7m2kgY29uIGdp4buvIG5ndXnDqm4gYG1hcmdpbjogMmAgbmjGsCBjxak7IGzhu4FcbiAgICogbsOgeSBjaOG7iSBjbyBydeG7mXQgbOG6oWkga2jhu49pIGJpw6puIHbhu48sIG5o4budIMSRw7MgdGF5IGPhuqdtIMSR4buVaSBrw61jaCB0aMaw4bubYyBj4bunYSBraOG7kWkgY29uIGx1w7RuIG7hurFtIHRyb25nIHThuqdtXG4gICAqIGNodeG7mXQgKG5nxrDhu51pIGTDuW5nIGNo4buRdCAyOC8wOC8yMDI2KS5cbiAgICovXG4gIHByb3RlY3RlZCByZWFkb25seSBjb250YWluZXJQYWRkaW5nID0gY29tcHV0ZWQoKCkgPT4gYCR7dGhpcy5zZXJ2aWNlLkZ1bmN0aW9uc0NvbnRyb2wuY29udGFpbmVyUGFkZGluZygpfXB4YCk7XG5cbiAgLyoqIEThuqNpIGvDqW8gY2jhu4kgaGnhu4duIOG7nyBjaOG6vyDEkeG7mSBz4butYSDigJQgY2jhur8gxJHhu5kgeGVtIGtow7RuZyBrw6lvIMSRxrDhu6NjIG7Dqm4gaGnhu4duIGThuqNpIGzDoCBnw6J5IG5o4bqnbS4gKi9cbiAgcHJvdGVjdGVkIHJlYWRvbmx5IGlzRWRpdE1vZGUgPSBjb21wdXRlZCgoKSA9PiB0aGlzLnNlcnZpY2UuSXNFZGl0TW9kZSgpKTtcblxuICBwcm90ZWN0ZWQgcmVhZG9ubHkgZ3JpZE9wdGlvbnMgPSBjb21wdXRlZCgoKSA9PiB7XG4gICAgLy8gxJDhu41jIGBWZXJzaW9uYCDEkeG7gyBgaW5pdCgpYCBs4bqhaSAoxJHhu5VpIGNo4bq/IMSR4buZLCBi4bqtdC904bqvdCBjaOG7k25nIGto4buRaSkgc2luaCByYSBvcHRpb25zIE3hu5pJIOKAlFxuICAgIC8vIGdyaWRzdGVyIGNo4buJIMOhcCBk4bulbmcgY+G6pXUgaMOsbmgga2hpIHRoYW0gY2hp4bq/dSBgb3B0aW9uc2AgxJHhu5VpLlxuICAgIHRoaXMuc2VydmljZS5WZXJzaW9uKCk7XG5cbiAgICByZXR1cm4gdGhpcy5zZXJ2aWNlLkZ1bmN0aW9uc0NvbnRyb2wuZ3JpZHN0ZXJPcHRpb25zKHRoaXMuZGVwdGgoKSwgKCkgPT4gdGhpcy5vdXRDaGFuZ2UuZW1pdCh7IHJvb3Q6IHRoaXMuY3VycmVudE5vZGUoKSB9KSk7XG4gIH0pO1xuXG4gIGNvbnN0cnVjdG9yKCkge1xuICAgIC8vIEfhuq9uIGNvbXBvbmVudCBj4bunYSBuxqFpIGTDuW5nIHbDoG8gdOG7q25nIMO0LCB2w6AgZ+G6r24gTOG6oEkgbeG7l2kga2hpIGPDonkgxJHhu5VpLlxuICAgIC8vIETDuW5nIGVmZmVjdCB2w6wgYGl0ZW1Ib3N0cygpYCBjaOG7iSBjw7MgZ2nDoSB0cuG7iyBzYXUga2hpIEFuZ3VsYXIgZOG7sW5nIHhvbmcgQGZvci5cbiAgICBlZmZlY3QoKCkgPT4ge1xuICAgICAgY29uc3QgaG9zdHMgPSB0aGlzLml0ZW1Ib3N0cygpO1xuICAgICAgY29uc3QgaXRlbXMgPSB0aGlzLmNoaWxkcmVuKCk7XG5cbiAgICAgIGl0ZW1zLmZvckVhY2goKGl0ZW0sIGkpID0+IHtcbiAgICAgICAgY29uc3QgaG9zdCA9IGhvc3RzW2ldO1xuXG4gICAgICAgIGlmICghaG9zdCkge1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIEto4buRaSBjw7MgY29uIGzDoCBDT05UQUlORVI6IHJ14buZdCBuw7MgZG8gbeG6t3QgcGjhurNuZyBs4buTbmcgduG6vSwga2jDtG5nIGfhuq9uIGNvbXBvbmVudCBu4buZaSBkdW5nLlxuICAgICAgICBpZiAoKGl0ZW0uY2hpbGRyZW4/Lmxlbmd0aCA/PyAwKSA+IDApIHtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnNlcnZpY2UuRnVuY3Rpb25zQ29udHJvbC5hdHRhY2hOb2RlKGl0ZW0sIHRoaXMuZGVwdGgoKSArIDEsIGhvc3QpO1xuICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICAvLyDEkOG7k25nIGLhu5kgbuG6v3UgbW9kZWwgem9vbSBiw6puIG5nb8OgaSB0aGF5IMSR4buVaVxuICAgIGVmZmVjdCgoKSA9PiB7XG4gICAgICBjb25zdCB6ID0gdGhpcy56b29tKCk7XG4gICAgICBpZiAoeiAhPT0gdW5kZWZpbmVkICYmIE1hdGguYWJzKHogLSB0aGlzLnNlcnZpY2UuWm9vbSgpKSA+IDAuMDAxKSB7XG4gICAgICAgIHRoaXMuc2VydmljZS5GdW5jdGlvbnNDb250cm9sLnNldFpvb20oeiwgdGhpcy5zdG9yYWdlS2V5KCkpO1xuICAgICAgfVxuICAgIH0pO1xuICB9XG5cbiAgbmdBZnRlclZpZXdJbml0KCk6IHZvaWQge1xuICAgIGlmICghdGhpcy5pc1pvb21BY3RpdmUoKSB8fCAhdGhpcy5hdXRvRml0T25Mb2FkKCkpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCBrZXkgPSB0aGlzLnN0b3JhZ2VLZXkoKTtcbiAgICBsZXQgaGFzU2F2ZWQgPSBmYWxzZTtcbiAgICBpZiAoa2V5ICYmIHR5cGVvZiBsb2NhbFN0b3JhZ2UgIT09ICd1bmRlZmluZWQnKSB7XG4gICAgICB0cnkge1xuICAgICAgICBoYXNTYXZlZCA9IEJvb2xlYW4obG9jYWxTdG9yYWdlLmdldEl0ZW0oa2V5KSk7XG4gICAgICB9IGNhdGNoIHtcbiAgICAgICAgLy8gaWdub3JlIGxvY2FsU3RvcmFnZSBhY2Nlc3MgZXJyb3JcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAoIWhhc1NhdmVkKSB7XG4gICAgICBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgY29uc3Qgc2Nyb2xsRWwgPSB0aGlzLnNjcm9sbEFyZWFSZWYoKT8ubmF0aXZlRWxlbWVudDtcbiAgICAgICAgaWYgKHNjcm9sbEVsICYmIHNjcm9sbEVsLmNsaWVudFdpZHRoID4gMCAmJiBzY3JvbGxFbC5jbGllbnRXaWR0aCA8IHRoaXMuc3RhZ2VXaWR0aCgpICsgNjQpIHtcbiAgICAgICAgICB0aGlzLmhhbmRsZXJGaXRTY3JlZW4oKTtcbiAgICAgICAgfVxuICAgICAgfSwgNTApO1xuICAgIH1cbiAgfVxuXG4gIG5nT25EZXN0cm95KCk6IHZvaWQge1xuICAgIHRoaXMuY2xlYW51cERyYWdHcmlkKCk7XG4gICAgZm9yIChjb25zdCBpdGVtIG9mIHRoaXMuY2hpbGRyZW4oKSkge1xuICAgICAgdGhpcy5zZXJ2aWNlLkZ1bmN0aW9uc0NvbnRyb2wuZGV0YWNoTm9kZShpdGVtLmlkKTtcbiAgICB9XG4gIH1cblxuICAvKiogVuG6vSBs4bqhaSBsxrDhu5tpIOKAlCBn4buNaSBraGkga2h1bmcgbmdvw6BpIMSR4buVaSBrw61jaCB0aMaw4bubYyBob+G6t2MgY8OieSB24burYSDEkeG7lWkgZGnhu4duIHLhu5luZy4gKi9cbiAgZ2V0IEZ1bmN0aW9uQ29udHJvbCgpIHtcbiAgICByZXR1cm4ge1xuICAgICAgdmVMYWlMdW9pOiAoKSA9PiB0aGlzLmdyaWRzdGVyUmVmKCk/Lm9wdGlvbnNDaGFuZ2VkKCksXG4gICAgICB6b29tSW46ICgpID0+IHRoaXMuaGFuZGxlclpvb21JbigpLFxuICAgICAgem9vbU91dDogKCkgPT4gdGhpcy5oYW5kbGVyWm9vbU91dCgpLFxuICAgICAgcmVzZXRab29tOiAoKSA9PiB0aGlzLmhhbmRsZXJSZXNldFpvb20oKSxcbiAgICAgIGZpdFRvU2NyZWVuOiAoKSA9PiB0aGlzLmhhbmRsZXJGaXRTY3JlZW4oKSxcbiAgICAgIHNldFpvb206ICh2YWw6IG51bWJlcikgPT4ge1xuICAgICAgICB0aGlzLnNlcnZpY2UuRnVuY3Rpb25zQ29udHJvbC5zZXRab29tKHZhbCwgdGhpcy5zdG9yYWdlS2V5KCkpO1xuICAgICAgICB0aGlzLnN5bmNab29tT3V0KCk7XG4gICAgICB9LFxuICAgIH07XG4gIH1cblxuICBwcm90ZWN0ZWQgaGFuZGxlclpvb21JbigpOiB2b2lkIHtcbiAgICB0aGlzLnNlcnZpY2UuRnVuY3Rpb25zQ29udHJvbC56b29tSW4odGhpcy56b29tU3RlcCgpLCB0aGlzLnN0b3JhZ2VLZXkoKSk7XG4gICAgdGhpcy5zeW5jWm9vbU91dCgpO1xuICB9XG5cbiAgcHJvdGVjdGVkIGhhbmRsZXJab29tT3V0KCk6IHZvaWQge1xuICAgIHRoaXMuc2VydmljZS5GdW5jdGlvbnNDb250cm9sLnpvb21PdXQodGhpcy56b29tU3RlcCgpLCB0aGlzLnN0b3JhZ2VLZXkoKSk7XG4gICAgdGhpcy5zeW5jWm9vbU91dCgpO1xuICB9XG5cbiAgcHJvdGVjdGVkIGhhbmRsZXJSZXNldFpvb20oKTogdm9pZCB7XG4gICAgdGhpcy5zZXJ2aWNlLkZ1bmN0aW9uc0NvbnRyb2wucmVzZXRab29tKHRoaXMuc3RvcmFnZUtleSgpKTtcbiAgICB0aGlzLnN5bmNab29tT3V0KCk7XG4gIH1cblxuICBwcm90ZWN0ZWQgaGFuZGxlckZpdFNjcmVlbigpOiB2b2lkIHtcbiAgICB0aGlzLmlzTWVudU9wZW4uc2V0KGZhbHNlKTtcbiAgICBjb25zdCBzY3JvbGxFbCA9IHRoaXMuc2Nyb2xsQXJlYVJlZigpPy5uYXRpdmVFbGVtZW50O1xuICAgIGNvbnN0IGNvbnRhaW5lcldpZHRoID0gc2Nyb2xsRWw/LmNsaWVudFdpZHRoIHx8ICh0eXBlb2Ygd2luZG93ICE9PSAndW5kZWZpbmVkJyA/IHdpbmRvdy5pbm5lcldpZHRoIC0gMzAwIDogMTIwMCk7XG4gICAgdGhpcy5zZXJ2aWNlLkZ1bmN0aW9uc0NvbnRyb2wuZml0VG9TY3JlZW4oY29udGFpbmVyV2lkdGgsIHRoaXMuc3RhZ2VXaWR0aCgpLCA0OCwgdGhpcy5zdG9yYWdlS2V5KCkpO1xuICAgIHRoaXMuc3luY1pvb21PdXQoKTtcbiAgfVxuXG4gIHByb3RlY3RlZCBoYW5kbGVyVG9nZ2xlTWVudSgpOiB2b2lkIHtcbiAgICB0aGlzLmlzTWVudU9wZW4udXBkYXRlKChvcGVuKSA9PiAhb3Blbik7XG4gIH1cblxuICBwcm90ZWN0ZWQgaGFuZGxlclNlbGVjdFByZXNldCh2YWx1ZTogbnVtYmVyKTogdm9pZCB7XG4gICAgdGhpcy5pc01lbnVPcGVuLnNldChmYWxzZSk7XG4gICAgdGhpcy5zZXJ2aWNlLkZ1bmN0aW9uc0NvbnRyb2wuc2V0Wm9vbSh2YWx1ZSwgdGhpcy5zdG9yYWdlS2V5KCkpO1xuICAgIHRoaXMuc3luY1pvb21PdXQoKTtcbiAgfVxuXG4gIHByb3RlY3RlZCBpc0N1cnJlbnRQcmVzZXQodmFsdWU6IG51bWJlcik6IGJvb2xlYW4ge1xuICAgIHJldHVybiBNYXRoLmFicyh0aGlzLmN1cnJlbnRab29tKCkgLSB2YWx1ZSkgPCAwLjAxO1xuICB9XG5cbiAgcHJpdmF0ZSBzeW5jWm9vbU91dCgpOiB2b2lkIHtcbiAgICBjb25zdCB2YWwgPSB0aGlzLnNlcnZpY2UuWm9vbSgpO1xuICAgIHRoaXMub3V0Wm9vbUNoYW5nZS5lbWl0KHZhbCk7XG4gICAgaWYgKHRoaXMuem9vbSgpICE9PSB2YWwpIHtcbiAgICAgIHRoaXMuem9vbS5zZXQodmFsKTtcbiAgICB9XG4gIH1cblxuICBwcm90ZWN0ZWQgaGFuZGxlcldoZWVsKGV2ZW50OiBXaGVlbEV2ZW50KTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLmlzWm9vbUFjdGl2ZSgpKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKGV2ZW50LmN0cmxLZXkgfHwgZXZlbnQubWV0YUtleSkge1xuICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgIGlmIChldmVudC5kZWx0YVkgPCAwKSB7XG4gICAgICAgIHRoaXMuaGFuZGxlclpvb21JbigpO1xuICAgICAgfSBlbHNlIGlmIChldmVudC5kZWx0YVkgPiAwKSB7XG4gICAgICAgIHRoaXMuaGFuZGxlclpvb21PdXQoKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBASG9zdExpc3RlbmVyKCdkb2N1bWVudDprZXlkb3duJywgWyckZXZlbnQnXSlcbiAgcHJvdGVjdGVkIGhhbmRsZXJEb2N1bWVudEtleURvd24oZXZlbnQ6IEtleWJvYXJkRXZlbnQpOiB2b2lkIHtcbiAgICBpZiAoIXRoaXMuaXNab29tQWN0aXZlKCkpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAoZXZlbnQuY3RybEtleSB8fCBldmVudC5tZXRhS2V5KSB7XG4gICAgICBpZiAoZXZlbnQua2V5ID09PSAnPScgfHwgZXZlbnQua2V5ID09PSAnKycpIHtcbiAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgdGhpcy5oYW5kbGVyWm9vbUluKCk7XG4gICAgICB9IGVsc2UgaWYgKGV2ZW50LmtleSA9PT0gJy0nIHx8IGV2ZW50LmtleSA9PT0gJ18nKSB7XG4gICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgIHRoaXMuaGFuZGxlclpvb21PdXQoKTtcbiAgICAgIH0gZWxzZSBpZiAoZXZlbnQua2V5ID09PSAnMCcpIHtcbiAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgdGhpcy5oYW5kbGVyUmVzZXRab29tKCk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgQEhvc3RMaXN0ZW5lcignZG9jdW1lbnQ6Y2xpY2snLCBbJyRldmVudCddKVxuICBwcm90ZWN0ZWQgaGFuZGxlckRvY3VtZW50Q2xpY2soZXZlbnQ6IE1vdXNlRXZlbnQpOiB2b2lkIHtcbiAgICBpZiAoIXRoaXMuaXNNZW51T3BlbigpKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3QgZG9ja0VsID0gdGhpcy56b29tRG9ja1JlZigpPy5uYXRpdmVFbGVtZW50O1xuICAgIGlmIChkb2NrRWwgJiYgIWRvY2tFbC5jb250YWlucyhldmVudC50YXJnZXQgYXMgTm9kZSkpIHtcbiAgICAgIHRoaXMuaXNNZW51T3Blbi5zZXQoZmFsc2UpO1xuICAgIH1cbiAgfVxuXG4gIHByb3RlY3RlZCBoYW5kbGVyVHJhY2tOb2RlKF9pbmRleDogbnVtYmVyLCBpdGVtOiBUX2dyaWRMYXlvdXRfbm9kZSk6IHN0cmluZyB7XG4gICAgcmV0dXJuIGl0ZW0uaWQ7XG4gIH1cblxuICAvKipcbiAgICog8J+UtCBDaOG6t24gYG1vdXNlZG93bmAgbuG7lWkgbMOqbiBsxrDhu5tpIENIQSBraGkgdGhhbyB0w6FjIHRyb25nIGzGsOG7m2kgY29uLlxuICAgKiBLaMO0bmcgY2jhurduIHRow6wgY+G6oyBoYWkgbMaw4bubaSBjw7luZyBuaOG6rW4gbeG7mXQgY8O6IGLhuqVtOiBrw6lvIGto4buRaSBjb24gbMOgIG5o4bqlYyBsdcO0biBjb250YWluZXIuXG4gICAqL1xuICAvKipcbiAgICogQ2jhurduIGBtb3VzZWRvd25gIGPhu6dhIGto4buRaSB0cm9uZyBsxrDhu5tpIEzhu5JORyBu4buVaSBsw6puIGzGsOG7m2kgY2hhLlxuICAgKlxuICAgKiBDaOG7iSBjaOG6t24g4bufIGzGsOG7m2kgbOG7k25nOiBsxrDhu5tpIGPhuqVwIHRyYW5nIGtow7RuZyBjw7MgY2hhIG7DoG8gxJHhu4MgY2jhurduLCB2w6AgY2jhurduIOG7nyDEkcOzIHPhur0gbnXhu5F0IGx1w7RuIHRoYW9cbiAgICogdMOhYyBj4bunYSBjaMOtbmggbsOzLlxuICAgKi9cbiAgLyoqXG4gICAqIPCflLQgQmEgaGFuZGxlciBkxrDhu5tpIMSRw6J5IFBI4bqiSSBgc3RvcFByb3BhZ2F0aW9uYC5cbiAgICogTsO6dCBu4bqxbSB0cm9uZyB2w7luZyBtYW5nIGBkcmFnSGFuZGxlQ2xhc3NgLCBraMO0bmcgY2jhurduIHRow6wgY8O6IGLhuqVtIGLhu4sgZ3JpZHN0ZXIgaGnhu4N1IGzDoCBi4bqvdCDEkeG6p3Uga8Opb1xuICAgKiB2w6AgYGRlbGF5U3RhcnQ6IDE2MGAgbnXhu5F0IGx1w7RuIGBjbGlja2Ag4oCUIG5nxrDhu51pIGTDuW5nIHRo4bqleSBuaMawIG7DunQgY2jhur90LlxuICAgKi9cbiAgcHJvdGVjdGVkIGhhbmRsZXJSZW1vdmUoZXZlbnQ6IEV2ZW50LCBub2RlOiBUX2dyaWRMYXlvdXRfbm9kZSk6IHZvaWQge1xuICAgIGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgdGhpcy5vdXRSZW1vdmVOb2RlLmVtaXQoeyBub2RlSWQ6IG5vZGUuaWQsIG5vZGUsIGNvbmZpcm06ICgpID0+IHRoaXMuc2VydmljZS5yZW1vdmVCbG9jayhub2RlLmlkKSB9KTtcbiAgfVxuXG4gIHByb3RlY3RlZCBoYW5kbGVyQWRkSW5zaWRlKGV2ZW50OiBFdmVudCwgbm9kZTogVF9ncmlkTGF5b3V0X25vZGUpOiB2b2lkIHtcbiAgICBldmVudC5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgIHRoaXMuZW1pdEFkZEluc2lkZShub2RlKTtcbiAgfVxuXG4gIHByb3RlY3RlZCBoYW5kbGVyVG9nZ2xlVHlwZShldmVudDogRXZlbnQsIG5vZGU6IFRfZ3JpZExheW91dF9ub2RlKTogdm9pZCB7XG4gICAgZXZlbnQuc3RvcFByb3BhZ2F0aW9uKCk7XG4gICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICB0aGlzLmVtaXRUb2dnbGVUeXBlKG5vZGUpO1xuICB9XG5cbiAgLyoqXG4gICAqIENo4bq3biBjw7ogYuG6pW0gdHJvbmcgdGhhbmggY8O0bmcgY+G7pSBu4buVaSBsw6puIGdyaWRzdGVyLlxuICAgKlxuICAgKiBDaOG7iSBgc3RvcFByb3BhZ2F0aW9uYCwgS0jDlE5HIGBwcmV2ZW50RGVmYXVsdGA6IG7DunQgYsOqbiB0cm9uZyB0ZW1wbGF0ZSBj4bunYSBuxqFpIGTDuW5nIHbhuqtuIGPhuqduXG4gICAqIGjDoG5oIHZpIG3hurdjIMSR4buLbmggY+G7p2EgbcOsbmggKG3hu58gZHJvcGRvd24sIGZvY3Vz4oCmKS5cbiAgICovXG4gIHByb3RlY3RlZCBoYW5kbGVyU3RvcEV2ZW50KGV2ZW50OiBFdmVudCk6IHZvaWQge1xuICAgIGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuICB9XG5cbiAgLyoqIFBow6F0IGBvdXRBZGRCbG9ja0luc2lkZWAg4oCUIGTDuW5nIGNodW5nIGNobyBuw7p0IG3hurdjIMSR4buLbmggdsOgIGB0ZW1wbGF0ZVRvb2xiYXJgLiAqL1xuICBwcml2YXRlIGVtaXRBZGRJbnNpZGUobm9kZTogVF9ncmlkTGF5b3V0X25vZGUpOiB2b2lkIHtcbiAgICB0aGlzLm91dEFkZEJsb2NrSW5zaWRlLmVtaXQoe1xuICAgICAgbm9kZUlkOiBub2RlLmlkLFxuICAgICAgbm9kZSxcbiAgICAgIGNvbmZpcm06IChpdGVtOiBUX2dyaWRMYXlvdXRfbmV3Tm9kZSkgPT4gdGhpcy5zZXJ2aWNlLmFkZEJsb2NrKGl0ZW0sIG5vZGUuaWQpLFxuICAgIH0pO1xuICB9XG5cbiAgLyoqIFBow6F0IGBvdXRUb2dnbGVUeXBlYCDigJQgZMO5bmcgY2h1bmcgY2hvIG7DunQgbeG6t2MgxJHhu4tuaCB2w6AgYHRlbXBsYXRlVG9vbGJhcmAuICovXG4gIHByaXZhdGUgZW1pdFRvZ2dsZVR5cGUobm9kZTogVF9ncmlkTGF5b3V0X25vZGUpOiB2b2lkIHtcbiAgICB0aGlzLm91dFRvZ2dsZVR5cGUuZW1pdCh7XG4gICAgICBub2RlSWQ6IG5vZGUuaWQsXG4gICAgICBub2RlLFxuICAgICAgLy8gR+G7mXAgaGF5IHTDoWNoIHN1eSByYSB04burIGNow61uaCBraOG7kWk6IMSRYW5nIGzDoCBjb250YWluZXIgdGjDrCB0w6FjaCwga2jDtG5nIHRow6wgZ+G7mXAuXG4gICAgICBjb25maXJtOiAoKSA9PiAodGhpcy5pc0NvbnRhaW5lcihub2RlKSA/IHRoaXMuc2VydmljZS50b1NpbmdsZShub2RlLmlkKSA6IHRoaXMuc2VydmljZS50b0NvbnRhaW5lcihub2RlLmlkKSksXG4gICAgfSk7XG4gIH1cblxuICAvKioga2jhu5FpIG7DoHkgY8OzIHBo4bqjaSBjb250YWluZXIga2jDtG5nIChjw7Mga2jhu5FpIGNvbikgKi9cbiAgcHJvdGVjdGVkIGlzQ29udGFpbmVyKGl0ZW06IFRfZ3JpZExheW91dF9ub2RlKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIChpdGVtLmNoaWxkcmVuPy5sZW5ndGggPz8gMCkgPiAwO1xuICB9XG5cbiAgLyoqIGNvbnRhaW5lciDEkcOjIGNo4bqhbSB0cuG6p24gbOG7k25nIHRow6wga2jDtG5nIGNobyB0aMOqbSBraOG7kWkgdsOgbyB0cm9uZyBu4buvYSAqL1xuICBwcm90ZWN0ZWQgY2FuQWRkSW5zaWRlKGl0ZW06IFRfZ3JpZExheW91dF9ub2RlKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuaXNDb250YWluZXIoaXRlbSkgJiYgdGhpcy5kZXB0aCgpIDwgdGhpcy5tYXhDb250YWluZXJEZXB0aCgpO1xuICB9XG5cbiAgLyoqIGto4buRaSDEkcahbiDhu58gY+G6pXAgY2jGsGEgY2jhuqFtIHRy4bqnbiBt4bubaSDEkcaw4bujYyBjaHV54buDbiB0aMOgbmggY29udGFpbmVyICovXG4gIHByb3RlY3RlZCBjYW5Ub2dnbGVUeXBlKGl0ZW06IFRfZ3JpZExheW91dF9ub2RlKTogYm9vbGVhbiB7XG4gICAgaWYgKHRoaXMuaXNDb250YWluZXIoaXRlbSkpIHtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cblxuICAgIHJldHVybiB0aGlzLmRlcHRoKCkgPCB0aGlzLm1heENvbnRhaW5lckRlcHRoKCk7XG4gIH1cblxuICBwcm90ZWN0ZWQgaGFuZGxlckJsb2NrUGFyZW50RHJhZyhldmVudDogRXZlbnQpOiB2b2lkIHtcbiAgICBpZiAoIXRoaXMuaXNOZXN0ZWRDYW52YXMoKSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuICB9XG5cbiAgcHJvdGVjdGVkIGhhbmRsZXJNb3VzZURvd25Ucm9uZ0x1b2koZXZlbnQ6IEV2ZW50KTogdm9pZCB7XG4gICAgaWYgKHRoaXMuZGVwdGgoKSA9PT0gMCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuICB9XG5cbiAgcHJvdGVjdGVkIGhhbmRsZXJTZWxlY3ROb2RlKG5vZGU6IFRfZ3JpZExheW91dF9ub2RlLCBldmVudD86IE1vdXNlRXZlbnQpOiB2b2lkIHtcbiAgICBpZiAoZXZlbnQpIHtcbiAgICAgIGNvbnN0IHRhcmdldCA9IGV2ZW50LnRhcmdldCBhcyBIVE1MRWxlbWVudDtcbiAgICAgIGlmICh0YXJnZXQuY2xvc2VzdCgnLmxpYnMtdWktZ3JpZC1sYXlvdXQtdG9vbGJhcicpIHx8IHRhcmdldC5jbG9zZXN0KCdidXR0b24nKSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgfVxuICAgIHRoaXMuc2VsZWN0ZWROb2RlSWQuc2V0KG5vZGUuaWQpO1xuICAgIHRoaXMub3V0U2VsZWN0Tm9kZS5lbWl0KG5vZGUpO1xuICB9XG5cbiAgcHJvdGVjdGVkIGhhbmRsZXJDb25maWcoZXZlbnQ6IEV2ZW50LCBub2RlOiBUX2dyaWRMYXlvdXRfbm9kZSk6IHZvaWQge1xuICAgIGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuICAgIGNvbnN0IGFjdGlvbkV2ZW50OiBUX2dyaWRMYXlvdXRfYWN0aW9uRXZlbnQgPSB7XG4gICAgICBub2RlSWQ6IG5vZGUuaWQsXG4gICAgICBub2RlLFxuICAgICAgY29uZmlybTogKCkgPT4gdHJ1ZSxcbiAgICB9O1xuICAgIHRoaXMub3V0Q29uZmlnTm9kZS5lbWl0KGFjdGlvbkV2ZW50KTtcbiAgfVxuXG4gIHByb3RlY3RlZCBoYW5kbGVyRHJhZ092ZXIoZXZlbnQ6IERyYWdFdmVudCk6IHZvaWQge1xuICAgIGlmICghdGhpcy5lbmFibGVFeHRlcm5hbERyb3AoKSB8fCB0aGlzLmRlcHRoKCkgPiAwKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgaWYgKGV2ZW50LmRhdGFUcmFuc2Zlcikge1xuICAgICAgZXZlbnQuZGF0YVRyYW5zZmVyLmRyb3BFZmZlY3QgPSAnY29weSc7XG4gICAgfVxuXG4gICAgY29uc3QgY29udGFpbmVyID0gdGhpcy5zY3JvbGxBcmVhUmVmKCk/Lm5hdGl2ZUVsZW1lbnQ7XG4gICAgY29uc3Qgcm9vdCA9IHRoaXMuc2VydmljZS5Sb290KCk7XG4gICAgY29uc3QgcGF5bG9hZCA9IHBhcnNlRHJvcFBheWxvYWQ8VF9ncmlkTGF5b3V0X2V4dGVybmFsRHJhZ1BheWxvYWQ+KFxuICAgICAgdGhpcy5zZXJ2aWNlLmdldERyYWdQYXlsb2FkKCkgYXMgVF9ncmlkTGF5b3V0X2V4dGVybmFsRHJhZ1BheWxvYWQgfCB1bmRlZmluZWQsXG4gICAgICBldmVudC5kYXRhVHJhbnNmZXIsXG4gICAgKTtcblxuICAgIGlmICghY29udGFpbmVyIHx8ICFyb290IHx8ICFwYXlsb2FkKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3Qgcm9vdEdyaWRzdGVyID0gY29udGFpbmVyLnF1ZXJ5U2VsZWN0b3IoJ2dyaWRzdGVyJykgYXMgSFRNTEVsZW1lbnQgfCBudWxsO1xuICAgIGlmIChyb290R3JpZHN0ZXIpIHtcbiAgICAgIGlmICghcm9vdEdyaWRzdGVyLmNsYXNzTGlzdC5jb250YWlucygnZGlzcGxheS1ncmlkJykpIHtcbiAgICAgICAgcm9vdEdyaWRzdGVyLmNsYXNzTGlzdC5hZGQoJ2Rpc3BsYXktZ3JpZCcpO1xuICAgICAgfVxuICAgICAgdGhpcy5yb290R3JpZHN0ZXJFbCA9IHJvb3RHcmlkc3RlcjtcbiAgICB9XG5cbiAgICBjb25zdCBnaG9zdCA9IGNhbGN1bGF0ZURyb3BHaG9zdChldmVudCwgY29udGFpbmVyLCByb290LCBwYXlsb2FkLCB0aGlzLnNlcnZpY2UudG90YWxDb2x1bW5zKTtcblxuICAgIGlmIChnaG9zdD8uaXNJbnNpZGVHcm91cCAmJiBnaG9zdC5ob3ZlcmVkR3JpZHN0ZXIpIHtcbiAgICAgIGlmICh0aGlzLmFjdGl2ZUhvdmVyZWRFbCAhPT0gZ2hvc3QuaG92ZXJlZEdyaWRzdGVyKSB7XG4gICAgICAgIHRoaXMuY2xlYW51cEhvdmVyZWRHcm91cCgpO1xuICAgICAgICBnaG9zdC5ob3ZlcmVkR3JpZHN0ZXIuY2xhc3NMaXN0LmFkZCgnZGlzcGxheS1ncmlkJyk7XG4gICAgICAgIHRoaXMuYWN0aXZlSG92ZXJlZEVsID0gZ2hvc3QuaG92ZXJlZEdyaWRzdGVyO1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLmNsZWFudXBIb3ZlcmVkR3JvdXAoKTtcbiAgICB9XG5cbiAgICB0aGlzLmRyb3BHaG9zdC5zZXQoZ2hvc3QpO1xuICB9XG5cbiAgcHJvdGVjdGVkIGhhbmRsZXJEcmFnTGVhdmUoZXZlbnQ6IERyYWdFdmVudCk6IHZvaWQge1xuICAgIGlmICh0aGlzLmRlcHRoKCkgPiAwKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGlmIChldmVudC5yZWxhdGVkVGFyZ2V0KSB7XG4gICAgICBjb25zdCBjb250YWluZXIgPSB0aGlzLnNjcm9sbEFyZWFSZWYoKT8ubmF0aXZlRWxlbWVudDtcbiAgICAgIGlmIChjb250YWluZXIgJiYgY29udGFpbmVyLmNvbnRhaW5zKGV2ZW50LnJlbGF0ZWRUYXJnZXQgYXMgTm9kZSkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgIH1cbiAgICB0aGlzLmRyb3BHaG9zdC5zZXQodW5kZWZpbmVkKTtcbiAgICB0aGlzLmNsZWFudXBEcmFnR3JpZCgpO1xuICB9XG5cbiAgcHJvdGVjdGVkIGhhbmRsZXJEcm9wKGV2ZW50OiBEcmFnRXZlbnQpOiB2b2lkIHtcbiAgICBpZiAoIXRoaXMuZW5hYmxlRXh0ZXJuYWxEcm9wKCkgfHwgdGhpcy5kZXB0aCgpID4gMCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgIGNvbnN0IGdob3N0ID0gdGhpcy5kcm9wR2hvc3QoKTtcbiAgICBjb25zdCBwYXlsb2FkID0gcGFyc2VEcm9wUGF5bG9hZDxUX2dyaWRMYXlvdXRfZXh0ZXJuYWxEcmFnUGF5bG9hZD4oXG4gICAgICB0aGlzLnNlcnZpY2UuZ2V0RHJhZ1BheWxvYWQoKSBhcyBUX2dyaWRMYXlvdXRfZXh0ZXJuYWxEcmFnUGF5bG9hZCB8IHVuZGVmaW5lZCxcbiAgICAgIGV2ZW50LmRhdGFUcmFuc2ZlcixcbiAgICApO1xuXG4gICAgdGhpcy5kcm9wR2hvc3Quc2V0KHVuZGVmaW5lZCk7XG4gICAgdGhpcy5jbGVhbnVwRHJhZ0dyaWQoKTtcbiAgICB0aGlzLnNlcnZpY2UuY2xlYXJEcmFnUGF5bG9hZCgpO1xuXG4gICAgaWYgKCFnaG9zdCB8fCAhcGF5bG9hZCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IHRhcmdldFBhcmVudElkID0gZ2hvc3QuaXNJbnNpZGVHcm91cCA/IGdob3N0LnRhcmdldFBhcmVudElkIDogdW5kZWZpbmVkO1xuICAgIGNvbnN0IGlzSW5zaWRlID0gQm9vbGVhbih0YXJnZXRQYXJlbnRJZCk7XG5cbiAgICBsZXQgaXRlbVRvQWRkOiBUX2dyaWRMYXlvdXRfbmV3Tm9kZTtcbiAgICBjb25zdCBwYXlsb2FkQW55ID0gcGF5bG9hZCBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbiAgICBpZiAodHlwZW9mIHBheWxvYWRBbnlbJ3Jlc29sdmVOb2RlJ10gPT09ICdmdW5jdGlvbicpIHtcbiAgICAgIGNvbnN0IHJlc29sdmVkID0gKHBheWxvYWRBbnlbJ3Jlc29sdmVOb2RlJ10gYXMgKGluc2lkZTogYm9vbGVhbikgPT4gVF9ncmlkTGF5b3V0X25ld05vZGUgfCB1bmRlZmluZWQpKGlzSW5zaWRlKTtcbiAgICAgIGl0ZW1Ub0FkZCA9IHJlc29sdmVkID8/IHtcbiAgICAgICAgY29sczogZ2hvc3QuY29scyxcbiAgICAgICAgcm93czogZ2hvc3Qucm93cyxcbiAgICAgICAgZGF0YTogcGF5bG9hZC5kYXRhID8/IChwYXlsb2FkLnR5cGUgPyB7IHR5cGU6IHBheWxvYWQudHlwZSwgdGl0bGU6IHBheWxvYWQudGl0bGUgfSA6IHVuZGVmaW5lZCksXG4gICAgICB9O1xuICAgIH0gZWxzZSB7XG4gICAgICBjb25zdCBuZXdOb2RlRGF0YSA9IHBheWxvYWQuZGF0YSA/PyAocGF5bG9hZC50eXBlID8geyB0eXBlOiBwYXlsb2FkLnR5cGUsIHRpdGxlOiBwYXlsb2FkLnRpdGxlIH0gOiB1bmRlZmluZWQpO1xuICAgICAgaXRlbVRvQWRkID0ge1xuICAgICAgICBjb2xzOiBnaG9zdC5jb2xzLFxuICAgICAgICByb3dzOiBnaG9zdC5yb3dzLFxuICAgICAgICBkYXRhOiBuZXdOb2RlRGF0YSxcbiAgICAgIH07XG4gICAgfVxuXG4gICAgY29uc3QgYWRkZWROb2RlID0gdGhpcy5zZXJ2aWNlLmluc2VydEJsb2NrV2l0aENvbGxpc2lvbihcbiAgICAgIGl0ZW1Ub0FkZCxcbiAgICAgIGdob3N0LmNvbCxcbiAgICAgIGdob3N0LnJvdyxcbiAgICAgIHRhcmdldFBhcmVudElkLFxuICAgICk7XG5cbiAgICBpZiAoYWRkZWROb2RlKSB7XG4gICAgICB0aGlzLnNlbGVjdGVkTm9kZUlkLnNldChhZGRlZE5vZGUuaWQpO1xuICAgICAgdGhpcy5vdXREcm9wTm9kZS5lbWl0KHtcbiAgICAgICAgbm9kZTogYWRkZWROb2RlLFxuICAgICAgICBwYXJlbnRJZDogdGFyZ2V0UGFyZW50SWQsXG4gICAgICAgIGNvbDogZ2hvc3QuY29sLFxuICAgICAgICByb3c6IGdob3N0LnJvdyxcbiAgICAgICAgY29sczogZ2hvc3QuY29scyxcbiAgICAgICAgcm93czogZ2hvc3Qucm93cyxcbiAgICAgICAgcmF3RXZlbnQ6IGV2ZW50LFxuICAgICAgICBwYXlsb2FkLFxuICAgICAgfSk7XG4gICAgICBjb25zdCByb290ID0gdGhpcy5zZXJ2aWNlLlJvb3QoKTtcbiAgICAgIGlmIChyb290KSB7XG4gICAgICAgIHRoaXMub3V0Q2hhbmdlLmVtaXQoe1xuICAgICAgICAgIHJvb3QsXG4gICAgICAgICAgbm9kZUlkOiBhZGRlZE5vZGUuaWQsXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgY2xlYW51cEhvdmVyZWRHcm91cCgpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5hY3RpdmVIb3ZlcmVkRWwpIHtcbiAgICAgIHRoaXMuYWN0aXZlSG92ZXJlZEVsLmNsYXNzTGlzdC5yZW1vdmUoJ2Rpc3BsYXktZ3JpZCcpO1xuICAgICAgdGhpcy5hY3RpdmVIb3ZlcmVkRWwgPSB1bmRlZmluZWQ7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBjbGVhbnVwRHJhZ0dyaWQoKTogdm9pZCB7XG4gICAgdGhpcy5jbGVhbnVwSG92ZXJlZEdyb3VwKCk7XG4gICAgaWYgKHRoaXMucm9vdEdyaWRzdGVyRWwgJiYgIXRoaXMuc2hvd0dyaWRMaW5lcygpKSB7XG4gICAgICB0aGlzLnJvb3RHcmlkc3RlckVsLmNsYXNzTGlzdC5yZW1vdmUoJ2Rpc3BsYXktZ3JpZCcpO1xuICAgICAgdGhpcy5yb290R3JpZHN0ZXJFbCA9IHVuZGVmaW5lZDtcbiAgICB9XG4gICAgY29uc3QgY29udGFpbmVyID0gdGhpcy5zY3JvbGxBcmVhUmVmKCk/Lm5hdGl2ZUVsZW1lbnQ7XG4gICAgaWYgKGNvbnRhaW5lciAmJiAhdGhpcy5zaG93R3JpZExpbmVzKCkpIHtcbiAgICAgIGNvbnRhaW5lci5xdWVyeVNlbGVjdG9yQWxsKCdncmlkc3Rlci5kaXNwbGF5LWdyaWQnKS5mb3JFYWNoKChlbCkgPT4ge1xuICAgICAgICBlbC5jbGFzc0xpc3QucmVtb3ZlKCdkaXNwbGF5LWdyaWQnKTtcbiAgICAgIH0pO1xuICAgIH1cbiAgfVxufVxuIiwiQGlmIChpc1pvb21BY3RpdmUoKSkge1xuICA8IS0tIEtodSB24buxYyBjdeG7mW4gY2jhu6lhIGNhbnZhcyBzdGFnZSB0aHUgcGjDs25nIC0tPlxuICA8ZGl2XG4gICAgI3Njcm9sbEFyZWFcbiAgICBjbGFzcz1cImxpYnMtdWktZ3JpZC1sYXlvdXQtc2Nyb2xsLWFyZWEgcmVsYXRpdmUgaC1mdWxsIG1pbi1oLTAgdy1mdWxsIG1pbi13LTAgb3ZlcmZsb3ctYXV0byBwLTYgZmxleCBqdXN0aWZ5LWNlbnRlciBpdGVtcy1zdGFydFwiXG4gICAgKG1vdXNlZG93bik9XCJoYW5kbGVyTW91c2VEb3duVHJvbmdMdW9pKCRldmVudClcIlxuICAgICh3aGVlbCk9XCJoYW5kbGVyV2hlZWwoJGV2ZW50KVwiXG4gICAgKGRyYWdvdmVyKT1cImhhbmRsZXJEcmFnT3ZlcigkZXZlbnQpXCJcbiAgICAoZHJhZ2xlYXZlKT1cImhhbmRsZXJEcmFnTGVhdmUoJGV2ZW50KVwiXG4gICAgKGRyb3ApPVwiaGFuZGxlckRyb3AoJGV2ZW50KVwiPlxuICAgIDxkaXZcbiAgICAgICNjYW52YXNTdGFnZVxuICAgICAgaWQ9XCJiaS1jYW52YXMtc3RhZ2VcIlxuICAgICAgY2xhc3M9XCJsaWJzLXVpLWdyaWQtbGF5b3V0LXN0YWdlIHJlbGF0aXZlIGZsZXggZmxleC1jb2wgdHJhbnNpdGlvbi1bem9vbV0gZHVyYXRpb24tMTUwIG9yaWdpbi10b3Agc2hyaW5rLTAgYmctd2hpdGUvODAgYm9yZGVyIGJvcmRlci1zbGF0ZS0yMDAvODAgcm91bmRlZC0yeGwgc2hhZG93LXNtIHAtNFwiXG4gICAgICBbc3R5bGUuem9vbV09XCJjdXJyZW50Wm9vbSgpXCJcbiAgICAgIFtzdHlsZS53aWR0aC5weF09XCJzdGFnZVdpZHRoKClcIlxuICAgICAgW3N0eWxlLm1pbi13aWR0aC5weF09XCJzdGFnZVdpZHRoKClcIlxuICAgICAgW3N0eWxlLm1pbi1oZWlnaHQucHhdPVwic3RhZ2VNaW5IZWlnaHQoKVwiPlxuICAgICAgPCEtLSBTbmFwcGVkIERyb3AgR2hvc3QgUHJldmlldyAtLT5cbiAgICAgIEBpZiAoZHJvcEdob3N0KCk7IGFzIGdob3N0KSB7XG4gICAgICAgIDxkaXZcbiAgICAgICAgICBjbGFzcz1cInBvaW50ZXItZXZlbnRzLW5vbmUgYWJzb2x1dGUgei0zMCBmbGV4IGZsZXgtY29sIGl0ZW1zLWNlbnRlciBqdXN0aWZ5LWNlbnRlciBvdmVyZmxvdy1oaWRkZW4gcm91bmRlZC1sZyBib3JkZXItMiBib3JkZXItZGFzaGVkIGJvcmRlci1ibHVlLTUwMCBiZy1ibHVlLTUwMC8xNSBwLTEgc2hhZG93LXNtIHRyYW5zaXRpb24tYWxsIGR1cmF0aW9uLTc1IGVhc2Utb3V0IGJhY2tkcm9wLWJsdXItWzAuNXB4XSBzZWxlY3Qtbm9uZVwiXG4gICAgICAgICAgW3N0eWxlLmxlZnQucHhdPVwiZ2hvc3QucGl4ZWxMZWZ0XCJcbiAgICAgICAgICBbc3R5bGUudG9wLnB4XT1cImdob3N0LnBpeGVsVG9wXCJcbiAgICAgICAgICBbc3R5bGUud2lkdGgucHhdPVwiZ2hvc3QucGl4ZWxXaWR0aFwiXG4gICAgICAgICAgW3N0eWxlLmhlaWdodC5weF09XCJnaG9zdC5waXhlbEhlaWdodFwiPlxuICAgICAgICAgIDxkaXYgY2xhc3M9XCJpbmxpbmUtZmxleCBtYXgtdy1bOTUlXSBpdGVtcy1jZW50ZXIgZ2FwLTEgdHJ1bmNhdGUgcm91bmRlZC1tZCBiZy1ibHVlLTYwMCBweC0yIHB5LTAuNSB0ZXh0LVsxMXB4XSBmb250LXNlbWlib2xkIHRleHQtd2hpdGUgc2hhZG93LXhzXCI+XG4gICAgICAgICAgICBAaWYgKGdob3N0LmNhcmRJY29uQ2xhc3MpIHtcbiAgICAgICAgICAgICAgPGkgW2NsYXNzXT1cImdob3N0LmNhcmRJY29uQ2xhc3MgKyAnIHRleHQteHMnXCI+PC9pPlxuICAgICAgICAgICAgfSBAZWxzZSBpZiAoZ2hvc3QuY2FyZEljb25UZXh0KSB7XG4gICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwidGV4dC1bMTBweF0gZm9udC1ib2xkXCI+e3sgZ2hvc3QuY2FyZEljb25UZXh0IH19PC9zcGFuPlxuICAgICAgICAgICAgfSBAZWxzZSB7XG4gICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwidGV4dC14cyBmb250LWJvbGRcIj57eyBnaG9zdC5pc0luc2lkZUdyb3VwID8gJ+KGsycgOiAnKycgfX08L3NwYW4+XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICA8c3BhbiBjbGFzcz1cInRydW5jYXRlXCI+e3sgZ2hvc3QuY2FyZFRpdGxlIH19PC9zcGFuPlxuICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJ0ZXh0LVs5cHhdIGZvbnQtbW9ubyBvcGFjaXR5LTc1XCI+KHt7IGdob3N0LmNvbHMgfX1jKTwvc3Bhbj5cbiAgICAgICAgICA8L2Rpdj5cblxuICAgICAgICAgIEBpZiAoZ2hvc3QucGl4ZWxIZWlnaHQgPj0gODApIHtcbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJtdC0xIGZsZXggbWF4LXctWzk1JV0gaXRlbXMtY2VudGVyIGdhcC0xLjUgdHJ1bmNhdGUgcm91bmRlZCBib3JkZXIgYm9yZGVyLWJsdWUtMTAwIGJnLXdoaXRlLzk1IHB4LTIgcHktMC41IHRleHQtWzEwcHhdIGZvbnQtbWVkaXVtIHRleHQtYmx1ZS03MDAgc2hhZG93LXhzXCI+XG4gICAgICAgICAgICAgIEBpZiAoZ2hvc3QuaXNJbnNpZGVHcm91cCkge1xuICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwidHJ1bmNhdGUgZm9udC1ib2xkIHRleHQtYmx1ZS05MDBcIj7ihrMge3sgZ2hvc3QuZ3JvdXBUaXRsZSB9fTwvc3Bhbj5cbiAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cInRleHQtYmx1ZS0zMDBcIj7igKI8L3NwYW4+XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgPHNwYW4+Q+G7mXQge3sgZ2hvc3QuY29sICsgMSB9fS17eyBnaG9zdC5jb2wgKyBnaG9zdC5jb2xzIH19PC9zcGFuPlxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgfVxuICAgICAgICA8L2Rpdj5cbiAgICAgIH1cbiAgICAgIDxncmlkc3RlciBjbGFzcz1cImgtZnVsbCB3LWZ1bGxcIiBbY2xhc3MuZGlzcGxheS1ncmlkXT1cInNob3dHcmlkTGluZXMoKVwiIFtvcHRpb25zXT1cImdyaWRPcHRpb25zKClcIj5cbiAgICAgICAgICBAZm9yIChpdGVtIG9mIGNoaWxkcmVuKCk7IHRyYWNrIGl0ZW0uaWQ7IGxldCBpdGVtSW5kZXggPSAkaW5kZXgpIHtcbiAgICA8IS0tIPCflLQgQ2jhurduIGBtb3VzZWRvd25gIHThuqFpIMSQw4JZIGNobyBsxrDhu5tpIGzhu5NuZyDigJQgQ+G6pE0gYuG7jyB2w6AgQ+G6pE0gY2h1eeG7g24gc2FuZyBjaOG7lyBraMOhYy5cbiAgICAgICAgIGBpZ25vcmVDb250ZW50Q2xhc3NgIG3hu5l0IG3DrG5oIEtIw5RORyDEkeG7pzogYGRlbGF5U3RhcnQ6IDE2MGAgbMOgbSBN4buWSSBsxrDhu5tpIGzDqm4gbOG7i2NoXG4gICAgICAgICBgZHJhZ1N0YXJ0YCBi4bqxbmcgYHNldFRpbWVvdXRgIG5nYXkgdOG6oWkgYG1vdXNlZG93bmAsIGPDsm4gYHN0b3BQcm9wYWdhdGlvbmAgbcOgIGxpYiBn4buNaSBiw6puXG4gICAgICAgICB0cm9uZyBgZHJhZ1N0YXJ0YCBjaOG6oXkgc2F1IDE2MG1zIG7Dqm4gcXXDoSBtdeG7mW4g4oCUIGzGsOG7m2kgQ0hBIMSRw6Mga+G7i3Agbmjhuq1uICjEkW8gMjgvMDgvMjAyNjoga8Opb1xuICAgICAgICAgZOG6o2kga2jhu5FpIGNvbiwgY2h14buXaSBjbGFzcyBkdXnhu4d0IGzDqm4gxJDDmk5HIG3DoCBjb250YWluZXIgduG6q24gbmjhuqN5IDAsMCDihpIgMCwxKS5cbiAgICAgICAgIEfhuq9uIOG7nyBgZ3JpZHN0ZXItaXRlbWAgbMOgIMSRw7puZyBiacOqbjogbMaw4bubaSBjb24gbmdoZSB0csOqbiBjaMOtbmggcGjhuqduIHThu60gbsOgeSBuw6puIMSRw6Mgbmjhuq1uIHhvbmcsXG4gICAgICAgICBsxrDhu5tpIGNoYSDhu58gbmdvw6BpIGLhu4sgY2jhurduLiAtLT5cbiAgICA8Z3JpZHN0ZXItaXRlbVxuICAgICAgW2l0ZW1dPVwiaXRlbVwiXG4gICAgICBbY2xhc3MubGlicy11aS1ncmlkLWxheW91dC1zZWxlY3RlZF09XCJzZWxlY3RlZE5vZGVJZCgpID09PSBpdGVtLmlkXCJcbiAgICAgIChjbGljayk9XCJoYW5kbGVyU2VsZWN0Tm9kZShpdGVtLCAkZXZlbnQpXCJcbiAgICAgIChtb3VzZWRvd24pPVwiaGFuZGxlckJsb2NrUGFyZW50RHJhZygkZXZlbnQpXCI+XG4gICAgICA8IS0tIPCflLQgVuG7jyBuw6B5IG1hbmcgYGRyYWdIYW5kbGVDbGFzc2Ag4oCUIEPhuqRNIGLhu48uXG4gICAgICAgICAgIGBpZ25vcmVDb250ZW50OiB0cnVlYCBi4bqvdCBncmlkc3RlciBDSOG7iCBjaG8ga8OpbyBraGkgY2jhu5cgYuG6pW0gbuG6sW0gZMaw4bubaSBt4buZdCBwaOG6p24gdOG7rSBjw7NcbiAgICAgICAgICAgYGRyYWdIYW5kbGVDbGFzc2AuIEtow7RuZyBjw7MgduG7jyBuw6B5IHRow6wgY29tcG9uZW50IGPhu6dhIG7GoWkgZMO5bmcgKHRoxrAgdmnhu4duIGtow7RuZyBraeG7g20gc2/DoXRcbiAgICAgICAgICAgxJHGsOG7o2MgY2xhc3MgY+G7p2EgbsOzKSBz4bq9IGtow7RuZyBjw7MgdGF5IGPhuqdtIG7DoG8sIHbDoCBLSMOUTkcga2jhu5FpIG7DoG8ga8OpbyDEkcaw4bujYyDigJQgxJFvIDI4LzA4LzIwMjY6XG4gICAgICAgICAgIGvDqW8gMzIwcHgsIHRv4bqhIMSR4buZIGto4buRaSBnaeG7ryBuZ3V5w6puIHg9Myx5PTAuXG4gICAgICAgICAgIFTDqm4gY2xhc3MgdGhlbyBj4bqlcDogbMaw4bubaSB0cmFuZyB2w6AgbMaw4bubaSBs4buTbmcgZMO5bmcgaGFpIHTDqm4gS0jDgUMgbmhhdSwgbuG6v3Uga2jDtG5nIGzGsOG7m2kgY2hhXG4gICAgICAgICAgIGPFqW5nIG5o4bqtbiByYSB0YXkgY+G6p20gY+G7p2Ega2jhu5FpIGNvbiB2w6AgbmjhuqVjIGx1w7RuIGNvbnRhaW5lci4gLS0+XG4gICAgICA8IS0tIPCflLQgVuG7jyBLSMOUTkcgbWFuZyBgZHJhZ0hhbmRsZUNsYXNzYCDigJQgQ+G6pE0gdGjDqm0gbOG6oWkuXG4gICAgICAgICAgIEvDqW8gY2jhu4kgxJHGsOG7o2MgcGjDqXAgYuG6r3QgxJHhuqd1IHThu6sgROG6okkgWEFOSCAobmfGsOG7nWkgZMO5bmcgY2jhu5F0IDI4LzA4LzIwMjY6IFwicGjhuqNpIGhvdmVyIHbDoG8gdsO5bmdcbiAgICAgICAgICAgbcOgdSB4YW5oIHRow6wgbeG7m2kga8OpbyB0aOG6oyDEkcaw4bujYyBjaG8gxJHhu5NuZyBuaOG6pXRcIikuIENobyBj4bqjIHbhu48gbMOgbSB0YXkgY+G6p20gdGjDrCBi4bqlbSDEkcOidSBjxaluZ1xuICAgICAgICAgICBrw6lvLCB2w6Aga2jhu5FpIGNvbiBu4bqxbSB0cm9uZyBjb250YWluZXIgc+G6vSBuaOG6pWMgbHXDtG4gY29udGFpbmVyIHbDrCBsxrDhu5tpIGNoYSBkdXnhu4d0IGzDqm4gZ+G6t3BcbiAgICAgICAgICAgdGF5IGPhuqdtIGPhu6dhIHbhu48gY29udGFpbmVyIHRyxrDhu5tjLlxuICAgICAgICAgICBW4buPIGto4buRaSBjb24gduG6q24gZ2nhu68gY2xhc3MgQ0jhurZOIMSR4buDIGzGsOG7m2kgY2hhIGThu6tuZyDEkcO6bmcg4bufIGJpw6puLiAtLT5cbiAgICAgIDxkaXZcbiAgICAgICAgY2xhc3M9XCJsaWJzLXVpLWdyaWQtbGF5b3V0LWJsb2NrLXNoZWxsIGdyb3VwIHJlbGF0aXZlIGgtZnVsbCB3LWZ1bGwgbWluLXctMFwiXG4gICAgICAgIFtjbGFzcy5saWJzLXVpLWdyaWQtbGF5b3V0LWJsb2NrLXBhcmVudC1kcmFnXT1cImlzTmVzdGVkQ2FudmFzKClcIj5cbiAgICAgICAgPCEtLSBE4bqjaSBrw6lvOiBoaeG7h24ga2hpIHLDqiBjaHXhu5l0IHbDoG8ga2jhu5FpLCBiYSBjaOG6pW0gbMOgIGThuqV1IGhp4buHdSBrw6lvIHF1ZW4gdGh14buZYy5cbiAgICAgICAgICAgICBOZ8aw4budaSBkw7luZyBj4bqnbiBt4buZdCBjaOG7lyBiw6FtIFLDlSBSw4BORyB0aGF5IHbDrCDEkW/DoW4geGVtIGLhuqVtIMSRw6J1IHRow6wga8OpbyDEkcaw4bujY1xuICAgICAgICAgICAgIChjaOG7kXQgMjgvMDgvMjAyNiwgdGhlbyDEkcO6bmcgZOG6o2kgxJFhbmcgZMO5bmcg4bufIG3DoG4gQ3VzdG9tZXIgMzYwIGPhu6dhIG1vYmlvLXdlYikuIC0tPlxuICAgICAgICBAaWYgKGlzRWRpdE1vZGUoKSkge1xuICAgICAgICAgIDwhLS0g8J+UtCBE4bqjaSBQSOG6okkgbWFuZyB0YXkgY+G6p20gxJDDmk5HIEPhuqRQIGPhu6dhIG7Dsy4gROG6o2kgbmjhuq1uIGNodeG7mXQgKGBwb2ludGVyLWV2ZW50czogYXV0b2ApLFxuICAgICAgICAgICAgICAgbsOqbiBu4bq/dSBraMO0bmcgbWFuZyB0YXkgY+G6p20gdGjDrCBgY2hlY2tEcmFnSGFuZGxlQ2xhc3NgIGR1eeG7h3QgbMOqbiBn4bq3cCB0YXkgY+G6p20gY+G7p2FcbiAgICAgICAgICAgICAgIGNvbnRhaW5lciB2w6AgbmjhuqVjIGNvbnRhaW5lciB0aGF5IHbDrCBraOG7kWkgY29uICjEkW8gMjgvMDgvMjAyNjoga8OpbyBk4bqjaSBraOG7kWkgY29uLFxuICAgICAgICAgICAgICAgY29udGFpbmVyIG5o4bqjeSAwLDAg4oaSIDAsMSBjw7JuIGto4buRaSBjb24gxJHhu6luZyBpbSkuXG4gICAgICAgICAgICAgICDwn5S0IEThuqNpIENI4buIIG1hbmcgdGF5IGPhuqdtLCBD4bqkTSBtYW5nIHRow6ptIGNsYXNzIGNo4bq3bjogYGNoZWNrRHJhZ0hhbmRsZUNsYXNzYCB4w6l0IGhhaVxuICAgICAgICAgICAgICAgY2xhc3MgxJHDsyB0csOqbiBDw5lORyBt4buZdCBub2RlIG7Dqm4gxJHhu4MgY2h1bmcgbMOgIGvDqW8gaOG7j25nICjEkW8gMjgvMDgvMjAyNjogYuG6pW0gZOG6o2kga2jhu5FpXG4gICAgICAgICAgICAgICBjb24ga8OpbyAxNDBweCwga2jhu5FpIMSR4bupbmcgaW0pLiBWaeG7h2MgY2jhurduIGzGsOG7m2kgY2hhIGRvIFbhu44gS0jhu5BJIGxvLiAtLT5cbiAgICAgICAgICA8ZGl2XG4gICAgICAgICAgICBjbGFzcz1cImxpYnMtdWktZ3JpZC1sYXlvdXQtZHJhZy1iYXJcIlxuICAgICAgICAgICAgW2NsYXNzLmxpYnMtdWktZ3JpZC1sYXlvdXQtZHJhZy1iYXItY2hpbGRdPVwiaXNOZXN0ZWRDYW52YXMoKVwiXG4gICAgICAgICAgICBbY2xhc3MubGlicy11aS1ncmlkLWxheW91dC1kcmFnLWhhbmRsZV09XCIhaXNOZXN0ZWRDYW52YXMoKVwiXG4gICAgICAgICAgICBbY2xhc3MubGlicy11aS1ncmlkLWxheW91dC1kcmFnLWhhbmRsZS1jaGlsZF09XCJpc05lc3RlZENhbnZhcygpXCI+XG4gICAgICAgICAgICA8c3BhbiBjbGFzcz1cImxpYnMtdWktZ3JpZC1sYXlvdXQtZHJhZy1iYXItZG90c1wiPlxuICAgICAgICAgICAgICBAZm9yIChkb3Qgb2YgZHJhZ0JhckRvdHM7IHRyYWNrIGRvdCkge1xuICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwibGlicy11aS1ncmlkLWxheW91dC1kcmFnLWJhci1kb3RcIj48L3NwYW4+XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIDwvc3Bhbj5cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgfVxuXG4gICAgICAgIDwhLS0gS2h1bmcgY2jhu6lhIGNvbXBvbmVudCBj4bunYSBuxqFpIGTDuW5nLlxuICAgICAgICAgICAgIPCflLQgUEjhuqJJIGPDsyBraHVuZyB0aOG6rXQgKGtow7RuZyBwaOG6o2kgYG5nLWNvbnRhaW5lcmAgdHLhu5FuZyk6IG7DsyBsbyBo4buZIG7GoWkgZMO5bmcgcGjhuqduIGzhuqVwIMSR4bqneVxuICAgICAgICAgICAgIMO0IHbDoCB2aeG7gW4gYsOhbyBjaOG6vyDEkeG7mSBz4butYS4gS2jDtG5nIGPDsyBraHVuZyB0aMOsIG3hu5dpIGNvbXBvbmVudCBu4buZaSBkdW5nIGzhuqFpIHBo4bqjaSB04buxIHZp4bq/dFxuICAgICAgICAgICAgIGA6aG9zdCB7IHdpZHRoL2hlaWdodDogMTAwJSB9YCArIHZp4buBbiDEkeG7qXQg4oCUIMSRw7MgbMOgIHZp4buHYyBj4bunYSB0aMawIHZp4buHbiwga2jDtG5nIHBo4bqjaSBj4bunYVxuICAgICAgICAgICAgIG5nxrDhu51pIGTDuW5nIChuZ8aw4budaSBkw7luZyBjaOG7kXQgMjgvMDgvMjAyNikuXG4gICAgICAgICAgICAgTeG7l2kga2jhu5FpIG3hu5l0IFZpZXdDb250YWluZXJSZWYgcmnDqm5nIG7Dqm4gY29tcG9uZW50IG7hurFtIMSRw7puZyDDtCBj4bunYSBuw7MuIC0tPlxuICAgICAgICA8ZGl2XG4gICAgICAgICAgY2xhc3M9XCJsaWJzLXVpLWdyaWQtbGF5b3V0LWNvbnRlbnQtZnJhbWVcIlxuICAgICAgICAgIFtjbGFzcy5saWJzLXVpLWdyaWQtbGF5b3V0LWNvbnRlbnQtZnJhbWUtZWRpdF09XCJpc0VkaXRNb2RlKCkgJiYgIWlzQ29udGFpbmVyKGl0ZW0pXCJcbiAgICAgICAgICBbY2xhc3MubGlicy11aS1ncmlkLWxheW91dC1jb250ZW50LWZyYW1lLWVtcHR5XT1cImlzQ29udGFpbmVyKGl0ZW0pXCI+XG4gICAgICAgICAgPG5nLWNvbnRhaW5lciAjaXRlbUhvc3QgLz5cbiAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgPCEtLSBE4bqldSBoaeG7h3UgQ09OVEFJTkVSOiBuaMOjbiBnw7NjIHRyw6puLXBo4bqjaSArIHZp4buBbiDEkeG7qXQgYmFvIHJ14buZdC4gS2jDtG5nIGPDsyBk4bqldSBoaeG7h3UgdGjDrFxuICAgICAgICAgICAgIG5nxrDhu51pIGTDuW5nIGtow7RuZyBiaeG6v3Qga2jhu5FpIG7DoG8gY2jhu6lhIMSRxrDhu6NjIGto4buRaSBraMOhYyAoY2jhu5F0IDI4LzA4LzIwMjYsIHRoZW8gxJHDum5nIGPDoWNoXG4gICAgICAgICAgICAgbcOgbiBDdXN0b21lciAzNjAgY+G7p2EgbW9iaW8td2ViIMSRYW5nIGzDoG0pLiAtLT5cbiAgICAgICAgQGlmIChpc0VkaXRNb2RlKCkgJiYgaXNDb250YWluZXIoaXRlbSkpIHtcbiAgICAgICAgICA8ZGl2IGNsYXNzPVwibGlicy11aS1ncmlkLWxheW91dC1jb250YWluZXItbGFiZWxcIj57eyAnaTE4bl9jb250YWluZXJfYmxvY2snIHwgdHJhbnNsYXRlIH19PC9kaXY+XG4gICAgICAgICAgPGRpdiBjbGFzcz1cImxpYnMtdWktZ3JpZC1sYXlvdXQtY29udGFpbmVyLWJvcmRlclwiPjwvZGl2PlxuICAgICAgICB9XG5cbiAgICAgICAgPCEtLSBUaGFuaCBjw7RuZyBj4bulOiBoaeG7h24ga2hpIHLDqiBjaHXhu5l0IHbDoG8ga2jhu5FpLlxuICAgICAgICAgICAgIPCflLQgRMO5bmcgYGxpYnNfdWktY29tcG9uZW50cy1idXR0b25zLWJ1dHRvbmAg4oCUIEPhuqRNIHThu7EgZOG7sW5nIHRo4bq7IGA8YnV0dG9uPmAuXG4gICAgICAgICAgICAgQ29tcG9uZW50IG7DoHkgxJHDoyBjw7Mgc+G6tW4ga2nhu4N1IG7DunQsIGPhu6EgbsO6dCB2w6AgYm9uZyBiw7NuZyBjaMO6IHRow61jaCB0aGVvIMSRw7puZyBi4buZIGdpYW8gZGnhu4duXG4gICAgICAgICAgICAgY+G7p2Egc+G6o24gcGjhuqltOyB04buxIGThu7FuZyBsw6AgbeG7l2kgbsahaSBt4buZdCBraeG7g3UgdsOgIG3huqV0IGx1w7RuIHRvb2x0aXAuIC0tPlxuICAgICAgICBAaWYgKGlzRWRpdE1vZGUoKSAmJiAhaGlkZGVuVG9vbGJhcigpKSB7XG4gICAgICAgICAgQGlmICh0ZW1wbGF0ZVRvb2xiYXIoKSkge1xuICAgICAgICAgICAgPCEtLSBOxqFpIGTDuW5nIHThu7EgduG6vSB0aGFuaCBjw7RuZyBj4bulOiBuaOG6rW4ga2jhu5FpICsgY8OhYyBow6BtIHBow6F0IGV2ZW50IHF1YSBjb250ZXh0LlxuXG4gICAgICAgICAgICAgICAgIPCflLQgS2jhu5FpIGLhu41jIHThu7EgY2jhurduIGBtb3VzZWRvd25gL2BjbGlja2AgbuG7lWkgbMOqbiBncmlkc3Rlci4gVGhhbmggY8O0bmcgY+G7pSBu4bqxbSB0cm9uZ1xuICAgICAgICAgICAgICAgICB2w7luZyBtYW5nIGBkcmFnSGFuZGxlQ2xhc3NgOyBraMO0bmcgY2jhurduIHRow6wgY8O6IGLhuqVtIGLhu4sgaGnhu4N1IGzDoCBi4bqvdCDEkeG6p3Uga8OpbyB2w6BcbiAgICAgICAgICAgICAgICAgYGRlbGF5U3RhcnQ6IDE2MGAgbnXhu5F0IGx1w7RuIGBjbGlja2Ag4oCUIG7DunQgdHJvbmcgdGVtcGxhdGUgbmdvw6BpIGLhuqVtIGtow7RuZyDEg25cbiAgICAgICAgICAgICAgICAgKMSRbyAwOS8wOS8yMDI2OiBi4bqlbSBi4bqxbmcgYC5jbGljaygpYCBj4bunYSBET00gdGjDrCBt4bufLCBi4bqlbSBjaHXhu5l0IHRo4bqtdCB0aMOsIGtow7RuZykuXG4gICAgICAgICAgICAgICAgIENo4bq3biDhu58gxJDDglkgxJHhu4MgbsahaSBkw7luZyBraMO0bmcgcGjhuqNpIGJp4bq/dCBi4bqreSBuw6B5LiAtLT5cbiAgICAgICAgICAgIDxkaXZcbiAgICAgICAgICAgICAgY2xhc3M9XCJsaWJzLXVpLWdyaWQtbGF5b3V0LXRvb2xiYXJcIlxuICAgICAgICAgICAgICByb2xlPVwidG9vbGJhclwiXG4gICAgICAgICAgICAgIHRhYmluZGV4PVwiMFwiXG4gICAgICAgICAgICAgIFtjbGFzcy5saWJzLXVpLWdyaWQtbGF5b3V0LXRvb2xiYXItY2hpbGRdPVwiaXNOZXN0ZWRDYW52YXMoKVwiXG4gICAgICAgICAgICAgIChtb3VzZWRvd24pPVwiaGFuZGxlclN0b3BFdmVudCgkZXZlbnQpXCJcbiAgICAgICAgICAgICAgKGtleWRvd24pPVwiaGFuZGxlclN0b3BFdmVudCgkZXZlbnQpXCJcbiAgICAgICAgICAgICAgKGNsaWNrKT1cImhhbmRsZXJTdG9wRXZlbnQoJGV2ZW50KVwiPlxuICAgICAgICAgICAgICA8bmctY29udGFpbmVyXG4gICAgICAgICAgICAgICAgKm5nVGVtcGxhdGVPdXRsZXQ9XCJ0ZW1wbGF0ZVRvb2xiYXIoKSE7IGNvbnRleHQ6IHRvb2xiYXJDb250ZXh0cygpW2l0ZW1JbmRleF1cIiAvPlxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgfSBAZWxzZSB7XG4gICAgICAgICAgICA8ZGl2XG4gICAgICAgICAgICAgIGNsYXNzPVwibGlicy11aS1ncmlkLWxheW91dC10b29sYmFyXCJcbiAgICAgICAgICAgICAgW2NsYXNzLmxpYnMtdWktZ3JpZC1sYXlvdXQtdG9vbGJhci1jaGlsZF09XCJpc05lc3RlZENhbnZhcygpXCI+XG4gICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwibGlicy11aS1ncmlkLWxheW91dC1kaW0tYmFkZ2VcIj5cbiAgICAgICAgICAgICAgICB7eyBpdGVtLnJvd3MgfX0gaMOgbmcgw5cge3sgaXRlbS5jb2xzIH19IGPhu5l0XG4gICAgICAgICAgICAgIDwvc3Bhbj5cbiAgICAgICAgICAgICAgQGlmIChjYW5BZGRJbnNpZGUoaXRlbSkpIHtcbiAgICAgICAgICAgICAgICA8bGlic191aS1jb21wb25lbnRzLWJ1dHRvbnMtYnV0dG9uXG4gICAgICAgICAgICAgICAgICBbdHlwZV09XCInYnV0dG9uLXRoaXJkJ1wiXG4gICAgICAgICAgICAgICAgICBbaWNvbk9ubHlUeXBlXT1cInRydWVcIlxuICAgICAgICAgICAgICAgICAgW3NpemVCdXR0b25dPVwiJ3NtYWxsZXInXCJcbiAgICAgICAgICAgICAgICAgIFtjbGFzc0ljb25MZWZ0XT1cIidsaWJzLXVpLWljb24tYWRkJ1wiXG4gICAgICAgICAgICAgICAgICBbcG9wb3Zlcl09XCJ7IGNvbmZpZzogeyBjb250ZW50OiAnVGjDqm0ga2jhu5FpIHbDoG8gdHJvbmcnLCB6SW5kZXg6IDEzMDAgfSB9XCJcbiAgICAgICAgICAgICAgICAgIChvdXRDbGljayk9XCJoYW5kbGVyQWRkSW5zaWRlKCRldmVudCwgaXRlbSlcIiAvPlxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIEBpZiAoY2FuVG9nZ2xlVHlwZShpdGVtKSkge1xuICAgICAgICAgICAgICAgIDxsaWJzX3VpLWNvbXBvbmVudHMtYnV0dG9ucy1idXR0b25cbiAgICAgICAgICAgICAgICAgIFt0eXBlXT1cIididXR0b24tdGhpcmQnXCJcbiAgICAgICAgICAgICAgICAgIFtpY29uT25seVR5cGVdPVwidHJ1ZVwiXG4gICAgICAgICAgICAgICAgICBbc2l6ZUJ1dHRvbl09XCInc21hbGxlcidcIlxuICAgICAgICAgICAgICAgICAgW2NsYXNzSWNvbkxlZnRdPVwiaXNDb250YWluZXIoaXRlbSkgPyAnbGlicy11aS1pY29uLXNwbGl0LWNlbGwnIDogJ2xpYnMtdWktaWNvbi1tZXJnZS1jZWxsJ1wiXG4gICAgICAgICAgICAgICAgICBbcG9wb3Zlcl09XCJ7IGNvbmZpZzogeyBjb250ZW50OiBpc0NvbnRhaW5lcihpdGVtKSA/ICfEkMawYSB24buBIGto4buRaSDEkcahbicgOiAnQ2h1eeG7g24gdGjDoG5oIGto4buRaSBnaMOpcCcsIHpJbmRleDogMTMwMCB9IH1cIlxuICAgICAgICAgICAgICAgICAgKG91dENsaWNrKT1cImhhbmRsZXJUb2dnbGVUeXBlKCRldmVudCwgaXRlbSlcIiAvPlxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIDxsaWJzX3VpLWNvbXBvbmVudHMtYnV0dG9ucy1idXR0b25cbiAgICAgICAgICAgICAgICBbdHlwZV09XCInYnV0dG9uLXRoaXJkJ1wiXG4gICAgICAgICAgICAgICAgW2ljb25Pbmx5VHlwZV09XCJ0cnVlXCJcbiAgICAgICAgICAgICAgICBbc2l6ZUJ1dHRvbl09XCInc21hbGxlcidcIlxuICAgICAgICAgICAgICAgIFtjbGFzc0ljb25MZWZ0XT1cIidsaWJzLXVpLWljb24tc2V0dGluZydcIlxuICAgICAgICAgICAgICAgIFtwb3BvdmVyXT1cInsgY29uZmlnOiB7IGNvbnRlbnQ6ICdD4bqldSBow6xuaCB0aOG6uycsIHpJbmRleDogMTMwMCB9IH1cIlxuICAgICAgICAgICAgICAgIChvdXRDbGljayk9XCJoYW5kbGVyQ29uZmlnKCRldmVudCwgaXRlbSlcIiAvPlxuICAgICAgICAgICAgICA8bGlic191aS1jb21wb25lbnRzLWJ1dHRvbnMtYnV0dG9uXG4gICAgICAgICAgICAgICAgW3R5cGVdPVwiJ2J1dHRvbi10aGlyZC1ob3Zlci1kYW5nZXInXCJcbiAgICAgICAgICAgICAgICBbaWNvbk9ubHlUeXBlXT1cInRydWVcIlxuICAgICAgICAgICAgICAgIFtzaXplQnV0dG9uXT1cIidzbWFsbGVyJ1wiXG4gICAgICAgICAgICAgICAgW2NsYXNzSWNvbkxlZnRdPVwiJ2xpYnMtdWktaWNvbi1yZW1vdmUnXCJcbiAgICAgICAgICAgICAgICBbcG9wb3Zlcl09XCJ7IGNvbmZpZzogeyBjb250ZW50OiBpc0NvbnRhaW5lcihpdGVtKSA/ICdYb8OhIGPhuqMga2jhu5FpIGdow6lwJyA6ICdYb8OhIGto4buRaScsIHpJbmRleDogMTMwMCB9IH1cIlxuICAgICAgICAgICAgICAgIChvdXRDbGljayk9XCJoYW5kbGVyUmVtb3ZlKCRldmVudCwgaXRlbSlcIiAvPlxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgQGlmIChpdGVtLmNoaWxkcmVuICYmIGl0ZW0uY2hpbGRyZW4ubGVuZ3RoID4gMCkge1xuICAgICAgICAgIDwhLS0gS2jhu5FpIGPDsyBjb24g4oaSIHJ14buZdCBuw7MgbOG6oWkgbMOgIG3hu5l0IG3hurd0IHBo4bqzbmcgbuG7r2EuIMSQ4buHIHF1eSDhu58gxJHDonksIG7GoWkgZMO5bmcga2jDtG5nIHBo4bqjaSBsby5cbiAgICAgICAgICAgICAgIEzhu4EgxJHhurd0IOG7nyDEkMOCWSAoduG7jyBjb250YWluZXIpLCBraMO0bmcgxJHhurd0IHbDoG8gbMaw4bubaSBjb24g4oCUIGzGsOG7m2kgY29uIGdp4buvIG5ndXnDqm4ga2hlIDJweC4gLS0+XG4gICAgICAgICAgPGxpYnNfdWktc2VydmljZXMtZ3JpZF9sYXlvdXQtY2FudmFzXG4gICAgICAgICAgICBjbGFzcz1cImJsb2NrIGgtZnVsbCB3LWZ1bGxcIlxuICAgICAgICAgICAgW3N0eWxlLnBhZGRpbmddPVwiY29udGFpbmVyUGFkZGluZygpXCJcbiAgICAgICAgICAgIFtub2RlXT1cIml0ZW1cIlxuICAgICAgICAgICAgW2RlcHRoXT1cImRlcHRoKCkgKyAxXCJcbiAgICAgICAgICAgIFtoaWRkZW5Ub29sYmFyXT1cImhpZGRlblRvb2xiYXIoKVwiXG4gICAgICAgICAgICBbdGVtcGxhdGVUb29sYmFyXT1cInRlbXBsYXRlVG9vbGJhcigpXCJcbiAgICAgICAgICAgIFtzZWxlY3RlZE5vZGVJZF09XCJzZWxlY3RlZE5vZGVJZCgpXCJcbiAgICAgICAgICAgIChvdXRTZWxlY3ROb2RlKT1cIm91dFNlbGVjdE5vZGUuZW1pdCgkZXZlbnQpXCJcbiAgICAgICAgICAgIChvdXRDb25maWdOb2RlKT1cIm91dENvbmZpZ05vZGUuZW1pdCgkZXZlbnQpXCJcbiAgICAgICAgICAgIChvdXRDaGFuZ2UpPVwib3V0Q2hhbmdlLmVtaXQoJGV2ZW50KVwiXG4gICAgICAgICAgICAob3V0UmVtb3ZlTm9kZSk9XCJvdXRSZW1vdmVOb2RlLmVtaXQoJGV2ZW50KVwiXG4gICAgICAgICAgICAob3V0QWRkQmxvY2tJbnNpZGUpPVwib3V0QWRkQmxvY2tJbnNpZGUuZW1pdCgkZXZlbnQpXCJcbiAgICAgICAgICAgIChvdXRUb2dnbGVUeXBlKT1cIm91dFRvZ2dsZVR5cGUuZW1pdCgkZXZlbnQpXCIgLz5cbiAgICAgICAgfVxuICAgICAgPC9kaXY+XG4gICAgPC9ncmlkc3Rlci1pdGVtPlxuICB9XG4gICAgICA8L2dyaWRzdGVyPlxuICAgIDwvZGl2PlxuICA8L2Rpdj5cblxuICA8IS0tIFRoYW5oIGRvY2sgxJFp4buBdSBraGnhu4NuIHRodSBwaMOzbmcgbuG7lWkg4bufIGfDs2MgZMaw4bubaSBwaOG6o2kgLS0+XG4gIEBpZiAoc2hvd1pvb21Eb2NrKCkpIHtcbiAgICA8ZGl2XG4gICAgICAjem9vbURvY2tcbiAgICAgIGlkPVwiY2FudmFzLXpvb20tZG9ja1wiXG4gICAgICByb2xlPVwidG9vbGJhclwiXG4gICAgICB0YWJpbmRleD1cIjBcIlxuICAgICAgY2xhc3M9XCJhYnNvbHV0ZSBib3R0b20tNCByaWdodC02IHotMzAgZmxleCBpdGVtcy1jZW50ZXIgYmctd2hpdGUvOTUgYmFja2Ryb3AtYmx1ci1tZCByb3VuZGVkLWZ1bGwgc2hhZG93LWxnIGJvcmRlciBib3JkZXItc2xhdGUtMzAwLzgwIHAtMSBzcGFjZS14LTEgc2VsZWN0LW5vbmVcIlxuICAgICAgKG1vdXNlZG93bik9XCIkZXZlbnQuc3RvcFByb3BhZ2F0aW9uKClcIlxuICAgICAgKGtleWRvd24pPVwiJGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpXCJcbiAgICAgIChjbGljayk9XCIkZXZlbnQuc3RvcFByb3BhZ2F0aW9uKClcIj5cbiAgICAgIDwhLS0gVGh1IG5o4buPICgtKSAtLT5cbiAgICAgIDxidXR0b25cbiAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgIGNsYXNzPVwidy03IGgtNyBmbGV4IGl0ZW1zLWNlbnRlciBqdXN0aWZ5LWNlbnRlciByb3VuZGVkLWZ1bGwgdGV4dC1zbGF0ZS02MDAgaG92ZXI6dGV4dC1zbGF0ZS05MDAgaG92ZXI6Ymctc2xhdGUtMTAwIGRpc2FibGVkOm9wYWNpdHktMzAgZGlzYWJsZWQ6aG92ZXI6YmctdHJhbnNwYXJlbnQgdHJhbnNpdGlvbi1jb2xvcnMgY3Vyc29yLXBvaW50ZXJcIlxuICAgICAgICBbZGlzYWJsZWRdPVwiY3VycmVudFpvb20oKSA8PSB6b29tTWluKClcIlxuICAgICAgICBbdGl0bGVdPVwiJ2kxOG5fem9vbV9vdXQnIHwgdHJhbnNsYXRlXCJcbiAgICAgICAgKGNsaWNrKT1cImhhbmRsZXJab29tT3V0KClcIj5cbiAgICAgICAgPHN2ZyBjbGFzcz1cInctMy41IGgtMy41XCIgdmlld0JveD1cIjAgMCAyNCAyNFwiIGZpbGw9XCJub25lXCIgc3Ryb2tlPVwiY3VycmVudENvbG9yXCIgc3Ryb2tlLXdpZHRoPVwiMi41XCIgc3Ryb2tlLWxpbmVjYXA9XCJyb3VuZFwiPjxsaW5lIHgxPVwiNVwiIHkxPVwiMTJcIiB4Mj1cIjE5XCIgeTI9XCIxMlwiLz48L3N2Zz5cbiAgICAgIDwvYnV0dG9uPlxuXG4gICAgICA8IS0tIFThu7cgbOG7hyAlIHbDoCBtZW51IHByZXNldCAtLT5cbiAgICAgIDxkaXYgY2xhc3M9XCJyZWxhdGl2ZVwiPlxuICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgY2xhc3M9XCJoLTcgcHgtMiBmbGV4IGl0ZW1zLWNlbnRlciBnYXAtMSByb3VuZGVkLWZ1bGwgdGV4dC14cyBmb250LXNlbWlib2xkIHRleHQtc2xhdGUtNzAwIGhvdmVyOmJnLXNsYXRlLTEwMCB0cmFuc2l0aW9uLWNvbG9ycyBjdXJzb3ItcG9pbnRlclwiXG4gICAgICAgICAgW3RpdGxlXT1cIidpMThuX3pvb21fb3B0aW9ucycgfCB0cmFuc2xhdGVcIlxuICAgICAgICAgIChjbGljayk9XCJoYW5kbGVyVG9nZ2xlTWVudSgpXCI+XG4gICAgICAgICAgPHNwYW4+e3sgem9vbVBlcmNlbnQoKSB9fSU8L3NwYW4+XG4gICAgICAgICAgPHN2ZyBjbGFzcz1cInctMyBoLTMgdGV4dC1zbGF0ZS00MDAgdHJhbnNpdGlvbi10cmFuc2Zvcm0gZHVyYXRpb24tMTUwXCIgW2NsYXNzLnJvdGF0ZS0xODBdPVwiaXNNZW51T3BlbigpXCIgdmlld0JveD1cIjAgMCAyNCAyNFwiIGZpbGw9XCJub25lXCIgc3Ryb2tlPVwiY3VycmVudENvbG9yXCIgc3Ryb2tlLXdpZHRoPVwiMi41XCIgc3Ryb2tlLWxpbmVjYXA9XCJyb3VuZFwiIHN0cm9rZS1saW5lam9pbj1cInJvdW5kXCI+PHBvbHlsaW5lIHBvaW50cz1cIjYgOSAxMiAxNSAxOCA5XCIvPjwvc3ZnPlxuICAgICAgICA8L2J1dHRvbj5cblxuICAgICAgICA8IS0tIE1lbnUgZHJvcGRvd24gY8OhYyBt4buRYyB0aHUgcGjDs25nIC0tPlxuICAgICAgICBAaWYgKGlzTWVudU9wZW4oKSkge1xuICAgICAgICAgIDxkaXYgY2xhc3M9XCJhYnNvbHV0ZSBib3R0b20tZnVsbCBtYi0yIHJpZ2h0LTAgdy02NCBiZy13aGl0ZSByb3VuZGVkLXhsIHNoYWRvdy14bCBib3JkZXIgYm9yZGVyLXNsYXRlLTIwMCBweS0xLjUgei00MCB0ZXh0LXhzIHNlbGVjdC1ub25lXCI+XG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwicHgtMyBweS0xIHRleHQtWzExcHhdIGZvbnQtc2VtaWJvbGQgdGV4dC1zbGF0ZS00MDAgdXBwZXJjYXNlIHRyYWNraW5nLXdpZGVyXCI+XG4gICAgICAgICAgICAgIHt7ICdpMThuX3pvb21fY2FudmFzX3dpZHRoJyB8IHRyYW5zbGF0ZTogeyB3aWR0aDogc3RhZ2VXaWR0aCgpIH0gfX1cbiAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgPGJ1dHRvblxuICAgICAgICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgICAgICAgY2xhc3M9XCJ3LWZ1bGwgcHgtMyBweS0yIHRleHQtbGVmdCBmbGV4IGl0ZW1zLWNlbnRlciBqdXN0aWZ5LWJldHdlZW4gaG92ZXI6Ymctc2xhdGUtNTAgdHJhbnNpdGlvbi1jb2xvcnMgY3Vyc29yLXBvaW50ZXJcIlxuICAgICAgICAgICAgICAoY2xpY2spPVwiaGFuZGxlckZpdFNjcmVlbigpXCI+XG4gICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwiZmxleCBpdGVtcy1jZW50ZXIgZ2FwLTIgdGV4dC1zbGF0ZS03MDAgZm9udC1tZWRpdW1cIj5cbiAgICAgICAgICAgICAgICA8c3ZnIGNsYXNzPVwidy0zLjUgaC0zLjUgdGV4dC1zbGF0ZS01MDBcIiB2aWV3Qm94PVwiMCAwIDI0IDI0XCIgZmlsbD1cIm5vbmVcIiBzdHJva2U9XCJjdXJyZW50Q29sb3JcIiBzdHJva2Utd2lkdGg9XCIyXCI+PHBvbHlsaW5lIHBvaW50cz1cIjE1IDMgMjEgMyAyMSA5XCIvPjxwb2x5bGluZSBwb2ludHM9XCI5IDIxIDMgMjEgMyAxNVwiLz48bGluZSB4MT1cIjIxXCIgeTE9XCIzXCIgeDI9XCIxNFwiIHkyPVwiMTBcIi8+PGxpbmUgeDE9XCIzXCIgeTE9XCIyMVwiIHgyPVwiMTBcIiB5Mj1cIjE0XCIvPjwvc3ZnPlxuICAgICAgICAgICAgICAgIHt7ICdpMThuX3pvb21fZml0X3NjcmVlbicgfCB0cmFuc2xhdGUgfX1cbiAgICAgICAgICAgICAgPC9zcGFuPlxuICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cInRleHQtWzEwcHhdIGJnLWJsdWUtNTAgdGV4dC1ibHVlLTYwMCBweC0xLjUgcHktMC41IHJvdW5kZWQgZm9udC1tZWRpdW1cIj57eyAnaTE4bl9hdXRvJyB8IHRyYW5zbGF0ZSB9fTwvc3Bhbj5cbiAgICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICAgICAgPGRpdiBjbGFzcz1cImgtcHggYmctc2xhdGUtMTAwIG15LTFcIj48L2Rpdj5cbiAgICAgICAgICAgIEBmb3IgKHByZXNldCBvZiB6b29tUHJlc2V0czsgdHJhY2sgcHJlc2V0LnZhbHVlKSB7XG4gICAgICAgICAgICAgIDxidXR0b25cbiAgICAgICAgICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgICAgICAgICBjbGFzcz1cInctZnVsbCBweC0zIHB5LTEuNSB0ZXh0LWxlZnQgZmxleCBpdGVtcy1jZW50ZXIganVzdGlmeS1iZXR3ZWVuIGhvdmVyOmJnLXNsYXRlLTUwIHRyYW5zaXRpb24tY29sb3JzIGN1cnNvci1wb2ludGVyXCJcbiAgICAgICAgICAgICAgICBbY2xhc3MudGV4dC1ibHVlLTYwMF09XCJpc0N1cnJlbnRQcmVzZXQocHJlc2V0LnZhbHVlKVwiXG4gICAgICAgICAgICAgICAgW2NsYXNzLmZvbnQtc2VtaWJvbGRdPVwiaXNDdXJyZW50UHJlc2V0KHByZXNldC52YWx1ZSlcIlxuICAgICAgICAgICAgICAgIFtjbGFzcy5iZy1ibHVlLTUwXT1cImlzQ3VycmVudFByZXNldChwcmVzZXQudmFsdWUpXCJcbiAgICAgICAgICAgICAgICAoY2xpY2spPVwiaGFuZGxlclNlbGVjdFByZXNldChwcmVzZXQudmFsdWUpXCI+XG4gICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJ0ZXh0LXNsYXRlLTcwMFwiIFtjbGFzcy50ZXh0LWJsdWUtNjAwXT1cImlzQ3VycmVudFByZXNldChwcmVzZXQudmFsdWUpXCI+XG4gICAgICAgICAgICAgICAgICB7eyBwcmVzZXQubGFiZWwgfCB0cmFuc2xhdGUgfX1cbiAgICAgICAgICAgICAgICA8L3NwYW4+XG4gICAgICAgICAgICAgICAgQGlmIChpc0N1cnJlbnRQcmVzZXQocHJlc2V0LnZhbHVlKSkge1xuICAgICAgICAgICAgICAgICAgPHN2ZyBjbGFzcz1cInctMy41IGgtMy41IHRleHQtYmx1ZS02MDBcIiB2aWV3Qm94PVwiMCAwIDI0IDI0XCIgZmlsbD1cIm5vbmVcIiBzdHJva2U9XCJjdXJyZW50Q29sb3JcIiBzdHJva2Utd2lkdGg9XCIyLjVcIiBzdHJva2UtbGluZWNhcD1cInJvdW5kXCIgc3Ryb2tlLWxpbmVqb2luPVwicm91bmRcIj48cG9seWxpbmUgcG9pbnRzPVwiMjAgNiA5IDE3IDQgMTJcIi8+PC9zdmc+XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgICAgIH1cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgfVxuICAgICAgPC9kaXY+XG5cbiAgICAgIDwhLS0gUGjDs25nIHRvICgrKSAtLT5cbiAgICAgIDxidXR0b25cbiAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgIGNsYXNzPVwidy03IGgtNyBmbGV4IGl0ZW1zLWNlbnRlciBqdXN0aWZ5LWNlbnRlciByb3VuZGVkLWZ1bGwgdGV4dC1zbGF0ZS02MDAgaG92ZXI6dGV4dC1zbGF0ZS05MDAgaG92ZXI6Ymctc2xhdGUtMTAwIGRpc2FibGVkOm9wYWNpdHktMzAgZGlzYWJsZWQ6aG92ZXI6YmctdHJhbnNwYXJlbnQgdHJhbnNpdGlvbi1jb2xvcnMgY3Vyc29yLXBvaW50ZXJcIlxuICAgICAgICBbZGlzYWJsZWRdPVwiY3VycmVudFpvb20oKSA+PSB6b29tTWF4KClcIlxuICAgICAgICBbdGl0bGVdPVwiJ2kxOG5fem9vbV9pbicgfCB0cmFuc2xhdGVcIlxuICAgICAgICAoY2xpY2spPVwiaGFuZGxlclpvb21JbigpXCI+XG4gICAgICAgIDxzdmcgY2xhc3M9XCJ3LTMuNSBoLTMuNVwiIHZpZXdCb3g9XCIwIDAgMjQgMjRcIiBmaWxsPVwibm9uZVwiIHN0cm9rZT1cImN1cnJlbnRDb2xvclwiIHN0cm9rZS13aWR0aD1cIjIuNVwiIHN0cm9rZS1saW5lY2FwPVwicm91bmRcIj48bGluZSB4MT1cIjEyXCIgeTE9XCI1XCIgeDI9XCIxMlwiIHkyPVwiMTlcIi8+PGxpbmUgeDE9XCI1XCIgeTE9XCIxMlwiIHgyPVwiMTlcIiB5Mj1cIjEyXCIvPjwvc3ZnPlxuICAgICAgPC9idXR0b24+XG5cbiAgICAgIDwhLS0gUGjDom4gY8OhY2ggLS0+XG4gICAgICA8ZGl2IGNsYXNzPVwiaC00IHctcHggYmctc2xhdGUtMjAwXCI+PC9kaXY+XG5cbiAgICAgIDwhLS0gTsO6dCBW4burYSBtw6BuIGjDrG5oIG5oYW5oIC0tPlxuICAgICAgPGJ1dHRvblxuICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgY2xhc3M9XCJoLTcgcHgtMi41IGZsZXggaXRlbXMtY2VudGVyIGdhcC0xIHJvdW5kZWQtZnVsbCB0ZXh0LXhzIHRleHQtc2xhdGUtNjAwIGhvdmVyOnRleHQtc2xhdGUtOTAwIGhvdmVyOmJnLXNsYXRlLTEwMCB0cmFuc2l0aW9uLWNvbG9ycyBjdXJzb3ItcG9pbnRlclwiXG4gICAgICAgIFt0aXRsZV09XCInaTE4bl96b29tX2ZpdF9zY3JlZW5fdG9vbHRpcCcgfCB0cmFuc2xhdGVcIlxuICAgICAgICAoY2xpY2spPVwiaGFuZGxlckZpdFNjcmVlbigpXCI+XG4gICAgICAgIDxzdmcgY2xhc3M9XCJ3LTMuNSBoLTMuNVwiIHZpZXdCb3g9XCIwIDAgMjQgMjRcIiBmaWxsPVwibm9uZVwiIHN0cm9rZT1cImN1cnJlbnRDb2xvclwiIHN0cm9rZS13aWR0aD1cIjJcIj48cG9seWxpbmUgcG9pbnRzPVwiMTUgMyAyMSAzIDIxIDlcIi8+PHBvbHlsaW5lIHBvaW50cz1cIjkgMjEgMyAyMSAzIDE1XCIvPjxsaW5lIHgxPVwiMjFcIiB5MT1cIjNcIiB4Mj1cIjE0XCIgeTI9XCIxMFwiLz48bGluZSB4MT1cIjNcIiB5MT1cIjIxXCIgeDI9XCIxMFwiIHkyPVwiMTRcIi8+PC9zdmc+XG4gICAgICAgIDxzcGFuIGNsYXNzPVwiZm9udC1tZWRpdW1cIj57eyAnaTE4bl96b29tX2ZpdF9zY3JlZW4nIHwgdHJhbnNsYXRlIH19PC9zcGFuPlxuICAgICAgPC9idXR0b24+XG5cbiAgICAgIDwhLS0gTsO6dCDEkOG6t3QgbOG6oWkgMTAwJSAoY2jhu4kgaGnhu4duIGtoaSBraMOhYyAxMDAlKSAtLT5cbiAgICAgIEBpZiAoem9vbVBlcmNlbnQoKSAhPT0gMTAwKSB7XG4gICAgICAgIDxidXR0b25cbiAgICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgICBjbGFzcz1cImgtNyBweC0yIGZsZXggaXRlbXMtY2VudGVyIGdhcC0xIHJvdW5kZWQtZnVsbCB0ZXh0LXhzIGZvbnQtc2VtaWJvbGQgdGV4dC1ibHVlLTYwMCBob3ZlcjpiZy1ibHVlLTUwIHRyYW5zaXRpb24tY29sb3JzIGN1cnNvci1wb2ludGVyXCJcbiAgICAgICAgICBbdGl0bGVdPVwiJ2kxOG5fem9vbV9yZXNldF90b29sdGlwJyB8IHRyYW5zbGF0ZTogeyB3aWR0aDogc3RhZ2VXaWR0aCgpLCBoZWlnaHQ6IHN0YWdlTWluSGVpZ2h0KCkgfVwiXG4gICAgICAgICAgKGNsaWNrKT1cImhhbmRsZXJSZXNldFpvb20oKVwiPlxuICAgICAgICAgIDxzdmcgY2xhc3M9XCJ3LTMgaC0zXCIgdmlld0JveD1cIjAgMCAyNCAyNFwiIGZpbGw9XCJub25lXCIgc3Ryb2tlPVwiY3VycmVudENvbG9yXCIgc3Ryb2tlLXdpZHRoPVwiMlwiIHN0cm9rZS1saW5lY2FwPVwicm91bmRcIiBzdHJva2UtbGluZWpvaW49XCJyb3VuZFwiPjxwb2x5bGluZSBwb2ludHM9XCIxIDQgMSAxMCA3IDEwXCIvPjxwYXRoIGQ9XCJNMy41MSAxNWE5IDkgMCAxIDAgMi4xMy05LjM2TDEgMTBcIi8+PC9zdmc+XG4gICAgICAgICAgPHNwYW4+MTAwJTwvc3Bhbj5cbiAgICAgICAgPC9idXR0b24+XG4gICAgICB9XG4gICAgPC9kaXY+XG4gIH1cbn0gQGVsc2Uge1xuICA8IS0tIPCflLQgYHJlbGF0aXZlYCBsw6AgQuG6rlQgQlXhu5hDLCBD4bqkTSBi4buPLlxuICAgICAgIGdyaWRzdGVyIMSR4buVaSB24buLIHRyw60gY2h14buZdCB0aMOgbmggw7QgbMaw4bubaSBi4bqxbmcgYGUuY2xpZW50WSArIChlbC5zY3JvbGxUb3AgLSBlbC5vZmZzZXRUb3ApYCDigJQgY8O0bmdcbiAgICAgICB0aOG7qWMgxJHDsyBjaOG7iSDEkcO6bmcga2hpIGBvZmZzZXRQYXJlbnRgIGPhu6dhIDxncmlkc3Rlcj4gQ0jDjU5IIEzDgCBraOG7kWkgY3Xhu5luIG7DoHkuIFRoaeG6v3UgYHJlbGF0aXZlYCB0aMOsXG4gICAgICAgYG9mZnNldFBhcmVudGAgbmjhuqN5IGzDqm4ga2jhu5FpIGJhbyBuZ2/DoGk6IGBvZmZzZXRUb3BgIHRy4bqjIDE2IHRyb25nIGtoaSBs4buHY2ggdGjhuq10IGzDoCA2NSDihpIgZ3JpZHN0ZXJcbiAgICAgICB0w61uaCDDtCBzYWkgNDlweCwgw7QgY2jhu50gxJHhurd0IGhp4buHbiBs4buHY2gga2jhu49pIGNvbiB0cuG7jyBuw6puIGvDqW8gdGjhuqMga2jDtG5nIMSR4buVaSDEkcaw4bujYyB24buLIHRyw60sIHbDoCBrw6lvIG3DqXBcbiAgICAgICBjxaluZyB0w61uaCBzYWkgxJFp4buDbSBk4burbmcuIC0tPlxuICA8ZGl2XG4gICAgI3Njcm9sbEFyZWFcbiAgICBjbGFzcz1cImxpYnMtdWktZ3JpZC1sYXlvdXQtc2Nyb2xsLWFyZWEgcmVsYXRpdmUgaC1mdWxsIG1pbi1oLTAgdy1mdWxsIG1pbi13LTBcIlxuICAgIFtjbGFzcy5vdmVyZmxvdy15LWF1dG9dPVwiIWlzTmVzdGVkQ2FudmFzKClcIlxuICAgIChtb3VzZWRvd24pPVwiaGFuZGxlck1vdXNlRG93blRyb25nTHVvaSgkZXZlbnQpXCJcbiAgICAoZHJhZ292ZXIpPVwiaGFuZGxlckRyYWdPdmVyKCRldmVudClcIlxuICAgIChkcmFnbGVhdmUpPVwiaGFuZGxlckRyYWdMZWF2ZSgkZXZlbnQpXCJcbiAgICAoZHJvcCk9XCJoYW5kbGVyRHJvcCgkZXZlbnQpXCI+XG4gICAgPCEtLSBTbmFwcGVkIERyb3AgR2hvc3QgUHJldmlldyAtLT5cbiAgICBAaWYgKGRyb3BHaG9zdCgpOyBhcyBnaG9zdCkge1xuICAgICAgPGRpdlxuICAgICAgICBjbGFzcz1cInBvaW50ZXItZXZlbnRzLW5vbmUgYWJzb2x1dGUgei0zMCBmbGV4IGZsZXgtY29sIGl0ZW1zLWNlbnRlciBqdXN0aWZ5LWNlbnRlciBvdmVyZmxvdy1oaWRkZW4gcm91bmRlZC1sZyBib3JkZXItMiBib3JkZXItZGFzaGVkIGJvcmRlci1ibHVlLTUwMCBiZy1ibHVlLTUwMC8xNSBwLTEgc2hhZG93LXNtIHRyYW5zaXRpb24tYWxsIGR1cmF0aW9uLTc1IGVhc2Utb3V0IGJhY2tkcm9wLWJsdXItWzAuNXB4XSBzZWxlY3Qtbm9uZVwiXG4gICAgICAgIFtzdHlsZS5sZWZ0LnB4XT1cImdob3N0LnBpeGVsTGVmdFwiXG4gICAgICAgIFtzdHlsZS50b3AucHhdPVwiZ2hvc3QucGl4ZWxUb3BcIlxuICAgICAgICBbc3R5bGUud2lkdGgucHhdPVwiZ2hvc3QucGl4ZWxXaWR0aFwiXG4gICAgICAgIFtzdHlsZS5oZWlnaHQucHhdPVwiZ2hvc3QucGl4ZWxIZWlnaHRcIj5cbiAgICAgICAgPGRpdiBjbGFzcz1cImlubGluZS1mbGV4IG1heC13LVs5NSVdIGl0ZW1zLWNlbnRlciBnYXAtMSB0cnVuY2F0ZSByb3VuZGVkLW1kIGJnLWJsdWUtNjAwIHB4LTIgcHktMC41IHRleHQtWzExcHhdIGZvbnQtc2VtaWJvbGQgdGV4dC13aGl0ZSBzaGFkb3cteHNcIj5cbiAgICAgICAgICBAaWYgKGdob3N0LmNhcmRJY29uQ2xhc3MpIHtcbiAgICAgICAgICAgIDxpIFtjbGFzc109XCJnaG9zdC5jYXJkSWNvbkNsYXNzICsgJyB0ZXh0LXhzJ1wiPjwvaT5cbiAgICAgICAgICB9IEBlbHNlIGlmIChnaG9zdC5jYXJkSWNvblRleHQpIHtcbiAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwidGV4dC1bMTBweF0gZm9udC1ib2xkXCI+e3sgZ2hvc3QuY2FyZEljb25UZXh0IH19PC9zcGFuPlxuICAgICAgICAgIH0gQGVsc2Uge1xuICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJ0ZXh0LXhzIGZvbnQtYm9sZFwiPnt7IGdob3N0LmlzSW5zaWRlR3JvdXAgPyAn4oazJyA6ICcrJyB9fTwvc3Bhbj5cbiAgICAgICAgICB9XG4gICAgICAgICAgPHNwYW4gY2xhc3M9XCJ0cnVuY2F0ZVwiPnt7IGdob3N0LmNhcmRUaXRsZSB9fTwvc3Bhbj5cbiAgICAgICAgICA8c3BhbiBjbGFzcz1cInRleHQtWzlweF0gZm9udC1tb25vIG9wYWNpdHktNzVcIj4oe3sgZ2hvc3QuY29scyB9fWMpPC9zcGFuPlxuICAgICAgICA8L2Rpdj5cblxuICAgICAgICBAaWYgKGdob3N0LnBpeGVsSGVpZ2h0ID49IDgwKSB7XG4gICAgICAgICAgPGRpdiBjbGFzcz1cIm10LTEgZmxleCBtYXgtdy1bOTUlXSBpdGVtcy1jZW50ZXIgZ2FwLTEuNSB0cnVuY2F0ZSByb3VuZGVkIGJvcmRlciBib3JkZXItYmx1ZS0xMDAgYmctd2hpdGUvOTUgcHgtMiBweS0wLjUgdGV4dC1bMTBweF0gZm9udC1tZWRpdW0gdGV4dC1ibHVlLTcwMCBzaGFkb3cteHNcIj5cbiAgICAgICAgICAgIEBpZiAoZ2hvc3QuaXNJbnNpZGVHcm91cCkge1xuICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cInRydW5jYXRlIGZvbnQtYm9sZCB0ZXh0LWJsdWUtOTAwXCI+4oazIHt7IGdob3N0Lmdyb3VwVGl0bGUgfX08L3NwYW4+XG4gICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwidGV4dC1ibHVlLTMwMFwiPuKAojwvc3Bhbj5cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIDxzcGFuPkPhu5l0IHt7IGdob3N0LmNvbCArIDEgfX0te3sgZ2hvc3QuY29sICsgZ2hvc3QuY29scyB9fTwvc3Bhbj5cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgfVxuICAgICAgPC9kaXY+XG4gICAgfVxuICAgIDxncmlkc3RlciBjbGFzcz1cImgtZnVsbCB3LWZ1bGxcIiBbY2xhc3MuZGlzcGxheS1ncmlkXT1cInNob3dHcmlkTGluZXMoKVwiIFtvcHRpb25zXT1cImdyaWRPcHRpb25zKClcIj5cbiAgICAgICAgQGZvciAoaXRlbSBvZiBjaGlsZHJlbigpOyB0cmFjayBpdGVtLmlkOyBsZXQgaXRlbUluZGV4ID0gJGluZGV4KSB7XG4gICAgPCEtLSDwn5S0IENo4bq3biBgbW91c2Vkb3duYCB04bqhaSDEkMOCWSBjaG8gbMaw4bubaSBs4buTbmcg4oCUIEPhuqRNIGLhu48gdsOgIEPhuqRNIGNodXnhu4NuIHNhbmcgY2jhu5cga2jDoWMuXG4gICAgICAgICBgaWdub3JlQ29udGVudENsYXNzYCBt4buZdCBtw6xuaCBLSMOUTkcgxJHhu6c6IGBkZWxheVN0YXJ0OiAxNjBgIGzDoG0gTeG7lkkgbMaw4bubaSBsw6puIGzhu4tjaFxuICAgICAgICAgYGRyYWdTdGFydGAgYuG6sW5nIGBzZXRUaW1lb3V0YCBuZ2F5IHThuqFpIGBtb3VzZWRvd25gLCBjw7JuIGBzdG9wUHJvcGFnYXRpb25gIG3DoCBsaWIgZ+G7jWkgYsOqblxuICAgICAgICAgdHJvbmcgYGRyYWdTdGFydGAgY2jhuqF5IHNhdSAxNjBtcyBuw6puIHF1w6EgbXXhu5luIOKAlCBsxrDhu5tpIENIQSDEkcOjIGvhu4twIG5o4bqtbiAoxJFvIDI4LzA4LzIwMjY6IGvDqW9cbiAgICAgICAgIGThuqNpIGto4buRaSBjb24sIGNodeG7l2kgY2xhc3MgZHV54buHdCBsw6puIMSQw5pORyBtw6AgY29udGFpbmVyIHbhuqtuIG5o4bqjeSAwLDAg4oaSIDAsMSkuXG4gICAgICAgICBH4bqvbiDhu58gYGdyaWRzdGVyLWl0ZW1gIGzDoCDEkcO6bmcgYmnDqm46IGzGsOG7m2kgY29uIG5naGUgdHLDqm4gY2jDrW5oIHBo4bqnbiB04butIG7DoHkgbsOqbiDEkcOjIG5o4bqtbiB4b25nLFxuICAgICAgICAgbMaw4bubaSBjaGEg4bufIG5nb8OgaSBi4buLIGNo4bq3bi4gLS0+XG4gICAgPGdyaWRzdGVyLWl0ZW1cbiAgICAgIFtpdGVtXT1cIml0ZW1cIlxuICAgICAgW2NsYXNzLmxpYnMtdWktZ3JpZC1sYXlvdXQtc2VsZWN0ZWRdPVwic2VsZWN0ZWROb2RlSWQoKSA9PT0gaXRlbS5pZFwiXG4gICAgICAoY2xpY2spPVwiaGFuZGxlclNlbGVjdE5vZGUoaXRlbSwgJGV2ZW50KVwiXG4gICAgICAobW91c2Vkb3duKT1cImhhbmRsZXJCbG9ja1BhcmVudERyYWcoJGV2ZW50KVwiPlxuICAgICAgPCEtLSDwn5S0IFbhu48gbsOgeSBtYW5nIGBkcmFnSGFuZGxlQ2xhc3NgIOKAlCBD4bqkTSBi4buPLlxuICAgICAgICAgICBgaWdub3JlQ29udGVudDogdHJ1ZWAgYuG6r3QgZ3JpZHN0ZXIgQ0jhu4ggY2hvIGvDqW8ga2hpIGNo4buXIGLhuqVtIG7hurFtIGTGsOG7m2kgbeG7mXQgcGjhuqduIHThu60gY8OzXG4gICAgICAgICAgIGBkcmFnSGFuZGxlQ2xhc3NgLiBLaMO0bmcgY8OzIHbhu48gbsOgeSB0aMOsIGNvbXBvbmVudCBj4bunYSBuxqFpIGTDuW5nICh0aMawIHZp4buHbiBraMO0bmcga2nhu4NtIHNvw6F0XG4gICAgICAgICAgIMSRxrDhu6NjIGNsYXNzIGPhu6dhIG7Dsykgc+G6vSBraMO0bmcgY8OzIHRheSBj4bqnbSBuw6BvLCB2w6AgS0jDlE5HIGto4buRaSBuw6BvIGvDqW8gxJHGsOG7o2Mg4oCUIMSRbyAyOC8wOC8yMDI2OlxuICAgICAgICAgICBrw6lvIDMyMHB4LCB0b+G6oSDEkeG7mSBraOG7kWkgZ2nhu68gbmd1ecOqbiB4PTMseT0wLlxuICAgICAgICAgICBUw6puIGNsYXNzIHRoZW8gY+G6pXA6IGzGsOG7m2kgdHJhbmcgdsOgIGzGsOG7m2kgbOG7k25nIGTDuW5nIGhhaSB0w6puIEtIw4FDIG5oYXUsIG7hur91IGtow7RuZyBsxrDhu5tpIGNoYVxuICAgICAgICAgICBjxaluZyBuaOG6rW4gcmEgdGF5IGPhuqdtIGPhu6dhIGto4buRaSBjb24gdsOgIG5o4bqlYyBsdcO0biBjb250YWluZXIuIC0tPlxuICAgICAgPCEtLSDwn5S0IFbhu48gS0jDlE5HIG1hbmcgYGRyYWdIYW5kbGVDbGFzc2Ag4oCUIEPhuqRNIHRow6ptIGzhuqFpLlxuICAgICAgICAgICBLw6lvIGNo4buJIMSRxrDhu6NjIHBow6lwIGLhuq90IMSR4bqndSB04burIEThuqJJIFhBTkggKG5nxrDhu51pIGTDuW5nIGNo4buRdCAyOC8wOC8yMDI2OiBcInBo4bqjaSBob3ZlciB2w6BvIHbDuW5nXG4gICAgICAgICAgIG3DoHUgeGFuaCB0aMOsIG3hu5tpIGvDqW8gdGjhuqMgxJHGsOG7o2MgY2hvIMSR4buTbmcgbmjhuqV0XCIpLiBDaG8gY+G6oyB24buPIGzDoG0gdGF5IGPhuqdtIHRow6wgYuG6pW0gxJHDonUgY8WpbmdcbiAgICAgICAgICAga8OpbywgdsOgIGto4buRaSBjb24gbuG6sW0gdHJvbmcgY29udGFpbmVyIHPhur0gbmjhuqVjIGx1w7RuIGNvbnRhaW5lciB2w6wgbMaw4bubaSBjaGEgZHV54buHdCBsw6puIGfhurdwXG4gICAgICAgICAgIHRheSBj4bqnbSBj4bunYSB24buPIGNvbnRhaW5lciB0csaw4bubYy5cbiAgICAgICAgICAgVuG7jyBraOG7kWkgY29uIHbhuqtuIGdp4buvIGNsYXNzIENI4bq2TiDEkeG7gyBsxrDhu5tpIGNoYSBk4burbmcgxJHDum5nIOG7nyBiacOqbi4gLS0+XG4gICAgICA8ZGl2XG4gICAgICAgIGNsYXNzPVwibGlicy11aS1ncmlkLWxheW91dC1ibG9jay1zaGVsbCBncm91cCByZWxhdGl2ZSBoLWZ1bGwgdy1mdWxsIG1pbi13LTBcIlxuICAgICAgICBbY2xhc3MubGlicy11aS1ncmlkLWxheW91dC1ibG9jay1wYXJlbnQtZHJhZ109XCJpc05lc3RlZENhbnZhcygpXCI+XG4gICAgICAgIDwhLS0gROG6o2kga8OpbzogaGnhu4duIGtoaSByw6ogY2h14buZdCB2w6BvIGto4buRaSwgYmEgY2jhuqVtIGzDoCBk4bqldSBoaeG7h3Uga8OpbyBxdWVuIHRodeG7mWMuXG4gICAgICAgICAgICAgTmfGsOG7nWkgZMO5bmcgY+G6p24gbeG7mXQgY2jhu5cgYsOhbSBSw5UgUsOATkcgdGhheSB2w6wgxJFvw6FuIHhlbSBi4bqlbSDEkcOidSB0aMOsIGvDqW8gxJHGsOG7o2NcbiAgICAgICAgICAgICAoY2jhu5F0IDI4LzA4LzIwMjYsIHRoZW8gxJHDum5nIGThuqNpIMSRYW5nIGTDuW5nIOG7nyBtw6BuIEN1c3RvbWVyIDM2MCBj4bunYSBtb2Jpby13ZWIpLiAtLT5cbiAgICAgICAgQGlmIChpc0VkaXRNb2RlKCkpIHtcbiAgICAgICAgICA8IS0tIPCflLQgROG6o2kgUEjhuqJJIG1hbmcgdGF5IGPhuqdtIMSQw5pORyBD4bqkUCBj4bunYSBuw7MuIEThuqNpIG5o4bqtbiBjaHXhu5l0IChgcG9pbnRlci1ldmVudHM6IGF1dG9gKSxcbiAgICAgICAgICAgICAgIG7Dqm4gbuG6v3Uga2jDtG5nIG1hbmcgdGF5IGPhuqdtIHRow6wgYGNoZWNrRHJhZ0hhbmRsZUNsYXNzYCBkdXnhu4d0IGzDqm4gZ+G6t3AgdGF5IGPhuqdtIGPhu6dhXG4gICAgICAgICAgICAgICBjb250YWluZXIgdsOgIG5o4bqlYyBjb250YWluZXIgdGhheSB2w6wga2jhu5FpIGNvbiAoxJFvIDI4LzA4LzIwMjY6IGvDqW8gZOG6o2kga2jhu5FpIGNvbixcbiAgICAgICAgICAgICAgIGNvbnRhaW5lciBuaOG6o3kgMCwwIOKGkiAwLDEgY8OybiBraOG7kWkgY29uIMSR4bupbmcgaW0pLlxuICAgICAgICAgICAgICAg8J+UtCBE4bqjaSBDSOG7iCBtYW5nIHRheSBj4bqnbSwgQ+G6pE0gbWFuZyB0aMOqbSBjbGFzcyBjaOG6t246IGBjaGVja0RyYWdIYW5kbGVDbGFzc2AgeMOpdCBoYWlcbiAgICAgICAgICAgICAgIGNsYXNzIMSRw7MgdHLDqm4gQ8OZTkcgbeG7mXQgbm9kZSBuw6puIMSR4buDIGNodW5nIGzDoCBrw6lvIGjhu49uZyAoxJFvIDI4LzA4LzIwMjY6IGLhuqVtIGThuqNpIGto4buRaVxuICAgICAgICAgICAgICAgY29uIGvDqW8gMTQwcHgsIGto4buRaSDEkeG7qW5nIGltKS4gVmnhu4djIGNo4bq3biBsxrDhu5tpIGNoYSBkbyBW4buOIEtI4buQSSBsby4gLS0+XG4gICAgICAgICAgPGRpdlxuICAgICAgICAgICAgY2xhc3M9XCJsaWJzLXVpLWdyaWQtbGF5b3V0LWRyYWctYmFyXCJcbiAgICAgICAgICAgIFtjbGFzcy5saWJzLXVpLWdyaWQtbGF5b3V0LWRyYWctYmFyLWNoaWxkXT1cImlzTmVzdGVkQ2FudmFzKClcIlxuICAgICAgICAgICAgW2NsYXNzLmxpYnMtdWktZ3JpZC1sYXlvdXQtZHJhZy1oYW5kbGVdPVwiIWlzTmVzdGVkQ2FudmFzKClcIlxuICAgICAgICAgICAgW2NsYXNzLmxpYnMtdWktZ3JpZC1sYXlvdXQtZHJhZy1oYW5kbGUtY2hpbGRdPVwiaXNOZXN0ZWRDYW52YXMoKVwiPlxuICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJsaWJzLXVpLWdyaWQtbGF5b3V0LWRyYWctYmFyLWRvdHNcIj5cbiAgICAgICAgICAgICAgQGZvciAoZG90IG9mIGRyYWdCYXJEb3RzOyB0cmFjayBkb3QpIHtcbiAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cImxpYnMtdWktZ3JpZC1sYXlvdXQtZHJhZy1iYXItZG90XCI+PC9zcGFuPlxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICA8L3NwYW4+XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgIH1cblxuICAgICAgICA8IS0tIEtodW5nIGNo4bupYSBjb21wb25lbnQgY+G7p2EgbsahaSBkw7luZy5cbiAgICAgICAgICAgICDwn5S0IFBI4bqiSSBjw7Mga2h1bmcgdGjhuq10IChraMO0bmcgcGjhuqNpIGBuZy1jb250YWluZXJgIHRy4buRbmcpOiBuw7MgbG8gaOG7mSBuxqFpIGTDuW5nIHBo4bqnbiBs4bqlcCDEkeG6p3lcbiAgICAgICAgICAgICDDtCB2w6Agdmnhu4FuIGLDoW8gY2jhur8gxJHhu5kgc+G7rWEuIEtow7RuZyBjw7Mga2h1bmcgdGjDrCBt4buXaSBjb21wb25lbnQgbuG7mWkgZHVuZyBs4bqhaSBwaOG6o2kgdOG7sSB2aeG6v3RcbiAgICAgICAgICAgICBgOmhvc3QgeyB3aWR0aC9oZWlnaHQ6IDEwMCUgfWAgKyB2aeG7gW4gxJHhu6l0IOKAlCDEkcOzIGzDoCB2aeG7h2MgY+G7p2EgdGjGsCB2aeG7h24sIGtow7RuZyBwaOG6o2kgY+G7p2FcbiAgICAgICAgICAgICBuZ8aw4budaSBkw7luZyAobmfGsOG7nWkgZMO5bmcgY2jhu5F0IDI4LzA4LzIwMjYpLlxuICAgICAgICAgICAgIE3hu5dpIGto4buRaSBt4buZdCBWaWV3Q29udGFpbmVyUmVmIHJpw6puZyBuw6puIGNvbXBvbmVudCBu4bqxbSDEkcO6bmcgw7QgY+G7p2EgbsOzLiAtLT5cbiAgICAgICAgPGRpdlxuICAgICAgICAgIGNsYXNzPVwibGlicy11aS1ncmlkLWxheW91dC1jb250ZW50LWZyYW1lXCJcbiAgICAgICAgICBbY2xhc3MubGlicy11aS1ncmlkLWxheW91dC1jb250ZW50LWZyYW1lLWVkaXRdPVwiaXNFZGl0TW9kZSgpICYmICFpc0NvbnRhaW5lcihpdGVtKVwiXG4gICAgICAgICAgW2NsYXNzLmxpYnMtdWktZ3JpZC1sYXlvdXQtY29udGVudC1mcmFtZS1lbXB0eV09XCJpc0NvbnRhaW5lcihpdGVtKVwiPlxuICAgICAgICAgIDxuZy1jb250YWluZXIgI2l0ZW1Ib3N0IC8+XG4gICAgICAgIDwvZGl2PlxuXG4gICAgICAgIDwhLS0gROG6pXUgaGnhu4d1IENPTlRBSU5FUjogbmjDo24gZ8OzYyB0csOqbi1waOG6o2kgKyB2aeG7gW4gxJHhu6l0IGJhbyBydeG7mXQuIEtow7RuZyBjw7MgZOG6pXUgaGnhu4d1IHRow6xcbiAgICAgICAgICAgICBuZ8aw4budaSBkw7luZyBraMO0bmcgYmnhur90IGto4buRaSBuw6BvIGNo4bupYSDEkcaw4bujYyBraOG7kWkga2jDoWMgKGNo4buRdCAyOC8wOC8yMDI2LCB0aGVvIMSRw7puZyBjw6FjaFxuICAgICAgICAgICAgIG3DoG4gQ3VzdG9tZXIgMzYwIGPhu6dhIG1vYmlvLXdlYiDEkWFuZyBsw6BtKS4gLS0+XG4gICAgICAgIEBpZiAoaXNFZGl0TW9kZSgpICYmIGlzQ29udGFpbmVyKGl0ZW0pKSB7XG4gICAgICAgICAgPGRpdiBjbGFzcz1cImxpYnMtdWktZ3JpZC1sYXlvdXQtY29udGFpbmVyLWxhYmVsXCI+e3sgJ2kxOG5fY29udGFpbmVyX2Jsb2NrJyB8IHRyYW5zbGF0ZSB9fTwvZGl2PlxuICAgICAgICAgIDxkaXYgY2xhc3M9XCJsaWJzLXVpLWdyaWQtbGF5b3V0LWNvbnRhaW5lci1ib3JkZXJcIj48L2Rpdj5cbiAgICAgICAgfVxuXG4gICAgICAgIDwhLS0gVGhhbmggY8O0bmcgY+G7pTogaGnhu4duIGtoaSByw6ogY2h14buZdCB2w6BvIGto4buRaS5cbiAgICAgICAgICAgICDwn5S0IETDuW5nIGBsaWJzX3VpLWNvbXBvbmVudHMtYnV0dG9ucy1idXR0b25gIOKAlCBD4bqkTSB04buxIGThu7FuZyB0aOG6uyBgPGJ1dHRvbj5gLlxuICAgICAgICAgICAgIENvbXBvbmVudCBuw6B5IMSRw6MgY8OzIHPhurVuIGtp4buDdSBuw7p0LCBj4buhIG7DunQgdsOgIGJvbmcgYsOzbmcgY2jDuiB0aMOtY2ggdGhlbyDEkcO6bmcgYuG7mSBnaWFvIGRp4buHblxuICAgICAgICAgICAgIGPhu6dhIHPhuqNuIHBo4bqpbTsgdOG7sSBk4buxbmcgbMOgIG3hu5dpIG7GoWkgbeG7mXQga2nhu4N1IHbDoCBt4bqldCBsdcO0biB0b29sdGlwLiAtLT5cbiAgICAgICAgQGlmIChpc0VkaXRNb2RlKCkgJiYgIWhpZGRlblRvb2xiYXIoKSkge1xuICAgICAgICAgIEBpZiAodGVtcGxhdGVUb29sYmFyKCkpIHtcbiAgICAgICAgICAgIDwhLS0gTsahaSBkw7luZyB04buxIHbhur0gdGhhbmggY8O0bmcgY+G7pTogbmjhuq1uIGto4buRaSArIGPDoWMgaMOgbSBwaMOhdCBldmVudCBxdWEgY29udGV4dC5cblxuICAgICAgICAgICAgICAgICDwn5S0IEto4buRaSBi4buNYyB04buxIGNo4bq3biBgbW91c2Vkb3duYC9gY2xpY2tgIG7hu5VpIGzDqm4gZ3JpZHN0ZXIuIFRoYW5oIGPDtG5nIGPhu6UgbuG6sW0gdHJvbmdcbiAgICAgICAgICAgICAgICAgdsO5bmcgbWFuZyBgZHJhZ0hhbmRsZUNsYXNzYDsga2jDtG5nIGNo4bq3biB0aMOsIGPDuiBi4bqlbSBi4buLIGhp4buDdSBsw6AgYuG6r3QgxJHhuqd1IGvDqW8gdsOgXG4gICAgICAgICAgICAgICAgIGBkZWxheVN0YXJ0OiAxNjBgIG514buRdCBsdcO0biBgY2xpY2tgIOKAlCBuw7p0IHRyb25nIHRlbXBsYXRlIG5nb8OgaSBi4bqlbSBraMO0bmcgxINuXG4gICAgICAgICAgICAgICAgICjEkW8gMDkvMDkvMjAyNjogYuG6pW0gYuG6sW5nIGAuY2xpY2soKWAgY+G7p2EgRE9NIHRow6wgbeG7nywgYuG6pW0gY2h14buZdCB0aOG6rXQgdGjDrCBraMO0bmcpLlxuICAgICAgICAgICAgICAgICBDaOG6t24g4bufIMSQw4JZIMSR4buDIG7GoWkgZMO5bmcga2jDtG5nIHBo4bqjaSBiaeG6v3QgYuG6q3kgbsOgeS4gLS0+XG4gICAgICAgICAgICA8ZGl2XG4gICAgICAgICAgICAgIGNsYXNzPVwibGlicy11aS1ncmlkLWxheW91dC10b29sYmFyXCJcbiAgICAgICAgICAgICAgcm9sZT1cInRvb2xiYXJcIlxuICAgICAgICAgICAgICB0YWJpbmRleD1cIjBcIlxuICAgICAgICAgICAgICBbY2xhc3MubGlicy11aS1ncmlkLWxheW91dC10b29sYmFyLWNoaWxkXT1cImlzTmVzdGVkQ2FudmFzKClcIlxuICAgICAgICAgICAgICAobW91c2Vkb3duKT1cImhhbmRsZXJTdG9wRXZlbnQoJGV2ZW50KVwiXG4gICAgICAgICAgICAgIChrZXlkb3duKT1cImhhbmRsZXJTdG9wRXZlbnQoJGV2ZW50KVwiXG4gICAgICAgICAgICAgIChjbGljayk9XCJoYW5kbGVyU3RvcEV2ZW50KCRldmVudClcIj5cbiAgICAgICAgICAgICAgPG5nLWNvbnRhaW5lclxuICAgICAgICAgICAgICAgICpuZ1RlbXBsYXRlT3V0bGV0PVwidGVtcGxhdGVUb29sYmFyKCkhOyBjb250ZXh0OiB0b29sYmFyQ29udGV4dHMoKVtpdGVtSW5kZXhdXCIgLz5cbiAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgIH0gQGVsc2Uge1xuICAgICAgICAgICAgPGRpdlxuICAgICAgICAgICAgICBjbGFzcz1cImxpYnMtdWktZ3JpZC1sYXlvdXQtdG9vbGJhclwiXG4gICAgICAgICAgICAgIFtjbGFzcy5saWJzLXVpLWdyaWQtbGF5b3V0LXRvb2xiYXItY2hpbGRdPVwiaXNOZXN0ZWRDYW52YXMoKVwiPlxuICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cImxpYnMtdWktZ3JpZC1sYXlvdXQtZGltLWJhZGdlXCI+XG4gICAgICAgICAgICAgICAge3sgaXRlbS5yb3dzIH19IGjDoG5nIMOXIHt7IGl0ZW0uY29scyB9fSBj4buZdFxuICAgICAgICAgICAgICA8L3NwYW4+XG4gICAgICAgICAgICAgIEBpZiAoY2FuQWRkSW5zaWRlKGl0ZW0pKSB7XG4gICAgICAgICAgICAgICAgPGxpYnNfdWktY29tcG9uZW50cy1idXR0b25zLWJ1dHRvblxuICAgICAgICAgICAgICAgICAgW3R5cGVdPVwiJ2J1dHRvbi10aGlyZCdcIlxuICAgICAgICAgICAgICAgICAgW2ljb25Pbmx5VHlwZV09XCJ0cnVlXCJcbiAgICAgICAgICAgICAgICAgIFtzaXplQnV0dG9uXT1cIidzbWFsbGVyJ1wiXG4gICAgICAgICAgICAgICAgICBbY2xhc3NJY29uTGVmdF09XCInbGlicy11aS1pY29uLWFkZCdcIlxuICAgICAgICAgICAgICAgICAgW3BvcG92ZXJdPVwieyBjb25maWc6IHsgY29udGVudDogJ1Row6ptIGto4buRaSB2w6BvIHRyb25nJywgekluZGV4OiAxMzAwIH0gfVwiXG4gICAgICAgICAgICAgICAgICAob3V0Q2xpY2spPVwiaGFuZGxlckFkZEluc2lkZSgkZXZlbnQsIGl0ZW0pXCIgLz5cbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICBAaWYgKGNhblRvZ2dsZVR5cGUoaXRlbSkpIHtcbiAgICAgICAgICAgICAgICA8bGlic191aS1jb21wb25lbnRzLWJ1dHRvbnMtYnV0dG9uXG4gICAgICAgICAgICAgICAgICBbdHlwZV09XCInYnV0dG9uLXRoaXJkJ1wiXG4gICAgICAgICAgICAgICAgICBbaWNvbk9ubHlUeXBlXT1cInRydWVcIlxuICAgICAgICAgICAgICAgICAgW3NpemVCdXR0b25dPVwiJ3NtYWxsZXInXCJcbiAgICAgICAgICAgICAgICAgIFtjbGFzc0ljb25MZWZ0XT1cImlzQ29udGFpbmVyKGl0ZW0pID8gJ2xpYnMtdWktaWNvbi1zcGxpdC1jZWxsJyA6ICdsaWJzLXVpLWljb24tbWVyZ2UtY2VsbCdcIlxuICAgICAgICAgICAgICAgICAgW3BvcG92ZXJdPVwieyBjb25maWc6IHsgY29udGVudDogaXNDb250YWluZXIoaXRlbSkgPyAnxJDGsGEgduG7gSBraOG7kWkgxJHGoW4nIDogJ0NodXnhu4NuIHRow6BuaCBraOG7kWkgZ2jDqXAnLCB6SW5kZXg6IDEzMDAgfSB9XCJcbiAgICAgICAgICAgICAgICAgIChvdXRDbGljayk9XCJoYW5kbGVyVG9nZ2xlVHlwZSgkZXZlbnQsIGl0ZW0pXCIgLz5cbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICA8bGlic191aS1jb21wb25lbnRzLWJ1dHRvbnMtYnV0dG9uXG4gICAgICAgICAgICAgICAgW3R5cGVdPVwiJ2J1dHRvbi10aGlyZCdcIlxuICAgICAgICAgICAgICAgIFtpY29uT25seVR5cGVdPVwidHJ1ZVwiXG4gICAgICAgICAgICAgICAgW3NpemVCdXR0b25dPVwiJ3NtYWxsZXInXCJcbiAgICAgICAgICAgICAgICBbY2xhc3NJY29uTGVmdF09XCInbGlicy11aS1pY29uLXNldHRpbmcnXCJcbiAgICAgICAgICAgICAgICBbcG9wb3Zlcl09XCJ7IGNvbmZpZzogeyBjb250ZW50OiAnQ+G6pXUgaMOsbmggdGjhursnLCB6SW5kZXg6IDEzMDAgfSB9XCJcbiAgICAgICAgICAgICAgICAob3V0Q2xpY2spPVwiaGFuZGxlckNvbmZpZygkZXZlbnQsIGl0ZW0pXCIgLz5cbiAgICAgICAgICAgICAgPGxpYnNfdWktY29tcG9uZW50cy1idXR0b25zLWJ1dHRvblxuICAgICAgICAgICAgICAgIFt0eXBlXT1cIididXR0b24tdGhpcmQtaG92ZXItZGFuZ2VyJ1wiXG4gICAgICAgICAgICAgICAgW2ljb25Pbmx5VHlwZV09XCJ0cnVlXCJcbiAgICAgICAgICAgICAgICBbc2l6ZUJ1dHRvbl09XCInc21hbGxlcidcIlxuICAgICAgICAgICAgICAgIFtjbGFzc0ljb25MZWZ0XT1cIidsaWJzLXVpLWljb24tcmVtb3ZlJ1wiXG4gICAgICAgICAgICAgICAgW3BvcG92ZXJdPVwieyBjb25maWc6IHsgY29udGVudDogaXNDb250YWluZXIoaXRlbSkgPyAnWG/DoSBj4bqjIGto4buRaSBnaMOpcCcgOiAnWG/DoSBraOG7kWknLCB6SW5kZXg6IDEzMDAgfSB9XCJcbiAgICAgICAgICAgICAgICAob3V0Q2xpY2spPVwiaGFuZGxlclJlbW92ZSgkZXZlbnQsIGl0ZW0pXCIgLz5cbiAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIEBpZiAoaXRlbS5jaGlsZHJlbiAmJiBpdGVtLmNoaWxkcmVuLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICA8IS0tIEto4buRaSBjw7MgY29uIOKGkiBydeG7mXQgbsOzIGzhuqFpIGzDoCBt4buZdCBt4bq3dCBwaOG6s25nIG7hu69hLiDEkOG7hyBxdXkg4bufIMSRw6J5LCBuxqFpIGTDuW5nIGtow7RuZyBwaOG6o2kgbG8uXG4gICAgICAgICAgICAgICBM4buBIMSR4bq3dCDhu58gxJDDglkgKHbhu48gY29udGFpbmVyKSwga2jDtG5nIMSR4bq3dCB2w6BvIGzGsOG7m2kgY29uIOKAlCBsxrDhu5tpIGNvbiBnaeG7ryBuZ3V5w6puIGtoZSAycHguIC0tPlxuICAgICAgICAgIDxsaWJzX3VpLXNlcnZpY2VzLWdyaWRfbGF5b3V0LWNhbnZhc1xuICAgICAgICAgICAgY2xhc3M9XCJibG9jayBoLWZ1bGwgdy1mdWxsXCJcbiAgICAgICAgICAgIFtzdHlsZS5wYWRkaW5nXT1cImNvbnRhaW5lclBhZGRpbmcoKVwiXG4gICAgICAgICAgICBbbm9kZV09XCJpdGVtXCJcbiAgICAgICAgICAgIFtkZXB0aF09XCJkZXB0aCgpICsgMVwiXG4gICAgICAgICAgICBbaGlkZGVuVG9vbGJhcl09XCJoaWRkZW5Ub29sYmFyKClcIlxuICAgICAgICAgICAgW3RlbXBsYXRlVG9vbGJhcl09XCJ0ZW1wbGF0ZVRvb2xiYXIoKVwiXG4gICAgICAgICAgICBbc2VsZWN0ZWROb2RlSWRdPVwic2VsZWN0ZWROb2RlSWQoKVwiXG4gICAgICAgICAgICAob3V0U2VsZWN0Tm9kZSk9XCJvdXRTZWxlY3ROb2RlLmVtaXQoJGV2ZW50KVwiXG4gICAgICAgICAgICAob3V0Q29uZmlnTm9kZSk9XCJvdXRDb25maWdOb2RlLmVtaXQoJGV2ZW50KVwiXG4gICAgICAgICAgICAob3V0Q2hhbmdlKT1cIm91dENoYW5nZS5lbWl0KCRldmVudClcIlxuICAgICAgICAgICAgKG91dFJlbW92ZU5vZGUpPVwib3V0UmVtb3ZlTm9kZS5lbWl0KCRldmVudClcIlxuICAgICAgICAgICAgKG91dEFkZEJsb2NrSW5zaWRlKT1cIm91dEFkZEJsb2NrSW5zaWRlLmVtaXQoJGV2ZW50KVwiXG4gICAgICAgICAgICAob3V0VG9nZ2xlVHlwZSk9XCJvdXRUb2dnbGVUeXBlLmVtaXQoJGV2ZW50KVwiIC8+XG4gICAgICAgIH1cbiAgICAgIDwvZGl2PlxuICAgIDwvZ3JpZHN0ZXItaXRlbT5cbiAgfVxuICAgIDwvZ3JpZHN0ZXI+XG4gIDwvZGl2PlxufVxuIl19
|
|
572
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ3JpZC1sYXlvdXQtY2FudmFzLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL2xpYnMtdWkvc2VydmljZXMvZ3JpZC1sYXlvdXQvc3JjL2NhbnZhcy9ncmlkLWxheW91dC1jYW52YXMuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vLi4vbGlicy11aS9zZXJ2aWNlcy9ncmlkLWxheW91dC9zcmMvY2FudmFzL2dyaWQtbGF5b3V0LWNhbnZhcy5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBRUwsdUJBQXVCLEVBQ3ZCLFNBQVMsRUFFVCxZQUFZLEVBR1osZ0JBQWdCLEVBQ2hCLFFBQVEsRUFDUixNQUFNLEVBQ04sTUFBTSxFQUNOLEtBQUssRUFDTCxLQUFLLEVBQ0wsTUFBTSxFQUNOLE1BQU0sRUFDTixTQUFTLEVBQ1QsWUFBWSxHQUNiLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQ25ELE9BQU8sRUFBRSxzQ0FBc0MsRUFBRSxNQUFNLG9DQUFvQyxDQUFDO0FBQzVGLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxjQUFjLEVBQUUsTUFBTSxZQUFZLENBQUM7QUFDL0QsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQ3RELE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxtQ0FBbUMsQ0FBQztBQUNsRSxPQUFPLEVBQUUsdUJBQXVCLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQWFqRSxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQzs7OztBQUVuRjs7Ozs7R0FLRztBQVNILE1BQU0sT0FBTywrQkFBK0I7SUFDMUM7Ozs7O09BS0c7SUFDTSxJQUFJLEdBQUcsS0FBSyxFQUFxQixDQUFDO0lBQzNDLDhEQUE4RDtJQUNyRCxLQUFLLEdB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ckMsc0JBQXNCO3NCQUQvQixZQUFZO3VCQUFDLGtCQUFrQixFQUFFLENBQUMsUUFBUSxDQUFDO2dCQXFCbEMsb0JBQW9CO3NCQUQ3QixZQUFZO3VCQUFDLGdCQUFnQixFQUFFLENBQUMsUUFBUSxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgQWZ0ZXJWaWV3SW5pdCxcbiAgQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3ksXG4gIENvbXBvbmVudCxcbiAgRWxlbWVudFJlZixcbiAgSG9zdExpc3RlbmVyLFxuICBPbkRlc3Ryb3ksXG4gIFRlbXBsYXRlUmVmLFxuICBWaWV3Q29udGFpbmVyUmVmLFxuICBjb21wdXRlZCxcbiAgZWZmZWN0LFxuICBpbmplY3QsXG4gIGlucHV0LFxuICBtb2RlbCxcbiAgb3V0cHV0LFxuICBzaWduYWwsXG4gIHZpZXdDaGlsZCxcbiAgdmlld0NoaWxkcmVuLFxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IE5nVGVtcGxhdGVPdXRsZXQgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuaW1wb3J0IHsgTGlic1VpQ29tcG9uZW50c0J1dHRvbnNCdXR0b25Db21wb25lbnQgfSBmcm9tICdAbGlicy11aS9jb21wb25lbnRzLWJ1dHRvbnMtYnV0dG9uJztcbmltcG9ydCB7IEdyaWRzdGVyQ29tcG9uZW50LCBHcmlkc3Rlck1vZHVsZSB9IGZyb20gJ2dyaWRzdGVyMTgnO1xuaW1wb3J0IHsgVHJhbnNsYXRlTW9kdWxlIH0gZnJvbSAnQG5neC10cmFuc2xhdGUvY29yZSc7XG5pbXBvcnQgeyBlbXB0eVJvb3ROb2RlIH0gZnJvbSAnLi4vZGVmaW5lcy9ncmlkc3Rlci1jb25maWcuZGVmaW5lJztcbmltcG9ydCB7IExpYnNVaUdyaWRMYXlvdXRTZXJ2aWNlIH0gZnJvbSAnLi4vZ3JpZC1sYXlvdXQuc2VydmljZSc7XG5pbXBvcnQge1xuICBUX2dyaWRMYXlvdXRfYWN0aW9uRXZlbnQsXG4gIFRfZ3JpZExheW91dF9hZGRFdmVudCxcbiAgVF9ncmlkTGF5b3V0X2NoYW5nZUV2ZW50LFxuICBUX2dyaWRMYXlvdXRfZHJvcEV2ZW50LFxuICBUX2dyaWRMYXlvdXRfZHJvcEdob3N0LFxuICBUX2dyaWRMYXlvdXRfZXh0ZXJuYWxEcmFnUGF5bG9hZCxcbiAgVF9ncmlkTGF5b3V0X25ld05vZGUsXG4gIFRfZ3JpZExheW91dF9ub2RlLFxuICBUX2dyaWRMYXlvdXRfdG9vbGJhckNvbnRleHQsXG4gIFRfZ3JpZExheW91dF96b29tUHJlc2V0LFxufSBmcm9tICcuLi9pbnRlcmZhY2VzL2dyaWQtbGF5b3V0LmludGVyZmFjZSc7XG5pbXBvcnQgeyBjYWxjdWxhdGVEcm9wR2hvc3QsIHBhcnNlRHJvcFBheWxvYWQgfSBmcm9tICcuLi9kZWZpbmVzL2NvbGxpc2lvbi5kZWZpbmUnO1xuXG4vKipcbiAqIE3hurd0IHBo4bqzbmcga8OpbyB0aOG6oy4gxJDhu4cgcXV5OiBraOG7kWkgY8OzIGBjaGlsZHJlbmAgdGjDrCBydeG7mXQgbsOzIGzhuqFpIGzDoCBt4buZdCBt4bq3dCBwaOG6s25nIG7hu69hLlxuICpcbiAqIE7GoWkgZMO5bmcgS0jDlE5HIGThu7FuZyBjb21wb25lbnQgbsOgeSB0cuG7sWMgdGnhur9wIGNobyB04burbmcga2jhu5FpIOKAlCBjaOG7iSDEkeG6t3QgTeG7mFQgdGjhursg4bufIGfhu5FjIHbDoCB0cnV54buBblxuICogYG5vZGVDb21wb25lbnRUeXBlYCBxdWEgYExpYnNVaUdyaWRMYXlvdXRTZXJ2aWNlLmluaXQoKWAuIFRoxrAgdmnhu4duIHThu7EgZ+G6r24gY29tcG9uZW50IGNobyBt4buNaSBraOG7kWkuXG4gKi9cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ2xpYnNfdWktc2VydmljZXMtZ3JpZF9sYXlvdXQtY2FudmFzJyxcbiAgc3RhbmRhbG9uZTogdHJ1ZSxcbiAgaW1wb3J0czogW0dyaWRzdGVyTW9kdWxlLCBMaWJzVWlDb21wb25lbnRzQnV0dG9uc0J1dHRvbkNvbXBvbmVudCwgTmdUZW1wbGF0ZU91dGxldCwgVHJhbnNsYXRlTW9kdWxlXSxcbiAgdGVtcGxhdGVVcmw6ICcuL2dyaWQtbGF5b3V0LWNhbnZhcy5jb21wb25lbnQuaHRtbCcsXG4gIHN0eWxlVXJsOiAnLi9ncmlkLWxheW91dC1jYW52YXMuY29tcG9uZW50LnNjc3MnLFxuICBjaGFuZ2VEZXRlY3Rpb246IENoYW5nZURldGVjdGlvblN0cmF0ZWd5Lk9uUHVzaCxcbn0pXG5leHBvcnQgY2xhc3MgTGlic1VpR3JpZExheW91dENhbnZhc0NvbXBvbmVudCBpbXBsZW1lbnRzIEFmdGVyVmlld0luaXQsIE9uRGVzdHJveSB7XG4gIC8qKlxuICAgKiBAaW50ZXJuYWwgQ2jhu4kgbeG6t3QgcGjhurNuZyBM4buSTkcgZMO5bmcg4oCUIHRoxrAgdmnhu4duIHThu7EgdHJ1eeG7gW4ga2hpIHbhur0gcnXhu5l0IGNvbnRhaW5lci5cbiAgICpcbiAgICogTsahaSBkw7luZyBLSMOUTkcgdHJ1eeG7gW46IG3hurd0IHBo4bqzbmcgZ+G7kWMgxJHhu41jIGPDonkgdOG7qyBzZXJ2aWNlICjEkcOjIMSRxrBhIHbDoG8gcXVhIGBpbml0KClgKSwgdHJ1eeG7gW4gdGjDqm1cbiAgICog4bufIMSRw6J5IGzDoCBraGFpIGhhaSBs4bqnbiBjw7luZyBt4buZdCB0aOG7qSAobmfGsOG7nWkgZMO5bmcgY2jhu5F0IDI4LzA4LzIwMjYpLlxuICAgKi9cbiAgcmVhZG9ubHkgbm9kZSA9IGlucHV0PFRfZ3JpZExheW91dF9ub2RlPigpO1xuICAvKiogQGludGVybmFsIENo4buJIG3hurd0IHBo4bqzbmcgTOG7kk5HIGTDuW5nIOKAlCB0aMawIHZp4buHbiB04buxIHRydXnhu4FuLiAqL1xuICByZWFkb25seSBkZXB0aCA9IGlucHV0PG51bWJlcj4oMCk7XG5cbiAgLyoqXG4gICAqIOG6qG4gaOG6s24gdGhhbmggY8O0bmcgY+G7pSBt4bq3YyDEkeG7i25oICh0aMOqbS12w6BvLXRyb25nIMK3IGfhu5lwL3TDoWNoIMK3IHhvw6EpIGPhu6dhIE3hu4xJIGto4buRaS5cbiAgICpcbiAgICogRMO5bmcga2hpIHPhuqNuIHBo4bqpbSBnb20gY8OhYyBow6BuaCDEkeG7mW5nIMSRw7MgdsOgbyBjaOG7lyBraMOhYyDigJQgdmQgbeG7mXQgbsO6dCDii64gbuG6sW0gdHJvbmcgY2jDrW5oIG7hu5lpIGR1bmdcbiAgICoga2jhu5FpLiDhuqhuIHLhu5NpIHRow6wgYG91dFJlbW92ZU5vZGVgIMK3IGBvdXRBZGRCbG9ja0luc2lkZWAgwrcgYG91dFRvZ2dsZVR5cGVgIGtow7RuZyBjw7JuIG5ndeG7k24gcGjDoXRcbiAgICogdOG7qyB0aMawIHZp4buHbjsgbsahaSBkw7luZyB04buxIGfhu41pIGByZW1vdmVCbG9ja2AgwrcgYGFkZEJsb2NrYCDCtyBgdG9nZ2xlVHlwZWAgY+G7p2Egc2VydmljZS5cbiAgICovXG4gIHJlYWRvbmx5IGhpZGRlblRvb2xiYXIgPSBpbnB1dDxib29sZWFuLCBib29sZWFuIHwgdW5kZWZpbmVkPihmYWxzZSwgeyB0cmFuc2Zvcm06ICh2YWx1ZSkgPT4gdmFsdWUgPz8gZmFsc2UgfSk7XG5cbiAgLyoqXG4gICAqIFRlbXBsYXRlIHThu7EgduG6vSB0aGFuaCBjw7RuZyBj4bulLCB0aGF5IGNobyBi4buZIG7DunQgbeG6t2MgxJHhu4tuaC5cbiAgICpcbiAgICogTmjhuq1uIGNvbnRleHQgYHsgJGltcGxpY2l0OiBub2RlLCBpc0NvbnRhaW5lciwgY2FuQWRkSW5zaWRlLCBjYW5Ub2dnbGVUeXBlIH1gIMSR4buDIG7GoWkgZMO5bmcgduG6vSDEkcO6bmdcbiAgICogbsO6dCBjaG8gdOG7q25nIGto4buRaSwgcuG7k2kgZ+G7jWkgbmfGsOG7o2MgcXVhIGBvdXRSZW1vdmVOb2RlYCDCtyBgb3V0QWRkQmxvY2tJbnNpZGVgIMK3IGBvdXRUb2dnbGVUeXBlYFxuICAgKiBi4bqxbmcgY2jDrW5oIGPDoWMgaMOgbSB0cm9uZyBjb250ZXh0LiBUcnV54buBbiBj4bqjIGBoaWRkZW5Ub29sYmFyYCB2w6AgYHRlbXBsYXRlVG9vbGJhcmAgdGjDrFxuICAgKiBgaGlkZGVuVG9vbGJhcmAgdGjhuq9uZyDigJQga2jDtG5nIHbhur0gZ8OsLlxuICAgKi9cbiAgcmVhZG9ubHkgdGVtcGxhdGVUb29sYmFyID0gaW5wdXQ8VGVtcGxhdGVSZWY8VF9ncmlkTGF5b3V0X3Rvb2xiYXJDb250ZXh0PiB8IHVuZGVmaW5lZD4odW5kZWZpbmVkKTtcblxuICAvKipcbiAgICogQuG7kSBj4bulYyB24burYSDEkeG7lWkgZG8gTkfGr+G7nEkgRMOZTkcga8OpbyBob+G6t2MgxJHhu5VpIGvDrWNoIHRoxrDhu5tjIGto4buRaS5cbiAgICpcbiAgICogTsahaSBkw7luZyB04buxIGfhu41pIGBhZGRCbG9ja2AgwrcgYHJlbW92ZUJsb2NrYCDCtyBgY29tcGFjdGAgdGjDrCBLSMOUTkcgYuG6r24g4oCUIGjhu40gduG7q2EgZ+G7jWkgdGjDrCDEkcOjIGJp4bq/dCxcbiAgICogYuG6r24gbmfGsOG7o2MgbOG6oWkgbMOgIHRo4burYSAobmfGsOG7nWkgZMO5bmcgY2jhu5F0IDI4LzA4LzIwMjYpLlxuICAgKi9cbiAgcmVhZG9ubHkgb3V0Q2hhbmdlID0gb3V0cHV0PFRfZ3JpZExheW91dF9jaGFuZ2VFdmVudD4oKTtcbiAgLyoqXG4gICAqIE5nxrDhu51pIGTDuW5nIGLhuqVtIG7DunQgWE/DgSB0csOqbiBt4buZdCBraOG7kWkuIFRoxrAgdmnhu4duIENIxq9BIHhvw6Eg4oCUIGfhu41pIGBldmVudC5jb25maXJtKClgIMSR4buDIHhvw6EgdGjhuq10LlxuICAgKiBD4bqnbiBo4buPaSB0csaw4bubYyB0aMOsIGjhu49pIHhvbmcgbeG7m2kgZ+G7jWk7IGtow7RuZyBjaG8gcGjDqXAgdGjDrCDEkeG7q25nIGfhu41pLlxuICAgKi9cbiAgcmVhZG9ubHkgb3V0UmVtb3ZlTm9kZSA9IG91dHB1dDxUX2dyaWRMYXlvdXRfYWN0aW9uRXZlbnQ+KCk7XG4gIC8qKlxuICAgKiBOZ8aw4budaSBkw7luZyBi4bqlbSBuw7p0IFRIw4pNIHRyw6puIG3hu5l0IGNvbnRhaW5lci4gVGjGsCB2aeG7h24gS0jDlE5HIHThu7EgdGjDqm0g4oCUIG7DsyBraMO0bmcgYmnhur90IGLhuqFuIGPDs1xuICAgKiBuaOG7r25nIGxv4bqhaSBraOG7kWkgbsOgby4gTeG7nyBtZW51IGNo4buNbiBsb+G6oWkgcuG7k2kgZ+G7jWkgYGV2ZW50LmNvbmZpcm0oaXRlbSlgIHbhu5tpIGto4buRaSBi4bqhbiBtdeG7kW4gdGjDqm0uXG4gICAqL1xuICByZWFkb25seSBvdXRBZGRCbG9ja0luc2lkZSA9IG91dHB1dDxUX2dyaWRMYXlvdXRfYWRkRXZlbnQ+KCk7XG4gIC8qKiBOZ8aw4budaSBkw7luZyBi4bqlbSBuw7p0IEfhu5hQL1TDgUNILiBUaMawIHZp4buHbiBjaMawYSBsw6BtIGfDrCDigJQgZ+G7jWkgYGV2ZW50LmNvbmZpcm0oKWAgxJHhu4MgdGjhu7FjIGhp4buHbi4gKi9cbiAgcmVhZG9ubHkgb3V0VG9nZ2xlVHlwZSA9IG91dHB1dDxUX2dyaWRMYXlvdXRfYWN0aW9uRXZlbnQ+KCk7XG5cbiAgLyoqIELhuq10IHTDrW5oIG7Eg25nIHRodSBwaMOzbmcgKHpvb20pIGNhbnZhcy4gQ2jhu4kgw6FwIGThu6VuZyBjaG8gY2FudmFzIGfhu5FjIChkZXB0aCAwKS4gKi9cbiAgcmVhZG9ubHkgZW5hYmxlWm9vbSA9IGlucHV0PGJvb2xlYW4sIGJvb2xlYW4gfCB1bmRlZmluZWQ+KGZhbHNlLCB7IHRyYW5zZm9ybTogKHZhbHVlKSA9PiB2YWx1ZSA/PyBmYWxzZSB9KTtcblxuICAvKiogVOG7tyBs4buHIHRodSBwaMOzbmcgaGnhu4duIHThuqFpICho4buXIHRy4bujIHR3by13YXkgYmluZGluZyBbKHpvb20pXT1cIm15Wm9vbVwiKS4gKi9cbiAgcmVhZG9ubHkgem9vbSA9IG1vZGVsPG51bWJlciB8IHVuZGVmaW5lZD4odW5kZWZpbmVkKTtcblxuICAvKiogR2nhu5tpIGjhuqFuIHRodSBwaMOzbmcgdOG7kWkgdGhp4buDdS4gTeG6t2MgxJHhu4tuaCAwLjQgKDQwJSkuICovXG4gIHJlYWRvbmx5IHpvb21NaW4gPSBpbnB1dDxudW1iZXI+KDAuNCk7XG5cbiAgLyoqIEdp4bubaSBo4bqhbiB0aHUgcGjDs25nIHThu5FpIMSRYS4gTeG6t2MgxJHhu4tuaCAxLjUgKDE1MCUpLiAqL1xuICByZWFkb25seSB6b29tTWF4ID0gaW5wdXQ8bnVtYmVyPigxLjUpO1xuXG4gIC8qKiBCxrDhu5tjIG5o4bqjeSB0aHUgcGjDs25nIG3hu5dpIGzhuqduIGLhuqVtICsvLSBob+G6t2MgbMSDbiBjaHXhu5l0LiBN4bq3YyDEkeG7i25oIDAuMDUgKDUlKS4gKi9cbiAgcmVhZG9ubHkgem9vbVN0ZXAgPSBpbnB1dDxudW1iZXI+KDAuMDUpO1xuXG4gIC8qKiBDaGnhu4F1IHLhu5luZyBjaHXhuqluIGPhu6dhIGNhbnZhcyBzdGFnZSB0w61uaCBi4bqxbmcgcHguIE3hurdjIMSR4buLbmggMTY2OC4gKi9cbiAgcmVhZG9ubHkgc3RhZ2VXaWR0aCA9IGlucHV0PG51bWJlcj4oMTY2OCk7XG5cbiAgLyoqIENoaeG7gXUgY2FvIHThu5FpIHRoaeG7g3UgY+G7p2EgY2FudmFzIHN0YWdlIHTDrW5oIGLhurFuZyBweC4gTeG6t2MgxJHhu4tuaCA5MzcuICovXG4gIHJlYWRvbmx5IHN0YWdlTWluSGVpZ2h0ID0gaW5wdXQ8bnVtYmVyPig5MzcpO1xuXG4gIC8qKiBLaMOzYSBsxrB1IHThu7cgbOG7hyB0aHUgcGjDs25nIHbDoG8gbG9jYWxTdG9yYWdlLiBN4bq3YyDEkeG7i25oICdvY2JfYmlfY2FudmFzX3pvb20nLiAqL1xuICByZWFkb25seSBzdG9yYWdlS2V5ID0gaW5wdXQ8c3RyaW5nIHwgdW5kZWZpbmVkPignb2NiX2JpX2NhbnZhc196b29tJyk7XG5cbiAgLyoqIEhp4buDbiB0aOG7iyB0aGFuaCBkb2NrIMSRaeG7gXUga2hp4buDbiB0aHUgcGjDs25nIG7hu5VpIOG7nyBnw7NjIGTGsOG7m2kgcGjhuqNpLiBN4bq3YyDEkeG7i25oIHRydWUuICovXG4gIHJlYWRvbmx5IHNob3dab29tRG9jayA9IGlucHV0PGJvb2xlYW4sIGJvb2xlYW4gfCB1bmRlZmluZWQ+KHRydWUsIHsgdHJhbnNmb3JtOiAodmFsdWUpID0+IHZhbHVlID8/IHRydWUgfSk7XG5cbiAgLyoqIFThu7EgxJHhu5luZyB24burYSBtw6BuIGjDrG5oIGtoaSB04bqjaSB0cmFuZyBs4bqnbiDEkeG6p3UgbuG6v3Uga2h1bmcgbmjDrG4gbmjhu48gaMahbiBzdGFnZVdpZHRoLiBN4bq3YyDEkeG7i25oIHRydWUuICovXG4gIHJlYWRvbmx5IGF1dG9GaXRPbkxvYWQgPSBpbnB1dDxib29sZWFuLCBib29sZWFuIHwgdW5kZWZpbmVkPih0cnVlLCB7IHRyYW5zZm9ybTogKHZhbHVlKSA9PiB2YWx1ZSA/PyB0cnVlIH0pO1xuXG4gIC8qKiBQaMOhdCByYSBraGkgdOG7tyBs4buHIHRodSBwaMOzbmcgdGhheSDEkeG7lWkuICovXG4gIHJlYWRvbmx5IG91dFpvb21DaGFuZ2UgPSBvdXRwdXQ8bnVtYmVyPigpO1xuXG4gIC8qKiBC4bqtdCB0w61uaCBuxINuZyBrw6lvIHRo4bqjIHRo4bq7IHThu6sgYsOqbiBuZ2/DoGkgdsOgbyBjYW52YXMgKG3hurdjIMSR4buLbmggdHJ1ZSkgKi9cbiAgcmVhZG9ubHkgZW5hYmxlRXh0ZXJuYWxEcm9wID0gaW5wdXQ8Ym9vbGVhbiwgYm9vbGVhbiB8IHVuZGVmaW5lZD4odHJ1ZSwgeyB0cmFuc2Zvcm06ICh2YWx1ZSkgPT4gdmFsdWUgPz8gdHJ1ZSB9KTtcblxuICAvKiogTHXDtG4gaGnhu4NuIHRo4buLIMSRxrDhu51uZyBr4bq7IGzGsOG7m2kgMjQgY+G7mXQgKi9cbiAgcmVhZG9ubHkgc2hvd0dyaWRMaW5lcyA9IGlucHV0PGJvb2xlYW4sIGJvb2xlYW4gfCB1bmRlZmluZWQ+KGZhbHNlLCB7IHRyYW5zZm9ybTogKHZhbHVlKSA9PiB2YWx1ZSA/PyBmYWxzZSB9KTtcblxuICAvKiogTcOjIGlkIGPhu6dhIGto4buRaSDEkWFuZyDEkcaw4bujYyBjaOG7jW4gKi9cbiAgcmVhZG9ubHkgc2VsZWN0ZWROb2RlSWQgPSBtb2RlbDxzdHJpbmcgfCBudWxsIHwgdW5kZWZpbmVkPih1bmRlZmluZWQpO1xuXG4gIC8qKiBQaMOhdCByYSBraGkgdGjhuqMgbeG7mXQgdGjhursgbeG7m2kgdOG7qyBiw6puIG5nb8OgaSB2w6BvIGNhbnZhcyAqL1xuICByZWFkb25seSBvdXREcm9wTm9kZSA9IG91dHB1dDxUX2dyaWRMYXlvdXRfZHJvcEV2ZW50PigpO1xuXG4gIC8qKiBQaMOhdCByYSBraGkgbmfGsOG7nWkgZMO5bmcgY2xpY2sgY2jhu41uIG3hu5l0IGto4buRaSAqL1xuICByZWFkb25seSBvdXRTZWxlY3ROb2RlID0gb3V0cHV0PFRfZ3JpZExheW91dF9ub2RlPigpO1xuXG4gIC8qKiBQaMOhdCByYSBraGkgbmfGsOG7nWkgZMO5bmcgYuG6pW0gbsO6dCBj4bqldSBow6xuaCB0csOqbiB0aGFuaCBjw7RuZyBj4bulIGPhu6dhIGto4buRaSAqL1xuICByZWFkb25seSBvdXRDb25maWdOb2RlID0gb3V0cHV0PFRfZ3JpZExheW91dF9hY3Rpb25FdmVudD4oKTtcblxuICBwcml2YXRlIHJlYWRvbmx5IGdyaWRzdGVyUmVmID0gdmlld0NoaWxkKEdyaWRzdGVyQ29tcG9uZW50KTtcbiAgcHJpdmF0ZSByZWFkb25seSBzY3JvbGxBcmVhUmVmID0gdmlld0NoaWxkPEVsZW1lbnRSZWY8SFRNTEVsZW1lbnQ+Pignc2Nyb2xsQXJlYScpO1xuICBwcml2YXRlIHJlYWRvbmx5IHpvb21Eb2NrUmVmID0gdmlld0NoaWxkPEVsZW1lbnRSZWY8SFRNTEVsZW1lbnQ+Pignem9vbURvY2snKTtcbiAgLyoqIG3hu5dpIMO0IG3hu5l0IGNo4buXIGfhuq9uIHJpw6puZyDigJQgY8O5bmcgdGjhu6kgdOG7sSB24bubaSBgY2hpbGRyZW4oKWAgKi9cbiAgcHJpdmF0ZSByZWFkb25seSBpdGVtSG9zdHMgPSB2aWV3Q2hpbGRyZW4oJ2l0ZW1Ib3N0JywgeyByZWFkOiBWaWV3Q29udGFpbmVyUmVmIH0pO1xuXG4gIC8qKiBLaHVuZyB4ZW0gdHLGsOG7m2MgduG7iyB0csOtIHRo4bqjIHRo4bq7IHThu6sgYsOqbiBuZ2/DoGkgKHNuYXBwZWQgZ2hvc3QgcHJldmlldykgKi9cbiAgcHJvdGVjdGVkIHJlYWRvbmx5IGRyb3BHaG9zdCA9IHNpZ25hbDxUX2dyaWRMYXlvdXRfZHJvcEdob3N0IHwgdW5kZWZpbmVkPih1bmRlZmluZWQpO1xuXG4gIHByaXZhdGUgYWN0aXZlSG92ZXJlZEVsPzogSFRNTEVsZW1lbnQ7XG4gIHByaXZhdGUgcm9vdEdyaWRzdGVyRWw/OiBIVE1MRWxlbWVudDtcblxuICAvKiogTWVudSBjaOG7jW4gcHJlc2V0IHRodSBwaMOzbmcgxJFhbmcgbeG7nyBoYXkgxJHDs25nICovXG4gIHByb3RlY3RlZCByZWFkb25seSBpc01lbnVPcGVuID0gc2lnbmFsPGJvb2xlYW4+KGZhbHNlKTtcblxuICAvKiogQ8OhYyBt4buRYyB0aHUgcGjDs25nIMSR4buLbmggc+G6tW4gKi9cbiAgcHJvdGVjdGVkIHJlYWRvbmx5IHpvb21QcmVzZXRzOiBBcnJheTxUX2dyaWRMYXlvdXRfem9vbVByZXNldD4gPSBbXG4gICAgeyBsYWJlbDogJ2kxOG5fem9vbV9wcmVzZXRfb3ZlcnZpZXcnLCB2YWx1ZTogMC41IH0sXG4gICAgeyBsYWJlbDogJ2kxOG5fem9vbV9wcmVzZXRfc21hbGxfbGFwdG9wJywgdmFsdWU6IDAuNjcgfSxcbiAgICB7IGxhYmVsOiAnaTE4bl96b29tX3ByZXNldF9sYXB0b3BfMTA4MHAnLCB2YWx1ZTogMC43NSB9LFxuICAgIHsgbGFiZWw6ICdpMThuX3pvb21fcHJlc2V0X3NjcmVlbl8xMDgwcCcsIHZhbHVlOiAwLjg1IH0sXG4gICAgeyBsYWJlbDogJ2kxOG5fem9vbV9wcmVzZXRfc3RhbmRhcmQnLCB2YWx1ZTogMC45IH0sXG4gICAgeyBsYWJlbDogJ2kxOG5fem9vbV9wcmVzZXRfb3JpZ2luYWxfc2l6ZScsIHZhbHVlOiAxIH0sXG4gICAgeyBsYWJlbDogJ2kxOG5fem9vbV9wcmVzZXRfbGFyZ2Vfc2NyZWVuJywgdmFsdWU6IDEuMSB9LFxuICAgIHsgbGFiZWw6ICdpMThuX3pvb21fcHJlc2V0X2hpZ2hfZHBpXzJrJywgdmFsdWU6IDEuMjUgfSxcbiAgXTtcblxuICAvKiogU8OhdSBjaOG6pW0gY+G7p2EgdGF5IGPhuqdtIGvDqW8g4oCUIGNo4buJIMSR4buDIGBAZm9yYCBk4buxbmcgxJHhu6cgNiB0aOG6uywgZ2nDoSB0cuG7iyBraMO0bmcgZMO5bmcgdOG7m2kuICovXG4gIHByb3RlY3RlZCByZWFkb25seSBkcmFnQmFyRG90cyA9IFswLCAxLCAyLCAzLCA0LCA1XTtcblxuICBwcml2YXRlIHJlYWRvbmx5IHNlcnZpY2UgPSBpbmplY3QoTGlic1VpR3JpZExheW91dFNlcnZpY2UpO1xuXG4gIC8qKiBDaOG6vyDEkeG7mSB0aHUgcGjDs25nIGPDsyDEkWFuZyBob+G6oXQgxJHhu5luZyB0csOqbiBjYW52YXMgbsOgeSBraMO0bmcgKGNo4buJIHJvb3QgY2FudmFzIGRlcHRoIDApICovXG4gIHByb3RlY3RlZCByZWFkb25seSBpc1pvb21BY3RpdmUgPSBjb21wdXRlZCgoKSA9PiB7XG4gICAgcmV0dXJuIHRoaXMuZGVwdGgoKSA9PT0gMCAmJiAodGhpcy5lbmFibGVab29tKCkgfHwgdGhpcy5zZXJ2aWNlLkZ1bmN0aW9uc0NvbnRyb2wuaXNab29tRW5hYmxlZCgpKTtcbiAgfSk7XG5cbiAgcHJvdGVjdGVkIHJlYWRvbmx5IGN1cnJlbnRab29tID0gY29tcHV0ZWQoKCkgPT4gdGhpcy5zZXJ2aWNlLlpvb20oKSk7XG4gIHByb3RlY3RlZCByZWFkb25seSB6b29tUGVyY2VudCA9IGNvbXB1dGVkKCgpID0+IE1hdGgucm91bmQodGhpcy5jdXJyZW50Wm9vbSgpICogMTAwKSk7XG5cbiAgLyoqXG4gICAqIE5vZGUgVEjhuqxUIGPhu6dhIG3hurd0IHBo4bqzbmcgbsOgeS5cbiAgICpcbiAgICog8J+UtCBN4bq3dCBwaOG6s25nIEfhu5BDIChkZXB0aCAwKSDEkeG7jWMgY8OieSB04burIFNFUlZJQ0UsIGtow7RuZyBkw7luZyBpbnB1dC5cbiAgICogTsahaSBkw7luZyB0aMaw4budbmcgc+G7rWEgY8OieSBU4bqgSSBDSOG7liAoYHRyZWVTZXJ2aWNlLmNvbXBhY3QodHJlZSlgKSBy4buTaSBn4buNaSBgcmVmcmVzaCgpYCwgbsOqbiBzaWduYWxcbiAgICogYHJvb3QoKWAgY+G7p2EgaOG7jSBnaeG7ryBuZ3V5w6puIHRoYW0gY2hp4bq/dSB2w6AgaW5wdXQgYG5vZGVgIGtow7RuZyBo4buBIMSR4buVaSDigJQgYEBmb3JgIGtow7RuZyBk4buxbmcgbOG6oWlcbiAgICogYGdyaWRzdGVyLWl0ZW1gLCBsxrDhu5tpIMSR4bupbmcgaW0gZMO5IGThu68gbGnhu4d1IMSRw6Mga2jDoWMgKMSRbyAyOC8wOC8yMDI2OiBi4bqlbSBcIlPhuq9wIGfhu41uXCIga2jDtG5nIHTDoWMgZOG7pW5nKS5cbiAgICogYHJlZnJlc2goKWAgY+G7p2Egc2VydmljZSB0aGF5IHRoYW0gY2hp4bq/dSBjw6J5LCBuw6puIMSR4buNYyB04burIMSRw7MgbeG7m2kgdGjhuqV5IHRoYXkgxJHhu5VpLlxuICAgKlxuICAgKiBN4bq3dCBwaOG6s25nIEzhu5JORyB24bqrbiBkw7luZyBpbnB1dDogbsOzIG5o4bqtbiBub2RlIGNvbiB04burIG3hurd0IHBo4bqzbmcgY2hhLCB24buRbiDEkcOjIGzDoCBvYmplY3QgbeG7m2kuXG4gICAqL1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgY3VycmVudE5vZGUgPSBjb21wdXRlZCgoKSA9PiB7XG4gICAgdGhpcy5zZXJ2aWNlLlZlcnNpb24oKTtcblxuICAgIGlmICh0aGlzLmRlcHRoKCkgPiAwKSB7XG4gICAgICByZXR1cm4gdGhpcy5ub2RlKCkgPz8gZW1wdHlSb290Tm9kZSgpO1xuICAgIH1cblxuICAgIHJldHVybiB0aGlzLnNlcnZpY2UuUm9vdCgpID8/IGVtcHR5Um9vdE5vZGUoKTtcbiAgfSk7XG5cbiAgcHJvdGVjdGVkIHJlYWRvbmx5IGNoaWxkcmVuID0gY29tcHV0ZWQoKCkgPT4gdGhpcy5jdXJyZW50Tm9kZSgpLmNoaWxkcmVuID8/IFtdKTtcblxuICAvKipcbiAgICogQuG7kWkgY+G6o25oIGNobyBgdGVtcGxhdGVUb29sYmFyYCwgZOG7sW5nIHPhurVuIHRoZW8gdOG7q25nIGto4buRaS5cbiAgICpcbiAgICogROG7sW5nIOG7nyBgY29tcHV0ZWRgIGNo4bupIGtow7RuZyBn4buNaSBow6BtIHRyw6puIHRlbXBsYXRlOiBn4buNaSBow6BtIHRyb25nIHRlbXBsYXRlIGNo4bqheSBs4bqhaSBt4buXaSB2w7JuZ1xuICAgKiBkw7IgdGhheSDEkeG7lWkgKHJ1bGUgYGZlLWNvZGluZy1jb252ZW50aW9uLXRlbXBsYXRlc2AgbeG7pWMgNikuXG4gICAqL1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgdG9vbGJhckNvbnRleHRzID0gY29tcHV0ZWQ8QXJyYXk8VF9ncmlkTGF5b3V0X3Rvb2xiYXJDb250ZXh0Pj4oKCkgPT5cbiAgICB0aGlzLmNoaWxkcmVuKCkubWFwKChpdGVtKSA9PiAoe1xuICAgICAgJGltcGxpY2l0OiBpdGVtLFxuICAgICAgaXNDb250YWluZXI6IHRoaXMuaXNDb250YWluZXIoaXRlbSksXG4gICAgICBjYW5BZGRJbnNpZGU6IHRoaXMuY2FuQWRkSW5zaWRlKGl0ZW0pLFxuICAgICAgY2FuVG9nZ2xlVHlwZTogdGhpcy5jYW5Ub2dnbGVUeXBlKGl0ZW0pLFxuICAgICAgcmVtb3ZlOiAoKSA9PiB0aGlzLm91dFJlbW92ZU5vZGUuZW1pdCh7IG5vZGVJZDogaXRlbS5pZCwgbm9kZTogaXRlbSwgY29uZmlybTogKCkgPT4gdGhpcy5zZXJ2aWNlLnJlbW92ZUJsb2NrKGl0ZW0uaWQpIH0pLFxuICAgICAgYWRkSW5zaWRlOiAoKSA9PiB0aGlzLmVtaXRBZGRJbnNpZGUoaXRlbSksXG4gICAgICB0b2dnbGVUeXBlOiAoKSA9PiB0aGlzLmVtaXRUb2dnbGVUeXBlKGl0ZW0pLFxuICAgIH0pKVxuICApO1xuXG4gIHByb3RlY3RlZCByZWFkb25seSBpc05lc3RlZENhbnZhcyA9IGNvbXB1dGVkKCgpID0+IHRoaXMuZGVwdGgoKSA+IDApO1xuXG4gIC8qKiB0cuG6p24gbOG7k25nIGNvbnRhaW5lciDigJQga2jhu5FpIMSRw6MgY2jhuqFtIHRy4bqnbiB0aMOsIGtow7RuZyBjaG8gY2h1eeG7g24gdGjDoG5oIGNvbnRhaW5lciAqL1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgbWF4Q29udGFpbmVyRGVwdGggPSBjb21wdXRlZCgoKSA9PiB0aGlzLnNlcnZpY2UuRnVuY3Rpb25zQ29udHJvbC5tYXhDb250YWluZXJEZXB0aCgpKTtcblxuICAvKipcbiAgICogTOG7gSB0cm9uZyBj4bunYSBjb250YWluZXIsIHB4LlxuICAgKlxuICAgKiDwn5S0IMSQ4bq3dCB0csOqbiBW4buOIGNvbnRhaW5lciwga2jDtG5nIMSR4bq3dCB2w6BvIGzGsOG7m2kgY29uLiBMxrDhu5tpIGNvbiBnaeG7ryBuZ3V5w6puIGBtYXJnaW46IDJgIG5oxrAgY8WpOyBs4buBXG4gICAqIG7DoHkgY2jhu4kgY28gcnXhu5l0IGzhuqFpIGto4buPaSBiacOqbiB24buPLCBuaOG7nSDEkcOzIHRheSBj4bqnbSDEkeG7lWkga8OtY2ggdGjGsOG7m2MgY+G7p2Ega2jhu5FpIGNvbiBsdcO0biBu4bqxbSB0cm9uZyB04bqnbVxuICAgKiBjaHXhu5l0IChuZ8aw4budaSBkw7luZyBjaOG7kXQgMjgvMDgvMjAyNikuXG4gICAqL1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgY29udGFpbmVyUGFkZGluZyA9IGNvbXB1dGVkKCgpID0+IGAke3RoaXMuc2VydmljZS5GdW5jdGlvbnNDb250cm9sLmNvbnRhaW5lclBhZGRpbmcoKX1weGApO1xuXG4gIC8qKiBE4bqjaSBrw6lvIGNo4buJIGhp4buHbiDhu58gY2jhur8gxJHhu5kgc+G7rWEg4oCUIGNo4bq/IMSR4buZIHhlbSBraMO0bmcga8OpbyDEkcaw4bujYyBuw6puIGhp4buHbiBk4bqjaSBsw6AgZ8OieSBuaOG6p20uICovXG4gIHByb3RlY3RlZCByZWFkb25seSBpc0VkaXRNb2RlID0gY29tcHV0ZWQoKCkgPT4gdGhpcy5zZXJ2aWNlLklzRWRpdE1vZGUoKSk7XG5cbiAgcHJvdGVjdGVkIHJlYWRvbmx5IGdyaWRPcHRpb25zID0gY29tcHV0ZWQoKCkgPT4ge1xuICAgIC8vIMSQ4buNYyBgVmVyc2lvbmAgxJHhu4MgYGluaXQoKWAgbOG6oWkgKMSR4buVaSBjaOG6vyDEkeG7mSwgYuG6rXQvdOG6r3QgY2jhu5NuZyBraOG7kWkpIHNpbmggcmEgb3B0aW9ucyBN4buaSSDigJRcbiAgICAvLyBncmlkc3RlciBjaOG7iSDDoXAgZOG7pW5nIGPhuqV1IGjDrG5oIGtoaSB0aGFtIGNoaeG6v3UgYG9wdGlvbnNgIMSR4buVaS5cbiAgICB0aGlzLnNlcnZpY2UuVmVyc2lvbigpO1xuXG4gICAgcmV0dXJuIHRoaXMuc2VydmljZS5GdW5jdGlvbnNDb250cm9sLmdyaWRzdGVyT3B0aW9ucyh0aGlzLmRlcHRoKCksICgpID0+IHRoaXMub3V0Q2hhbmdlLmVtaXQoeyByb290OiB0aGlzLmN1cnJlbnROb2RlKCkgfSkpO1xuICB9KTtcblxuICBjb25zdHJ1Y3RvcigpIHtcbiAgICAvLyBH4bqvbiBjb21wb25lbnQgY+G7p2EgbsahaSBkw7luZyB2w6BvIHThu6tuZyDDtCwgdsOgIGfhuq9uIEzhuqBJIG3hu5dpIGtoaSBjw6J5IMSR4buVaS5cbiAgICAvLyBEw7luZyBlZmZlY3QgdsOsIGBpdGVtSG9zdHMoKWAgY2jhu4kgY8OzIGdpw6EgdHLhu4sgc2F1IGtoaSBBbmd1bGFyIGThu7FuZyB4b25nIEBmb3IuXG4gICAgZWZmZWN0KCgpID0+IHtcbiAgICAgIGNvbnN0IGhvc3RzID0gdGhpcy5pdGVtSG9zdHMoKTtcbiAgICAgIGNvbnN0IGl0ZW1zID0gdGhpcy5jaGlsZHJlbigpO1xuXG4gICAgICBpdGVtcy5mb3JFYWNoKChpdGVtLCBpKSA9PiB7XG4gICAgICAgIGNvbnN0IGhvc3QgPSBob3N0c1tpXTtcblxuICAgICAgICBpZiAoIWhvc3QpIHtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICAvLyBLaOG7kWkgY8OzIGNvbiBsw6AgQ09OVEFJTkVSOiBydeG7mXQgbsOzIGRvIG3hurd0IHBo4bqzbmcgbOG7k25nIHbhur0sIGtow7RuZyBn4bqvbiBjb21wb25lbnQgbuG7mWkgZHVuZy5cbiAgICAgICAgaWYgKChpdGVtLmNoaWxkcmVuPy5sZW5ndGggPz8gMCkgPiAwKSB7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5zZXJ2aWNlLkZ1bmN0aW9uc0NvbnRyb2wuYXR0YWNoTm9kZShpdGVtLCB0aGlzLmRlcHRoKCkgKyAxLCBob3N0KTtcbiAgICAgIH0pO1xuICAgIH0pO1xuXG4gICAgLy8gxJDhu5NuZyBi4buZIG7hur91IG1vZGVsIHpvb20gYsOqbiBuZ2/DoGkgdGhheSDEkeG7lWlcbiAgICBlZmZlY3QoKCkgPT4ge1xuICAgICAgY29uc3QgeiA9IHRoaXMuem9vbSgpO1xuICAgICAgaWYgKHogIT09IHVuZGVmaW5lZCAmJiBNYXRoLmFicyh6IC0gdGhpcy5zZXJ2aWNlLlpvb20oKSkgPiAwLjAwMSkge1xuICAgICAgICB0aGlzLnNlcnZpY2UuRnVuY3Rpb25zQ29udHJvbC5zZXRab29tKHosIHRoaXMuc3RvcmFnZUtleSgpKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgfVxuXG4gIG5nQWZ0ZXJWaWV3SW5pdCgpOiB2b2lkIHtcbiAgICBpZiAoIXRoaXMuaXNab29tQWN0aXZlKCkgfHwgIXRoaXMuYXV0b0ZpdE9uTG9hZCgpKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3Qga2V5ID0gdGhpcy5zdG9yYWdlS2V5KCk7XG4gICAgbGV0IGhhc1NhdmVkID0gZmFsc2U7XG4gICAgaWYgKGtleSAmJiB0eXBlb2YgbG9jYWxTdG9yYWdlICE9PSAndW5kZWZpbmVkJykge1xuICAgICAgdHJ5IHtcbiAgICAgICAgaGFzU2F2ZWQgPSBCb29sZWFuKGxvY2FsU3RvcmFnZS5nZXRJdGVtKGtleSkpO1xuICAgICAgfSBjYXRjaCB7XG4gICAgICAgIC8vIGlnbm9yZSBsb2NhbFN0b3JhZ2UgYWNjZXNzIGVycm9yXG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKCFoYXNTYXZlZCkge1xuICAgICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgIGNvbnN0IHNjcm9sbEVsID0gdGhpcy5zY3JvbGxBcmVhUmVmKCk/Lm5hdGl2ZUVsZW1lbnQ7XG4gICAgICAgIGlmIChzY3JvbGxFbCAmJiBzY3JvbGxFbC5jbGllbnRXaWR0aCA+IDAgJiYgc2Nyb2xsRWwuY2xpZW50V2lkdGggPCB0aGlzLnN0YWdlV2lkdGgoKSArIDY0KSB7XG4gICAgICAgICAgdGhpcy5oYW5kbGVyRml0U2NyZWVuKCk7XG4gICAgICAgIH1cbiAgICAgIH0sIDUwKTtcbiAgICB9XG4gIH1cblxuICBuZ09uRGVzdHJveSgpOiB2b2lkIHtcbiAgICB0aGlzLmNsZWFudXBEcmFnR3JpZCgpO1xuICAgIGZvciAoY29uc3QgaXRlbSBvZiB0aGlzLmNoaWxkcmVuKCkpIHtcbiAgICAgIHRoaXMuc2VydmljZS5GdW5jdGlvbnNDb250cm9sLmRldGFjaE5vZGUoaXRlbS5pZCk7XG4gICAgfVxuICB9XG5cbiAgLyoqIFbhur0gbOG6oWkgbMaw4bubaSDigJQgZ+G7jWkga2hpIGtodW5nIG5nb8OgaSDEkeG7lWkga8OtY2ggdGjGsOG7m2MgaG/hurdjIGPDonkgduG7q2EgxJHhu5VpIGRp4buHbiBy4buZbmcuICovXG4gIGdldCBGdW5jdGlvbkNvbnRyb2woKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIHZlTGFpTHVvaTogKCkgPT4gdGhpcy5ncmlkc3RlclJlZigpPy5vcHRpb25zQ2hhbmdlZCgpLFxuICAgICAgem9vbUluOiAoKSA9PiB0aGlzLmhhbmRsZXJab29tSW4oKSxcbiAgICAgIHpvb21PdXQ6ICgpID0+IHRoaXMuaGFuZGxlclpvb21PdXQoKSxcbiAgICAgIHJlc2V0Wm9vbTogKCkgPT4gdGhpcy5oYW5kbGVyUmVzZXRab29tKCksXG4gICAgICBmaXRUb1NjcmVlbjogKCkgPT4gdGhpcy5oYW5kbGVyRml0U2NyZWVuKCksXG4gICAgICBzZXRab29tOiAodmFsOiBudW1iZXIpID0+IHtcbiAgICAgICAgdGhpcy5zZXJ2aWNlLkZ1bmN0aW9uc0NvbnRyb2wuc2V0Wm9vbSh2YWwsIHRoaXMuc3RvcmFnZUtleSgpKTtcbiAgICAgICAgdGhpcy5zeW5jWm9vbU91dCgpO1xuICAgICAgfSxcbiAgICAgIC8vIFbDuW5nIGN14buZbiBj4bunYSBt4bq3dCBwaOG6s25nIOKAlCBuxqFpIGTDuW5nIGPhuqduIG7DsyDEkeG7gyB04buxIGN14buZbiB04bubaSBt4buZdCBraOG7kWksIGhv4bq3YyDEkW8gdG/huqEgxJHhu5kga2hpIGvDqW8uXG4gICAgICAvLyBLaMO0bmcgbeG7nyDhu58gxJHDonkgdGjDrCBuxqFpIGTDuW5nIHBo4bqjaSBkw7IgYuG6sW5nIHTDqm4gbOG7m3AgQ1NTIG7hu5lpIGLhu5ksIHbDoCB0w6puIMSRw7MgxJHhu5VpIGzDumMgbsOgbyBraMO0bmcgaGF5LlxuICAgICAgc2Nyb2xsQXJlYTogKCk6IEhUTUxFbGVtZW50IHwgdW5kZWZpbmVkID0+IHRoaXMuc2Nyb2xsQXJlYVJlZigpPy5uYXRpdmVFbGVtZW50LFxuICAgIH07XG4gIH1cblxuICBwcm90ZWN0ZWQgaGFuZGxlclpvb21JbigpOiB2b2lkIHtcbiAgICB0aGlzLnNlcnZpY2UuRnVuY3Rpb25zQ29udHJvbC56b29tSW4odGhpcy56b29tU3RlcCgpLCB0aGlzLnN0b3JhZ2VLZXkoKSk7XG4gICAgdGhpcy5zeW5jWm9vbU91dCgpO1xuICB9XG5cbiAgcHJvdGVjdGVkIGhhbmRsZXJab29tT3V0KCk6IHZvaWQge1xuICAgIHRoaXMuc2VydmljZS5GdW5jdGlvbnNDb250cm9sLnpvb21PdXQodGhpcy56b29tU3RlcCgpLCB0aGlzLnN0b3JhZ2VLZXkoKSk7XG4gICAgdGhpcy5zeW5jWm9vbU91dCgpO1xuICB9XG5cbiAgcHJvdGVjdGVkIGhhbmRsZXJSZXNldFpvb20oKTogdm9pZCB7XG4gICAgdGhpcy5zZXJ2aWNlLkZ1bmN0aW9uc0NvbnRyb2wucmVzZXRab29tKHRoaXMuc3RvcmFnZUtleSgpKTtcbiAgICB0aGlzLnN5bmNab29tT3V0KCk7XG4gIH1cblxuICBwcm90ZWN0ZWQgaGFuZGxlckZpdFNjcmVlbigpOiB2b2lkIHtcbiAgICB0aGlzLmlzTWVudU9wZW4uc2V0KGZhbHNlKTtcbiAgICBjb25zdCBzY3JvbGxFbCA9IHRoaXMuc2Nyb2xsQXJlYVJlZigpPy5uYXRpdmVFbGVtZW50O1xuICAgIGNvbnN0IGNvbnRhaW5lcldpZHRoID0gc2Nyb2xsRWw/LmNsaWVudFdpZHRoIHx8ICh0eXBlb2Ygd2luZG93ICE9PSAndW5kZWZpbmVkJyA/IHdpbmRvdy5pbm5lcldpZHRoIC0gMzAwIDogMTIwMCk7XG4gICAgdGhpcy5zZXJ2aWNlLkZ1bmN0aW9uc0NvbnRyb2wuZml0VG9TY3JlZW4oY29udGFpbmVyV2lkdGgsIHRoaXMuc3RhZ2VXaWR0aCgpLCA0OCwgdGhpcy5zdG9yYWdlS2V5KCkpO1xuICAgIHRoaXMuc3luY1pvb21PdXQoKTtcbiAgfVxuXG4gIHByb3RlY3RlZCBoYW5kbGVyVG9nZ2xlTWVudSgpOiB2b2lkIHtcbiAgICB0aGlzLmlzTWVudU9wZW4udXBkYXRlKChvcGVuKSA9PiAhb3Blbik7XG4gIH1cblxuICBwcm90ZWN0ZWQgaGFuZGxlclNlbGVjdFByZXNldCh2YWx1ZTogbnVtYmVyKTogdm9pZCB7XG4gICAgdGhpcy5pc01lbnVPcGVuLnNldChmYWxzZSk7XG4gICAgdGhpcy5zZXJ2aWNlLkZ1bmN0aW9uc0NvbnRyb2wuc2V0Wm9vbSh2YWx1ZSwgdGhpcy5zdG9yYWdlS2V5KCkpO1xuICAgIHRoaXMuc3luY1pvb21PdXQoKTtcbiAgfVxuXG4gIHByb3RlY3RlZCBpc0N1cnJlbnRQcmVzZXQodmFsdWU6IG51bWJlcik6IGJvb2xlYW4ge1xuICAgIHJldHVybiBNYXRoLmFicyh0aGlzLmN1cnJlbnRab29tKCkgLSB2YWx1ZSkgPCAwLjAxO1xuICB9XG5cbiAgcHJpdmF0ZSBzeW5jWm9vbU91dCgpOiB2b2lkIHtcbiAgICBjb25zdCB2YWwgPSB0aGlzLnNlcnZpY2UuWm9vbSgpO1xuICAgIHRoaXMub3V0Wm9vbUNoYW5nZS5lbWl0KHZhbCk7XG4gICAgaWYgKHRoaXMuem9vbSgpICE9PSB2YWwpIHtcbiAgICAgIHRoaXMuem9vbS5zZXQodmFsKTtcbiAgICB9XG4gIH1cblxuICBwcm90ZWN0ZWQgaGFuZGxlcldoZWVsKGV2ZW50OiBXaGVlbEV2ZW50KTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLmlzWm9vbUFjdGl2ZSgpKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKGV2ZW50LmN0cmxLZXkgfHwgZXZlbnQubWV0YUtleSkge1xuICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgIGlmIChldmVudC5kZWx0YVkgPCAwKSB7XG4gICAgICAgIHRoaXMuaGFuZGxlclpvb21JbigpO1xuICAgICAgfSBlbHNlIGlmIChldmVudC5kZWx0YVkgPiAwKSB7XG4gICAgICAgIHRoaXMuaGFuZGxlclpvb21PdXQoKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBASG9zdExpc3RlbmVyKCdkb2N1bWVudDprZXlkb3duJywgWyckZXZlbnQnXSlcbiAgcHJvdGVjdGVkIGhhbmRsZXJEb2N1bWVudEtleURvd24oZXZlbnQ6IEtleWJvYXJkRXZlbnQpOiB2b2lkIHtcbiAgICBpZiAoIXRoaXMuaXNab29tQWN0aXZlKCkpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAoZXZlbnQuY3RybEtleSB8fCBldmVudC5tZXRhS2V5KSB7XG4gICAgICBpZiAoZXZlbnQua2V5ID09PSAnPScgfHwgZXZlbnQua2V5ID09PSAnKycpIHtcbiAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgdGhpcy5oYW5kbGVyWm9vbUluKCk7XG4gICAgICB9IGVsc2UgaWYgKGV2ZW50LmtleSA9PT0gJy0nIHx8IGV2ZW50LmtleSA9PT0gJ18nKSB7XG4gICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgIHRoaXMuaGFuZGxlclpvb21PdXQoKTtcbiAgICAgIH0gZWxzZSBpZiAoZXZlbnQua2V5ID09PSAnMCcpIHtcbiAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgdGhpcy5oYW5kbGVyUmVzZXRab29tKCk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgQEhvc3RMaXN0ZW5lcignZG9jdW1lbnQ6Y2xpY2snLCBbJyRldmVudCddKVxuICBwcm90ZWN0ZWQgaGFuZGxlckRvY3VtZW50Q2xpY2soZXZlbnQ6IE1vdXNlRXZlbnQpOiB2b2lkIHtcbiAgICBpZiAoIXRoaXMuaXNNZW51T3BlbigpKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3QgZG9ja0VsID0gdGhpcy56b29tRG9ja1JlZigpPy5uYXRpdmVFbGVtZW50O1xuICAgIGlmIChkb2NrRWwgJiYgIWRvY2tFbC5jb250YWlucyhldmVudC50YXJnZXQgYXMgTm9kZSkpIHtcbiAgICAgIHRoaXMuaXNNZW51T3Blbi5zZXQoZmFsc2UpO1xuICAgIH1cbiAgfVxuXG4gIHByb3RlY3RlZCBoYW5kbGVyVHJhY2tOb2RlKF9pbmRleDogbnVtYmVyLCBpdGVtOiBUX2dyaWRMYXlvdXRfbm9kZSk6IHN0cmluZyB7XG4gICAgcmV0dXJuIGl0ZW0uaWQ7XG4gIH1cblxuICAvKipcbiAgICog8J+UtCBDaOG6t24gYG1vdXNlZG93bmAgbuG7lWkgbMOqbiBsxrDhu5tpIENIQSBraGkgdGhhbyB0w6FjIHRyb25nIGzGsOG7m2kgY29uLlxuICAgKiBLaMO0bmcgY2jhurduIHRow6wgY+G6oyBoYWkgbMaw4bubaSBjw7luZyBuaOG6rW4gbeG7mXQgY8O6IGLhuqVtOiBrw6lvIGto4buRaSBjb24gbMOgIG5o4bqlYyBsdcO0biBjb250YWluZXIuXG4gICAqL1xuICAvKipcbiAgICogQ2jhurduIGBtb3VzZWRvd25gIGPhu6dhIGto4buRaSB0cm9uZyBsxrDhu5tpIEzhu5JORyBu4buVaSBsw6puIGzGsOG7m2kgY2hhLlxuICAgKlxuICAgKiBDaOG7iSBjaOG6t24g4bufIGzGsOG7m2kgbOG7k25nOiBsxrDhu5tpIGPhuqVwIHRyYW5nIGtow7RuZyBjw7MgY2hhIG7DoG8gxJHhu4MgY2jhurduLCB2w6AgY2jhurduIOG7nyDEkcOzIHPhur0gbnXhu5F0IGx1w7RuIHRoYW9cbiAgICogdMOhYyBj4bunYSBjaMOtbmggbsOzLlxuICAgKi9cbiAgLyoqXG4gICAqIPCflLQgQmEgaGFuZGxlciBkxrDhu5tpIMSRw6J5IFBI4bqiSSBgc3RvcFByb3BhZ2F0aW9uYC5cbiAgICogTsO6dCBu4bqxbSB0cm9uZyB2w7luZyBtYW5nIGBkcmFnSGFuZGxlQ2xhc3NgLCBraMO0bmcgY2jhurduIHRow6wgY8O6IGLhuqVtIGLhu4sgZ3JpZHN0ZXIgaGnhu4N1IGzDoCBi4bqvdCDEkeG6p3Uga8Opb1xuICAgKiB2w6AgYGRlbGF5U3RhcnQ6IDE2MGAgbnXhu5F0IGx1w7RuIGBjbGlja2Ag4oCUIG5nxrDhu51pIGTDuW5nIHRo4bqleSBuaMawIG7DunQgY2jhur90LlxuICAgKi9cbiAgcHJvdGVjdGVkIGhhbmRsZXJSZW1vdmUoZXZlbnQ6IEV2ZW50LCBub2RlOiBUX2dyaWRMYXlvdXRfbm9kZSk6IHZvaWQge1xuICAgIGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgdGhpcy5vdXRSZW1vdmVOb2RlLmVtaXQoeyBub2RlSWQ6IG5vZGUuaWQsIG5vZGUsIGNvbmZpcm06ICgpID0+IHRoaXMuc2VydmljZS5yZW1vdmVCbG9jayhub2RlLmlkKSB9KTtcbiAgfVxuXG4gIHByb3RlY3RlZCBoYW5kbGVyQWRkSW5zaWRlKGV2ZW50OiBFdmVudCwgbm9kZTogVF9ncmlkTGF5b3V0X25vZGUpOiB2b2lkIHtcbiAgICBldmVudC5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgIHRoaXMuZW1pdEFkZEluc2lkZShub2RlKTtcbiAgfVxuXG4gIHByb3RlY3RlZCBoYW5kbGVyVG9nZ2xlVHlwZShldmVudDogRXZlbnQsIG5vZGU6IFRfZ3JpZExheW91dF9ub2RlKTogdm9pZCB7XG4gICAgZXZlbnQuc3RvcFByb3BhZ2F0aW9uKCk7XG4gICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICB0aGlzLmVtaXRUb2dnbGVUeXBlKG5vZGUpO1xuICB9XG5cbiAgLyoqXG4gICAqIENo4bq3biBjw7ogYuG6pW0gdHJvbmcgdGhhbmggY8O0bmcgY+G7pSBu4buVaSBsw6puIGdyaWRzdGVyLlxuICAgKlxuICAgKiBDaOG7iSBgc3RvcFByb3BhZ2F0aW9uYCwgS0jDlE5HIGBwcmV2ZW50RGVmYXVsdGA6IG7DunQgYsOqbiB0cm9uZyB0ZW1wbGF0ZSBj4bunYSBuxqFpIGTDuW5nIHbhuqtuIGPhuqduXG4gICAqIGjDoG5oIHZpIG3hurdjIMSR4buLbmggY+G7p2EgbcOsbmggKG3hu58gZHJvcGRvd24sIGZvY3Vz4oCmKS5cbiAgICovXG4gIHByb3RlY3RlZCBoYW5kbGVyU3RvcEV2ZW50KGV2ZW50OiBFdmVudCk6IHZvaWQge1xuICAgIGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuICB9XG5cbiAgLyoqIFBow6F0IGBvdXRBZGRCbG9ja0luc2lkZWAg4oCUIGTDuW5nIGNodW5nIGNobyBuw7p0IG3hurdjIMSR4buLbmggdsOgIGB0ZW1wbGF0ZVRvb2xiYXJgLiAqL1xuICBwcml2YXRlIGVtaXRBZGRJbnNpZGUobm9kZTogVF9ncmlkTGF5b3V0X25vZGUpOiB2b2lkIHtcbiAgICB0aGlzLm91dEFkZEJsb2NrSW5zaWRlLmVtaXQoe1xuICAgICAgbm9kZUlkOiBub2RlLmlkLFxuICAgICAgbm9kZSxcbiAgICAgIGNvbmZpcm06IChpdGVtOiBUX2dyaWRMYXlvdXRfbmV3Tm9kZSkgPT4gdGhpcy5zZXJ2aWNlLmFkZEJsb2NrKGl0ZW0sIG5vZGUuaWQpLFxuICAgIH0pO1xuICB9XG5cbiAgLyoqIFBow6F0IGBvdXRUb2dnbGVUeXBlYCDigJQgZMO5bmcgY2h1bmcgY2hvIG7DunQgbeG6t2MgxJHhu4tuaCB2w6AgYHRlbXBsYXRlVG9vbGJhcmAuICovXG4gIHByaXZhdGUgZW1pdFRvZ2dsZVR5cGUobm9kZTogVF9ncmlkTGF5b3V0X25vZGUpOiB2b2lkIHtcbiAgICB0aGlzLm91dFRvZ2dsZVR5cGUuZW1pdCh7XG4gICAgICBub2RlSWQ6IG5vZGUuaWQsXG4gICAgICBub2RlLFxuICAgICAgLy8gR+G7mXAgaGF5IHTDoWNoIHN1eSByYSB04burIGNow61uaCBraOG7kWk6IMSRYW5nIGzDoCBjb250YWluZXIgdGjDrCB0w6FjaCwga2jDtG5nIHRow6wgZ+G7mXAuXG4gICAgICBjb25maXJtOiAoKSA9PiAodGhpcy5pc0NvbnRhaW5lcihub2RlKSA/IHRoaXMuc2VydmljZS50b1NpbmdsZShub2RlLmlkKSA6IHRoaXMuc2VydmljZS50b0NvbnRhaW5lcihub2RlLmlkKSksXG4gICAgfSk7XG4gIH1cblxuICAvKioga2jhu5FpIG7DoHkgY8OzIHBo4bqjaSBjb250YWluZXIga2jDtG5nIChjw7Mga2jhu5FpIGNvbikgKi9cbiAgcHJvdGVjdGVkIGlzQ29udGFpbmVyKGl0ZW06IFRfZ3JpZExheW91dF9ub2RlKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIChpdGVtLmNoaWxkcmVuPy5sZW5ndGggPz8gMCkgPiAwO1xuICB9XG5cbiAgLyoqIGNvbnRhaW5lciDEkcOjIGNo4bqhbSB0cuG6p24gbOG7k25nIHRow6wga2jDtG5nIGNobyB0aMOqbSBraOG7kWkgdsOgbyB0cm9uZyBu4buvYSAqL1xuICBwcm90ZWN0ZWQgY2FuQWRkSW5zaWRlKGl0ZW06IFRfZ3JpZExheW91dF9ub2RlKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuaXNDb250YWluZXIoaXRlbSkgJiYgdGhpcy5kZXB0aCgpIDwgdGhpcy5tYXhDb250YWluZXJEZXB0aCgpO1xuICB9XG5cbiAgLyoqIGto4buRaSDEkcahbiDhu58gY+G6pXAgY2jGsGEgY2jhuqFtIHRy4bqnbiBt4bubaSDEkcaw4bujYyBjaHV54buDbiB0aMOgbmggY29udGFpbmVyICovXG4gIHByb3RlY3RlZCBjYW5Ub2dnbGVUeXBlKGl0ZW06IFRfZ3JpZExheW91dF9ub2RlKTogYm9vbGVhbiB7XG4gICAgaWYgKHRoaXMuaXNDb250YWluZXIoaXRlbSkpIHtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cblxuICAgIHJldHVybiB0aGlzLmRlcHRoKCkgPCB0aGlzLm1heENvbnRhaW5lckRlcHRoKCk7XG4gIH1cblxuICBwcm90ZWN0ZWQgaGFuZGxlckJsb2NrUGFyZW50RHJhZyhldmVudDogRXZlbnQpOiB2b2lkIHtcbiAgICBpZiAoIXRoaXMuaXNOZXN0ZWRDYW52YXMoKSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuICB9XG5cbiAgcHJvdGVjdGVkIGhhbmRsZXJNb3VzZURvd25Ucm9uZ0x1b2koZXZlbnQ6IEV2ZW50KTogdm9pZCB7XG4gICAgaWYgKHRoaXMuZGVwdGgoKSA9PT0gMCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuICB9XG5cbiAgcHJvdGVjdGVkIGhhbmRsZXJTZWxlY3ROb2RlKG5vZGU6IFRfZ3JpZExheW91dF9ub2RlLCBldmVudD86IE1vdXNlRXZlbnQpOiB2b2lkIHtcbiAgICBpZiAoZXZlbnQpIHtcbiAgICAgIGNvbnN0IHRhcmdldCA9IGV2ZW50LnRhcmdldCBhcyBIVE1MRWxlbWVudDtcbiAgICAgIGlmICh0YXJnZXQuY2xvc2VzdCgnLmxpYnMtdWktZ3JpZC1sYXlvdXQtdG9vbGJhcicpIHx8IHRhcmdldC5jbG9zZXN0KCdidXR0b24nKSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgfVxuICAgIHRoaXMuc2VsZWN0ZWROb2RlSWQuc2V0KG5vZGUuaWQpO1xuICAgIHRoaXMub3V0U2VsZWN0Tm9kZS5lbWl0KG5vZGUpO1xuICB9XG5cbiAgcHJvdGVjdGVkIGhhbmRsZXJDb25maWcoZXZlbnQ6IEV2ZW50LCBub2RlOiBUX2dyaWRMYXlvdXRfbm9kZSk6IHZvaWQge1xuICAgIGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuICAgIGNvbnN0IGFjdGlvbkV2ZW50OiBUX2dyaWRMYXlvdXRfYWN0aW9uRXZlbnQgPSB7XG4gICAgICBub2RlSWQ6IG5vZGUuaWQsXG4gICAgICBub2RlLFxuICAgICAgY29uZmlybTogKCkgPT4gdHJ1ZSxcbiAgICB9O1xuICAgIHRoaXMub3V0Q29uZmlnTm9kZS5lbWl0KGFjdGlvbkV2ZW50KTtcbiAgfVxuXG4gIHByb3RlY3RlZCBoYW5kbGVyRHJhZ092ZXIoZXZlbnQ6IERyYWdFdmVudCk6IHZvaWQge1xuICAgIGlmICghdGhpcy5lbmFibGVFeHRlcm5hbERyb3AoKSB8fCB0aGlzLmRlcHRoKCkgPiAwKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgaWYgKGV2ZW50LmRhdGFUcmFuc2Zlcikge1xuICAgICAgZXZlbnQuZGF0YVRyYW5zZmVyLmRyb3BFZmZlY3QgPSAnY29weSc7XG4gICAgfVxuXG4gICAgY29uc3QgY29udGFpbmVyID0gdGhpcy5zY3JvbGxBcmVhUmVmKCk/Lm5hdGl2ZUVsZW1lbnQ7XG4gICAgY29uc3Qgcm9vdCA9IHRoaXMuc2VydmljZS5Sb290KCk7XG4gICAgY29uc3QgcGF5bG9hZCA9IHBhcnNlRHJvcFBheWxvYWQ8VF9ncmlkTGF5b3V0X2V4dGVybmFsRHJhZ1BheWxvYWQ+KFxuICAgICAgdGhpcy5zZXJ2aWNlLmdldERyYWdQYXlsb2FkKCkgYXMgVF9ncmlkTGF5b3V0X2V4dGVybmFsRHJhZ1BheWxvYWQgfCB1bmRlZmluZWQsXG4gICAgICBldmVudC5kYXRhVHJhbnNmZXIsXG4gICAgKTtcblxuICAgIGlmICghY29udGFpbmVyIHx8ICFyb290IHx8ICFwYXlsb2FkKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3Qgcm9vdEdyaWRzdGVyID0gY29udGFpbmVyLnF1ZXJ5U2VsZWN0b3IoJ2dyaWRzdGVyJykgYXMgSFRNTEVsZW1lbnQgfCBudWxsO1xuICAgIGlmIChyb290R3JpZHN0ZXIpIHtcbiAgICAgIGlmICghcm9vdEdyaWRzdGVyLmNsYXNzTGlzdC5jb250YWlucygnZGlzcGxheS1ncmlkJykpIHtcbiAgICAgICAgcm9vdEdyaWRzdGVyLmNsYXNzTGlzdC5hZGQoJ2Rpc3BsYXktZ3JpZCcpO1xuICAgICAgfVxuICAgICAgdGhpcy5yb290R3JpZHN0ZXJFbCA9IHJvb3RHcmlkc3RlcjtcbiAgICB9XG5cbiAgICBjb25zdCBnaG9zdCA9IGNhbGN1bGF0ZURyb3BHaG9zdChldmVudCwgY29udGFpbmVyLCByb290LCBwYXlsb2FkLCB0aGlzLnNlcnZpY2UudG90YWxDb2x1bW5zKTtcblxuICAgIGlmIChnaG9zdD8uaXNJbnNpZGVHcm91cCAmJiBnaG9zdC5ob3ZlcmVkR3JpZHN0ZXIpIHtcbiAgICAgIGlmICh0aGlzLmFjdGl2ZUhvdmVyZWRFbCAhPT0gZ2hvc3QuaG92ZXJlZEdyaWRzdGVyKSB7XG4gICAgICAgIHRoaXMuY2xlYW51cEhvdmVyZWRHcm91cCgpO1xuICAgICAgICBnaG9zdC5ob3ZlcmVkR3JpZHN0ZXIuY2xhc3NMaXN0LmFkZCgnZGlzcGxheS1ncmlkJyk7XG4gICAgICAgIHRoaXMuYWN0aXZlSG92ZXJlZEVsID0gZ2hvc3QuaG92ZXJlZEdyaWRzdGVyO1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLmNsZWFudXBIb3ZlcmVkR3JvdXAoKTtcbiAgICB9XG5cbiAgICB0aGlzLmRyb3BHaG9zdC5zZXQoZ2hvc3QpO1xuICB9XG5cbiAgcHJvdGVjdGVkIGhhbmRsZXJEcmFnTGVhdmUoZXZlbnQ6IERyYWdFdmVudCk6IHZvaWQge1xuICAgIGlmICh0aGlzLmRlcHRoKCkgPiAwKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGlmIChldmVudC5yZWxhdGVkVGFyZ2V0KSB7XG4gICAgICBjb25zdCBjb250YWluZXIgPSB0aGlzLnNjcm9sbEFyZWFSZWYoKT8ubmF0aXZlRWxlbWVudDtcbiAgICAgIGlmIChjb250YWluZXIgJiYgY29udGFpbmVyLmNvbnRhaW5zKGV2ZW50LnJlbGF0ZWRUYXJnZXQgYXMgTm9kZSkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgIH1cbiAgICB0aGlzLmRyb3BHaG9zdC5zZXQodW5kZWZpbmVkKTtcbiAgICB0aGlzLmNsZWFudXBEcmFnR3JpZCgpO1xuICB9XG5cbiAgcHJvdGVjdGVkIGhhbmRsZXJEcm9wKGV2ZW50OiBEcmFnRXZlbnQpOiB2b2lkIHtcbiAgICBpZiAoIXRoaXMuZW5hYmxlRXh0ZXJuYWxEcm9wKCkgfHwgdGhpcy5kZXB0aCgpID4gMCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgIGNvbnN0IGdob3N0ID0gdGhpcy5kcm9wR2hvc3QoKTtcbiAgICBjb25zdCBwYXlsb2FkID0gcGFyc2VEcm9wUGF5bG9hZDxUX2dyaWRMYXlvdXRfZXh0ZXJuYWxEcmFnUGF5bG9hZD4oXG4gICAgICB0aGlzLnNlcnZpY2UuZ2V0RHJhZ1BheWxvYWQoKSBhcyBUX2dyaWRMYXlvdXRfZXh0ZXJuYWxEcmFnUGF5bG9hZCB8IHVuZGVmaW5lZCxcbiAgICAgIGV2ZW50LmRhdGFUcmFuc2ZlcixcbiAgICApO1xuXG4gICAgdGhpcy5kcm9wR2hvc3Quc2V0KHVuZGVmaW5lZCk7XG4gICAgdGhpcy5jbGVhbnVwRHJhZ0dyaWQoKTtcbiAgICB0aGlzLnNlcnZpY2UuY2xlYXJEcmFnUGF5bG9hZCgpO1xuXG4gICAgaWYgKCFnaG9zdCB8fCAhcGF5bG9hZCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IHRhcmdldFBhcmVudElkID0gZ2hvc3QuaXNJbnNpZGVHcm91cCA/IGdob3N0LnRhcmdldFBhcmVudElkIDogdW5kZWZpbmVkO1xuICAgIGNvbnN0IGlzSW5zaWRlID0gQm9vbGVhbih0YXJnZXRQYXJlbnRJZCk7XG5cbiAgICBsZXQgaXRlbVRvQWRkOiBUX2dyaWRMYXlvdXRfbmV3Tm9kZTtcbiAgICBjb25zdCBwYXlsb2FkQW55ID0gcGF5bG9hZCBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbiAgICBpZiAodHlwZW9mIHBheWxvYWRBbnlbJ3Jlc29sdmVOb2RlJ10gPT09ICdmdW5jdGlvbicpIHtcbiAgICAgIGNvbnN0IHJlc29sdmVkID0gKHBheWxvYWRBbnlbJ3Jlc29sdmVOb2RlJ10gYXMgKGluc2lkZTogYm9vbGVhbikgPT4gVF9ncmlkTGF5b3V0X25ld05vZGUgfCB1bmRlZmluZWQpKGlzSW5zaWRlKTtcbiAgICAgIGl0ZW1Ub0FkZCA9IHJlc29sdmVkID8/IHtcbiAgICAgICAgY29sczogZ2hvc3QuY29scyxcbiAgICAgICAgcm93czogZ2hvc3Qucm93cyxcbiAgICAgICAgZGF0YTogcGF5bG9hZC5kYXRhID8/IChwYXlsb2FkLnR5cGUgPyB7IHR5cGU6IHBheWxvYWQudHlwZSwgdGl0bGU6IHBheWxvYWQudGl0bGUgfSA6IHVuZGVmaW5lZCksXG4gICAgICB9O1xuICAgIH0gZWxzZSB7XG4gICAgICBjb25zdCBuZXdOb2RlRGF0YSA9IHBheWxvYWQuZGF0YSA/PyAocGF5bG9hZC50eXBlID8geyB0eXBlOiBwYXlsb2FkLnR5cGUsIHRpdGxlOiBwYXlsb2FkLnRpdGxlIH0gOiB1bmRlZmluZWQpO1xuICAgICAgaXRlbVRvQWRkID0ge1xuICAgICAgICBjb2xzOiBnaG9zdC5jb2xzLFxuICAgICAgICByb3dzOiBnaG9zdC5yb3dzLFxuICAgICAgICBkYXRhOiBuZXdOb2RlRGF0YSxcbiAgICAgIH07XG4gICAgfVxuXG4gICAgY29uc3QgYWRkZWROb2RlID0gdGhpcy5zZXJ2aWNlLmluc2VydEJsb2NrV2l0aENvbGxpc2lvbihcbiAgICAgIGl0ZW1Ub0FkZCxcbiAgICAgIGdob3N0LmNvbCxcbiAgICAgIGdob3N0LnJvdyxcbiAgICAgIHRhcmdldFBhcmVudElkLFxuICAgICk7XG5cbiAgICBpZiAoYWRkZWROb2RlKSB7XG4gICAgICB0aGlzLnNlbGVjdGVkTm9kZUlkLnNldChhZGRlZE5vZGUuaWQpO1xuICAgICAgdGhpcy5vdXREcm9wTm9kZS5lbWl0KHtcbiAgICAgICAgbm9kZTogYWRkZWROb2RlLFxuICAgICAgICBwYXJlbnRJZDogdGFyZ2V0UGFyZW50SWQsXG4gICAgICAgIGNvbDogZ2hvc3QuY29sLFxuICAgICAgICByb3c6IGdob3N0LnJvdyxcbiAgICAgICAgY29sczogZ2hvc3QuY29scyxcbiAgICAgICAgcm93czogZ2hvc3Qucm93cyxcbiAgICAgICAgcmF3RXZlbnQ6IGV2ZW50LFxuICAgICAgICBwYXlsb2FkLFxuICAgICAgfSk7XG4gICAgICBjb25zdCByb290ID0gdGhpcy5zZXJ2aWNlLlJvb3QoKTtcbiAgICAgIGlmIChyb290KSB7XG4gICAgICAgIHRoaXMub3V0Q2hhbmdlLmVtaXQoe1xuICAgICAgICAgIHJvb3QsXG4gICAgICAgICAgbm9kZUlkOiBhZGRlZE5vZGUuaWQsXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgY2xlYW51cEhvdmVyZWRHcm91cCgpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5hY3RpdmVIb3ZlcmVkRWwpIHtcbiAgICAgIHRoaXMuYWN0aXZlSG92ZXJlZEVsLmNsYXNzTGlzdC5yZW1vdmUoJ2Rpc3BsYXktZ3JpZCcpO1xuICAgICAgdGhpcy5hY3RpdmVIb3ZlcmVkRWwgPSB1bmRlZmluZWQ7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBjbGVhbnVwRHJhZ0dyaWQoKTogdm9pZCB7XG4gICAgdGhpcy5jbGVhbnVwSG92ZXJlZEdyb3VwKCk7XG4gICAgaWYgKHRoaXMucm9vdEdyaWRzdGVyRWwgJiYgIXRoaXMuc2hvd0dyaWRMaW5lcygpKSB7XG4gICAgICB0aGlzLnJvb3RHcmlkc3RlckVsLmNsYXNzTGlzdC5yZW1vdmUoJ2Rpc3BsYXktZ3JpZCcpO1xuICAgICAgdGhpcy5yb290R3JpZHN0ZXJFbCA9IHVuZGVmaW5lZDtcbiAgICB9XG4gICAgY29uc3QgY29udGFpbmVyID0gdGhpcy5zY3JvbGxBcmVhUmVmKCk/Lm5hdGl2ZUVsZW1lbnQ7XG4gICAgaWYgKGNvbnRhaW5lciAmJiAhdGhpcy5zaG93R3JpZExpbmVzKCkpIHtcbiAgICAgIGNvbnRhaW5lci5xdWVyeVNlbGVjdG9yQWxsKCdncmlkc3Rlci5kaXNwbGF5LWdyaWQnKS5mb3JFYWNoKChlbCkgPT4ge1xuICAgICAgICBlbC5jbGFzc0xpc3QucmVtb3ZlKCdkaXNwbGF5LWdyaWQnKTtcbiAgICAgIH0pO1xuICAgIH1cbiAgfVxufVxuIiwiQGlmIChpc1pvb21BY3RpdmUoKSkge1xuICA8IS0tIEtodSB24buxYyBjdeG7mW4gY2jhu6lhIGNhbnZhcyBzdGFnZSB0aHUgcGjDs25nIC0tPlxuICA8ZGl2XG4gICAgI3Njcm9sbEFyZWFcbiAgICBjbGFzcz1cImxpYnMtdWktZ3JpZC1sYXlvdXQtc2Nyb2xsLWFyZWEgcmVsYXRpdmUgaC1mdWxsIG1pbi1oLTAgdy1mdWxsIG1pbi13LTAgb3ZlcmZsb3ctYXV0byBwLTYgZmxleCBqdXN0aWZ5LWNlbnRlciBpdGVtcy1zdGFydFwiXG4gICAgKG1vdXNlZG93bik9XCJoYW5kbGVyTW91c2VEb3duVHJvbmdMdW9pKCRldmVudClcIlxuICAgICh3aGVlbCk9XCJoYW5kbGVyV2hlZWwoJGV2ZW50KVwiXG4gICAgKGRyYWdvdmVyKT1cImhhbmRsZXJEcmFnT3ZlcigkZXZlbnQpXCJcbiAgICAoZHJhZ2xlYXZlKT1cImhhbmRsZXJEcmFnTGVhdmUoJGV2ZW50KVwiXG4gICAgKGRyb3ApPVwiaGFuZGxlckRyb3AoJGV2ZW50KVwiPlxuICAgIDxkaXZcbiAgICAgICNjYW52YXNTdGFnZVxuICAgICAgaWQ9XCJiaS1jYW52YXMtc3RhZ2VcIlxuICAgICAgY2xhc3M9XCJsaWJzLXVpLWdyaWQtbGF5b3V0LXN0YWdlIHJlbGF0aXZlIGZsZXggZmxleC1jb2wgdHJhbnNpdGlvbi1bem9vbV0gZHVyYXRpb24tMTUwIG9yaWdpbi10b3Agc2hyaW5rLTAgYmctd2hpdGUvODAgYm9yZGVyIGJvcmRlci1zbGF0ZS0yMDAvODAgcm91bmRlZC0yeGwgc2hhZG93LXNtIHAtNFwiXG4gICAgICBbc3R5bGUuem9vbV09XCJjdXJyZW50Wm9vbSgpXCJcbiAgICAgIFtzdHlsZS53aWR0aC5weF09XCJzdGFnZVdpZHRoKClcIlxuICAgICAgW3N0eWxlLm1pbi13aWR0aC5weF09XCJzdGFnZVdpZHRoKClcIlxuICAgICAgW3N0eWxlLm1pbi1oZWlnaHQucHhdPVwic3RhZ2VNaW5IZWlnaHQoKVwiPlxuICAgICAgPCEtLSBTbmFwcGVkIERyb3AgR2hvc3QgUHJldmlldyAtLT5cbiAgICAgIEBpZiAoZHJvcEdob3N0KCk7IGFzIGdob3N0KSB7XG4gICAgICAgIDxkaXZcbiAgICAgICAgICBjbGFzcz1cInBvaW50ZXItZXZlbnRzLW5vbmUgYWJzb2x1dGUgei0zMCBmbGV4IGZsZXgtY29sIGl0ZW1zLWNlbnRlciBqdXN0aWZ5LWNlbnRlciBvdmVyZmxvdy1oaWRkZW4gcm91bmRlZC1sZyBib3JkZXItMiBib3JkZXItZGFzaGVkIGJvcmRlci1ibHVlLTUwMCBiZy1ibHVlLTUwMC8xNSBwLTEgc2hhZG93LXNtIHRyYW5zaXRpb24tYWxsIGR1cmF0aW9uLTc1IGVhc2Utb3V0IGJhY2tkcm9wLWJsdXItWzAuNXB4XSBzZWxlY3Qtbm9uZVwiXG4gICAgICAgICAgW3N0eWxlLmxlZnQucHhdPVwiZ2hvc3QucGl4ZWxMZWZ0XCJcbiAgICAgICAgICBbc3R5bGUudG9wLnB4XT1cImdob3N0LnBpeGVsVG9wXCJcbiAgICAgICAgICBbc3R5bGUud2lkdGgucHhdPVwiZ2hvc3QucGl4ZWxXaWR0aFwiXG4gICAgICAgICAgW3N0eWxlLmhlaWdodC5weF09XCJnaG9zdC5waXhlbEhlaWdodFwiPlxuICAgICAgICAgIDxkaXYgY2xhc3M9XCJpbmxpbmUtZmxleCBtYXgtdy1bOTUlXSBpdGVtcy1jZW50ZXIgZ2FwLTEgdHJ1bmNhdGUgcm91bmRlZC1tZCBiZy1ibHVlLTYwMCBweC0yIHB5LTAuNSB0ZXh0LVsxMXB4XSBmb250LXNlbWlib2xkIHRleHQtd2hpdGUgc2hhZG93LXhzXCI+XG4gICAgICAgICAgICBAaWYgKGdob3N0LmNhcmRJY29uQ2xhc3MpIHtcbiAgICAgICAgICAgICAgPGkgW2NsYXNzXT1cImdob3N0LmNhcmRJY29uQ2xhc3MgKyAnIHRleHQteHMnXCI+PC9pPlxuICAgICAgICAgICAgfSBAZWxzZSBpZiAoZ2hvc3QuY2FyZEljb25UZXh0KSB7XG4gICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwidGV4dC1bMTBweF0gZm9udC1ib2xkXCI+e3sgZ2hvc3QuY2FyZEljb25UZXh0IH19PC9zcGFuPlxuICAgICAgICAgICAgfSBAZWxzZSB7XG4gICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwidGV4dC14cyBmb250LWJvbGRcIj57eyBnaG9zdC5pc0luc2lkZUdyb3VwID8gJ+KGsycgOiAnKycgfX08L3NwYW4+XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICA8c3BhbiBjbGFzcz1cInRydW5jYXRlXCI+e3sgZ2hvc3QuY2FyZFRpdGxlIH19PC9zcGFuPlxuICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJ0ZXh0LVs5cHhdIGZvbnQtbW9ubyBvcGFjaXR5LTc1XCI+KHt7IGdob3N0LmNvbHMgfX1jKTwvc3Bhbj5cbiAgICAgICAgICA8L2Rpdj5cblxuICAgICAgICAgIEBpZiAoZ2hvc3QucGl4ZWxIZWlnaHQgPj0gODApIHtcbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJtdC0xIGZsZXggbWF4LXctWzk1JV0gaXRlbXMtY2VudGVyIGdhcC0xLjUgdHJ1bmNhdGUgcm91bmRlZCBib3JkZXIgYm9yZGVyLWJsdWUtMTAwIGJnLXdoaXRlLzk1IHB4LTIgcHktMC41IHRleHQtWzEwcHhdIGZvbnQtbWVkaXVtIHRleHQtYmx1ZS03MDAgc2hhZG93LXhzXCI+XG4gICAgICAgICAgICAgIEBpZiAoZ2hvc3QuaXNJbnNpZGVHcm91cCkge1xuICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwidHJ1bmNhdGUgZm9udC1ib2xkIHRleHQtYmx1ZS05MDBcIj7ihrMge3sgZ2hvc3QuZ3JvdXBUaXRsZSB9fTwvc3Bhbj5cbiAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cInRleHQtYmx1ZS0zMDBcIj7igKI8L3NwYW4+XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgPHNwYW4+Q+G7mXQge3sgZ2hvc3QuY29sICsgMSB9fS17eyBnaG9zdC5jb2wgKyBnaG9zdC5jb2xzIH19PC9zcGFuPlxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgfVxuICAgICAgICA8L2Rpdj5cbiAgICAgIH1cbiAgICAgIDxncmlkc3RlciBjbGFzcz1cImgtZnVsbCB3LWZ1bGxcIiBbY2xhc3MuZGlzcGxheS1ncmlkXT1cInNob3dHcmlkTGluZXMoKVwiIFtvcHRpb25zXT1cImdyaWRPcHRpb25zKClcIj5cbiAgICAgICAgICBAZm9yIChpdGVtIG9mIGNoaWxkcmVuKCk7IHRyYWNrIGl0ZW0uaWQ7IGxldCBpdGVtSW5kZXggPSAkaW5kZXgpIHtcbiAgICA8IS0tIPCflLQgQ2jhurduIGBtb3VzZWRvd25gIHThuqFpIMSQw4JZIGNobyBsxrDhu5tpIGzhu5NuZyDigJQgQ+G6pE0gYuG7jyB2w6AgQ+G6pE0gY2h1eeG7g24gc2FuZyBjaOG7lyBraMOhYy5cbiAgICAgICAgIGBpZ25vcmVDb250ZW50Q2xhc3NgIG3hu5l0IG3DrG5oIEtIw5RORyDEkeG7pzogYGRlbGF5U3RhcnQ6IDE2MGAgbMOgbSBN4buWSSBsxrDhu5tpIGzDqm4gbOG7i2NoXG4gICAgICAgICBgZHJhZ1N0YXJ0YCBi4bqxbmcgYHNldFRpbWVvdXRgIG5nYXkgdOG6oWkgYG1vdXNlZG93bmAsIGPDsm4gYHN0b3BQcm9wYWdhdGlvbmAgbcOgIGxpYiBn4buNaSBiw6puXG4gICAgICAgICB0cm9uZyBgZHJhZ1N0YXJ0YCBjaOG6oXkgc2F1IDE2MG1zIG7Dqm4gcXXDoSBtdeG7mW4g4oCUIGzGsOG7m2kgQ0hBIMSRw6Mga+G7i3Agbmjhuq1uICjEkW8gMjgvMDgvMjAyNjoga8Opb1xuICAgICAgICAgZOG6o2kga2jhu5FpIGNvbiwgY2h14buXaSBjbGFzcyBkdXnhu4d0IGzDqm4gxJDDmk5HIG3DoCBjb250YWluZXIgduG6q24gbmjhuqN5IDAsMCDihpIgMCwxKS5cbiAgICAgICAgIEfhuq9uIOG7nyBgZ3JpZHN0ZXItaXRlbWAgbMOgIMSRw7puZyBiacOqbjogbMaw4bubaSBjb24gbmdoZSB0csOqbiBjaMOtbmggcGjhuqduIHThu60gbsOgeSBuw6puIMSRw6Mgbmjhuq1uIHhvbmcsXG4gICAgICAgICBsxrDhu5tpIGNoYSDhu58gbmdvw6BpIGLhu4sgY2jhurduLiAtLT5cbiAgICA8Z3JpZHN0ZXItaXRlbVxuICAgICAgW2l0ZW1dPVwiaXRlbVwiXG4gICAgICBbY2xhc3MubGlicy11aS1ncmlkLWxheW91dC1zZWxlY3RlZF09XCJzZWxlY3RlZE5vZGVJZCgpID09PSBpdGVtLmlkXCJcbiAgICAgIChjbGljayk9XCJoYW5kbGVyU2VsZWN0Tm9kZShpdGVtLCAkZXZlbnQpXCJcbiAgICAgIChtb3VzZWRvd24pPVwiaGFuZGxlckJsb2NrUGFyZW50RHJhZygkZXZlbnQpXCI+XG4gICAgICA8IS0tIPCflLQgVuG7jyBuw6B5IG1hbmcgYGRyYWdIYW5kbGVDbGFzc2Ag4oCUIEPhuqRNIGLhu48uXG4gICAgICAgICAgIGBpZ25vcmVDb250ZW50OiB0cnVlYCBi4bqvdCBncmlkc3RlciBDSOG7iCBjaG8ga8OpbyBraGkgY2jhu5cgYuG6pW0gbuG6sW0gZMaw4bubaSBt4buZdCBwaOG6p24gdOG7rSBjw7NcbiAgICAgICAgICAgYGRyYWdIYW5kbGVDbGFzc2AuIEtow7RuZyBjw7MgduG7jyBuw6B5IHRow6wgY29tcG9uZW50IGPhu6dhIG7GoWkgZMO5bmcgKHRoxrAgdmnhu4duIGtow7RuZyBraeG7g20gc2/DoXRcbiAgICAgICAgICAgxJHGsOG7o2MgY2xhc3MgY+G7p2EgbsOzKSBz4bq9IGtow7RuZyBjw7MgdGF5IGPhuqdtIG7DoG8sIHbDoCBLSMOUTkcga2jhu5FpIG7DoG8ga8OpbyDEkcaw4bujYyDigJQgxJFvIDI4LzA4LzIwMjY6XG4gICAgICAgICAgIGvDqW8gMzIwcHgsIHRv4bqhIMSR4buZIGto4buRaSBnaeG7ryBuZ3V5w6puIHg9Myx5PTAuXG4gICAgICAgICAgIFTDqm4gY2xhc3MgdGhlbyBj4bqlcDogbMaw4bubaSB0cmFuZyB2w6AgbMaw4bubaSBs4buTbmcgZMO5bmcgaGFpIHTDqm4gS0jDgUMgbmhhdSwgbuG6v3Uga2jDtG5nIGzGsOG7m2kgY2hhXG4gICAgICAgICAgIGPFqW5nIG5o4bqtbiByYSB0YXkgY+G6p20gY+G7p2Ega2jhu5FpIGNvbiB2w6AgbmjhuqVjIGx1w7RuIGNvbnRhaW5lci4gLS0+XG4gICAgICA8IS0tIPCflLQgVuG7jyBLSMOUTkcgbWFuZyBgZHJhZ0hhbmRsZUNsYXNzYCDigJQgQ+G6pE0gdGjDqm0gbOG6oWkuXG4gICAgICAgICAgIEvDqW8gY2jhu4kgxJHGsOG7o2MgcGjDqXAgYuG6r3QgxJHhuqd1IHThu6sgROG6okkgWEFOSCAobmfGsOG7nWkgZMO5bmcgY2jhu5F0IDI4LzA4LzIwMjY6IFwicGjhuqNpIGhvdmVyIHbDoG8gdsO5bmdcbiAgICAgICAgICAgbcOgdSB4YW5oIHRow6wgbeG7m2kga8OpbyB0aOG6oyDEkcaw4bujYyBjaG8gxJHhu5NuZyBuaOG6pXRcIikuIENobyBj4bqjIHbhu48gbMOgbSB0YXkgY+G6p20gdGjDrCBi4bqlbSDEkcOidSBjxaluZ1xuICAgICAgICAgICBrw6lvLCB2w6Aga2jhu5FpIGNvbiBu4bqxbSB0cm9uZyBjb250YWluZXIgc+G6vSBuaOG6pWMgbHXDtG4gY29udGFpbmVyIHbDrCBsxrDhu5tpIGNoYSBkdXnhu4d0IGzDqm4gZ+G6t3BcbiAgICAgICAgICAgdGF5IGPhuqdtIGPhu6dhIHbhu48gY29udGFpbmVyIHRyxrDhu5tjLlxuICAgICAgICAgICBW4buPIGto4buRaSBjb24gduG6q24gZ2nhu68gY2xhc3MgQ0jhurZOIMSR4buDIGzGsOG7m2kgY2hhIGThu6tuZyDEkcO6bmcg4bufIGJpw6puLiAtLT5cbiAgICAgIDxkaXZcbiAgICAgICAgY2xhc3M9XCJsaWJzLXVpLWdyaWQtbGF5b3V0LWJsb2NrLXNoZWxsIGdyb3VwIHJlbGF0aXZlIGgtZnVsbCB3LWZ1bGwgbWluLXctMFwiXG4gICAgICAgIFtjbGFzcy5saWJzLXVpLWdyaWQtbGF5b3V0LWJsb2NrLXBhcmVudC1kcmFnXT1cImlzTmVzdGVkQ2FudmFzKClcIj5cbiAgICAgICAgPCEtLSBE4bqjaSBrw6lvOiBoaeG7h24ga2hpIHLDqiBjaHXhu5l0IHbDoG8ga2jhu5FpLCBiYSBjaOG6pW0gbMOgIGThuqV1IGhp4buHdSBrw6lvIHF1ZW4gdGh14buZYy5cbiAgICAgICAgICAgICBOZ8aw4budaSBkw7luZyBj4bqnbiBt4buZdCBjaOG7lyBiw6FtIFLDlSBSw4BORyB0aGF5IHbDrCDEkW/DoW4geGVtIGLhuqVtIMSRw6J1IHRow6wga8OpbyDEkcaw4bujY1xuICAgICAgICAgICAgIChjaOG7kXQgMjgvMDgvMjAyNiwgdGhlbyDEkcO6bmcgZOG6o2kgxJFhbmcgZMO5bmcg4bufIG3DoG4gQ3VzdG9tZXIgMzYwIGPhu6dhIG1vYmlvLXdlYikuIC0tPlxuICAgICAgICBAaWYgKGlzRWRpdE1vZGUoKSkge1xuICAgICAgICAgIDwhLS0g8J+UtCBE4bqjaSBQSOG6okkgbWFuZyB0YXkgY+G6p20gxJDDmk5HIEPhuqRQIGPhu6dhIG7Dsy4gROG6o2kgbmjhuq1uIGNodeG7mXQgKGBwb2ludGVyLWV2ZW50czogYXV0b2ApLFxuICAgICAgICAgICAgICAgbsOqbiBu4bq/dSBraMO0bmcgbWFuZyB0YXkgY+G6p20gdGjDrCBgY2hlY2tEcmFnSGFuZGxlQ2xhc3NgIGR1eeG7h3QgbMOqbiBn4bq3cCB0YXkgY+G6p20gY+G7p2FcbiAgICAgICAgICAgICAgIGNvbnRhaW5lciB2w6AgbmjhuqVjIGNvbnRhaW5lciB0aGF5IHbDrCBraOG7kWkgY29uICjEkW8gMjgvMDgvMjAyNjoga8OpbyBk4bqjaSBraOG7kWkgY29uLFxuICAgICAgICAgICAgICAgY29udGFpbmVyIG5o4bqjeSAwLDAg4oaSIDAsMSBjw7JuIGto4buRaSBjb24gxJHhu6luZyBpbSkuXG4gICAgICAgICAgICAgICDwn5S0IEThuqNpIENI4buIIG1hbmcgdGF5IGPhuqdtLCBD4bqkTSBtYW5nIHRow6ptIGNsYXNzIGNo4bq3bjogYGNoZWNrRHJhZ0hhbmRsZUNsYXNzYCB4w6l0IGhhaVxuICAgICAgICAgICAgICAgY2xhc3MgxJHDsyB0csOqbiBDw5lORyBt4buZdCBub2RlIG7Dqm4gxJHhu4MgY2h1bmcgbMOgIGvDqW8gaOG7j25nICjEkW8gMjgvMDgvMjAyNjogYuG6pW0gZOG6o2kga2jhu5FpXG4gICAgICAgICAgICAgICBjb24ga8OpbyAxNDBweCwga2jhu5FpIMSR4bupbmcgaW0pLiBWaeG7h2MgY2jhurduIGzGsOG7m2kgY2hhIGRvIFbhu44gS0jhu5BJIGxvLiAtLT5cbiAgICAgICAgICA8ZGl2XG4gICAgICAgICAgICBjbGFzcz1cImxpYnMtdWktZ3JpZC1sYXlvdXQtZHJhZy1iYXJcIlxuICAgICAgICAgICAgW2NsYXNzLmxpYnMtdWktZ3JpZC1sYXlvdXQtZHJhZy1iYXItY2hpbGRdPVwiaXNOZXN0ZWRDYW52YXMoKVwiXG4gICAgICAgICAgICBbY2xhc3MubGlicy11aS1ncmlkLWxheW91dC1kcmFnLWhhbmRsZV09XCIhaXNOZXN0ZWRDYW52YXMoKVwiXG4gICAgICAgICAgICBbY2xhc3MubGlicy11aS1ncmlkLWxheW91dC1kcmFnLWhhbmRsZS1jaGlsZF09XCJpc05lc3RlZENhbnZhcygpXCI+XG4gICAgICAgICAgICA8c3BhbiBjbGFzcz1cImxpYnMtdWktZ3JpZC1sYXlvdXQtZHJhZy1iYXItZG90c1wiPlxuICAgICAgICAgICAgICBAZm9yIChkb3Qgb2YgZHJhZ0JhckRvdHM7IHRyYWNrIGRvdCkge1xuICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwibGlicy11aS1ncmlkLWxheW91dC1kcmFnLWJhci1kb3RcIj48L3NwYW4+XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIDwvc3Bhbj5cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgfVxuXG4gICAgICAgIDwhLS0gS2h1bmcgY2jhu6lhIGNvbXBvbmVudCBj4bunYSBuxqFpIGTDuW5nLlxuICAgICAgICAgICAgIPCflLQgUEjhuqJJIGPDsyBraHVuZyB0aOG6rXQgKGtow7RuZyBwaOG6o2kgYG5nLWNvbnRhaW5lcmAgdHLhu5FuZyk6IG7DsyBsbyBo4buZIG7GoWkgZMO5bmcgcGjhuqduIGzhuqVwIMSR4bqneVxuICAgICAgICAgICAgIMO0IHbDoCB2aeG7gW4gYsOhbyBjaOG6vyDEkeG7mSBz4butYS4gS2jDtG5nIGPDsyBraHVuZyB0aMOsIG3hu5dpIGNvbXBvbmVudCBu4buZaSBkdW5nIGzhuqFpIHBo4bqjaSB04buxIHZp4bq/dFxuICAgICAgICAgICAgIGA6aG9zdCB7IHdpZHRoL2hlaWdodDogMTAwJSB9YCArIHZp4buBbiDEkeG7qXQg4oCUIMSRw7MgbMOgIHZp4buHYyBj4bunYSB0aMawIHZp4buHbiwga2jDtG5nIHBo4bqjaSBj4bunYVxuICAgICAgICAgICAgIG5nxrDhu51pIGTDuW5nIChuZ8aw4budaSBkw7luZyBjaOG7kXQgMjgvMDgvMjAyNikuXG4gICAgICAgICAgICAgTeG7l2kga2jhu5FpIG3hu5l0IFZpZXdDb250YWluZXJSZWYgcmnDqm5nIG7Dqm4gY29tcG9uZW50IG7hurFtIMSRw7puZyDDtCBj4bunYSBuw7MuIC0tPlxuICAgICAgICA8ZGl2XG4gICAgICAgICAgY2xhc3M9XCJsaWJzLXVpLWdyaWQtbGF5b3V0LWNvbnRlbnQtZnJhbWVcIlxuICAgICAgICAgIFtjbGFzcy5saWJzLXVpLWdyaWQtbGF5b3V0LWNvbnRlbnQtZnJhbWUtZWRpdF09XCJpc0VkaXRNb2RlKCkgJiYgIWlzQ29udGFpbmVyKGl0ZW0pXCJcbiAgICAgICAgICBbY2xhc3MubGlicy11aS1ncmlkLWxheW91dC1jb250ZW50LWZyYW1lLWVtcHR5XT1cImlzQ29udGFpbmVyKGl0ZW0pXCI+XG4gICAgICAgICAgPG5nLWNvbnRhaW5lciAjaXRlbUhvc3QgLz5cbiAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgPCEtLSBE4bqldSBoaeG7h3UgQ09OVEFJTkVSOiBuaMOjbiBnw7NjIHRyw6puLXBo4bqjaSArIHZp4buBbiDEkeG7qXQgYmFvIHJ14buZdC4gS2jDtG5nIGPDsyBk4bqldSBoaeG7h3UgdGjDrFxuICAgICAgICAgICAgIG5nxrDhu51pIGTDuW5nIGtow7RuZyBiaeG6v3Qga2jhu5FpIG7DoG8gY2jhu6lhIMSRxrDhu6NjIGto4buRaSBraMOhYyAoY2jhu5F0IDI4LzA4LzIwMjYsIHRoZW8gxJHDum5nIGPDoWNoXG4gICAgICAgICAgICAgbcOgbiBDdXN0b21lciAzNjAgY+G7p2EgbW9iaW8td2ViIMSRYW5nIGzDoG0pLiAtLT5cbiAgICAgICAgQGlmIChpc0VkaXRNb2RlKCkgJiYgaXNDb250YWluZXIoaXRlbSkpIHtcbiAgICAgICAgICA8ZGl2IGNsYXNzPVwibGlicy11aS1ncmlkLWxheW91dC1jb250YWluZXItbGFiZWxcIj57eyAnaTE4bl9jb250YWluZXJfYmxvY2snIHwgdHJhbnNsYXRlIH19PC9kaXY+XG4gICAgICAgICAgPGRpdiBjbGFzcz1cImxpYnMtdWktZ3JpZC1sYXlvdXQtY29udGFpbmVyLWJvcmRlclwiPjwvZGl2PlxuICAgICAgICB9XG5cbiAgICAgICAgPCEtLSBUaGFuaCBjw7RuZyBj4bulOiBoaeG7h24ga2hpIHLDqiBjaHXhu5l0IHbDoG8ga2jhu5FpLlxuICAgICAgICAgICAgIPCflLQgRMO5bmcgYGxpYnNfdWktY29tcG9uZW50cy1idXR0b25zLWJ1dHRvbmAg4oCUIEPhuqRNIHThu7EgZOG7sW5nIHRo4bq7IGA8YnV0dG9uPmAuXG4gICAgICAgICAgICAgQ29tcG9uZW50IG7DoHkgxJHDoyBjw7Mgc+G6tW4ga2nhu4N1IG7DunQsIGPhu6EgbsO6dCB2w6AgYm9uZyBiw7NuZyBjaMO6IHRow61jaCB0aGVvIMSRw7puZyBi4buZIGdpYW8gZGnhu4duXG4gICAgICAgICAgICAgY+G7p2Egc+G6o24gcGjhuqltOyB04buxIGThu7FuZyBsw6AgbeG7l2kgbsahaSBt4buZdCBraeG7g3UgdsOgIG3huqV0IGx1w7RuIHRvb2x0aXAuIC0tPlxuICAgICAgICBAaWYgKGlzRWRpdE1vZGUoKSAmJiAhaGlkZGVuVG9vbGJhcigpKSB7XG4gICAgICAgICAgQGlmICh0ZW1wbGF0ZVRvb2xiYXIoKSkge1xuICAgICAgICAgICAgPCEtLSBOxqFpIGTDuW5nIHThu7EgduG6vSB0aGFuaCBjw7RuZyBj4bulOiBuaOG6rW4ga2jhu5FpICsgY8OhYyBow6BtIHBow6F0IGV2ZW50IHF1YSBjb250ZXh0LlxuXG4gICAgICAgICAgICAgICAgIPCflLQgS2jhu5FpIGLhu41jIHThu7EgY2jhurduIGBtb3VzZWRvd25gL2BjbGlja2AgbuG7lWkgbMOqbiBncmlkc3Rlci4gVGhhbmggY8O0bmcgY+G7pSBu4bqxbSB0cm9uZ1xuICAgICAgICAgICAgICAgICB2w7luZyBtYW5nIGBkcmFnSGFuZGxlQ2xhc3NgOyBraMO0bmcgY2jhurduIHRow6wgY8O6IGLhuqVtIGLhu4sgaGnhu4N1IGzDoCBi4bqvdCDEkeG6p3Uga8OpbyB2w6BcbiAgICAgICAgICAgICAgICAgYGRlbGF5U3RhcnQ6IDE2MGAgbnXhu5F0IGx1w7RuIGBjbGlja2Ag4oCUIG7DunQgdHJvbmcgdGVtcGxhdGUgbmdvw6BpIGLhuqVtIGtow7RuZyDEg25cbiAgICAgICAgICAgICAgICAgKMSRbyAwOS8wOS8yMDI2OiBi4bqlbSBi4bqxbmcgYC5jbGljaygpYCBj4bunYSBET00gdGjDrCBt4bufLCBi4bqlbSBjaHXhu5l0IHRo4bqtdCB0aMOsIGtow7RuZykuXG4gICAgICAgICAgICAgICAgIENo4bq3biDhu58gxJDDglkgxJHhu4MgbsahaSBkw7luZyBraMO0bmcgcGjhuqNpIGJp4bq/dCBi4bqreSBuw6B5LiAtLT5cbiAgICAgICAgICAgIDxkaXZcbiAgICAgICAgICAgICAgY2xhc3M9XCJsaWJzLXVpLWdyaWQtbGF5b3V0LXRvb2xiYXJcIlxuICAgICAgICAgICAgICByb2xlPVwidG9vbGJhclwiXG4gICAgICAgICAgICAgIHRhYmluZGV4PVwiMFwiXG4gICAgICAgICAgICAgIFtjbGFzcy5saWJzLXVpLWdyaWQtbGF5b3V0LXRvb2xiYXItY2hpbGRdPVwiaXNOZXN0ZWRDYW52YXMoKVwiXG4gICAgICAgICAgICAgIChtb3VzZWRvd24pPVwiaGFuZGxlclN0b3BFdmVudCgkZXZlbnQpXCJcbiAgICAgICAgICAgICAgKGtleWRvd24pPVwiaGFuZGxlclN0b3BFdmVudCgkZXZlbnQpXCJcbiAgICAgICAgICAgICAgKGNsaWNrKT1cImhhbmRsZXJTdG9wRXZlbnQoJGV2ZW50KVwiPlxuICAgICAgICAgICAgICA8bmctY29udGFpbmVyXG4gICAgICAgICAgICAgICAgKm5nVGVtcGxhdGVPdXRsZXQ9XCJ0ZW1wbGF0ZVRvb2xiYXIoKSE7IGNvbnRleHQ6IHRvb2xiYXJDb250ZXh0cygpW2l0ZW1JbmRleF1cIiAvPlxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgfSBAZWxzZSB7XG4gICAgICAgICAgICA8ZGl2XG4gICAgICAgICAgICAgIGNsYXNzPVwibGlicy11aS1ncmlkLWxheW91dC10b29sYmFyXCJcbiAgICAgICAgICAgICAgW2NsYXNzLmxpYnMtdWktZ3JpZC1sYXlvdXQtdG9vbGJhci1jaGlsZF09XCJpc05lc3RlZENhbnZhcygpXCI+XG4gICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwibGlicy11aS1ncmlkLWxheW91dC1kaW0tYmFkZ2VcIj5cbiAgICAgICAgICAgICAgICB7eyBpdGVtLnJvd3MgfX0gaMOgbmcgw5cge3sgaXRlbS5jb2xzIH19IGPhu5l0XG4gICAgICAgICAgICAgIDwvc3Bhbj5cbiAgICAgICAgICAgICAgQGlmIChjYW5BZGRJbnNpZGUoaXRlbSkpIHtcbiAgICAgICAgICAgICAgICA8bGlic191aS1jb21wb25lbnRzLWJ1dHRvbnMtYnV0dG9uXG4gICAgICAgICAgICAgICAgICBbdHlwZV09XCInYnV0dG9uLXRoaXJkJ1wiXG4gICAgICAgICAgICAgICAgICBbaWNvbk9ubHlUeXBlXT1cInRydWVcIlxuICAgICAgICAgICAgICAgICAgW3NpemVCdXR0b25dPVwiJ3NtYWxsZXInXCJcbiAgICAgICAgICAgICAgICAgIFtjbGFzc0ljb25MZWZ0XT1cIidsaWJzLXVpLWljb24tYWRkJ1wiXG4gICAgICAgICAgICAgICAgICBbcG9wb3Zlcl09XCJ7IGNvbmZpZzogeyBjb250ZW50OiAnVGjDqm0ga2jhu5FpIHbDoG8gdHJvbmcnLCB6SW5kZXg6IDEzMDAgfSB9XCJcbiAgICAgICAgICAgICAgICAgIChvdXRDbGljayk9XCJoYW5kbGVyQWRkSW5zaWRlKCRldmVudCwgaXRlbSlcIiAvPlxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIEBpZiAoY2FuVG9nZ2xlVHlwZShpdGVtKSkge1xuICAgICAgICAgICAgICAgIDxsaWJzX3VpLWNvbXBvbmVudHMtYnV0dG9ucy1idXR0b25cbiAgICAgICAgICAgICAgICAgIFt0eXBlXT1cIididXR0b24tdGhpcmQnXCJcbiAgICAgICAgICAgICAgICAgIFtpY29uT25seVR5cGVdPVwidHJ1ZVwiXG4gICAgICAgICAgICAgICAgICBbc2l6ZUJ1dHRvbl09XCInc21hbGxlcidcIlxuICAgICAgICAgICAgICAgICAgW2NsYXNzSWNvbkxlZnRdPVwiaXNDb250YWluZXIoaXRlbSkgPyAnbGlicy11aS1pY29uLXNwbGl0LWNlbGwnIDogJ2xpYnMtdWktaWNvbi1tZXJnZS1jZWxsJ1wiXG4gICAgICAgICAgICAgICAgICBbcG9wb3Zlcl09XCJ7IGNvbmZpZzogeyBjb250ZW50OiBpc0NvbnRhaW5lcihpdGVtKSA/ICfEkMawYSB24buBIGto4buRaSDEkcahbicgOiAnQ2h1eeG7g24gdGjDoG5oIGto4buRaSBnaMOpcCcsIHpJbmRleDogMTMwMCB9IH1cIlxuICAgICAgICAgICAgICAgICAgKG91dENsaWNrKT1cImhhbmRsZXJUb2dnbGVUeXBlKCRldmVudCwgaXRlbSlcIiAvPlxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIDxsaWJzX3VpLWNvbXBvbmVudHMtYnV0dG9ucy1idXR0b25cbiAgICAgICAgICAgICAgICBbdHlwZV09XCInYnV0dG9uLXRoaXJkJ1wiXG4gICAgICAgICAgICAgICAgW2ljb25Pbmx5VHlwZV09XCJ0cnVlXCJcbiAgICAgICAgICAgICAgICBbc2l6ZUJ1dHRvbl09XCInc21hbGxlcidcIlxuICAgICAgICAgICAgICAgIFtjbGFzc0ljb25MZWZ0XT1cIidsaWJzLXVpLWljb24tc2V0dGluZydcIlxuICAgICAgICAgICAgICAgIFtwb3BvdmVyXT1cInsgY29uZmlnOiB7IGNvbnRlbnQ6ICdD4bqldSBow6xuaCB0aOG6uycsIHpJbmRleDogMTMwMCB9IH1cIlxuICAgICAgICAgICAgICAgIChvdXRDbGljayk9XCJoYW5kbGVyQ29uZmlnKCRldmVudCwgaXRlbSlcIiAvPlxuICAgICAgICAgICAgICA8bGlic191aS1jb21wb25lbnRzLWJ1dHRvbnMtYnV0dG9uXG4gICAgICAgICAgICAgICAgW3R5cGVdPVwiJ2J1dHRvbi10aGlyZC1ob3Zlci1kYW5nZXInXCJcbiAgICAgICAgICAgICAgICBbaWNvbk9ubHlUeXBlXT1cInRydWVcIlxuICAgICAgICAgICAgICAgIFtzaXplQnV0dG9uXT1cIidzbWFsbGVyJ1wiXG4gICAgICAgICAgICAgICAgW2NsYXNzSWNvbkxlZnRdPVwiJ2xpYnMtdWktaWNvbi1yZW1vdmUnXCJcbiAgICAgICAgICAgICAgICBbcG9wb3Zlcl09XCJ7IGNvbmZpZzogeyBjb250ZW50OiBpc0NvbnRhaW5lcihpdGVtKSA/ICdYb8OhIGPhuqMga2jhu5FpIGdow6lwJyA6ICdYb8OhIGto4buRaScsIHpJbmRleDogMTMwMCB9IH1cIlxuICAgICAgICAgICAgICAgIChvdXRDbGljayk9XCJoYW5kbGVyUmVtb3ZlKCRldmVudCwgaXRlbSlcIiAvPlxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgQGlmIChpdGVtLmNoaWxkcmVuICYmIGl0ZW0uY2hpbGRyZW4ubGVuZ3RoID4gMCkge1xuICAgICAgICAgIDwhLS0gS2jhu5FpIGPDsyBjb24g4oaSIHJ14buZdCBuw7MgbOG6oWkgbMOgIG3hu5l0IG3hurd0IHBo4bqzbmcgbuG7r2EuIMSQ4buHIHF1eSDhu58gxJHDonksIG7GoWkgZMO5bmcga2jDtG5nIHBo4bqjaSBsby5cbiAgICAgICAgICAgICAgIEzhu4EgxJHhurd0IOG7nyDEkMOCWSAoduG7jyBjb250YWluZXIpLCBraMO0bmcgxJHhurd0IHbDoG8gbMaw4bubaSBjb24g4oCUIGzGsOG7m2kgY29uIGdp4buvIG5ndXnDqm4ga2hlIDJweC4gLS0+XG4gICAgICAgICAgPGxpYnNfdWktc2VydmljZXMtZ3JpZF9sYXlvdXQtY2FudmFzXG4gICAgICAgICAgICBjbGFzcz1cImJsb2NrIGgtZnVsbCB3LWZ1bGxcIlxuICAgICAgICAgICAgW3N0eWxlLnBhZGRpbmddPVwiY29udGFpbmVyUGFkZGluZygpXCJcbiAgICAgICAgICAgIFtub2RlXT1cIml0ZW1cIlxuICAgICAgICAgICAgW2RlcHRoXT1cImRlcHRoKCkgKyAxXCJcbiAgICAgICAgICAgIFtoaWRkZW5Ub29sYmFyXT1cImhpZGRlblRvb2xiYXIoKVwiXG4gICAgICAgICAgICBbdGVtcGxhdGVUb29sYmFyXT1cInRlbXBsYXRlVG9vbGJhcigpXCJcbiAgICAgICAgICAgIFtzZWxlY3RlZE5vZGVJZF09XCJzZWxlY3RlZE5vZGVJZCgpXCJcbiAgICAgICAgICAgIChvdXRTZWxlY3ROb2RlKT1cIm91dFNlbGVjdE5vZGUuZW1pdCgkZXZlbnQpXCJcbiAgICAgICAgICAgIChvdXRDb25maWdOb2RlKT1cIm91dENvbmZpZ05vZGUuZW1pdCgkZXZlbnQpXCJcbiAgICAgICAgICAgIChvdXRDaGFuZ2UpPVwib3V0Q2hhbmdlLmVtaXQoJGV2ZW50KVwiXG4gICAgICAgICAgICAob3V0UmVtb3ZlTm9kZSk9XCJvdXRSZW1vdmVOb2RlLmVtaXQoJGV2ZW50KVwiXG4gICAgICAgICAgICAob3V0QWRkQmxvY2tJbnNpZGUpPVwib3V0QWRkQmxvY2tJbnNpZGUuZW1pdCgkZXZlbnQpXCJcbiAgICAgICAgICAgIChvdXRUb2dnbGVUeXBlKT1cIm91dFRvZ2dsZVR5cGUuZW1pdCgkZXZlbnQpXCIgLz5cbiAgICAgICAgfVxuICAgICAgPC9kaXY+XG4gICAgPC9ncmlkc3Rlci1pdGVtPlxuICB9XG4gICAgICA8L2dyaWRzdGVyPlxuICAgIDwvZGl2PlxuICA8L2Rpdj5cblxuICA8IS0tIFRoYW5oIGRvY2sgxJFp4buBdSBraGnhu4NuIHRodSBwaMOzbmcgbuG7lWkg4bufIGfDs2MgZMaw4bubaSB0csOhaSAtLT5cbiAgQGlmIChzaG93Wm9vbURvY2soKSkge1xuICAgIDxkaXZcbiAgICAgICN6b29tRG9ja1xuICAgICAgaWQ9XCJjYW52YXMtem9vbS1kb2NrXCJcbiAgICAgIHJvbGU9XCJ0b29sYmFyXCJcbiAgICAgIHRhYmluZGV4PVwiMFwiXG4gICAgICBjbGFzcz1cImFic29sdXRlIGJvdHRvbS00IGxlZnQtNiB6LTMwIGZsZXggaXRlbXMtY2VudGVyIGJnLXdoaXRlIHJvdW5kZWQtZnVsbCBzaGFkb3ctMnhsIGJvcmRlci0yIGJvcmRlci1zbGF0ZS00MDAgcC0xIHNwYWNlLXgtMSBzZWxlY3Qtbm9uZVwiXG4gICAgICAobW91c2Vkb3duKT1cIiRldmVudC5zdG9wUHJvcGFnYXRpb24oKVwiXG4gICAgICAoa2V5ZG93bik9XCIkZXZlbnQuc3RvcFByb3BhZ2F0aW9uKClcIlxuICAgICAgKGNsaWNrKT1cIiRldmVudC5zdG9wUHJvcGFnYXRpb24oKVwiPlxuICAgICAgPCEtLSBUaHUgbmjhu48gKC0pIC0tPlxuICAgICAgPGJ1dHRvblxuICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgY2xhc3M9XCJ3LVsyOHB4XSBoLVsyOHB4XSBmbGV4IGl0ZW1zLWNlbnRlciBqdXN0aWZ5LWNlbnRlciByb3VuZGVkLWZ1bGwgdGV4dC1zbGF0ZS03MDAgaG92ZXI6dGV4dC1zbGF0ZS05MDAgaG92ZXI6Ymctc2xhdGUtMjAwIGRpc2FibGVkOm9wYWNpdHktMzAgZGlzYWJsZWQ6aG92ZXI6YmctdHJhbnNwYXJlbnQgdHJhbnNpdGlvbi1jb2xvcnMgY3Vyc29yLXBvaW50ZXJcIlxuICAgICAgICBbZGlzYWJsZWRdPVwiY3VycmVudFpvb20oKSA8PSB6b29tTWluKClcIlxuICAgICAgICBbdGl0bGVdPVwiJ2kxOG5fem9vbV9vdXQnIHwgdHJhbnNsYXRlXCJcbiAgICAgICAgKGNsaWNrKT1cImhhbmRsZXJab29tT3V0KClcIj5cbiAgICAgICAgPHN2ZyBjbGFzcz1cInctMy41IGgtMy41XCIgdmlld0JveD1cIjAgMCAyNCAyNFwiIGZpbGw9XCJub25lXCIgc3Ryb2tlPVwiY3VycmVudENvbG9yXCIgc3Ryb2tlLXdpZHRoPVwiMi41XCIgc3Ryb2tlLWxpbmVjYXA9XCJyb3VuZFwiPjxsaW5lIHgxPVwiNVwiIHkxPVwiMTJcIiB4Mj1cIjE5XCIgeTI9XCIxMlwiLz48L3N2Zz5cbiAgICAgIDwvYnV0dG9uPlxuXG4gICAgICA8IS0tIFThu7cgbOG7hyAlIHbDoCBtZW51IHByZXNldCAtLT5cbiAgICAgIDxkaXYgY2xhc3M9XCJyZWxhdGl2ZVwiPlxuICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgY2xhc3M9XCJoLVsyOHB4XSBweC0yIGZsZXggaXRlbXMtY2VudGVyIGdhcC0xIHJvdW5kZWQtZnVsbCB0ZXh0LXhzIGZvbnQtc2VtaWJvbGQgdGV4dC1zbGF0ZS03MDAgaG92ZXI6Ymctc2xhdGUtMjAwIHRyYW5zaXRpb24tY29sb3JzIGN1cnNvci1wb2ludGVyXCJcbiAgICAgICAgICBbdGl0bGVdPVwiJ2kxOG5fem9vbV9vcHRpb25zJyB8IHRyYW5zbGF0ZVwiXG4gICAgICAgICAgKGNsaWNrKT1cImhhbmRsZXJUb2dnbGVNZW51KClcIj5cbiAgICAgICAgICA8c3Bhbj57eyB6b29tUGVyY2VudCgpIH19JTwvc3Bhbj5cbiAgICAgICAgICA8c3ZnIGNsYXNzPVwidy1bMTJweF0gaC1bMTJweF0gdGV4dC1zbGF0ZS00MDAgdHJhbnNpdGlvbi10cmFuc2Zvcm0gZHVyYXRpb24tMTUwXCIgW2NsYXNzLnJvdGF0ZS0xODBdPVwiaXNNZW51T3BlbigpXCIgdmlld0JveD1cIjAgMCAyNCAyNFwiIGZpbGw9XCJub25lXCIgc3Ryb2tlPVwiY3VycmVudENvbG9yXCIgc3Ryb2tlLXdpZHRoPVwiMi41XCIgc3Ryb2tlLWxpbmVjYXA9XCJyb3VuZFwiIHN0cm9rZS1saW5lam9pbj1cInJvdW5kXCI+PHBvbHlsaW5lIHBvaW50cz1cIjYgOSAxMiAxNSAxOCA5XCIvPjwvc3ZnPlxuICAgICAgICA8L2J1dHRvbj5cblxuICAgICAgICA8IS0tIE1lbnUgZHJvcGRvd24gY8OhYyBt4buRYyB0aHUgcGjDs25nIC0tPlxuICAgICAgICBAaWYgKGlzTWVudU9wZW4oKSkge1xuICAgICAgICAgIDxkaXYgY2xhc3M9XCJhYnNvbHV0ZSBib3R0b20tZnVsbCBtYi0yIGxlZnQtMCB3LVsyNTZweF0gYmctd2hpdGUgcm91bmRlZC14bCBzaGFkb3cteGwgYm9yZGVyIGJvcmRlci1zbGF0ZS0yMDAgcHktMS41IHotNDAgdGV4dC14cyBzZWxlY3Qtbm9uZVwiPlxuICAgICAgICAgICAgPGRpdiBjbGFzcz1cInB4LTMgcHktMSB0ZXh0LVsxMXB4XSBmb250LXNlbWlib2xkIHRleHQtc2xhdGUtNDAwIHVwcGVyY2FzZSB0cmFja2luZy13aWRlclwiPlxuICAgICAgICAgICAgICB7eyAnaTE4bl96b29tX2NhbnZhc193aWR0aCcgfCB0cmFuc2xhdGU6IHsgd2lkdGg6IHN0YWdlV2lkdGgoKSB9IH19XG4gICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgIDxidXR0b25cbiAgICAgICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgICAgIGNsYXNzPVwidy1mdWxsIHB4LTMgcHktMiB0ZXh0LWxlZnQgZmxleCBpdGVtcy1jZW50ZXIganVzdGlmeS1iZXR3ZWVuIGhvdmVyOmJnLXNsYXRlLTUwIHRyYW5zaXRpb24tY29sb3JzIGN1cnNvci1wb2ludGVyXCJcbiAgICAgICAgICAgICAgKGNsaWNrKT1cImhhbmRsZXJGaXRTY3JlZW4oKVwiPlxuICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cImZsZXggaXRlbXMtY2VudGVyIGdhcC0yIHRleHQtc2xhdGUtNzAwIGZvbnQtbWVkaXVtXCI+XG4gICAgICAgICAgICAgICAgPHN2ZyBjbGFzcz1cInctMy41IGgtMy41IHRleHQtc2xhdGUtNjAwXCIgdmlld0JveD1cIjAgMCAyNCAyNFwiIGZpbGw9XCJub25lXCIgc3Ryb2tlPVwiY3VycmVudENvbG9yXCIgc3Ryb2tlLXdpZHRoPVwiMlwiPjxwb2x5bGluZSBwb2ludHM9XCIxNSAzIDIxIDMgMjEgOVwiLz48cG9seWxpbmUgcG9pbnRzPVwiOSAyMSAzIDIxIDMgMTVcIi8+PGxpbmUgeDE9XCIyMVwiIHkxPVwiM1wiIHgyPVwiMTRcIiB5Mj1cIjEwXCIvPjxsaW5lIHgxPVwiM1wiIHkxPVwiMjFcIiB4Mj1cIjEwXCIgeTI9XCIxNFwiLz48L3N2Zz5cbiAgICAgICAgICAgICAgICB7eyAnaTE4bl96b29tX2ZpdF9zY3JlZW4nIHwgdHJhbnNsYXRlIH19XG4gICAgICAgICAgICAgIDwvc3Bhbj5cbiAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJ0ZXh0LVsxMHB4XSBiZy1ibHVlLTUwIHRleHQtYmx1ZS02MDAgcHgtMS41IHB5LTAuNSByb3VuZGVkIGZvbnQtbWVkaXVtXCI+e3sgJ2kxOG5fYXV0bycgfCB0cmFuc2xhdGUgfX08L3NwYW4+XG4gICAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJoLXB4IGJnLXNsYXRlLTEwMCBteS0xXCI+PC9kaXY+XG4gICAgICAgICAgICBAZm9yIChwcmVzZXQgb2Ygem9vbVByZXNldHM7IHRyYWNrIHByZXNldC52YWx1ZSkge1xuICAgICAgICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgICAgICAgY2xhc3M9XCJ3LWZ1bGwgcHgtMyBweS0xLjUgdGV4dC1sZWZ0IGZsZXggaXRlbXMtY2VudGVyIGp1c3RpZnktYmV0d2VlbiBob3ZlcjpiZy1zbGF0ZS01MCB0cmFuc2l0aW9uLWNvbG9ycyBjdXJzb3ItcG9pbnRlclwiXG4gICAgICAgICAgICAgICAgW2NsYXNzLnRleHQtYmx1ZS02MDBdPVwiaXNDdXJyZW50UHJlc2V0KHByZXNldC52YWx1ZSlcIlxuICAgICAgICAgICAgICAgIFtjbGFzcy5mb250LXNlbWlib2xkXT1cImlzQ3VycmVudFByZXNldChwcmVzZXQudmFsdWUpXCJcbiAgICAgICAgICAgICAgICBbY2xhc3MuYmctYmx1ZS01MF09XCJpc0N1cnJlbnRQcmVzZXQocHJlc2V0LnZhbHVlKVwiXG4gICAgICAgICAgICAgICAgKGNsaWNrKT1cImhhbmRsZXJTZWxlY3RQcmVzZXQocHJlc2V0LnZhbHVlKVwiPlxuICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwidGV4dC1zbGF0ZS03MDBcIiBbY2xhc3MudGV4dC1ibHVlLTYwMF09XCJpc0N1cnJlbnRQcmVzZXQocHJlc2V0LnZhbHVlKVwiPlxuICAgICAgICAgICAgICAgICAge3sgcHJlc2V0LmxhYmVsIHwgdHJhbnNsYXRlIH19XG4gICAgICAgICAgICAgICAgPC9zcGFuPlxuICAgICAgICAgICAgICAgIEBpZiAoaXNDdXJyZW50UHJlc2V0KHByZXNldC52YWx1ZSkpIHtcbiAgICAgICAgICAgICAgICAgIDxzdmcgY2xhc3M9XCJ3LTMuNSBoLTMuNSB0ZXh0LWJsdWUtNjAwXCIgdmlld0JveD1cIjAgMCAyNCAyNFwiIGZpbGw9XCJub25lXCIgc3Ryb2tlPVwiY3VycmVudENvbG9yXCIgc3Ryb2tlLXdpZHRoPVwiMi41XCIgc3Ryb2tlLWxpbmVjYXA9XCJyb3VuZFwiIHN0cm9rZS1saW5lam9pbj1cInJvdW5kXCI+PHBvbHlsaW5lIHBvaW50cz1cIjIwIDYgOSAxNyA0IDEyXCIvPjwvc3ZnPlxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgPC9idXR0b24+XG4gICAgICAgICAgICB9XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgIH1cbiAgICAgIDwvZGl2PlxuXG4gICAgICA8IS0tIFBow7NuZyB0byAoKykgLS0+XG4gICAgICA8YnV0dG9uXG4gICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICBjbGFzcz1cInctWzI4cHhdIGgtWzI4cHhdIGZsZXggaXRlbXMtY2VudGVyIGp1c3RpZnktY2VudGVyIHJvdW5kZWQtZnVsbCB0ZXh0LXNsYXRlLTcwMCBob3Zlcjp0ZXh0LXNsYXRlLTkwMCBob3ZlcjpiZy1zbGF0ZS0yMDAgZGlzYWJsZWQ6b3BhY2l0eS0zMCBkaXNhYmxlZDpob3ZlcjpiZy10cmFuc3BhcmVudCB0cmFuc2l0aW9uLWNvbG9ycyBjdXJzb3ItcG9pbnRlclwiXG4gICAgICAgIFtkaXNhYmxlZF09XCJjdXJyZW50Wm9vbSgpID49IHpvb21NYXgoKVwiXG4gICAgICAgIFt0aXRsZV09XCInaTE4bl96b29tX2luJyB8IHRyYW5zbGF0ZVwiXG4gICAgICAgIChjbGljayk9XCJoYW5kbGVyWm9vbUluKClcIj5cbiAgICAgICAgPHN2ZyBjbGFzcz1cInctMy41IGgtMy41XCIgdmlld0JveD1cIjAgMCAyNCAyNFwiIGZpbGw9XCJub25lXCIgc3Ryb2tlPVwiY3VycmVudENvbG9yXCIgc3Ryb2tlLXdpZHRoPVwiMi41XCIgc3Ryb2tlLWxpbmVjYXA9XCJyb3VuZFwiPjxsaW5lIHgxPVwiMTJcIiB5MT1cIjVcIiB4Mj1cIjEyXCIgeTI9XCIxOVwiLz48bGluZSB4MT1cIjVcIiB5MT1cIjEyXCIgeDI9XCIxOVwiIHkyPVwiMTJcIi8+PC9zdmc+XG4gICAgICA8L2J1dHRvbj5cblxuICAgICAgPCEtLSBQaMOibiBjw6FjaCAtLT5cbiAgICAgIDxkaXYgY2xhc3M9XCJoLVsxNnB4XSB3LXB4IGJnLXNsYXRlLTIwMFwiPjwvZGl2PlxuXG4gICAgICA8IS0tIE7DunQgVuG7q2EgbcOgbiBow6xuaCBuaGFuaCAtLT5cbiAgICAgIDxidXR0b25cbiAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgIGNsYXNzPVwiaC1bMjhweF0gc2hyaW5rLTAgcHgtMi41IGZsZXggaXRlbXMtY2VudGVyIGdhcC0xIHJvdW5kZWQtZnVsbCB0ZXh0LXhzIHRleHQtc2xhdGUtNzAwIGhvdmVyOnRleHQtc2xhdGUtOTAwIGhvdmVyOmJnLXNsYXRlLTIwMCB0cmFuc2l0aW9uLWNvbG9ycyBjdXJzb3ItcG9pbnRlclwiXG4gICAgICAgIFt0aXRsZV09XCInaTE4bl96b29tX2ZpdF9zY3JlZW5fdG9vbHRpcCcgfCB0cmFuc2xhdGVcIlxuICAgICAgICAoY2xpY2spPVwiaGFuZGxlckZpdFNjcmVlbigpXCI+XG4gICAgICAgIDxzdmcgY2xhc3M9XCJ3LTMuNSBoLTMuNVwiIHZpZXdCb3g9XCIwIDAgMjQgMjRcIiBmaWxsPVwibm9uZVwiIHN0cm9rZT1cImN1cnJlbnRDb2xvclwiIHN0cm9rZS13aWR0aD1cIjJcIj48cG9seWxpbmUgcG9pbnRzPVwiMTUgMyAyMSAzIDIxIDlcIi8+PHBvbHlsaW5lIHBvaW50cz1cIjkgMjEgMyAyMSAzIDE1XCIvPjxsaW5lIHgxPVwiMjFcIiB5MT1cIjNcIiB4Mj1cIjE0XCIgeTI9XCIxMFwiLz48bGluZSB4MT1cIjNcIiB5MT1cIjIxXCIgeDI9XCIxMFwiIHkyPVwiMTRcIi8+PC9zdmc+XG4gICAgICAgIDxzcGFuIGNsYXNzPVwid2hpdGVzcGFjZS1ub3dyYXAgZm9udC1tZWRpdW1cIj57eyAnaTE4bl96b29tX2ZpdF9zY3JlZW4nIHwgdHJhbnNsYXRlIH19PC9zcGFuPlxuICAgICAgPC9idXR0b24+XG5cbiAgICAgIDwhLS0gTsO6dCDEkOG6t3QgbOG6oWkgMTAwJSAoY2jhu4kgaGnhu4duIGtoaSBraMOhYyAxMDAlKSAtLT5cbiAgICAgIEBpZiAoem9vbVBlcmNlbnQoKSAhPT0gMTAwKSB7XG4gICAgICAgIDxidXR0b25cbiAgICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgICBjbGFzcz1cImgtWzI4cHhdIHB4LTIgZmxleCBpdGVtcy1jZW50ZXIgZ2FwLTEgcm91bmRlZC1mdWxsIHRleHQteHMgZm9udC1zZW1pYm9sZCB0ZXh0LWJsdWUtNjAwIGhvdmVyOmJnLWJsdWUtNTAgdHJhbnNpdGlvbi1jb2xvcnMgY3Vyc29yLXBvaW50ZXJcIlxuICAgICAgICAgIFt0aXRsZV09XCInaTE4bl96b29tX3Jlc2V0X3Rvb2x0aXAnIHwgdHJhbnNsYXRlOiB7IHdpZHRoOiBzdGFnZVdpZHRoKCksIGhlaWdodDogc3RhZ2VNaW5IZWlnaHQoKSB9XCJcbiAgICAgICAgICAoY2xpY2spPVwiaGFuZGxlclJlc2V0Wm9vbSgpXCI+XG4gICAgICAgICAgPHN2ZyBjbGFzcz1cInctWzEycHhdIGgtWzEycHhdXCIgdmlld0JveD1cIjAgMCAyNCAyNFwiIGZpbGw9XCJub25lXCIgc3Ryb2tlPVwiY3VycmVudENvbG9yXCIgc3Ryb2tlLXdpZHRoPVwiMlwiIHN0cm9rZS1saW5lY2FwPVwicm91bmRcIiBzdHJva2UtbGluZWpvaW49XCJyb3VuZFwiPjxwb2x5bGluZSBwb2ludHM9XCIxIDQgMSAxMCA3IDEwXCIvPjxwYXRoIGQ9XCJNMy41MSAxNWE5IDkgMCAxIDAgMi4xMy05LjM2TDEgMTBcIi8+PC9zdmc+XG4gICAgICAgICAgPHNwYW4+MTAwJTwvc3Bhbj5cbiAgICAgICAgPC9idXR0b24+XG4gICAgICB9XG4gICAgPC9kaXY+XG4gIH1cbn0gQGVsc2Uge1xuICA8IS0tIPCflLQgYHJlbGF0aXZlYCBsw6AgQuG6rlQgQlXhu5hDLCBD4bqkTSBi4buPLlxuICAgICAgIGdyaWRzdGVyIMSR4buVaSB24buLIHRyw60gY2h14buZdCB0aMOgbmggw7QgbMaw4bubaSBi4bqxbmcgYGUuY2xpZW50WSArIChlbC5zY3JvbGxUb3AgLSBlbC5vZmZzZXRUb3ApYCDigJQgY8O0bmdcbiAgICAgICB0aOG7qWMgxJHDsyBjaOG7iSDEkcO6bmcga2hpIGBvZmZzZXRQYXJlbnRgIGPhu6dhIDxncmlkc3Rlcj4gQ0jDjU5IIEzDgCBraOG7kWkgY3Xhu5luIG7DoHkuIFRoaeG6v3UgYHJlbGF0aXZlYCB0aMOsXG4gICAgICAgYG9mZnNldFBhcmVudGAgbmjhuqN5IGzDqm4ga2jhu5FpIGJhbyBuZ2/DoGk6IGBvZmZzZXRUb3BgIHRy4bqjIDE2IHRyb25nIGtoaSBs4buHY2ggdGjhuq10IGzDoCA2NSDihpIgZ3JpZHN0ZXJcbiAgICAgICB0w61uaCDDtCBzYWkgNDlweCwgw7QgY2jhu50gxJHhurd0IGhp4buHbiBs4buHY2gga2jhu49pIGNvbiB0cuG7jyBuw6puIGvDqW8gdGjhuqMga2jDtG5nIMSR4buVaSDEkcaw4bujYyB24buLIHRyw60sIHbDoCBrw6lvIG3DqXBcbiAgICAgICBjxaluZyB0w61uaCBzYWkgxJFp4buDbSBk4burbmcuIC0tPlxuICA8ZGl2XG4gICAgI3Njcm9sbEFyZWFcbiAgICBjbGFzcz1cImxpYnMtdWktZ3JpZC1sYXlvdXQtc2Nyb2xsLWFyZWEgcmVsYXRpdmUgaC1mdWxsIG1pbi1oLTAgdy1mdWxsIG1pbi13LTBcIlxuICAgIFtjbGFzcy5vdmVyZmxvdy15LWF1dG9dPVwiIWlzTmVzdGVkQ2FudmFzKClcIlxuICAgIChtb3VzZWRvd24pPVwiaGFuZGxlck1vdXNlRG93blRyb25nTHVvaSgkZXZlbnQpXCJcbiAgICAoZHJhZ292ZXIpPVwiaGFuZGxlckRyYWdPdmVyKCRldmVudClcIlxuICAgIChkcmFnbGVhdmUpPVwiaGFuZGxlckRyYWdMZWF2ZSgkZXZlbnQpXCJcbiAgICAoZHJvcCk9XCJoYW5kbGVyRHJvcCgkZXZlbnQpXCI+XG4gICAgPCEtLSBTbmFwcGVkIERyb3AgR2hvc3QgUHJldmlldyAtLT5cbiAgICBAaWYgKGRyb3BHaG9zdCgpOyBhcyBnaG9zdCkge1xuICAgICAgPGRpdlxuICAgICAgICBjbGFzcz1cInBvaW50ZXItZXZlbnRzLW5vbmUgYWJzb2x1dGUgei0zMCBmbGV4IGZsZXgtY29sIGl0ZW1zLWNlbnRlciBqdXN0aWZ5LWNlbnRlciBvdmVyZmxvdy1oaWRkZW4gcm91bmRlZC1sZyBib3JkZXItMiBib3JkZXItZGFzaGVkIGJvcmRlci1ibHVlLTUwMCBiZy1ibHVlLTUwMC8xNSBwLTEgc2hhZG93LXNtIHRyYW5zaXRpb24tYWxsIGR1cmF0aW9uLTc1IGVhc2Utb3V0IGJhY2tkcm9wLWJsdXItWzAuNXB4XSBzZWxlY3Qtbm9uZVwiXG4gICAgICAgIFtzdHlsZS5sZWZ0LnB4XT1cImdob3N0LnBpeGVsTGVmdFwiXG4gICAgICAgIFtzdHlsZS50b3AucHhdPVwiZ2hvc3QucGl4ZWxUb3BcIlxuICAgICAgICBbc3R5bGUud2lkdGgucHhdPVwiZ2hvc3QucGl4ZWxXaWR0aFwiXG4gICAgICAgIFtzdHlsZS5oZWlnaHQucHhdPVwiZ2hvc3QucGl4ZWxIZWlnaHRcIj5cbiAgICAgICAgPGRpdiBjbGFzcz1cImlubGluZS1mbGV4IG1heC13LVs5NSVdIGl0ZW1zLWNlbnRlciBnYXAtMSB0cnVuY2F0ZSByb3VuZGVkLW1kIGJnLWJsdWUtNjAwIHB4LTIgcHktMC41IHRleHQtWzExcHhdIGZvbnQtc2VtaWJvbGQgdGV4dC13aGl0ZSBzaGFkb3cteHNcIj5cbiAgICAgICAgICBAaWYgKGdob3N0LmNhcmRJY29uQ2xhc3MpIHtcbiAgICAgICAgICAgIDxpIFtjbGFzc109XCJnaG9zdC5jYXJkSWNvbkNsYXNzICsgJyB0ZXh0LXhzJ1wiPjwvaT5cbiAgICAgICAgICB9IEBlbHNlIGlmIChnaG9zdC5jYXJkSWNvblRleHQpIHtcbiAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwidGV4dC1bMTBweF0gZm9udC1ib2xkXCI+e3sgZ2hvc3QuY2FyZEljb25UZXh0IH19PC9zcGFuPlxuICAgICAgICAgIH0gQGVsc2Uge1xuICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJ0ZXh0LXhzIGZvbnQtYm9sZFwiPnt7IGdob3N0LmlzSW5zaWRlR3JvdXAgPyAn4oazJyA6ICcrJyB9fTwvc3Bhbj5cbiAgICAgICAgICB9XG4gICAgICAgICAgPHNwYW4gY2xhc3M9XCJ0cnVuY2F0ZVwiPnt7IGdob3N0LmNhcmRUaXRsZSB9fTwvc3Bhbj5cbiAgICAgICAgICA8c3BhbiBjbGFzcz1cInRleHQtWzlweF0gZm9udC1tb25vIG9wYWNpdHktNzVcIj4oe3sgZ2hvc3QuY29scyB9fWMpPC9zcGFuPlxuICAgICAgICA8L2Rpdj5cblxuICAgICAgICBAaWYgKGdob3N0LnBpeGVsSGVpZ2h0ID49IDgwKSB7XG4gICAgICAgICAgPGRpdiBjbGFzcz1cIm10LTEgZmxleCBtYXgtdy1bOTUlXSBpdGVtcy1jZW50ZXIgZ2FwLTEuNSB0cnVuY2F0ZSByb3VuZGVkIGJvcmRlciBib3JkZXItYmx1ZS0xMDAgYmctd2hpdGUvOTUgcHgtMiBweS0wLjUgdGV4dC1bMTBweF0gZm9udC1tZWRpdW0gdGV4dC1ibHVlLTcwMCBzaGFkb3cteHNcIj5cbiAgICAgICAgICAgIEBpZiAoZ2hvc3QuaXNJbnNpZGVHcm91cCkge1xuICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cInRydW5jYXRlIGZvbnQtYm9sZCB0ZXh0LWJsdWUtOTAwXCI+4oazIHt7IGdob3N0Lmdyb3VwVGl0bGUgfX08L3NwYW4+XG4gICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwidGV4dC1ibHVlLTMwMFwiPuKAojwvc3Bhbj5cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIDxzcGFuPkPhu5l0IHt7IGdob3N0LmNvbCArIDEgfX0te3sgZ2hvc3QuY29sICsgZ2hvc3QuY29scyB9fTwvc3Bhbj5cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgfVxuICAgICAgPC9kaXY+XG4gICAgfVxuICAgIDxncmlkc3RlciBjbGFzcz1cImgtZnVsbCB3LWZ1bGxcIiBbY2xhc3MuZGlzcGxheS1ncmlkXT1cInNob3dHcmlkTGluZXMoKVwiIFtvcHRpb25zXT1cImdyaWRPcHRpb25zKClcIj5cbiAgICAgICAgQGZvciAoaXRlbSBvZiBjaGlsZHJlbigpOyB0cmFjayBpdGVtLmlkOyBsZXQgaXRlbUluZGV4ID0gJGluZGV4KSB7XG4gICAgPCEtLSDwn5S0IENo4bq3biBgbW91c2Vkb3duYCB04bqhaSDEkMOCWSBjaG8gbMaw4bubaSBs4buTbmcg4oCUIEPhuqRNIGLhu48gdsOgIEPhuqRNIGNodXnhu4NuIHNhbmcgY2jhu5cga2jDoWMuXG4gICAgICAgICBgaWdub3JlQ29udGVudENsYXNzYCBt4buZdCBtw6xuaCBLSMOUTkcgxJHhu6c6IGBkZWxheVN0YXJ0OiAxNjBgIGzDoG0gTeG7lkkgbMaw4bubaSBsw6puIGzhu4tjaFxuICAgICAgICAgYGRyYWdTdGFydGAgYuG6sW5nIGBzZXRUaW1lb3V0YCBuZ2F5IHThuqFpIGBtb3VzZWRvd25gLCBjw7JuIGBzdG9wUHJvcGFnYXRpb25gIG3DoCBsaWIgZ+G7jWkgYsOqblxuICAgICAgICAgdHJvbmcgYGRyYWdTdGFydGAgY2jhuqF5IHNhdSAxNjBtcyBuw6puIHF1w6EgbXXhu5luIOKAlCBsxrDhu5tpIENIQSDEkcOjIGvhu4twIG5o4bqtbiAoxJFvIDI4LzA4LzIwMjY6IGvDqW9cbiAgICAgICAgIGThuqNpIGto4buRaSBjb24sIGNodeG7l2kgY2xhc3MgZHV54buHdCBsw6puIMSQw5pORyBtw6AgY29udGFpbmVyIHbhuqtuIG5o4bqjeSAwLDAg4oaSIDAsMSkuXG4gICAgICAgICBH4bqvbiDhu58gYGdyaWRzdGVyLWl0ZW1gIGzDoCDEkcO6bmcgYmnDqm46IGzGsOG7m2kgY29uIG5naGUgdHLDqm4gY2jDrW5oIHBo4bqnbiB04butIG7DoHkgbsOqbiDEkcOjIG5o4bqtbiB4b25nLFxuICAgICAgICAgbMaw4bubaSBjaGEg4bufIG5nb8OgaSBi4buLIGNo4bq3bi4gLS0+XG4gICAgPGdyaWRzdGVyLWl0ZW1cbiAgICAgIFtpdGVtXT1cIml0ZW1cIlxuICAgICAgW2NsYXNzLmxpYnMtdWktZ3JpZC1sYXlvdXQtc2VsZWN0ZWRdPVwic2VsZWN0ZWROb2RlSWQoKSA9PT0gaXRlbS5pZFwiXG4gICAgICAoY2xpY2spPVwiaGFuZGxlclNlbGVjdE5vZGUoaXRlbSwgJGV2ZW50KVwiXG4gICAgICAobW91c2Vkb3duKT1cImhhbmRsZXJCbG9ja1BhcmVudERyYWcoJGV2ZW50KVwiPlxuICAgICAgPCEtLSDwn5S0IFbhu48gbsOgeSBtYW5nIGBkcmFnSGFuZGxlQ2xhc3NgIOKAlCBD4bqkTSBi4buPLlxuICAgICAgICAgICBgaWdub3JlQ29udGVudDogdHJ1ZWAgYuG6r3QgZ3JpZHN0ZXIgQ0jhu4ggY2hvIGvDqW8ga2hpIGNo4buXIGLhuqVtIG7hurFtIGTGsOG7m2kgbeG7mXQgcGjhuqduIHThu60gY8OzXG4gICAgICAgICAgIGBkcmFnSGFuZGxlQ2xhc3NgLiBLaMO0bmcgY8OzIHbhu48gbsOgeSB0aMOsIGNvbXBvbmVudCBj4bunYSBuxqFpIGTDuW5nICh0aMawIHZp4buHbiBraMO0bmcga2nhu4NtIHNvw6F0XG4gICAgICAgICAgIMSRxrDhu6NjIGNsYXNzIGPhu6dhIG7Dsykgc+G6vSBraMO0bmcgY8OzIHRheSBj4bqnbSBuw6BvLCB2w6AgS0jDlE5HIGto4buRaSBuw6BvIGvDqW8gxJHGsOG7o2Mg4oCUIMSRbyAyOC8wOC8yMDI2OlxuICAgICAgICAgICBrw6lvIDMyMHB4LCB0b+G6oSDEkeG7mSBraOG7kWkgZ2nhu68gbmd1ecOqbiB4PTMseT0wLlxuICAgICAgICAgICBUw6puIGNsYXNzIHRoZW8gY+G6pXA6IGzGsOG7m2kgdHJhbmcgdsOgIGzGsOG7m2kgbOG7k25nIGTDuW5nIGhhaSB0w6puIEtIw4FDIG5oYXUsIG7hur91IGtow7RuZyBsxrDhu5tpIGNoYVxuICAgICAgICAgICBjxaluZyBuaOG6rW4gcmEgdGF5IGPhuqdtIGPhu6dhIGto4buRaSBjb24gdsOgIG5o4bqlYyBsdcO0biBjb250YWluZXIuIC0tPlxuICAgICAgPCEtLSDwn5S0IFbhu48gS0jDlE5HIG1hbmcgYGRyYWdIYW5kbGVDbGFzc2Ag4oCUIEPhuqRNIHRow6ptIGzhuqFpLlxuICAgICAgICAgICBLw6lvIGNo4buJIMSRxrDhu6NjIHBow6lwIGLhuq90IMSR4bqndSB04burIEThuqJJIFhBTkggKG5nxrDhu51pIGTDuW5nIGNo4buRdCAyOC8wOC8yMDI2OiBcInBo4bqjaSBob3ZlciB2w6BvIHbDuW5nXG4gICAgICAgICAgIG3DoHUgeGFuaCB0aMOsIG3hu5tpIGvDqW8gdGjhuqMgxJHGsOG7o2MgY2hvIMSR4buTbmcgbmjhuqV0XCIpLiBDaG8gY+G6oyB24buPIGzDoG0gdGF5IGPhuqdtIHRow6wgYuG6pW0gxJHDonUgY8WpbmdcbiAgICAgICAgICAga8OpbywgdsOgIGto4buRaSBjb24gbuG6sW0gdHJvbmcgY29udGFpbmVyIHPhur0gbmjhuqVjIGx1w7RuIGNvbnRhaW5lciB2w6wgbMaw4bubaSBjaGEgZHV54buHdCBsw6puIGfhurdwXG4gICAgICAgICAgIHRheSBj4bqnbSBj4bunYSB24buPIGNvbnRhaW5lciB0csaw4bubYy5cbiAgICAgICAgICAgVuG7jyBraOG7kWkgY29uIHbhuqtuIGdp4buvIGNsYXNzIENI4bq2TiDEkeG7gyBsxrDhu5tpIGNoYSBk4burbmcgxJHDum5nIOG7nyBiacOqbi4gLS0+XG4gICAgICA8ZGl2XG4gICAgICAgIGNsYXNzPVwibGlicy11aS1ncmlkLWxheW91dC1ibG9jay1zaGVsbCBncm91cCByZWxhdGl2ZSBoLWZ1bGwgdy1mdWxsIG1pbi13LTBcIlxuICAgICAgICBbY2xhc3MubGlicy11aS1ncmlkLWxheW91dC1ibG9jay1wYXJlbnQtZHJhZ109XCJpc05lc3RlZENhbnZhcygpXCI+XG4gICAgICAgIDwhLS0gROG6o2kga8OpbzogaGnhu4duIGtoaSByw6ogY2h14buZdCB2w6BvIGto4buRaSwgYmEgY2jhuqVtIGzDoCBk4bqldSBoaeG7h3Uga8OpbyBxdWVuIHRodeG7mWMuXG4gICAgICAgICAgICAgTmfGsOG7nWkgZMO5bmcgY+G6p24gbeG7mXQgY2jhu5cgYsOhbSBSw5UgUsOATkcgdGhheSB2w6wgxJFvw6FuIHhlbSBi4bqlbSDEkcOidSB0aMOsIGvDqW8gxJHGsOG7o2NcbiAgICAgICAgICAgICAoY2jhu5F0IDI4LzA4LzIwMjYsIHRoZW8gxJHDum5nIGThuqNpIMSRYW5nIGTDuW5nIOG7nyBtw6BuIEN1c3RvbWVyIDM2MCBj4bunYSBtb2Jpby13ZWIpLiAtLT5cbiAgICAgICAgQGlmIChpc0VkaXRNb2RlKCkpIHtcbiAgICAgICAgICA8IS0tIPCflLQgROG6o2kgUEjhuqJJIG1hbmcgdGF5IGPhuqdtIMSQw5pORyBD4bqkUCBj4bunYSBuw7MuIEThuqNpIG5o4bqtbiBjaHXhu5l0IChgcG9pbnRlci1ldmVudHM6IGF1dG9gKSxcbiAgICAgICAgICAgICAgIG7Dqm4gbuG6v3Uga2jDtG5nIG1hbmcgdGF5IGPhuqdtIHRow6wgYGNoZWNrRHJhZ0hhbmRsZUNsYXNzYCBkdXnhu4d0IGzDqm4gZ+G6t3AgdGF5IGPhuqdtIGPhu6dhXG4gICAgICAgICAgICAgICBjb250YWluZXIgdsOgIG5o4bqlYyBjb250YWluZXIgdGhheSB2w6wga2jhu5FpIGNvbiAoxJFvIDI4LzA4LzIwMjY6IGvDqW8gZOG6o2kga2jhu5FpIGNvbixcbiAgICAgICAgICAgICAgIGNvbnRhaW5lciBuaOG6o3kgMCwwIOKGkiAwLDEgY8OybiBraOG7kWkgY29uIMSR4bupbmcgaW0pLlxuICAgICAgICAgICAgICAg8J+UtCBE4bqjaSBDSOG7iCBtYW5nIHRheSBj4bqnbSwgQ+G6pE0gbWFuZyB0aMOqbSBjbGFzcyBjaOG6t246IGBjaGVja0RyYWdIYW5kbGVDbGFzc2AgeMOpdCBoYWlcbiAgICAgICAgICAgICAgIGNsYXNzIMSRw7MgdHLDqm4gQ8OZTkcgbeG7mXQgbm9kZSBuw6puIMSR4buDIGNodW5nIGzDoCBrw6lvIGjhu49uZyAoxJFvIDI4LzA4LzIwMjY6IGLhuqVtIGThuqNpIGto4buRaVxuICAgICAgICAgICAgICAgY29uIGvDqW8gMTQwcHgsIGto4buRaSDEkeG7qW5nIGltKS4gVmnhu4djIGNo4bq3biBsxrDhu5tpIGNoYSBkbyBW4buOIEtI4buQSSBsby4gLS0+XG4gICAgICAgICAgPGRpdlxuICAgICAgICAgICAgY2xhc3M9XCJsaWJzLXVpLWdyaWQtbGF5b3V0LWRyYWctYmFyXCJcbiAgICAgICAgICAgIFtjbGFzcy5saWJzLXVpLWdyaWQtbGF5b3V0LWRyYWctYmFyLWNoaWxkXT1cImlzTmVzdGVkQ2FudmFzKClcIlxuICAgICAgICAgICAgW2NsYXNzLmxpYnMtdWktZ3JpZC1sYXlvdXQtZHJhZy1oYW5kbGVdPVwiIWlzTmVzdGVkQ2FudmFzKClcIlxuICAgICAgICAgICAgW2NsYXNzLmxpYnMtdWktZ3JpZC1sYXlvdXQtZHJhZy1oYW5kbGUtY2hpbGRdPVwiaXNOZXN0ZWRDYW52YXMoKVwiPlxuICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJsaWJzLXVpLWdyaWQtbGF5b3V0LWRyYWctYmFyLWRvdHNcIj5cbiAgICAgICAgICAgICAgQGZvciAoZG90IG9mIGRyYWdCYXJEb3RzOyB0cmFjayBkb3QpIHtcbiAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cImxpYnMtdWktZ3JpZC1sYXlvdXQtZHJhZy1iYXItZG90XCI+PC9zcGFuPlxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICA8L3NwYW4+XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgIH1cblxuICAgICAgICA8IS0tIEtodW5nIGNo4bupYSBjb21wb25lbnQgY+G7p2EgbsahaSBkw7luZy5cbiAgICAgICAgICAgICDwn5S0IFBI4bqiSSBjw7Mga2h1bmcgdGjhuq10IChraMO0bmcgcGjhuqNpIGBuZy1jb250YWluZXJgIHRy4buRbmcpOiBuw7MgbG8gaOG7mSBuxqFpIGTDuW5nIHBo4bqnbiBs4bqlcCDEkeG6p3lcbiAgICAgICAgICAgICDDtCB2w6Agdmnhu4FuIGLDoW8gY2jhur8gxJHhu5kgc+G7rWEuIEtow7RuZyBjw7Mga2h1bmcgdGjDrCBt4buXaSBjb21wb25lbnQgbuG7mWkgZHVuZyBs4bqhaSBwaOG6o2kgdOG7sSB2aeG6v3RcbiAgICAgICAgICAgICBgOmhvc3QgeyB3aWR0aC9oZWlnaHQ6IDEwMCUgfWAgKyB2aeG7gW4gxJHhu6l0IOKAlCDEkcOzIGzDoCB2aeG7h2MgY+G7p2EgdGjGsCB2aeG7h24sIGtow7RuZyBwaOG6o2kgY+G7p2FcbiAgICAgICAgICAgICBuZ8aw4budaSBkw7luZyAobmfGsOG7nWkgZMO5bmcgY2jhu5F0IDI4LzA4LzIwMjYpLlxuICAgICAgICAgICAgIE3hu5dpIGto4buRaSBt4buZdCBWaWV3Q29udGFpbmVyUmVmIHJpw6puZyBuw6puIGNvbXBvbmVudCBu4bqxbSDEkcO6bmcgw7QgY+G7p2EgbsOzLiAtLT5cbiAgICAgICAgPGRpdlxuICAgICAgICAgIGNsYXNzPVwibGlicy11aS1ncmlkLWxheW91dC1jb250ZW50LWZyYW1lXCJcbiAgICAgICAgICBbY2xhc3MubGlicy11aS1ncmlkLWxheW91dC1jb250ZW50LWZyYW1lLWVkaXRdPVwiaXNFZGl0TW9kZSgpICYmICFpc0NvbnRhaW5lcihpdGVtKVwiXG4gICAgICAgICAgW2NsYXNzLmxpYnMtdWktZ3JpZC1sYXlvdXQtY29udGVudC1mcmFtZS1lbXB0eV09XCJpc0NvbnRhaW5lcihpdGVtKVwiPlxuICAgICAgICAgIDxuZy1jb250YWluZXIgI2l0ZW1Ib3N0IC8+XG4gICAgICAgIDwvZGl2PlxuXG4gICAgICAgIDwhLS0gROG6pXUgaGnhu4d1IENPTlRBSU5FUjogbmjDo24gZ8OzYyB0csOqbi1waOG6o2kgKyB2aeG7gW4gxJHhu6l0IGJhbyBydeG7mXQuIEtow7RuZyBjw7MgZOG6pXUgaGnhu4d1IHRow6xcbiAgICAgICAgICAgICBuZ8aw4budaSBkw7luZyBraMO0bmcgYmnhur90IGto4buRaSBuw6BvIGNo4bupYSDEkcaw4bujYyBraOG7kWkga2jDoWMgKGNo4buRdCAyOC8wOC8yMDI2LCB0aGVvIMSRw7puZyBjw6FjaFxuICAgICAgICAgICAgIG3DoG4gQ3VzdG9tZXIgMzYwIGPhu6dhIG1vYmlvLXdlYiDEkWFuZyBsw6BtKS4gLS0+XG4gICAgICAgIEBpZiAoaXNFZGl0TW9kZSgpICYmIGlzQ29udGFpbmVyKGl0ZW0pKSB7XG4gICAgICAgICAgPGRpdiBjbGFzcz1cImxpYnMtdWktZ3JpZC1sYXlvdXQtY29udGFpbmVyLWxhYmVsXCI+e3sgJ2kxOG5fY29udGFpbmVyX2Jsb2NrJyB8IHRyYW5zbGF0ZSB9fTwvZGl2PlxuICAgICAgICAgIDxkaXYgY2xhc3M9XCJsaWJzLXVpLWdyaWQtbGF5b3V0LWNvbnRhaW5lci1ib3JkZXJcIj48L2Rpdj5cbiAgICAgICAgfVxuXG4gICAgICAgIDwhLS0gVGhhbmggY8O0bmcgY+G7pTogaGnhu4duIGtoaSByw6ogY2h14buZdCB2w6BvIGto4buRaS5cbiAgICAgICAgICAgICDwn5S0IETDuW5nIGBsaWJzX3VpLWNvbXBvbmVudHMtYnV0dG9ucy1idXR0b25gIOKAlCBD4bqkTSB04buxIGThu7FuZyB0aOG6uyBgPGJ1dHRvbj5gLlxuICAgICAgICAgICAgIENvbXBvbmVudCBuw6B5IMSRw6MgY8OzIHPhurVuIGtp4buDdSBuw7p0LCBj4buhIG7DunQgdsOgIGJvbmcgYsOzbmcgY2jDuiB0aMOtY2ggdGhlbyDEkcO6bmcgYuG7mSBnaWFvIGRp4buHblxuICAgICAgICAgICAgIGPhu6dhIHPhuqNuIHBo4bqpbTsgdOG7sSBk4buxbmcgbMOgIG3hu5dpIG7GoWkgbeG7mXQga2nhu4N1IHbDoCBt4bqldCBsdcO0biB0b29sdGlwLiAtLT5cbiAgICAgICAgQGlmIChpc0VkaXRNb2RlKCkgJiYgIWhpZGRlblRvb2xiYXIoKSkge1xuICAgICAgICAgIEBpZiAodGVtcGxhdGVUb29sYmFyKCkpIHtcbiAgICAgICAgICAgIDwhLS0gTsahaSBkw7luZyB04buxIHbhur0gdGhhbmggY8O0bmcgY+G7pTogbmjhuq1uIGto4buRaSArIGPDoWMgaMOgbSBwaMOhdCBldmVudCBxdWEgY29udGV4dC5cblxuICAgICAgICAgICAgICAgICDwn5S0IEto4buRaSBi4buNYyB04buxIGNo4bq3biBgbW91c2Vkb3duYC9gY2xpY2tgIG7hu5VpIGzDqm4gZ3JpZHN0ZXIuIFRoYW5oIGPDtG5nIGPhu6UgbuG6sW0gdHJvbmdcbiAgICAgICAgICAgICAgICAgdsO5bmcgbWFuZyBgZHJhZ0hhbmRsZUNsYXNzYDsga2jDtG5nIGNo4bq3biB0aMOsIGPDuiBi4bqlbSBi4buLIGhp4buDdSBsw6AgYuG6r3QgxJHhuqd1IGvDqW8gdsOgXG4gICAgICAgICAgICAgICAgIGBkZWxheVN0YXJ0OiAxNjBgIG514buRdCBsdcO0biBgY2xpY2tgIOKAlCBuw7p0IHRyb25nIHRlbXBsYXRlIG5nb8OgaSBi4bqlbSBraMO0bmcgxINuXG4gICAgICAgICAgICAgICAgICjEkW8gMDkvMDkvMjAyNjogYuG6pW0gYuG6sW5nIGAuY2xpY2soKWAgY+G7p2EgRE9NIHRow6wgbeG7nywgYuG6pW0gY2h14buZdCB0aOG6rXQgdGjDrCBraMO0bmcpLlxuICAgICAgICAgICAgICAgICBDaOG6t24g4bufIMSQw4JZIMSR4buDIG7GoWkgZMO5bmcga2jDtG5nIHBo4bqjaSBiaeG6v3QgYuG6q3kgbsOgeS4gLS0+XG4gICAgICAgICAgICA8ZGl2XG4gICAgICAgICAgICAgIGNsYXNzPVwibGlicy11aS1ncmlkLWxheW91dC10b29sYmFyXCJcbiAgICAgICAgICAgICAgcm9sZT1cInRvb2xiYXJcIlxuICAgICAgICAgICAgICB0YWJpbmRleD1cIjBcIlxuICAgICAgICAgICAgICBbY2xhc3MubGlicy11aS1ncmlkLWxheW91dC10b29sYmFyLWNoaWxkXT1cImlzTmVzdGVkQ2FudmFzKClcIlxuICAgICAgICAgICAgICAobW91c2Vkb3duKT1cImhhbmRsZXJTdG9wRXZlbnQoJGV2ZW50KVwiXG4gICAgICAgICAgICAgIChrZXlkb3duKT1cImhhbmRsZXJTdG9wRXZlbnQoJGV2ZW50KVwiXG4gICAgICAgICAgICAgIChjbGljayk9XCJoYW5kbGVyU3RvcEV2ZW50KCRldmVudClcIj5cbiAgICAgICAgICAgICAgPG5nLWNvbnRhaW5lclxuICAgICAgICAgICAgICAgICpuZ1RlbXBsYXRlT3V0bGV0PVwidGVtcGxhdGVUb29sYmFyKCkhOyBjb250ZXh0OiB0b29sYmFyQ29udGV4dHMoKVtpdGVtSW5kZXhdXCIgLz5cbiAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgIH0gQGVsc2Uge1xuICAgICAgICAgICAgPGRpdlxuICAgICAgICAgICAgICBjbGFzcz1cImxpYnMtdWktZ3JpZC1sYXlvdXQtdG9vbGJhclwiXG4gICAgICAgICAgICAgIFtjbGFzcy5saWJzLXVpLWdyaWQtbGF5b3V0LXRvb2xiYXItY2hpbGRdPVwiaXNOZXN0ZWRDYW52YXMoKVwiPlxuICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cImxpYnMtdWktZ3JpZC1sYXlvdXQtZGltLWJhZGdlXCI+XG4gICAgICAgICAgICAgICAge3sgaXRlbS5yb3dzIH19IGjDoG5nIMOXIHt7IGl0ZW0uY29scyB9fSBj4buZdFxuICAgICAgICAgICAgICA8L3NwYW4+XG4gICAgICAgICAgICAgIEBpZiAoY2FuQWRkSW5zaWRlKGl0ZW0pKSB7XG4gICAgICAgICAgICAgICAgPGxpYnNfdWktY29tcG9uZW50cy1idXR0b25zLWJ1dHRvblxuICAgICAgICAgICAgICAgICAgW3R5cGVdPVwiJ2J1dHRvbi10aGlyZCdcIlxuICAgICAgICAgICAgICAgICAgW2ljb25Pbmx5VHlwZV09XCJ0cnVlXCJcbiAgICAgICAgICAgICAgICAgIFtzaXplQnV0dG9uXT1cIidzbWFsbGVyJ1wiXG4gICAgICAgICAgICAgICAgICBbY2xhc3NJY29uTGVmdF09XCInbGlicy11aS1pY29uLWFkZCdcIlxuICAgICAgICAgICAgICAgICAgW3BvcG92ZXJdPVwieyBjb25maWc6IHsgY29udGVudDogJ1Row6ptIGto4buRaSB2w6BvIHRyb25nJywgekluZGV4OiAxMzAwIH0gfVwiXG4gICAgICAgICAgICAgICAgICAob3V0Q2xpY2spPVwiaGFuZGxlckFkZEluc2lkZSgkZXZlbnQsIGl0ZW0pXCIgLz5cbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICBAaWYgKGNhblRvZ2dsZVR5cGUoaXRlbSkpIHtcbiAgICAgICAgICAgICAgICA8bGlic191aS1jb21wb25lbnRzLWJ1dHRvbnMtYnV0dG9uXG4gICAgICAgICAgICAgICAgICBbdHlwZV09XCInYnV0dG9uLXRoaXJkJ1wiXG4gICAgICAgICAgICAgICAgICBbaWNvbk9ubHlUeXBlXT1cInRydWVcIlxuICAgICAgICAgICAgICAgICAgW3NpemVCdXR0b25dPVwiJ3NtYWxsZXInXCJcbiAgICAgICAgICAgICAgICAgIFtjbGFzc0ljb25MZWZ0XT1cImlzQ29udGFpbmVyKGl0ZW0pID8gJ2xpYnMtdWktaWNvbi1zcGxpdC1jZWxsJyA6ICdsaWJzLXVpLWljb24tbWVyZ2UtY2VsbCdcIlxuICAgICAgICAgICAgICAgICAgW3BvcG92ZXJdPVwieyBjb25maWc6IHsgY29udGVudDogaXNDb250YWluZXIoaXRlbSkgPyAnxJDGsGEgduG7gSBraOG7kWkgxJHGoW4nIDogJ0NodXnhu4NuIHRow6BuaCBraOG7kWkgZ2jDqXAnLCB6SW5kZXg6IDEzMDAgfSB9XCJcbiAgICAgICAgICAgICAgICAgIChvdXRDbGljayk9XCJoYW5kbGVyVG9nZ2xlVHlwZSgkZXZlbnQsIGl0ZW0pXCIgLz5cbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICA8bGlic191aS1jb21wb25lbnRzLWJ1dHRvbnMtYnV0dG9uXG4gICAgICAgICAgICAgICAgW3R5cGVdPVwiJ2J1dHRvbi10aGlyZCdcIlxuICAgICAgICAgICAgICAgIFtpY29uT25seVR5cGVdPVwidHJ1ZVwiXG4gICAgICAgICAgICAgICAgW3NpemVCdXR0b25dPVwiJ3NtYWxsZXInXCJcbiAgICAgICAgICAgICAgICBbY2xhc3NJY29uTGVmdF09XCInbGlicy11aS1pY29uLXNldHRpbmcnXCJcbiAgICAgICAgICAgICAgICBbcG9wb3Zlcl09XCJ7IGNvbmZpZzogeyBjb250ZW50OiAnQ+G6pXUgaMOsbmggdGjhursnLCB6SW5kZXg6IDEzMDAgfSB9XCJcbiAgICAgICAgICAgICAgICAob3V0Q2xpY2spPVwiaGFuZGxlckNvbmZpZygkZXZlbnQsIGl0ZW0pXCIgLz5cbiAgICAgICAgICAgICAgPGxpYnNfdWktY29tcG9uZW50cy1idXR0b25zLWJ1dHRvblxuICAgICAgICAgICAgICAgIFt0eXBlXT1cIididXR0b24tdGhpcmQtaG92ZXItZGFuZ2VyJ1wiXG4gICAgICAgICAgICAgICAgW2ljb25Pbmx5VHlwZV09XCJ0cnVlXCJcbiAgICAgICAgICAgICAgICBbc2l6ZUJ1dHRvbl09XCInc21hbGxlcidcIlxuICAgICAgICAgICAgICAgIFtjbGFzc0ljb25MZWZ0XT1cIidsaWJzLXVpLWljb24tcmVtb3ZlJ1wiXG4gICAgICAgICAgICAgICAgW3BvcG92ZXJdPVwieyBjb25maWc6IHsgY29udGVudDogaXNDb250YWluZXIoaXRlbSkgPyAnWG/DoSBj4bqjIGto4buRaSBnaMOpcCcgOiAnWG/DoSBraOG7kWknLCB6SW5kZXg6IDEzMDAgfSB9XCJcbiAgICAgICAgICAgICAgICAob3V0Q2xpY2spPVwiaGFuZGxlclJlbW92ZSgkZXZlbnQsIGl0ZW0pXCIgLz5cbiAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIEBpZiAoaXRlbS5jaGlsZHJlbiAmJiBpdGVtLmNoaWxkcmVuLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICA8IS0tIEto4buRaSBjw7MgY29uIOKGkiBydeG7mXQgbsOzIGzhuqFpIGzDoCBt4buZdCBt4bq3dCBwaOG6s25nIG7hu69hLiDEkOG7hyBxdXkg4bufIMSRw6J5LCBuxqFpIGTDuW5nIGtow7RuZyBwaOG6o2kgbG8uXG4gICAgICAgICAgICAgICBM4buBIMSR4bq3dCDhu58gxJDDglkgKHbhu48gY29udGFpbmVyKSwga2jDtG5nIMSR4bq3dCB2w6BvIGzGsOG7m2kgY29uIOKAlCBsxrDhu5tpIGNvbiBnaeG7ryBuZ3V5w6puIGtoZSAycHguIC0tPlxuICAgICAgICAgIDxsaWJzX3VpLXNlcnZpY2VzLWdyaWRfbGF5b3V0LWNhbnZhc1xuICAgICAgICAgICAgY2xhc3M9XCJibG9jayBoLWZ1bGwgdy1mdWxsXCJcbiAgICAgICAgICAgIFtzdHlsZS5wYWRkaW5nXT1cImNvbnRhaW5lclBhZGRpbmcoKVwiXG4gICAgICAgICAgICBbbm9kZV09XCJpdGVtXCJcbiAgICAgICAgICAgIFtkZXB0aF09XCJkZXB0aCgpICsgMVwiXG4gICAgICAgICAgICBbaGlkZGVuVG9vbGJhcl09XCJoaWRkZW5Ub29sYmFyKClcIlxuICAgICAgICAgICAgW3RlbXBsYXRlVG9vbGJhcl09XCJ0ZW1wbGF0ZVRvb2xiYXIoKVwiXG4gICAgICAgICAgICBbc2VsZWN0ZWROb2RlSWRdPVwic2VsZWN0ZWROb2RlSWQoKVwiXG4gICAgICAgICAgICAob3V0U2VsZWN0Tm9kZSk9XCJvdXRTZWxlY3ROb2RlLmVtaXQoJGV2ZW50KVwiXG4gICAgICAgICAgICAob3V0Q29uZmlnTm9kZSk9XCJvdXRDb25maWdOb2RlLmVtaXQoJGV2ZW50KVwiXG4gICAgICAgICAgICAob3V0Q2hhbmdlKT1cIm91dENoYW5nZS5lbWl0KCRldmVudClcIlxuICAgICAgICAgICAgKG91dFJlbW92ZU5vZGUpPVwib3V0UmVtb3ZlTm9kZS5lbWl0KCRldmVudClcIlxuICAgICAgICAgICAgKG91dEFkZEJsb2NrSW5zaWRlKT1cIm91dEFkZEJsb2NrSW5zaWRlLmVtaXQoJGV2ZW50KVwiXG4gICAgICAgICAgICAob3V0VG9nZ2xlVHlwZSk9XCJvdXRUb2dnbGVUeXBlLmVtaXQoJGV2ZW50KVwiIC8+XG4gICAgICAgIH1cbiAgICAgIDwvZGl2PlxuICAgIDwvZ3JpZHN0ZXItaXRlbT5cbiAgfVxuICAgIDwvZ3JpZHN0ZXI+XG4gIDwvZGl2PlxufVxuIl19
|