ngx-diagrams
Version:
> Light Weight, Modular, Typed Diagram Engine for Angular
424 lines • 62.5 kB
JavaScript
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