angular-resizable-element
Version:
An angular 15.0+ directive that allows an element to be dragged and resized
551 lines • 78.1 kB
JavaScript
import { Directive, Output, Input, EventEmitter, Inject, PLATFORM_ID, } from '@angular/core';
import { isPlatformBrowser } from '@angular/common';
import { Subject, Observable, merge } from 'rxjs';
import { map, mergeMap, takeUntil, filter, pairwise, take, share, tap, } from 'rxjs/operators';
import { IS_TOUCH_DEVICE } from './util/is-touch-device';
import { deepCloneNode } from './util/clone-node';
import * as i0 from "@angular/core";
function getNewBoundingRectangle(startingRect, edges, clientX, clientY) {
const newBoundingRect = {
top: startingRect.top,
bottom: startingRect.bottom,
left: startingRect.left,
right: startingRect.right,
};
if (edges.top) {
newBoundingRect.top += clientY;
}
if (edges.bottom) {
newBoundingRect.bottom += clientY;
}
if (edges.left) {
newBoundingRect.left += clientX;
}
if (edges.right) {
newBoundingRect.right += clientX;
}
newBoundingRect.height = newBoundingRect.bottom - newBoundingRect.top;
newBoundingRect.width = newBoundingRect.right - newBoundingRect.left;
return newBoundingRect;
}
function getElementRect(element, ghostElementPositioning) {
let translateX = 0;
let translateY = 0;
const style = element.nativeElement.style;
const transformProperties = [
'transform',
'-ms-transform',
'-moz-transform',
'-o-transform',
];
const transform = transformProperties
.map((property) => style[property])
.find((value) => !!value);
if (transform && transform.includes('translate')) {
translateX = transform.replace(/.*translate3?d?\((-?[0-9]*)px, (-?[0-9]*)px.*/, '$1');
translateY = transform.replace(/.*translate3?d?\((-?[0-9]*)px, (-?[0-9]*)px.*/, '$2');
}
if (ghostElementPositioning === 'absolute') {
return {
height: element.nativeElement.offsetHeight,
width: element.nativeElement.offsetWidth,
top: element.nativeElement.offsetTop - translateY,
bottom: element.nativeElement.offsetHeight +
element.nativeElement.offsetTop -
translateY,
left: element.nativeElement.offsetLeft - translateX,
right: element.nativeElement.offsetWidth +
element.nativeElement.offsetLeft -
translateX,
};
}
else {
const boundingRect = element.nativeElement.getBoundingClientRect();
return {
height: boundingRect.height,
width: boundingRect.width,
top: boundingRect.top - translateY,
bottom: boundingRect.bottom - translateY,
left: boundingRect.left - translateX,
right: boundingRect.right - translateX,
scrollTop: element.nativeElement.scrollTop,
scrollLeft: element.nativeElement.scrollLeft,
};
}
}
const DEFAULT_RESIZE_CURSORS = Object.freeze({
topLeft: 'nw-resize',
topRight: 'ne-resize',
bottomLeft: 'sw-resize',
bottomRight: 'se-resize',
leftOrRight: 'col-resize',
topOrBottom: 'row-resize',
});
function getResizeCursor(edges, cursors) {
if (edges.left && edges.top) {
return cursors.topLeft;
}
else if (edges.right && edges.top) {
return cursors.topRight;
}
else if (edges.left && edges.bottom) {
return cursors.bottomLeft;
}
else if (edges.right && edges.bottom) {
return cursors.bottomRight;
}
else if (edges.left || edges.right) {
return cursors.leftOrRight;
}
else if (edges.top || edges.bottom) {
return cursors.topOrBottom;
}
else {
return '';
}
}
function getEdgesDiff({ edges, initialRectangle, newRectangle, }) {
const edgesDiff = {};
Object.keys(edges).forEach((edge) => {
edgesDiff[edge] = (newRectangle[edge] || 0) - (initialRectangle[edge] || 0);
});
return edgesDiff;
}
const RESIZE_ACTIVE_CLASS = 'resize-active';
const RESIZE_GHOST_ELEMENT_CLASS = 'resize-ghost-element';
export const MOUSE_MOVE_THROTTLE_MS = 50;
/**
* Place this on an element to make it resizable. For example:
*
* ```html
* <div
* mwlResizable
* [resizeEdges]="{bottom: true, right: true, top: true, left: true}"
* [enableGhostResize]="true">
* </div>
* ```
* Or in case they are sibling elements:
* ```html
* <div mwlResizable #resizableElement="mwlResizable"></div>
* <div mwlResizeHandle [resizableContainer]="resizableElement" [resizeEdges]="{bottom: true, right: true}"></div>
* ```
*/
export class ResizableDirective {
/**
* @hidden
*/
constructor(platformId, renderer, elm, zone) {
this.platformId = platformId;
this.renderer = renderer;
this.elm = elm;
this.zone = zone;
/**
* Set to `true` to enable a temporary resizing effect of the element in between the `resizeStart` and `resizeEnd` events.
*/
this.enableGhostResize = false;
/**
* A snap grid that resize events will be locked to.
*
* e.g. to only allow the element to be resized every 10px set it to `{left: 10, right: 10}`
*/
this.resizeSnapGrid = {};
/**
* The mouse cursors that will be set on the resize edges
*/
this.resizeCursors = DEFAULT_RESIZE_CURSORS;
/**
* Define the positioning of the ghost element (can be fixed or absolute)
*/
this.ghostElementPositioning = 'fixed';
/**
* Allow elements to be resized to negative dimensions
*/
this.allowNegativeResizes = false;
/**
* The mouse move throttle in milliseconds, default: 50 ms
*/
this.mouseMoveThrottleMS = MOUSE_MOVE_THROTTLE_MS;
/**
* Called when the mouse is pressed and a resize event is about to begin. `$event` is a `ResizeEvent` object.
*/
this.resizeStart = new EventEmitter();
/**
* Called as the mouse is dragged after a resize event has begun. `$event` is a `ResizeEvent` object.
*/
this.resizing = new EventEmitter();
/**
* Called after the mouse is released after a resize event. `$event` is a `ResizeEvent` object.
*/
this.resizeEnd = new EventEmitter();
/**
* @hidden
*/
this.mouseup = new Subject();
/**
* @hidden
*/
this.mousedown = new Subject();
/**
* @hidden
*/
this.mousemove = new Subject();
this.destroy$ = new Subject();
this.pointerEventListeners = PointerEventListeners.getInstance(renderer, zone);
}
/**
* @hidden
*/
ngOnInit() {
const mousedown$ = merge(this.pointerEventListeners.pointerDown, this.mousedown);
const mousemove$ = merge(this.pointerEventListeners.pointerMove, this.mousemove).pipe(tap(({ event }) => {
if (currentResize && event.cancelable) {
event.preventDefault();
}
}), share());
const mouseup$ = merge(this.pointerEventListeners.pointerUp, this.mouseup);
let currentResize;
const removeGhostElement = () => {
if (currentResize && currentResize.clonedNode) {
this.elm.nativeElement.parentElement.removeChild(currentResize.clonedNode);
this.renderer.setStyle(this.elm.nativeElement, 'visibility', 'inherit');
}
};
const getResizeCursors = () => {
return {
...DEFAULT_RESIZE_CURSORS,
...this.resizeCursors,
};
};
const mousedrag = mousedown$
.pipe(mergeMap((startCoords) => {
function getDiff(moveCoords) {
return {
clientX: moveCoords.clientX - startCoords.clientX,
clientY: moveCoords.clientY - startCoords.clientY,
};
}
const getSnapGrid = () => {
const snapGrid = { x: 1, y: 1 };
if (currentResize) {
if (this.resizeSnapGrid.left && currentResize.edges.left) {
snapGrid.x = +this.resizeSnapGrid.left;
}
else if (this.resizeSnapGrid.right &&
currentResize.edges.right) {
snapGrid.x = +this.resizeSnapGrid.right;
}
if (this.resizeSnapGrid.top && currentResize.edges.top) {
snapGrid.y = +this.resizeSnapGrid.top;
}
else if (this.resizeSnapGrid.bottom &&
currentResize.edges.bottom) {
snapGrid.y = +this.resizeSnapGrid.bottom;
}
}
return snapGrid;
};
function getGrid(coords, snapGrid) {
return {
x: Math.ceil(coords.clientX / snapGrid.x),
y: Math.ceil(coords.clientY / snapGrid.y),
};
}
return merge(mousemove$.pipe(take(1)).pipe(map((coords) => [, coords])), mousemove$.pipe(pairwise()))
.pipe(map(([previousCoords, newCoords]) => {
return [
previousCoords ? getDiff(previousCoords) : previousCoords,
getDiff(newCoords),
];
}))
.pipe(filter(([previousCoords, newCoords]) => {
if (!previousCoords) {
return true;
}
const snapGrid = getSnapGrid();
const previousGrid = getGrid(previousCoords, snapGrid);
const newGrid = getGrid(newCoords, snapGrid);
return (previousGrid.x !== newGrid.x || previousGrid.y !== newGrid.y);
}))
.pipe(map(([, newCoords]) => {
const snapGrid = getSnapGrid();
return {
clientX: Math.round(newCoords.clientX / snapGrid.x) * snapGrid.x,
clientY: Math.round(newCoords.clientY / snapGrid.y) * snapGrid.y,
};
}))
.pipe(takeUntil(merge(mouseup$, mousedown$)));
}))
.pipe(filter(() => !!currentResize));
mousedrag
.pipe(map(({ clientX, clientY }) => {
return getNewBoundingRectangle(currentResize.startingRect, currentResize.edges, clientX, clientY);
}))
.pipe(filter((newBoundingRect) => {
return (this.allowNegativeResizes ||
!!(newBoundingRect.height &&
newBoundingRect.width &&
newBoundingRect.height > 0 &&
newBoundingRect.width > 0));
}))
.pipe(filter((newBoundingRect) => {
return this.validateResize
? this.validateResize({
rectangle: newBoundingRect,
edges: getEdgesDiff({
edges: currentResize.edges,
initialRectangle: currentResize.startingRect,
newRectangle: newBoundingRect,
}),
})
: true;
}), takeUntil(this.destroy$))
.subscribe((newBoundingRect) => {
if (currentResize && currentResize.clonedNode) {
this.renderer.setStyle(currentResize.clonedNode, 'height', `${newBoundingRect.height}px`);
this.renderer.setStyle(currentResize.clonedNode, 'width', `${newBoundingRect.width}px`);
this.renderer.setStyle(currentResize.clonedNode, 'top', `${newBoundingRect.top}px`);
this.renderer.setStyle(currentResize.clonedNode, 'left', `${newBoundingRect.left}px`);
}
if (this.resizing.observers.length > 0) {
this.zone.run(() => {
this.resizing.emit({
edges: getEdgesDiff({
edges: currentResize.edges,
initialRectangle: currentResize.startingRect,
newRectangle: newBoundingRect,
}),
rectangle: newBoundingRect,
});
});
}
currentResize.currentRect = newBoundingRect;
});
mousedown$
.pipe(map(({ edges }) => {
return edges || {};
}), filter((edges) => {
return Object.keys(edges).length > 0;
}), takeUntil(this.destroy$))
.subscribe((edges) => {
if (currentResize) {
removeGhostElement();
}
const startingRect = getElementRect(this.elm, this.ghostElementPositioning);
currentResize = {
edges,
startingRect,
currentRect: startingRect,
};
const resizeCursors = getResizeCursors();
const cursor = getResizeCursor(currentResize.edges, resizeCursors);
this.renderer.setStyle(document.body, 'cursor', cursor);
this.setElementClass(this.elm, RESIZE_ACTIVE_CLASS, true);
if (this.enableGhostResize) {
currentResize.clonedNode = deepCloneNode(this.elm.nativeElement);
this.elm.nativeElement.parentElement.appendChild(currentResize.clonedNode);
this.renderer.setStyle(this.elm.nativeElement, 'visibility', 'hidden');
this.renderer.setStyle(currentResize.clonedNode, 'position', this.ghostElementPositioning);
this.renderer.setStyle(currentResize.clonedNode, 'left', `${currentResize.startingRect.left}px`);
this.renderer.setStyle(currentResize.clonedNode, 'top', `${currentResize.startingRect.top}px`);
this.renderer.setStyle(currentResize.clonedNode, 'height', `${currentResize.startingRect.height}px`);
this.renderer.setStyle(currentResize.clonedNode, 'width', `${currentResize.startingRect.width}px`);
this.renderer.setStyle(currentResize.clonedNode, 'cursor', getResizeCursor(currentResize.edges, resizeCursors));
this.renderer.addClass(currentResize.clonedNode, RESIZE_GHOST_ELEMENT_CLASS);
currentResize.clonedNode.scrollTop = currentResize.startingRect
.scrollTop;
currentResize.clonedNode.scrollLeft = currentResize.startingRect
.scrollLeft;
}
if (this.resizeStart.observers.length > 0) {
this.zone.run(() => {
this.resizeStart.emit({
edges: getEdgesDiff({
edges,
initialRectangle: startingRect,
newRectangle: startingRect,
}),
rectangle: getNewBoundingRectangle(startingRect, {}, 0, 0),
});
});
}
});
mouseup$.pipe(takeUntil(this.destroy$)).subscribe(() => {
if (currentResize) {
this.renderer.removeClass(this.elm.nativeElement, RESIZE_ACTIVE_CLASS);
this.renderer.setStyle(document.body, 'cursor', '');
this.renderer.setStyle(this.elm.nativeElement, 'cursor', '');
if (this.resizeEnd.observers.length > 0) {
this.zone.run(() => {
this.resizeEnd.emit({
edges: getEdgesDiff({
edges: currentResize.edges,
initialRectangle: currentResize.startingRect,
newRectangle: currentResize.currentRect,
}),
rectangle: currentResize.currentRect,
});
});
}
removeGhostElement();
currentResize = null;
}
});
}
/**
* @hidden
*/
ngOnDestroy() {
// browser check for angular universal, because it doesn't know what document is
if (isPlatformBrowser(this.platformId)) {
this.renderer.setStyle(document.body, 'cursor', '');
}
this.mousedown.complete();
this.mouseup.complete();
this.mousemove.complete();
this.destroy$.next();
}
setElementClass(elm, name, add) {
if (add) {
this.renderer.addClass(elm.nativeElement, name);
}
else {
this.renderer.removeClass(elm.nativeElement, name);
}
}
}
ResizableDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.3", ngImport: i0, type: ResizableDirective, deps: [{ token: PLATFORM_ID }, { token: i0.Renderer2 }, { token: i0.ElementRef }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Directive });
ResizableDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.0.3", type: ResizableDirective, selector: "[mwlResizable]", inputs: { validateResize: "validateResize", enableGhostResize: "enableGhostResize", resizeSnapGrid: "resizeSnapGrid", resizeCursors: "resizeCursors", ghostElementPositioning: "ghostElementPositioning", allowNegativeResizes: "allowNegativeResizes", mouseMoveThrottleMS: "mouseMoveThrottleMS" }, outputs: { resizeStart: "resizeStart", resizing: "resizing", resizeEnd: "resizeEnd" }, exportAs: ["mwlResizable"], ngImport: i0 });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.3", ngImport: i0, type: ResizableDirective, decorators: [{
type: Directive,
args: [{
selector: '[mwlResizable]',
exportAs: 'mwlResizable',
}]
}], ctorParameters: function () { return [{ type: undefined, decorators: [{
type: Inject,
args: [PLATFORM_ID]
}] }, { type: i0.Renderer2 }, { type: i0.ElementRef }, { type: i0.NgZone }]; }, propDecorators: { validateResize: [{
type: Input
}], enableGhostResize: [{
type: Input
}], resizeSnapGrid: [{
type: Input
}], resizeCursors: [{
type: Input
}], ghostElementPositioning: [{
type: Input
}], allowNegativeResizes: [{
type: Input
}], mouseMoveThrottleMS: [{
type: Input
}], resizeStart: [{
type: Output
}], resizing: [{
type: Output
}], resizeEnd: [{
type: Output
}] } });
class PointerEventListeners {
constructor(renderer, zone) {
this.pointerDown = new Observable((observer) => {
let unsubscribeMouseDown;
let unsubscribeTouchStart;
zone.runOutsideAngular(() => {
unsubscribeMouseDown = renderer.listen('document', 'mousedown', (event) => {
observer.next({
clientX: event.clientX,
clientY: event.clientY,
event,
});
});
if (IS_TOUCH_DEVICE) {
unsubscribeTouchStart = renderer.listen('document', 'touchstart', (event) => {
observer.next({
clientX: event.touches[0].clientX,
clientY: event.touches[0].clientY,
event,
});
});
}
});
return () => {
unsubscribeMouseDown();
if (IS_TOUCH_DEVICE) {
unsubscribeTouchStart();
}
};
}).pipe(share());
this.pointerMove = new Observable((observer) => {
let unsubscribeMouseMove;
let unsubscribeTouchMove;
zone.runOutsideAngular(() => {
unsubscribeMouseMove = renderer.listen('document', 'mousemove', (event) => {
observer.next({
clientX: event.clientX,
clientY: event.clientY,
event,
});
});
if (IS_TOUCH_DEVICE) {
unsubscribeTouchMove = renderer.listen('document', 'touchmove', (event) => {
observer.next({
clientX: event.targetTouches[0].clientX,
clientY: event.targetTouches[0].clientY,
event,
});
});
}
});
return () => {
unsubscribeMouseMove();
if (IS_TOUCH_DEVICE) {
unsubscribeTouchMove();
}
};
}).pipe(share());
this.pointerUp = new Observable((observer) => {
let unsubscribeMouseUp;
let unsubscribeTouchEnd;
let unsubscribeTouchCancel;
zone.runOutsideAngular(() => {
unsubscribeMouseUp = renderer.listen('document', 'mouseup', (event) => {
observer.next({
clientX: event.clientX,
clientY: event.clientY,
event,
});
});
if (IS_TOUCH_DEVICE) {
unsubscribeTouchEnd = renderer.listen('document', 'touchend', (event) => {
observer.next({
clientX: event.changedTouches[0].clientX,
clientY: event.changedTouches[0].clientY,
event,
});
});
unsubscribeTouchCancel = renderer.listen('document', 'touchcancel', (event) => {
observer.next({
clientX: event.changedTouches[0].clientX,
clientY: event.changedTouches[0].clientY,
event,
});
});
}
});
return () => {
unsubscribeMouseUp();
if (IS_TOUCH_DEVICE) {
unsubscribeTouchEnd();
unsubscribeTouchCancel();
}
};
}).pipe(share());
}
static getInstance(renderer, zone) {
if (!PointerEventListeners.instance) {
PointerEventListeners.instance = new PointerEventListeners(renderer, zone);
}
return PointerEventListeners.instance;
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVzaXphYmxlLmRpcmVjdGl2ZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3Byb2plY3RzL2FuZ3VsYXItcmVzaXphYmxlLWVsZW1lbnQvc3JjL2xpYi9yZXNpemFibGUuZGlyZWN0aXZlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFDTCxTQUFTLEVBSVQsTUFBTSxFQUNOLEtBQUssRUFDTCxZQUFZLEVBR1osTUFBTSxFQUNOLFdBQVcsR0FDWixNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUNwRCxPQUFPLEVBQUUsT0FBTyxFQUFFLFVBQVUsRUFBWSxLQUFLLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDNUQsT0FBTyxFQUNMLEdBQUcsRUFDSCxRQUFRLEVBQ1IsU0FBUyxFQUNULE1BQU0sRUFDTixRQUFRLEVBQ1IsSUFBSSxFQUNKLEtBQUssRUFDTCxHQUFHLEdBQ0osTUFBTSxnQkFBZ0IsQ0FBQztBQUl4QixPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDekQsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLG1CQUFtQixDQUFDOztBQWFsRCxTQUFTLHVCQUF1QixDQUM5QixZQUErQixFQUMvQixLQUFZLEVBQ1osT0FBZSxFQUNmLE9BQWU7SUFFZixNQUFNLGVBQWUsR0FBc0I7UUFDekMsR0FBRyxFQUFFLFlBQVksQ0FBQyxHQUFHO1FBQ3JCLE1BQU0sRUFBRSxZQUFZLENBQUMsTUFBTTtRQUMzQixJQUFJLEVBQUUsWUFBWSxDQUFDLElBQUk7UUFDdkIsS0FBSyxFQUFFLFlBQVksQ0FBQyxLQUFLO0tBQzFCLENBQUM7SUFFRixJQUFJLEtBQUssQ0FBQyxHQUFHLEVBQUU7UUFDYixlQUFlLENBQUMsR0FBRyxJQUFJLE9BQU8sQ0FBQztLQUNoQztJQUNELElBQUksS0FBSyxDQUFDLE1BQU0sRUFBRTtRQUNoQixlQUFl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Q0FBQyxDQUNGLENBQUM7b0JBRUYsc0JBQXNCLEdBQUcsUUFBUSxDQUFDLE1BQU0sQ0FDdEMsVUFBVSxFQUNWLGFBQWEsRUFDYixDQUFDLEtBQWlCLEVBQUUsRUFBRTt3QkFDcEIsUUFBUSxDQUFDLElBQUksQ0FBQzs0QkFDWixPQUFPLEVBQUUsS0FBSyxDQUFDLGNBQWMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxPQUFPOzRCQUN4QyxPQUFPLEVBQUUsS0FBSyxDQUFDLGNBQWMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxPQUFPOzRCQUN4QyxLQUFLO3lCQUNOLENBQUMsQ0FBQztvQkFDTCxDQUFDLENBQ0YsQ0FBQztpQkFDSDtZQUNILENBQUMsQ0FBQyxDQUFDO1lBRUgsT0FBTyxHQUFHLEVBQUU7Z0JBQ1Ysa0JBQWtCLEVBQUUsQ0FBQztnQkFDckIsSUFBSSxlQUFlLEVBQUU7b0JBQ25CLG1CQUFvQixFQUFFLENBQUM7b0JBQ3ZCLHNCQUF1QixFQUFFLENBQUM7aUJBQzNCO1lBQ0gsQ0FBQyxDQUFDO1FBQ0osQ0FBQyxDQUNGLENBQUMsSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDLENBQUM7SUFDbEIsQ0FBQztJQXpKTSxNQUFNLENBQUMsV0FBVyxDQUN2QixRQUFtQixFQUNuQixJQUFZO1FBRVosSUFBSSxDQUFDLHFCQUFxQixDQUFDLFFBQVEsRUFBRTtZQUNuQyxxQkFBcUIsQ0FBQyxRQUFRLEdBQUcsSUFBSSxxQkFBcUIsQ0FDeEQsUUFBUSxFQUNSLElBQUksQ0FDTCxDQUFDO1NBQ0g7UUFDRCxPQUFPLHFCQUFxQixDQUFDLFFBQVEsQ0FBQztJQUN4QyxDQUFDO0NBK0lGIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgRGlyZWN0aXZlLFxuICBSZW5kZXJlcjIsXG4gIEVsZW1lbnRSZWYsXG4gIE9uSW5pdCxcbiAgT3V0cHV0LFxuICBJbnB1dCxcbiAgRXZlbnRFbWl0dGVyLFxuICBPbkRlc3Ryb3ksXG4gIE5nWm9uZSxcbiAgSW5qZWN0LFxuICBQTEFURk9STV9JRCxcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBpc1BsYXRmb3JtQnJvd3NlciB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XG5pbXBvcnQgeyBTdWJqZWN0LCBPYnNlcnZhYmxlLCBPYnNlcnZlciwgbWVyZ2UgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7XG4gIG1hcCxcbiAgbWVyZ2VNYXAsXG4gIHRha2VVbnRpbCxcbiAgZmlsdGVyLFxuICBwYWlyd2lzZSxcbiAgdGFrZSxcbiAgc2hhcmUsXG4gIHRhcCxcbn0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuaW1wb3J0IHsgRWRnZXMgfSBmcm9tICcuL2ludGVyZmFjZXMvZWRnZXMuaW50ZXJmYWNlJztcbmltcG9ydCB7IEJvdW5kaW5nUmVjdGFuZ2xlIH0gZnJvbSAnLi9pbnRlcmZhY2VzL2JvdW5kaW5nLXJlY3RhbmdsZS5pbnRlcmZhY2UnO1xuaW1wb3J0IHsgUmVzaXplRXZlbnQgfSBmcm9tICcuL2ludGVyZmFjZXMvcmVzaXplLWV2ZW50LmludGVyZmFjZSc7XG5pbXBvcnQgeyBJU19UT1VDSF9ERVZJQ0UgfSBmcm9tICcuL3V0aWwvaXMtdG91Y2gtZGV2aWNlJztcbmltcG9ydCB7IGRlZXBDbG9uZU5vZGUgfSBmcm9tICcuL3V0aWwvY2xvbmUtbm9kZSc7XG5cbmludGVyZmFjZSBQb2ludGVyRXZlbnRDb29yZGluYXRlIHtcbiAgY2xpZW50WDogbnVtYmVyO1xuICBjbGllbnRZOiBudW1iZXI7XG4gIGV2ZW50OiBNb3VzZUV2ZW50IHwgVG91Y2hFdmVudDtcbn1cblxuaW50ZXJmYWNlIENvb3JkaW5hdGUge1xuICB4OiBudW1iZXI7XG4gIHk6IG51bWJlcjtcbn1cblxuZnVuY3Rpb24gZ2V0TmV3Qm91bmRpbmdSZWN0YW5nbGUoXG4gIHN0YXJ0aW5nUmVjdDogQm91bmRpbmdSZWN0YW5nbGUsXG4gIGVkZ2VzOiBFZGdlcyxcbiAgY2xpZW50WDogbnVtYmVyLFxuICBjbGllbnRZOiBudW1iZXJcbik6IEJvdW5kaW5nUmVjdGFuZ2xlIHtcbiAgY29uc3QgbmV3Qm91bmRpbmdSZWN0OiBCb3VuZGluZ1JlY3RhbmdsZSA9IHtcbiAgICB0b3A6IHN0YXJ0aW5nUmVjdC50b3AsXG4gICAgYm90dG9tOiBzdGFydGluZ1JlY3QuYm90dG9tLFxuICAgIGxlZnQ6IHN0YXJ0aW5nUmVjdC5sZWZ0LFxuICAgIHJpZ2h0OiBzdGFydGluZ1JlY3QucmlnaHQsXG4gIH07XG5cbiAgaWYgKGVkZ2VzLnRvcCkge1xuICAgIG5ld0JvdW5kaW5nUmVjdC50b3AgKz0gY2xpZW50WTtcbiAgfVxuICBpZiAoZWRnZXMuYm90dG9tKSB7XG4gICAgbmV3Qm91bmRpbmdSZWN0LmJvdHRvbSArPSBjbGllbnRZO1xuICB9XG4gIGlmIChlZGdlcy5sZWZ0KSB7XG4gICAgbmV3Qm91bmRpbmdSZWN0LmxlZnQgKz0gY2xpZW50WDtcbiAgfVxuICBpZiAoZWRnZXMucmlnaHQpIHtcbiAgICBuZXdCb3VuZGluZ1JlY3QucmlnaHQgKz0gY2xpZW50WDtcbiAgfVxuICBuZXdCb3VuZGluZ1JlY3QuaGVpZ2h0ID0gbmV3Qm91bmRpbmdSZWN0LmJvdHRvbSAtIG5ld0JvdW5kaW5nUmVjdC50b3A7XG4gIG5ld0JvdW5kaW5nUmVjdC53aWR0aCA9IG5ld0JvdW5kaW5nUmVjdC5yaWdodCAtIG5ld0JvdW5kaW5nUmVjdC5sZWZ0O1xuXG4gIHJldHVybiBuZXdCb3VuZGluZ1JlY3Q7XG59XG5cbmZ1bmN0aW9uIGdldEVsZW1lbnRSZWN0KFxuICBlbGVtZW50OiBFbGVtZW50UmVmLFxuICBnaG9zdEVsZW1lbnRQb3NpdGlvbmluZzogc3RyaW5nXG4pOiBCb3VuZGluZ1JlY3RhbmdsZSB7XG4gIGxldCB0cmFuc2xhdGVYID0gMDtcbiAgbGV0IHRyYW5zbGF0ZVkgPSAwO1xuICBjb25zdCBzdHlsZSA9IGVsZW1lbnQubmF0aXZlRWxlbWVudC5zdHlsZTtcbiAgY29uc3QgdHJhbnNmb3JtUHJvcGVydGllcyA9IFtcbiAgICAndHJhbnNmb3JtJyxcbiAgICAnLW1zLXRyYW5zZm9ybScsXG4gICAgJy1tb3otdHJhbnNmb3JtJyxcbiAgICAnLW8tdHJhbnNmb3JtJyxcbiAgXTtcbiAgY29uc3QgdHJhbnNmb3JtID0gdHJhbnNmb3JtUHJvcGVydGllc1xuICAgIC5tYXAoKHByb3BlcnR5KSA9PiBzdHlsZVtwcm9wZXJ0eV0pXG4gICAgLmZpbmQoKHZhbHVlKSA9PiAhIXZhbHVlKTtcbiAgaWYgKHRyYW5zZm9ybSAmJiB0cmFuc2Zvcm0uaW5jbHVkZXMoJ3RyYW5zbGF0ZScpKSB7XG4gICAgdHJhbnNsYXRlWCA9IHRyYW5zZm9ybS5yZXBsYWNlKFxuICAgICAgLy4qdHJhbnNsYXRlMz9kP1xcKCgtP1swLTldKilweCwgKC0/WzAtOV0qKXB4LiovLFxuICAgICAgJyQxJ1xuICAgICk7XG4gICAgdHJhbnNsYXRlWSA9IHRyYW5zZm9ybS5yZXBsYWNlKFxuICAgICAgLy4qdHJhbnNsYXRlMz9kP1xcKCgtP1swLTldKilweCwgKC0/WzAtOV0qKXB4LiovLFxuICAgICAgJyQyJ1xuICAgICk7XG4gIH1cblxuICBpZiAoZ2hvc3RFbGVtZW50UG9zaXRpb25pbmcgPT09ICdhYnNvbHV0ZScpIHtcbiAgICByZXR1cm4ge1xuICAgICAgaGVpZ2h0OiBlbGVtZW50Lm5hdGl2ZUVsZW1lbnQub2Zmc2V0SGVpZ2h0LFxuICAgICAgd2lkdGg6IGVsZW1lbnQubmF0aXZlRWxlbWVudC5vZmZzZXRXaWR0aCxcbiAgICAgIHRvcDogZWxlbWVudC5uYXRpdmVFbGVtZW50Lm9mZnNldFRvcCAtIHRyYW5zbGF0ZVksXG4gICAgICBib3R0b206XG4gICAgICAgIGVsZW1lbnQubmF0aXZlRWxlbWVudC5vZmZzZXRIZWlnaHQgK1xuICAgICAgICBlbGVtZW50Lm5hdGl2ZUVsZW1lbnQub2Zmc2V0VG9wIC1cbiAgICAgICAgdHJhbnNsYXRlWSxcbiAgICAgIGxlZnQ6IGVsZW1lbnQubmF0aXZlRWxlbWVudC5vZmZzZXRMZWZ0IC0gdHJhbnNsYXRlWCxcbiAgICAgIHJpZ2h0OlxuICAgICAgICBlbGVtZW50Lm5hdGl2ZUVsZW1lbnQub2Zmc2V0V2lkdGggK1xuICAgICAgICBlbGVtZW50Lm5hdGl2ZUVsZW1lbnQub2Zmc2V0TGVmdCAtXG4gICAgICAgIHRyYW5zbGF0ZVgsXG4gICAgfTtcbiAgfSBlbHNlIHtcbiAgICBjb25zdCBib3VuZGluZ1JlY3Q6IEJvdW5kaW5nUmVjdGFuZ2xlID1cbiAgICAgIGVsZW1lbnQubmF0aXZlRWxlbWVudC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcbiAgICByZXR1cm4ge1xuICAgICAgaGVpZ2h0OiBib3VuZGluZ1JlY3QuaGVpZ2h0LFxuICAgICAgd2lkdGg6IGJvdW5kaW5nUmVjdC53aWR0aCxcbiAgICAgIHRvcDogYm91bmRpbmdSZWN0LnRvcCAtIHRyYW5zbGF0ZVksXG4gICAgICBib3R0b206IGJvdW5kaW5nUmVjdC5ib3R0b20gLSB0cmFuc2xhdGVZLFxuICAgICAgbGVmdDogYm91