UNPKG

angular-resizable-element

Version:

An angular 15.0+ directive that allows an element to be dragged and resized

551 lines 78.1 kB
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