@libs-ui/services-grid-layout 0.2.357-22 → 0.2.357-24
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 +5 -0
- package/defines/collision.define.d.ts +1 -1
- package/drag-controller.d.ts +1 -1
- package/esm2022/canvas/grid-layout-canvas.component.mjs +25 -7
- package/esm2022/defines/collision.define.mjs +5 -3
- package/esm2022/drag-controller.mjs +5 -3
- package/esm2022/grid-layout.service.mjs +49 -1
- package/esm2022/interfaces/grid-layout.interface.mjs +1 -1
- package/esm2022/tree.service.mjs +15 -2
- package/fesm2022/libs-ui-services-grid-layout.mjs +94 -11
- package/fesm2022/libs-ui-services-grid-layout.mjs.map +1 -1
- package/grid-layout.service.d.ts +32 -0
- package/interfaces/grid-layout.interface.d.ts +20 -0
- package/package.json +3 -3
|
@@ -161,6 +161,11 @@ export class LibsUiGridLayoutCanvasComponent {
|
|
|
161
161
|
toggleType: () => this.emitToggleType(item),
|
|
162
162
|
})));
|
|
163
163
|
isNestedCanvas = computed(() => this.depth() > 0);
|
|
164
|
+
/**
|
|
165
|
+
* Khe nhìn thấy giữa các khối CẤP GỐC. Mặt phẳng lồng trả 0 — khối con là các dòng của cùng một
|
|
166
|
+
* thẻ, tách chúng ra làm chúng trông như thẻ rời.
|
|
167
|
+
*/
|
|
168
|
+
visualGap = computed(() => (this.depth() === 0 ? this.service.visualGapPx : 0));
|
|
164
169
|
/** trần lồng container — khối đã chạm trần thì không cho chuyển thành container */
|
|
165
170
|
maxContainerDepth = computed(() => this.service.FunctionsControl.maxContainerDepth());
|
|
166
171
|
/**
|
|
@@ -190,8 +195,18 @@ export class LibsUiGridLayoutCanvasComponent {
|
|
|
190
195
|
if (!host) {
|
|
191
196
|
return;
|
|
192
197
|
}
|
|
193
|
-
// Khối có con là CONTAINER:
|
|
194
|
-
|
|
198
|
+
// Khối có con là CONTAINER: RUỘT nó do mặt phẳng lồng vẽ.
|
|
199
|
+
//
|
|
200
|
+
// 🔴 Nhưng container VẪN được gắn component nếu nơi dùng chủ động khai `getComponentOutlet`
|
|
201
|
+
// cho chính khối đó — đó là hàng tiêu đề / phần vỏ của khối ghép, vẽ quanh mặt phẳng lồng chứ
|
|
202
|
+
// không thay thế nó. Trước đây chặn cứng ở đây nên nơi dùng phải tự `document.createElement`
|
|
203
|
+
// rồi `insertBefore` vào DOM của thư viện, kéo theo một loạt luật CSS `!important` để chỉnh
|
|
204
|
+
// thứ mình vừa chèn tay.
|
|
205
|
+
//
|
|
206
|
+
// Container KHÔNG khai outlet riêng thì vẫn bỏ qua y như cũ — `config.getComponentOutlet`
|
|
207
|
+
// dùng chung là để vẽ NỘI DUNG khối lá, đem áp cho container sẽ đè mất mặt phẳng lồng.
|
|
208
|
+
const isContainerNode = (item.children?.length ?? 0) > 0;
|
|
209
|
+
if (isContainerNode && !item.getComponentOutlet) {
|
|
195
210
|
return;
|
|
196
211
|
}
|
|
197
212
|
this.service.FunctionsControl.attachNode(item, this.depth() + 1, host);
|
|
@@ -418,8 +433,11 @@ export class LibsUiGridLayoutCanvasComponent {
|
|
|
418
433
|
}
|
|
419
434
|
handlerSelectNode(node, event) {
|
|
420
435
|
if (event) {
|
|
436
|
+
// 🔴 CHỈ bỏ qua khi đích thực sự là nút bấm. Trước đây bỏ qua cả vùng
|
|
437
|
+
// `.libs-ui-grid-layout-toolbar`: thanh này phủ gần kín khối nhỏ nên bấm vào khối không bao giờ
|
|
438
|
+
// chọn được, nơi dùng phải tắt `pointer-events` của cả thanh để cứu.
|
|
421
439
|
const target = event.target;
|
|
422
|
-
if (target.closest('
|
|
440
|
+
if (target.closest('button') || target.closest('[data-grid-layout-action]')) {
|
|
423
441
|
return;
|
|
424
442
|
}
|
|
425
443
|
}
|
|
@@ -456,7 +474,7 @@ export class LibsUiGridLayoutCanvasComponent {
|
|
|
456
474
|
}
|
|
457
475
|
this.rootGridsterEl = rootGridster;
|
|
458
476
|
}
|
|
459
|
-
const ghost = calculateDropGhost(event, container, root, payload, this.service.totalColumns);
|
|
477
|
+
const ghost = calculateDropGhost(event, container, root, payload, this.service.totalColumns, this.service.rowStepPx);
|
|
460
478
|
if (ghost?.isInsideGroup && ghost.hoveredGridster) {
|
|
461
479
|
if (this.activeHoveredEl !== ghost.hoveredGridster) {
|
|
462
480
|
this.cleanupHoveredGroup();
|
|
@@ -557,11 +575,11 @@ export class LibsUiGridLayoutCanvasComponent {
|
|
|
557
575
|
}
|
|
558
576
|
}
|
|
559
577
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: LibsUiGridLayoutCanvasComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
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 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 });
|
|
578
|
+
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-start 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 mx-auto 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 [style.--libs-ui-grid-layout-visual-gap.px]=\"visualGap()\">\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 [attr.data-node-id]=\"item.id\"\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) && !item.getComponentOutlet\">\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 [attr.data-node-id]=\"item.id\"\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) && !item.getComponentOutlet\">\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}.libs-ui-grid-layout-stage>gridster>gridster-item>.libs-ui-grid-layout-block-shell{inset:calc(var(--libs-ui-grid-layout-visual-gap, 0px) / 2);width:calc(100% - var(--libs-ui-grid-layout-visual-gap, 0px));height:calc(100% - var(--libs-ui-grid-layout-visual-gap, 0px));box-sizing:border-box}\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 });
|
|
561
579
|
}
|
|
562
580
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: LibsUiGridLayoutCanvasComponent, decorators: [{
|
|
563
581
|
type: Component,
|
|
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 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"] }]
|
|
582
|
+
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-start 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 mx-auto 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 [style.--libs-ui-grid-layout-visual-gap.px]=\"visualGap()\">\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 [attr.data-node-id]=\"item.id\"\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) && !item.getComponentOutlet\">\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 [attr.data-node-id]=\"item.id\"\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) && !item.getComponentOutlet\">\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}.libs-ui-grid-layout-stage>gridster>gridster-item>.libs-ui-grid-layout-block-shell{inset:calc(var(--libs-ui-grid-layout-visual-gap, 0px) / 2);width:calc(100% - var(--libs-ui-grid-layout-visual-gap, 0px));height:calc(100% - var(--libs-ui-grid-layout-visual-gap, 0px));box-sizing:border-box}\n"] }]
|
|
565
583
|
}], ctorParameters: () => [], propDecorators: { handlerDocumentKeyDown: [{
|
|
566
584
|
type: HostListener,
|
|
567
585
|
args: ['document:keydown', ['$event']]
|
|
@@ -569,4 +587,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
569
587
|
type: HostListener,
|
|
570
588
|
args: ['document:click', ['$event']]
|
|
571
589
|
}] } });
|
|
572
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ3JpZC1sYXlvdXQtY2FudmFzLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL2xpYnMtdWkvc2VydmljZXMvZ3JpZC1sYXlvdXQvc3JjL2NhbnZhcy9ncmlkLWxheW91dC1jYW52YXMuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vLi4vbGlicy11aS9zZXJ2aWNlcy9ncmlkLWxheW91dC9zcmMvY2FudmFzL2dyaWQtbGF5b3V0LWNhbnZhcy5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBRUwsdUJBQXVCLEVBQ3ZCLFNBQVMsRUFFVCxZQUFZLEVBR1osZ0JBQWdCLEVBQ2hCLFFBQVEsRUFDUixNQUFNLEVBQ04sTUFBTSxFQUNOLEtBQUssRUFDTCxLQUFLLEVBQ0wsTUFBTSxFQUNOLE1BQU0sRUFDTixTQUFTLEVBQ1QsWUFBWSxHQUNiLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQ25ELE9BQU8sRUFBRSxzQ0FBc0MsRUFBRSxNQUFNLG9DQUFvQyxDQUFDO0FBQzVGLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxjQUFjLEVBQUUsTUFBTSxZQUFZLENBQUM7QUFDL0QsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQ3RELE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxtQ0FBbUMsQ0FBQztBQUNsRSxPQUFPLEVBQUUsdUJBQXVCLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQWFqRSxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQzs7OztBQUVuRjs7Ozs7R0FLRztBQVNILE1BQU0sT0FBTywrQkFBK0I7SUFDMUM7Ozs7O09BS0c7SUFDTSxJQUFJLEdBQUcsS0FBSyxFQUFxQixDQUFDO0lBQzNDLDhEQUE4RDtJQUNyRCxLQUFLLEdBQUcsS0FBSyxDQUFTLENBQUMsQ0FBQyxDQUFDO0lBRWxDOzs7Ozs7T0FNRztJQUNNLGFBQWEsR0FBRyxLQUFLLENBQStCLEtBQUssRUFBRSxFQUFFLFNBQVMsRUFBRSxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsS0FBSyxJQUFJLEtBQUssRUFBRSxDQUFDLENBQUM7SUFFOUc7Ozs7Ozs7T0FPRztJQUNNLGVBQWUsR0FBRyxLQUFLLENBQXVELFNBQVMsQ0FBQyxDQUFDO0lBRWxHOzs7OztPQUtHO0lBQ00sU0FBUyxHQUFHLE1BQU0sRUFBNEIsQ0FBQztJQUN4RDs7O09BR0c7SUFDTSxhQUFhLEdBQUcsTUFBTSxFQUE0QixDQUFDO0lBQzVEOzs7T0FHRztJQUNNLGlCQUFpQixHQUFHLE1BQU0sRUFBeUIsQ0FBQztJQUM3RCw4RkFBOEY7SUFDckYsYUFBYSxHQUFHLE1BQU0sRUFBNEIsQ0FBQztJQUU1RCxtRkFBbUY7SUFDMUUsVUFBVSxHQUFHLEtBQUssQ0FBK0IsS0FBSyxFQUFFLEVBQUUsU0FBUyxFQUFFLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxLQUFLLElBQUksS0FBSyxFQUFFLENBQUMsQ0FBQztJQUUzRywyRUFBMkU7SUFDbEUsSUFBSSxHQUFHLEtBQUssQ0FBcUIsU0FBUyxDQUFDLENBQUM7SUFFckQsd0RBQXdEO0lBQy9DLE9BQU8sR0FBRyxLQUFLLENBQVMsR0FBRyxDQUFDLENBQUM7SUFFdEMsc0RBQXNEO0lBQzdDLE9BQU8sR0FBRyxLQUFLLENBQVMsR0FBRyxDQUFDLENBQUM7SUFFdEMsOEVBQThFO0lBQ3JFLFFBQVEsR0FBRyxLQUFLLENBQVMsSUFBSSxDQUFDLENBQUM7SUFFeEMscUVBQXFFO0lBQzVELFVBQVUsR0FBRyxLQUFLLENBQVMsSUFBSSxDQUFDLENBQUM7SUFFMUMsdUVBQXVFO0lBQzlELGNBQWMsR0FBRyxLQUFLLENBQVMsR0FBRyxDQUFDLENBQUM7SUFFN0MsZ0ZBQWdGO0lBQ3ZFLFVBQVUsR0FBRyxLQUFLLENBQXFCLG9CQUFvQixDQUFDLENBQUM7SUFFdEUsbUZBQW1GO0lBQzFFLFlBQVksR0FBRyxLQUFLLENBQStCLElBQUksRUFBRSxFQUFFLFNBQVMsRUFBRSxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsS0FBSyxJQUFJLElBQUksRUFBRSxDQUFDLENBQUM7SUFFM0csbUdBQW1HO0lBQzFGLGFBQWEsR0FBRyxLQUFLLENBQStCLElBQUksRUFBRSxFQUFFLFNBQVMsRUFBRSxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsS0FBSyxJQUFJLElBQUksRUFBRSxDQUFDLENBQUM7SUFFNUcsNENBQTRDO0lBQ25DLGFBQWEsR0FBRyxNQUFNLEVBQVUsQ0FBQztJQUUxQyx3RUFBd0U7SUFDL0Qsa0JBQWtCLEdBQUcsS0FBSyxDQUErQixJQUFJLEVBQUUsRUFBRSxTQUFTLEVBQUUsQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLEtBQUssSUFBSSxJQUFJLEVBQUUsQ0FBQyxDQUFDO0lBRWpILHlDQUF5QztJQUNoQyxhQUFhLEdBQUcsS0FBSyxDQUErQixLQUFLLEVBQUUsRUFBRSxTQUFTLEVBQUUsQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLEtBQUssSUFBSSxLQUFLLEVBQUUsQ0FBQyxDQUFDO0lBRTlHLG9DQUFvQztJQUMzQixjQUFjLEdBQUcsS0FBSyxDQUE0QixTQUFTLENBQUMsQ0FBQztJQUV0RSwwREFBMEQ7SUFDakQsV0FBVyxHQUFHLE1BQU0sRUFBMEIsQ0FBQztJQUV4RCxpREFBaUQ7SUFDeEMsYUFBYSxHQUFHLE1BQU0sRUFBcUIsQ0FBQztJQUVyRCwwRUFBMEU7SUFDakUsYUFBYSxHQUFHLE1BQU0sRUFBNEIsQ0FBQztJQUUzQyxXQUFXLEdBQUcsU0FBUyxDQUFDLGlCQUFpQixDQUFDLENBQUM7SUFDM0MsYUFBYSxHQUFHLFNBQVMsQ0FBMEIsWUFBWSxDQUFDLENBQUM7SUFDakUsV0FBVyxHQUFHLFNBQVMsQ0FBMEIsVUFBVSxDQUFDLENBQUM7SUFDOUUsNkRBQTZEO0lBQzVDLFNBQVMsR0FBRyxZQUFZLENBQUMsVUFBVSxFQUFFLEVBQUUsSUFBSSxFQUFFLGdCQUFnQixFQUFFLENBQUMsQ0FBQztJQUVsRiwwRUFBMEU7SUFDdkQsU0FBUyxHQUFHLE1BQU0sQ0FBcUMsU0FBUyxDQUFDLENBQUM7SUFFN0UsZUFBZSxDQUFlO0lBQzlCLGNBQWMsQ0FBZTtJQUVyQyxrREFBa0Q7SUFDL0IsVUFBVSxHQUFHLE1BQU0sQ0FBVSxLQUFLLENBQUMsQ0FBQztJQUV2RCxpQ0FBaUM7SUFDZCxXQUFXLEdBQW1DO1FBQy9ELEVBQUUsS0FBSyxFQUFFLDJCQUEyQixFQUFFLEtBQUssRUFBRSxHQUFHLEVBQUU7UUFDbEQsRUFBRSxLQUFLLEVBQUUsK0JBQStCLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRTtRQUN2RCxFQUFFLEtBQUssRUFBRSwrQkFBK0IsRUFBRSxLQUFLLEVBQUUsSUFBSSxFQUFFO1FBQ3ZELEVBQUUsS0FBSyxFQUFFLCtCQUErQixFQUFFLEtBQUssRUFBRSxJQUFJLEVBQUU7UUFDdkQsRUFBRSxLQUFLLEVBQUUsMkJBQTJCLEVBQUUsS0FBSyxFQUFFLEdBQUcsRUFBRTtRQUNsRCxFQUFFLEtBQUssRUFBRSxnQ0FBZ0MsRUFBRSxLQUFLLEVBQUUsQ0FBQyxFQUFFO1FBQ3JELEVBQUUsS0FBSyxFQUFFLCtCQUErQixFQUFFLEtBQUssRUFBRSxHQUFHLEVBQUU7UUFDdEQsRUFBRSxLQUFLLEVBQUUsOEJBQThCLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRTtLQUN2RCxDQUFDO0lBRUYsc0ZBQXNGO0lBQ25FLFdBQVcsR0FBRyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7SUFFbkMsT0FBTyxHQUFHLE1BQU0sQ0FBQyx1QkFBdUIsQ0FBQyxDQUFDO0lBRTNELHlGQUF5RjtJQUN0RSxZQUFZLEdBQUcsUUFBUSxDQUFDLEdBQUcsRUFBRTtRQUM5QyxPQUFPLElBQUksQ0FBQyxLQUFLLEVBQUUsS0FBSyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsVUFBVSxFQUFFLElBQUksSUFBSSxDQUFDLE9BQU8sQ0FBQyxnQkFBZ0IsQ0FBQyxhQUFhLEVBQUUsQ0FBQyxDQUFDO0lBQ3BHLENBQUMsQ0FBQyxDQUFDO0lBRWdCLFdBQVcsR0FBRyxRQUFRLENBQUMsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDO0lBQ2xELFdBQVcsR0FBRyxRQUFRLENBQUMsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsV0FBVyxFQUFFLEdBQUcsR0FBRyxDQUFDLENBQUMsQ0FBQztJQUV0Rjs7Ozs7Ozs7OztPQVVHO0lBQ2dCLFdBQVcsR0FBRyxRQUFRLENBQUMsR0FBRyxFQUFFO1FBQzdDLElBQUksQ0FBQyxPQUFPLENBQUMsT0FBTyxFQUFFLENBQUM7UUFFdkIsSUFBSSxJQUFJLENBQUMsS0FBSyxFQUFFLEdBQUcsQ0FBQyxFQUFFLENBQUM7WUFDckIsT0FBTyxJQUFJLENBQUMsSUFBSSxFQUFFLElBQUksYUFBYSxFQUFFLENBQUM7UUFDeEMsQ0FBQztRQUVELE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLEVBQUUsSUFBSSxhQUFhLEVBQUUsQ0FBQztJQUNoRCxDQUFDLENBQUMsQ0FBQztJQUVnQixRQUFRLEdBQUcsUUFBUSxDQUFDLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQyxRQUFRLElBQUksRUFBRSxDQUFDLENBQUM7SUFFaEY7Ozs7O09BS0c7SUFDZ0IsZUFBZSxHQUFHLFFBQVEsQ0FBcUMsR0FBRyxFQUFFLENBQ3JGLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUFDLENBQUM7UUFDN0IsU0FBUyxFQUFFLElBQUk7UUFDZixXQUFXLEVBQUUsSUFBSSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUM7UUFDbkMsWUFBWSxFQUFFLElBQUksQ0FBQyxZQUFZLENBQUMsSUFBSSxDQUFDO1FBQ3JDLGFBQWEsRUFBRSxJQUFJLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQztRQUN2QyxNQUFNLEVBQUUsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsRUFBRSxNQUFNLEVBQUUsSUFBSSxDQUFDLEVBQUUsRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLE9BQU8sRUFBRSxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQztRQUN4SCxTQUFTLEVBQUUsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUM7UUFDekMsVUFBVSxFQUFFLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxjQUFjLENBQUMsSUFBSSxDQUFDO0tBQzVDLENBQUMsQ0FBQyxDQUNKLENBQUM7SUFFaUIsY0FBYyxHQUFHLFFBQVEsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsS0FBSyxFQUFFLEdBQUcsQ0FBQyxDQUFDLENBQUM7SUFFckUsbUZBQW1GO0lBQ2hFLGlCQUFpQixHQUFHLFFBQVEsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLGdCQUFnQixDQUFDLGlCQUFpQixFQUFFLENBQUMsQ0FBQztJQUV6Rzs7Ozs7O09BTUc7SUFDZ0IsZ0JBQWdCLEdBQUcsUUFBUSxDQUFDLEdBQUcsRUFBRSxDQUFDLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxnQkFBZ0IsQ0FBQyxnQkFBZ0IsRUFBRSxJQUFJLENBQUMsQ0FBQztJQUU5RywwRkFBMEY7SUFDdkUsVUFBVSxHQUFHLFFBQVEsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLFVBQVUsRUFBRSxDQUFDLENBQUM7SUFFdkQsV0FBVyxHQUFHLFFBQVEsQ0FBQyxHQUFHLEVBQUU7UUFDN0MsdUZBQXVGO1FBQ3ZGLDhEQUE4RDtRQUM5RCxJQUFJLENBQUMsT0FBTyxDQUFDLE9BQU8sRUFBRSxDQUFDO1FBRXZCLE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBQyxnQkFBZ0IsQ0FBQyxlQUFlLENBQUMsSUFBSSxDQUFDLEtBQUssRUFBRSxFQUFFLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLEVBQUUsSUFBSSxFQUFFLElBQUksQ0FBQyxXQUFXLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQztJQUM5SCxDQUFDLENBQUMsQ0FBQztJQUVIO1FBQ0UscUVBQXFFO1FBQ3JFLDhFQUE4RTtRQUM5RSxNQUFNLENBQUMsR0FBRyxFQUFFO1lBQ1YsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLFNBQVMsRUFBRSxDQUFDO1lBQy9CLE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQztZQUU5QixLQUFLLENBQUMsT0FBTyxDQUFDLENBQUMsSUFBSSxFQUFFLENBQUMsRUFBRSxFQUFFO2dCQUN4QixNQUFNLElBQUksR0FBRyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUM7Z0JBRXRCLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQztvQkFDVixPQUFPO2dCQUNULENBQUM7Z0JBRUQsd0ZBQXdGO2dCQUN4RixJQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSxNQUFNLElBQUksQ0FBQyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUM7b0JBQ3JDLE9BQU87Z0JBQ1QsQ0FBQztnQkFFRCxJQUFJLENBQUMsT0FBTyxDQUFDLGdCQUFnQixDQUFDLFVBQVUsQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLEtBQUssRUFBRSxHQUFHLENBQUMsRUFBRSxJQUFJLENBQUMsQ0FBQztZQUN6RSxDQUFDLENBQUMsQ0FBQztRQUNMLENBQUMsQ0FBQyxDQUFDO1FBRUgsNENBQTRDO1FBQzVDLE1BQU0sQ0FBQyxHQUFHLEVBQUU7WUFDVixNQUFNLENBQUMsR0FBRyxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUM7WUFDdEIsSUFBSSxDQUFDLEtBQUssU0FBUyxJQUFJLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxFQUFFLENBQUMsR0FBRyxLQUFLLEVBQUUsQ0FBQztnQkFDakUsSUFBSSxDQUFDLE9BQU8sQ0FBQyxnQkFBZ0IsQ0FBQyxPQUFPLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FBQyxDQUFDO1lBQzlELENBQUM7UUFDSCxDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFRCxlQUFlO1FBQ2IsSUFBSSxDQUFDLElBQUksQ0FBQyxZQUFZLEVBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyxhQUFhLEVBQUUsRUFBRSxDQUFDO1lBQ2xELE9BQU87UUFDVCxDQUFDO1FBRUQsTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDO1FBQzlCLElBQUksUUFBUSxHQUFHLEtBQUssQ0FBQztRQUNyQixJQUFJLEdBQUcsSUFBSSxPQUFPLFlBQVksS0FBSyxXQUFXLEVBQUUsQ0FBQztZQUMvQyxJQUFJLENBQUM7Z0JBQ0gsUUFBUSxHQUFHLE9BQU8sQ0FBQyxZQUFZLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7WUFDaEQsQ0FBQztZQUFDLE1BQU0sQ0FBQztnQkFDUCxtQ0FBbUM7WUFDckMsQ0FBQztRQUNILENBQUM7UUFFRCxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUM7WUFDZCxVQUFVLENBQUMsR0FBRyxFQUFFO2dCQUNkLE1BQU0sUUFBUSxHQUFHLElBQUksQ0FBQyxhQUFhLEVBQUUsRUFBRSxhQUFhLENBQUM7Z0JBQ3JELElBQUksUUFBUSxJQUFJLFFBQVEsQ0FBQyxXQUFXLEdBQUcsQ0FBQyxJQUFJLFFBQVEsQ0FBQyxXQUFXLEdBQUcsSUFBSSxDQUFDLFVBQVUsRUFBRSxHQUFHLEVBQUUsRUFBRSxDQUFDO29CQUMxRixJQUFJLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQztnQkFDMUIsQ0FBQztZQUNILENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQztRQUNULENBQUM7SUFDSCxDQUFDO0lBRUQsV0FBVztRQUNULElBQUksQ0FBQyxlQUFlLEVBQUUsQ0FBQztRQUN2QixLQUFLLE1BQU0sSUFBSSxJQUFJLElBQUksQ0FBQyxRQUFRLEVBQUUsRUFBRSxDQUFDO1lBQ25DLElBQUksQ0FBQyxPQUFPLENBQUMsZ0JBQWdCLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUNwRCxDQUFDO0lBQ0gsQ0FBQztJQUVELG1GQUFtRjtJQUNuRixJQUFJLGVBQWU7UUFDakIsT0FBTztZQUNMLFNBQVMsRUFBRSxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsV0FBVyxFQUFFLEVBQUUsY0FBYyxFQUFFO1lBQ3JELE1BQU0sRUFBRSxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsYUFBYSxFQUFFO1lBQ2xDLE9BQU8sRUFBRSxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsY0FBYyxFQUFFO1lBQ3BDLFNBQVMsRUFBRSxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsZ0JBQWdCLEVBQUU7WUFDeEMsV0FBVyxFQUFFLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxnQkFBZ0IsRUFBRTtZQUMxQyxPQUFPLEVBQUUsQ0FBQyxHQUFXLEVBQUUsRUFBRTtnQkFDdkIsSUFBSSxDQUFDLE9BQU8sQ0FBQyxnQkFBZ0IsQ0FBQyxPQUFPLENBQUMsR0FBRyxFQUFFLElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FBQyxDQUFDO2dCQUM5RCxJQUFJLENBQUMsV0FBVyxFQUFFLENBQUM7WUFDckIsQ0FBQztZQUNELDZGQUE2RjtZQUM3RixnR0FBZ0c7WUFDaEcsVUFBVSxFQUFFLEdBQTRCLEVBQUUsQ0FBQyxJQUFJLENBQUMsYUFBYSxFQUFFLEVBQUUsYUFBYTtTQUMvRSxDQUFDO0lBQ0osQ0FBQztJQUVTLGFBQWE7UUFDckIsSUFBSSxDQUFDLE9BQU8sQ0FBQyxnQkFBZ0IsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSxFQUFFLElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FBQyxDQUFDO1FBQ3pFLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQztJQUNyQixDQUFDO0lBRVMsY0FBYztRQUN0QixJQUFJLENBQUMsT0FBTyxDQUFDLGdCQUFnQixDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFLEVBQUUsSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDLENBQUM7UUFDMUUsSUFBSSxDQUFDLFdBQVcsRUFBRSxDQUFDO0lBQ3JCLENBQUM7SUFFUyxnQkFBZ0I7UUFDeEIsSUFBSSxDQUFDLE9BQU8sQ0FBQyxnQkFBZ0IsQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDLENBQUM7UUFDM0QsSUFBSSxDQUFDLFdBQVcsRUFBRSxDQUFDO0lBQ3JCLENBQUM7SUFFUyxnQkFBZ0I7UUFDeEIsSUFBSSxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDM0IsTUFBTSxRQUFRLEdBQUcsSUFBSSxDQUFDLGFBQWEsRUFBRSxFQUFFLGFBQWEsQ0FBQztRQUNyRCxNQUFNLGNBQWMsR0FBRyxRQUFRLEVBQUUsV0FBVyxJQUFJLENBQUMsT0FBTyxNQUFNLEtBQUssV0FBVyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsVUFBVSxHQUFHLEdBQUcsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDakgsSUFBSSxDQUFDLE9BQU8sQ0FBQyxnQkFBZ0IsQ0FBQyxXQUFXLENBQUMsY0FBYyxFQUFFLElBQUksQ0FBQyxVQUFVLEVBQUUsRUFBRSxFQUFFLEVBQUUsSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDLENBQUM7UUFDcEcsSUFBSSxDQUFDLFdBQVcsRUFBRSxDQUFDO0lBQ3JCLENBQUM7SUFFUyxpQkFBaUI7UUFDekIsSUFBSSxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUMsQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDMUMsQ0FBQztJQUVTLG1CQUFtQixDQUFDLEtBQWE7UUFDekMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDM0IsSUFBSSxDQUFDLE9BQU8sQ0FBQyxnQkFBZ0IsQ0FBQyxPQUFPLENBQUMsS0FBSyxFQUFFLElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FBQyxDQUFDO1FBQ2hFLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQztJQUNyQixDQUFDO0lBRVMsZUFBZSxDQUFDLEtBQWE7UUFDckMsT0FBTyxJQUFJLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxXQUFXLEVBQUUsR0FBRyxLQUFLLENBQUMsR0FBRyxJQUFJLENBQUM7SUFDckQsQ0FBQztJQUVPLFdBQVc7UUFDakIsTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLEVBQUUsQ0FBQztRQUNoQyxJQUFJLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUM3QixJQUFJLElBQUksQ0FBQyxJQUFJLEVBQUUsS0FBSyxHQUFHLEVBQUUsQ0FBQztZQUN4QixJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUNyQixDQUFDO0lBQ0gsQ0FBQztJQUVTLFlBQVksQ0FBQyxLQUFpQjtRQUN0QyxJQUFJLENBQUMsSUFBSSxDQUFDLFlBQVksRUFBRSxFQUFFLENBQUM7WUFDekIsT0FBTztRQUNULENBQUM7UUFFRCxJQUFJLEtBQUssQ0FBQyxPQUFPLElBQUksS0FBSyxDQUFDLE9BQU8sRUFBRSxDQUFDO1lBQ25DLEtBQUssQ0FBQyxjQUFjLEVBQUUsQ0FBQztZQUN2QixJQUFJLEtBQUssQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUM7Z0JBQ3JCLElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQztZQUN2QixDQUFDO2lCQUFNLElBQUksS0FBSyxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQztnQkFDNUIsSUFBSSxDQUFDLGNBQWMsRUFBRSxDQUFDO1lBQ3hCLENBQUM7UUFDSCxDQUFDO0lBQ0gsQ0FBQztJQUdTLHNCQUFzQixDQUFDLEtBQW9CO1FBQ25ELElBQUksQ0FBQyxJQUFJLENBQUMsWUFBWSxFQUFFLEVBQUUsQ0FBQztZQUN6QixPQUFPO1FBQ1QsQ0FBQztRQUVELElBQUksS0FBSyxDQUFDLE9BQU8sSUFBSSxLQUFLLENBQUMsT0FBTyxFQUFFLENBQUM7WUFDbkMsSUFBSSxLQUFLLENBQUMsR0FBRyxLQUFLLEdBQUcsSUFBSSxLQUFLLENBQUMsR0FBRyxLQUFLLEdBQUcsRUFBRSxDQUFDO2dCQUMzQyxLQUFLLENBQUMsY0FBYyxFQUFFLENBQUM7Z0JBQ3ZCLElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQztZQUN2QixDQUFDO2lCQUFNLElBQUksS0FBSyxDQUFDLEdBQUcsS0FBSyxHQUFHLElBQUksS0FBSyxDQUFDLEdBQUcsS0FBSyxHQUFHLEVBQUUsQ0FBQztnQkFDbEQsS0FBSyxDQUFDLGNBQWMsRUFBRSxDQUFDO2dCQUN2QixJQUFJLENBQUMsY0FBYyxFQUFFLENBQUM7WUFDeEIsQ0FBQztpQkFBTSxJQUFJLEtBQUssQ0FBQyxHQUFHLEtBQUssR0FBRyxFQUFFLENBQUM7Z0JBQzdCLEtBQUssQ0FBQyxjQUFjLEVBQUUsQ0FBQztnQkFDdkIsSUFBSSxDQUFDLGdCQUFnQixFQUFFLENBQUM7WUFDMUIsQ0FBQztRQUNILENBQUM7SUFDSCxDQUFDO0lBR1Msb0JBQW9CLENBQUMsS0FBaUI7UUFDOUMsSUFBSSxDQUFDLElBQUksQ0FBQyxVQUFVLEVBQUUsRUFBRSxDQUFDO1lBQ3ZCLE9BQU87UUFDVCxDQUFDO1FBRUQsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLFdBQVcsRUFBRSxFQUFFLGFBQWEsQ0FBQztRQUNqRCxJQUFJLE1BQU0sSUFBSSxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLE1BQWMsQ0FBQyxFQUFFLENBQUM7WUFDckQsSUFBSSxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDN0IsQ0FBQztJQUNILENBQUM7SUFFUyxnQkFBZ0IsQ0FBQyxNQUFjLEVBQUUsSUFBdUI7UUFDaEUsT0FBTyxJQUFJLENBQUMsRUFBRSxDQUFDO0lBQ2pCLENBQUM7SUFFRDs7O09BR0c7SUFDSDs7Ozs7T0FLRztJQUNIOzs7O09BSUc7SUFDTyxhQUFhLENBQUMsS0FBWSxFQUFFLElBQXVCO1FBQzNELEtBQUssQ0FBQyxlQUFlLEVBQUUsQ0FBQztRQUN4QixLQUFLLENBQUMsY0FBYyxFQUFFLENBQUM7UUFDdkIsSUFBSSxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsRUFBRSxNQUFNLEVBQUUsSUFBSSxDQUFDLEVBQUUsRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFFLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDdkcsQ0FBQztJQUVTLGdCQUFnQixDQUFDLEtBQVksRUFBRSxJQUF1QjtRQUM5RCxLQUFLLENBQUMsZUFBZSxFQUFFLENBQUM7UUFDeEIsS0FBSyxDQUFDLGNBQWMsRUFBRSxDQUFDO1FBQ3ZCLElBQUksQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDM0IsQ0FBQztJQUVTLGlCQUFpQixDQUFDLEtBQVksRUFBRSxJQUF1QjtRQUMvRCxLQUFLLENBQUMsZUFBZSxFQUFFLENBQUM7UUFDeEIsS0FBSyxDQUFDLGNBQWMsRUFBRSxDQUFDO1FBQ3ZCLElBQUksQ0FBQyxjQUFjLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDNUIsQ0FBQztJQUVEOzs7OztPQUtHO0lBQ08sZ0JBQWdCLENBQUMsS0FBWTtRQUNyQyxLQUFLLENBQUMsZUFBZSxFQUFFLENBQUM7SUFDMUIsQ0FBQztJQUVELG1GQUFtRjtJQUMzRSxhQUFhLENBQUMsSUFBdUI7UUFDM0MsSUFBSSxDQUFDLGlCQUFpQixDQUFDLElBQUksQ0FBQztZQUMxQixNQUFNLEVBQUUsSUFBSSxDQUFDLEVBQUU7WUFDZixJQUFJO1lBQ0osT0FBTyxFQUFFLENBQUMsSUFBMEIsRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxFQUFFLENBQUM7U0FDOUUsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVELCtFQUErRTtJQUN2RSxjQUFjLENBQUMsSUFBdUI7UUFDNUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUM7WUFDdEIsTUFBTSxFQUFFLElBQUksQ0FBQyxFQUFFO1lBQ2YsSUFBSTtZQUNKLGdGQUFnRjtZQUNoRixPQUFPLEVBQUUsR0FBRyxFQUFFLENBQUMsQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQztTQUM3RyxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQscURBQXFEO0lBQzNDLFdBQVcsQ0FBQyxJQUF1QjtRQUMzQyxPQUFPLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSxNQUFNLElBQUksQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQzFDLENBQUM7SUFFRCx3RUFBd0U7SUFDOUQsWUFBWSxDQUFDLElBQXVCO1FBQzVDLE9BQU8sSUFBSSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsSUFBSSxJQUFJLENBQUMsS0FBSyxFQUFFLEdBQUcsSUFBSSxDQUFDLGlCQUFpQixFQUFFLENBQUM7SUFDM0UsQ0FBQztJQUVELG9FQUFvRTtJQUMxRCxhQUFhLENBQUMsSUFBdUI7UUFDN0MsSUFBSSxJQUFJLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUM7WUFDM0IsT0FBTyxJQUFJLENBQUM7UUFDZCxDQUFDO1FBRUQsT0FBTyxJQUFJLENBQUMsS0FBSyxFQUFFLEdBQUcsSUFBSSxDQUFDLGlCQUFpQixFQUFFLENBQUM7SUFDakQsQ0FBQztJQUVTLHNCQUFzQixDQUFDLEtBQVk7UUFDM0MsSUFBSSxDQUFDLElBQUksQ0FBQyxjQUFjLEVBQUUsRUFBRSxDQUFDO1lBQzNCLE9BQU87UUFDVCxDQUFDO1FBRUQsS0FBSyxDQUFDLGVBQWUsRUFBRSxDQUFDO0lBQzFCLENBQUM7SUFFUyx5QkFBeUIsQ0FBQyxLQUFZO1FBQzlDLElBQUksSUFBSSxDQUFDLEtBQUssRUFBRSxLQUFLLENBQUMsRUFBRSxDQUFDO1lBQ3ZCLE9BQU87UUFDVCxDQUFDO1FBRUQsS0FBSyxDQUFDLGVBQWUsRUFBRSxDQUFDO0lBQzFCLENBQUM7SUFFUyxpQkFBaUIsQ0FBQyxJQUF1QixFQUFFLEtBQWtCO1FBQ3JFLElBQUksS0FBSyxFQUFFLENBQUM7WUFDVixNQUFNLE1BQU0sR0FBRyxLQUFLLENBQUMsTUFBcUIsQ0FBQztZQUMzQyxJQUFJLE1BQU0sQ0FBQyxPQUFPLENBQUMsOEJBQThCLENBQUMsSUFBSSxNQUFNLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUM7Z0JBQy9FLE9BQU87WUFDVCxDQUFDO1FBQ0gsQ0FBQztRQUNELElBQUksQ0FBQyxjQUFjLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUNqQyxJQUFJLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUNoQyxDQUFDO0lBRVMsYUFBYSxDQUFDLEtBQVksRUFBRSxJQUF1QjtRQUMzRCxLQUFLLENBQUMsZUFBZSxFQUFFLENBQUM7UUFDeEIsTUFBTSxXQUFXLEdBQTZCO1lBQzVDLE1BQU0sRUFBRSxJQUFJLENBQUMsRUFBRTtZQUNmLElBQUk7WUFDSixPQUFPLEVBQUUsR0FBRyxFQUFFLENBQUMsSUFBSTtTQUNwQixDQUFDO1FBQ0YsSUFBSSxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLENBQUM7SUFDdkMsQ0FBQztJQUVTLGVBQWUsQ0FBQyxLQUFnQjtRQUN4QyxJQUFJLENBQUMsSUFBSSxDQUFDLGtCQUFrQixFQUFFLElBQUksSUFBSSxDQUFDLEtBQUssRUFBRSxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQ25ELE9BQU87UUFDVCxDQUFDO1FBQ0QsS0FBSyxDQUFDLGNBQWMsRUFBRSxDQUFDO1FBQ3ZCLElBQUksS0FBSyxDQUFDLFlBQVksRUFBRSxDQUFDO1lBQ3ZCLEtBQUssQ0FBQyxZQUFZLENBQUMsVUFBVSxHQUFHLE1BQU0sQ0FBQztRQUN6QyxDQUFDO1FBRUQsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLGFBQWEsRUFBRSxFQUFFLGFBQWEsQ0FBQztRQUN0RCxNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksRUFBRSxDQUFDO1FBQ2pDLE1BQU0sT0FBTyxHQUFHLGdCQUFnQixDQUM5QixJQUFJLENBQUMsT0FBTyxDQUFDLGNBQWMsRUFBa0QsRUFDN0UsS0FBSyxDQUFDLFlBQVksQ0FDbkIsQ0FBQztRQUVGLElBQUksQ0FBQyxTQUFTLElBQUksQ0FBQyxJQUFJLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQztZQUNwQyxPQUFPO1FBQ1QsQ0FBQztRQUVELE1BQU0sWUFBWSxHQUFHLFNBQVMsQ0FBQyxhQUFhLENBQUMsVUFBVSxDQUF1QixDQUFDO1FBQy9FLElBQUksWUFBWSxFQUFFLENBQUM7WUFDakIsSUFBSSxDQUFDLFlBQVksQ0FBQyxTQUFTLENBQUMsUUFBUSxDQUFDLGNBQWMsQ0FBQyxFQUFFLENBQUM7Z0JBQ3JELFlBQVksQ0FBQyxTQUFTLENBQUMsR0FBRyxDQUFDLGNBQWMsQ0FBQyxDQUFDO1lBQzdDLENBQUM7WUFDRCxJQUFJLENBQUMsY0FBYyxHQUFHLFlBQVksQ0FBQztRQUNyQyxDQUFDO1FBRUQsTUFBTSxLQUFLLEdBQUcsa0JBQWtCLENBQUMsS0FBSyxFQUFFLFNBQVMsRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFFLElBQUksQ0FBQyxPQUFPLENBQUMsWUFBWSxDQUFDLENBQUM7UUFFN0YsSUFBSSxLQUFLLEVBQUUsYUFBYSxJQUFJLEtBQUssQ0FBQyxlQUFlLEVBQUUsQ0FBQztZQUNsRCxJQUFJLElBQUksQ0FBQyxlQUFlLEtBQUssS0FBSyxDQUFDLGVBQWUsRUFBRSxDQUFDO2dCQUNuRCxJQUFJLENBQUMsbUJBQW1CLEVBQUUsQ0FBQztnQkFDM0IsS0FBSyxDQUFDLGVBQWUsQ0FBQyxTQUFTLENBQUMsR0FBRyxDQUFDLGNBQWMsQ0FBQyxDQUFDO2dCQUNwRCxJQUFJLENBQUMsZUFBZSxHQUFHLEtBQUssQ0FBQyxlQUFlLENBQUM7WUFDL0MsQ0FBQztRQUNILENBQUM7YUFBTSxDQUFDO1lBQ04sSUFBSSxDQUFDLG1CQUFtQixFQUFFLENBQUM7UUFDN0IsQ0FBQztRQUVELElBQUksQ0FBQyxTQUFTLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQzVCLENBQUM7SUFFUyxnQkFBZ0IsQ0FBQyxLQUFnQjtRQUN6QyxJQUFJLElBQUksQ0FBQyxLQUFLLEVBQUUsR0FBRyxDQUFDLEVBQUUsQ0FBQztZQUNyQixPQUFPO1FBQ1QsQ0FBQztRQUNELElBQUksS0FBSyxDQUFDLGFBQWEsRUFBRSxDQUFDO1lBQ3hCLE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxhQUFhLEVBQUUsRUFBRSxhQUFhLENBQUM7WUFDdEQsSUFBSSxTQUFTLElBQUksU0FBUyxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsYUFBcUIsQ0FBQyxFQUFFLENBQUM7Z0JBQ2pFLE9BQU87WUFDVCxDQUFDO1FBQ0gsQ0FBQztRQUNELElBQUksQ0FBQyxTQUFTLENBQUMsR0FBRyxDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBQzlCLElBQUksQ0FBQyxlQUFlLEVBQUUsQ0FBQztJQUN6QixDQUFDO0lBRVMsV0FBVyxDQUFDLEtBQWdCO1FBQ3BDLElBQUksQ0FBQyxJQUFJLENBQUMsa0JBQWtCLEVBQUUsSUFBSSxJQUFJLENBQUMsS0FBSyxFQUFFLEdBQUcsQ0FBQyxFQUFFLENBQUM7WUFDbkQsT0FBTztRQUNULENBQUM7UUFDRCxLQUFLLENBQUMsY0FBYyxFQUFFLENBQUM7UUFDdkIsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLFNBQVMsRUFBRSxDQUFDO1FBQy9CLE1BQU0sT0FBTyxHQUFHLGdCQUFnQixDQUM5QixJQUFJLENBQUMsT0FBTyxDQUFDLGNBQWMsRUFBa0QsRUFDN0UsS0FBSyxDQUFDLFlBQVksQ0FDbkIsQ0FBQztRQUVGLElBQUksQ0FBQyxTQUFTLENBQUMsR0FBRyxDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBQzlCLElBQUksQ0FBQyxlQUFlLEVBQUUsQ0FBQztRQUN2QixJQUFJLENBQUMsT0FBTyxDQUFDLGdCQUFnQixFQUFFLENBQUM7UUFFaEMsSUFBSSxDQUFDLEtBQUssSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDO1lBQ3ZCLE9BQU87UUFDVCxDQUFDO1FBRUQsTUFBTSxjQUFjLEdBQUcsS0FBSyxDQUFDLGFBQWEsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLGNBQWMsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDO1FBQzlFLE1BQU0sUUFBUSxHQUFHLE9BQU8sQ0FBQyxjQUFjLENBQUMsQ0FBQztRQUV6QyxJQUFJLFNBQStCLENBQUM7UUFDcEMsTUFBTSxVQUFVLEdBQUcsT0FBa0MsQ0FBQztRQUN0RCxJQUFJLE9BQU8sVUFBVSxDQUFDLGFBQWEsQ0FBQyxLQUFLLFVBQVUsRUFBRSxDQUFDO1lBQ3BELE1BQU0sUUFBUSxHQUFJLFVBQVUsQ0FBQyxhQUFhLENBQTJELENBQUMsUUFBUSxDQUFDLENBQUM7WUFDaEgsU0FBUyxHQUFHLFFBQVEsSUFBSTtnQkFDdEIsSUFBSSxFQUFFLEtBQUssQ0FBQyxJQUFJO2dCQUNoQixJQUFJLEVBQUUsS0FBSyxDQUFDLElBQUk7Z0JBQ2hCLElBQUksRUFBRSxPQUFPLENBQUMsSUFBSSxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxJQUFJLEVBQUUsT0FBTyxDQUFDLElBQUksRUFBRSxLQUFLLEVBQUUsT0FBTyxDQUFDLEtBQUssRUFBRSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7YUFDaEcsQ0FBQztRQUNKLENBQUM7YUFBTSxDQUFDO1lBQ04sTUFBTSxXQUFXLEdBQUcsT0FBTyxDQUFDLElBQUksSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsSUFBSSxFQUFFLE9BQU8sQ0FBQyxJQUFJLEVBQUUsS0FBSyxFQUFFLE9BQU8sQ0FBQyxLQUFLLEVBQUUsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLENBQUM7WUFDOUcsU0FBUyxHQUFHO2dCQUNWLElBQUksRUFBRSxLQUFLLENBQUMsSUFBSTtnQkFDaEIsSUFBSSxFQUFFLEtBQUssQ0FBQyxJQUFJO2dCQUNoQixJQUFJLEVBQUUsV0FBVzthQUNsQixDQUFDO1FBQ0osQ0FBQztRQUVELE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsd0JBQXdCLENBQ3JELFNBQVMsRUFDVCxLQUFLLENBQUMsR0FBRyxFQUNULEtBQUssQ0FBQyxHQUFHLEVBQ1QsY0FBYyxDQUNmLENBQUM7UUFFRixJQUFJLFNBQVMsRUFBRSxDQUFDO1lBQ2QsSUFBSSxDQUFDLGNBQWMsQ0FBQyxHQUFHLENBQUMsU0FBUyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1lBQ3RDLElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDO2dCQUNwQixJQUFJLEVBQUUsU0FBUztnQkFDZixRQUFRLEVBQUUsY0FBYztnQkFDeEIsR0FBRyxFQUFFLEtBQUssQ0FBQyxHQUFHO2dCQUNkLEdBQUcsRUFBRSxLQUFLLENBQUMsR0FBRztnQkFDZCxJQUFJLEVBQUUsS0FBSyxDQUFDLElBQUk7Z0JBQ2hCLElBQUksRUFBRSxLQUFLLENBQUMsSUFBSTtnQkFDaEIsUUFBUSxFQUFFLEtBQUs7Z0JBQ2YsT0FBTzthQUNSLENBQUMsQ0FBQztZQUNILE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxFQUFFLENBQUM7WUFDakMsSUFBSSxJQUFJLEVBQUUsQ0FBQztnQkFDVCxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQztvQkFDbEIsSUFBSTtvQkFDSixNQUFNLEVBQUUsU0FBUyxDQUFDLEVBQUU7aUJBQ3JCLENBQUMsQ0FBQztZQUNMLENBQUM7UUFDSCxDQUFDO0lBQ0gsQ0FBQztJQUVPLG1CQUFtQjtRQUN6QixJQUFJLElBQUksQ0FBQyxlQUFlLEVBQUUsQ0FBQztZQUN6QixJQUFJLENBQUMsZUFBZSxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUMsY0FBYyxDQUFDLENBQUM7WUFDdEQsSUFBSSxDQUFDLGVBQWUsR0FBRyxTQUFTLENBQUM7UUFDbkMsQ0FBQztJQUNILENBQUM7SUFFTyxlQUFlO1FBQ3JCLElBQUksQ0FBQyxtQkFBbUIsRUFBRSxDQUFDO1FBQzNCLElBQUksSUFBSSxDQUFDLGNBQWMsSUFBSSxDQUFDLElBQUksQ0FBQyxhQUFhLEVBQUUsRUFBRSxDQUFDO1lBQ2pELElBQUksQ0FBQyxjQUFjLENBQUMsU0FBUyxDQUFDLE1BQU0sQ0FBQyxjQUFjLENBQUMsQ0FBQztZQUNyRCxJQUFJLENBQUMsY0FBYyxHQUFHLFNBQVMsQ0FBQztRQUNsQyxDQUFDO1FBQ0QsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLGFBQWEsRUFBRSxFQUFFLGFBQWEsQ0FBQztRQUN0RCxJQUFJLFNBQVMsSUFBSSxDQUFDLElBQUksQ0FBQyxhQUFhLEVBQUUsRUFBRSxDQUFDO1lBQ3ZDLFNBQVMsQ0FBQyxnQkFBZ0IsQ0FBQyx1QkFBdUIsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDLEVBQUUsRUFBRSxFQUFFO2dCQUNqRSxFQUFFLENBQUMsU0FBUyxDQUFDLE1BQU0sQ0FBQyxjQUFjLENBQUMsQ0FBQztZQUN0QyxDQUFDLENBQUMsQ0FBQztRQUNMLENBQUM7SUFDSCxDQUFDO3dHQXhvQlUsK0JBQStCOzRGQUEvQiwrQkFBK0IsMDJGQXFHRCxpQkFBaUIsOFVBSUksZ0JBQWdCLDZDQzlKaEYsMG5yQ0FxaEJBLDR0TERoZWEsK0JBQStCLHFnQkFMaEMsY0FBYyxvUkFBRSxzQ0FBc0Msc2pCQUFFLGdCQUFnQixtSkFBRSxlQUFlOzs0RkFLeEYsK0JBQStCO2tCQVIzQyxTQUFTOytCQUNFLHFDQUFxQyxjQUNuQyxJQUFJLFdBQ1AsQ0FBQyxjQUFjLEVBQUUsc0NBQXNDLEVBQUUsZ0JBQWdCLEVBQUUsZUFBZSxDQUFDLG1CQUduRix1QkFBdUIsQ0FBQyxNQUFNO3dEQWdXckMsc0JBQXNCO3NCQUQvQixZQUFZO3VCQUFDLGtCQUFrQixFQUFFLENBQUMsUUFBUSxDQUFDO2dCQXFCbEMsb0JBQW9CO3NCQUQ3QixZQUFZO3VCQUFDLGdCQUFnQixFQUFFLENBQUMsUUFBUSxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgQWZ0ZXJWaWV3SW5pdCxcbiAgQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3ksXG4gIENvbXBvbmVudCxcbiAgRWxlbWVudFJlZixcbiAgSG9zdExpc3RlbmVyLFxuICBPbkRlc3Ryb3ksXG4gIFRlbXBsYXRlUmVmLFxuICBWaWV3Q29udGFpbmVyUmVmLFxuICBjb21wdXRlZCxcbiAgZWZmZWN0LFxuICBpbmplY3QsXG4gIGlucHV0LFxuICBtb2RlbCxcbiAgb3V0cHV0LFxuICBzaWduYWwsXG4gIHZpZXdDaGlsZCxcbiAgdmlld0NoaWxkcmVuLFxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IE5nVGVtcGxhdGVPdXRsZXQgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuaW1wb3J0IHsgTGlic1VpQ29tcG9uZW50c0J1dHRvbnNCdXR0b25Db21wb25lbnQgfSBmcm9tICdAbGlicy11aS9jb21wb25lbnRzLWJ1dHRvbnMtYnV0dG9uJztcbmltcG9ydCB7IEdyaWRzdGVyQ29tcG9uZW50LCBHcmlkc3Rlck1vZHVsZSB9IGZyb20gJ2dyaWRzdGVyMTgnO1xuaW1wb3J0IHsgVHJhbnNsYXRlTW9kdWxlIH0gZnJvbSAnQG5neC10cmFuc2xhdGUvY29yZSc7XG5pbXBvcnQgeyBlbXB0eVJvb3ROb2RlIH0gZnJvbSAnLi4vZGVmaW5lcy9ncmlkc3Rlci1jb25maWcuZGVmaW5lJztcbmltcG9ydCB7IExpYnNVaUdyaWRMYXlvdXRTZXJ2aWNlIH0gZnJvbSAnLi4vZ3JpZC1sYXlvdXQuc2VydmljZSc7XG5pbXBvcnQge1xuICBUX2dyaWRMYXlvdXRfYWN0aW9uRXZlbnQsXG4gIFRfZ3JpZExheW91dF9hZGRFdmVudCxcbiAgVF9ncmlkTGF5b3V0X2NoYW5nZUV2ZW50LFxuICBUX2dyaWRMYXlvdXRfZHJvcEV2ZW50LFxuICBUX2dyaWRMYXlvdXRfZHJvcEdob3N0LFxuICBUX2dyaWRMYXlvdXRfZXh0ZXJuYWxEcmFnUGF5bG9hZCxcbiAgVF9ncmlkTGF5b3V0X25ld05vZGUsXG4gIFRfZ3JpZExheW91dF9ub2RlLFxuICBUX2dyaWRMYXlvdXRfdG9vbGJhckNvbnRleHQsXG4gIFRfZ3JpZExheW91dF96b29tUHJlc2V0LFxufSBmcm9tICcuLi9pbnRlcmZhY2VzL2dyaWQtbGF5b3V0LmludGVyZmFjZSc7XG5pbXBvcnQgeyBjYWxjdWxhdGVEcm9wR2hvc3QsIHBhcnNlRHJvcFBheWxvYWQgfSBmcm9tICcuLi9kZWZpbmVzL2NvbGxpc2lvbi5kZWZpbmUnO1xuXG4vKipcbiAqIE3hurd0IHBo4bqzbmcga8OpbyB0aOG6oy4gxJDhu4cgcXV5OiBraOG7kWkgY8OzIGBjaGlsZHJlbmAgdGjDrCBydeG7mXQgbsOzIGzhuqFpIGzDoCBt4buZdCBt4bq3dCBwaOG6s25nIG7hu69hLlxuICpcbiAqIE7GoWkgZMO5bmcgS0jDlE5HIGThu7FuZyBjb21wb25lbnQgbsOgeSB0cuG7sWMgdGnhur9wIGNobyB04burbmcga2jhu5FpIOKAlCBjaOG7iSDEkeG6t3QgTeG7mFQgdGjhursg4bufIGfhu5FjIHbDoCB0cnV54buBblxuICogYG5vZGVDb21wb25lbnRUeXBlYCBxdWEgYExpYnNVaUdyaWRMYXlvdXRTZXJ2aWNlLmluaXQoKWAuIFRoxrAgdmnhu4duIHThu7EgZ+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+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
|
|
590
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ3JpZC1sYXlvdXQtY2FudmFzLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL2xpYnMtdWkvc2VydmljZXMvZ3JpZC1sYXlvdXQvc3JjL2NhbnZhcy9ncmlkLWxheW91dC1jYW52YXMuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vLi4vbGlicy11aS9zZXJ2aWNlcy9ncmlkLWxheW91dC9zcmMvY2FudmFzL2dyaWQtbGF5b3V0LWNhbnZhcy5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBRUwsdUJBQXVCLEVBQ3ZCLFNBQVMsRUFFVCxZQUFZLEVBR1osZ0JBQWdCLEVBQ2hCLFFBQVEsRUFDUixNQUFNLEVBQ04sTUFBTSxFQUNOLEtBQUssRUFDTCxLQUFLLEVBQ0wsTUFBTSxFQUNOLE1BQU0sRUFDTixTQUFTLEVBQ1QsWUFBWSxHQUNiLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQ25ELE9BQU8sRUFBRSxzQ0FBc0MsRUFBRSxNQUFNLG9DQUFvQyxDQUFDO0FBQzVGLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxjQUFjLEVBQUUsTUFBTSxZQUFZLENBQUM7QUFDL0QsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQ3RELE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxtQ0FBbUMsQ0FBQztBQUNsRSxPQUFPLEVBQUUsdUJBQXVCLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQWFqRSxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQzs7OztBQUVuRjs7Ozs7R0FLRztBQVNILE1BQU0sT0FBTywrQkFBK0I7SUFDMUM7Ozs7O09BS0c7SUFDTSxJQUFJLEdBQUcsS0FBSyxFQUFxQixDQUFDO0lBQzNDLDhEQUE4RDtJQUNyRCxLQUFLLEdBQUcsS0FBSyxDQUFTLENBQUMsQ0FBQyxDQUFDO0lBRWxDOzs7Ozs7T0FNRztJQUNNLGFBQWEsR0FBRyxLQUFLLENBQStCLEtBQUssRUFBRSxFQUFFLFNBQVMsRUFBRSxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsS0FBSyxJQUFJLEtBQUssRUFBRSxDQUFDLENBQUM7SUFFOUc7Ozs7Ozs7T0FPRztJQUNNLGVBQWUsR0FBRyxLQUFLLENBQXVELFNBQVMsQ0FBQyxDQUFDO0lBRWxHOzs7OztPQUtHO0lBQ00sU0FBUyxHQUFHLE1BQU0sRUFBNEIsQ0FBQztJQUN4RDs7O09BR0c7SUFDTSxhQUFhLEdBQUcsTUFBTSxFQUE0QixDQUFDO0lBQzVEOzs7T0FHRztJQUNNLGlCQUFpQixHQUFHLE1BQU0sRUFBeUIsQ0FBQztJQUM3RCw4RkFBOEY7SUFDckYsYUFBYSxHQUFHLE1BQU0sRUFBNEIsQ0FBQztJQUU1RCxtRkFBbUY7SUFDMUUsVUFBVSxHQUFHLEtBQUssQ0FBK0IsS0FBSyxFQUFFLEVBQUUsU0FBUyxFQUFFLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxLQUFLLElBQUksS0FBSyxFQUFFLENBQUMsQ0FBQztJQUUzRywyRUFBMkU7SUFDbEUsSUFBSSxHQUFHLEtBQUssQ0FBcUIsU0FBUyxDQUFDLENBQUM7SUFFckQsd0RBQXdEO0lBQy9DLE9BQU8sR0FBRyxLQUFLLENBQVMsR0FBRyxDQUFDLENBQUM7SUFFdEMsc0RBQXNEO0lBQzdDLE9BQU8sR0FBRyxLQUFLLENBQVMsR0FBRyxDQUFDLENBQUM7SUFFdEMsOEVBQThFO0lBQ3JFLFFBQVEsR0FBRyxLQUFLLENBQVMsSUFBSSxDQUFDLENBQUM7SUFFeEMscUVBQXFFO0lBQzVELFVBQVUsR0FBRyxLQUFLLENBQVMsSUFBSSxDQUFDLENBQUM7SUFFMUMsdUVBQXVFO0lBQzlELGNBQWMsR0FBRyxLQUFLLENBQVMsR0FBRyxDQUFDLENBQUM7SUFFN0MsZ0ZBQWdGO0lBQ3ZFLFVBQVUsR0FBRyxLQUFLLENBQXFCLG9CQUFvQixDQUFDLENBQUM7SUFFdEUsbUZBQW1GO0lBQzFFLFlBQVksR0FBRyxLQUFLLENBQStCLElBQUksRUFBRSxFQUFFLFNBQVMsRUFBRSxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsS0FBSyxJQUFJLElBQUksRUFBRSxDQUFDLENBQUM7SUFFM0csbUdBQW1HO0lBQzFGLGFBQWEsR0FBRyxLQUFLLENBQStCLElBQUksRUFBRSxFQUFFLFNBQVMsRUFBRSxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsS0FBSyxJQUFJLElBQUksRUFBRSxDQUFDLENBQUM7SUFFNUcsNENBQTRDO0lBQ25DLGFBQWEsR0FBRyxNQUFNLEVBQVUsQ0FBQztJQUUxQyx3RUFBd0U7SUFDL0Qsa0JBQWtCLEdBQUcsS0FBSyxDQUErQixJQUFJLEVBQUUsRUFBRSxTQUFTLEVBQUUsQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLEtBQUssSUFBSSxJQUFJLEVBQUUsQ0FBQyxDQUFDO0lBRWpILHlDQUF5QztJQUNoQyxhQUFhLEdBQUcsS0FBSyxDQUErQixLQUFLLEVBQUUsRUFBRSxTQUFTLEVBQUUsQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLEtBQUssSUFBSSxLQUFLLEVBQUUsQ0FBQyxDQUFDO0lBRTlHLG9DQUFvQztJQUMzQixjQUFjLEdBQUcsS0FBSyxDQUE0QixTQUFTLENBQUMsQ0FBQztJQUV0RSwwREFBMEQ7SUFDakQsV0FBVyxHQUFHLE1BQU0sRUFBMEIsQ0FBQztJQUV4RCxpREFBaUQ7SUFDeEMsYUFBYSxHQUFHLE1BQU0sRUFBcUIsQ0FBQztJQUVyRCwwRUFBMEU7SUFDakUsYUFBYSxHQUFHLE1BQU0sRUFBNEIsQ0FBQztJQUUzQyxXQUFXLEdBQUcsU0FBUyxDQUFDLGlCQUFpQixDQUFDLENBQUM7SUFDM0MsYUFBYSxHQUFHLFNBQVMsQ0FBMEIsWUFBWSxDQUFDLENBQUM7SUFDakUsV0FBVyxHQUFHLFNBQVMsQ0FBMEIsVUFBVSxDQUFDLENBQUM7SUFDOUUsNkRBQTZEO0lBQzVDLFNBQVMsR0FBRyxZQUFZLENBQUMsVUFBVSxFQUFFLEVBQUUsSUFBSSxFQUFFLGdCQUFnQixFQUFFLENBQUMsQ0FBQztJQUVsRiwwRUFBMEU7SUFDdkQsU0FBUyxHQUFHLE1BQU0sQ0FBcUMsU0FBUyxDQUFDLENBQUM7SUFFN0UsZUFBZSxDQUFlO0lBQzlCLGNBQWMsQ0FBZTtJQUVyQyxrREFBa0Q7SUFDL0IsVUFBVSxHQUFHLE1BQU0sQ0FBVSxLQUFLLENBQUMsQ0FBQztJQUV2RCxpQ0FBaUM7SUFDZCxXQUFXLEdBQW1DO1FBQy9ELEVBQUUsS0FBSyxFQUFFLDJCQUEyQixFQUFFLEtBQUssRUFBRSxHQUFHLEVBQUU7UUFDbEQsRUFBRSxLQUFLLEVBQUUsK0JBQStCLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRTtRQUN2RCxFQUFFLEtBQUssRUFBRSwrQkFBK0IsRUFBRSxLQUFLLEVBQUUsSUFBSSxFQUFFO1FBQ3ZELEVBQUUsS0FBSyxFQUFFLCtCQUErQixFQUFFLEtBQUssRUFBRSxJQUFJLEVBQUU7UUFDdkQsRUFBRSxLQUFLLEVBQUUsMkJBQTJCLEVBQUUsS0FBSyxFQUFFLEdBQUcsRUFBRTtRQUNsRCxFQUFFLEtBQUssRUFBRSxnQ0FBZ0MsRUFBRSxLQUFLLEVBQUUsQ0FBQyxFQUFFO1FBQ3JELEVBQUUsS0FBSyxFQUFFLCtCQUErQixFQUFFLEtBQUssRUFBRSxHQUFHLEVBQUU7UUFDdEQsRUFBRSxLQUFLLEVBQUUsOEJBQThCLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRTtLQUN2RCxDQUFDO0lBRUYsc0ZBQXNGO0lBQ25FLFdBQVcsR0FBRyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7SUFFbkMsT0FBTyxHQUFHLE1BQU0sQ0FBQyx1QkFBdUIsQ0FBQyxDQUFDO0lBRTNELHlGQUF5RjtJQUN0RSxZQUFZLEdBQUcsUUFBUSxDQUFDLEdBQUcsRUFBRTtRQUM5QyxPQUFPLElBQUksQ0FBQyxLQUFLLEVBQUUsS0FBSyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsVUFBVSxFQUFFLElBQUksSUFBSSxDQUFDLE9BQU8sQ0FBQyxnQkFBZ0IsQ0FBQyxhQUFhLEVBQUUsQ0FBQyxDQUFDO0lBQ3BHLENBQUMsQ0FBQyxDQUFDO0lBRWdCLFdBQVcsR0FBRyxRQUFRLENBQUMsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDO0lBQ2xELFdBQVcsR0FBRyxRQUFRLENBQUMsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsV0FBVyxFQUFFLEdBQUcsR0FBRyxDQUFDLENBQUMsQ0FBQztJQUV0Rjs7Ozs7Ozs7OztPQVVHO0lBQ2dCLFdBQVcsR0FBRyxRQUFRLENBQUMsR0FBRyxFQUFFO1FBQzdDLElBQUksQ0FBQyxPQUFPLENBQUMsT0FBTyxFQUFFLENBQUM7UUFFdkIsSUFBSSxJQUFJLENBQUMsS0FBSyxFQUFFLEdBQUcsQ0FBQyxFQUFFLENBQUM7WUFDckIsT0FBTyxJQUFJLENBQUMsSUFBSSxFQUFFLElBQUksYUFBYSxFQUFFLENBQUM7UUFDeEMsQ0FBQztRQUVELE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLEVBQUUsSUFBSSxhQUFhLEVBQUUsQ0FBQztJQUNoRCxDQUFDLENBQUMsQ0FBQztJQUVnQixRQUFRLEdBQUcsUUFBUSxDQUFDLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQyxRQUFRLElBQUksRUFBRSxDQUFDLENBQUM7SUFFaEY7Ozs7O09BS0c7SUFDZ0IsZUFBZSxHQUFHLFFBQVEsQ0FBcUMsR0FBRyxFQUFFLENBQ3JGLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUFDLENBQUM7UUFDN0IsU0FBUyxFQUFFLElBQUk7UUFDZixXQUFXLEVBQUUsSUFBSSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUM7UUFDbkMsWUFBWSxFQUFFLElBQUksQ0FBQyxZQUFZLENBQUMsSUFBSSxDQUFDO1FBQ3JDLGFBQWEsRUFBRSxJQUFJLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQztRQUN2QyxNQUFNLEVBQUUsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsRUFBRSxNQUFNLEVBQUUsSUFBSSxDQUFDLEVBQUUsRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLE9BQU8sRUFBRSxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQztRQUN4SCxTQUFTLEVBQUUsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUM7UUFDekMsVUFBVSxFQUFFLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxjQUFjLENBQUMsSUFBSSxDQUFDO0tBQzVDLENBQUMsQ0FBQyxDQUNKLENBQUM7SUFFaUIsY0FBYyxHQUFHLFFBQVEsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsS0FBSyxFQUFFLEdBQUcsQ0FBQyxDQUFDLENBQUM7SUFFckU7OztPQUdHO0lBQ2dCLFNBQVMsR0FBRyxRQUFRLENBQUMsR0FBRyxFQUFFLENBQUMsQ0FBQyxJQUFJLENBQUMsS0FBSyxFQUFFLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUVuRyxtRkFBbUY7SUFDaEUsaUJBQWlCLEdBQUcsUUFBUSxDQUFDLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsZ0JBQWdCLENBQUMsaUJBQWlCLEVBQUUsQ0FBQyxDQUFDO0lBRXpHOzs7Ozs7T0FNRztJQUNnQixnQkFBZ0IsR0FBRyxRQUFRLENBQUMsR0FBRyxFQUFFLENBQUMsR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLGdCQUFnQixDQUFDLGdCQUFnQixFQUFFLElBQUksQ0FBQyxDQUFDO0lBRTlHLDBGQUEwRjtJQUN2RSxVQUFVLEdBQUcsUUFBUSxDQUFDLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsVUFBVSxFQUFFLENBQUMsQ0FBQztJQUV2RCxXQUFXLEdBQUcsUUFBUSxDQUFDLEdBQUcsRUFBRTtRQUM3Qyx1RkFBdUY7UUFDdkYsOERBQThEO1FBQzlELElBQUksQ0FBQyxPQUFPLENBQUMsT0FBTyxFQUFFLENBQUM7UUFFdkIsT0FBTyxJQUFJLENBQUMsT0FBTyxDQUFDLGdCQUFnQixDQUFDLGVBQWUsQ0FBQyxJQUFJLENBQUMsS0FBSyxFQUFFLEVBQUUsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsRUFBRSxJQUFJLEVBQUUsSUFBSSxDQUFDLFdBQVcsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDO0lBQzlILENBQUMsQ0FBQyxDQUFDO0lBRUg7UUFDRSxxRUFBcUU7UUFDckUsOEVBQThFO1FBQzlFLE1BQU0sQ0FBQyxHQUFHLEVBQUU7WUFDVixNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsU0FBUyxFQUFFLENBQUM7WUFDL0IsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDO1lBRTlCLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxFQUFFLEVBQUU7Z0JBQ3hCLE1BQU0sSUFBSSxHQUFHLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQztnQkFFdEIsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO29CQUNWLE9BQU87Z0JBQ1QsQ0FBQztnQkFFRCwwREFBMEQ7Z0JBQzFELEVBQUU7Z0JBQ0YsNEZBQTRGO2dCQUM1Riw4RkFBOEY7Z0JBQzlGLDZGQUE2RjtnQkFDN0YsNEZBQTRGO2dCQUM1Rix5QkFBeUI7Z0JBQ3pCLEVBQUU7Z0JBQ0YsMEZBQTBGO2dCQUMxRix1RkFBdUY7Z0JBQ3ZGLE1BQU0sZUFBZSxHQUFHLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSxNQUFNLElBQUksQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDO2dCQUV6RCxJQUFJLGVBQWUsSUFBSSxDQUFDLElBQUksQ0FBQyxrQkFBa0IsRUFBRSxDQUFDO29CQUNoRCxPQUFPO2dCQUNULENBQUM7Z0JBRUQsSUFBSSxDQUFDLE9BQU8sQ0FBQyxnQkFBZ0IsQ0FBQyxVQUFVLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxLQUFLLEVBQUUsR0FBRyxDQUFDLEVBQUUsSUFBSSxDQUFDLENBQUM7WUFDekUsQ0FBQyxDQUFDLENBQUM7UUFDTCxDQUFDLENBQUMsQ0FBQztRQUVILDRDQUE0QztRQUM1QyxNQUFNLENBQUMsR0FBRyxFQUFFO1lBQ1YsTUFBTSxDQUFDLEdBQUcsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO1lBQ3RCLElBQUksQ0FBQyxLQUFLLFNBQVMsSUFBSSxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksRUFBRSxDQUFDLEdBQUcsS0FBSyxFQUFFLENBQUM7Z0JBQ2pFLElBQUksQ0FBQyxPQUFPLENBQUMsZ0JBQWdCLENBQUMsT0FBTyxDQUFDLENBQUMsRUFBRSxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUMsQ0FBQztZQUM5RCxDQUFDO1FBQ0gsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQsZUFBZTtRQUNiLElBQUksQ0FBQyxJQUFJLENBQUMsWUFBWSxFQUFFLElBQUksQ0FBQyxJQUFJLENBQUMsYUFBYSxFQUFFLEVBQUUsQ0FBQztZQUNsRCxPQUFPO1FBQ1QsQ0FBQztRQUVELE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FBQztRQUM5QixJQUFJLFFBQVEsR0FBRyxLQUFLLENBQUM7UUFDckIsSUFBSSxHQUFHLElBQUksT0FBTyxZQUFZLEtBQUssV0FBVyxFQUFFLENBQUM7WUFDL0MsSUFBSSxDQUFDO2dCQUNILFFBQVEsR0FBRyxPQUFPLENBQUMsWUFBWSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO1lBQ2hELENBQUM7WUFBQyxNQUFNLENBQUM7Z0JBQ1AsbUNBQW1DO1lBQ3JDLENBQUM7UUFDSCxDQUFDO1FBRUQsSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDO1lBQ2QsVUFBVSxDQUFDLEdBQUcsRUFBRTtnQkFDZCxNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsYUFBYSxFQUFFLEVBQUUsYUFBYSxDQUFDO2dCQUNyRCxJQUFJLFFBQVEsSUFBSSxRQUFRLENBQUMsV0FBVyxHQUFHLENBQUMsSUFBSSxRQUFRLENBQUMsV0FBVyxHQUFHLElBQUksQ0FBQyxVQUFVLEVBQUUsR0FBRyxFQUFFLEVBQUUsQ0FBQztvQkFDMUYsSUFBSSxDQUFDLGdCQUFnQixFQUFFLENBQUM7Z0JBQzFCLENBQUM7WUFDSCxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUM7UUFDVCxDQUFDO0lBQ0gsQ0FBQztJQUVELFdBQVc7UUFDVCxJQUFJLENBQUMsZUFBZSxFQUFFLENBQUM7UUFDdkIsS0FBSyxNQUFNLElBQUksSUFBSSxJQUFJLENBQUMsUUFBUSxFQUFFLEVBQUUsQ0FBQztZQUNuQyxJQUFJLENBQUMsT0FBTyxDQUFDLGdCQUFnQixDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUM7UUFDcEQsQ0FBQztJQUNILENBQUM7SUFFRCxtRkFBbUY7SUFDbkYsSUFBSSxlQUFlO1FBQ2pCLE9BQU87WUFDTCxTQUFTLEVBQUUsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLFdBQVcsRUFBRSxFQUFFLGNBQWMsRUFBRTtZQUNyRCxNQUFNLEVBQUUsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLGFBQWEsRUFBRTtZQUNsQyxPQUFPLEVBQUUsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLGNBQWMsRUFBRTtZQUNwQyxTQUFTLEVBQUUsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLGdCQUFnQixFQUFFO1lBQ3hDLFdBQVcsRUFBRSxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsZ0JBQWdCLEVBQUU7WUFDMUMsT0FBTyxFQUFFLENBQUMsR0FBVyxFQUFFLEVBQUU7Z0JBQ3ZCLElBQUksQ0FBQyxPQUFPLENBQUMsZ0JBQWdCLENBQUMsT0FBTyxDQUFDLEdBQUcsRUFBRSxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUMsQ0FBQztnQkFDOUQsSUFBSSxDQUFDLFdBQVcsRUFBRSxDQUFDO1lBQ3JCLENBQUM7WUFDRCw2RkFBNkY7WUFDN0YsZ0dBQWdHO1lBQ2hHLFVBQVUsRUFBRSxHQUE0QixFQUFFLENBQUMsSUFBSSxDQUFDLGFBQWEsRUFBRSxFQUFFLGFBQWE7U0FDL0UsQ0FBQztJQUNKLENBQUM7SUFFUyxhQUFhO1FBQ3JCLElBQUksQ0FBQyxPQUFPLENBQUMsZ0JBQWdCLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsRUFBRSxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUMsQ0FBQztRQUN6RSxJQUFJLENBQUMsV0FBVyxFQUFFLENBQUM7SUFDckIsQ0FBQztJQUVTLGNBQWM7UUFDdEIsSUFBSSxDQUFDLE9BQU8sQ0FBQyxnQkFBZ0IsQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSxFQUFFLElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FBQyxDQUFDO1FBQzFFLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQztJQUNyQixDQUFDO0lBRVMsZ0JBQWdCO1FBQ3hCLElBQUksQ0FBQyxPQUFPLENBQUMsZ0JBQWdCLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FBQyxDQUFDO1FBQzNELElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQztJQUNyQixDQUFDO0lBRVMsZ0JBQWdCO1FBQ3hCLElBQUksQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQzNCLE1BQU0sUUFBUSxHQUFHLElBQUksQ0FBQyxhQUFhLEVBQUUsRUFBRSxhQUFhLENBQUM7UUFDckQsTUFBTSxjQUFjLEdBQUcsUUFBUSxFQUFFLFdBQVcsSUFBSSxDQUFDLE9BQU8sTUFBTSxLQUFLLFdBQVcsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLFVBQVUsR0FBRyxHQUFHLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ2pILElBQUksQ0FBQyxPQUFPLENBQUMsZ0JBQWdCLENBQUMsV0FBVyxDQUFDLGNBQWMsRUFBRSxJQUFJLENBQUMsVUFBVSxFQUFFLEVBQUUsRUFBRSxFQUFFLElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FBQyxDQUFDO1FBQ3BHLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQztJQUNyQixDQUFDO0lBRVMsaUJBQWlCO1FBQ3pCLElBQUksQ0FBQyxVQUFVLENBQUMsTUFBTSxDQUFDLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQzFDLENBQUM7SUFFUyxtQkFBbUIsQ0FBQyxLQUFhO1FBQ3pDLElBQUksQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQzNCLElBQUksQ0FBQyxPQUFPLENBQUMsZ0JBQWdCLENBQUMsT0FBTyxDQUFDLEtBQUssRUFBRSxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUMsQ0FBQztRQUNoRSxJQUFJLENBQUMsV0FBVyxFQUFFLENBQUM7SUFDckIsQ0FBQztJQUVTLGVBQWUsQ0FBQyxLQUFhO1FBQ3JDLE9BQU8sSUFBSSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsV0FBVyxFQUFFLEdBQUcsS0FBSyxDQUFDLEdBQUcsSUFBSSxDQUFDO0lBQ3JELENBQUM7SUFFTyxXQUFXO1FBQ2pCLE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDaEMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDN0IsSUFBSSxJQUFJLENBQUMsSUFBSSxFQUFFLEtBQUssR0FBRyxFQUFFLENBQUM7WUFDeEIsSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDckIsQ0FBQztJQUNILENBQUM7SUFFUyxZQUFZLENBQUMsS0FBaUI7UUFDdEMsSUFBSSxDQUFDLElBQUksQ0FBQyxZQUFZLEVBQUUsRUFBRSxDQUFDO1lBQ3pCLE9BQU87UUFDVCxDQUFDO1FBRUQsSUFBSSxLQUFLLENBQUMsT0FBTyxJQUFJLEtBQUssQ0FBQyxPQUFPLEVBQUUsQ0FBQztZQUNuQyxLQUFLLENBQUMsY0FBYyxFQUFFLENBQUM7WUFDdkIsSUFBSSxLQUFLLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDO2dCQUNyQixJQUFJLENBQUMsYUFBYSxFQUFFLENBQUM7WUFDdkIsQ0FBQztpQkFBTSxJQUFJLEtBQUssQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUM7Z0JBQzVCLElBQUksQ0FBQyxjQUFjLEVBQUUsQ0FBQztZQUN4QixDQUFDO1FBQ0gsQ0FBQztJQUNILENBQUM7SUFHUyxzQkFBc0IsQ0FBQyxLQUFvQjtRQUNuRCxJQUFJLENBQUMsSUFBSSxDQUFDLFlBQVksRUFBRSxFQUFFLENBQUM7WUFDekIsT0FBTztRQUNULENBQUM7UUFFRCxJQUFJLEtBQUssQ0FBQyxPQUFPLElBQUksS0FBSyxDQUFDLE9BQU8sRUFBRSxDQUFDO1lBQ25DLElBQUksS0FBSyxDQUFDLEdBQUcsS0FBSyxHQUFHLElBQUksS0FBSyxDQUFDLEdBQUcsS0FBSyxHQUFHLEVBQUUsQ0FBQztnQkFDM0MsS0FBSyxDQUFDLGNBQWMsRUFBRSxDQUFDO2dCQUN2QixJQUFJLENBQUMsYUFBYSxFQUFFLENBQUM7WUFDdkIsQ0FBQztpQkFBTSxJQUFJLEtBQUssQ0FBQyxHQUFHLEtBQUssR0FBRyxJQUFJLEtBQUssQ0FBQyxHQUFHLEtBQUssR0FBRyxFQUFFLENBQUM7Z0JBQ2xELEtBQUssQ0FBQyxjQUFjLEVBQUUsQ0FBQztnQkFDdkIsSUFBSSxDQUFDLGNBQWMsRUFBRSxDQUFDO1lBQ3hCLENBQUM7aUJBQU0sSUFBSSxLQUFLLENBQUMsR0FBRyxLQUFLLEdBQUcsRUFBRSxDQUFDO2dCQUM3QixLQUFLLENBQUMsY0FBYyxFQUFFLENBQUM7Z0JBQ3ZCLElBQUksQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDO1lBQzFCLENBQUM7UUFDSCxDQUFDO0lBQ0gsQ0FBQztJQUdTLG9CQUFvQixDQUFDLEtBQWlCO1FBQzlDLElBQUksQ0FBQyxJQUFJLENBQUMsVUFBVSxFQUFFLEVBQUUsQ0FBQztZQUN2QixPQUFPO1FBQ1QsQ0FBQztRQUVELE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxXQUFXLEVBQUUsRUFBRSxhQUFhLENBQUM7UUFDakQsSUFBSSxNQUFNLElBQUksQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxNQUFjLENBQUMsRUFBRSxDQUFDO1lBQ3JELElBQUksQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQzdCLENBQUM7SUFDSCxDQUFDO0lBRVMsZ0JBQWdCLENBQUMsTUFBYyxFQUFFLElBQXVCO1FBQ2hFLE9BQU8sSUFBSSxDQUFDLEVBQUUsQ0FBQztJQUNqQixDQUFDO0lBRUQ7OztPQUdHO0lBQ0g7Ozs7O09BS0c7SUFDSDs7OztPQUlHO0lBQ08sYUFBYSxDQUFDLEtBQVksRUFBRSxJQUF1QjtRQUMzRCxLQUFLLENBQUMsZUFBZSxFQUFFLENBQUM7UUFDeEIsS0FBSyxDQUFDLGNBQWMsRUFBRSxDQUFDO1FBQ3ZCLElBQUksQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLEVBQUUsTUFBTSxFQUFFLElBQUksQ0FBQyxFQUFFLEVBQUUsSUFBSSxFQUFFLE9BQU8sRUFBRSxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQ3ZHLENBQUM7SUFFUyxnQkFBZ0IsQ0FBQyxLQUFZLEVBQUUsSUFBdUI7UUFDOUQsS0FBSyxDQUFDLGVBQWUsRUFBRSxDQUFDO1FBQ3hCLEtBQUssQ0FBQyxjQUFjLEVBQUUsQ0FBQztRQUN2QixJQUFJLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQzNCLENBQUM7SUFFUyxpQkFBaUIsQ0FBQyxLQUFZLEVBQUUsSUFBdUI7UUFDL0QsS0FBSyxDQUFDLGVBQWUsRUFBRSxDQUFDO1FBQ3hCLEtBQUssQ0FBQyxjQUFjLEVBQUUsQ0FBQztRQUN2QixJQUFJLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQzVCLENBQUM7SUFFRDs7Ozs7T0FLRztJQUNPLGdCQUFnQixDQUFDLEtBQVk7UUFDckMsS0FBSyxDQUFDLGVBQWUsRUFBRSxDQUFDO0lBQzFCLENBQUM7SUFFRCxtRkFBbUY7SUFDM0UsYUFBYSxDQUFDLElBQXVCO1FBQzNDLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxJQUFJLENBQUM7WUFDMUIsTUFBTSxFQUFFLElBQUksQ0FBQyxFQUFFO1lBQ2YsSUFBSTtZQUNKLE9BQU8sRUFBRSxDQUFDLElBQTBCLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsRUFBRSxDQUFDO1NBQzlFLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFRCwrRUFBK0U7SUFDdkUsY0FBYyxDQUFDLElBQXVCO1FBQzVDLElBQUksQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDO1lBQ3RCLE1BQU0sRUFBRSxJQUFJLENBQUMsRUFBRTtZQUNmLElBQUk7WUFDSixnRkFBZ0Y7WUFDaEYsT0FBTyxFQUFFLEdBQUcsRUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUM7U0FDN0csQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVELHFEQUFxRDtJQUMzQyxXQUFXLENBQUMsSUFBdUI7UUFDM0MsT0FBTyxDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsTUFBTSxJQUFJLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUMxQyxDQUFDO0lBRUQsd0VBQXdFO0lBQzlELFlBQVksQ0FBQyxJQUF1QjtRQUM1QyxPQUFPLElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLElBQUksSUFBSSxDQUFDLEtBQUssRUFBRSxHQUFHLElBQUksQ0FBQyxpQkFBaUIsRUFBRSxDQUFDO0lBQzNFLENBQUM7SUFFRCxvRUFBb0U7SUFDMUQsYUFBYSxDQUFDLElBQXVCO1FBQzdDLElBQUksSUFBSSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO1lBQzNCLE9BQU8sSUFBSSxDQUFDO1FBQ2QsQ0FBQztRQUVELE9BQU8sSUFBSSxDQUFDLEtBQUssRUFBRSxHQUFHLElBQUksQ0FBQyxpQkFBaUIsRUFBRSxDQUFDO0lBQ2pELENBQUM7SUFFUyxzQkFBc0IsQ0FBQyxLQUFZO1FBQzNDLElBQUksQ0FBQyxJQUFJLENBQUMsY0FBYyxFQUFFLEVBQUUsQ0FBQztZQUMzQixPQUFPO1FBQ1QsQ0FBQztRQUVELEtBQUssQ0FBQyxlQUFlLEVBQUUsQ0FBQztJQUMxQixDQUFDO0lBRVMseUJBQXlCLENBQUMsS0FBWTtRQUM5QyxJQUFJLElBQUksQ0FBQyxLQUFLLEVBQUUsS0FBSyxDQUFDLEVBQUUsQ0FBQztZQUN2QixPQUFPO1FBQ1QsQ0FBQztRQUVELEtBQUssQ0FBQyxlQUFlLEVBQUUsQ0FBQztJQUMxQixDQUFDO0lBRVMsaUJBQWlCLENBQUMsSUFBdUIsRUFBRSxLQUFrQjtRQUNyRSxJQUFJLEtBQUssRUFBRSxDQUFDO1lBQ1Ysc0VBQXNFO1lBQ3RFLGdHQUFnRztZQUNoRyxxRUFBcUU7WUFDckUsTUFBTSxNQUFNLEdBQUcsS0FBSyxDQUFDLE1BQXFCLENBQUM7WUFDM0MsSUFBSSxNQUFNLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxJQUFJLE1BQU0sQ0FBQyxPQUFPLENBQUMsMkJBQTJCLENBQUMsRUFBRSxDQUFDO2dCQUM1RSxPQUFPO1lBQ1QsQ0FBQztRQUNILENBQUM7UUFDRCxJQUFJLENBQUMsY0FBYyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUM7UUFDakMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDaEMsQ0FBQztJQUVTLGFBQWEsQ0FBQyxLQUFZLEVBQUUsSUFBdUI7UUFDM0QsS0FBSyxDQUFDLGVBQWUsRUFBRSxDQUFDO1FBQ3hCLE1BQU0sV0FBVyxHQUE2QjtZQUM1QyxNQUFNLEVBQUUsSUFBSSxDQUFDLEVBQUU7WUFDZixJQUFJO1lBQ0osT0FBTyxFQUFFLEdBQUcsRUFBRSxDQUFDLElBQUk7U0FDcEIsQ0FBQztRQUNGLElBQUksQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxDQUFDO0lBQ3ZDLENBQUM7SUFFUyxlQUFlLENBQUMsS0FBZ0I7UUFDeEMsSUFBSSxDQUFDLElBQUksQ0FBQyxrQkFBa0IsRUFBRSxJQUFJLElBQUksQ0FBQyxLQUFLLEVBQUUsR0FBRyxDQUFDLEVBQUUsQ0FBQztZQUNuRCxPQUFPO1FBQ1QsQ0FBQztRQUNELEtBQUssQ0FBQyxjQUFjLEVBQUUsQ0FBQztRQUN2QixJQUFJLEtBQUssQ0FBQyxZQUFZLEVBQUUsQ0FBQztZQUN2QixLQUFLLENBQUMsWUFBWSxDQUFDLFVBQVUsR0FBRyxNQUFNLENBQUM7UUFDekMsQ0FBQztRQUVELE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxhQUFhLEVBQUUsRUFBRSxhQUFhLENBQUM7UUFDdEQsTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLEVBQUUsQ0FBQztRQUNqQyxNQUFNLE9BQU8sR0FBRyxnQkFBZ0IsQ0FDOUIsSUFBSSxDQUFDLE9BQU8sQ0FBQyxjQUFjLEVBQWtELEVBQzdFLEtBQUssQ0FBQyxZQUFZLENBQ25CLENBQUM7UUFFRixJQUFJLENBQUMsU0FBUyxJQUFJLENBQUMsSUFBSSxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7WUFDcEMsT0FBTztRQUNULENBQUM7UUFFRCxNQUFNLFlBQVksR0FBRyxTQUFTLENBQUMsYUFBYSxDQUFDLFVBQVUsQ0FBdUIsQ0FBQztRQUMvRSxJQUFJLFlBQVksRUFBRSxDQUFDO1lBQ2pCLElBQUksQ0FBQyxZQUFZLENBQUMsU0FBUyxDQUFDLFFBQVEsQ0FBQyxjQUFjLENBQUMsRUFBRSxDQUFDO2dCQUNyRCxZQUFZLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxjQUFjLENBQUMsQ0FBQztZQUM3QyxDQUFDO1lBQ0QsSUFBSSxDQUFDLGNBQWMsR0FBRyxZQUFZLENBQUM7UUFDckMsQ0FBQztRQUVELE1BQU0sS0FBSyxHQUFHLGtCQUFrQixDQUFDLEtBQUssRUFBRSxTQUFTLEVBQUUsSUFBSSxFQUFFLE9BQU8sRUFBRSxJQUFJLENBQUMsT0FBTyxDQUFDLFlBQVksRUFBRSxJQUFJLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBRXJILElBQUksS0FBSyxFQUFFLGFBQWEsSUFBSSxLQUFLLENBQUMsZUFBZSxFQUFFLENBQUM7WUFDbEQsSUFBSSxJQUFJLENBQUMsZUFBZSxLQUFLLEtBQUssQ0FBQyxlQUFlLEVBQUUsQ0FBQztnQkFDbkQsSUFBSSxDQUFDLG1CQUFtQixFQUFFLENBQUM7Z0JBQzNCLEtBQUssQ0FBQyxlQUFlLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxjQUFjLENBQUMsQ0FBQztnQkFDcEQsSUFBSSxDQUFDLGVBQWUsR0FBRyxLQUFLLENBQUMsZUFBZSxDQUFDO1lBQy9DLENBQUM7UUFDSCxDQUFDO2FBQU0sQ0FBQztZQUNOLElBQUksQ0FBQyxtQkFBbUIsRUFBRSxDQUFDO1FBQzdCLENBQUM7UUFFRCxJQUFJLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUM1QixDQUFDO0lBRVMsZ0JBQWdCLENBQUMsS0FBZ0I7UUFDekMsSUFBSSxJQUFJLENBQUMsS0FBSyxFQUFFLEdBQUcsQ0FBQyxFQUFFLENBQUM7WUFDckIsT0FBTztRQUNULENBQUM7UUFDRCxJQUFJLEtBQUssQ0FBQyxhQUFhLEVBQUUsQ0FBQztZQUN4QixNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsYUFBYSxFQUFFLEVBQUUsYUFBYSxDQUFDO1lBQ3RELElBQUksU0FBUyxJQUFJLFNBQVMsQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLGFBQXFCLENBQUMsRUFBRSxDQUFDO2dCQUNqRSxPQUFPO1lBQ1QsQ0FBQztRQUNILENBQUM7UUFDRCxJQUFJLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUM5QixJQUFJLENBQUMsZUFBZSxFQUFFLENBQUM7SUFDekIsQ0FBQztJQUVTLFdBQVcsQ0FBQyxLQUFnQjtRQUNwQyxJQUFJLENBQUMsSUFBSSxDQUFDLGtCQUFrQixFQUFFLElBQUksSUFBSSxDQUFDLEtBQUssRUFBRSxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQ25ELE9BQU87UUFDVCxDQUFDO1FBQ0QsS0FBSyxDQUFDLGNBQWMsRUFBRSxDQUFDO1FBQ3ZCLE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQztRQUMvQixNQUFNLE9BQU8sR0FBRyxnQkFBZ0IsQ0FDOUIsSUFBSSxDQUFDLE9BQU8sQ0FBQyxjQUFjLEVBQWtELEVBQzdFLEtBQUssQ0FBQyxZQUFZLENBQ25CLENBQUM7UUFFRixJQUFJLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUM5QixJQUFJLENBQUMsZUFBZSxFQUFFLENBQUM7UUFDdkIsSUFBSSxDQUFDLE9BQU8sQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDO1FBRWhDLElBQUksQ0FBQyxLQUFLLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQztZQUN2QixPQUFPO1FBQ1QsQ0FBQztRQUVELE1BQU0sY0FBYyxHQUFHLEtBQUssQ0FBQyxhQUFhLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxjQUFjLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQztRQUM5RSxNQUFNLFFBQVEsR0FBRyxPQUFPLENBQUMsY0FBYyxDQUFDLENBQUM7UUFFekMsSUFBSSxTQUErQixDQUFDO1FBQ3BDLE1BQU0sVUFBVSxHQUFHLE9BQWtDLENBQUM7UUFDdEQsSUFBSSxPQUFPLFVBQVUsQ0FBQyxhQUFhLENBQUMsS0FBSyxVQUFVLEVBQUUsQ0FBQztZQUNwRCxNQUFNLFFBQVEsR0FBSSxVQUFVLENBQUMsYUFBYSxDQUEyRCxDQUFDLFFBQVEsQ0FBQyxDQUFDO1lBQ2hILFNBQVMsR0FBRyxRQUFRLElBQUk7Z0JBQ3RCLElBQUksRUFBRSxLQUFLLENBQUMsSUFBSTtnQkFDaEIsSUFBSSxFQUFFLEtBQUssQ0FBQyxJQUFJO2dCQUNoQixJQUFJLEVBQUUsT0FBTyxDQUFDLElBQUksSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsSUFBSSxFQUFFLE9BQU8sQ0FBQyxJQUFJLEVBQUUsS0FBSyxFQUFFLE9BQU8sQ0FBQyxLQUFLLEVBQUUsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDO2FBQ2hHLENBQUM7UUFDSixDQUFDO2FBQU0sQ0FBQztZQUNOLE1BQU0sV0FBVyxHQUFHLE9BQU8sQ0FBQyxJQUFJLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLElBQUksRUFBRSxPQUFPLENBQUMsSUFBSSxFQUFFLEtBQUssRUFBRSxPQUFPLENBQUMsS0FBSyxFQUFFLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxDQUFDO1lBQzlHLFNBQVMsR0FBRztnQkFDVixJQUFJLEVBQUUsS0FBSyxDQUFDLElBQUk7Z0JBQ2hCLElBQUksRUFBRSxLQUFLLENBQUMsSUFBSTtnQkFDaEIsSUFBSSxFQUFFLFdBQVc7YUFDbEIsQ0FBQztRQUNKLENBQUM7UUFFRCxNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLHdCQUF3QixDQUNyRCxTQUFTLEVBQ1QsS0FBSyxDQUFDLEdBQUcsRUFDVCxLQUFLLENBQUMsR0FBRyxFQUNULGNBQWMsQ0FDZixDQUFDO1FBRUYsSUFBSSxTQUFTLEVBQUUsQ0FBQztZQUNkLElBQUksQ0FBQyxjQUFjLENBQUMsR0FBRyxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUMsQ0FBQztZQUN0QyxJQUFJLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQztnQkFDcEIsSUFBSSxFQUFFLFNBQVM7Z0JBQ2YsUUFBUSxFQUFFLGNBQWM7Z0JBQ3hCLEdBQUcsRUFBRSxLQUFLLENBQUMsR0FBRztnQkFDZCxHQUFHLEVBQUUsS0FBSyxDQUFDLEdBQUc7Z0JBQ2QsSUFBSSxFQUFFLEtBQUssQ0FBQyxJQUFJO2dCQUNoQixJQUFJLEVBQUUsS0FBSyxDQUFDLElBQUk7Z0JBQ2hCLFFBQVEsRUFBRSxLQUFLO2dCQUNmLE9BQU87YUFDUixDQUFDLENBQUM7WUFDSCxNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksRUFBRSxDQUFDO1lBQ2pDLElBQUksSUFBSSxFQUFFLENBQUM7Z0JBQ1QsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUM7b0JBQ2xCLElBQUk7b0JBQ0osTUFBTSxFQUFFLFNBQVMsQ0FBQyxFQUFFO2lCQUNyQixDQUFDLENBQUM7WUFDTCxDQUFDO1FBQ0gsQ0FBQztJQUNILENBQUM7SUFFTyxtQkFBbUI7UUFDekIsSUFBSSxJQUFJLENBQUMsZUFBZSxFQUFFLENBQUM7WUFDekIsSUFBSSxDQUFDLGVBQWUsQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDLGNBQWMsQ0FBQyxDQUFDO1lBQ3RELElBQUksQ0FBQyxlQUFlLEdBQUcsU0FBUyxDQUFDO1FBQ25DLENBQUM7SUFDSCxDQUFDO0lBRU8sZUFBZTtRQUNyQixJQUFJLENBQUMsbUJBQW1CLEVBQUUsQ0FBQztRQUMzQixJQUFJLElBQUksQ0FBQyxjQUFjLElBQUksQ0FBQyxJQUFJLENBQUMsYUFBYSxFQUFFLEVBQUUsQ0FBQztZQUNqRCxJQUFJLENBQUMsY0FBYyxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUMsY0FBYyxDQUFDLENBQUM7WUFDckQsSUFBSSxDQUFDLGNBQWMsR0FBRyxTQUFTLENBQUM7UUFDbEMsQ0FBQztRQUNELE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxhQUFhLEVBQUUsRUFBRSxhQUFhLENBQUM7UUFDdEQsSUFBSSxTQUFTLElBQUksQ0FBQyxJQUFJLENBQUMsYUFBYSxFQUFFLEVBQUUsQ0FBQztZQUN2QyxTQUFTLENBQUMsZ0JBQWdCLENBQUMsdUJBQXVCLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxFQUFFLEVBQUUsRUFBRTtnQkFDakUsRUFBRSxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUMsY0FBYyxDQUFDLENBQUM7WUFDdEMsQ0FBQyxDQUFDLENBQUM7UUFDTCxDQUFDO0lBQ0gsQ0FBQzt3R0E1cEJVLCtCQUErQjs0RkFBL0IsK0JBQStCLDAyRkFxR0QsaUJBQWlCLDhVQUlJLGdCQUFnQiw2Q0M5SmhGLG81ckNBd2hCQSw2L0xEbmVhLCtCQUErQixxZ0JBTGhDLGNBQWMsb1JBQUUsc0NBQXNDLHNqQkFBRSxnQkFBZ0IsbUpBQUUsZUFBZTs7NEZBS3hGLCtCQUErQjtrQkFSM0MsU0FBUzsrQkFDRSxxQ0FBcUMsY0FDbkMsSUFBSSxXQUNQLENBQUMsY0FBYyxFQUFFLHNDQUFzQyxFQUFFLGdCQUFnQixFQUFFLGVBQWUsQ0FBQyxtQkFHbkYsdUJBQXVCLENBQUMsTUFBTTt3REFpWHJDLHNCQUFzQjtzQkFEL0IsWUFBWTt1QkFBQyxrQkFBa0IsRUFBRSxDQUFDLFFBQVEsQ0FBQztnQkFxQmxDLG9CQUFvQjtzQkFEN0IsWUFBWTt1QkFBQyxnQkFBZ0IsRUFBRSxDQUFDLFFBQVEsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIEFmdGVyVmlld0luaXQsXG4gIENoYW5nZURldGVjdGlvblN0cmF0ZWd5LFxuICBDb21wb25lbnQsXG4gIEVsZW1lbnRSZWYsXG4gIEhvc3RMaXN0ZW5lcixcbiAgT25EZXN0cm95LFxuICBUZW1wbGF0ZVJlZixcbiAgVmlld0NvbnRhaW5lclJlZixcbiAgY29tcHV0ZWQsXG4gIGVmZmVjdCxcbiAgaW5qZWN0LFxuICBpbnB1dCxcbiAgbW9kZWwsXG4gIG91dHB1dCxcbiAgc2lnbmFsLFxuICB2aWV3Q2hpbGQsXG4gIHZpZXdDaGlsZHJlbixcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBOZ1RlbXBsYXRlT3V0bGV0IH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uJztcbmltcG9ydCB7IExpYnNVaUNvbXBvbmVudHNCdXR0b25zQnV0dG9uQ29tcG9uZW50IH0gZnJvbSAnQGxpYnMtdWkvY29tcG9uZW50cy1idXR0b25zLWJ1dHRvbic7XG5pbXBvcnQgeyBHcmlkc3RlckNvbXBvbmVudCwgR3JpZHN0ZXJNb2R1bGUgfSBmcm9tICdncmlkc3RlcjE4JztcbmltcG9ydCB7IFRyYW5zbGF0ZU1vZHVsZSB9IGZyb20gJ0BuZ3gtdHJhbnNsYXRlL2NvcmUnO1xuaW1wb3J0IHsgZW1wdHlSb290Tm9kZSB9IGZyb20gJy4uL2RlZmluZXMvZ3JpZHN0ZXItY29uZmlnLmRlZmluZSc7XG5pbXBvcnQgeyBMaWJzVWlHcmlkTGF5b3V0U2VydmljZSB9IGZyb20gJy4uL2dyaWQtbGF5b3V0LnNlcnZpY2UnO1xuaW1wb3J0IHtcbiAgVF9ncmlkTGF5b3V0X2FjdGlvbkV2ZW50LFxuICBUX2dyaWRMYXlvdXRfYWRkRXZlbnQsXG4gIFRfZ3JpZExheW91dF9jaGFuZ2VFdmVudCxcbiAgVF9ncmlkTGF5b3V0X2Ryb3BFdmVudCxcbiAgVF9ncmlkTGF5b3V0X2Ryb3BHaG9zdCxcbiAgVF9ncmlkTGF5b3V0X2V4dGVybmFsRHJhZ1BheWxvYWQsXG4gIFRfZ3JpZExheW91dF9uZXdOb2RlLFxuICBUX2dyaWRMYXlvdXRfbm9kZSxcbiAgVF9ncmlkTGF5b3V0X3Rvb2xiYXJDb250ZXh0LFxuICBUX2dyaWRMYXlvdXRfem9vbVByZXNldCxcbn0gZnJvbSAnLi4vaW50ZXJmYWNlcy9ncmlkLWxheW91dC5pbnRlcmZhY2UnO1xuaW1wb3J0IHsgY2FsY3VsYXRlRHJvcEdob3N0LCBwYXJzZURyb3BQYXlsb2FkIH0gZnJvbSAnLi4vZGVmaW5lcy9jb2xsaXNpb24uZGVmaW5lJztcblxuLyoqXG4gKiBN4bq3dCBwaOG6s25nIGvDqW8gdGjhuqMuIMSQ4buHIHF1eToga2jhu5FpIGPDsyBgY2hpbGRyZW5gIHRow6wgcnXhu5l0IG7DsyBs4bqhaSBsw6AgbeG7mXQgbeG6t3QgcGjhurNuZyBu4buvYS5cbiAqXG4gKiBOxqFpIGTDuW5nIEtIw5RORyBk4buxbmcgY29tcG9uZW50IG7DoHkgdHLhu7FjIHRp4bq/cCBjaG8gdOG7q25nIGto4buRaSDigJQgY2jhu4kgxJHhurd0IE3hu5hUIHRo4bq7IOG7nyBn4buRYyB2w6AgdHJ1eeG7gW5cbiAqIGBub2RlQ29tcG9uZW50VHlwZWAgcXVhIGBMaWJzVWlHcmlkTGF5b3V0U2VydmljZS5pbml0KClgLiBUaMawIHZp4buHbiB04buxIGfhuq9uIGNvbXBvbmVudCBjaG8gbeG7jWkga2jhu5FpLlxuICovXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICdsaWJzX3VpLXNlcnZpY2VzLWdyaWRfbGF5b3V0LWNhbnZhcycsXG4gIHN0YW5kYWxvbmU6IHRydWUsXG4gIGltcG9ydHM6IFtHcmlkc3Rlck1vZHVsZSwgTGlic1VpQ29tcG9uZW50c0J1dHRvbnNCdXR0b25Db21wb25lbnQsIE5nVGVtcGxhdGVPdXRsZXQsIFRyYW5zbGF0ZU1vZHVsZV0sXG4gIHRlbXBsYXRlVXJsOiAnLi9ncmlkLWxheW91dC1jYW52YXMuY29tcG9uZW50Lmh0bWwnLFxuICBzdHlsZVVybDogJy4vZ3JpZC1sYXlvdXQtY2FudmFzLmNvbXBvbmVudC5zY3NzJyxcbiAgY2hhbmdlRGV0ZWN0aW9uOiBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneS5PblB1c2gsXG59KVxuZXhwb3J0IGNsYXNzIExpYnNVaUdyaWRMYXlvdXRDYW52YXNDb21wb25lbnQgaW1wbGVtZW50cyBBZnRlclZpZXdJbml0LCBPbkRlc3Ryb3kge1xuICAvKipcbiAgICogQGludGVybmFsIENo4buJIG3hurd0IHBo4bqzbmcgTOG7kk5HIGTDuW5nIOKAlCB0aMawIHZp4buHbiB04buxIHRydXnhu4FuIGtoaSB24bq9IHJ14buZdCBjb250YWluZXIuXG4gICAqXG4gICAqIE7GoWkgZMO5bmcgS0jDlE5HIHRydXnhu4FuOiBt4bq3dCBwaOG6s25nIGfhu5FjIMSR4buNYyBjw6J5IHThu6sgc2VydmljZSAoxJHDoyDEkcawYSB2w6BvIHF1YSBgaW5pdCgpYCksIHRydXnhu4FuIHRow6ptXG4gICAqIOG7nyDEkcOieSBsw6Aga2hhaSBoYWkgbOG6p24gY8O5bmcgbeG7mXQgdGjhu6kgKG5nxrDhu51pIGTDuW5nIGNo4buRdCAyOC8wOC8yMDI2KS5cbiAgICovXG4gIHJlYWRvbmx5IG5vZGUgPSBpbnB1dDxUX2dyaWRMYXlvdXRfbm9kZT4oKTtcbiAgLyoqIEBpbnRlcm5hbCBDaOG7iSBt4bq3dCBwaOG6s25nIEzhu5JORyBkw7luZyDigJQgdGjGsCB2aeG7h24gdOG7sSB0cnV54buBbi4gKi9cbiAgcmVhZG9ubHkgZGVwdGggPSBpbnB1dDxudW1iZXI+KDApO1xuXG4gIC8qKlxuICAgKiDhuqhuIGjhurNuIHRoYW5oIGPDtG5nIGPhu6UgbeG6t2MgxJHhu4tuaCAodGjDqm0tdsOgby10cm9uZyDCtyBn4buZcC90w6FjaCDCtyB4b8OhKSBj4bunYSBN4buMSSBraOG7kWkuXG4gICAqXG4gICAqIETDuW5nIGtoaSBz4bqjbiBwaOG6qW0gZ29tIGPDoWMgaMOgbmggxJHhu5luZyDEkcOzIHbDoG8gY2jhu5cga2jDoWMg4oCUIHZkIG3hu5l0IG7DunQg4ouuIG7hurFtIHRyb25nIGNow61uaCBu4buZaSBkdW5nXG4gICAqIGto4buRaS4g4bqobiBy4buTaSB0aMOsIGBvdXRSZW1vdmVOb2RlYCDCtyBgb3V0QWRkQmxvY2tJbnNpZGVgIMK3IGBvdXRUb2dnbGVUeXBlYCBraMO0bmcgY8OybiBuZ3Xhu5NuIHBow6F0XG4gICAqIHThu6sgdGjGsCB2aeG7h247IG7GoWkgZMO5bmcgdOG7sSBn4buNaSBgcmVtb3ZlQmxvY2tgIMK3IGBhZGRCbG9ja2AgwrcgYHRvZ2dsZVR5cGVgIGPhu6dhIHNlcnZpY2UuXG4gICAqL1xuICByZWFkb25seSBoaWRkZW5Ub29sYmFyID0gaW5wdXQ8Ym9vbGVhbiwgYm9vbGVhbiB8IHVuZGVmaW5lZD4oZmFsc2UsIHsgdHJhbnNmb3JtOiAodmFsdWUpID0+IHZhbHVlID8/IGZhbHNlIH0pO1xuXG4gIC8qKlxuICAgKiBUZW1wbGF0ZSB04buxIHbhur0gdGhhbmggY8O0bmcgY+G7pSwgdGhheSBjaG8gYuG7mSBuw7p0IG3hurdjIMSR4buLbmguXG4gICAqXG4gICAqIE5o4bqtbiBjb250ZXh0IGB7ICRpbXBsaWNpdDogbm9kZSwgaXNDb250YWluZXIsIGNhbkFkZEluc2lkZSwgY2FuVG9nZ2xlVHlwZSB9YCDEkeG7gyBuxqFpIGTDuW5nIHbhur0gxJHDum5nXG4gICAqIG7DunQgY2hvIHThu6tuZyBraOG7kWksIHLhu5NpIGfhu41pIG5nxrDhu6NjIHF1YSBgb3V0UmVtb3ZlTm9kZWAgwrcgYG91dEFkZEJsb2NrSW5zaWRlYCDCtyBgb3V0VG9nZ2xlVHlwZWBcbiAgICogYuG6sW5nIGNow61uaCBjw6FjIGjDoG0gdHJvbmcgY29udGV4dC4gVHJ1eeG7gW4gY+G6oyBgaGlkZGVuVG9vbGJhcmAgdsOgIGB0ZW1wbGF0ZVRvb2xiYXJgIHRow6xcbiAgICogYGhpZGRlblRvb2xiYXJgIHRo4bqvbmcg4oCUIGtow7RuZyB24bq9IGfDrC5cbiAgICovXG4gIHJlYWRvbmx5IHRlbXBsYXRlVG9vbGJhciA9IGlucHV0PFRlbXBsYXRlUmVmPFRfZ3JpZExheW91dF90b29sYmFyQ29udGV4dD4gfCB1bmRlZmluZWQ+KHVuZGVmaW5lZCk7XG5cbiAgLyoqXG4gICAqIELhu5EgY+G7pWMgduG7q2EgxJHhu5VpIGRvIE5Hxq/hu5xJIETDmU5HIGvDqW8gaG/hurdjIMSR4buVaSBrw61jaCB0aMaw4bubYyBraOG7kWkuXG4gICAqXG4gICAqIE7GoWkgZMO5bmcgdOG7sSBn4buNaSBgYWRkQmxvY2tgIMK3IGByZW1vdmVCbG9ja2AgwrcgYGNvbXBhY3RgIHRow6wgS0jDlE5HIGLhuq9uIOKAlCBo4buNIHbhu6thIGfhu41pIHRow6wgxJHDoyBiaeG6v3QsXG4gICAqIGLhuq9uIG5nxrDhu6NjIGzhuqFpIGzDoCB0aOG7q2EgKG5nxrDhu51pIGTDuW5nIGNo4buRdCAyOC8wOC8yMDI2KS5cbiAgICovXG4gIHJlYWRvbmx5IG91dENoYW5nZSA9IG91dHB1dDxUX2dyaWRMYXlvdXRfY2hhbmdlRXZlbnQ+KCk7XG4gIC8qKlxuICAgKiBOZ8aw4budaSBkw7luZyBi4bqlbSBuw7p0IFhPw4EgdHLDqm4gbeG7mXQga2jhu5FpLiBUaMawIHZp4buHbiBDSMavQSB4b8OhIOKAlCBn4buNaSBgZXZlbnQuY29uZmlybSgpYCDEkeG7gyB4b8OhIHRo4bqtdC5cbiAgICogQ+G6p24gaOG7j2kgdHLGsOG7m2MgdGjDrCBo4buPaSB4b25nIG3hu5tpIGfhu41pOyBraMO0bmcgY2hvIHBow6lwIHRow6wgxJHhu6tuZyBn4buNaS5cbiAgICovXG4gIHJlYWRvbmx5IG91dFJlbW92ZU5vZGUgPSBvdXRwdXQ8VF9ncmlkTGF5b3V0X2FjdGlvbkV2ZW50PigpO1xuICAvKipcbiAgICogTmfGsOG7nWkgZMO5bmcgYuG6pW0gbsO6dCBUSMOKTSB0csOqbiBt4buZdCBjb250YWluZXIuIFRoxrAgdmnhu4duIEtIw5RORyB04buxIHRow6ptIOKAlCBuw7Mga2jDtG5nIGJp4bq/dCBi4bqhbiBjw7NcbiAgICogbmjhu69uZyBsb+G6oWkga2jhu5FpIG7DoG8uIE3hu58gbWVudSBjaOG7jW4gbG/huqFpIHLhu5NpIGfhu41pIGBldmVudC5jb25maXJtKGl0ZW0pYCB24bubaSBraOG7kWkgYuG6oW4gbXXhu5FuIHRow6ptLlxuICAgKi9cbiAgcmVhZG9ubHkgb3V0QWRkQmxvY2tJbnNpZGUgPSBvdXRwdXQ8VF9ncmlkTGF5b3V0X2FkZEV2ZW50PigpO1xuICAvKiogTmfGsOG7nWkgZMO5bmcgYuG6pW0gbsO6dCBH4buYUC9Uw4FDSC4gVGjGsCB2aeG7h24gY2jGsGEgbMOgbSBnw6wg4oCUIGfhu41pIGBldmVudC5jb25maXJtKClgIMSR4buDIHRo4buxYyBoaeG7h24uICovXG4gIHJlYWRvbmx5IG91dFRvZ2dsZVR5cGUgPSBvdXRwdXQ8VF9ncmlkTGF5b3V0X2FjdGlvbkV2ZW50PigpO1xuXG4gIC8qKiBC4bqtdCB0w61uaCBuxINuZyB0aHUgcGjDs25nICh6b29tKSBjYW52YXMuIENo4buJIMOhcCBk4bulbmcgY2hvIGNhbnZhcyBn4buRYyAoZGVwdGggMCkuICovXG4gIHJlYWRvbmx5IGVuYWJsZVpvb20gPSBpbnB1dDxib29sZWFuLCBib29sZWFuIHwgdW5kZWZpbmVkPihmYWxzZSwgeyB0cmFuc2Zvcm06ICh2YWx1ZSkgPT4gdmFsdWUgPz8gZmFsc2UgfSk7XG5cbiAgLyoqIFThu7cgbOG7hyB0aHUgcGjDs25nIGhp4buHbiB04bqhaSAoaOG7lyB0cuG7oyB0d28td2F5IGJpbmRpbmcgWyh6b29tKV09XCJteVpvb21cIikuICovXG4gIHJlYWRvbmx5IHpvb20gPSBtb2RlbDxudW1iZXIgfCB1bmRlZmluZWQ+KHVuZGVmaW5lZCk7XG5cbiAgLyoqIEdp4bubaSBo4bqhbiB0aHUgcGjDs25nIHThu5FpIHRoaeG7g3UuIE3hurdjIMSR4buLbmggMC40ICg0MCUpLiAqL1xuICByZWFkb25seSB6b29tTWluID0gaW5wdXQ8bnVtYmVyPigwLjQpO1xuXG4gIC8qKiBHaeG7m2kgaOG6oW4gdGh1IHBow7NuZyB04buRaSDEkWEuIE3hurdjIMSR4buLbmggMS41ICgxNTAlKS4gKi9cbiAgcmVhZG9ubHkgem9vbU1heCA9IGlucHV0PG51bWJlcj4oMS41KTtcblxuICAvKiogQsaw4bubYyBuaOG6o3kgdGh1IHBow7NuZyBt4buXaSBs4bqnbiBi4bqlbSArLy0gaG/hurdjIGzEg24gY2h14buZdC4gTeG6t2MgxJHhu4tuaCAwLjA1ICg1JSkuICovXG4gIHJlYWRvbmx5IHpvb21TdGVwID0gaW5wdXQ8bnVtYmVyPigwLjA1KTtcblxuICAvKiogQ2hp4buBdSBy4buZbmcgY2h14bqpbiBj4bunYSBjYW52YXMgc3RhZ2UgdMOtbmggYuG6sW5nIHB4LiBN4bq3YyDEkeG7i25oIDE2NjguICovXG4gIHJlYWRvbmx5IHN0YWdlV2lkdGggPSBpbnB1dDxudW1iZXI+KDE2NjgpO1xuXG4gIC8qKiBDaGnhu4F1IGNhbyB04buRaSB0aGnhu4N1IGPhu6dhIGNhbnZhcyBzdGFnZSB0w61uaCBi4bqxbmcgcHguIE3hurdjIMSR4buLbmggOTM3LiAqL1xuICByZWFkb25seSBzdGFnZU1pbkhlaWdodCA9IGlucHV0PG51bWJlcj4oOTM3KTtcblxuICAvKiogS2jDs2EgbMawdSB04bu3IGzhu4cgdGh1IHBow7NuZyB2w6BvIGxvY2FsU3RvcmFnZS4gTeG6t2MgxJHhu4tuaCAnb2NiX2JpX2NhbnZhc196b29tJy4gKi9cbiAgcmVhZG9ubHkgc3RvcmFnZUtleSA9IGlucHV0PHN0cmluZyB8IHVuZGVmaW5lZD4oJ29jYl9iaV9jYW52YXNfem9vbScpO1xuXG4gIC8qKiBIaeG7g24gdGjhu4sgdGhhbmggZG9jayDEkWnhu4F1IGtoaeG7g24gdGh1IHBow7NuZyBu4buVaSDhu58gZ8OzYyBkxrDhu5tpIHBo4bqjaS4gTeG6t2MgxJHhu4tuaCB0cnVlLiAqL1xuICByZWFkb25seSBzaG93Wm9vbURvY2sgPSBpbnB1dDxib29sZWFuLCBib29sZWFuIHwgdW5kZWZpbmVkPih0cnVlLCB7IHRyYW5zZm9ybTogKHZhbHVlKSA9PiB2YWx1ZSA/PyB0cnVlIH0pO1xuXG4gIC8qKiBU4buxIMSR4buZbmcgduG7q2EgbcOgbiBow6xuaCBraGkgdOG6o2kgdHJhbmcgbOG6p24gxJHhuqd1IG7hur91IGtodW5nIG5ow6xuIG5o4buPIGjGoW4gc3RhZ2VXaWR0aC4gTeG6t2MgxJHhu4tuaCB0cnVlLiAqL1xuICByZWFkb25seSBhdXRvRml0T25Mb2FkID0gaW5wdXQ8Ym9vbGVhbiwgYm9vbGVhbiB8IHVuZGVmaW5lZD4odHJ1ZSwgeyB0cmFuc2Zvcm06ICh2YWx1ZSkgPT4gdmFsdWUgPz8gdHJ1ZSB9KTtcblxuICAvKiogUGjDoXQgcmEga2hpIHThu7cgbOG7hyB0aHUgcGjDs25nIHRoYXkgxJHhu5VpLiAqL1xuICByZWFkb25seSBvdXRab29tQ2hhbmdlID0gb3V0cHV0PG51bWJlcj4oKTtcblxuICAvKiogQuG6rXQgdMOtbmggbsSDbmcga8OpbyB0aOG6oyB0aOG6uyB04burIGLDqm4gbmdvw6BpIHbDoG8gY2FudmFzICht4bq3YyDEkeG7i25oIHRydWUpICovXG4gIHJlYWRvbmx5IGVuYWJsZUV4dGVybmFsRHJvcCA9IGlucHV0PGJvb2xlYW4sIGJvb2xlYW4gfCB1bmRlZmluZWQ+KHRydWUsIHsgdHJhbnNmb3JtOiAodmFsdWUpID0+IHZhbHVlID8/IHRydWUgfSk7XG5cbiAgLyoqIEx1w7RuIGhp4buDbiB0aOG7iyDEkcaw4budbmcga+G6uyBsxrDhu5tpIDI0IGPhu5l0ICovXG4gIHJlYWRvbmx5IHNob3dHcmlkTGluZXMgPSBpbnB1dDxib29sZWFuLCBib29sZWFuIHwgdW5kZWZpbmVkPihmYWxzZSwgeyB0cmFuc2Zvcm06ICh2YWx1ZSkgPT4gdmFsdWUgPz8gZmFsc2UgfSk7XG5cbiAgLyoqIE3DoyBpZCBj4bunYSBraOG7kWkgxJFhbmcgxJHGsOG7o2MgY2jhu41uICovXG4gIHJlYWRvbmx5IHNlbGVjdGVkTm9kZUlkID0gbW9kZWw8c3RyaW5nIHwgbnVsbCB8IHVuZGVmaW5lZD4odW5kZWZpbmVkKTtcblxuICAvKiogUGjDoXQgcmEga2hpIHRo4bqjIG3hu5l0IHRo4bq7IG3hu5tpIHThu6sgYsOqbiBuZ2/DoGkgdsOgbyBjYW52YXMgKi9cbiAgcmVhZG9ubHkgb3V0RHJvcE5vZGUgPSBvdXRwdXQ8VF9ncmlkTGF5b3V0X2Ryb3BFdmVudD4oKTtcblxuICAvKiogUGjDoXQgcmEga2hpIG5nxrDhu51pIGTDuW5nIGNsaWNrIGNo4buNbiBt4buZdCBraOG7kWkgKi9cbiAgcmVhZG9ubHkgb3V0U2VsZWN0Tm9kZSA9IG91dHB1dDxUX2dyaWRMYXlvdXRfbm9kZT4oKTtcblxuICAvKiogUGjDoXQgcmEga2hpIG5nxrDhu51pIGTDuW5nIGLhuqVtIG7DunQgY+G6pXUgaMOsbmggdHLDqm4gdGhhbmggY8O0bmcgY+G7pSBj4bunYSBraOG7kWkgKi9cbiAgcmVhZG9ubHkgb3V0Q29uZmlnTm9kZSA9IG91dHB1dDxUX2dyaWRMYXlvdXRfYWN0aW9uRXZlbnQ+KCk7XG5cbiAgcHJpdmF0ZSByZWFkb25seSBncmlkc3RlclJlZiA9IHZpZXdDaGlsZChHcmlkc3RlckNvbXBvbmVudCk7XG4gIHByaXZhdGUgcmVhZG9ubHkgc2Nyb2xsQXJlYVJlZiA9IHZpZXdDaGlsZDxFbGVtZW50UmVmPEhUTUxFbGVtZW50Pj4oJ3Njcm9sbEFyZWEnKTtcbiAgcHJpdmF0ZSByZWFkb25seSB6b29tRG9ja1JlZiA9IHZpZXdDaGlsZDxFbGVtZW50UmVmPEhUTUxFbGVtZW50Pj4oJ3pvb21Eb2NrJyk7XG4gIC8qKiBt4buXaSDDtCBt4buZdCBjaOG7lyBn4bqvbiByacOqbmcg4oCUIGPDuW5nIHRo4bupIHThu7EgduG7m2kgYGNoaWxkcmVuKClgICovXG4gIHByaXZhdGUgcmVhZG9ubHkgaXRlbUhvc3RzID0gdmlld0NoaWxkcmVuKCdpdGVtSG9zdCcsIHsgcmVhZDogVmlld0NvbnRhaW5lclJlZiB9KTtcblxuICAvKiogS2h1bmcgeGVtIHRyxrDhu5tjIHbhu4sgdHLDrSB0aOG6oyB0aOG6uyB04burIGLDqm4gbmdvw6BpIChzbmFwcGVkIGdob3N0IHByZXZpZXcpICovXG4gIHByb3RlY3RlZCByZWFkb25seSBkcm9wR2hvc3QgPSBzaWduYWw8VF9ncmlkTGF5b3V0X2Ryb3BHaG9zdCB8IHVuZGVmaW5lZD4odW5kZWZpbmVkKTtcblxuICBwcml2YXRlIGFjdGl2ZUhvdmVyZWRFbD86IEhUTUxFbGVtZW50O1xuICBwcml2YXRlIHJvb3RHcmlkc3RlckVsPzogSFRNTEVsZW1lbnQ7XG5cbiAgLyoqIE1lbnUgY2jhu41uIHByZXNldCB0aHUgcGjDs25nIMSRYW5nIG3hu58gaGF5IMSRw7NuZyAqL1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgaXNNZW51T3BlbiA9IHNpZ25hbDxib29sZWFuPihmYWxzZSk7XG5cbiAgLyoqIEPDoWMgbeG7kWMgdGh1IHBow7NuZyDEkeG7i25oIHPhurVuICovXG4gIHByb3RlY3RlZCByZWFkb25seSB6b29tUHJlc2V0czogQXJyYXk8VF9ncmlkTGF5b3V0X3pvb21QcmVzZXQ+ID0gW1xuICAgIHsgbGFiZWw6ICdpMThuX3pvb21fcHJlc2V0X292ZXJ2aWV3JywgdmFsdWU6IDAuNSB9LFxuICAgIHsgbGFiZWw6ICdpMThuX3pvb21fcHJlc2V0X3NtYWxsX2xhcHRvcCcsIHZhbHVlOiAwLjY3IH0sXG4gICAgeyBsYWJlbDogJ2kxOG5fem9vbV9wcmVzZXRfbGFwdG9wXzEwODBwJywgdmFsdWU6IDAuNzUgfSxcbiAgICB7IGxhYmVsOiAnaTE4bl96b29tX3ByZXNldF9zY3JlZW5fMTA4MHAnLCB2YWx1ZTogMC44NSB9LFxuICAgIHsgbGFiZWw6ICdpMThuX3pvb21fcHJlc2V0X3N0YW5kYXJkJywgdmFsdWU6IDAuOSB9LFxuICAgIHsgbGFiZWw6ICdpMThuX3pvb21fcHJlc2V0X29yaWdpbmFsX3NpemUnLCB2YWx1ZTogMSB9LFxuICAgIHsgbGFiZWw6ICdpMThuX3pvb21fcHJlc2V0X2xhcmdlX3NjcmVlbicsIHZhbHVlOiAxLjEgfSxcbiAgICB7IGxhYmVsOiAnaTE4bl96b29tX3ByZXNldF9oaWdoX2RwaV8yaycsIHZhbHVlOiAxLjI1IH0sXG4gIF07XG5cbiAgLyoqIFPDoXUgY2jhuqVtIGPhu6dhIHRheSBj4bqnbSBrw6lvIOKAlCBjaOG7iSDEkeG7gyBgQGZvcmAgZOG7sW5nIMSR4bunIDYgdGjhurssIGdpw6EgdHLhu4sga2jDtG5nIGTDuW5nIHThu5tpLiAqL1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgZHJhZ0JhckRvdHMgPSBbMCwgMSwgMiwgMywgNCwgNV07XG5cbiAgcHJpdmF0ZSByZWFkb25seSBzZXJ2aWNlID0gaW5qZWN0KExpYnNVaUdyaWRMYXlvdXRTZXJ2aWNlKTtcblxuICAvKiogQ2jhur8gxJHhu5kgdGh1IHBow7NuZyBjw7MgxJFhbmcgaG/huqF0IMSR4buZbmcgdHLDqm4gY2FudmFzIG7DoHkga2jDtG5nIChjaOG7iSByb290IGNhbnZhcyBkZXB0aCAwKSAqL1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgaXNab29tQWN0aXZlID0gY29tcHV0ZWQoKCkgPT4ge1xuICAgIHJldHVybiB0aGlzLmRlcHRoKCkgPT09IDAgJiYgKHRoaXMuZW5hYmxlWm9vbSgpIHx8IHRoaXMuc2VydmljZS5GdW5jdGlvbnNDb250cm9sLmlzWm9vbUVuYWJsZWQoKSk7XG4gIH0pO1xuXG4gIHByb3RlY3RlZCByZWFkb25seSBjdXJyZW50Wm9vbSA9IGNvbXB1dGVkKCgpID0+IHRoaXMuc2VydmljZS5ab29tKCkpO1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgem9vbVBlcmNlbnQgPSBjb21wdXRlZCgoKSA9PiBNYXRoLnJvdW5kKHRoaXMuY3VycmVudFpvb20oKSAqIDEwMCkpO1xuXG4gIC8qKlxuICAgKiBOb2RlIFRI4bqsVCBj4bunYSBt4bq3dCBwaOG6s25nIG7DoHkuXG4gICAqXG4gICAqIPCflLQgTeG6t3QgcGjhurNuZyBH4buQQyAoZGVwdGggMCkgxJHhu41jIGPDonkgdOG7qyBTRVJWSUNFLCBraMO0bmcgZMO5bmcgaW5wdXQuXG4gICAqIE7GoWkgZMO5bmcgdGjGsOG7nW5nIHPhu61hIGPDonkgVOG6oEkgQ0jhu5YgKGB0cmVlU2VydmljZS5jb21wYWN0KHRyZWUpYCkgcuG7k2kgZ+G7jWkgYHJlZnJlc2goKWAsIG7Dqm4gc2lnbmFsXG4gICAqIGByb290KClgIGPhu6dhIGjhu40gZ2nhu68gbmd1ecOqbiB0aGFtIGNoaeG6v3UgdsOgIGlucHV0IGBub2RlYCBraMO0bmcgaOG7gSDEkeG7lWkg4oCUIGBAZm9yYCBraMO0bmcgZOG7sW5nIGzhuqFpXG4gICAqIGBncmlkc3Rlci1pdGVtYCwgbMaw4bubaSDEkeG7qW5nIGltIGTDuSBk4buvIGxp4buHdSDEkcOjIGtow6FjICjEkW8gMjgvMDgvMjAyNjogYuG6pW0gXCJT4bqvcCBn4buNblwiIGtow7RuZyB0w6FjIGThu6VuZykuXG4gICAqIGByZWZyZXNoKClgIGPhu6dhIHNlcnZpY2UgdGhheSB0aGFtIGNoaeG6v3UgY8OieSwgbsOqbiDEkeG7jWMgdOG7qyDEkcOzIG3hu5tpIHRo4bqleSB0aGF5IMSR4buVaS5cbiAgICpcbiAgICogTeG6t3QgcGjhurNuZyBM4buSTkcgduG6q24gZMO5bmcgaW5wdXQ6IG7DsyBuaOG6rW4gbm9kZSBjb24gdOG7qyBt4bq3dCBwaOG6s25nIGNoYSwgduG7kW4gxJHDoyBsw6Agb2JqZWN0IG3hu5tpLlxuICAgKi9cbiAgcHJvdGVjdGVkIHJlYWRvbmx5IGN1cnJlbnROb2RlID0gY29tcHV0ZWQoKCkgPT4ge1xuICAgIHRoaXMuc2VydmljZS5WZXJzaW9uKCk7XG5cbiAgICBpZiAodGhpcy5kZXB0aCgpID4gMCkge1xuICAgICAgcmV0dXJuIHRoaXMubm9kZSgpID8/IGVtcHR5Um9vdE5vZGUoKTtcbiAgICB9XG5cbiAgICByZXR1cm4gdGhpcy5zZXJ2aWNlLlJvb3QoKSA/PyBlbXB0eVJvb3ROb2RlKCk7XG4gIH0pO1xuXG4gIHByb3RlY3RlZCByZWFkb25seSBjaGlsZHJlbiA9IGNvbXB1dGVkKCgpID0+IHRoaXMuY3VycmVudE5vZGUoKS5jaGlsZHJlbiA/PyBbXSk7XG5cbiAgLyoqXG4gICAqIELhu5FpIGPhuqNuaCBjaG8gYHRlbXBsYXRlVG9vbGJhcmAsIGThu7FuZyBz4bq1biB0aGVvIHThu6tuZyBraOG7kWkuXG4gICAqXG4gICAqIEThu7FuZyDhu58gYGNvbXB1dGVkYCBjaOG7qSBraMO0bmcgZ+G7jWkgaMOgbSB0csOqbiB0ZW1wbGF0ZTogZ+G7jWkgaMOgbSB0cm9uZyB0ZW1wbGF0ZSBjaOG6oXkgbOG6oWkgbeG7l2kgdsOybmdcbiAgICogZMOyIHRoYXkgxJHhu5VpIChydWxlIGBmZS1jb2RpbmctY29udmVudGlvbi10ZW1wbGF0ZXNgIG3hu6VjIDYpLlxuICAgKi9cbiAgcHJvdGVjdGVkIHJlYWRvbmx5IHRvb2xiYXJDb250ZXh0cyA9IGNvbXB1dGVkPEFycmF5PFRfZ3JpZExheW91dF90b29sYmFyQ29udGV4dD4+KCgpID0+XG4gICAgdGhpcy5jaGlsZHJlbigpLm1hcCgoaXRlbSkgPT4gKHtcbiAgICAgICRpbXBsaWNpdDogaXRlbSxcbiAgICAgIGlzQ29udGFpbmVyOiB0aGlzLmlzQ29udGFpbmVyKGl0ZW0pLFxuICAgICAgY2FuQWRkSW5zaWRlOiB0aGlzLmNhbkFkZEluc2lkZShpdGVtKSxcbiAgICAgIGNhblRvZ2dsZVR5cGU6IHRoaXMuY2FuVG9nZ2xlVHlwZShpdGVtKSxcbiAgICAgIHJlbW92ZTogKCkgPT4gdGhpcy5vdXRSZW1vdmVOb2RlLmVtaXQoeyBub2RlSWQ6IGl0ZW0uaWQsIG5vZGU6IGl0ZW0sIGNvbmZpcm06ICgpID0+IHRoaXMuc2VydmljZS5yZW1vdmVCbG9jayhpdGVtLmlkKSB9KSxcbiAgICAgIGFkZEluc2lkZTogKCkgPT4gdGhpcy5lbWl0QWRkSW5zaWRlKGl0ZW0pLFxuICAgICAgdG9nZ2xlVHlwZTogKCkgPT4gdGhpcy5lbWl0VG9nZ2xlVHlwZShpdGVtKSxcbiAgICB9KSlcbiAgKTtcblxuICBwcm90ZWN0ZWQgcmVhZG9ubHkgaXNOZXN0ZWRDYW52YXMgPSBjb21wdXRlZCgoKSA9PiB0aGlzLmRlcHRoKCkgPiAwKTtcblxuICAvKipcbiAgICogS2hlIG5ow6xuIHRo4bqleSBnaeG7r2EgY8OhYyBraOG7kWkgQ+G6pFAgR+G7kEMuIE3hurd0IHBo4bqzbmcgbOG7k25nIHRy4bqjIDAg4oCUIGto4buRaSBjb24gbMOgIGPDoWMgZMOybmcgY+G7p2EgY8O5bmcgbeG7mXRcbiAgICogdGjhurssIHTDoWNoIGNow7puZyByYSBsw6BtIGNow7puZyB0csO0bmcgbmjGsCB0aOG6uyBy4budaS5cbiAgICovXG4gIHByb3RlY3RlZCByZWFkb25seSB2aXN1YWxHYXAgPSBjb21wdXRlZCgoKSA9PiAodGhpcy5kZXB0aCgpID09PSAwID8gdGhpcy5zZXJ2aWNlLnZpc3VhbEdhcFB4IDogMCkpO1xuXG4gIC8qKiB0cuG6p24gbOG7k25nIGNvbnRhaW5lciDigJQga2jhu5FpIMSRw6MgY2jhuqFtIHRy4bqnbiB0aMOsIGtow7RuZyBjaG8gY2h1eeG7g24gdGjDoG5oIGNvbnRhaW5lciAqL1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgbWF4Q29udGFpbmVyRGVwdGggPSBjb21wdXRlZCgoKSA9PiB0aGlzLnNlcnZpY2UuRnVuY3Rpb25zQ29udHJvbC5tYXhDb250YWluZXJEZXB0aCgpKTtcblxuICAvKipcbiAgICogTOG7gSB0cm9uZyBj4bunYSBjb250YWluZXIsIHB4LlxuICAgKlxuICAgKiDwn5S0IMSQ4bq3dCB0csOqbiBW4buOIGNvbnRhaW5lciwga2jDtG5nIMSR4bq3dCB2w6BvIGzGsOG7m2kgY29uLiBMxrDhu5tpIGNvbiBnaeG7ryBuZ3V5w6puIGBtYXJnaW46IDJgIG5oxrAgY8WpOyBs4buBXG4gICAqIG7DoHkgY2jhu4kgY28gcnXhu5l0IGzhuqFpIGto4buPaSBiacOqbiB24buPLCBuaOG7nSDEkcOzIHRheSBj4bqnbSDEkeG7lWkga8OtY2ggdGjGsOG7m2MgY+G7p2Ega2jhu5FpIGNvbiBsdcO0biBu4bqxbSB0cm9uZyB04bqnbVxuICAgKiBjaHXhu5l0IChuZ8aw4budaSBkw7luZyBjaOG7kXQgMjgvMDgvMjAyNikuXG4gICAqL1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgY29udGFpbmVyUGFkZGluZyA9IGNvbXB1dGVkKCgpID0+IGAke3RoaXMuc2VydmljZS5GdW5jdGlvbnNDb250cm9sLmNvbnRhaW5lclBhZGRpbmcoKX1weGApO1xuXG4gIC8qKiBE4bqjaSBrw6lvIGNo4buJIGhp4buHbiDhu58gY2jhur8gxJHhu5kgc+G7rWEg4oCUIGNo4bq/IMSR4buZIHhlbSBraMO0bmcga8OpbyDEkcaw4bujYyBuw6puIGhp4buHbiBk4bqjaSBsw6AgZ8OieSBuaOG6p20uICovXG4gIHByb3RlY3RlZCByZWFkb25seSBpc0VkaXRNb2RlID0gY29tcHV0ZWQoKCkgPT4gdGhpcy5zZXJ2aWNlLklzRWRpdE1vZGUoKSk7XG5cbiAgcHJvdGVjdGVkIHJlYWRvbmx5IGdyaWRPcHRpb25zID0gY29tcHV0ZWQoKCkgPT4ge1xuICAgIC8vIMSQ4buNYyBgVmVyc2lvbmAgxJHhu4MgYGluaXQoKWAgbOG6oWkgKMSR4buVaSBjaOG6vyDEkeG7mSwgYuG6rXQvdOG6r3QgY2jhu5NuZyBraOG7kWkpIHNpbmggcmEgb3B0aW9ucyBN4buaSSDigJRcbiAgICAvLyBncmlkc3RlciBjaOG7iSDDoXAgZOG7pW5nIGPhuqV1IGjDrG5oIGtoaSB0aGFtIGNoaeG6v3UgYG9wdGlvbnNgIMSR4buVaS5cbiAgICB0aGlzLnNlcnZpY2UuVmVyc2lvbigpO1xuXG4gICAgcmV0dXJuIHRoaXMuc2VydmljZS5GdW5jdGlvbnNDb250cm9sLmdyaWRzdGVyT3B0aW9ucyh0aGlzLmRlcHRoKCksICgpID0+IHRoaXMub3V0Q2hhbmdlLmVtaXQoeyByb290OiB0aGlzLmN1cnJlbnROb2RlKCkgfSkpO1xuICB9KTtcblxuICBjb25zdHJ1Y3RvcigpIHtcbiAgICAvLyBH4bqvbiBjb21wb25lbnQgY+G7p2EgbsahaSBkw7luZyB2w6BvIHThu6tuZyDDtCwgdsOgIGfhuq9uIEzhuqBJIG3hu5dpIGtoaSBjw6J5IMSR4buVaS5cbiAgICAvLyBEw7luZyBlZmZlY3QgdsOsIGBpdGVtSG9zdHMoKWAgY2jhu4kgY8OzIGdpw6EgdHLhu4sgc2F1IGtoaSBBbmd1bGFyIGThu7FuZyB4b25nIEBmb3IuXG4gICAgZWZmZWN0KCgpID0+IHtcbiAgICAgIGNvbnN0IGhvc3RzID0gdGhpcy5pdGVtSG9zdHMoKTtcbiAgICAgIGNvbnN0IGl0ZW1zID0gdGhpcy5jaGlsZHJlbigpO1xuXG4gICAgICBpdGVtcy5mb3JFYWNoKChpdGVtLCBpKSA9PiB7XG4gICAgICAgIGNvbnN0IGhvc3QgPSBob3N0c1tpXTtcblxuICAgICAgICBpZiAoIWhvc3QpIHtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICAvLyBLaOG7kWkgY8OzIGNvbiBsw6AgQ09OVEFJTkVSOiBSVeG7mFQgbsOzIGRvIG3hurd0IHBo4bqzbmcgbOG7k25nIHbhur0uXG4gICAgICAgIC8vXG4gICAgICAgIC8vIPCflLQgTmjGsG5nIGNvbnRhaW5lciBW4bqqTiDEkcaw4bujYyBn4bqvbiBjb21wb25lbnQgbuG6v3UgbsahaSBkw7luZyBjaOG7pyDEkeG7mW5nIGtoYWkgYGdldENvbXBvbmVudE91dGxldGBcbiAgICAgICAgLy8gY2hvIGNow61uaCBraOG7kWkgxJHDsyDigJQgxJHDsyBsw6AgaMOgbmcgdGnDqnUgxJHhu4EgLyBwaOG6p24gduG7jyBj4bunYSBraOG7kWkgZ2jDqXAsIHbhur0gcXVhbmggbeG6t3QgcGjhurNuZyBs4buTbmcgY2jhu6lcbiAgICAgICAgLy8ga2jDtG5nIHRoYXkgdGjhur8gbsOzLiBUcsaw4bubYyDEkcOieSBjaOG6t24gY+G7qW5nIOG7nyDEkcOieSBuw6puIG7GoWkgZMO5bmcgcGjhuqNpIHThu7EgYGRvY3VtZW50LmNyZWF0ZUVsZW1lbnRgXG4gICAgICAgIC8vIHLhu5NpIGBpbnNlcnRCZWZvcmVgIHbDoG8gRE9NIGPhu6dhIHRoxrAgdmnhu4duLCBrw6lvIHRoZW8gbeG7mXQgbG/huqF0IGx14bqtdCBDU1MgYCFpbXBvcnRhbnRgIMSR4buDIGNo4buJbmhcbiAgICAgICAgLy8gdGjhu6kgbcOsbmggduG7q2EgY2jDqG4gdGF5LlxuICAgICAgICAvL1xuICAgICAgICAvLyBDb250YWluZXIgS0jDlE5HIGtoYWkgb3V0bGV0IHJpw6puZyB0aMOsIHbhuqtuIGLhu48gcXVhIHkgbmjGsCBjxakg4oCUIGBjb25maWcuZ2V0Q29tcG9uZW50T3V0bGV0YFxuICAgICAgICAvLyBkw7luZyBjaHVuZyBsw6AgxJHhu4MgduG6vSBO4buYSSBEVU5HIGto4buRaSBsw6EsIMSRZW0gw6FwIGNobyBjb250YWluZXIgc+G6vSDEkcOoIG3huqV0IG3hurd0IHBo4bqzbmcgbOG7k25nLlxuICAgICAgICBjb25zdCBpc0NvbnRhaW5lck5vZGUgPSAoaXRlbS5jaGlsZHJlbj8ubGVuZ3RoID8/IDApID4gMDtcblxuICAgICAgICBpZiAoaXNDb250YWluZXJOb2RlICYmICFpdGVtLmdldENvbXBvbmVudE91dGxldCkge1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuc2VydmljZS5GdW5jdGlvbnNDb250cm9sLmF0dGFjaE5vZGUoaXRlbSwgdGhpcy5kZXB0aCgpICsgMSwgaG9zdCk7XG4gICAgICB9KTtcbiAgICB9KTtcblxuICAgIC8vIMSQ4buTbmcgYuG7mSBu4bq/dSBtb2RlbCB6b29tIGLDqm4gbmdvw6BpIHRoYXkgxJHhu5VpXG4gICAgZWZmZWN0KCgpID0+IHtcbiAgICAgIGNvbnN0IHogPSB0aGlzLnpvb20oKTtcbiAgICAgIGlmICh6ICE9PSB1bmRlZmluZWQgJiYgTWF0aC5hYnMoeiAtIHRoaXMuc2VydmljZS5ab29tKCkpID4gMC4wMDEpIHtcbiAgICAgICAgdGhpcy5zZXJ2aWNlLkZ1bmN0aW9uc0NvbnRyb2wuc2V0Wm9vbSh6LCB0aGlzLnN0b3JhZ2VLZXkoKSk7XG4gICAgICB9XG4gICAgfSk7XG4gIH1cblxuICBuZ0FmdGVyVmlld0luaXQoKTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLmlzWm9vbUFjdGl2ZSgpIHx8ICF0aGlzLmF1dG9GaXRPbkxvYWQoKSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IGtleSA9IHRoaXMuc3RvcmFnZUtleSgpO1xuICAgIGxldCBoYXNTYXZlZCA9IGZhbHNlO1xuICAgIGlmIChrZXkgJiYgdHlwZW9mIGxvY2FsU3RvcmFnZSAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGhhc1NhdmVkID0gQm9vbGVhbihsb2NhbFN0b3JhZ2UuZ2V0SXRlbShrZXkpKTtcbiAgICAgIH0gY2F0Y2gge1xuICAgICAgICAvLyBpZ25vcmUgbG9jYWxTdG9yYWdlIGFjY2VzcyBlcnJvclxuICAgICAgfVxuICAgIH1cblxuICAgIGlmICghaGFzU2F2ZWQpIHtcbiAgICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICBjb25zdCBzY3JvbGxFbCA9IHRoaXMuc2Nyb2xsQXJlYVJlZigpPy5uYXRpdmVFbGVtZW50O1xuICAgICAgICBpZiAoc2Nyb2xsRWwgJiYgc2Nyb2xsRWwuY2xpZW50V2lkdGggPiAwICYmIHNjcm9sbEVsLmNsaWVudFdpZHRoIDwgdGhpcy5zdGFnZVdpZHRoKCkgKyA2NCkge1xuICAgICAgICAgIHRoaXMuaGFuZGxlckZpdFNjcmVlbigpO1xuICAgICAgICB9XG4gICAgICB9LCA1MCk7XG4gICAgfVxuICB9XG5cbiAgbmdPbkRlc3Ryb3koKTogdm9pZCB7XG4gICAgdGhpcy5jbGVhbnVwRHJhZ0dyaWQoKTtcbiAgICBmb3IgKGNvbnN0IGl0ZW0gb2YgdGhpcy5jaGlsZHJlbigpKSB7XG4gICAgICB0aGlzLnNlcnZpY2UuRnVuY3Rpb25zQ29udHJvbC5kZXRhY2hOb2RlKGl0ZW0uaWQpO1xuICAgIH1cbiAgfVxuXG4gIC8qKiBW4bq9IGzhuqFpIGzGsOG7m2kg4oCUIGfhu41pIGtoaSBraHVuZyBuZ2/DoGkgxJHhu5VpIGvDrWNoIHRoxrDhu5tjIGhv4bq3YyBjw6J5IHbhu6thIMSR4buVaSBkaeG7h24gcuG7mW5nLiAqL1xuICBnZXQgRnVuY3Rpb25Db250cm9sKCkge1xuICAgIHJldHVybiB7XG4gICAgICB2ZUxhaUx1b2k6ICgpID0+IHRoaXMuZ3JpZHN0ZXJSZWYoKT8ub3B0aW9uc0NoYW5nZWQoKSxcbiAgICAgIHpvb21JbjogKCkgPT4gdGhpcy5oYW5kbGVyWm9vbUluKCksXG4gICAgICB6b29tT3V0OiAoKSA9PiB0aGlzLmhhbmRsZXJab29tT3V0KCksXG4gICAgICByZXNldFpvb206ICgpID0+IHRoaXMuaGFuZGxlclJlc2V0Wm9vbSgpLFxuICAgICAgZml0VG9TY3JlZW46ICgpID0+IHRoaXMuaGFuZGxlckZpdFNjcmVlbigpLFxuICAgICAgc2V0Wm9vbTogKHZhbDogbnVtYmVyKSA9PiB7XG4gICAgICAgIHRoaXMuc2VydmljZS5GdW5jdGlvbnNDb250cm9sLnNldFpvb20odmFsLCB0aGlzLnN0b3JhZ2VLZXkoKSk7XG4gICAgICAgIHRoaXMuc3luY1pvb21PdXQoKTtcbiAgICAgIH0sXG4gICAgICAvLyBWw7luZyBjdeG7mW4gY+G7p2EgbeG6t3QgcGjhurNuZyDigJQgbsahaSBkw7luZyBj4bqnbiBuw7MgxJHhu4MgdOG7sSBjdeG7mW4gdOG7m2kgbeG7mXQga2jhu5FpLCBob+G6t2MgxJFvIHRv4bqhIMSR4buZIGtoaSBrw6lvLlxuICAgICAgLy8gS2jDtG5nIG3hu58g4bufIMSRw6J5IHRow6wgbsahaSBkw7luZyBwaOG6o2kgZMOyIGLhurFuZyB0w6puIGzhu5twIENTUyBu4buZaSBi4buZLCB2w6AgdMOqbiDEkcOzIMSR4buVaSBsw7pjIG7DoG8ga2jDtG5nIGhheS5cbiAgICAgIHNjcm9sbEFyZWE6ICgpOiBIVE1MRWxlbWVudCB8IHVuZGVmaW5lZCA9PiB0aGlzLnNjcm9sbEFyZWFSZWYoKT8ubmF0aXZlRWxlbWVudCxcbiAgICB9O1xuICB9XG5cbiAgcHJvdGVjdGVkIGhhbmRsZXJab29tSW4oKTogdm9pZCB7XG4gICAgdGhpcy5zZXJ2aWNlLkZ1bmN0aW9uc0NvbnRyb2wuem9vbUluKHRoaXMuem9vbVN0ZXAoKSwgdGhpcy5zdG9yYWdlS2V5KCkpO1xuICAgIHRoaXMuc3luY1pvb21PdXQoKTtcbiAgfVxuXG4gIHByb3RlY3RlZCBoYW5kbGVyWm9vbU91dCgpOiB2b2lkIHtcbiAgICB0aGlzLnNlcnZpY2UuRnVuY3Rpb25zQ29udHJvbC56b29tT3V0KHRoaXMuem9vbVN0ZXAoKSwgdGhpcy5zdG9yYWdlS2V5KCkpO1xuICAgIHRoaXMuc3luY1pvb21PdXQoKTtcbiAgfVxuXG4gIHByb3RlY3RlZCBoYW5kbGVyUmVzZXRab29tKCk6IHZvaWQge1xuICAgIHRoaXMuc2VydmljZS5GdW5jdGlvbnNDb250cm9sLnJlc2V0Wm9vbSh0aGlzLnN0b3JhZ2VLZXkoKSk7XG4gICAgdGhpcy5zeW5jWm9vbU91dCgpO1xuICB9XG5cbiAgcHJvdGVjdGVkIGhhbmRsZXJGaXRTY3JlZW4oKTogdm9pZCB7XG4gICAgdGhpcy5pc01lbnVPcGVuLnNldChmYWxzZSk7XG4gICAgY29uc3Qgc2Nyb2xsRWwgPSB0aGlzLnNjcm9sbEFyZWFSZWYoKT8ubmF0aXZlRWxlbWVudDtcbiAgICBjb25zdCBjb250YWluZXJXaWR0aCA9IHNjcm9sbEVsPy5jbGllbnRXaWR0aCB8fCAodHlwZW9mIHdpbmRvdyAhPT0gJ3VuZGVmaW5lZCcgPyB3aW5kb3cuaW5uZXJXaWR0aCAtIDMwMCA6IDEyMDApO1xuICAgIHRoaXMuc2VydmljZS5GdW5jdGlvbnNDb250cm9sLmZpdFRvU2NyZWVuKGNvbnRhaW5lcldpZHRoLCB0aGlzLnN0YWdlV2lkdGgoKSwgNDgsIHRoaXMuc3RvcmFnZUtleSgpKTtcbiAgICB0aGlzLnN5bmNab29tT3V0KCk7XG4gIH1cblxuICBwcm90ZWN0ZWQgaGFuZGxlclRvZ2dsZU1lbnUoKTogdm9pZCB7XG4gICAgdGhpcy5pc01lbnVPcGVuLnVwZGF0ZSgob3BlbikgPT4gIW9wZW4pO1xuICB9XG5cbiAgcHJvdGVjdGVkIGhhbmRsZXJTZWxlY3RQcmVzZXQodmFsdWU6IG51bWJlcik6IHZvaWQge1xuICAgIHRoaXMuaXNNZW51T3Blbi5zZXQoZmFsc2UpO1xuICAgIHRoaXMuc2VydmljZS5GdW5jdGlvbnNDb250cm9sLnNldFpvb20odmFsdWUsIHRoaXMuc3RvcmFnZUtleSgpKTtcbiAgICB0aGlzLnN5bmNab29tT3V0KCk7XG4gIH1cblxuICBwcm90ZWN0ZWQgaXNDdXJyZW50UHJlc2V0KHZhbHVlOiBudW1iZXIpOiBib29sZWFuIHtcbiAgICByZXR1cm4gTWF0aC5hYnModGhpcy5jdXJyZW50Wm9vbSgpIC0gdmFsdWUpIDwgMC4wMTtcbiAgfVxuXG4gIHByaXZhdGUgc3luY1pvb21PdXQoKTogdm9pZCB7XG4gICAgY29uc3QgdmFsID0gdGhpcy5zZXJ2aWNlLlpvb20oKTtcbiAgICB0aGlzLm91dFpvb21DaGFuZ2UuZW1pdCh2YWwpO1xuICAgIGlmICh0aGlzLnpvb20oKSAhPT0gdmFsKSB7XG4gICAgICB0aGlzLnpvb20uc2V0KHZhbCk7XG4gICAgfVxuICB9XG5cbiAgcHJvdGVjdGVkIGhhbmRsZXJXaGVlbChldmVudDogV2hlZWxFdmVudCk6IHZvaWQge1xuICAgIGlmICghdGhpcy5pc1pvb21BY3RpdmUoKSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmIChldmVudC5jdHJsS2V5IHx8IGV2ZW50Lm1ldGFLZXkpIHtcbiAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICBpZiAoZXZlbnQuZGVsdGFZIDwgMCkge1xuICAgICAgICB0aGlzLmhhbmRsZXJab29tSW4oKTtcbiAgICAgIH0gZWxzZSBpZiAoZXZlbnQuZGVsdGFZID4gMCkge1xuICAgICAgICB0aGlzLmhhbmRsZXJab29tT3V0KCk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgQEhvc3RMaXN0ZW5lcignZG9jdW1lbnQ6a2V5ZG93bicsIFsnJGV2ZW50J10pXG4gIHByb3RlY3RlZCBoYW5kbGVyRG9jdW1lbnRLZXlEb3duKGV2ZW50OiBLZXlib2FyZEV2ZW50KTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLmlzWm9vbUFjdGl2ZSgpKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKGV2ZW50LmN0cmxLZXkgfHwgZXZlbnQubWV0YUtleSkge1xuICAgICAgaWYgKGV2ZW50LmtleSA9PT0gJz0nIHx8IGV2ZW50LmtleSA9PT0gJysnKSB7XG4gICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgIHRoaXMuaGFuZGxlclpvb21JbigpO1xuICAgICAgfSBlbHNlIGlmIChldmVudC5rZXkgPT09ICctJyB8fCBldmVudC5rZXkgPT09ICdfJykge1xuICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICB0aGlzLmhhbmRsZXJab29tT3V0KCk7XG4gICAgICB9IGVsc2UgaWYgKGV2ZW50LmtleSA9PT0gJzAnKSB7XG4gICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgIHRoaXMuaGFuZGxlclJlc2V0Wm9vbSgpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIEBIb3N0TGlzdGVuZXIoJ2RvY3VtZW50OmNsaWNrJywgWyckZXZlbnQnXSlcbiAgcHJvdGVjdGVkIGhhbmRsZXJEb2N1bWVudENsaWNrKGV2ZW50OiBNb3VzZUV2ZW50KTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLmlzTWVudU9wZW4oKSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IGRvY2tFbCA9IHRoaXMuem9vbURvY2tSZWYoKT8ubmF0aXZlRWxlbWVudDtcbiAgICBpZiAoZG9ja0VsICYmICFkb2NrRWwuY29udGFpbnMoZXZlbnQudGFyZ2V0IGFzIE5vZGUpKSB7XG4gICAgICB0aGlzLmlzTWVudU9wZW4uc2V0KGZhbHNlKTtcbiAgICB9XG4gIH1cblxuICBwcm90ZWN0ZWQgaGFuZGxlclRyYWNrTm9kZShfaW5kZXg6IG51bWJlciwgaXRlbTogVF9ncmlkTGF5b3V0X25vZGUpOiBzdHJpbmcge1xuICAgIHJldHVybiBpdGVtLmlkO1xuICB9XG5cbiAgLyoqXG4gICAqIPCflLQgQ2jhurduIGBtb3VzZWRvd25gIG7hu5VpIGzDqm4gbMaw4bubaSBDSEEga2hpIHRoYW8gdMOhYyB0cm9uZyBsxrDhu5tpIGNvbi5cbiAgICogS2jDtG5nIGNo4bq3biB0aMOsIGPhuqMgaGFpIGzGsOG7m2kgY8O5bmcgbmjhuq1uIG3hu5l0IGPDuiBi4bqlbToga8OpbyBraOG7kWkgY29uIGzDoCBuaOG6pWMgbHXDtG4gY29udGFpbmVyLlxuICAgKi9cbiAgLyoqXG4gICAqIENo4bq3biBgbW91c2Vkb3duYCBj4bunYSBraOG7kWkgdHJvbmcgbMaw4bubaSBM4buSTkcgbuG7lWkgbMOqbiBsxrDhu5tpIGNoYS5cbiAgICpcbiAgICogQ2jhu4kgY2jhurduIOG7nyBsxrDhu5tpIGzhu5NuZzogbMaw4bubaSBj4bqlcCB0cmFuZyBraMO0bmcgY8OzIGNoYSBuw6BvIMSR4buDIGNo4bq3biwgdsOgIGNo4bq3biDhu58gxJHDsyBz4bq9IG514buRdCBsdcO0biB0aGFvXG4gICAqIHTDoWMgY+G7p2EgY2jDrW5oIG7Dsy5cbiAgICovXG4gIC8qKlxuICAgKiDwn5S0IEJhIGhhbmRsZXIgZMaw4bubaSDEkcOieSBQSOG6okkgYHN0b3BQcm9wYWdhdGlvbmAuXG4gICAqIE7DunQgbuG6sW0gdHJvbmcgdsO5bmcgbWFuZyBgZHJhZ0hhbmRsZUNsYXNzYCwga2jDtG5nIGNo4bq3biB0aMOsIGPDuiBi4bqlbSBi4buLIGdyaWRzdGVyIGhp4buDdSBsw6AgYuG6r3QgxJHhuqd1IGvDqW9cbiAgICogdsOgIGBkZWxheVN0YXJ0OiAxNjBgIG514buRdCBsdcO0biBgY2xpY2tgIOKAlCBuZ8aw4budaSBkw7luZyB0aOG6pXkgbmjGsCBuw7p0IGNo4bq/dC5cbiAgICovXG4gIHByb3RlY3RlZCBoYW5kbGVyUmVtb3ZlKGV2ZW50OiBFdmVudCwgbm9kZTogVF9ncmlkTGF5b3V0X25vZGUpOiB2b2lkIHtcbiAgICBldmVudC5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgIHRoaXMub3V0UmVtb3ZlTm9kZS5lbWl0KHsgbm9kZUlkOiBub2RlLmlkLCBub2RlLCBjb25maXJtOiAoKSA9PiB0aGlzLnNlcnZpY2UucmVtb3ZlQmxvY2sobm9kZS5pZCkgfSk7XG4gIH1cblxuICBwcm90ZWN0ZWQgaGFuZGxlckFkZEluc2lkZShldmVudDogRXZlbnQsIG5vZGU6IFRfZ3JpZExheW91dF9ub2RlKTogdm9pZCB7XG4gICAgZXZlbnQuc3RvcFByb3BhZ2F0aW9uKCk7XG4gICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICB0aGlzLmVtaXRBZGRJbnNpZGUobm9kZSk7XG4gIH1cblxuICBwcm90ZWN0ZWQgaGFuZGxlclRvZ2dsZVR5cGUoZXZlbnQ6IEV2ZW50LCBub2RlOiBUX2dyaWRMYXlvdXRfbm9kZSk6IHZvaWQge1xuICAgIGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgdGhpcy5lbWl0VG9nZ2xlVHlwZShub2RlKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDaOG6t24gY8O6IGLhuqVtIHRyb25nIHRoYW5oIGPDtG5nIGPhu6UgbuG7lWkgbMOqbiBncmlkc3Rlci5cbiAgICpcbiAgICogQ2jhu4kgYHN0b3BQcm9wYWdhdGlvbmAsIEtIw5RORyBgcHJldmVudERlZmF1bHRgOiBuw7p0IGLDqm4gdHJvbmcgdGVtcGxhdGUgY+G7p2EgbsahaSBkw7luZyB24bqrbiBj4bqnblxuICAgKiBow6BuaCB2aSBt4bq3YyDEkeG7i25oIGPhu6dhIG3DrG5oICht4bufIGRyb3Bkb3duLCBmb2N1c+KApikuXG4gICAqL1xuICBwcm90ZWN0ZWQgaGFuZGxlclN0b3BFdmVudChldmVudDogRXZlbnQpOiB2b2lkIHtcbiAgICBldmVudC5zdG9wUHJvcGFnYXRpb24oKTtcbiAgfVxuXG4gIC8qKiBQaMOhdCBgb3V0QWRkQmxvY2tJbnNpZGVgIOKAlCBkw7luZyBjaHVuZyBjaG8gbsO6dCBt4bq3YyDEkeG7i25oIHbDoCBgdGVtcGxhdGVUb29sYmFyYC4gKi9cbiAgcHJpdmF0ZSBlbWl0QWRkSW5zaWRlKG5vZGU6IFRfZ3JpZExheW91dF9ub2RlKTogdm9pZCB7XG4gICAgdGhpcy5vdXRBZGRCbG9ja0luc2lkZS5lbWl0KHtcbiAgICAgIG5vZGVJZDogbm9kZS5pZCxcbiAgICAgIG5vZGUsXG4gICAgICBjb25maXJtOiAoaXRlbTogVF9ncmlkTGF5b3V0X25ld05vZGUpID0+IHRoaXMuc2VydmljZS5hZGRCbG9jayhpdGVtLCBub2RlLmlkKSxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKiBQaMOhdCBgb3V0VG9nZ2xlVHlwZWAg4oCUIGTDuW5nIGNodW5nIGNobyBuw7p0IG3hurdjIMSR4buLbmggdsOgIGB0ZW1wbGF0ZVRvb2xiYXJgLiAqL1xuICBwcml2YXRlIGVtaXRUb2dnbGVUeXBlKG5vZGU6IFRfZ3JpZExheW91dF9ub2RlKTogdm9pZCB7XG4gICAgdGhpcy5vdXRUb2dnbGVUeXBlLmVtaXQoe1xuICAgICAgbm9kZUlkOiBub2RlLmlkLFxuICAgICAgbm9kZSxcbiAgICAgIC8vIEfhu5lwIGhheSB0w6FjaCBzdXkgcmEgdOG7qyBjaMOtbmgga2jhu5FpOiDEkWFuZyBsw6AgY29udGFpbmVyIHRow6wgdMOhY2gsIGtow7RuZyB0aMOsIGfhu5lwLlxuICAgICAgY29uZmlybTogKCkgPT4gKHRoaXMuaXNDb250YWluZXIobm9kZSkgPyB0aGlzLnNlcnZpY2UudG9TaW5nbGUobm9kZS5pZCkgOiB0aGlzLnNlcnZpY2UudG9Db250YWluZXIobm9kZS5pZCkpLFxuICAgIH0pO1xuICB9XG5cbiAgLyoqIGto4buRaSBuw6B5IGPDsyBwaOG6o2kgY29udGFpbmVyIGtow7RuZyAoY8OzIGto4buRaSBjb24pICovXG4gIHByb3RlY3RlZCBpc0NvbnRhaW5lcihpdGVtOiBUX2dyaWRMYXlvdXRfbm9kZSk6IGJvb2xlYW4ge1xuICAgIHJldHVybiAoaXRlbS5jaGlsZHJlbj8ubGVuZ3RoID8/IDApID4gMDtcbiAgfVxuXG4gIC8qKiBjb250YWluZXIgxJHDoyBjaOG6oW0gdHLhuqduIGzhu5NuZyB0aMOsIGtow7RuZyBjaG8gdGjDqm0ga2jhu5FpIHbDoG8gdHJvbmcgbuG7r2EgKi9cbiAgcHJvdGVjdGVkIGNhbkFkZEluc2lkZShpdGVtOiBUX2dyaWRMYXlvdXRfbm9kZSk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmlzQ29udGFpbmVyKGl0ZW0pICYmIHRoaXMuZGVwdGgoKSA8IHRoaXMubWF4Q29udGFpbmVyRGVwdGgoKTtcbiAgfVxuXG4gIC8qKiBraOG7kWkgxJHGoW4g4bufIGPhuqVwIGNoxrBhIGNo4bqhbSB0cuG6p24gbeG7m2kgxJHGsOG7o2MgY2h1eeG7g24gdGjDoG5oIGNvbnRhaW5lciAqL1xuICBwcm90ZWN0ZWQgY2FuVG9nZ2xlVHlwZShpdGVtOiBUX2dyaWRMYXlvdXRfbm9kZSk6IGJvb2xlYW4ge1xuICAgIGlmICh0aGlzLmlzQ29udGFpbmVyKGl0ZW0pKSB7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG5cbiAgICByZXR1cm4gdGhpcy5kZXB0aCgpIDwgdGhpcy5tYXhDb250YWluZXJEZXB0aCgpO1xuICB9XG5cbiAgcHJvdGVjdGVkIGhhbmRsZXJCbG9ja1BhcmVudERyYWcoZXZlbnQ6IEV2ZW50KTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLmlzTmVzdGVkQ2FudmFzKCkpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBldmVudC5zdG9wUHJvcGFnYXRpb24oKTtcbiAgfVxuXG4gIHByb3RlY3RlZCBoYW5kbGVyTW91c2VEb3duVHJvbmdMdW9pKGV2ZW50OiBFdmVudCk6IHZvaWQge1xuICAgIGlmICh0aGlzLmRlcHRoKCkgPT09IDApIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBldmVudC5zdG9wUHJvcGFnYXRpb24oKTtcbiAgfVxuXG4gIHByb3RlY3RlZCBoYW5kbGVyU2VsZWN0Tm9kZShub2RlOiBUX2dyaWRMYXlvdXRfbm9kZSwgZXZlbnQ/OiBNb3VzZUV2ZW50KTogdm9pZCB7XG4gICAgaWYgKGV2ZW50KSB7XG4gICAgICAvLyDwn5S0IENI4buIIGLhu48gcXVhIGtoaSDEkcOtY2ggdGjhu7FjIHPhu7EgbMOgIG7DunQgYuG6pW0uIFRyxrDhu5tjIMSRw6J5IGLhu48gcXVhIGPhuqMgdsO5bmdcbiAgICAgIC8vIGAubGlicy11aS1ncmlkLWxheW91dC10b29sYmFyYDogdGhhbmggbsOgeSBwaOG7pyBn4bqnbiBrw61uIGto4buRaSBuaOG7jyBuw6puIGLhuqVtIHbDoG8ga2jhu5FpIGtow7RuZyBiYW8gZ2nhu51cbiAgICAgIC8vIGNo4buNbiDEkcaw4bujYywgbsahaSBkw7luZyBwaOG6o2kgdOG6r3QgYHBvaW50ZXItZXZlbnRzYCBj4bunYSBj4bqjIHRoYW5oIMSR4buDIGPhu6l1LlxuICAgICAgY29uc3QgdGFyZ2V0ID0gZXZlbnQudGFyZ2V0IGFzIEhUTUxFbGVtZW50O1xuICAgICAgaWYgKHRhcmdldC5jbG9zZXN0KCdidXR0b24nKSB8fCB0YXJnZXQuY2xvc2VzdCgnW2RhdGEtZ3JpZC1sYXlvdXQtYWN0aW9uXScpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICB9XG4gICAgdGhpcy5zZWxlY3RlZE5vZGVJZC5zZXQobm9kZS5pZCk7XG4gICAgdGhpcy5vdXRTZWxlY3ROb2RlLmVtaXQobm9kZSk7XG4gIH1cblxuICBwcm90ZWN0ZWQgaGFuZGxlckNvbmZpZyhldmVudDogRXZlbnQsIG5vZGU6IFRfZ3JpZExheW91dF9ub2RlKTogdm9pZCB7XG4gICAgZXZlbnQuc3RvcFByb3BhZ2F0aW9uKCk7XG4gICAgY29uc3QgYWN0aW9uRXZlbnQ6IFRfZ3JpZExheW91dF9hY3Rpb25FdmVudCA9IHtcbiAgICAgIG5vZGVJZDogbm9kZS5pZCxcbiAgICAgIG5vZGUsXG4gICAgICBjb25maXJtOiAoKSA9PiB0cnVlLFxuICAgIH07XG4gICAgdGhpcy5vdXRDb25maWdOb2RlLmVtaXQoYWN0aW9uRXZlbnQpO1xuICB9XG5cbiAgcHJvdGVjdGVkIGhhbmRsZXJEcmFnT3ZlcihldmVudDogRHJhZ0V2ZW50KTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLmVuYWJsZUV4dGVybmFsRHJvcCgpIHx8IHRoaXMuZGVwdGgoKSA+IDApIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICBpZiAoZXZlbnQuZGF0YVRyYW5zZmVyKSB7XG4gICAgICBldmVudC5kYXRhVHJhbnNmZXIuZHJvcEVmZmVjdCA9ICdjb3B5JztcbiAgICB9XG5cbiAgICBjb25zdCBjb250YWluZXIgPSB0aGlzLnNjcm9sbEFyZWFSZWYoKT8ubmF0aXZlRWxlbWVudDtcbiAgICBjb25zdCByb290ID0gdGhpcy5zZXJ2aWNlLlJvb3QoKTtcbiAgICBjb25zdCBwYXlsb2FkID0gcGFyc2VEcm9wUGF5bG9hZDxUX2dyaWRMYXlvdXRfZXh0ZXJuYWxEcmFnUGF5bG9hZD4oXG4gICAgICB0aGlzLnNlcnZpY2UuZ2V0RHJhZ1BheWxvYWQoKSBhcyBUX2dyaWRMYXlvdXRfZXh0ZXJuYWxEcmFnUGF5bG9hZCB8IHVuZGVmaW5lZCxcbiAgICAgIGV2ZW50LmRhdGFUcmFuc2ZlcixcbiAgICApO1xuXG4gICAgaWYgKCFjb250YWluZXIgfHwgIXJvb3QgfHwgIXBheWxvYWQpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCByb290R3JpZHN0ZXIgPSBjb250YWluZXIucXVlcnlTZWxlY3RvcignZ3JpZHN0ZXInKSBhcyBIVE1MRWxlbWVudCB8IG51bGw7XG4gICAgaWYgKHJvb3RHcmlkc3Rlcikge1xuICAgICAgaWYgKCFyb290R3JpZHN0ZXIuY2xhc3NMaXN0LmNvbnRhaW5zKCdkaXNwbGF5LWdyaWQnKSkge1xuICAgICAgICByb290R3JpZHN0ZXIuY2xhc3NMaXN0LmFkZCgnZGlzcGxheS1ncmlkJyk7XG4gICAgICB9XG4gICAgICB0aGlzLnJvb3RHcmlkc3RlckVsID0gcm9vdEdyaWRzdGVyO1xuICAgIH1cblxuICAgIGNvbnN0IGdob3N0ID0gY2FsY3VsYXRlRHJvcEdob3N0KGV2ZW50LCBjb250YWluZXIsIHJvb3QsIHBheWxvYWQsIHRoaXMuc2VydmljZS50b3RhbENvbHVtbnMsIHRoaXMuc2VydmljZS5yb3dTdGVwUHgpO1xuXG4gICAgaWYgKGdob3N0Py5pc0luc2lkZUdyb3VwICYmIGdob3N0LmhvdmVyZWRHcmlkc3Rlcikge1xuICAgICAgaWYgKHRoaXMuYWN0aXZlSG92ZXJlZEVsICE9PSBnaG9zdC5ob3ZlcmVkR3JpZHN0ZXIpIHtcbiAgICAgICAgdGhpcy5jbGVhbnVwSG92ZXJlZEdyb3VwKCk7XG4gICAgICAgIGdob3N0LmhvdmVyZWRHcmlkc3Rlci5jbGFzc0xpc3QuYWRkKCdkaXNwbGF5LWdyaWQnKTtcbiAgICAgICAgdGhpcy5hY3RpdmVIb3ZlcmVkRWwgPSBnaG9zdC5ob3ZlcmVkR3JpZHN0ZXI7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuY2xlYW51cEhvdmVyZWRHcm91cCgpO1xuICAgIH1cblxuICAgIHRoaXMuZHJvcEdob3N0LnNldChnaG9zdCk7XG4gIH1cblxuICBwcm90ZWN0ZWQgaGFuZGxlckRyYWdMZWF2ZShldmVudDogRHJhZ0V2ZW50KTogdm9pZCB7XG4gICAgaWYgKHRoaXMuZGVwdGgoKSA+IDApIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgaWYgKGV2ZW50LnJlbGF0ZWRUYXJnZXQpIHtcbiAgICAgIGNvbnN0IGNvbnRhaW5lciA9IHRoaXMuc2Nyb2xsQXJlYVJlZigpPy5uYXRpdmVFbGVtZW50O1xuICAgICAgaWYgKGNvbnRhaW5lciAmJiBjb250YWluZXIuY29udGFpbnMoZXZlbnQucmVsYXRlZFRhcmdldCBhcyBOb2RlKSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgfVxuICAgIHRoaXMuZHJvcEdob3N0LnNldCh1bmRlZmluZWQpO1xuICAgIHRoaXMuY2xlYW51cERyYWdHcmlkKCk7XG4gIH1cblxuICBwcm90ZWN0ZWQgaGFuZGxlckRyb3AoZXZlbnQ6IERyYWdFdmVudCk6IHZvaWQge1xuICAgIGlmICghdGhpcy5lbmFibGVFeHRlcm5hbERyb3AoKSB8fCB0aGlzLmRlcHRoKCkgPiAwKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgY29uc3QgZ2hvc3QgPSB0aGlzLmRyb3BHaG9zdCgpO1xuICAgIGNvbnN0IHBheWxvYWQgPSBwYXJzZURyb3BQYXlsb2FkPFRfZ3JpZExheW91dF9leHRlcm5hbERyYWdQYXlsb2FkPihcbiAgICAgIHRoaXMuc2VydmljZS5nZXREcmFnUGF5bG9hZCgpIGFzIFRfZ3JpZExheW91dF9leHRlcm5hbERyYWdQYXlsb2FkIHwgdW5kZWZpbmVkLFxuICAgICAgZXZlbnQuZGF0YVRyYW5zZmVyLFxuICAgICk7XG5cbiAgICB0aGlzLmRyb3BHaG9zdC5zZXQodW5kZWZpbmVkKTtcbiAgICB0aGlzLmNsZWFudXBEcmFnR3JpZCgpO1xuICAgIHRoaXMuc2VydmljZS5jbGVhckRyYWdQYXlsb2FkKCk7XG5cbiAgICBpZiAoIWdob3N0IHx8ICFwYXlsb2FkKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3QgdGFyZ2V0UGFyZW50SWQgPSBnaG9zdC5pc0luc2lkZUdyb3VwID8gZ2hvc3QudGFyZ2V0UGFyZW50SWQgOiB1bmRlZmluZWQ7XG4gICAgY29uc3QgaXNJbnNpZGUgPSBCb29sZWFuKHRhcmdldFBhcmVudElkKTtcblxuICAgIGxldCBpdGVtVG9BZGQ6IFRfZ3JpZExheW91dF9uZXdOb2RlO1xuICAgIGNvbnN0IHBheWxvYWRBbnkgPSBwYXlsb2FkIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xuICAgIGlmICh0eXBlb2YgcGF5bG9hZEFueVsncmVzb2x2ZU5vZGUnXSA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgY29uc3QgcmVzb2x2ZWQgPSAocGF5bG9hZEFueVsncmVzb2x2ZU5vZGUnXSBhcyAoaW5zaWRlOiBib29sZWFuKSA9PiBUX2dyaWRMYXlvdXRfbmV3Tm9kZSB8IHVuZGVmaW5lZCkoaXNJbnNpZGUpO1xuICAgICAgaXRlbVRvQWRkID0gcmVzb2x2ZWQgPz8ge1xuICAgICAgICBjb2xzOiBnaG9zdC5jb2xzLFxuICAgICAgICByb3dzOiBnaG9zdC5yb3dzLFxuICAgICAgICBkYXRhOiBwYXlsb2FkLmRhdGEgPz8gKHBheWxvYWQudHlwZSA/IHsgdHlwZTogcGF5bG9hZC50eXBlLCB0aXRsZTogcGF5bG9hZC50aXRsZSB9IDogdW5kZWZpbmVkKSxcbiAgICAgIH07XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbnN0IG5ld05vZGVEYXRhID0gcGF5bG9hZC5kYXRhID8/IChwYXlsb2FkLnR5cGUgPyB7IHR5cGU6IHBheWxvYWQudHlwZSwgdGl0bGU6IHBheWxvYWQudGl0bGUgfSA6IHVuZGVmaW5lZCk7XG4gICAgICBpdGVtVG9BZGQgPSB7XG4gICAgICAgIGNvbHM6IGdob3N0LmNvbHMsXG4gICAgICAgIHJvd3M6IGdob3N0LnJvd3MsXG4gICAgICAgIGRhdGE6IG5ld05vZGVEYXRhLFxuICAgICAgfTtcbiAgICB9XG5cbiAgICBjb25zdCBhZGRlZE5vZGUgPSB0aGlzLnNlcnZpY2UuaW5zZXJ0QmxvY2tXaXRoQ29sbGlzaW9uKFxuICAgICAgaXRlbVRvQWRkLFxuICAgICAgZ2hvc3QuY29sLFxuICAgICAgZ2hvc3Qucm93LFxuICAgICAgdGFyZ2V0UGFyZW50SWQsXG4gICAgKTtcblxuICAgIGlmIChhZGRlZE5vZGUpIHtcbiAgICAgIHRoaXMuc2VsZWN0ZWROb2RlSWQuc2V0KGFkZGVkTm9kZS5pZCk7XG4gICAgICB0aGlzLm91dERyb3BOb2RlLmVtaXQoe1xuICAgICAgICBub2RlOiBhZGRlZE5vZGUsXG4gICAgICAgIHBhcmVudElkOiB0YXJnZXRQYXJlbnRJZCxcbiAgICAgICAgY29sOiBnaG9zdC5jb2wsXG4gICAgICAgIHJvdzogZ2hvc3Qucm93LFxuICAgICAgICBjb2xzOiBnaG9zdC5jb2xzLFxuICAgICAgICByb3dzOiBnaG9zdC5yb3dzLFxuICAgICAgICByYXdFdmVudDogZXZlbnQsXG4gICAgICAgIHBheWxvYWQsXG4gICAgICB9KTtcbiAgICAgIGNvbnN0IHJvb3QgPSB0aGlzLnNlcnZpY2UuUm9vdCgpO1xuICAgICAgaWYgKHJvb3QpIHtcbiAgICAgICAgdGhpcy5vdXRDaGFuZ2UuZW1pdCh7XG4gICAgICAgICAgcm9vdCxcbiAgICAgICAgICBub2RlSWQ6IGFkZGVkTm9kZS5pZCxcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBjbGVhbnVwSG92ZXJlZEdyb3VwKCk6IHZvaWQge1xuICAgIGlmICh0aGlzLmFjdGl2ZUhvdmVyZWRFbCkge1xuICAgICAgdGhpcy5hY3RpdmVIb3ZlcmVkRWwuY2xhc3NMaXN0LnJlbW92ZSgnZGlzcGxheS1ncmlkJyk7XG4gICAgICB0aGlzLmFjdGl2ZUhvdmVyZWRFbCA9IHVuZGVmaW5lZDtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGNsZWFudXBEcmFnR3JpZCgpOiB2b2lkIHtcbiAgICB0aGlzLmNsZWFudXBIb3ZlcmVkR3JvdXAoKTtcbiAgICBpZiAodGhpcy5yb290R3JpZHN0ZXJFbCAmJiAhdGhpcy5zaG93R3JpZExpbmVzKCkpIHtcbiAgICAgIHRoaXMucm9vdEdyaWRzdGVyRWwuY2xhc3NMaXN0LnJlbW92ZSgnZGlzcGxheS1ncmlkJyk7XG4gICAgICB0aGlzLnJvb3RHcmlkc3RlckVsID0gdW5kZWZpbmVkO1xuICAgIH1cbiAgICBjb25zdCBjb250YWluZXIgPSB0aGlzLnNjcm9sbEFyZWFSZWYoKT8ubmF0aXZlRWxlbWVudDtcbiAgICBpZiAoY29udGFpbmVyICYmICF0aGlzLnNob3dHcmlkTGluZXMoKSkge1xuICAgICAgY29udGFpbmVyLnF1ZXJ5U2VsZWN0b3JBbGwoJ2dyaWRzdGVyLmRpc3BsYXktZ3JpZCcpLmZvckVhY2goKGVsKSA9PiB7XG4gICAgICAgIGVsLmNsYXNzTGlzdC5yZW1vdmUoJ2Rpc3BsYXktZ3JpZCcpO1xuICAgICAgfSk7XG4gICAgfVxuICB9XG59XG4iLCJAaWYgKGlzWm9vbUFjdGl2ZSgpKSB7XG4gIDwhLS0gS2h1IHbhu7FjIGN14buZbiBjaOG7qWEgY2FudmFzIHN0YWdlIHRodSBwaMOzbmcgLS0+XG4gIDxkaXZcbiAgICAjc2Nyb2xsQXJlYVxuICAgIGNsYXNzPVwibGlicy11aS1ncmlkLWxheW91dC1zY3JvbGwtYXJlYSByZWxhdGl2ZSBoLWZ1bGwgbWluLWgtMCB3LWZ1bGwgbWluLXctMCBvdmVyZmxvdy1hdXRvIHAtNiBmbGV4IGp1c3RpZnktc3RhcnQgaXRlbXMtc3RhcnRcIlxuICAgIChtb3VzZWRvd24pPVwiaGFuZGxlck1vdXNlRG93blRyb25nTHVvaSgkZXZlbnQpXCJcbiAgICAod2hlZWwpPVwiaGFuZGxlcldoZWVsKCRldmVudClcIlxuICAgIChkcmFnb3Zlcik9XCJoYW5kbGVyRHJhZ092ZXIoJGV2ZW50KVwiXG4gICAgKGRyYWdsZWF2ZSk9XCJoYW5kbGVyRHJhZ0xlYXZlKCRldmVudClcIlxuICAgIChkcm9wKT1cImhhbmRsZXJEcm9wKCRldmVudClcIj5cbiAgICA8ZGl2XG4gICAgICAjY2FudmFzU3RhZ2VcbiAgICAgIGlkPVwiYmktY2FudmFzLXN0YWdlXCJcbiAgICAgIGNsYXNzPVwibGlicy11aS1ncmlkLWxheW91dC1zdGFnZSByZWxhdGl2ZSBmbGV4IGZsZXgtY29sIHRyYW5zaXRpb24tW3pvb21dIGR1cmF0aW9uLTE1MCBvcmlnaW4tdG9wIHNocmluay0wIG14LWF1dG8gYmctd2hpdGUvODAgYm9yZGVyIGJvcmRlci1zbGF0ZS0yMDAvODAgcm91bmRlZC0yeGwgc2hhZG93LXNtIHAtNFwiXG4gICAgICBbc3R5bGUuem9vbV09XCJjdXJyZW50Wm9vbSgpXCJcbiAgICAgIFtzdHlsZS53aWR0aC5weF09XCJzdGFnZVdpZHRoKClcIlxuICAgICAgW3N0eWxlLm1pbi13aWR0aC5weF09XCJzdGFnZVdpZHRoKClcIlxuICAgICAgW3N0eWxlLm1pbi1oZWlnaHQucHhdPVwic3RhZ2VNaW5IZWlnaHQoKVwiXG4gICAgICBbc3R5bGUuLS1saWJzLXVpLWdyaWQtbGF5b3V0LXZpc3VhbC1nYXAucHhdPVwidmlzdWFsR2FwKClcIj5cbiAgICAgIDwhLS0gU25hcHBlZCBEcm9wIEdob3N0IFByZXZpZXcgLS0+XG4gICAgICBAaWYgKGRyb3BHaG9zdCgpOyBhcyBnaG9zdCkge1xuICAgICAgICA8ZGl2XG4gICAgICAgICAgY2xhc3M9XCJwb2ludGVyLWV2ZW50cy1ub25lIGFic29sdXRlIHotMzAgZmxleCBmbGV4LWNvbCBpdGVtcy1jZW50ZXIganVzdGlmeS1jZW50ZXIgb3ZlcmZsb3ctaGlkZGVuIHJvdW5kZWQtbGcgYm9yZGVyLTIgYm9yZGVyLWRhc2hlZCBib3JkZXItYmx1ZS01MDAgYmctYmx1ZS01MDAvMTUgcC0xIHNoYWRvdy1zbSB0cmFuc2l0aW9uLWFsbCBkdXJhdGlvbi03NSBlYXNlLW91dCBiYWNrZHJvcC1ibHVyLVswLjVweF0gc2VsZWN0LW5vbmVcIlxuICAgICAgICAgIFtzdHlsZS5sZWZ0LnB4XT1cImdob3N0LnBpeGVsTGVmdFwiXG4gICAgICAgICAgW3N0eWxlLnRvcC5weF09XCJnaG9zdC5waXhlbFRvcFwiXG4gICAgICAgICAgW3N0eWxlLndpZHRoLnB4XT1cImdob3N0LnBpeGVsV2lkdGhcIlxuICAgICAgICAgIFtzdHlsZS5oZWlnaHQucHhdPVwiZ2hvc3QucGl4ZWxIZWlnaHRcIj5cbiAgICAgICAgICA8ZGl2IGNsYXNzPVwiaW5saW5lLWZsZXggbWF4LXctWzk1JV0gaXRlbXMtY2VudGVyIGdhcC0xIHRydW5jYXRlIHJvdW5kZWQtbWQgYmctYmx1ZS02MDAgcHgtMiBweS0wLjUgdGV4dC1bMTFweF0gZm9udC1zZW1pYm9sZCB0ZXh0LXdoaXRlIHNoYWRvdy14c1wiPlxuICAgICAgICAgICAgQGlmIChnaG9zdC5jYXJkSWNvbkNsYXNzKSB7XG4gICAgICAgICAgICAgIDxpIFtjbGFzc109XCJnaG9zdC5jYXJkSWNvbkNsYXNzICsgJyB0ZXh0LXhzJ1wiPjwvaT5cbiAgICAgICAgICAgIH0gQGVsc2UgaWYgKGdob3N0LmNhcmRJY29uVGV4dCkge1xuICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cInRleHQtWzEwcHhdIGZvbnQtYm9sZFwiPnt7IGdob3N0LmNhcmRJY29uVGV4dCB9fTwvc3Bhbj5cbiAgICAgICAgICAgIH0gQGVsc2Uge1xuICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cInRleHQteHMgZm9udC1ib2xkXCI+e3sgZ2hvc3QuaXNJbnNpZGVHcm91cCA/ICfihrMnIDogJysnIH19PC9zcGFuPlxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJ0cnVuY2F0ZVwiPnt7IGdob3N0LmNhcmRUaXRsZSB9fTwvc3Bhbj5cbiAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwidGV4dC1bOXB4XSBmb250LW1vbm8gb3BhY2l0eS03NVwiPih7eyBnaG9zdC5jb2xzIH19Yyk8L3NwYW4+XG4gICAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgICBAaWYgKGdob3N0LnBpeGVsSGVpZ2h0ID49IDgwKSB7XG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwibXQtMSBmbGV4IG1heC13LVs5NSVdIGl0ZW1zLWNlbnRlciBnYXAtMS41IHRydW5jYXRlIHJvdW5kZWQgYm9yZGVyIGJvcmRlci1ibHVlLTEwMCBiZy13aGl0ZS85NSBweC0yIHB5LTAuNSB0ZXh0LVsxMHB4XSBmb250LW1lZGl1bSB0ZXh0LWJsdWUtNzAwIHNoYWRvdy14c1wiPlxuICAgICAgICAgICAgICBAaWYgKGdob3N0LmlzSW5zaWRlR3JvdXApIHtcbiAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cInRydW5jYXRlIGZvbnQtYm9sZCB0ZXh0LWJsdWUtOTAwXCI+4oazIHt7IGdob3N0Lmdyb3VwVGl0bGUgfX08L3NwYW4+XG4gICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJ0ZXh0LWJsdWUtMzAwXCI+4oCiPC9zcGFuPlxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIDxzcGFuPkPhu5l0IHt7IGdob3N0LmNvbCArIDEgfX0te3sgZ2hvc3QuY29sICsgZ2hvc3QuY29scyB9fTwvc3Bhbj5cbiAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgIH1cbiAgICAgICAgPC9kaXY+XG4gICAgICB9XG4gICAgICA8Z3JpZHN0ZXIgY2xhc3M9XCJoLWZ1bGwgdy1mdWxsXCIgW2NsYXNzLmRpc3BsYXktZ3JpZF09XCJzaG93R3JpZExpbmVzKClcIiBbb3B0aW9uc109XCJncmlkT3B0aW9ucygpXCI+XG4gICAgICAgICAgQGZvciAoaXRlbSBvZiBjaGlsZHJlbigpOyB0cmFjayBpdGVtLmlkOyBsZXQgaXRlbUluZGV4ID0gJGluZGV4KSB7XG4gICAgPCEtLSDwn5S0IENo4bq3biBgbW91c2Vkb3duYCB04bqhaSDEkMOCWSBjaG8gbMaw4bubaSBs4buTbmcg4oCUIEPhuqRNIGLhu48gdsOgIEPhuqRNIGNodXnhu4NuIHNhbmcgY2jhu5cga2jDoWMuXG4gICAgICAgICBgaWdub3JlQ29udGVudENsYXNzYCBt4buZdCBtw6xuaCBLSMOUTkcgxJHhu6c6IGBkZWxheVN0YXJ0OiAxNjBgIGzDoG0gTeG7lkkgbMaw4bubaSBsw6puIGzhu4tjaFxuICAgICAgICAgYGRyYWdTdGFydGAgYuG6sW5nIGBzZXRUaW1lb3V0YCBuZ2F5IHThuqFpIGBtb3VzZWRvd25gLCBjw7JuIGBzdG9wUHJvcGFnYXRpb25gIG3DoCBsaWIgZ+G7jWkgYsOqblxuICAgICAgICAgdHJvbmcgYGRyYWdTdGFydGAgY2jhuqF5IHNhdSAxNjBtcyBuw6puIHF1w6EgbXXhu5luIOKAlCBsxrDhu5tpIENIQSDEkcOjIGvhu4twIG5o4bqtbiAoxJFvIDI4LzA4LzIwMjY6IGvDqW9cbiAgICAgICAgIGThuqNpIGto4buRaSBjb24sIGNodeG7l2kgY2xhc3MgZHV54buHdCBsw6puIMSQw5pORyBtw6AgY29udGFpbmVyIHbhuqtuIG5o4bqjeSAwLDAg4oaSIDAsMSkuXG4gICAgICAgICBH4bqvbiDhu58gYGdyaWRzdGVyLWl0ZW1gIGzDoCDEkcO6bmcgYmnDqm46IGzGsOG7m2kgY29uIG5naGUgdHLDqm4gY2jDrW5oIHBo4bqnbiB04butIG7DoHkgbsOqbiDEkcOjIG5o4bqtbiB4b25nLFxuICAgICAgICAgbMaw4bubaSBjaGEg4bufIG5nb8OgaSBi4buLIGNo4bq3bi4gLS0+XG4gICAgPGdyaWRzdGVyLWl0ZW1cbiAgICAgIFtpdGVtXT1cIml0ZW1cIlxuICAgICAgW2NsYXNzLmxpYnMtdWktZ3JpZC1sYXlvdXQtc2VsZWN0ZWRdPVwic2VsZWN0ZWROb2RlSWQoKSA9PT0gaXRlbS5pZFwiXG4gICAgICAoY2xpY2spPVwiaGFuZGxlclNlbGVjdE5vZGUoaXRlbSwgJGV2ZW50KVwiXG4gICAgICAobW91c2Vkb3duKT1cImhhbmRsZXJCbG9ja1BhcmVudERyYWcoJGV2ZW50KVwiPlxuICAgICAgPCEtLSDwn5S0IFbhu48gbsOgeSBtYW5nIGBkcmFnSGFuZGxlQ2xhc3NgIOKAlCBD4bqkTSBi4buPLlxuICAgICAgICAgICBgaWdub3JlQ29udGVudDogdHJ1ZWAgYuG6r3QgZ3JpZHN0ZXIgQ0jhu4ggY2hvIGvDqW8ga2hpIGNo4buXIGLhuqVtIG7hurFtIGTGsOG7m2kgbeG7mXQgcGjhuqduIHThu60gY8OzXG4gICAgICAgICAgIGBkcmFnSGFuZGxlQ2xhc3NgLiBLaMO0bmcgY8OzIHbhu48gbsOgeSB0aMOsIGNvbXBvbmVudCBj4bunYSBuxqFpIGTDuW5nICh0aMawIHZp4buHbiBraMO0bmcga2nhu4NtIHNvw6F0XG4gICAgICAgICAgIMSRxrDhu6NjIGNsYXNzIGPhu6dhIG7Dsykgc+G6vSBraMO0bmcgY8OzIHRheSBj4bqnbSBuw6BvLCB2w6AgS0jDlE5HIGto4buRaSBuw6BvIGvDqW8gxJHGsOG7o2Mg4oCUIMSRbyAyOC8wOC8yMDI2OlxuICAgICAgICAgICBrw6lvIDMyMHB4LCB0b+G6oSDEkeG7mSBraOG7kWkgZ2nhu68gbmd1ecOqbiB4PTMseT0wLlxuICAgICAgICAgICBUw6puIGNsYXNzIHRoZW8gY+G6pXA6IGzGsOG7m2kgdHJhbmcgdsOgIGzGsOG7m2kgbOG7k25nIGTDuW5nIGhhaSB0w6puIEtIw4FDIG5oYXUsIG7hur91IGtow7RuZyBsxrDhu5tpIGNoYVxuICAgICAgICAgICBjxaluZyBuaOG6rW4gcmEgdGF5IGPhuqdtIGPhu6dhIGto4buRaSBjb24gdsOgIG5o4bqlYyBsdcO0biBjb250YWluZXIuIC0tPlxuICAgICAgPCEtLSDwn5S0IFbhu48gS0jDlE5HIG1hbmcgYGRyYWdIYW5kbGVDbGFzc2Ag4oCUIEPhuqRNIHRow6ptIGzhuqFpLlxuICAgICAgICAgICBLw6lvIGNo4buJIMSRxrDhu6NjIHBow6lwIGLhuq90IMSR4bqndSB04burIEThuqJJIFhBTkggKG5nxrDhu51pIGTDuW5nIGNo4buRdCAyOC8wOC8yMDI2OiBcInBo4bqjaSBob3ZlciB2w6BvIHbDuW5nXG4gICAgICAgICAgIG3DoHUgeGFuaCB0aMOsIG3hu5tpIGvDqW8gdGjhuqMgxJHGsOG7o2MgY2hvIMSR4buTbmcgbmjhuqV0XCIpLiBDaG8gY+G6oyB24buPIGzDoG0gdGF5IGPhuqdtIHRow6wgYuG6pW0gxJHDonUgY8WpbmdcbiAgICAgICAgICAga8OpbywgdsOgIGto4buRaSBjb24gbuG6sW0gdHJvbmcgY29udGFpbmVyIHPhur0gbmjhuqVjIGx1w7RuIGNvbnRhaW5lciB2w6wgbMaw4bubaSBjaGEgZHV54buHdCBsw6puIGfhurdwXG4gICAgICAgICAgIHRheSBj4bqnbSBj4bunYSB24buPIGNvbnRhaW5lciB0csaw4bubYy5cbiAgICAgICAgICAgVuG7jyBraOG7kWkgY29uIHbhuqtuIGdp4buvIGNsYXNzIENI4bq2TiDEkeG7gyBsxrDhu5tpIGNoYSBk4burbmcgxJHDum5nIOG7nyBiacOqbi4gLS0+XG4gICAgICA8ZGl2XG4gICAgICAgIGNsYXNzPVwibGlicy11aS1ncmlkLWxheW91dC1ibG9jay1zaGVsbCBncm91cCByZWxhdGl2ZSBoLWZ1bGwgdy1mdWxsIG1pbi13LTBcIlxuICAgICAgICBbYXR0ci5kYXRhLW5vZGUtaWRdPVwiaXRlbS5pZFwiXG4gICAgICAgIFtjbGFzcy5saWJzLXVpLWdyaWQtbGF5b3V0LWJsb2NrLXBhcmVudC1kcmFnXT1cImlzTmVzdGVkQ2FudmFzKClcIj5cbiAgICAgICAgPCEtLSBE4bqjaSBrw6lvOiBoaeG7h24ga2hpIHLDqiBjaHXhu5l0IHbDoG8ga2jhu5FpLCBiYSBjaOG6pW0gbMOgIGThuqV1IGhp4buHdSBrw6lvIHF1ZW4gdGh14buZYy5cbiAgICAgICAgICAgICBOZ8aw4budaSBkw7luZyBj4bqnbiBt4buZdCBjaOG7lyBiw6FtIFLDlSBSw4BORyB0aGF5IHbDrCDEkW/DoW4geGVtIGLhuqVtIMSRw6J1IHRow6wga8OpbyDEkcaw4bujY1xuICAgICAgICAgICAgIChjaOG7kXQgMjgvMDgvMjAyNiwgdGhlbyDEkcO6bmcgZOG6o2kgxJFhbmcgZMO5bmcg4bufIG3DoG4gQ3VzdG9tZXIgMzYwIGPhu6dhIG1vYmlvLXdlYikuIC0tPlxuICAgICAgICBAaWYgKGlzRWRpdE1vZGUoKSkge1xuICAgICAgICAgIDwhLS0g8J+UtCBE4bqjaSBQSOG6okkgbWFuZyB0YXkgY+G6p20gxJDDmk5HIEPhuqRQIGPhu6dhIG7Dsy4gROG6o2kgbmjhuq1uIGNodeG7mXQgKGBwb2ludGVyLWV2ZW50czogYXV0b2ApLFxuICAgICAgICAgICAgICAgbsOqbiBu4bq/dSBraMO0bmcgbWFuZyB0YXkgY+G6p20gdGjDrCBgY2hlY2tEcmFnSGFuZGxlQ2xhc3NgIGR1eeG7h3QgbMOqbiBn4bq3cCB0YXkgY+G6p20gY+G7p2FcbiAgICAgICAgICAgICAgIGNvbnRhaW5lciB2w6AgbmjhuqVjIGNvbnRhaW5lciB0aGF5IHbDrCBraOG7kWkgY29uICjEkW8gMjgvMDgvMjAyNjoga8OpbyBk4bqjaSBraOG7kWkgY29uLFxuICAgICAgICAgICAgICAgY29udGFpbmVyIG5o4bqjeSAwLDAg4oaSIDAsMSBjw7JuIGto4buRaSBjb24gxJHhu6luZyBpbSkuXG4gICAgICAgICAgICAgICDwn5S0IEThuqNpIENI4buIIG1hbmcgdGF5IGPhuqdtLCBD4bqkTSBtYW5nIHRow6ptIGNsYXNzIGNo4bq3bjogYGNoZWNrRHJhZ0hhbmRsZUNsYXNzYCB4w6l0IGhhaVxuICAgICAgICAgICAgICAgY2xhc3MgxJHDsyB0csOqbiBDw5lORyBt4buZdCBub2RlIG7Dqm4gxJHhu4MgY2h1bmcgbMOgIGvDqW8gaOG7j25nICjEkW8gMjgvMDgvMjAyNjogYuG6pW0gZOG6o2kga2jhu5FpXG4gICAgICAgICAgICAgICBjb24ga8OpbyAxNDBweCwga2jhu5FpIMSR4bupbmcgaW0pLiBWaeG7h2MgY2jhurduIGzGsOG7m2kgY2hhIGRvIFbhu44gS0jhu5BJIGxvLiAtLT5cbiAgICAgICAgICA8ZGl2XG4gICAgICAgICAgICBjbGFzcz1cImxpYnMtdWktZ3JpZC1sYXlvdXQtZHJhZy1iYXJcIlxuICAgICAgICAgICAgW2NsYXNzLmxpYnMtdWktZ3JpZC1sYXlvdXQtZHJhZy1iYXItY2hpbGRdPVwiaXNOZXN0ZWRDYW52YXMoKVwiXG4gICAgICAgICAgICBbY2xhc3MubGlicy11aS1ncmlkLWxheW91dC1kcmFnLWhhbmRsZV09XCIhaXNOZXN0ZWRDYW52YXMoKVwiXG4gICAgICAgICAgICBbY2xhc3MubGlicy11aS1ncmlkLWxheW91dC1kcmFnLWhhbmRsZS1jaGlsZF09XCJpc05lc3RlZENhbnZhcygpXCI+XG4gICAgICAgICAgICA8c3BhbiBjbGFzcz1cImxpYnMtdWktZ3JpZC1sYXlvdXQtZHJhZy1iYXItZG90c1wiPlxuICAgICAgICAgICAgICBAZm9yIChkb3Qgb2YgZHJhZ0JhckRvdHM7IHRyYWNrIGRvdCkge1xuICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwibGlicy11aS1ncmlkLWxheW91dC1kcmFnLWJhci1kb3RcIj48L3NwYW4+XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIDwvc3Bhbj5cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgfVxuXG4gICAgICAgIDwhLS0gS2h1bmcgY2jhu6lhIGNvbXBvbmVudCBj4bunYSBuxqFpIGTDuW5nLlxuICAgICAgICAgICAgIPCflLQgUEjhuqJJIGPDsyBraHVuZyB0aOG6rXQgKGtow7RuZyBwaOG6o2kgYG5nLWNvbnRhaW5lcmAgdHLhu5FuZyk6IG7DsyBsbyBo4buZIG7GoWkgZMO5bmcgcGjhuqduIGzhuqVwIMSR4bqneVxuICAgICAgICAgICAgIMO0IHbDoCB2aeG7gW4gYsOhbyBjaOG6vyDEkeG7mSBz4butYS4gS2jDtG5nIGPDsyBraHVuZyB0aMOsIG3hu5dpIGNvbXBvbmVudCBu4buZaSBkdW5nIGzhuqFpIHBo4bqjaSB04buxIHZp4bq/dFxuICAgICAgICAgICAgIGA6aG9zdCB7IHdpZHRoL2hlaWdodDogMTAwJSB9YCArIHZp4buBbiDEkeG7qXQg4oCUIMSRw7MgbMOgIHZp4buHYyBj4bunYSB0aMawIHZp4buHbiwga2jDtG5nIHBo4bqjaSBj4bunYVxuICAgICAgICAgICAgIG5nxrDhu51pIGTDuW5nIChuZ8aw4budaSBkw7luZyBjaOG7kXQgMjgvMDgvMjAyNikuXG4gICAgICAgICAgICAgTeG7l2kga2jhu5FpIG3hu5l0IFZpZXdDb250YWluZXJSZWYgcmnDqm5nIG7Dqm4gY29tcG9uZW50IG7hurFtIMSRw7puZyDDtCBj4bunYSBuw7MuIC0tPlxuICAgICAgICA8ZGl2XG4gICAgICAgICAgY2xhc3M9XCJsaWJzLXVpLWdyaWQtbGF5b3V0LWNvbnRlbnQtZnJhbWVcIlxuICAgICAgICAgIFtjbGFzcy5saWJzLXVpLWdyaWQtbGF5b3V0LWNvbnRlbnQtZnJhbWUtZWRpdF09XCJpc0VkaXRNb2RlKCkgJiYgIWlzQ29udGFpbmVyKGl0ZW0pXCJcbiAgICAgICAgICBbY2xhc3MubGlicy11aS1ncmlkLWxheW91dC1jb250ZW50LWZyYW1lLWVtcHR5XT1cImlzQ29udGFpbmVyKGl0ZW0pICYmICFpdGVtLmdldENvbXBvbmVudE91dGxldFwiPlxuICAgICAgICAgIDxuZy1jb250YWluZXIgI2l0ZW1Ib3N0IC8+XG4gICAgICAgIDwvZGl2PlxuXG4gICAgICAgIDwhLS0gROG6pXUgaGnhu4d1IENPTlRBSU5FUjogbmjDo24gZ8OzYyB0csOqbi1waOG6o2kgKyB2aeG7gW4gxJHhu6l0IGJhbyBydeG7mXQuIEtow7RuZyBjw7MgZOG6pXUgaGnhu4d1IHRow6xcbiAgICAgICAgICAgICBuZ8aw4budaSBkw7luZyBraMO0bmcgYmnhur90IGto4buRaSBuw6BvIGNo4bupYSDEkcaw4bujYyBraOG7kWkga2jDoWMgKGNo4buRdCAyOC8wOC8yMDI2LCB0aGVvIMSRw7puZyBjw6FjaFxuICAgICAgICAgICAgIG3DoG4gQ3VzdG9tZXIgMzYwIGPhu6dhIG1vYmlvLXdlYiDEkWFuZyBsw6BtKS4gLS0+XG4gICAgICAgIEBpZiAoaXNFZGl0TW9kZSgpICYmIGlzQ29udGFpbmVyKGl0ZW0pKSB7XG4gICAgICAgICAgPGRpdiBjbGFzcz1cImxpYnMtdWktZ3JpZC1sYXlvdXQtY29udGFpbmVyLWxhYmVsXCI+e3sgJ2kxOG5fY29udGFpbmVyX2Jsb2NrJyB8IHRyYW5zbGF0ZSB9fTwvZGl2PlxuICAgICAgICAgIDxkaXYgY2xhc3M9XCJsaWJzLXVpLWdyaWQtbGF5b3V0LWNvbnRhaW5lci1ib3JkZXJcIj48L2Rpdj5cbiAgICAgICAgfVxuXG4gICAgICAgIDwhLS0gVGhhbmggY8O0bmcgY+G7pTogaGnhu4duIGtoaSByw6ogY2h14buZdCB2w6BvIGto4buRaS5cbiAgICAgICAgICAgICDwn5S0IETDuW5nIGBsaWJzX3VpLWNvbXBvbmVudHMtYnV0dG9ucy1idXR0b25gIOKAlCBD4bqkTSB04buxIGThu7FuZyB0aOG6uyBgPGJ1dHRvbj5gLlxuICAgICAgICAgICAgIENvbXBvbmVudCBuw6B5IMSRw6MgY8OzIHPhurVuIGtp4buDdSBuw7p0LCBj4buhIG7DunQgdsOgIGJvbmcgYsOzbmcgY2jDuiB0aMOtY2ggdGhlbyDEkcO6bmcgYuG7mSBnaWFvIGRp4buHblxuICAgICAgICAgICAgIGPhu6dhIHPhuqNuIHBo4bqpbTsgdOG7sSBk4buxbmcgbMOgIG3hu5dpIG7GoWkgbeG7mXQga2nhu4N1IHbDoCBt4bqldCBsdcO0biB0b29sdGlwLiAtLT5cbiAgICAgICAgQGlmIChpc0VkaXRNb2RlKCkgJiYgIWhpZGRlblRvb2xiYXIoKSkge1xuICAgICAgICAgIEBpZiAodGVtcGxhdGVUb29sYmFyKCkpIHtcbiAgICAgICAgICAgIDwhLS0gTsahaSBkw7luZyB04buxIHbhur0gdGhhbmggY8O0bmcgY+G7pTogbmjhuq1uIGto4buRaSArIGPDoWMgaMOgbSBwaMOhdCBldmVudCBxdWEgY29udGV4dC5cblxuICAgICAgICAgICAgICAgICDwn5S0IEto4buRaSBi4buNYyB04buxIGNo4bq3biBgbW91c2Vkb3duYC9gY2xpY2tgIG7hu5VpIGzDqm4gZ3JpZHN0ZXIuIFRoYW5oIGPDtG5nIGPhu6UgbuG6sW0gdHJvbmdcbiAgICAgICAgICAgICAgICAgdsO5bmcgbWFuZyBgZHJhZ0hhbmRsZUNsYXNzYDsga2jDtG5nIGNo4bq3biB0aMOsIGPDuiBi4bqlbSBi4buLIGhp4buDdSBsw6AgYuG6r3QgxJHhuqd1IGvDqW8gdsOgXG4gICAgICAgICAgICAgICAgIGBkZWxheVN0YXJ0OiAxNjBgIG514buRdCBsdcO0biBgY2xpY2tgIOKAlCBuw7p0IHRyb25nIHRlbXBsYXRlIG5nb8OgaSBi4bqlbSBraMO0bmcgxINuXG4gICAgICAgICAgICAgICAgICjEkW8gMDkvMDkvMjAyNjogYuG6pW0gYuG6sW5nIGAuY2xpY2soKWAgY+G7p2EgRE9NIHRow6wgbeG7nywgYuG6pW0gY2h14buZdCB0aOG6rXQgdGjDrCBraMO0bmcpLlxuICAgICAgICAgICAgICAgICBDaOG6t24g4bufIMSQw4JZIMSR4buDIG7GoWkgZMO5bmcga2jDtG5nIHBo4bqjaSBiaeG6v3QgYuG6q3kgbsOgeS4gLS0+XG4gICAgICAgICAgICA8ZGl2XG4gICAgICAgICAgICAgIGNsYXNzPVwibGlicy11aS1ncmlkLWxheW91dC10b29sYmFyXCJcbiAgICAgICAgICAgICAgcm9sZT1cInRvb2xiYXJcIlxuICAgICAgICAgICAgICB0YWJpbmRleD1cIjBcIlxuICAgICAgICAgICAgICBbY2xhc3MubGlicy11aS1ncmlkLWxheW91dC10b29sYmFyLWNoaWxkXT1cImlzTmVzdGVkQ2FudmFzKClcIlxuICAgICAgICAgICAgICAobW91c2Vkb3duKT1cImhhbmRsZXJTdG9wRXZlbnQoJGV2ZW50KVwiXG4gICAgICAgICAgICAgIChrZXlkb3duKT1cImhhbmRsZXJTdG9wRXZlbnQoJGV2ZW50KVwiXG4gICAgICAgICAgICAgIChjbGljayk9XCJoYW5kbGVyU3RvcEV2ZW50KCRldmVudClcIj5cbiAgICAgICAgICAgICAgPG5nLWNvbnRhaW5lclxuICAgICAgICAgICAgICAgICpuZ1RlbXBsYXRlT3V0bGV0PVwidGVtcGxhdGVUb29sYmFyKCkhOyBjb250ZXh0OiB0b29sYmFyQ29udGV4dHMoKVtpdGVtSW5kZXhdXCIgLz5cbiAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgIH0gQGVsc2Uge1xuICAgICAgICAgICAgPGRpdlxuICAgICAgICAgICAgICBjbGFzcz1cImxpYnMtdWktZ3JpZC1sYXlvdXQtdG9vbGJhclwiXG4gICAgICAgICAgICAgIFtjbGFzcy5saWJzLXVpLWdyaWQtbGF5b3V0LXRvb2xiYXItY2hpbGRdPVwiaXNOZXN0ZWRDYW52YXMoKVwiPlxuICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cImxpYnMtdWktZ3JpZC1sYXlvdXQtZGltLWJhZGdlXCI+XG4gICAgICAgICAgICAgICAge3sgaXRlbS5yb3dzIH19IGjDoG5nIMOXIHt7IGl0ZW0uY29scyB9fSBj4buZdFxuICAgICAgICAgICAgICA8L3NwYW4+XG4gICAgICAgICAgICAgIEBpZiAoY2FuQWRkSW5zaWRlKGl0ZW0pKSB7XG4gICAgICAgICAgICAgICAgPGxpYnNfdWktY29tcG9uZW50cy1idXR0b25zLWJ1dHRvblxuICAgICAgICAgICAgICAgICAgW3R5cGVdPVwiJ2J1dHRvbi10aGlyZCdcIlxuICAgICAgICAgICAgICAgICAgW2ljb25Pbmx5VHlwZV09XCJ0cnVlXCJcbiAgICAgICAgICAgICAgICAgIFtzaXplQnV0dG9uXT1cIidzbWFsbGVyJ1wiXG4gICAgICAgICAgICAgICAgICBbY2xhc3NJY29uTGVmdF09XCInbGlicy11aS1pY29uLWFkZCdcIlxuICAgICAgICAgICAgICAgICAgW3BvcG92ZXJdPVwieyBjb25maWc6IHsgY29udGVudDogJ1Row6ptIGto4buRaSB2w6BvIHRyb25nJywgekluZGV4OiAxMzAwIH0gfVwiXG4gICAgICAgICAgICAgICAgICAob3V0Q2xpY2spPVwiaGFuZGxlckFkZEluc2lkZSgkZXZlbnQsIGl0ZW0pXCIgLz5cbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICBAaWYgKGNhblRvZ2dsZVR5cGUoaXRlbSkpIHtcbiAgICAgICAgICAgICAgICA8bGlic191aS1jb21wb25lbnRzLWJ1dHRvbnMtYnV0dG9uXG4gICAgICAgICAgICAgICAgICBbdHlwZV09XCInYnV0dG9uLXRoaXJkJ1wiXG4gICAgICAgICAgICAgICAgICBbaWNvbk9ubHlUeXBlXT1cInRydWVcIlxuICAgICAgICAgICAgICAgICAgW3NpemVCdXR0b25dPVwiJ3NtYWxsZXInXCJcbiAgICAgICAgICAgICAgICAgIFtjbGFzc0ljb25MZWZ0XT1cImlzQ29udGFpbmVyKGl0ZW0pID8gJ2xpYnMtdWktaWNvbi1zcGxpdC1jZWxsJyA6ICdsaWJzLXVpLWljb24tbWVyZ2UtY2VsbCdcIlxuICAgICAgICAgICAgICAgICAgW3BvcG92ZXJdPVwieyBjb25maWc6IHsgY29udGVudDogaXNDb250YWluZXIoaXRlbSkgPyAnxJDGsGEgduG7gSBraOG7kWkgxJHGoW4nIDogJ0NodXnhu4NuIHRow6BuaCBraOG7kWkgZ2jDqXAnLCB6SW5kZXg6IDEzMDAgfSB9XCJcbiAgICAgICAgICAgICAgICAgIChvdXRDbGljayk9XCJoYW5kbGVyVG9nZ2xlVHlwZSgkZXZlbnQsIGl0ZW0pXCIgLz5cbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICA8bGlic191aS1jb21wb25lbnRzLWJ1dHRvbnMtYnV0dG9uXG4gICAgICAgICAgICAgICAgW3R5cGVdPVwiJ2J1dHRvbi10aGlyZCdcIlxuICAgICAgICAgICAgICAgIFtpY29uT25seVR5cGVdPVwidHJ1ZVwiXG4gICAgICAgICAgICAgICAgW3NpemVCdXR0b25dPVwiJ3NtYWxsZXInXCJcbiAgICAgICAgICAgICAgICBbY2xhc3NJY29uTGVmdF09XCInbGlicy11aS1pY29uLXNldHRpbmcnXCJcbiAgICAgICAgICAgICAgICBbcG9wb3Zlcl09XCJ7IGNvbmZpZzogeyBjb250ZW50OiAnQ+G6pXUgaMOsbmggdGjhursnLCB6SW5kZXg6IDEzMDAgfSB9XCJcbiAgICAgICAgICAgICAgICAob3V0Q2xpY2spPVwiaGFuZGxlckNvbmZpZygkZXZlbnQsIGl0ZW0pXCIgLz5cbiAgICAgICAgICAgICAgPGxpYnNfdWktY29tcG9uZW50cy1idXR0b25zLWJ1dHRvblxuICAgICAgICAgICAgICAgIFt0eXBlXT1cIididXR0b24tdGhpcmQtaG92ZXItZGFuZ2VyJ1wiXG4gICAgICAgICAgICAgICAgW2ljb25Pbmx5VHlwZV09XCJ0cnVlXCJcbiAgICAgICAgICAgICAgICBbc2l6ZUJ1dHRvbl09XCInc21hbGxlcidcIlxuICAgICAgICAgICAgICAgIFtjbGFzc0ljb25MZWZ0XT1cIidsaWJzLXVpLWljb24tcmVtb3ZlJ1wiXG4gICAgICAgICAgICAgICAgW3BvcG92ZXJdPVwieyBjb25maWc6IHsgY29udGVudDogaXNDb250YWluZXIoaXRlbSkgPyAnWG/DoSBj4bqjIGto4buRaSBnaMOpcCcgOiAnWG/DoSBraOG7kWknLCB6SW5kZXg6IDEzMDAgfSB9XCJcbiAgICAgICAgICAgICAgICAob3V0Q2xpY2spPVwiaGFuZGxlclJlbW92ZSgkZXZlbnQsIGl0ZW0pXCIgLz5cbiAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIEBpZiAoaXRlbS5jaGlsZHJlbiAmJiBpdGVtLmNoaWxkcmVuLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICA8IS0tIEto4buRaSBjw7MgY29uIOKGkiBydeG7mXQgbsOzIGzhuqFpIGzDoCBt4buZdCBt4bq3dCBwaOG6s25nIG7hu69hLiDEkOG7hyBxdXkg4bufIMSRw6J5LCBuxqFpIGTDuW5nIGtow7RuZyBwaOG6o2kgbG8uXG4gICAgICAgICAgICAgICBM4buBIMSR4bq3dCDhu58gxJDDglkgKHbhu48gY29udGFpbmVyKSwga2jDtG5nIMSR4bq3dCB2w6BvIGzGsOG7m2kgY29uIOKAlCBsxrDhu5tpIGNvbiBnaeG7ryBuZ3V5w6puIGtoZSAycHguIC0tPlxuICAgICAgICAgIDxsaWJzX3VpLXNlcnZpY2VzLWdyaWRfbGF5b3V0LWNhbnZhc1xuICAgICAgICAgICAgY2xhc3M9XCJibG9jayBoLWZ1bGwgdy1mdWxsXCJcbiAgICAgICAgICAgIFtzdHlsZS5wYWRkaW5nXT1cImNvbnRhaW5lclBhZGRpbmcoKVwiXG4gICAgICAgICAgICBbbm9kZV09XCJpdGVtXCJcbiAgICAgICAgICAgIFtkZXB0aF09XCJkZXB0aCgpICsgMVwiXG4gICAgICAgICAgICBbaGlkZGVuVG9vbGJhcl09XCJoaWRkZW5Ub29sYmFyKClcIlxuICAgICAgICAgICAgW3RlbXBsYXRlVG9vbGJhcl09XCJ0ZW1wbGF0ZVRvb2xiYXIoKVwiXG4gICAgICAgICAgICBbc2VsZWN0ZWROb2RlSWRdPVwic2VsZWN0ZWROb2RlSWQoKVwiXG4gICAgICAgICAgICAob3V0U2VsZWN0Tm9kZSk9XCJvdXRTZWxlY3ROb2RlLmVtaXQoJGV2ZW50KVwiXG4gICAgICAgICAgICAob3V0Q29uZmlnTm9kZSk9XCJvdXRDb25maWdOb2RlLmVtaXQoJGV2ZW50KVwiXG4gICAgICAgICAgICAob3V0Q2hhbmdlKT1cIm91dENoYW5nZS5lbWl0KCRldmVudClcIlxuICAgICAgICAgICAgKG91dFJlbW92ZU5vZGUpPVwib3V0UmVtb3ZlTm9kZS5lbWl0KCRldmVudClcIlxuICAgICAgICAgICAgKG91dEFkZEJsb2NrSW5zaWRlKT1cIm91dEFkZEJsb2NrSW5zaWRlLmVtaXQoJGV2ZW50KVwiXG4gICAgICAgICAgICAob3V0VG9nZ2xlVHlwZSk9XCJvdXRUb2dnbGVUeXBlLmVtaXQoJGV2ZW50KVwiIC8+XG4gICAgICAgIH1cbiAgICAgIDwvZGl2PlxuICAgIDwvZ3JpZHN0ZXItaXRlbT5cbiAgfVxuICAgICAgPC9ncmlkc3Rlcj5cbiAgICA8L2Rpdj5cbiAgPC9kaXY+XG5cbiAgPCEtLSBUaGFuaCBkb2NrIMSRaeG7gXUga2hp4buDbiB0aHUgcGjDs25nIG7hu5VpIOG7nyBnw7NjIGTGsOG7m2kgdHLDoWkgLS0+XG4gIEBpZiAoc2hvd1pvb21Eb2NrKCkpIHtcbiAgICA8ZGl2XG4gICAgICAjem9vbURvY2tcbiAgICAgIGlkPVwiY2FudmFzLXpvb20tZG9ja1wiXG4gICAgICByb2xlPVwidG9vbGJhclwiXG4gICAgICB0YWJpbmRleD1cIjBcIlxuICAgICAgY2xhc3M9XCJhYnNvbHV0ZSBib3R0b20tNCBsZWZ0LTYgei0zMCBmbGV4IGl0ZW1zLWNlbnRlciBiZy13aGl0ZSByb3VuZGVkLWZ1bGwgc2hhZG93LTJ4bCBib3JkZXItMiBib3JkZXItc2xhdGUtNDAwIHAtMSBzcGFjZS14LTEgc2VsZWN0LW5vbmVcIlxuICAgICAgKG1vdXNlZG93bik9XCIkZXZlbnQuc3RvcFByb3BhZ2F0aW9uKClcIlxuICAgICAgKGtleWRvd24pPVwiJGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpXCJcbiAgICAgIChjbGljayk9XCIkZXZlbnQuc3RvcFByb3BhZ2F0aW9uKClcIj5cbiAgICAgIDwhLS0gVGh1IG5o4buPICgtKSAtLT5cbiAgICAgIDxidXR0b25cbiAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgIGNsYXNzPVwidy1bMjhweF0gaC1bMjhweF0gZmxleCBpdGVtcy1jZW50ZXIganVzdGlmeS1jZW50ZXIgcm91bmRlZC1mdWxsIHRleHQtc2xhdGUtNzAwIGhvdmVyOnRleHQtc2xhdGUtOTAwIGhvdmVyOmJnLXNsYXRlLTIwMCBkaXNhYmxlZDpvcGFjaXR5LTMwIGRpc2FibGVkOmhvdmVyOmJnLXRyYW5zcGFyZW50IHRyYW5zaXRpb24tY29sb3JzIGN1cnNvci1wb2ludGVyXCJcbiAgICAgICAgW2Rpc2FibGVkXT1cImN1cnJlbnRab29tKCkgPD0gem9vbU1pbigpXCJcbiAgICAgICAgW3RpdGxlXT1cIidpMThuX3pvb21fb3V0JyB8IHRyYW5zbGF0ZVwiXG4gICAgICAgIChjbGljayk9XCJoYW5kbGVyWm9vbU91dCgpXCI+XG4gICAgICAgIDxzdmcgY2xhc3M9XCJ3LTMuNSBoLTMuNVwiIHZpZXdCb3g9XCIwIDAgMjQgMjRcIiBmaWxsPVwibm9uZVwiIHN0cm9rZT1cImN1cnJlbnRDb2xvclwiIHN0cm9rZS13aWR0aD1cIjIuNVwiIHN0cm9rZS1saW5lY2FwPVwicm91bmRcIj48bGluZSB4MT1cIjVcIiB5MT1cIjEyXCIgeDI9XCIxOVwiIHkyPVwiMTJcIi8+PC9zdmc+XG4gICAgICA8L2J1dHRvbj5cblxuICAgICAgPCEtLSBU4bu3IGzhu4cgJSB2w6AgbWVudSBwcmVzZXQgLS0+XG4gICAgICA8ZGl2IGNsYXNzPVwicmVsYXRpdmVcIj5cbiAgICAgICAgPGJ1dHRvblxuICAgICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICAgIGNsYXNzPVwiaC1bMjhweF0gcHgtMiBmbGV4IGl0ZW1zLWNlbnRlciBnYXAtMSByb3VuZGVkLWZ1bGwgdGV4dC14cyBmb250LXNlbWlib2xkIHRleHQtc2xhdGUtNzAwIGhvdmVyOmJnLXNsYXRlLTIwMCB0cmFuc2l0aW9uLWNvbG9ycyBjdXJzb3ItcG9pbnRlclwiXG4gICAgICAgICAgW3RpdGxlXT1cIidpMThuX3pvb21fb3B0aW9ucycgfCB0cmFuc2xhdGVcIlxuICAgICAgICAgIChjbGljayk9XCJoYW5kbGVyVG9nZ2xlTWVudSgpXCI+XG4gICAgICAgICAgPHNwYW4+e3sgem9vbVBlcmNlbnQoKSB9fSU8L3NwYW4+XG4gICAgICAgICAgPHN2ZyBjbGFzcz1cInctWzEycHhdIGgtWzEycHhdIHRleHQtc2xhdGUtNDAwIHRyYW5zaXRpb24tdHJhbnNmb3JtIGR1cmF0aW9uLTE1MFwiIFtjbGFzcy5yb3RhdGUtMTgwXT1cImlzTWVudU9wZW4oKVwiIHZpZXdCb3g9XCIwIDAgMjQgMjRcIiBmaWxsPVwibm9uZVwiIHN0cm9rZT1cImN1cnJlbnRDb2xvclwiIHN0cm9rZS13aWR0aD1cIjIuNVwiIHN0cm9rZS1saW5lY2FwPVwicm91bmRcIiBzdHJva2UtbGluZWpvaW49XCJyb3VuZFwiPjxwb2x5bGluZSBwb2ludHM9XCI2IDkgMTIgMTUgMTggOVwiLz48L3N2Zz5cbiAgICAgICAgPC9idXR0b24+XG5cbiAgICAgICAgPCEtLSBNZW51IGRyb3Bkb3duIGPDoWMgbeG7kWMgdGh1IHBow7NuZyAtLT5cbiAgICAgICAgQGlmIChpc01lbnVPcGVuKCkpIHtcbiAgICAgICAgICA8ZGl2IGNsYXNzPVwiYWJzb2x1dGUgYm90dG9tLWZ1bGwgbWItMiBsZWZ0LTAgdy1bMjU2cHhdIGJnLXdoaXRlIHJvdW5kZWQteGwgc2hhZG93LXhsIGJvcmRlciBib3JkZXItc2xhdGUtMjAwIHB5LTEuNSB6LTQwIHRleHQteHMgc2VsZWN0LW5vbmVcIj5cbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJweC0zIHB5LTEgdGV4dC1bMTFweF0gZm9udC1zZW1pYm9sZCB0ZXh0LXNsYXRlLTQwMCB1cHBlcmNhc2UgdHJhY2tpbmctd2lkZXJcIj5cbiAgICAgICAgICAgICAge3sgJ2kxOG5fem9vbV9jYW52YXNfd2lkdGgnIHwgdHJhbnNsYXRlOiB7IHdpZHRoOiBzdGFnZVdpZHRoKCkgfSB9fVxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICAgICAgICBjbGFzcz1cInctZnVsbCBweC0zIHB5LTIgdGV4dC1sZWZ0IGZsZXggaXRlbXMtY2VudGVyIGp1c3RpZnktYmV0d2VlbiBob3ZlcjpiZy1zbGF0ZS01MCB0cmFuc2l0aW9uLWNvbG9ycyBjdXJzb3ItcG9pbnRlclwiXG4gICAgICAgICAgICAgIChjbGljayk9XCJoYW5kbGVyRml0U2NyZWVuKClcIj5cbiAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJmbGV4IGl0ZW1zLWNlbnRlciBnYXAtMiB0ZXh0LXNsYXRlLTcwMCBmb250LW1lZGl1bVwiPlxuICAgICAgICAgICAgICAgIDxzdmcgY2xhc3M9XCJ3LTMuNSBoLTMuNSB0ZXh0LXNsYXRlLTYwMFwiIHZpZXdCb3g9XCIwIDAgMjQgMjRcIiBmaWxsPVwibm9uZVwiIHN0cm9rZT1cImN1cnJlbnRDb2xvclwiIHN0cm9rZS13aWR0aD1cIjJcIj48cG9seWxpbmUgcG9pbnRzPVwiMTUgMyAyMSAzIDIxIDlcIi8+PHBvbHlsaW5lIHBvaW50cz1cIjkgMjEgMyAyMSAzIDE1XCIvPjxsaW5lIHgxPVwiMjFcIiB5MT1cIjNcIiB4Mj1cIjE0XCIgeTI9XCIxMFwiLz48bGluZSB4MT1cIjNcIiB5MT1cIjIxXCIgeDI9XCIxMFwiIHkyPVwiMTRcIi8+PC9zdmc+XG4gICAgICAgICAgICAgICAge3sgJ2kxOG5fem9vbV9maXRfc2NyZWVuJyB8IHRyYW5zbGF0ZSB9fVxuICAgICAgICAgICAgICA8L3NwYW4+XG4gICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwidGV4dC1bMTBweF0gYmctYmx1ZS01MCB0ZXh0LWJsdWUtNjAwIHB4LTEuNSBweS0wLjUgcm91bmRlZCBmb250LW1lZGl1bVwiPnt7ICdpMThuX2F1dG8nIHwgdHJhbnNsYXRlIH19PC9zcGFuPlxuICAgICAgICAgICAgPC9idXR0b24+XG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwiaC1weCBiZy1zbGF0ZS0xMDAgbXktMVwiPjwvZGl2PlxuICAgICAgICAgICAgQGZvciAocHJlc2V0IG9mIHpvb21QcmVzZXRzOyB0cmFjayBwcmVzZXQudmFsdWUpIHtcbiAgICAgICAgICAgICAgPGJ1dHRvblxuICAgICAgICAgICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICAgICAgICAgIGNsYXNzPVwidy1mdWxsIHB4LTMgcHktMS41IHRleHQtbGVmdCBmbGV4IGl0ZW1zLWNlbnRlciBqdXN0aWZ5LWJldHdlZW4gaG92ZXI6Ymctc2xhdGUtNTAgdHJhbnNpdGlvbi1jb2xvcnMgY3Vyc29yLXBvaW50ZXJcIlxuICAgICAgICAgICAgICAgIFtjbGFzcy50ZXh0LWJsdWUtNjAwXT1cImlzQ3VycmVudFByZXNldChwcmVzZXQudmFsdWUpXCJcbiAgICAgICAgICAgICAgICBbY2xhc3MuZm9udC1zZW1pYm9sZF09XCJpc0N1cnJlbnRQcmVzZXQocHJlc2V0LnZhbHVlKVwiXG4gICAgICAgICAgICAgICAgW2NsYXNzLmJnLWJsdWUtNTBdPVwiaXNDdXJyZW50UHJlc2V0KHByZXNldC52YWx1ZSlcIlxuICAgICAgICAgICAgICAgIChjbGljayk9XCJoYW5kbGVyU2VsZWN0UHJlc2V0KHByZXNldC52YWx1ZSlcIj5cbiAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cInRleHQtc2xhdGUtNzAwXCIgW2NsYXNzLnRleHQtYmx1ZS02MDBdPVwiaXNDdXJyZW50UHJlc2V0KHByZXNldC52YWx1ZSlcIj5cbiAgICAgICAgICAgICAgICAgIHt7IHByZXNldC5sYWJlbCB8IHRyYW5zbGF0ZSB9fVxuICAgICAgICAgICAgICAgIDwvc3Bhbj5cbiAgICAgICAgICAgICAgICBAaWYgKGlzQ3VycmVudFByZXNldChwcmVzZXQudmFsdWUpKSB7XG4gICAgICAgICAgICAgICAgICA8c3ZnIGNsYXNzPVwidy0zLjUgaC0zLjUgdGV4dC1ibHVlLTYwMFwiIHZpZXdCb3g9XCIwIDAgMjQgMjRcIiBmaWxsPVwibm9uZVwiIHN0cm9rZT1cImN1cnJlbnRDb2xvclwiIHN0cm9rZS13aWR0aD1cIjIuNVwiIHN0cm9rZS1saW5lY2FwPVwicm91bmRcIiBzdHJva2UtbGluZWpvaW49XCJyb3VuZFwiPjxwb2x5bGluZSBwb2ludHM9XCIyMCA2IDkgMTcgNCAxMlwiLz48L3N2Zz5cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICAgICAgfVxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICB9XG4gICAgICA8L2Rpdj5cblxuICAgICAgPCEtLSBQaMOzbmcgdG8gKCspIC0tPlxuICAgICAgPGJ1dHRvblxuICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgY2xhc3M9XCJ3LVsyOHB4XSBoLVsyOHB4XSBmbGV4IGl0ZW1zLWNlbnRlciBqdXN0aWZ5LWNlbnRlciByb3VuZGVkLWZ1bGwgdGV4dC1zbGF0ZS03MDAgaG92ZXI6dGV4dC1zbGF0ZS05MDAgaG92ZXI6Ymctc2xhdGUtMjAwIGRpc2FibGVkOm9wYWNpdHktMzAgZGlzYWJsZWQ6aG92ZXI6YmctdHJhbnNwYXJlbnQgdHJhbnNpdGlvbi1jb2xvcnMgY3Vyc29yLXBvaW50ZXJcIlxuICAgICAgICBbZGlzYWJsZWRdPVwiY3VycmVudFpvb20oKSA+PSB6b29tTWF4KClcIlxuICAgICAgICBbdGl0bGVdPVwiJ2kxOG5fem9vbV9pbicgfCB0cmFuc2xhdGVcIlxuICAgICAgICAoY2xpY2spPVwiaGFuZGxlclpvb21JbigpXCI+XG4gICAgICAgIDxzdmcgY2xhc3M9XCJ3LTMuNSBoLTMuNVwiIHZpZXdCb3g9XCIwIDAgMjQgMjRcIiBmaWxsPVwibm9uZVwiIHN0cm9rZT1cImN1cnJlbnRDb2xvclwiIHN0cm9rZS13aWR0aD1cIjIuNVwiIHN0cm9rZS1saW5lY2FwPVwicm91bmRcIj48bGluZSB4MT1cIjEyXCIgeTE9XCI1XCIgeDI9XCIxMlwiIHkyPVwiMTlcIi8+PGxpbmUgeDE9XCI1XCIgeTE9XCIxMlwiIHgyPVwiMTlcIiB5Mj1cIjEyXCIvPjwvc3ZnPlxuICAgICAgPC9idXR0b24+XG5cbiAgICAgIDwhLS0gUGjDom4gY8OhY2ggLS0+XG4gICAgICA8ZGl2IGNsYXNzPVwiaC1bMTZweF0gdy1weCBiZy1zbGF0ZS0yMDBcIj48L2Rpdj5cblxuICAgICAgPCEtLSBOw7p0IFbhu6thIG3DoG4gaMOsbmggbmhhbmggLS0+XG4gICAgICA8YnV0dG9uXG4gICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICBjbGFzcz1cImgtWzI4cHhdIHNocmluay0wIHB4LTIuNSBmbGV4IGl0ZW1zLWNlbnRlciBnYXAtMSByb3VuZGVkLWZ1bGwgdGV4dC14cyB0ZXh0LXNsYXRlLTcwMCBob3Zlcjp0ZXh0LXNsYXRlLTkwMCBob3ZlcjpiZy1zbGF0ZS0yMDAgdHJhbnNpdGlvbi1jb2xvcnMgY3Vyc29yLXBvaW50ZXJcIlxuICAgICAgICBbdGl0bGVdPVwiJ2kxOG5fem9vbV9maXRfc2NyZWVuX3Rvb2x0aXAnIHwgdHJhbnNsYXRlXCJcbiAgICAgICAgKGNsaWNrKT1cImhhbmRsZXJGaXRTY3JlZW4oKVwiPlxuICAgICAgICA8c3ZnIGNsYXNzPVwidy0zLjUgaC0zLjVcIiB2aWV3Qm94PVwiMCAwIDI0IDI0XCIgZmlsbD1cIm5vbmVcIiBzdHJva2U9XCJjdXJyZW50Q29sb3JcIiBzdHJva2Utd2lkdGg9XCIyXCI+PHBvbHlsaW5lIHBvaW50cz1cIjE1IDMgMjEgMyAyMSA5XCIvPjxwb2x5bGluZSBwb2ludHM9XCI5IDIxIDMgMjEgMyAxNVwiLz48bGluZSB4MT1cIjIxXCIgeTE9XCIzXCIgeDI9XCIxNFwiIHkyPVwiMTBcIi8+PGxpbmUgeDE9XCIzXCIgeTE9XCIyMVwiIHgyPVwiMTBcIiB5Mj1cIjE0XCIvPjwvc3ZnPlxuICAgICAgICA8c3BhbiBjbGFzcz1cIndoaXRlc3BhY2Utbm93cmFwIGZvbnQtbWVkaXVtXCI+e3sgJ2kxOG5fem9vbV9maXRfc2NyZWVuJyB8IHRyYW5zbGF0ZSB9fTwvc3Bhbj5cbiAgICAgIDwvYnV0dG9uPlxuXG4gICAgICA8IS0tIE7DunQgxJDhurd0IGzhuqFpIDEwMCUgKGNo4buJIGhp4buHbiBraGkga2jDoWMgMTAwJSkgLS0+XG4gICAgICBAaWYgKHpvb21QZXJjZW50KCkgIT09IDEwMCkge1xuICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgY2xhc3M9XCJoLVsyOHB4XSBweC0yIGZsZXggaXRlbXMtY2VudGVyIGdhcC0xIHJvdW5kZWQtZnVsbCB0ZXh0LXhzIGZvbnQtc2VtaWJvbGQgdGV4dC1ibHVlLTYwMCBob3ZlcjpiZy1ibHVlLTUwIHRyYW5zaXRpb24tY29sb3JzIGN1cnNvci1wb2ludGVyXCJcbiAgICAgICAgICBbdGl0bGVdPVwiJ2kxOG5fem9vbV9yZXNldF90b29sdGlwJyB8IHRyYW5zbGF0ZTogeyB3aWR0aDogc3RhZ2VXaWR0aCgpLCBoZWlnaHQ6IHN0YWdlTWluSGVpZ2h0KCkgfVwiXG4gICAgICAgICAgKGNsaWNrKT1cImhhbmRsZXJSZXNldFpvb20oKVwiPlxuICAgICAgICAgIDxzdmcgY2xhc3M9XCJ3LVsxMnB4XSBoLVsxMnB4XVwiIHZpZXdCb3g9XCIwIDAgMjQgMjRcIiBmaWxsPVwibm9uZVwiIHN0cm9rZT1cImN1cnJlbnRDb2xvclwiIHN0cm9rZS13aWR0aD1cIjJcIiBzdHJva2UtbGluZWNhcD1cInJvdW5kXCIgc3Ryb2tlLWxpbmVqb2luPVwicm91bmRcIj48cG9seWxpbmUgcG9pbnRzPVwiMSA0IDEgMTAgNyAxMFwiLz48cGF0aCBkPVwiTTMuNTEgMTVhOSA5IDAgMSAwIDIuMTMtOS4zNkwxIDEwXCIvPjwvc3ZnPlxuICAgICAgICAgIDxzcGFuPjEwMCU8L3NwYW4+XG4gICAgICAgIDwvYnV0dG9uPlxuICAgICAgfVxuICAgIDwvZGl2PlxuICB9XG59IEBlbHNlIHtcbiAgPCEtLSDwn5S0IGByZWxhdGl2ZWAgbMOgIELhuq5UIEJV4buYQywgQ+G6pE0gYuG7jy5cbiAgICAgICBncmlkc3RlciDEkeG7lWkgduG7iyB0csOtIGNodeG7mXQgdGjDoG5oIMO0IGzGsOG7m2kgYuG6sW5nIGBlLmNsaWVudFkgKyAoZWwuc2Nyb2xsVG9wIC0gZWwub2Zmc2V0VG9wKWAg4oCUIGPDtG5nXG4gICAgICAgdGjhu6ljIMSRw7MgY2jhu4kgxJHDum5nIGtoaSBgb2Zmc2V0UGFyZW50YCBj4bunYSA8Z3JpZHN0ZXI+IENIw41OSCBMw4Aga2jhu5FpIGN14buZbiBuw6B5LiBUaGnhur91IGByZWxhdGl2ZWAgdGjDrFxuICAgICAgIGBvZmZzZXRQYXJlbnRgIG5o4bqjeSBsw6puIGto4buRaSBiYW8gbmdvw6BpOiBgb2Zmc2V0VG9wYCB0cuG6oyAxNiB0cm9uZyBraGkgbOG7h2NoIHRo4bqtdCBsw6AgNjUg4oaSIGdyaWRzdGVyXG4gICAgICAgdMOtbmggw7Qgc2FpIDQ5cHgsIMO0IGNo4budIMSR4bq3dCBoaeG7h24gbOG7h2NoIGto4buPaSBjb24gdHLhu48gbsOqbiBrw6lvIHRo4bqjIGtow7RuZyDEkeG7lWkgxJHGsOG7o2MgduG7iyB0csOtLCB2w6Aga8OpbyBtw6lwXG4gICAgICAgY8WpbmcgdMOtbmggc2FpIMSRaeG7g20gZOG7q25nLiAtLT5cbiAgPGRpdlxuICAgICNzY3JvbGxBcmVhXG4gICAgY2xhc3M9XCJsaWJzLXVpLWdyaWQtbGF5b3V0LXNjcm9sbC1hcmVhIHJlbGF0aXZlIGgtZnVsbCBtaW4taC0wIHctZnVsbCBtaW4tdy0wXCJcbiAgICBbY2xhc3Mub3ZlcmZsb3cteS1hdXRvXT1cIiFpc05lc3RlZENhbnZhcygpXCJcbiAgICAobW91c2Vkb3duKT1cImhhbmRsZXJNb3VzZURvd25Ucm9uZ0x1b2koJGV2ZW50KVwiXG4gICAgKGRyYWdvdmVyKT1cImhhbmRsZXJEcmFnT3ZlcigkZXZlbnQpXCJcbiAgICAoZHJhZ2xlYXZlKT1cImhhbmRsZXJEcmFnTGVhdmUoJGV2ZW50KVwiXG4gICAgKGRyb3ApPVwiaGFuZGxlckRyb3AoJGV2ZW50KVwiPlxuICAgIDwhLS0gU25hcHBlZCBEcm9wIEdob3N0IFByZXZpZXcgLS0+XG4gICAgQGlmIChkcm9wR2hvc3QoKTsgYXMgZ2hvc3QpIHtcbiAgICAgIDxkaXZcbiAgICAgICAgY2xhc3M9XCJwb2ludGVyLWV2ZW50cy1ub25lIGFic29sdXRlIHotMzAgZmxleCBmbGV4LWNvbCBpdGVtcy1jZW50ZXIganVzdGlmeS1jZW50ZXIgb3ZlcmZsb3ctaGlkZGVuIHJvdW5kZWQtbGcgYm9yZGVyLTIgYm9yZGVyLWRhc2hlZCBib3JkZXItYmx1ZS01MDAgYmctYmx1ZS01MDAvMTUgcC0xIHNoYWRvdy1zbSB0cmFuc2l0aW9uLWFsbCBkdXJhdGlvbi03NSBlYXNlLW91dCBiYWNrZHJvcC1ibHVyLVswLjVweF0gc2VsZWN0LW5vbmVcIlxuICAgICAgICBbc3R5bGUubGVmdC5weF09XCJnaG9zdC5waXhlbExlZnRcIlxuICAgICAgICBbc3R5bGUudG9wLnB4XT1cImdob3N0LnBpeGVsVG9wXCJcbiAgICAgICAgW3N0eWxlLndpZHRoLnB4XT1cImdob3N0LnBpeGVsV2lkdGhcIlxuICAgICAgICBbc3R5bGUuaGVpZ2h0LnB4XT1cImdob3N0LnBpeGVsSGVpZ2h0XCI+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJpbmxpbmUtZmxleCBtYXgtdy1bOTUlXSBpdGVtcy1jZW50ZXIgZ2FwLTEgdHJ1bmNhdGUgcm91bmRlZC1tZCBiZy1ibHVlLTYwMCBweC0yIHB5LTAuNSB0ZXh0LVsxMXB4XSBmb250LXNlbWlib2xkIHRleHQtd2hpdGUgc2hhZG93LXhzXCI+XG4gICAgICAgICAgQGlmIChnaG9zdC5jYXJkSWNvbkNsYXNzKSB7XG4gICAgICAgICAgICA8aSBbY2xhc3NdPVwiZ2hvc3QuY2FyZEljb25DbGFzcyArICcgdGV4dC14cydcIj48L2k+XG4gICAgICAgICAgfSBAZWxzZSBpZiAoZ2hvc3QuY2FyZEljb25UZXh0KSB7XG4gICAgICAgICAgICA8c3BhbiBjbGFzcz1cInRleHQtWzEwcHhdIGZvbnQtYm9sZFwiPnt7IGdob3N0LmNhcmRJY29uVGV4dCB9fTwvc3Bhbj5cbiAgICAgICAgICB9IEBlbHNlIHtcbiAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwidGV4dC14cyBmb250LWJvbGRcIj57eyBnaG9zdC5pc0luc2lkZUdyb3VwID8gJ+KGsycgOiAnKycgfX08L3NwYW4+XG4gICAgICAgICAgfVxuICAgICAgICAgIDxzcGFuIGNsYXNzPVwidHJ1bmNhdGVcIj57eyBnaG9zdC5jYXJkVGl0bGUgfX08L3NwYW4+XG4gICAgICAgICAgPHNwYW4gY2xhc3M9XCJ0ZXh0LVs5cHhdIGZvbnQtbW9ubyBvcGFjaXR5LTc1XCI+KHt7IGdob3N0LmNvbHMgfX1jKTwvc3Bhbj5cbiAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgQGlmIChnaG9zdC5waXhlbEhlaWdodCA+PSA4MCkge1xuICAgICAgICAgIDxkaXYgY2xhc3M9XCJtdC0xIGZsZXggbWF4LXctWzk1JV0gaXRlbXMtY2VudGVyIGdhcC0xLjUgdHJ1bmNhdGUgcm91bmRlZCBib3JkZXIgYm9yZGVyLWJsdWUtMTAwIGJnLXdoaXRlLzk1IHB4LTIgcHktMC41IHRleHQtWzEwcHhdIGZvbnQtbWVkaXVtIHRleHQtYmx1ZS03MDAgc2hhZG93LXhzXCI+XG4gICAgICAgICAgICBAaWYgKGdob3N0LmlzSW5zaWRlR3JvdXApIHtcbiAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJ0cnVuY2F0ZSBmb250LWJvbGQgdGV4dC1ibHVlLTkwMFwiPuKGsyB7eyBnaG9zdC5ncm91cFRpdGxlIH19PC9zcGFuPlxuICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cInRleHQtYmx1ZS0zMDBcIj7igKI8L3NwYW4+XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICA8c3Bhbj5D4buZdCB7eyBnaG9zdC5jb2wgKyAxIH19LXt7IGdob3N0LmNvbCArIGdob3N0LmNvbHMgfX08L3NwYW4+XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgIH1cbiAgICAgIDwvZGl2PlxuICAgIH1cbiAgICA8Z3JpZHN0ZXIgY2xhc3M9XCJoLWZ1bGwgdy1mdWxsXCIgW2NsYXNzLmRpc3BsYXktZ3JpZF09XCJzaG93R3JpZExpbmVzKClcIiBbb3B0aW9uc109XCJncmlkT3B0aW9ucygpXCI+XG4gICAgICAgIEBmb3IgKGl0ZW0gb2YgY2hpbGRyZW4oKTsgdHJhY2sgaXRlbS5pZDsgbGV0IGl0ZW1JbmRleCA9ICRpbmRleCkge1xuICAgIDwhLS0g8J+UtCBDaOG6t24gYG1vdXNlZG93bmAgdOG6oWkgxJDDglkgY2hvIGzGsOG7m2kgbOG7k25nIOKAlCBD4bqkTSBi4buPIHbDoCBD4bqkTSBjaHV54buDbiBzYW5nIGNo4buXIGtow6FjLlxuICAgICAgICAgYGlnbm9yZUNvbnRlbnRDbGFzc2AgbeG7mXQgbcOsbmggS0jDlE5HIMSR4bunOiBgZGVsYXlTdGFydDogMTYwYCBsw6BtIE3hu5ZJIGzGsOG7m2kgbMOqbiBs4buLY2hcbiAgICAgICAgIGBkcmFnU3RhcnRgIGLhurFuZyBgc2V0VGltZW91dGAgbmdheSB04bqhaSBgbW91c2Vkb3duYCwgY8OybiBgc3RvcFByb3BhZ2F0aW9uYCBtw6AgbGliIGfhu41pIGLDqm5cbiAgICAgICAgIHRyb25nIGBkcmFnU3RhcnRgIGNo4bqheSBzYXUgMTYwbXMgbsOqbiBxdcOhIG114buZbiDigJQgbMaw4bubaSBDSEEgxJHDoyBr4buLcCBuaOG6rW4gKMSRbyAyOC8wOC8yMDI2OiBrw6lvXG4gICAgICAgICBk4bqjaSBraOG7kWkgY29uLCBjaHXhu5dpIGNsYXNzIGR1eeG7h3QgbMOqbiDEkMOaTkcgbcOgIGNvbnRhaW5lciB24bqrbiBuaOG6o3kgMCwwIOKGkiAwLDEpLlxuICAgICAgICAgR+G6r24g4bufIGBncmlkc3Rlci1pdGVtYCBsw6AgxJHDum5nIGJpw6puOiBsxrDhu5tpIGNvbiBuZ2hlIHRyw6puIGNow61uaCBwaOG6p24gdOG7rSBuw6B5IG7Dqm4gxJHDoyBuaOG6rW4geG9uZyxcbiAgICAgICAgIGzGsOG7m2kgY2hhIOG7nyBuZ2/DoGkgYuG7iyBjaOG6t24uIC0tPlxuICAgIDxncmlkc3Rlci1pdGVtXG4gICAgICBbaXRlbV09XCJpdGVtXCJcbiAgICAgIFtjbGFzcy5saWJzLXVpLWdyaWQtbGF5b3V0LXNlbGVjdGVkXT1cInNlbGVjdGVkTm9kZUlkKCkgPT09IGl0ZW0uaWRcIlxuICAgICAgKGNsaWNrKT1cImhhbmRsZXJTZWxlY3ROb2RlKGl0ZW0sICRldmVudClcIlxuICAgICAgKG1vdXNlZG93bik9XCJoYW5kbGVyQmxvY2tQYXJlbnREcmFnKCRldmVudClcIj5cbiAgICAgIDwhLS0g8J+UtCBW4buPIG7DoHkgbWFuZyBgZHJhZ0hhbmRsZUNsYXNzYCDigJQgQ+G6pE0gYuG7jy5cbiAgICAgICAgICAgYGlnbm9yZUNvbnRlbnQ6IHRydWVgIGLhuq90IGdyaWRzdGVyIENI4buIIGNobyBrw6lvIGtoaSBjaOG7lyBi4bqlbSBu4bqxbSBkxrDhu5tpIG3hu5l0IHBo4bqnbiB04butIGPDs1xuICAgICAgICAgICBgZHJhZ0hhbmRsZUNsYXNzYC4gS2jDtG5nIGPDsyB24buPIG7DoHkgdGjDrCBjb21wb25lbnQgY+G7p2EgbsahaSBkw7luZyAodGjGsCB2aeG7h24ga2jDtG5nIGtp4buDbSBzb8OhdFxuICAgICAgICAgICDEkcaw4bujYyBjbGFzcyBj4bunYSBuw7MpIHPhur0ga2jDtG5nIGPDsyB0YXkgY+G6p20gbsOgbywgdsOgIEtIw5RORyBraOG7kWkgbsOgbyBrw6lvIMSRxrDhu6NjIOKAlCDEkW8gMjgvMDgvMjAyNjpcbiAgICAgICAgICAga8OpbyAzMjBweCwgdG/huqEgxJHhu5kga2jhu5FpIGdp4buvIG5ndXnDqm4geD0zLHk9MC5cbiAgICAgICAgICAgVMOqbiBjbGFzcyB0aGVvIGPhuqVwOiBsxrDhu5tpIHRyYW5nIHbDoCBsxrDhu5tpIGzhu5NuZyBkw7luZyBoYWkgdMOqbiBLSMOBQyBuaGF1LCBu4bq/dSBraMO0bmcgbMaw4bubaSBjaGFcbiAgICAgICAgICAgY8Wpbmcgbmjhuq1uIHJhIHRheSBj4bqnbSBj4bunYSBraOG7kWkgY29uIHbDoCBuaOG6pWMgbHXDtG4gY29udGFpbmVyLiAtLT5cbiAgICAgIDwhLS0g8J+UtCBW4buPIEtIw5RORyBtYW5nIGBkcmFnSGFuZGxlQ2xhc3NgIOKAlCBD4bqkTSB0aMOqbSBs4bqhaS5cbiAgICAgICAgICAgS8OpbyBjaOG7iSDEkcaw4bujYyBwaMOpcCBi4bqvdCDEkeG6p3UgdOG7qyBE4bqiSSBYQU5IIChuZ8aw4budaSBkw7luZyBjaOG7kXQgMjgvMDgvMjAyNjogXCJwaOG6o2kgaG92ZXIgdsOgbyB2w7luZ1xuICAgICAgICAgICBtw6B1IHhhbmggdGjDrCBt4bubaSBrw6lvIHRo4bqjIMSRxrDhu6NjIGNobyDEkeG7k25nIG5o4bqldFwiKS4gQ2hvIGPhuqMgduG7jyBsw6BtIHRheSBj4bqnbSB0aMOsIGLhuqVtIMSRw6J1IGPFqW5nXG4gICAgICAgICAgIGvDqW8sIHbDoCBraOG7kWkgY29uIG7hurFtIHRyb25nIGNvbnRhaW5lciBz4bq9IG5o4bqlYyBsdcO0biBjb250YWluZXIgdsOsIGzGsOG7m2kgY2hhIGR1eeG7h3QgbMOqbiBn4bq3cFxuICAgICAgICAgICB0YXkgY+G6p20gY+G7p2EgduG7jyBjb250YWluZXIgdHLGsOG7m2MuXG4gICAgICAgICAgIFbhu48ga2jhu5FpIGNvbiB24bqrbiBnaeG7ryBjbGFzcyBDSOG6tk4gxJHhu4MgbMaw4bubaSBjaGEgZOG7q25nIMSRw7puZyDhu58gYmnDqm4uIC0tPlxuICAgICAgPGRpdlxuICAgICAgICBjbGFzcz1cImxpYnMtdWktZ3JpZC1sYXlvdXQtYmxvY2stc2hlbGwgZ3JvdXAgcmVsYXRpdmUgaC1mdWxsIHctZnVsbCBtaW4tdy0wXCJcbiAgICAgICAgW2F0dHIuZGF0YS1ub2RlLWlkXT1cIml0ZW0uaWRcIlxuICAgICAgICBbY2xhc3MubGlicy11aS1ncmlkLWxheW91dC1ibG9jay1wYXJlbnQtZHJhZ109XCJpc05lc3RlZENhbnZhcygpXCI+XG4gICAgICAgIDwhLS0gROG6o2kga8OpbzogaGnhu4duIGtoaSByw6ogY2h14buZdCB2w6BvIGto4buRaSwgYmEgY2jhuqVtIGzDoCBk4bqldSBoaeG7h3Uga8OpbyBxdWVuIHRodeG7mWMuXG4gICAgICAgICAgICAgTmfGsOG7nWkgZMO5bmcgY+G6p24gbeG7mXQgY2jhu5cgYsOhbSBSw5UgUsOATkcgdGhheSB2w6wgxJFvw6FuIHhlbSBi4bqlbSDEkcOidSB0aMOsIGvDqW8gxJHGsOG7o2NcbiAgICAgICAgICAgICAoY2jhu5F0IDI4LzA4LzIwMjYsIHRoZW8gxJHDum5nIGThuqNpIMSRYW5nIGTDuW5nIOG7nyBtw6BuIEN1c3RvbWVyIDM2MCBj4bunYSBtb2Jpby13ZWIpLiAtLT5cbiAgICAgICAgQGlmIChpc0VkaXRNb2RlKCkpIHtcbiAgICAgICAgICA8IS0tIPCflLQgROG6o2kgUEjhuqJJIG1hbmcgdGF5IGPhuqdtIMSQw5pORyBD4bqkUCBj4bunYSBuw7MuIEThuqNpIG5o4bqtbiBjaHXhu5l0IChgcG9pbnRlci1ldmVudHM6IGF1dG9gKSxcbiAgICAgICAgICAgICAgIG7Dqm4gbuG6v3Uga2jDtG5nIG1hbmcgdGF5IGPhuqdtIHRow6wgYGNoZWNrRHJhZ0hhbmRsZUNsYXNzYCBkdXnhu4d0IGzDqm4gZ+G6t3AgdGF5IGPhuqdtIGPhu6dhXG4gICAgICAgICAgICAgICBjb250YWluZXIgdsOgIG5o4bqlYyBjb250YWluZXIgdGhheSB2w6wga2jhu5FpIGNvbiAoxJFvIDI4LzA4LzIwMjY6IGvDqW8gZOG6o2kga2jhu5FpIGNvbixcbiAgICAgICAgICAgICAgIGNvbnRhaW5lciBuaOG6o3kgMCwwIOKGkiAwLDEgY8OybiBraOG7kWkgY29uIMSR4bupbmcgaW0pLlxuICAgICAgICAgICAgICAg8J+UtCBE4bqjaSBDSOG7iCBtYW5nIHRheSBj4bqnbSwgQ+G6pE0gbWFuZyB0aMOqbSBjbGFzcyBjaOG6t246IGBjaGVja0RyYWdIYW5kbGVDbGFzc2AgeMOpdCBoYWlcbiAgICAgICAgICAgICAgIGNsYXNzIMSRw7MgdHLDqm4gQ8OZTkcgbeG7mXQgbm9kZSBuw6puIMSR4buDIGNodW5nIGzDoCBrw6lvIGjhu49uZyAoxJFvIDI4LzA4LzIwMjY6IGLhuqVtIGThuqNpIGto4buRaVxuICAgICAgICAgICAgICAgY29uIGvDqW8gMTQwcHgsIGto4buRaSDEkeG7qW5nIGltKS4gVmnhu4djIGNo4bq3biBsxrDhu5tpIGNoYSBkbyBW4buOIEtI4buQSSBsby4gLS0+XG4gICAgICAgICAgPGRpdlxuICAgICAgICAgICAgY2xhc3M9XCJsaWJzLXVpLWdyaWQtbGF5b3V0LWRyYWctYmFyXCJcbiAgICAgICAgICAgIFtjbGFzcy5saWJzLXVpLWdyaWQtbGF5b3V0LWRyYWctYmFyLWNoaWxkXT1cImlzTmVzdGVkQ2FudmFzKClcIlxuICAgICAgICAgICAgW2NsYXNzLmxpYnMtdWktZ3JpZC1sYXlvdXQtZHJhZy1oYW5kbGVdPVwiIWlzTmVzdGVkQ2FudmFzKClcIlxuICAgICAgICAgICAgW2NsYXNzLmxpYnMtdWktZ3JpZC1sYXlvdXQtZHJhZy1oYW5kbGUtY2hpbGRdPVwiaXNOZXN0ZWRDYW52YXMoKVwiPlxuICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJsaWJzLXVpLWdyaWQtbGF5b3V0LWRyYWctYmFyLWRvdHNcIj5cbiAgICAgICAgICAgICAgQGZvciAoZG90IG9mIGRyYWdCYXJEb3RzOyB0cmFjayBkb3QpIHtcbiAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cImxpYnMtdWktZ3JpZC1sYXlvdXQtZHJhZy1iYXItZG90XCI+PC9zcGFuPlxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICA8L3NwYW4+XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgIH1cblxuICAgICAgICA8IS0tIEtodW5nIGNo4bupYSBjb21wb25lbnQgY+G7p2EgbsahaSBkw7luZy5cbiAgICAgICAgICAgICDwn5S0IFBI4bqiSSBjw7Mga2h1bmcgdGjhuq10IChraMO0bmcgcGjhuqNpIGBuZy1jb250YWluZXJgIHRy4buRbmcpOiBuw7MgbG8gaOG7mSBuxqFpIGTDuW5nIHBo4bqnbiBs4bqlcCDEkeG6p3lcbiAgICAgICAgICAgICDDtCB2w6Agdmnhu4FuIGLDoW8gY2jhur8gxJHhu5kgc+G7rWEuIEtow7RuZyBjw7Mga2h1bmcgdGjDrCBt4buXaSBjb21wb25lbnQgbuG7mWkgZHVuZyBs4bqhaSBwaOG6o2kgdOG7sSB2aeG6v3RcbiAgICAgICAgICAgICBgOmhvc3QgeyB3aWR0aC9oZWlnaHQ6IDEwMCUgfWAgKyB2aeG7gW4gxJHhu6l0IOKAlCDEkcOzIGzDoCB2aeG7h2MgY+G7p2EgdGjGsCB2aeG7h24sIGtow7RuZyBwaOG6o2kgY+G7p2FcbiAgICAgICAgICAgICBuZ8aw4budaSBkw7luZyAobmfGsOG7nWkgZMO5bmcgY2jhu5F0IDI4LzA4LzIwMjYpLlxuICAgICAgICAgICAgIE3hu5dpIGto4buRaSBt4buZdCBWaWV3Q29udGFpbmVyUmVmIHJpw6puZyBuw6puIGNvbXBvbmVudCBu4bqxbSDEkcO6bmcgw7QgY+G7p2EgbsOzLiAtLT5cbiAgICAgICAgPGRpdlxuICAgICAgICAgIGNsYXNzPVwibGlicy11aS1ncmlkLWxheW91dC1jb250ZW50LWZyYW1lXCJcbiAgICAgICAgICBbY2xhc3MubGlicy11aS1ncmlkLWxheW91dC1jb250ZW50LWZyYW1lLWVkaXRdPVwiaXNFZGl0TW9kZSgpICYmICFpc0NvbnRhaW5lcihpdGVtKVwiXG4gICAgICAgICAgW2NsYXNzLmxpYnMtdWktZ3JpZC1sYXlvdXQtY29udGVudC1mcmFtZS1lbXB0eV09XCJpc0NvbnRhaW5lcihpdGVtKSAmJiAhaXRlbS5nZXRDb21wb25lbnRPdXRsZXRcIj5cbiAgICAgICAgICA8bmctY29udGFpbmVyICNpdGVtSG9zdCAvPlxuICAgICAgICA8L2Rpdj5cblxuICAgICAgICA8IS0tIEThuqV1IGhp4buHdSBDT05UQUlORVI6IG5ow6NuIGfDs2MgdHLDqm4tcGjhuqNpICsgdmnhu4FuIMSR4bupdCBiYW8gcnXhu5l0LiBLaMO0bmcgY8OzIGThuqV1IGhp4buHdSB0aMOsXG4gICAgICAgICAgICAgbmfGsOG7nWkgZMO5bmcga2jDtG5nIGJp4bq/dCBraOG7kWkgbsOgbyBjaOG7qWEgxJHGsOG7o2Mga2jhu5FpIGtow6FjIChjaOG7kXQgMjgvMDgvMjAyNiwgdGhlbyDEkcO6bmcgY8OhY2hcbiAgICAgICAgICAgICBtw6BuIEN1c3RvbWVyIDM2MCBj4bunYSBtb2Jpby13ZWIgxJFhbmcgbMOgbSkuIC0tPlxuICAgICAgICBAaWYgKGlzRWRpdE1vZGUoKSAmJiBpc0NvbnRhaW5lcihpdGVtKSkge1xuICAgICAgICAgIDxkaXYgY2xhc3M9XCJsaWJzLXVpLWdyaWQtbGF5b3V0LWNvbnRhaW5lci1sYWJlbFwiPnt7ICdpMThuX2NvbnRhaW5lcl9ibG9jaycgfCB0cmFuc2xhdGUgfX08L2Rpdj5cbiAgICAgICAgICA8ZGl2IGNsYXNzPVwibGlicy11aS1ncmlkLWxheW91dC1jb250YWluZXItYm9yZGVyXCI+PC9kaXY+XG4gICAgICAgIH1cblxuICAgICAgICA8IS0tIFRoYW5oIGPDtG5nIGPhu6U6IGhp4buHbiBraGkgcsOqIGNodeG7mXQgdsOgbyBraOG7kWkuXG4gICAgICAgICAgICAg8J+UtCBEw7luZyBgbGlic191aS1jb21wb25lbnRzLWJ1dHRvbnMtYnV0dG9uYCDigJQgQ+G6pE0gdOG7sSBk4buxbmcgdGjhursgYDxidXR0b24+YC5cbiAgICAgICAgICAgICBDb21wb25lbnQgbsOgeSDEkcOjIGPDsyBz4bq1biBraeG7g3UgbsO6dCwgY+G7oSBuw7p0IHbDoCBib25nIGLDs25nIGNow7ogdGjDrWNoIHRoZW8gxJHDum5nIGLhu5kgZ2lhbyBkaeG7h25cbiAgICAgICAgICAgICBj4bunYSBz4bqjbiBwaOG6qW07IHThu7EgZOG7sW5nIGzDoCBt4buXaSBuxqFpIG3hu5l0IGtp4buDdSB2w6AgbeG6pXQgbHXDtG4gdG9vbHRpcC4gLS0+XG4gICAgICAgIEBpZiAoaXNFZGl0TW9kZSgpICYmICFoaWRkZW5Ub29sYmFyKCkpIHtcbiAgICAgICAgICBAaWYgKHRlbXBsYXRlVG9vbGJhcigpKSB7XG4gICAgICAgICAgICA8IS0tIE7GoWkgZMO5bmcgdOG7sSB24bq9IHRoYW5oIGPDtG5nIGPhu6U6IG5o4bqtbiBraOG7kWkgKyBjw6FjIGjDoG0gcGjDoXQgZXZlbnQgcXVhIGNvbnRleHQuXG5cbiAgICAgICAgICAgICAgICAg8J+UtCBLaOG7kWkgYuG7jWMgdOG7sSBjaOG6t24gYG1vdXNlZG93bmAvYGNsaWNrYCBu4buVaSBsw6puIGdyaWRzdGVyLiBUaGFuaCBjw7RuZyBj4bulIG7hurFtIHRyb25nXG4gICAgICAgICAgICAgICAgIHbDuW5nIG1hbmcgYGRyYWdIYW5kbGVDbGFzc2A7IGtow7RuZyBjaOG6t24gdGjDrCBjw7ogYuG6pW0gYuG7iyBoaeG7g3UgbMOgIGLhuq90IMSR4bqndSBrw6lvIHbDoFxuICAgICAgICAgICAgICAgICBgZGVsYXlTdGFydDogMTYwYCBudeG7kXQgbHXDtG4gYGNsaWNrYCDigJQgbsO6dCB0cm9uZyB0ZW1wbGF0ZSBuZ2/DoGkgYuG6pW0ga2jDtG5nIMSDblxuICAgICAgICAgICAgICAgICAoxJFvIDA5LzA5LzIwMjY6IGLhuqVtIGLhurFuZyBgLmNsaWNrKClgIGPhu6dhIERPTSB0aMOsIG3hu58sIGLhuqVtIGNodeG7mXQgdGjhuq10IHRow6wga2jDtG5nKS5cbiAgICAgICAgICAgICAgICAgQ2jhurduIOG7nyDEkMOCWSDEkeG7gyBuxqFpIGTDuW5nIGtow7RuZyBwaOG6o2kgYmnhur90IGLhuqt5IG7DoHkuIC0tPlxuICAgICAgICAgICAgPGRpdlxuICAgICAgICAgICAgICBjbGFzcz1cImxpYnMtdWktZ3JpZC1sYXlvdXQtdG9vbGJhclwiXG4gICAgICAgICAgICAgIHJvbGU9XCJ0b29sYmFyXCJcbiAgICAgICAgICAgICAgdGFiaW5kZXg9XCIwXCJcbiAgICAgICAgICAgICAgW2NsYXNzLmxpYnMtdWktZ3JpZC1sYXlvdXQtdG9vbGJhci1jaGlsZF09XCJpc05lc3RlZENhbnZhcygpXCJcbiAgICAgICAgICAgICAgKG1vdXNlZG93bik9XCJoYW5kbGVyU3RvcEV2ZW50KCRldmVudClcIlxuICAgICAgICAgICAgICAoa2V5ZG93bik9XCJoYW5kbGVyU3RvcEV2ZW50KCRldmVudClcIlxuICAgICAgICAgICAgICAoY2xpY2spPVwiaGFuZGxlclN0b3BFdmVudCgkZXZlbnQpXCI+XG4gICAgICAgICAgICAgIDxuZy1jb250YWluZXJcbiAgICAgICAgICAgICAgICAqbmdUZW1wbGF0ZU91dGxldD1cInRlbXBsYXRlVG9vbGJhcigpITsgY29udGV4dDogdG9vbGJhckNvbnRleHRzKClbaXRlbUluZGV4XVwiIC8+XG4gICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICB9IEBlbHNlIHtcbiAgICAgICAgICAgIDxkaXZcbiAgICAgICAgICAgICAgY2xhc3M9XCJsaWJzLXVpLWdyaWQtbGF5b3V0LXRvb2xiYXJcIlxuICAgICAgICAgICAgICBbY2xhc3MubGlicy11aS1ncmlkLWxheW91dC10b29sYmFyLWNoaWxkXT1cImlzTmVzdGVkQ2FudmFzKClcIj5cbiAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJsaWJzLXVpLWdyaWQtbGF5b3V0LWRpbS1iYWRnZVwiPlxuICAgICAgICAgICAgICAgIHt7IGl0ZW0ucm93cyB9fSBow6BuZyDDlyB7eyBpdGVtLmNvbHMgfX0gY+G7mXRcbiAgICAgICAgICAgICAgPC9zcGFuPlxuICAgICAgICAgICAgICBAaWYgKGNhbkFkZEluc2lkZShpdGVtKSkge1xuICAgICAgICAgICAgICAgIDxsaWJzX3VpLWNvbXBvbmVudHMtYnV0dG9ucy1idXR0b25cbiAgICAgICAgICAgICAgICAgIFt0eXBlXT1cIididXR0b24tdGhpcmQnXCJcbiAgICAgICAgICAgICAgICAgIFtpY29uT25seVR5cGVdPVwidHJ1ZVwiXG4gICAgICAgICAgICAgICAgICBbc2l6ZUJ1dHRvbl09XCInc21hbGxlcidcIlxuICAgICAgICAgICAgICAgICAgW2NsYXNzSWNvbkxlZnRdPVwiJ2xpYnMtdWktaWNvbi1hZGQnXCJcbiAgICAgICAgICAgICAgICAgIFtwb3BvdmVyXT1cInsgY29uZmlnOiB7IGNvbnRlbnQ6ICdUaMOqbSBraOG7kWkgdsOgbyB0cm9uZycsIHpJbmRleDogMTMwMCB9IH1cIlxuICAgICAgICAgICAgICAgICAgKG91dENsaWNrKT1cImhhbmRsZXJBZGRJbnNpZGUoJGV2ZW50LCBpdGVtKVwiIC8+XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgQGlmIChjYW5Ub2dnbGVUeXBlKGl0ZW0pKSB7XG4gICAgICAgICAgICAgICAgPGxpYnNfdWktY29tcG9uZW50cy1idXR0b25zLWJ1dHRvblxuICAgICAgICAgICAgICAgICAgW3R5cGVdPVwiJ2J1dHRvbi10aGlyZCdcIlxuICAgICAgICAgICAgICAgICAgW2ljb25Pbmx5VHlwZV09XCJ0cnVlXCJcbiAgICAgICAgICAgICAgICAgIFtzaXplQnV0dG9uXT1cIidzbWFsbGVyJ1wiXG4gICAgICAgICAgICAgICAgICBbY2xhc3NJY29uTGVmdF09XCJpc0NvbnRhaW5lcihpdGVtKSA/ICdsaWJzLXVpLWljb24tc3BsaXQtY2VsbCcgOiAnbGlicy11aS1pY29uLW1lcmdlLWNlbGwnXCJcbiAgICAgICAgICAgICAgICAgIFtwb3BvdmVyXT1cInsgY29uZmlnOiB7IGNvbnRlbnQ6IGlzQ29udGFpbmVyKGl0ZW0pID8gJ8SQxrBhIHbhu4Ega2jhu5FpIMSRxqFuJyA6ICdDaHV54buDbiB0aMOgbmgga2jhu5FpIGdow6lwJywgekluZGV4OiAxMzAwIH0gfVwiXG4gICAgICAgICAgICAgICAgICAob3V0Q2xpY2spPVwiaGFuZGxlclRvZ2dsZVR5cGUoJGV2ZW50LCBpdGVtKVwiIC8+XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgPGxpYnNfdWktY29tcG9uZW50cy1idXR0b25zLWJ1dHRvblxuICAgICAgICAgICAgICAgIFt0eXBlXT1cIididXR0b24tdGhpcmQnXCJcbiAgICAgICAgICAgICAgICBbaWNvbk9ubHlUeXBlXT1cInRydWVcIlxuICAgICAgICAgICAgICAgIFtzaXplQnV0dG9uXT1cIidzbWFsbGVyJ1wiXG4gICAgICAgICAgICAgICAgW2NsYXNzSWNvbkxlZnRdPVwiJ2xpYnMtdWktaWNvbi1zZXR0aW5nJ1wiXG4gICAgICAgICAgICAgICAgW3BvcG92ZXJdPVwieyBjb25maWc6IHsgY29udGVudDogJ0PhuqV1IGjDrG5oIHRo4bq7JywgekluZGV4OiAxMzAwIH0gfVwiXG4gICAgICAgICAgICAgICAgKG91dENsaWNrKT1cImhhbmRsZXJDb25maWcoJGV2ZW50LCBpdGVtKVwiIC8+XG4gICAgICAgICAgICAgIDxsaWJzX3VpLWNvbXBvbmVudHMtYnV0dG9ucy1idXR0b25cbiAgICAgICAgICAgICAgICBbdHlwZV09XCInYnV0dG9uLXRoaXJkLWhvdmVyLWRhbmdlcidcIlxuICAgICAgICAgICAgICAgIFtpY29uT25seVR5cGVdPVwidHJ1ZVwiXG4gICAgICAgICAgICAgICAgW3NpemVCdXR0b25dPVwiJ3NtYWxsZXInXCJcbiAgICAgICAgICAgICAgICBbY2xhc3NJY29uTGVmdF09XCInbGlicy11aS1pY29uLXJlbW92ZSdcIlxuICAgICAgICAgICAgICAgIFtwb3BvdmVyXT1cInsgY29uZmlnOiB7IGNvbnRlbnQ6IGlzQ29udGFpbmVyKGl0ZW0pID8gJ1hvw6EgY+G6oyBraOG7kWkgZ2jDqXAnIDogJ1hvw6Ega2jhu5FpJywgekluZGV4OiAxMzAwIH0gfVwiXG4gICAgICAgICAgICAgICAgKG91dENsaWNrKT1cImhhbmRsZXJSZW1vdmUoJGV2ZW50LCBpdGVtKVwiIC8+XG4gICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBAaWYgKGl0ZW0uY2hpbGRyZW4gJiYgaXRlbS5jaGlsZHJlbi5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgPCEtLSBLaOG7kWkgY8OzIGNvbiDihpIgcnXhu5l0IG7DsyBs4bqhaSBsw6AgbeG7mXQgbeG6t3QgcGjhurNuZyBu4buvYS4gxJDhu4cgcXV5IOG7nyDEkcOieSwgbsahaSBkw7luZyBraMO0bmcgcGjhuqNpIGxvLlxuICAgICAgICAgICAgICAgTOG7gSDEkeG6t3Qg4bufIMSQw4JZICh24buPIGNvbnRhaW5lciksIGtow7RuZyDEkeG6t3QgdsOgbyBsxrDhu5tpIGNvbiDigJQgbMaw4bubaSBjb24gZ2nhu68gbmd1ecOqbiBraGUgMnB4LiAtLT5cbiAgICAgICAgICA8bGlic191aS1zZXJ2aWNlcy1ncmlkX2xheW91dC1jYW52YXNcbiAgICAgICAgICAgIGNsYXNzPVwiYmxvY2sgaC1mdWxsIHctZnVsbFwiXG4gICAgICAgICAgICBbc3R5bGUucGFkZGluZ109XCJjb250YWluZXJQYWRkaW5nKClcIlxuICAgICAgICAgICAgW25vZGVdPVwiaXRlbVwiXG4gICAgICAgICAgICBbZGVwdGhdPVwiZGVwdGgoKSArIDFcIlxuICAgICAgICAgICAgW2hpZGRlblRvb2xiYXJdPVwiaGlkZGVuVG9vbGJhcigpXCJcbiAgICAgICAgICAgIFt0ZW1wbGF0ZVRvb2xiYXJdPVwidGVtcGxhdGVUb29sYmFyKClcIlxuICAgICAgICAgICAgW3NlbGVjdGVkTm9kZUlkXT1cInNlbGVjdGVkTm9kZUlkKClcIlxuICAgICAgICAgICAgKG91dFNlbGVjdE5vZGUpPVwib3V0U2VsZWN0Tm9kZS5lbWl0KCRldmVudClcIlxuICAgICAgICAgICAgKG91dENvbmZpZ05vZGUpPVwib3V0Q29uZmlnTm9kZS5lbWl0KCRldmVudClcIlxuICAgICAgICAgICAgKG91dENoYW5nZSk9XCJvdXRDaGFuZ2UuZW1pdCgkZXZlbnQpXCJcbiAgICAgICAgICAgIChvdXRSZW1vdmVOb2RlKT1cIm91dFJlbW92ZU5vZGUuZW1pdCgkZXZlbnQpXCJcbiAgICAgICAgICAgIChvdXRBZGRCbG9ja0luc2lkZSk9XCJvdXRBZGRCbG9ja0luc2lkZS5lbWl0KCRldmVudClcIlxuICAgICAgICAgICAgKG91dFRvZ2dsZVR5cGUpPVwib3V0VG9nZ2xlVHlwZS5lbWl0KCRldmVudClcIiAvPlxuICAgICAgICB9XG4gICAgICA8L2Rpdj5cbiAgICA8L2dyaWRzdGVyLWl0ZW0+XG4gIH1cbiAgICA8L2dyaWRzdGVyPlxuICA8L2Rpdj5cbn1cbiJdfQ==
|