@recruitler/drag-drop
Version:
A forked version of Angular/'s drag-drop CDK.
171 lines • 33.1 kB
JavaScript
import { NgFor, NgIf, NgStyle, NgTemplateOutlet } from '@angular/common';
import { Component, EventEmitter, HostListener, Input, Output, ViewChild, ViewChildren, ViewEncapsulation, } from '@angular/core';
import { NgClass } from '@angular/common';
import { asapScheduler } from 'rxjs';
import { CdkDrag } from '../../directives/drag';
import { CdkDragHandle } from '../../directives/drag-handle';
import { CdkDragPlaceholder } from '../../directives/drag-placeholder';
import { CdkDragPreview } from '../../directives/drag-preview';
import { CdkDropList } from '../../directives/drop-list';
import { CdkDropListGroup } from '../../directives/drop-list-group';
import { DragDrop } from '../../drag-drop';
import { transferArrayItem } from '../../drag-utils';
import { getParent } from '../../drag-drop-tree';
import * as i0 from "@angular/core";
// unused?
const TAG = 'nested-drag-drop.component.ts';
// Drag&Drop connected sorting group
export class CdkNestedDragDropComponent {
itemTreeList = [];
itemTemplate;
placeholderTemplate;
pageMode = 'PAGINATION';
style_height = '100%';
dropped = new EventEmitter();
scrollNextPage = new EventEmitter();
scrollBox;
scrollGap;
scrollContent;
dlq;
dropLists = [];
dropGutterSize = 0;
isLoading = false;
showGap = true;
onScroll(event) {
if (this.pageMode == 'VIRTUAL-SCROLL') {
if (!this.isLoading &&
this.showGap &&
document.scrollingElement &&
document.scrollingElement?.scrollHeight -
document.scrollingElement?.scrollTop <=
document.scrollingElement?.clientHeight + 1) {
this.isLoading = true;
this.scrollNextPage.emit(event);
}
}
}
constructor() { }
ngAfterViewInit() {
const ldls = [];
this.dlq.forEach((dl) => {
ldls.push(dl);
});
asapScheduler.schedule(() => {
this.dropLists = ldls;
});
}
ngAfterContentChecked() {
if (this.pageMode == 'VIRTUAL-SCROLL') {
this.showGap = true;
}
else if (this.pageMode == 'PAGINATION') {
this.showGap = false;
}
}
drop(event) {
let prevListData = event.previousContainer.data;
let curListData = event.container.data;
const previousIndex = prevListData.length > 0 && prevListData[0]['_isEmpty'] == true
? event.previousIndex + 1
: event.previousIndex;
const currentIndex = curListData.length > 0 && curListData[0]['_isEmpty'] == true
? event.currentIndex + 1
: event.currentIndex;
let nestIndex = -1;
let nestInfo = event.nestInfo;
if (nestInfo &&
nestInfo.nestIndex < curListData.length &&
nestInfo.nestIndex >= 0) {
nestIndex = nestInfo.nestIndex;
curListData.length > 0 &&
curListData[0]['_isEmpty'] == true &&
(nestIndex = nestIndex + 1);
}
if (nestIndex >= 0) {
let targetItem = curListData[nestIndex];
let targetChildren = targetItem?.children ? targetItem.children : [];
// BEGIN OF SENDING MESSAGE
this.dropped.emit({
item: prevListData[previousIndex],
parent: targetItem,
position: targetChildren.length,
isNesting: true,
});
// END OF SENDING MESSAGE
transferArrayItem(prevListData, targetChildren, previousIndex, targetChildren.length);
targetItem.children = targetChildren;
}
else {
// BEGIN OF SENDING MESSAGE
const parent = getParent(this.itemTreeList, curListData);
this.dropped.emit({
item: prevListData[previousIndex],
parent: parent,
position: currentIndex,
isNesting: false,
});
// END OF SENDING MESSAGE
transferArrayItem(prevListData, curListData, previousIndex, currentIndex);
}
}
nest(event) { }
getDropGutterSize() {
this.dropGutterSize = 0;
return 0;
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.7", ngImport: i0, type: CdkNestedDragDropComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.0.7", type: CdkNestedDragDropComponent, isStandalone: true, selector: "nested-drag-drop", inputs: { itemTreeList: ["cdkNestedDropDownData", "itemTreeList"], itemTemplate: ["cdkListItemTemplate", "itemTemplate"], placeholderTemplate: ["cdkPlaceholderTemplate", "placeholderTemplate"], pageMode: ["cdkPageMode", "pageMode"], style_height: ["height", "style_height"] }, outputs: { dropped: "cdkDragDropped", scrollNextPage: "cdkScrollNextPage" }, host: { listeners: { "window:scroll": "onScroll($event)" } }, providers: [DragDrop], viewQueries: [{ propertyName: "scrollBox", first: true, predicate: ["scrollBox"], descendants: true }, { propertyName: "scrollGap", first: true, predicate: ["scrollGap"], descendants: true }, { propertyName: "scrollContent", first: true, predicate: ["scrollContent"], descendants: true }, { propertyName: "dlq", predicate: CdkDropList, descendants: true }], ngImport: i0, template: "<!-- <lib-pagination [pagination]=\"pagination\" [navigate]=\"false\" [loading]=\"false\" (pageUpdate)=\"onPageUpdate($event)\" /> -->\n\n<div #scrollBox class=\"scroll-box\" (scroll)=\"onScroll($event)\" [ngStyle]=\"{ height: style_height }\">\n <div #scrollContent cdkDropListGroup [cdkDropGutterSize]=\"getDropGutterSize()\">\n <ng-template #recursiveList let-items>\n <div\n class=\"cdk-nest-dragdrop-list\"\n cdkDropList\n [cdkDropListData]=\"items\"\n (cdkDropListDropped)=\"drop($event)\"\n (cdkDropListNested)=\"nest($event)\"\n [cdkDropListConnectedTo]=\"dropLists\"\n [cdkDropListNestEnabled]=\"true\">\n @for (item of items; let i = $index; track 'key' + i) { \n @if (item?._isEmpty == undefined) { \n <div cdkDrag class=\"cdk-nest-dragdrop-item\" [cdkDragDisabled]=\"item.draggingDisabled\">\n <div *cdkDragPlaceholder>\n <ng-container *ngTemplateOutlet=\"placeholderTemplate;context: { $implicit: item }\" />\n </div>\n \n @defer (on viewport) { \n @defer(on idle) {\n <ng-container *ngTemplateOutlet=\"itemTemplate; context: { $implicit: item }\" />\n } @placeholder {\n <span>Loading...</span>\n } \n } @placeholder {\n <span>Loading...</span>\n }\n \n @if (item.children && !!item.children.length) {\n <div class=\"cdk-nest-dragdrop-sublist\" [ngStyle]=\"{ 'padding-top.px': 0 }\">\n <ng-container *ngTemplateOutlet=\"recursiveList; context: { $implicit: item.children } \" />\n </div>\n }\n </div>\n }\n \n @if (item?._isEmpty) { \n <div class=\"cdk-nest-dragdrop-item\" [ngStyle]=\"{ 'padding-top.px': 0 }\">\n @if (item.children && !!item.children.length) {\n <div class=\"cdk-nest-dragdrop-sublist\" [ngStyle]=\"{ 'padding-top.px': 0 }\">\n <ng-container *ngTemplateOutlet=\"recursiveList; context: { $implicit: item.children } \" />\n </div>\n }\n </div>\n }\n }\n </div>\n </ng-template>\n <ng-container *ngTemplateOutlet=\"recursiveList; context: { $implicit: itemTreeList }\" />\n </div>\n\n <!-- SCROLL GAP BOX -->\n @if (showGap) {\n <div #scrollGap class=\"scroll-gap\"></div>\n }\n</div>\n\n<!--\nCopyright 2019 Google Inc. All Rights Reserved.\nUse of this source code is governed by an MIT-style license that\ncan be found in the LICENSE file at http://angular.io/license\n-->", styles: [".cdk-nest-dragdrop-list{overflow:hidden;display:block}.cdk-nest-dragdrop-item{padding:20px 30px;color:#000000de;flex-direction:row;align-items:center;justify-content:space-between;box-sizing:border-box;cursor:move;font-size:14px}.cdk-nest-dragdrop-sublist{padding-top:15px}.cdk-nest-dragdrop-item:last-child{border:none}.cdk-drop-list-dragging .cdk-drag,.cdk-drag-animating{transition:transform .5s cubic-bezier(0,0,.2,1)}.cdk-drag-placeholder{transition:all .2s ease-in-out}.cdk-drag-placeholder-hidden{opacity:0}.scroll-box{width:100%;overflow:auto}.scroll-gap{height:100px;opacity:0}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListNestEnabled", "cdkDropListNestThreshold"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListNested", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: CdkDropListGroup, selector: "[cdkDropListGroup]", inputs: ["cdkDropGutterSize", "cdkDropListGroupDisabled"], exportAs: ["cdkDropListGroup"] }, { kind: "directive", type: CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: CdkDragPlaceholder, selector: "ng-template[cdkDragPlaceholder]", inputs: ["data"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }], encapsulation: i0.ViewEncapsulation.None });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.7", ngImport: i0, type: CdkNestedDragDropComponent, decorators: [{
type: Component,
args: [{ selector: 'nested-drag-drop', standalone: true, providers: [DragDrop], imports: [
NgFor,
NgIf,
NgTemplateOutlet,
CdkDropList,
CdkDropListGroup,
CdkDrag,
CdkDragHandle,
CdkDragPreview,
CdkDragPlaceholder,
NgClass,
NgStyle,
], encapsulation: ViewEncapsulation.None, template: "<!-- <lib-pagination [pagination]=\"pagination\" [navigate]=\"false\" [loading]=\"false\" (pageUpdate)=\"onPageUpdate($event)\" /> -->\n\n<div #scrollBox class=\"scroll-box\" (scroll)=\"onScroll($event)\" [ngStyle]=\"{ height: style_height }\">\n <div #scrollContent cdkDropListGroup [cdkDropGutterSize]=\"getDropGutterSize()\">\n <ng-template #recursiveList let-items>\n <div\n class=\"cdk-nest-dragdrop-list\"\n cdkDropList\n [cdkDropListData]=\"items\"\n (cdkDropListDropped)=\"drop($event)\"\n (cdkDropListNested)=\"nest($event)\"\n [cdkDropListConnectedTo]=\"dropLists\"\n [cdkDropListNestEnabled]=\"true\">\n @for (item of items; let i = $index; track 'key' + i) { \n @if (item?._isEmpty == undefined) { \n <div cdkDrag class=\"cdk-nest-dragdrop-item\" [cdkDragDisabled]=\"item.draggingDisabled\">\n <div *cdkDragPlaceholder>\n <ng-container *ngTemplateOutlet=\"placeholderTemplate;context: { $implicit: item }\" />\n </div>\n \n @defer (on viewport) { \n @defer(on idle) {\n <ng-container *ngTemplateOutlet=\"itemTemplate; context: { $implicit: item }\" />\n } @placeholder {\n <span>Loading...</span>\n } \n } @placeholder {\n <span>Loading...</span>\n }\n \n @if (item.children && !!item.children.length) {\n <div class=\"cdk-nest-dragdrop-sublist\" [ngStyle]=\"{ 'padding-top.px': 0 }\">\n <ng-container *ngTemplateOutlet=\"recursiveList; context: { $implicit: item.children } \" />\n </div>\n }\n </div>\n }\n \n @if (item?._isEmpty) { \n <div class=\"cdk-nest-dragdrop-item\" [ngStyle]=\"{ 'padding-top.px': 0 }\">\n @if (item.children && !!item.children.length) {\n <div class=\"cdk-nest-dragdrop-sublist\" [ngStyle]=\"{ 'padding-top.px': 0 }\">\n <ng-container *ngTemplateOutlet=\"recursiveList; context: { $implicit: item.children } \" />\n </div>\n }\n </div>\n }\n }\n </div>\n </ng-template>\n <ng-container *ngTemplateOutlet=\"recursiveList; context: { $implicit: itemTreeList }\" />\n </div>\n\n <!-- SCROLL GAP BOX -->\n @if (showGap) {\n <div #scrollGap class=\"scroll-gap\"></div>\n }\n</div>\n\n<!--\nCopyright 2019 Google Inc. All Rights Reserved.\nUse of this source code is governed by an MIT-style license that\ncan be found in the LICENSE file at http://angular.io/license\n-->", styles: [".cdk-nest-dragdrop-list{overflow:hidden;display:block}.cdk-nest-dragdrop-item{padding:20px 30px;color:#000000de;flex-direction:row;align-items:center;justify-content:space-between;box-sizing:border-box;cursor:move;font-size:14px}.cdk-nest-dragdrop-sublist{padding-top:15px}.cdk-nest-dragdrop-item:last-child{border:none}.cdk-drop-list-dragging .cdk-drag,.cdk-drag-animating{transition:transform .5s cubic-bezier(0,0,.2,1)}.cdk-drag-placeholder{transition:all .2s ease-in-out}.cdk-drag-placeholder-hidden{opacity:0}.scroll-box{width:100%;overflow:auto}.scroll-gap{height:100px;opacity:0}\n"] }]
}], ctorParameters: () => [], propDecorators: { itemTreeList: [{
type: Input,
args: ['cdkNestedDropDownData']
}], itemTemplate: [{
type: Input,
args: ['cdkListItemTemplate']
}], placeholderTemplate: [{
type: Input,
args: ['cdkPlaceholderTemplate']
}], pageMode: [{
type: Input,
args: ['cdkPageMode']
}], style_height: [{
type: Input,
args: ['height']
}], dropped: [{
type: Output,
args: ['cdkDragDropped']
}], scrollNextPage: [{
type: Output,
args: ['cdkScrollNextPage']
}], scrollBox: [{
type: ViewChild,
args: ['scrollBox']
}], scrollGap: [{
type: ViewChild,
args: ['scrollGap']
}], scrollContent: [{
type: ViewChild,
args: ['scrollContent']
}], dlq: [{
type: ViewChildren,
args: [CdkDropList]
}], onScroll: [{
type: HostListener,
args: ['window:scroll', ['$event']]
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmVzdGVkLWRyYWctZHJvcC5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9zb3J0YWJsZS9zcmMvbGliL2RyYWctZHJvcC9jb21wb25lbnRzL3RyZWUtY29tcG9uZW50L25lc3RlZC1kcmFnLWRyb3AuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvc29ydGFibGUvc3JjL2xpYi9kcmFnLWRyb3AvY29tcG9uZW50cy90cmVlLWNvbXBvbmVudC9uZXN0ZWQtZHJhZy1kcm9wLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxLQUFLLEVBQUUsSUFBSSxFQUFFLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQ3pFLE9BQU8sRUFDTCxTQUFTLEVBRVQsWUFBWSxFQUNaLFlBQVksRUFDWixLQUFLLEVBQ0wsTUFBTSxFQUdOLFNBQVMsRUFDVCxZQUFZLEVBQ1osaUJBQWlCLEdBQ2xCLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUMxQyxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBSXJDLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUNoRCxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sOEJBQThCLENBQUM7QUFDN0QsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sbUNBQW1DLENBQUM7QUFDdkUsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLCtCQUErQixDQUFDO0FBQy9ELE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUN6RCxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxrQ0FBa0MsQ0FBQztBQUNwRSxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0saUJBQWlC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QUNULFFBQVE7c0JBQTdCLEtBQUs7dUJBQUMsYUFBYTtnQkFDSCxZQUFZO3NCQUE1QixLQUFLO3VCQUFDLFFBQVE7Z0JBRW9CLE9BQU87c0JBQXpDLE1BQU07dUJBQUMsZ0JBQWdCO2dCQUNjLGNBQWM7c0JBQW5ELE1BQU07dUJBQUMsbUJBQW1CO2dCQUVILFNBQVM7c0JBQWhDLFNBQVM7dUJBQUMsV0FBVztnQkFDRSxTQUFTO3NCQUFoQyxTQUFTO3VCQUFDLFdBQVc7Z0JBQ00sYUFBYTtzQkFBeEMsU0FBUzt1QkFBQyxlQUFlO2dCQUVTLEdBQUc7c0JBQXJDLFlBQVk7dUJBQUMsV0FBVztnQkFPa0IsUUFBUTtzQkFBbEQsWUFBWTt1QkFBQyxlQUFlLEVBQUUsQ0FBQyxRQUFRLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBOZ0ZvciwgTmdJZiwgTmdTdHlsZSwgTmdUZW1wbGF0ZU91dGxldCB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XG5pbXBvcnQge1xuICBDb21wb25lbnQsXG4gIEVsZW1lbnRSZWYsXG4gIEV2ZW50RW1pdHRlcixcbiAgSG9zdExpc3RlbmVyLFxuICBJbnB1dCxcbiAgT3V0cHV0LFxuICBRdWVyeUxpc3QsXG4gIFRlbXBsYXRlUmVmLFxuICBWaWV3Q2hpbGQsXG4gIFZpZXdDaGlsZHJlbixcbiAgVmlld0VuY2Fwc3VsYXRpb24sXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgTmdDbGFzcyB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XG5pbXBvcnQgeyBhc2FwU2NoZWR1bGVyIH0gZnJvbSAncnhqcyc7XG5cbmltcG9ydCB7IENka0RyYWdEcm9wLCBDZGtEcmFnTmVzdCwgQ2RrTmVzdERyb3AgfSBmcm9tICcuLi8uLi9kcmFnLWV2ZW50cyc7XG5cbmltcG9ydCB7IENka0RyYWcgfSBmcm9tICcuLi8uLi9kaXJlY3RpdmVzL2RyYWcnO1xuaW1wb3J0IHsgQ2RrRHJhZ0hhbmRsZSB9IGZyb20gJy4uLy4uL2RpcmVjdGl2ZXMvZHJhZy1oYW5kbGUnO1xuaW1wb3J0IHsgQ2RrRHJhZ1BsYWNlaG9sZGVyIH0gZnJvbSAnLi4vLi4vZGlyZWN0aXZlcy9kcmFnLXBsYWNlaG9sZGVyJztcbmltcG9ydCB7IENka0RyYWdQcmV2aWV3IH0gZnJvbSAnLi4vLi4vZGlyZWN0aXZlcy9kcmFnLXByZXZpZXcnO1xuaW1wb3J0IHsgQ2RrRHJvcExpc3QgfSBmcm9tICcuLi8uLi9kaXJlY3RpdmVzL2Ryb3AtbGlzdCc7XG5pbXBvcnQgeyBDZGtEcm9wTGlzdEdyb3VwIH0gZnJvbSAnLi4vLi4vZGlyZWN0aXZlcy9kcm9wLWxpc3QtZ3JvdXAnO1xuaW1wb3J0IHsgRHJhZ0Ryb3AgfSBmcm9tICcuLi8uLi9kcmFnLWRyb3AnO1xuaW1wb3J0IHsgdHJhbnNmZXJBcnJheUl0ZW0gfSBmcm9tICcuLi8uLi9kcmFnLXV0aWxzJztcblxuZXhwb3J0IHR5cGUgSVBhZ2VNb2RlID0gJ1ZJUlRVQUwtU0NST0xMJyB8ICdQQUdJTkFUSU9OJztcblxuaW1wb3J0IHsgQ2RrRHJvcERvd25JdGVtLCBnZXRQYXJlbnQgfSBmcm9tICcuLi8uLi9kcmFnLWRyb3AtdHJlZSc7XG5cbi8vIHVudXNlZD9cbmNvbnN0IFRBRyA9ICduZXN0ZWQtZHJhZy1kcm9wLmNvbXBvbmVudC50cyc7XG5cbi8vIERyYWcmRHJvcCBjb25uZWN0ZWQgc29ydGluZyBncm91cFxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnbmVzdGVkLWRyYWctZHJvcCcsXG4gIHRlbXBsYXRlVXJsOiAnLi9uZXN0ZWQtZHJhZy1kcm9wLmNvbXBvbmVudC5odG1sJyxcbiAgc3R5bGVVcmxzOiBbJ25lc3RlZC1kcmFnLWRyb3AuY29tcG9uZW50LnNjc3MnXSxcbiAgc3RhbmRhbG9uZTogdHJ1ZSxcbiAgcHJvdmlkZXJzOiBbRHJhZ0Ryb3BdLFxuICBpbXBvcnRzOiBbXG4gICAgTmdGb3IsXG4gICAgTmdJZixcbiAgICBOZ1RlbXBsYXRlT3V0bGV0LFxuICAgIENka0Ryb3BMaXN0LFxuICAgIENka0Ryb3BMaXN0R3JvdXAsXG4gICAgQ2RrRHJhZyxcbiAgICBDZGtEcmFnSGFuZGxlLFxuICAgIENka0RyYWdQcmV2aWV3LFxuICAgIENka0RyYWdQbGFjZWhvbGRlcixcbiAgICBOZ0NsYXNzLFxuICAgIE5nU3R5bGUsXG4gIF0sXG4gIGVuY2Fwc3VsYXRpb246IFZpZXdFbmNhcHN1bGF0aW9uLk5vbmUsXG59KVxuZXhwb3J0IGNsYXNzIENka05lc3RlZERyYWdEcm9wQ29tcG9uZW50IHtcbiAgQElucHV0KCdjZGtOZXN0ZWREcm9wRG93bkRhdGEnKWl0ZW1UcmVlTGlzdDogQ2RrRHJvcERvd25JdGVtW10gPSBbXTtcbiAgQElucHV0KCdjZGtMaXN0SXRlbVRlbXBsYXRlJylpdGVtVGVtcGxhdGUhOiBUZW1wbGF0ZVJlZjxhbnk+O1xuICBASW5wdXQoJ2Nka1BsYWNlaG9sZGVyVGVtcGxhdGUnKXBsYWNlaG9sZGVyVGVtcGxhdGUhOiBUZW1wbGF0ZVJlZjxhbnk+O1xuICBASW5wdXQoJ2Nka1BhZ2VNb2RlJykgcGFnZU1vZGU6IElQYWdlTW9kZSA9ICdQQUdJTkFUSU9OJztcbiAgQElucHV0KCdoZWlnaHQnKSBzdHlsZV9oZWlnaHQ6IHN0cmluZyA9ICcxMDAlJztcblxuICBAT3V0cHV0KCdjZGtEcmFnRHJvcHBlZCcpIHJlYWRvbmx5IGRyb3BwZWQ6IEV2ZW50RW1pdHRlcjxDZGtOZXN0RHJvcD4gPW5ldyBFdmVudEVtaXR0ZXI8Q2RrTmVzdERyb3A+KCk7XG4gIEBPdXRwdXQoJ2Nka1Njcm9sbE5leHRQYWdlJykgcmVhZG9ubHkgc2Nyb2xsTmV4dFBhZ2U6IEV2ZW50RW1pdHRlcjxhbnk+ID1uZXcgRXZlbnRFbWl0dGVyPGFueT4oKTtcblxuICBAVmlld0NoaWxkKCdzY3JvbGxCb3gnKSBzY3JvbGxCb3ghOiBFbGVtZW50UmVmPEhUTUxFbGVtZW50PjtcbiAgQFZpZXdDaGlsZCgnc2Nyb2xsR2FwJykgc2Nyb2xsR2FwITogRWxlbWVudFJlZjxIVE1MRWxlbWVudD47XG4gIEBWaWV3Q2hpbGQoJ3Njcm9sbENvbnRlbnQnKSBzY3JvbGxDb250ZW50ITogRWxlbWVudFJlZjxIVE1MRWxlbWVudD47XG5cbiAgQFZpZXdDaGlsZHJlbihDZGtEcm9wTGlzdCkgcHJpdmF0ZSBkbHE6IFF1ZXJ5TGlzdDxDZGtEcm9wTGlzdD47XG5cbiAgZHJvcExpc3RzOiBDZGtEcm9wTGlzdFtdID0gW107XG4gIGRyb3BHdXR0ZXJTaXplID0gMDtcbiAgaXNMb2FkaW5nID0gZmFsc2U7XG4gIHNob3dHYXA6IGJvb2xlYW4gPSB0cnVlO1xuXG4gIEBIb3N0TGlzdGVuZXIoJ3dpbmRvdzpzY3JvbGwnLCBbJyRldmVudCddKSBvblNjcm9sbChldmVudDogRXZlbnQpIHtcbiAgICBpZiAodGhpcy5wYWdlTW9kZSA9PSAnVklSVFVBTC1TQ1JPTEwnKSB7XG4gICAgICBpZiAoXG4gICAgICAgICF0aGlzLmlzTG9hZGluZyAmJlxuICAgICAgICB0aGlzLnNob3dHYXAgJiZcbiAgICAgICAgZG9jdW1lbnQuc2Nyb2xsaW5nRWxlbWVudCAmJlxuICAgICAgICBkb2N1bWVudC5zY3JvbGxpbmdFbGVtZW50Py5zY3JvbGxIZWlnaHQgLVxuICAgICAgICAgIGRvY3VtZW50LnNjcm9sbGluZ0VsZW1lbnQ/LnNjcm9sbFRvcCA8PVxuICAgICAgICAgIGRvY3VtZW50LnNjcm9sbGluZ0VsZW1lbnQ/LmNsaWVudEhlaWdodCArIDFcbiAgICAgICkge1xuICAgICAgICB0aGlzLmlzTG9hZGluZyA9IHRydWU7XG4gICAgICAgIHRoaXMuc2Nyb2xsTmV4dFBhZ2UuZW1pdChldmVudCk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgY29uc3RydWN0b3IoKSB7IH1cblxuICBuZ0FmdGVyVmlld0luaXQoKSB7XG4gICAgY29uc3QgbGRsczogQ2RrRHJvcExpc3RbXSA9IFtdO1xuICAgIHRoaXMuZGxxLmZvckVhY2goKGRsKSA9PiB7XG4gICAgICBsZGxzLnB1c2goZGwpO1xuICAgIH0pO1xuXG4gICAgYXNhcFNjaGVkdWxlci5zY2hlZHVsZSgoKSA9PiB7XG4gICAgICB0aGlzLmRyb3BMaXN0cyA9IGxkbHM7XG4gICAgfSk7XG4gIH1cblxuICBuZ0FmdGVyQ29udGVudENoZWNrZWQoKSB7XG4gICAgaWYgKHRoaXMucGFnZU1vZGUgPT0gJ1ZJUlRVQUwtU0NST0xMJykge1xuICAgICAgdGhpcy5zaG93R2FwID0gdHJ1ZTtcbiAgICB9IGVsc2UgaWYgKHRoaXMucGFnZU1vZGUgPT0gJ1BBR0lOQVRJT04nKSB7XG4gICAgICB0aGlzLnNob3dHYXAgPSBmYWxzZTtcbiAgICB9XG4gIH1cblxuICBkcm9wKGV2ZW50OiBDZGtEcmFnRHJvcDxhbnk+KSB7XG4gICAgbGV0IHByZXZMaXN0RGF0YTogQ2RrRHJvcERvd25JdGVtW10gPSBldmVudC5wcmV2aW91c0NvbnRhaW5lci5kYXRhO1xuICAgIGxldCBjdXJMaXN0RGF0YTogQ2RrRHJvcERvd25JdGVtW10gPSBldmVudC5jb250YWluZXIuZGF0YTtcblxuICAgIGNvbnN0IHByZXZpb3VzSW5kZXggPVxuICAgICAgcHJldkxpc3REYXRhLmxlbmd0aCA+IDAgJiYgcHJldkxpc3REYXRhWzBdWydfaXNFbXB0eSddID09IHRydWVcbiAgICAgICAgPyBldmVudC5wcmV2aW91c0luZGV4ICsgMVxuICAgICAgICA6IGV2ZW50LnByZXZpb3VzSW5kZXg7XG4gICAgY29uc3QgY3VycmVudEluZGV4ID1cbiAgICAgIGN1ckxpc3REYXRhLmxlbmd0aCA+IDAgJiYgY3VyTGlzdERhdGFbMF1bJ19pc0VtcHR5J10gPT0gdHJ1ZVxuICAgICAgICA/IGV2ZW50LmN1cnJlbnRJbmRleCArIDFcbiAgICAgICAgOiBldmVudC5jdXJyZW50SW5kZXg7XG5cbiAgICBsZXQgbmVzdEluZGV4ID0gLTE7XG4gICAgbGV0IG5lc3RJbmZvID0gZXZlbnQubmVzdEluZm87XG5cbiAgICBpZiAoXG4gICAgICBuZXN0SW5mbyAmJlxuICAgICAgbmVzdEluZm8ubmVzdEluZGV4IDwgY3VyTGlzdERhdGEubGVuZ3RoICYmXG4gICAgICBuZXN0SW5mby5uZXN0SW5kZXggPj0gMFxuICAgICkge1xuICAgICAgbmVzdEluZGV4ID0gbmVzdEluZm8ubmVzdEluZGV4O1xuICAgICAgY3VyTGlzdERhdGEubGVuZ3RoID4gMCAmJlxuICAgICAgICBjdXJMaXN0RGF0YVswXVsnX2lzRW1wdHknXSA9PSB0cnVlICYmXG4gICAgICAgIChuZXN0SW5kZXggPSBuZXN0SW5kZXggKyAxKTtcbiAgICB9XG5cbiAgICBpZiAobmVzdEluZGV4ID49IDApIHtcbiAgICAgIGxldCB0YXJnZXRJdGVtID0gY3VyTGlzdERhdGFbbmVzdEluZGV4XTtcbiAgICAgIGxldCB0YXJnZXRDaGlsZHJlbiA9IHRhcmdldEl0ZW0/LmNoaWxkcmVuID8gdGFyZ2V0SXRlbS5jaGlsZHJlbiA6IFtdO1xuXG4gICAgICAvLyBCRUdJTiBPRiBTRU5ESU5HIE1FU1NBR0VcbiAgICAgIHRoaXMuZHJvcHBlZC5lbWl0KHtcbiAgICAgICAgaXRlbTogcHJldkxpc3REYXRhW3ByZXZpb3VzSW5kZXhdLFxuICAgICAgICBwYXJlbnQ6IHRhcmdldEl0ZW0sXG4gICAgICAgIHBvc2l0aW9uOiB0YXJnZXRDaGlsZHJlbi5sZW5ndGgsXG4gICAgICAgIGlzTmVzdGluZzogdHJ1ZSxcbiAgICAgIH0pO1xuICAgICAgLy8gRU5EIE9GIFNFTkRJTkcgTUVTU0FHRVxuXG4gICAgICB0cmFuc2ZlckFycmF5SXRlbShcbiAgICAgICAgcHJldkxpc3REYXRhLFxuICAgICAgICB0YXJnZXRDaGlsZHJlbixcbiAgICAgICAgcHJldmlvdXNJbmRleCxcbiAgICAgICAgdGFyZ2V0Q2hpbGRyZW4ubGVuZ3RoXG4gICAgICApO1xuICAgICAgdGFyZ2V0SXRlbS5jaGlsZHJlbiA9IHRhcmdldENoaWxkcmVuO1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBCRUdJTiBPRiBTRU5ESU5HIE1FU1NBR0VcbiAgICAgIGNvbnN0IHBhcmVudCA9IGdldFBhcmVudCh0aGlzLml0ZW1UcmVlTGlzdCwgY3VyTGlzdERhdGEpO1xuICAgICAgdGhpcy5kcm9wcGVkLmVtaXQoe1xuICAgICAgICBpdGVtOiBwcmV2TGlzdERhdGFbcHJldmlvdXNJbmRleF0sXG4gICAgICAgIHBhcmVudDogcGFyZW50LFxuICAgICAgICBwb3NpdGlvbjogY3VycmVudEluZGV4LFxuICAgICAgICBpc05lc3Rpbmc6IGZhbHNlLFxuICAgICAgfSk7XG4gICAgICAvLyBFTkQgT0YgU0VORElORyBNRVNTQUdFXG4gICAgICB0cmFuc2ZlckFycmF5SXRlbShwcmV2TGlzdERhdGEsIGN1ckxpc3REYXRhLCBwcmV2aW91c0luZGV4LCBjdXJyZW50SW5kZXgpO1xuICAgIH1cbiAgfVxuXG4gIG5lc3QoZXZlbnQ6IENka0RyYWdOZXN0PGFueT4pIHt9XG5cbiAgZ2V0RHJvcEd1dHRlclNpemUoKTogbnVtYmVyIHtcbiAgICB0aGlzLmRyb3BHdXR0ZXJTaXplID0gMDtcbiAgICByZXR1cm4gMDtcbiAgfVxufSIsIjwhLS0gPGxpYi1wYWdpbmF0aW9uIFtwYWdpbmF0aW9uXT1cInBhZ2luYXRpb25cIiBbbmF2aWdhdGVdPVwiZmFsc2VcIiBbbG9hZGluZ109XCJmYWxzZVwiIChwYWdlVXBkYXRlKT1cIm9uUGFnZVVwZGF0ZSgkZXZlbnQpXCIgLz4gLS0+XG5cbjxkaXYgI3Njcm9sbEJveCBjbGFzcz1cInNjcm9sbC1ib3hcIiAoc2Nyb2xsKT1cIm9uU2Nyb2xsKCRldmVudClcIiBbbmdTdHlsZV09XCJ7IGhlaWdodDogc3R5bGVfaGVpZ2h0IH1cIj5cbiAgPGRpdiAjc2Nyb2xsQ29udGVudCBjZGtEcm9wTGlzdEdyb3VwIFtjZGtEcm9wR3V0dGVyU2l6ZV09XCJnZXREcm9wR3V0dGVyU2l6ZSgpXCI+XG4gICAgPG5nLXRlbXBsYXRlICNyZWN1cnNpdmVMaXN0IGxldC1pdGVtcz5cbiAgICAgIDxkaXZcbiAgICAgICAgY2xhc3M9XCJjZGstbmVzdC1kcmFnZHJvcC1saXN0XCJcbiAgICAgICAgY2RrRHJvcExpc3RcbiAgICAgICAgW2Nka0Ryb3BMaXN0RGF0YV09XCJpdGVtc1wiXG4gICAgICAgIChjZGtEcm9wTGlzdERyb3BwZWQpPVwiZHJvcCgkZXZlbnQpXCJcbiAgICAgICAgKGNka0Ryb3BMaXN0TmVzdGVkKT1cIm5lc3QoJGV2ZW50KVwiXG4gICAgICAgIFtjZGtEcm9wTGlzdENvbm5lY3RlZFRvXT1cImRyb3BMaXN0c1wiXG4gICAgICAgIFtjZGtEcm9wTGlzdE5lc3RFbmFibGVkXT1cInRydWVcIj5cbiAgICAgICAgQGZvciAoaXRlbSBvZiBpdGVtczsgbGV0IGkgPSAkaW5kZXg7IHRyYWNrICdrZXknICsgaSkgeyAgXG4gICAgICAgICAgQGlmIChpdGVtPy5faXNFbXB0eSA9PSB1bmRlZmluZWQpIHsgIFxuICAgICAgICAgICAgPGRpdiBjZGtEcmFnIGNsYXNzPVwiY2RrLW5lc3QtZHJhZ2Ryb3AtaXRlbVwiIFtjZGtEcmFnRGlzYWJsZWRdPVwiaXRlbS5kcmFnZ2luZ0Rpc2FibGVkXCI+XG4gICAgICAgICAgICAgIDxkaXYgKmNka0RyYWdQbGFjZWhvbGRlcj5cbiAgICAgICAgICAgICAgICA8bmctY29udGFpbmVyICpuZ1RlbXBsYXRlT3V0bGV0PVwicGxhY2Vob2xkZXJUZW1wbGF0ZTtjb250ZXh0OiB7ICRpbXBsaWNpdDogaXRlbSB9XCIgLz5cbiAgICAgICAgICAgICAgPC9kaXY+XG4gIFxuICAgICAgICAgICAgICBAZGVmZXIgKG9uIHZpZXdwb3J0KSB7IFxuICAgICAgICAgICAgICAgIEBkZWZlcihvbiBpZGxlKSB7XG4gICAgICAgICAgICAgICAgICA8bmctY29udGFpbmVyICpuZ1RlbXBsYXRlT3V0bGV0PVwiaXRlbVRlbXBsYXRlOyBjb250ZXh0OiB7ICRpbXBsaWNpdDogaXRlbSB9XCIgLz5cbiAgICAgICAgICAgICAgICB9IEBwbGFjZWhvbGRlciB7XG4gICAgICAgICAgICAgICAgICA8c3Bhbj5Mb2FkaW5nLi4uPC9zcGFuPlxuICAgICAgICAgICAgICAgIH0gXG4gICAgICAgICAgICAgIH0gQHBsYWNlaG9sZGVyIHtcbiAgICAgICAgICAgICAgICA8c3Bhbj5Mb2FkaW5nLi4uPC9zcGFuPlxuICAgICAgICAgICAgICB9XG4gIFxuICAgICAgICAgICAgICBAaWYgKGl0ZW0uY2hpbGRyZW4gJiYgISFpdGVtLmNoaWxkcmVuLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJjZGstbmVzdC1kcmFnZHJvcC1zdWJsaXN0XCIgW25nU3R5bGVdPVwieyAncGFkZGluZy10b3AucHgnOiAwIH1cIj5cbiAgICAgICAgICAgICAgICAgIDxuZy1jb250YWluZXIgKm5nVGVtcGxhdGVPdXRsZXQ9XCJyZWN1cnNpdmVMaXN0OyBjb250ZXh0OiB7ICRpbXBsaWNpdDogaXRlbS5jaGlsZHJlbiB9IFwiIC8+XG4gICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgIH1cbiAgXG4gICAgICAgICAgQGlmIChpdGVtPy5faXNFbXB0eSkgeyAgXG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwiY2RrLW5lc3QtZHJhZ2Ryb3AtaXRlbVwiIFtuZ1N0eWxlXT1cInsgJ3BhZGRpbmctdG9wLnB4JzogMCB9XCI+XG4gICAgICAgICAgICAgIEBpZiAoaXRlbS5jaGlsZHJlbiAmJiAhIWl0ZW0uY2hpbGRyZW4ubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cImNkay1uZXN0LWRyYWdkcm9wLXN1Ymxpc3RcIiBbbmdTdHlsZV09XCJ7ICdwYWRkaW5nLXRvcC5weCc6IDAgfVwiPlxuICAgICAgICAgICAgICAgICAgPG5nLWNvbnRhaW5lciAqbmdUZW1wbGF0ZU91dGxldD1cInJlY3Vyc2l2ZUxpc3Q7IGNvbnRleHQ6IHsgJGltcGxpY2l0OiBpdGVtLmNoaWxkcmVuIH0gXCIgLz5cbiAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICA8L2Rpdj5cbiAgICA8L25nLXRlbXBsYXRlPlxuICAgIDxuZy1jb250YWluZXIgKm5nVGVtcGxhdGVPdXRsZXQ9XCJyZWN1cnNpdmVMaXN0OyBjb250ZXh0OiB7ICRpbXBsaWNpdDogaXRlbVRyZWVMaXN0IH1cIiAvPlxuICA8L2Rpdj5cblxuICA8IS0tIFNDUk9MTCBHQVAgQk9YIC0tPlxuICBAaWYgKHNob3dHYXApIHtcbiAgICA8ZGl2ICNzY3JvbGxHYXAgY2xhc3M9XCJzY3JvbGwtZ2FwXCI+PC9kaXY+XG4gIH1cbjwvZGl2PlxuXG48IS0tXG5Db3B5cmlnaHQgMjAxOSBHb29nbGUgSW5jLiBBbGwgUmlnaHRzIFJlc2VydmVkLlxuVXNlIG9mIHRoaXMgc291cmNlIGNvZGUgaXMgZ292ZXJuZWQgYnkgYW4gTUlULXN0eWxlIGxpY2Vuc2UgdGhhdFxuY2FuIGJlIGZvdW5kIGluIHRoZSBMSUNFTlNFIGZpbGUgYXQgaHR0cDovL2FuZ3VsYXIuaW8vbGljZW5zZVxuLS0+Il19