UNPKG

ngx-diagrams

Version:

> Light Weight, Modular, Typed Diagram Engine for Angular

424 lines 62.5 kB
import { ComponentFactoryResolver, Injectable, RendererFactory2 } from '@angular/core'; import { delay, filter, take } from 'rxjs/operators'; import { DefaultLabelFactory } from '../defaults/factories/default-label.factory'; import { DefaultLinkFactory } from '../defaults/factories/default-link.factory'; import { DefaultNodeFactory } from '../defaults/factories/default-node.factory'; import { DefaultPortFactory } from '../defaults/factories/default-port.factory'; import { DiagramModel } from '../models/diagram.model'; import { NgxDiagramsModule } from '../ngx-diagrams.module'; import { PathFinding, ROUTING_SCALING_FACTOR } from '../plugins/smart-routing.plugin'; import { createValueState } from '../state/state'; import * as i0 from "@angular/core"; import * as i1 from "../ngx-diagrams.module"; export class DiagramEngine { constructor(resolver, rendererFactory) { this.resolver = resolver; this.rendererFactory = rendererFactory; this.nodeFactories = new Map(); this.labelFactories = new Map(); this.linkFactories = new Map(); this.portFactories = new Map(); this.canvas$ = createValueState(null); // calculated only when smart routing is active this.canvasMatrix = []; this.routingMatrix = []; // used when at least one element has negative coordinates this.hAdjustmentFactor = 0; this.vAdjustmentFactor = 0; this.markMatrixPoint = (matrix, x, y) => { if (matrix[y] !== undefined && matrix[y][x] !== undefined) { matrix[y][x] = 1; } }; this._renderer = this.rendererFactory.createRenderer(null, null); } createDiagram() { this.diagramModel = new DiagramModel(this); return this.diagramModel; } registerDefaultFactories() { this.registerNodeFactory(new DefaultNodeFactory(this.resolver, this._renderer)); this.registerPortFactory(new DefaultPortFactory(this.resolver, this._renderer)); this.registerLinkFactory(new DefaultLinkFactory(this.resolver, this._renderer)); this.registerLabelFactory(new DefaultLabelFactory(this.resolver, this._renderer)); } //#region Factories // LABELS registerLabelFactory(labelFactory) { this.labelFactories.set(labelFactory.type, labelFactory); } getLabelFactories() { return this.labelFactories; } getLabelFactory(type) { if (this.labelFactories.has(type)) { return this.labelFactories.get(type); } throw new Error(`cannot find factory for node of type: [${type}]`); } getFactoryForLabel(label) { return this.getLabelFactory(label.getType()); } generateWidgetForLabel(label, labelHost) { const labelFactory = this.getFactoryForLabel(label); if (!labelFactory) { throw new Error(`Cannot find widget factory for node: ${label.getType()}`); } return labelFactory.generateWidget(label, labelHost); } // NODES registerNodeFactory(nodeFactory) { this.nodeFactories.set(nodeFactory.type, nodeFactory); } getNodeFactories() { return this.nodeFactories; } getNodeFactory(type) { if (this.nodeFactories.has(type)) { return this.nodeFactories.get(type); } throw new Error(`cannot find factory for node of type: [${type}]`); } getFactoryForNode(node) { return this.getNodeFactory(node.getType()); } generateWidgetForNode(node, nodesHost) { const nodeFactory = this.getFactoryForNode(node); if (!nodeFactory) { throw new Error(`Cannot find widget factory for node: ${node.getType()}`); } return nodeFactory.generateWidget(this, node, nodesHost); } // PORTS registerPortFactory(factory) { this.portFactories.set(factory.type, factory); } getPortFactories() { return this.portFactories; } getPortFactory(type) { if (this.portFactories.has(type)) { return this.portFactories.get(type); } throw new Error(`cannot find factory for port of type: [${type}]`); } getFactoryForPort(port) { return this.getPortFactory(port.getType()); } generateWidgetForPort(port, portsHost) { const portFactory = this.getFactoryForPort(port); if (!portFactory) { throw new Error(`Cannot find widget factory for port: ${port.getType()}`); } return portFactory.generateWidget(port, portsHost); } // LINKS getLinkFactories() { return this.linkFactories; } registerLinkFactory(factory) { this.linkFactories.set(factory.type, factory); } getLinkFactory(type) { if (this.linkFactories.has(type)) { return this.linkFactories.get(type); } throw new Error(`cannot find factory for link of type: [${type}]`); } getFactoryForLink(link) { return this.getLinkFactory(link.getType()); } generateWidgetForLink(link, linksHost) { const linkFactory = this.getFactoryForLink(link); if (!linkFactory) { throw new Error(`Cannot find link factory for link: ${link.getType()}`); } return linkFactory.generateWidget(this, link, linksHost); } //#endregion getNodeElement(node) { const selector = this.canvas$.value.querySelector(`[data-nodeid="${node.id}"]`); if (selector === null) { throw new Error('Cannot find Node element with node id: [' + node.id + ']'); } return selector; } getNodePortElement(port) { const selector = this.canvas$.value.querySelector(`[data-nodeid="${port.getParent().id}"] [data-portid="${port.id}"]`); if (selector === null) { throw new Error('Cannot find Node Port element with node id: [' + port.getParent().id + '] and port id: [' + port.id + ']'); } return selector; } getPortCenter(port) { const sourceElement = this.getNodePortElement(port); const sourceRect = sourceElement.getBoundingClientRect(); const rel = this.getRelativePoint(sourceRect.left, sourceRect.top); return { x: sourceElement.offsetWidth / 2 + (rel.x - this.diagramModel.getOffsetX()) / (this.diagramModel.getZoomLevel() / 100.0), y: sourceElement.offsetHeight / 2 + (rel.y - this.diagramModel.getOffsetY()) / (this.diagramModel.getZoomLevel() / 100.0) }; } /** * Calculate rectangular coordinates of the port passed in. */ getPortCoords(port) { const sourceElement = this.getNodePortElement(port); const sourceRect = sourceElement.getBoundingClientRect(); const canvasRect = this.canvas$.value.getBoundingClientRect(); return { x: (sourceRect.x - this.diagramModel.getOffsetX()) / (this.diagramModel.getZoomLevel() / 100.0) - canvasRect.left, y: (sourceRect.y - this.diagramModel.getOffsetY()) / (this.diagramModel.getZoomLevel() / 100.0) - canvasRect.top, width: sourceRect.width, height: sourceRect.height }; } /** * Determine the width and height of the node passed in. * It currently assumes nodes have a rectangular shape, can be overriden for customised shapes. */ getNodeDimensions(node) { if (!this.canvas$.value) { return { width: 0, height: 0 }; } const nodeElement = this.getNodeElement(node); const nodeRect = nodeElement.getBoundingClientRect(); return { width: nodeRect.width, height: nodeRect.height }; } setCanvas(canvas) { this.canvas$.set(canvas).emit(); } getRelativeMousePoint(event) { const point = this.getRelativePoint(event.clientX, event.clientY); return { x: (point.x - this.diagramModel.getOffsetX()) / (this.diagramModel.getZoomLevel() / 100.0), y: (point.y - this.diagramModel.getOffsetY()) / (this.diagramModel.getZoomLevel() / 100.0) }; } getRelativePoint(x, y) { const canvasRect = this.canvas$.value.getBoundingClientRect(); return { x: x - canvasRect.left, y: y - canvasRect.top }; } getDiagramModel() { return this.diagramModel; } isModelLocked(model) { if (this.diagramModel.getLocked()) { return true; } return model.getLocked(); } /** * fit the canvas zoom levels to the elements contained. * @param additionalZoomFactor allow for further zooming out to make sure edges doesn't cut */ zoomToFit(additionalZoomFactor = 0.005) { this.canvas$.value$.pipe(filter(Boolean), take(1), delay(0)).subscribe((canvas) => { const xFactor = canvas.clientWidth / canvas.scrollWidth; const yFactor = canvas.clientHeight / canvas.scrollHeight; const zoomFactor = xFactor < yFactor ? xFactor : yFactor; let newZoomLvl = this.diagramModel.getZoomLevel() * (zoomFactor - additionalZoomFactor); const maxZoomOut = this.diagramModel.getMaxZoomOut(); if (maxZoomOut && newZoomLvl < maxZoomOut) { newZoomLvl = maxZoomOut; } this.diagramModel.setZoomLevel(newZoomLvl); // TODO: either block the canvas movement on 0,0 or detect the top left furthest element and set the offest to its edges this.diagramModel.setOffset(0, 0); }); } // SMART ROUTING setSmartRoutingStatus(status) { if (status && !this.pathFinding) { this.pathFinding = new PathFinding(this); } else { this.pathFinding = null; } this.smartRouting = status; } getPathfinding() { return this.pathFinding; } calculateCanvasMatrix() { const { width: canvasWidth, hAdjustmentFactor, height: canvasHeight, vAdjustmentFactor } = this.calculateMatrixDimensions(); this.hAdjustmentFactor = hAdjustmentFactor; this.vAdjustmentFactor = vAdjustmentFactor; const matrixWidth = Math.ceil(canvasWidth / ROUTING_SCALING_FACTOR); const matrixHeight = Math.ceil(canvasHeight / ROUTING_SCALING_FACTOR); this.canvasMatrix = Array.from({ length: matrixHeight }, (_, i) => i + 1).map(() => { return new Array(matrixWidth).fill(0); }); } /** * Despite being a long method, we simply iterate over all three collections (nodes, ports and points) * to find the highest X and Y dimensions, so we can build the matrix large enough to contain all elements. */ calculateMatrixDimensions() { const allNodesCoords = this.diagramModel.getNodesArray().map((item) => ({ x: item.getCoords().x, width: item.getWidth(), y: item.getCoords().y, height: item.getHeight() })); const allLinks = this.diagramModel.getLinksArray(); const allPortsCoords = allLinks .flatMap((link) => [link.getSourcePort(), link.getTargetPort()]) .filter((port) => port !== null) .map((item) => ({ x: item.getX(), width: item.getWidth(), y: item.getY(), height: item.getHeight() })); const allPointsCoords = allLinks .flatMap((link) => link.getPoints()) .map((item) => ({ // points don't have width/height, so let's just use 0 x: item.getCoords().x, width: 0, y: item.getCoords().y, height: 0 })); const canvas = this.canvas$.value; const allElements = allNodesCoords.concat(allPortsCoords, allPointsCoords); const minX = Math.floor(Math.min(allElements.reduce((a, b) => { return a.x <= b.x ? a : b; }).x, 0) / ROUTING_SCALING_FACTOR) * ROUTING_SCALING_FACTOR; const maxXElement = allElements.reduce((a, b) => { return a.x + a.width >= b.x + b.width ? a : b; }); const maxX = Math.max(maxXElement.x + maxXElement.width, canvas.offsetWidth); const minY = Math.floor(Math.min(allElements.reduce((a, b) => { return a.y <= b.y ? a : b; }).y, 0) / ROUTING_SCALING_FACTOR) * ROUTING_SCALING_FACTOR; const maxYElement = allElements.reduce((a, b) => { return a.y + a.height >= b.y + b.height ? a : b; }); const maxY = Math.max(maxYElement.y + maxYElement.height, canvas.offsetWidth); const width = Math.ceil(Math.abs(minX) + maxX); const height = Math.ceil(Math.abs(minY) + maxY); return { width, hAdjustmentFactor: Math.abs(minX) / ROUTING_SCALING_FACTOR + 1, height, vAdjustmentFactor: Math.abs(minY) / ROUTING_SCALING_FACTOR + 1 }; } /** * A representation of the canvas in the following format: * * +-----------------+ * | 0 0 0 0 0 0 0 0 | * | 0 0 0 0 0 0 0 0 | * | 0 0 0 0 0 0 0 0 | * | 0 0 0 0 0 0 0 0 | * | 0 0 0 0 0 0 0 0 | * +-----------------+ * * In which all walkable points are marked by zeros. * It uses @link{#ROUTING_SCALING_FACTOR} to reduce the matrix dimensions and improve performance. */ getCanvasMatrix() { if (this.canvasMatrix.length === 0) { this.calculateCanvasMatrix(); } return this.canvasMatrix; } /** * The routing matrix does not have negative indexes, but elements could be negatively positioned. * We use the functions below to translate back and forth between these coordinates, relying on the * calculated values of hAdjustmentFactor and vAdjustmentFactor. */ translateRoutingX(x, reverse = false) { return x + this.hAdjustmentFactor * (reverse ? -1 : 1); } translateRoutingY(y, reverse = false) { return y + this.vAdjustmentFactor * (reverse ? -1 : 1); } /** * A representation of the canvas in the following format: * * +-----------------+ * | 0 0 1 1 0 0 0 0 | * | 0 0 1 1 0 0 1 1 | * | 0 0 0 0 0 0 1 1 | * | 1 1 0 0 0 0 0 0 | * | 1 1 0 0 0 0 0 0 | * +-----------------+ * * In which all points blocked by a node (and its ports) are * marked as 1; points were there is nothing (ie, free) receive 0. */ getRoutingMatrix() { if (this.routingMatrix.length === 0) { this.calculateRoutingMatrix(); } return this.routingMatrix; } calculateRoutingMatrix() { const matrix = this.getCanvasMatrix().map((item) => item.slice(0)); // nodes need to be marked as blocked points this.markNodes(matrix); // same thing for ports this.markPorts(matrix); this.routingMatrix = matrix; } getSmartRouting() { return !!this.smartRouting; } /** * Updates (by reference) where nodes will be drawn on the matrix passed in. */ markNodes(matrix) { this.diagramModel.getNodes().forEach((node) => { const startX = Math.floor(node.getCoords().x / ROUTING_SCALING_FACTOR); const endX = Math.ceil((node.getCoords().x + node.getWidth()) / ROUTING_SCALING_FACTOR); const startY = Math.floor(node.getCoords().y / ROUTING_SCALING_FACTOR); const endY = Math.ceil((node.getCoords().y + node.getHeight()) / ROUTING_SCALING_FACTOR); for (let x = startX - 1; x <= endX + 1; x++) { for (let y = startY - 1; y < endY + 1; y++) { this.markMatrixPoint(matrix, this.translateRoutingX(x), this.translateRoutingY(y)); } } }); } /** * Updates (by reference) where ports will be drawn on the matrix passed in. */ markPorts(matrix) { const allElements = this.diagramModel .getLinksArray() .flatMap((link) => [link.getSourcePort(), link.getTargetPort()]); allElements .filter((port) => port !== null) .forEach((port) => { const startX = Math.floor(port.getX() / ROUTING_SCALING_FACTOR); const endX = Math.ceil((port.getX() + port.getWidth()) / ROUTING_SCALING_FACTOR); const startY = Math.floor(port.getY() / ROUTING_SCALING_FACTOR); const endY = Math.ceil((port.getY() + port.getHeight()) / ROUTING_SCALING_FACTOR); for (let x = startX - 1; x <= endX + 1; x++) { for (let y = startY - 1; y < endY + 1; y++) { this.markMatrixPoint(matrix, this.translateRoutingX(x), this.translateRoutingY(y)); } } }); } } DiagramEngine.ɵprov = i0.ɵɵdefineInjectable({ factory: function DiagramEngine_Factory() { return new DiagramEngine(i0.ɵɵinject(i0.ComponentFactoryResolver), i0.ɵɵinject(i0.RendererFactory2)); }, token: DiagramEngine, providedIn: i1.NgxDiagramsModule }); DiagramEngine.decorators = [ { type: Injectable, args: [{ providedIn: NgxDiagramsModule },] } ]; DiagramEngine.ctorParameters = () => [ { type: ComponentFactoryResolver }, { type: RendererFactory2 } ]; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZW5naW5lLnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiLi4vLi4vLi4vLi4vbGlicy9uZ3gtZGlhZ3JhbXMvc3JjLyIsInNvdXJjZXMiOlsibGliL3NlcnZpY2VzL2VuZ2luZS5zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFDTCx3QkFBd0IsRUFFeEIsVUFBVSxFQUVWLGdCQUFnQixFQUVqQixNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRSxJQUFJLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUVyRCxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSw2Q0FBNkMsQ0FBQztBQUNsRixPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSw0Q0FBNEMsQ0FBQztBQUNoRixPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSw0Q0FBNEMsQ0FBQztBQUNoRixPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSw0Q0FBNEMsQ0FBQztBQUtoRixPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFLdkQsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDM0QsT0FBTyxFQUFFLFdBQVcsRUFBRSxzQkFBc0IsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBQ3RGLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLGdCQUFnQixDQUFDOzs7QUFJbEQsTUFBTSxPQUFPLGFBQWE7SUFzQnhCLFlBQXNCLFFBQWtDLEVBQVksZUFBaUM7UUFBL0UsYUFBUSxHQUFSLFFBQVEsQ0FBMEI7UUFBWSxvQkFBZSxHQUFmLGVBQWUsQ0FBa0I7UUFwQjNGLGtCQUFhLEdBQUcsSUFBSSxHQUFHLEVBQStCLENBQUM7UUFDdkQsbUJBQWMsR0FBRyxJQUFJLEdBQUcsRUFBZ0MsQ0FBQztRQUN6RCxrQkFBYSxHQUFHLElBQUksR0FBRyxFQUErQixDQUFDO1FBQ3ZELGtCQUFhLEdBQUcsSUFBSSxH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eEIsZ0JBQWdCIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgQ29tcG9uZW50RmFjdG9yeVJlc29sdmVyLFxuICBDb21wb25lbnRSZWYsXG4gIEluamVjdGFibGUsXG4gIFJlbmRlcmVyMixcbiAgUmVuZGVyZXJGYWN0b3J5MixcbiAgVmlld0NvbnRhaW5lclJlZlxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IGRlbGF5LCBmaWx0ZXIsIHRha2UgfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5pbXBvcnQgeyBCYXNlRW50aXR5IH0gZnJvbSAnLi4vYmFzZS5lbnRpdHknO1xuaW1wb3J0IHsgRGVmYXVsdExhYmVsRmFjdG9yeSB9IGZyb20gJy4uL2RlZmF1bHRzL2ZhY3Rvcmllcy9kZWZhdWx0LWxhYmVsLmZhY3RvcnknO1xuaW1wb3J0IHsgRGVmYXVsdExpbmtGYWN0b3J5IH0gZnJvbSAnLi4vZGVmYXVsdHMvZmFjdG9yaWVzL2RlZmF1bHQtbGluay5mYWN0b3J5JztcbmltcG9ydCB7IERlZmF1bHROb2RlRmFjdG9yeSB9IGZyb20gJy4uL2RlZmF1bHRzL2ZhY3Rvcmllcy9kZWZhdWx0LW5vZGUuZmFjdG9yeSc7XG5pbXBvcnQgeyBEZWZhdWx0UG9ydEZhY3RvcnkgfSBmcm9tICcuLi9kZWZhdWx0cy9mYWN0b3JpZXMvZGVmYXVsdC1wb3J0LmZhY3RvcnknO1xuaW1wb3J0IHsgQWJzdHJhY3RMYWJlbEZhY3RvcnkgfSBmcm9tICcuLi9mYWN0b3JpZXMvbGFiZWwuZmFjdG9yeSc7XG5pbXBvcnQgeyBBYnN0cmFjdExpbmtGYWN0b3J5IH0gZnJvbSAnLi4vZmFjdG9yaWVzL2xpbmsuZmFjdG9yeSc7XG5pbXBvcnQgeyBBYnN0cmFjdE5vZGVGYWN0b3J5IH0gZnJvbSAnLi4vZmFjdG9yaWVzL25vZGUuZmFjdG9yeSc7XG5pbXBvcnQgeyBBYnN0cmFjdFBvcnRGYWN0b3J5IH0gZnJvbSAnLi4vZmFjdG9yaWVzL3BvcnQuZmFjdG9yeSc7XG5pbXBvcnQgeyBEaWFncmFtTW9kZWwgfSBmcm9tICcuLi9tb2RlbHMvZGlhZ3JhbS5tb2RlbCc7XG5pbXBvcnQgeyBMYWJlbE1vZGVsIH0gZnJvbSAnLi4vbW9kZWxzL2xhYmVsLm1vZGVsJztcbmltcG9ydCB7IExpbmtNb2RlbCB9IGZyb20gJy4uL21vZGVscy9saW5rLm1vZGVsJztcbmltcG9ydCB7IE5vZGVNb2RlbCB9IGZyb20gJy4uL21vZGVscy9ub2RlLm1vZGVsJztcbmltcG9ydCB7IFBvcnRNb2RlbCB9IGZyb20gJy4uL21vZGVscy9wb3J0Lm1vZGVsJztcbmltcG9ydCB7IE5neERpYWdyYW1zTW9kdWxlIH0gZnJvbSAnLi4vbmd4LWRpYWdyYW1zLm1vZHVsZSc7XG5pbXBvcnQgeyBQYXRoRmluZGluZywgUk9VVElOR19TQ0FMSU5HX0ZBQ1RPUiB9IGZyb20gJy4uL3BsdWdpbnMvc21hcnQtcm91dGluZy5wbHVnaW4nO1xuaW1wb3J0IHsgY3JlYXRlVmFsdWVTdGF0ZSB9IGZyb20gJy4uL3N0YXRlL3N0YXRlJztcbmltcG9ydCB7IEVudGl0eU1hcCB9IGZyb20gJy4uL3V0aWxzJztcblxuQEluamVjdGFibGUoeyBwcm92aWRlZEluOiBOZ3hEaWFncmFtc01vZHVsZSB9KVxuZXhwb3J0IGNsYXNzIERpYWdyYW1FbmdpbmUge1xuICBwcm90ZWN0ZWQgX3JlbmRlcmVyOiBSZW5kZXJlcjI7XG4gIHByb3RlY3RlZCBub2RlRmFjdG9yaWVzID0gbmV3IE1hcDxzdHJpbmcsIEFic3RyYWN0Tm9kZUZhY3Rvcnk+KCk7XG4gIHByb3RlY3RlZCBsYWJlbEZhY3RvcmllcyA9IG5ldyBNYXA8c3RyaW5nLCBBYnN0cmFjdExhYmVsRmFjdG9yeT4oKTtcbiAgcHJvdGVjdGVkIGxpbmtGYWN0b3JpZXMgPSBuZXcgTWFwPHN0cmluZywgQWJzdHJhY3RMaW5rRmFjdG9yeT4oKTtcbiAgcHJvdGVjdGVkIHBvcnRGYWN0b3JpZXMgPSBuZXcgTWFwPHN0cmluZywgQWJzdHJhY3RQb3J0RmFjdG9yeT4oKTtcbiAgcHJvdGVjdGVkIGNhbnZhcyQgPSBjcmVhdGVWYWx1ZVN0YXRlPEVsZW1lbnQ+KG51bGwpO1xuXG4gIC8vIHNtYXJ0IHJvdXRpbmcgcmVsYXRlZCBwcm9wZXJ0aWVzXG4gIHNtYXJ0Um91dGluZzogYm9vbGVhbjtcbiAgcGF0aEZpbmRpbmc6IFBhdGhGaW5kaW5nO1xuXG4gIC8vIGNhbGN1bGF0ZWQgb25seSB3aGVuIHNtYXJ0IHJvdXRpbmcgaXMgYWN0aXZlXG4gIGNhbnZhc01hdHJpeDogbnVtYmVyW11bXSA9IFtdO1xuICByb3V0aW5nTWF0cml4OiBudW1iZXJbXVtdID0gW107XG5cbiAgLy8gdXNlZCB3aGVuIGF0IGxlYXN0IG9uZSBlbGVtZW50IGhhcyBuZWdhdGl2ZSBjb29yZGluYXRlc1xuICBoQWRqdXN0bWVudEZhY3RvciA9IDA7XG4gIHZBZGp1c3RtZW50RmFjdG9yID0gMDtcblxuICBkaWFncmFtTW9kZWw6IERpYWdyYW1Nb2RlbDtcblxuICBjb25zdHJ1Y3Rvcihwcm90ZWN0ZWQgcmVzb2x2ZXI6IENvbXBvbmVudEZhY3RvcnlSZXNvbHZlciwgcHJvdGVjdGVkIHJlbmRlcmVyRmFjdG9yeTogUmVuZGVyZXJGYWN0b3J5Mikge1xuICAgIHRoaXMuX3JlbmRlcmVyID0gdGhpcy5yZW5kZXJlckZhY3RvcnkuY3JlYXRlUmVuZGVyZXIobnVsbCwgbnVsbCk7XG4gIH1cblxuICBjcmVhdGVEaWFncmFtKCkge1xuICAgIHRoaXMuZGlhZ3JhbU1vZGVsID0gbmV3IERpYWdyYW1Nb2RlbCh0aGlzKTtcbiAgICByZXR1cm4gdGhpcy5kaWFncmFtTW9kZWw7XG4gIH1cblxuICByZWdpc3RlckRlZmF1bHRGYWN0b3JpZXMoKSB7XG4gICAgdGhpcy5yZWdpc3Rlck5vZGVGYWN0b3J5KG5ldyBEZWZhdWx0Tm9kZUZhY3RvcnkodGhpcy5yZXNvbHZlciwgdGhpcy5fcmVuZGVyZXIpKTtcbiAgICB0aGlzLnJlZ2lzdGVyUG9ydEZhY3RvcnkobmV3IERlZmF1bHRQb3J0RmFjdG9yeSh0aGlzLnJlc29sdmVyLCB0aGlzLl9yZW5kZXJlcikpO1xuICAgIHRoaXMucmVnaXN0ZXJMaW5rRmFjdG9yeShuZXcgRGVmYXVsdExpbmtGYWN0b3J5KHRoaXMucmVzb2x2ZXIsIHRoaXMuX3JlbmRlcmVyKSk7XG4gICAgdGhpcy5yZWdpc3RlckxhYmVsRmFjdG9yeShuZXcgRGVmYXVsdExhYmVsRmFjdG9yeSh0aGlzLnJlc29sdmVyLCB0aGlzLl9yZW5kZXJlcikpO1xuICB9XG5cbiAgLy8jcmVnaW9uIEZhY3Rvcmllc1xuICAvLyBMQUJFTFNcbiAgcmVnaXN0ZXJMYWJlbEZhY3RvcnkobGFiZWxGYWN0b3J5OiBBYnN0cmFjdExhYmVsRmFjdG9yeSkge1xuICAgIHRoaXMubGFiZWxGYWN0b3JpZXMuc2V0KGxhYmVsRmFjdG9yeS50eXBlLCBsYWJlbEZhY3RvcnkpO1xuICB9XG5cbiAgZ2V0TGFiZWxGYWN0b3JpZXMoKTogRW50aXR5TWFwPEFic3RyYWN0TGFiZWxGYWN0b3J5PiB7XG4gICAgcmV0dXJuIHRoaXMubGFiZWxGYWN0b3JpZXM7XG4gIH1cblxuICBnZXRMYWJlbEZhY3RvcnkodHlwZTogc3RyaW5nKTogQWJzdHJhY3RMYWJlbEZhY3Rvcnkge1xuICAgIGlmICh0aGlzLmxhYmVsRmFjdG9yaWVzLmhhcyh0eXBlKSkge1xuICAgICAgcmV0dXJuIHRoaXMubGFiZWxGYWN0b3JpZXMuZ2V0KHR5cGUpO1xuICAgIH1cbiAgICB0aHJvdyBuZXcgRXJyb3IoYGNhbm5vdCBmaW5kIGZhY3RvcnkgZm9yIG5vZGUgb2YgdHlwZTogWyR7dHlwZX1dYCk7XG4gIH1cblxuICBnZXRGYWN0b3J5Rm9yTGFiZWwobGFiZWw6IExhYmVsTW9kZWwpOiBBYnN0cmFjdExhYmVsRmFjdG9yeSB8IG51bGwge1xuICAgIHJldHVybiB0aGlzLmdldExhYmVsRmFjdG9yeShsYWJlbC5nZXRUeXBlKCkpO1xuICB9XG5cbiAgZ2VuZXJhdGVXaWRnZXRGb3JMYWJlbChsYWJlbDogTGFiZWxNb2RlbCwgbGFiZWxIb3N0OiBWaWV3Q29udGFpbmVyUmVmKTogQ29tcG9uZW50UmVmPExhYmVsTW9kZWw+IHwgbnVsbCB7XG4gICAgY29uc3QgbGFiZWxGYWN0b3J5ID0gdGhpcy5nZXRGYWN0b3J5Rm9yTGFiZWwobGFiZWwpO1xuICAgIGlmICghbGFiZWxGYWN0b3J5KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYENhbm5vdCBmaW5kIHdpZGdldCBmYWN0b3J5IGZvciBub2RlOiAke2xhYmVsLmdldFR5cGUoKX1gKTtcbiAgICB9XG4gICAgcmV0dXJuIGxhYmVsRmFjdG9yeS5nZW5lcmF0ZVdpZGdldChsYWJlbCwgbGFiZWxIb3N0KTtcbiAgfVxuXG4gIC8vIE5PREVTXG4gIHJlZ2lzdGVyTm9kZUZhY3Rvcnkobm9kZUZhY3Rvcnk6IEFic3RyYWN0Tm9kZUZhY3RvcnkpIHtcbiAgICB0aGlzLm5vZGVGYWN0b3JpZXMuc2V0KG5vZGVGYWN0b3J5LnR5cGUsIG5vZGVGYWN0b3J5KTtcbiAgfVxuXG4gIGdldE5vZGVGYWN0b3JpZXMoKTogRW50aXR5TWFwPEFic3RyYWN0Tm9kZUZhY3Rvcnk+IHtcbiAgICByZXR1cm4gdGhpcy5ub2RlRmFjdG9yaWVzO1xuICB9XG5cbiAgZ2V0Tm9kZUZhY3RvcnkodHlwZTogc3RyaW5nKTogQWJzdHJhY3ROb2RlRmFjdG9yeSB7XG4gICAgaWYgKHRoaXMubm9kZUZhY3Rvcmllcy5oYXModHlwZSkpIHtcbiAgICAgIHJldHVybiB0aGlzLm5vZGVGYWN0b3JpZXMuZ2V0KHR5cGUpO1xuICAgIH1cbiAgICB0aHJvdyBuZXcgRXJyb3IoYGNhbm5vdCBmaW5kIGZhY3RvcnkgZm9yIG5vZGUgb2YgdHlwZTogWyR7dHlwZX1dYCk7XG4gIH1cblxuICBnZXRGYWN0b3J5Rm9yTm9kZShub2RlOiBOb2RlTW9kZWwpOiBBYnN0cmFjdE5vZGVGYWN0b3J5IHwgbnVsbCB7XG4gICAgcmV0dXJuIHRoaXMuZ2V0Tm9kZUZhY3Rvcnkobm9kZS5nZXRUeXBlKCkpO1xuICB9XG5cbiAgZ2VuZXJhdGVXaWRnZXRGb3JOb2RlKG5vZGU6IE5vZGVNb2RlbCwgbm9kZXNIb3N0OiBWaWV3Q29udGFpbmVyUmVmKTogQ29tcG9uZW50UmVmPE5vZGVNb2RlbD4gfCBudWxsIHtcbiAgICBjb25zdCBub2RlRmFjdG9yeSA9IHRoaXMuZ2V0RmFjdG9yeUZvck5vZGUobm9kZSk7XG4gICAgaWYgKCFub2RlRmFjdG9yeSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBDYW5ub3QgZmluZCB3aWRnZXQgZmFjdG9yeSBmb3Igbm9kZTogJHtub2RlLmdldFR5cGUoKX1gKTtcbiAgICB9XG4gICAgcmV0dXJuIG5vZGVGYWN0b3J5LmdlbmVyYXRlV2lkZ2V0KHRoaXMsIG5vZGUsIG5vZGVzSG9zdCk7XG4gIH1cblxuICAvLyBQT1JUU1xuICByZWdpc3RlclBvcnRGYWN0b3J5KGZhY3Rvcnk6IEFic3RyYWN0UG9ydEZhY3RvcnkpIHtcbiAgICB0aGlzLnBvcnRGYWN0b3JpZXMuc2V0KGZhY3RvcnkudHlwZSwgZmFjdG9yeSk7XG4gIH1cblxuICBnZXRQb3J0RmFjdG9yaWVzKCkge1xuICAgIHJldHVybiB0aGlzLnBvcnRGYWN0b3JpZXM7XG4gIH1cblxuICBnZXRQb3J0RmFjdG9yeSh0eXBlOiBzdHJpbmcpOiBBYnN0cmFjdFBvcnRGYWN0b3J5IHtcbiAgICBpZiAodGhpcy5wb3J0RmFjdG9yaWVzLmhhcyh0eXBlKSkge1xuICAgICAgcmV0dXJuIHRoaXMucG9ydEZhY3Rvcmllcy5nZXQodHlwZSk7XG4gICAgfVxuICAgIHRocm93IG5ldyBFcnJvcihgY2Fubm90IGZpbmQgZmFjdG9yeSBmb3IgcG9ydCBvZiB0eXBlOiBbJHt0eXBlfV1gKTtcbiAgfVxuXG4gIGdldEZhY3RvcnlGb3JQb3J0KHBvcnQ6IFBvcnRNb2RlbCk6IEFic3RyYWN0UG9ydEZhY3RvcnkgfCBudWxsIHtcbiAgICByZXR1cm4gdGhpcy5nZXRQb3J0RmFjdG9yeShwb3J0LmdldFR5cGUoKSk7XG4gIH1cblxuICBnZW5lcmF0ZVdpZGdldEZvclBvcnQocG9ydDogUG9ydE1vZGVsLCBwb3J0c0hvc3Q6IFZpZXdDb250YWluZXJSZWYpOiBDb21wb25lbnRSZWY8UG9ydE1vZGVsPiB8IG51bGwge1xuICAgIGNvbnN0IHBvcnRGYWN0b3J5ID0gdGhpcy5nZXRGYWN0b3J5Rm9yUG9ydChwb3J0KTtcbiAgICBpZiAoIXBvcnRGYWN0b3J5KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYENhbm5vdCBmaW5kIHdpZGdldCBmYWN0b3J5IGZvciBwb3J0OiAke3BvcnQuZ2V0VHlwZSgpfWApO1xuICAgIH1cbiAgICByZXR1cm4gcG9ydEZhY3RvcnkuZ2VuZXJhdGVXaWRnZXQocG9ydCwgcG9ydHNIb3N0KTtcbiAgfVxuXG4gIC8vIExJTktTXG4gIGdldExpbmtGYWN0b3JpZXMoKTogRW50aXR5TWFwPEFic3RyYWN0TGlua0ZhY3Rvcnk+IHtcbiAgICByZXR1cm4gdGhpcy5saW5rRmFjdG9yaWVzO1xuICB9XG5cbiAgcmVnaXN0ZXJMaW5rRmFjdG9yeShmYWN0b3J5OiBBYnN0cmFjdExpbmtGYWN0b3J5KSB7XG4gICAgdGhpcy5saW5rRmFjdG9yaWVzLnNldChmYWN0b3J5LnR5cGUsIGZhY3RvcnkpO1xuICB9XG5cbiAgZ2V0TGlua0ZhY3RvcnkodHlwZTogc3RyaW5nKTogQWJzdHJhY3RMaW5rRmFjdG9yeSB7XG4gICAgaWYgKHRoaXMubGlua0ZhY3Rvcmllcy5oYXModHlwZSkpIHtcbiAgICAgIHJldHVybiB0aGlzLmxpbmtGYWN0b3JpZXMuZ2V0KHR5cGUpO1xuICAgIH1cbiAgICB0aHJvdyBuZXcgRXJyb3IoYGNhbm5vdCBmaW5kIGZhY3RvcnkgZm9yIGxpbmsgb2YgdHlwZTogWyR7dHlwZX1dYCk7XG4gIH1cblxuICBnZXRGYWN0b3J5Rm9yTGluayhsaW5rOiBMaW5rTW9kZWwpOiBBYnN0cmFjdExpbmtGYWN0b3J5IHwgbnVsbCB7XG4gICAgcmV0dXJuIHRoaXMuZ2V0TGlua0ZhY3RvcnkobGluay5nZXRUeXBlKCkpO1xuICB9XG5cbiAgZ2VuZXJhdGVXaWRnZXRGb3JMaW5rKGxpbms6IExpbmtNb2RlbCwgbGlua3NIb3N0OiBWaWV3Q29udGFpbmVyUmVmKTogQ29tcG9uZW50UmVmPExpbmtNb2RlbD4gfCBudWxsIHtcbiAgICBjb25zdCBsaW5rRmFjdG9yeSA9IHRoaXMuZ2V0RmFjdG9yeUZvckxpbmsobGluayk7XG4gICAgaWYgKCFsaW5rRmFjdG9yeSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBDYW5ub3QgZmluZCBsaW5rIGZhY3RvcnkgZm9yIGxpbms6ICR7bGluay5nZXRUeXBlKCl9YCk7XG4gICAgfVxuICAgIHJldHVybiBsaW5rRmFjdG9yeS5nZW5lcmF0ZVdpZGdldCh0aGlzLCBsaW5rLCBsaW5rc0hvc3QpO1xuICB9XG4gIC8vI2VuZHJlZ2lvblxuXG4gIGdldE5vZGVFbGVtZW50KG5vZGU6IE5vZGVNb2RlbCk6IEhUTUxFbGVtZW50IHtcbiAgICBjb25zdCBzZWxlY3RvciA9IHRoaXMuY2FudmFzJC52YWx1ZS5xdWVyeVNlbGVjdG9yKGBbZGF0YS1ub2RlaWQ9XCIke25vZGUuaWR9XCJdYCk7XG4gICAgaWYgKHNlbGVjdG9yID09PSBudWxsKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0Nhbm5vdCBmaW5kIE5vZGUgZWxlbWVudCB3aXRoIG5vZGUgaWQ6IFsnICsgbm9kZS5pZCArICddJyk7XG4gICAgfVxuICAgIHJldHVybiBzZWxlY3RvciBhcyBIVE1MRWxlbWVudDtcbiAgfVxuXG4gIGdldE5vZGVQb3J0RWxlbWVudChwb3J0OiBQb3J0TW9kZWwpOiBIVE1MRWxlbWVudCB7XG4gICAgY29uc3Qgc2VsZWN0b3IgPSB0aGlzLmNhbnZhcyQudmFsdWUucXVlcnlTZWxlY3RvcihcbiAgICAgIGBbZGF0YS1ub2RlaWQ9XCIke3BvcnQuZ2V0UGFyZW50KCkuaWR9XCJdIFtkYXRhLXBvcnRpZD1cIiR7cG9ydC5pZH1cIl1gXG4gICAgKTtcbiAgICBpZiAoc2VsZWN0b3IgPT09IG51bGwpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgJ0Nhbm5vdCBmaW5kIE5vZGUgUG9ydCBlbGVtZW50IHdpdGggbm9kZSBpZDogWycgKyBwb3J0LmdldFBhcmVudCgpLmlkICsgJ10gYW5kIHBvcnQgaWQ6IFsnICsgcG9ydC5pZCArICddJ1xuICAgICAgKTtcbiAgICB9XG4gICAgcmV0dXJuIHNlbGVjdG9yIGFzIEhUTUxFbGVtZW50O1xuICB9XG5cbiAgZ2V0UG9ydENlbnRlcihwb3J0OiBQb3J0TW9kZWwpIHtcbiAgICBjb25zdCBzb3VyY2VFbGVtZW50ID0gdGhpcy5nZXROb2RlUG9ydEVsZW1lbnQocG9ydCk7XG4gICAgY29uc3Qgc291cmNlUmVjdCA9IHNvdXJjZUVsZW1lbnQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG4gICAgY29uc3QgcmVsID0gdGhpcy5nZXRSZWxhdGl2ZVBvaW50KHNvdXJjZVJlY3QubGVmdCwgc291cmNlUmVjdC50b3ApO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIHg6XG4gICAgICAgIHNvdXJjZUVsZW1lbnQub2Zmc2V0V2lkdGggLyAyICtcbiAgICAgICAgKHJlbC54IC0gdGhpcy5kaWFncmFtTW9kZWwuZ2V0T2Zmc2V0WCgpKSAvICh0aGlzLmRpYWdyYW1Nb2RlbC5nZXRab29tTGV2ZWwoKSAvIDEwMC4wKSxcbiAgICAgIHk6XG4gICAgICAgIHNvdXJjZUVsZW1lbnQub2Zmc2V0SGVpZ2h0IC8gMiArXG4gICAgICAgIChyZWwueSAtIHRoaXMuZGlhZ3JhbU1vZGVsLmdldE9mZnNldFkoKSkgLyAodGhpcy5kaWFncmFtTW9kZWwuZ2V0Wm9vbUxldmVsKCkgLyAxMDAuMClcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIENhbGN1bGF0ZSByZWN0YW5ndWxhciBjb29yZGluYXRlcyBvZiB0aGUgcG9ydCBwYXNzZWQgaW4uXG4gICAqL1xuICBnZXRQb3J0Q29vcmRzKFxuICAgIHBvcnQ6IFBvcnRNb2RlbFxuICApOiB7XG4gICAgeDogbnVtYmVyO1xuICAgIHk6IG51bWJlcjtcbiAgICB3aWR0aDogbnVtYmVyO1xuICAgIGhlaWdodDogbnVtYmVyO1xuICB9IHtcbiAgICBjb25zdCBzb3VyY2VFbGVtZW50ID0gdGhpcy5nZXROb2RlUG9ydEVsZW1lbnQocG9ydCk7XG4gICAgY29uc3Qgc291cmNlUmVjdCA9IHNvdXJjZUVsZW1lbnQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkgYXMgRE9NUmVjdDtcbiAgICBjb25zdCBjYW52YXNSZWN0ID0gdGhpcy5jYW52YXMkLnZhbHVlLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpIGFzIENsaWVudFJlY3Q7XG5cbiAgICByZXR1cm4ge1xuICAgICAgeDogKHNvdXJjZVJlY3QueCAtIHRoaXMuZGlhZ3JhbU1vZGVsLmdldE9mZnNldFgoKSkgLyAodGhpcy5kaWFncmFtTW9kZWwuZ2V0Wm9vbUxldmVsKCkgLyAxMDAuMCkgLSBjYW52YXNSZWN0LmxlZnQsXG4gICAgICB5OiAoc291cmNlUmVjdC55IC0gdGhpcy5kaWFncmFtTW9kZWwuZ2V0T2Zmc2V0WSgpKSAvICh0aGlzLmRpYWdyYW1Nb2RlbC5nZXRab29tTGV2ZWwoKSAvIDEwMC4wKSAtIGNhbnZhc1JlY3QudG9wLFxuICAgICAgd2lkdGg6IHNvdXJjZVJlY3Qud2lkdGgsXG4gICAgICBoZWlnaHQ6IHNvdXJjZVJlY3QuaGVpZ2h0XG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBEZXRlcm1pbmUgdGhlIHdpZHRoIGFuZCBoZWlnaHQgb2YgdGhlIG5vZGUgcGFzc2VkIGluLlxuICAgKiBJdCBjdXJyZW50bHkgYXNzdW1lcyBub2RlcyBoYXZlIGEgcmVjdGFuZ3VsYXIgc2hhcGUsIGNhbiBiZSBvdmVycmlkZW4gZm9yIGN1c3RvbWlzZWQgc2hhcGVzLlxuICAgKi9cbiAgZ2V0Tm9kZURpbWVuc2lvbnMobm9kZTogTm9kZU1vZGVsKTogeyB3aWR0aDogbnVtYmVyOyBoZWlnaHQ6IG51bWJlciB9IHtcbiAgICBpZiAoIXRoaXMuY2FudmFzJC52YWx1ZSkge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgd2lkdGg6IDAsXG4gICAgICAgIGhlaWdodDogMFxuICAgICAgfTtcbiAgICB9XG5cbiAgICBjb25zdCBub2RlRWxlbWVudCA9IHRoaXMuZ2V0Tm9kZUVsZW1lbnQobm9kZSk7XG4gICAgY29uc3Qgbm9kZVJlY3QgPSBub2RlRWxlbWVudC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoK