ngx-diagrams
Version:
This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 7.2.0.
660 lines • 74 kB
JavaScript
/**
* @fileoverview added by tsickle
* Generated from: lib/containers/diagram/diagram.component.ts
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
import { Component, Input, Renderer2, Output, EventEmitter, ViewChild, ViewContainerRef, ElementRef, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';
import { DiagramModel } from '../../models/diagram.model';
import { NodeModel } from '../../models/node.model';
import { BehaviorSubject, combineLatest, ReplaySubject } from 'rxjs';
import { filter, takeUntil } from 'rxjs/operators';
import { MoveCanvasAction, SelectingAction, LinkCreatedAction } from '../../actions';
import { MoveItemsAction } from '../../actions/move-items.action';
import { PointModel } from '../../models/point.model';
import { PortModel } from '../../models/port.model';
import { some } from 'lodash';
export class NgxDiagramComponent {
/**
* @param {?} renderer
* @param {?} cdRef
*/
constructor(renderer, cdRef) {
this.renderer = renderer;
this.cdRef = cdRef;
this.allowCanvasZoon = true;
this.allowCanvasTranslation = true;
this.inverseZoom = true;
this.allowLooseLinks = true;
this.actionStartedFiring = new EventEmitter();
this.actionStillFiring = new EventEmitter();
this.actionStoppedFiring = new EventEmitter();
this.action$ = new BehaviorSubject(null);
this.destroyed$ = new ReplaySubject(1);
this.mouseUpListener = (/**
* @return {?}
*/
() => { });
this.mouseMoveListener = (/**
* @return {?}
*/
() => { });
this.onMouseUp = (/**
* @param {?} event
* @return {?}
*/
(event) => {
/** @type {?} */
const diagramEngine = this.diagramModel.getDiagramEngine();
/** @type {?} */
const action = this.action$.getValue();
// are we going to connect a link to something?
if (action instanceof MoveItemsAction) {
/** @type {?} */
const element = this.getMouseElement(event);
action.selectionModels.forEach((/**
* @param {?} model
* @return {?}
*/
model => {
// only care about points connecting to things
if (!(model.model instanceof PointModel)) {
return;
}
if (element && element.model instanceof PortModel && !diagramEngine.isModelLocked(element.model)) {
/** @type {?} */
const link = model.model.getLink();
if (link.getTargetPort() !== null) {
// if this was a valid link already and we are adding a node in the middle, create 2 links from the original
if (link.getTargetPort() !== element.model && link.getSourcePort() !== element.model) {
/** @type {?} */
const targetPort = link.getTargetPort();
/** @type {?} */
const newLink = link.clone({});
newLink.setSourcePort(element.model);
newLink.setTargetPort(targetPort);
link.setTargetPort(element.model);
targetPort.removeLink(link);
newLink.removePointsBefore(newLink.getPoints()[link.getPointIndex(model.model)]);
link.removePointsAfter(model.model);
diagramEngine.getDiagramModel().addLink(newLink);
// if we are connecting to the same target or source, destroy tweener points
}
else if (link.getTargetPort() === element.model) {
link.removePointsAfter(model.model);
}
else if (link.getSourcePort() === element.model) {
link.removePointsBefore(model.model);
}
}
else {
link.setTargetPort(element.model);
/** @type {?} */
const targetPort = link.getTargetPort();
/** @type {?} */
const srcPort = link.getSourcePort();
if (targetPort.id !== srcPort.id) {
// link is valid, fire the event
this.startFiringAction(new LinkCreatedAction(event.clientX, event.clientY, link));
}
}
}
}));
// check for / destroy any loose links in any models which have been moved
if (!this.allowLooseLinks) {
action.selectionModels.forEach((/**
* @param {?} model
* @return {?}
*/
model => {
// only care about points connecting to things
if (!(model.model instanceof PointModel)) {
return;
}
/** @type {?} */
const selectedPoint = model.model;
/** @type {?} */
const link = selectedPoint.getLink();
if (link.getSourcePort() === null || link.getTargetPort() === null) {
link.destroy();
}
}));
}
// destroy any invalid links
action.selectionModels.forEach((/**
* @param {?} model
* @return {?}
*/
model => {
// only care about points connecting to things
if (!(model.model instanceof PointModel)) {
return;
}
/** @type {?} */
const link = model.model.getLink();
/** @type {?} */
const sourcePort = link.getSourcePort();
/** @type {?} */
const targetPort = link.getTargetPort();
if (sourcePort !== null && targetPort !== null) {
if (!sourcePort.canLinkToPort(targetPort)) {
// link not allowed
link.destroy();
}
else if (some(Object.values(targetPort.getLinks()), (/**
* @param {?} l
* @return {?}
*/
(l) => l !== link && (l.getSourcePort() === sourcePort || l.getTargetPort() === sourcePort)))) {
// link is a duplicate
link.destroy();
}
}
}));
this.stopFiringAction();
}
else {
this.stopFiringAction();
}
this.mouseUpListener();
this.mouseMoveListener();
this.action$.next(null);
});
this.onMouseMove = (/**
* @param {?} event
* @return {?}
*/
(event) => {
/** @type {?} */
const action = this.action$.getValue();
if (action === null || action === undefined) {
return;
}
if (action instanceof SelectingAction) {
/** @type {?} */
const relative = this.diagramModel.getDiagramEngine().getRelativePoint(event.clientX, event.clientY);
Object.values(this.diagramModel.getNodes()).forEach((/**
* @param {?} node
* @return {?}
*/
node => {
if (((/** @type {?} */ (action))).containsElement(node.getCoords(), this.diagramModel)) {
node.setSelected();
}
else {
node.setSelected(false);
}
}));
Object.values(this.diagramModel.getLinks()).forEach((/**
* @param {?} link
* @return {?}
*/
link => {
/** @type {?} */
let allSelected = true;
link.getPoints().forEach((/**
* @param {?} point
* @return {?}
*/
point => {
if (((/** @type {?} */ (action))).containsElement(point.getCoords(), this.diagramModel)) {
point.setSelected();
}
else {
point.setSelected(false);
allSelected = false;
}
}));
if (allSelected) {
link.setSelected();
}
}));
action.mouseX2 = relative.x;
action.mouseY2 = relative.y;
this.fireAction();
this.action$.next(action);
return;
}
else if (action instanceof MoveItemsAction) {
/** @type {?} */
const coords = {
x: event.clientX - action.mouseX,
y: event.clientY - action.mouseY
};
/** @type {?} */
const amountZoom = this.diagramModel.getZoomLevel() / 100;
action.selectionModels.forEach((/**
* @param {?} model
* @return {?}
*/
model => {
// in this case we need to also work out the relative grid position
if (model.model instanceof NodeModel || (model.model instanceof PointModel && !model.model.isConnectedToPort())) {
/** @type {?} */
const newCoords = { x: model.initialX + coords.x / amountZoom, y: model.initialY + coords.y / amountZoom };
model.model.setCoords(this.diagramModel.getGridPosition(newCoords));
if (model.model instanceof NodeModel) {
// update port coordinates as well
Object.values(model.model.getPorts()).forEach((/**
* @param {?} port
* @return {?}
*/
port => {
/** @type {?} */
const portCoords = this.diagramModel.getDiagramEngine().getPortCoords(port);
port.updateCoords(portCoords);
}));
}
}
else if (model.model instanceof PointModel) {
// we want points that are connected to ports, to not necessarily snap to grid
// this stuff needs to be pixel perfect, dont touch it
/** @type {?} */
const newCoords = this.diagramModel.getGridPosition({ x: coords.x / amountZoom, y: coords.y / amountZoom });
model.model.setCoords({ x: model.initialX + newCoords.x, y: model.initialY + newCoords.y });
}
}));
this.fireAction();
}
else if (action instanceof MoveCanvasAction) {
if (this.allowCanvasTranslation) {
this.diagramModel.setOffset(action.initialOffsetX + (event.clientX - action.mouseX), action.initialOffsetY + (event.clientY - action.mouseY));
this.fireAction();
}
}
});
}
// TODO: handle destruction of container, resseting all observables to avoid memory leaks!
/**
* @return {?}
*/
ngOnInit() {
if (this.diagramModel) {
this.diagramModel.getDiagramEngine().setCanvas(this.canvas.nativeElement);
this.nodes$ = this.diagramModel.selectNodes();
this.links$ = this.diagramModel.selectLinks();
this.nodesRendered$ = new BehaviorSubject(false);
this.nodes$.pipe(takeUntil(this.destroyed$)).subscribe((/**
* @param {?} nodes
* @return {?}
*/
nodes => {
this.nodesRendered$.next(false);
Object.values(nodes).forEach((/**
* @param {?} node
* @return {?}
*/
node => {
if (!node.getPainted()) {
this.diagramModel.getDiagramEngine().generateWidgetForNode(node, this.nodesLayer);
node.setPainted();
this.cdRef.detectChanges();
}
}));
this.nodesRendered$.next(true);
}));
}
}
/**
* @return {?}
*/
ngOnDestroy() {
this.destroyed$.next(true);
this.destroyed$.complete();
}
/**
* @return {?}
*/
ngAfterViewInit() {
combineLatest([this.nodesRendered$, this.links$])
.pipe(takeUntil(this.destroyed$), filter((/**
* @param {?} __0
* @return {?}
*/
([nodesRendered, _]) => !!nodesRendered)))
.subscribe((/**
* @param {?} __0
* @return {?}
*/
([_, links]) => {
Object.values(links).forEach((/**
* @param {?} link
* @return {?}
*/
link => {
if (!link.getPainted()) {
if (link.getSourcePort() !== null) {
/** @type {?} */
const portCenter = this.diagramModel.getDiagramEngine().getPortCenter(link.getSourcePort());
link.getPoints()[0].setCoords(portCenter);
/** @type {?} */
const portCoords = this.diagramModel.getDiagramEngine().getPortCoords(link.getSourcePort());
link.getSourcePort().updateCoords(portCoords);
}
if (link.getTargetPort() !== null) {
/** @type {?} */
const portCenter = this.diagramModel.getDiagramEngine().getPortCenter(link.getTargetPort());
link.getPoints()[link.getPoints().length - 1].setCoords(portCenter);
/** @type {?} */
const portCoords = this.diagramModel.getDiagramEngine().getPortCoords(link.getTargetPort());
link.getTargetPort().updateCoords(portCoords);
}
this.diagramModel.getDiagramEngine().generateWidgetForLink(link, this.linksLayer);
link.setPainted();
this.cdRef.detectChanges();
}
}));
}));
}
/**
* fire the action registered and notify subscribers
* @return {?}
*/
fireAction() {
if (this.action$.value) {
this.actionStillFiring.emit(this.action$.value);
}
}
/**
* Unregister the action, post firing and notify subscribers
* @param {?=} shouldSkipEvent
* @return {?}
*/
stopFiringAction(shouldSkipEvent) {
if (!shouldSkipEvent) {
this.actionStoppedFiring.emit(this.action$.value);
}
this.action$.next(null);
}
/**
* Register the new action, pre firing and notify subscribers
* @param {?} action
* @return {?}
*/
startFiringAction(action) {
this.action$.next(action);
this.actionStartedFiring.emit(action);
}
/**
* @return {?}
*/
selectAction() {
return this.action$;
}
/**
* @return {?}
*/
shouldDrawSelectionBox() {
/** @type {?} */
const action = this.action$.getValue();
if (action instanceof SelectingAction) {
action.getBoxDimensions();
return true;
}
return false;
}
/**
* @param {?} event
* @return {?}
*/
getMouseElement(event) {
/** @type {?} */
const target = (/** @type {?} */ (event.target));
// is it a port?
/** @type {?} */
let element = target.closest('[data-portid]');
if (element) {
// get the relevant node and return the port.
/** @type {?} */
const nodeEl = target.closest('[data-nodeid]');
return {
model: this.diagramModel.getNode(nodeEl.getAttribute('data-nodeid')).getPort(element.getAttribute('data-portid')),
element
};
}
// look for a point
element = target.closest('[data-pointid]');
if (element) {
return {
model: this.diagramModel.getLink(element.getAttribute('data-linkid')).getPointModel(element.getAttribute('data-pointid')),
element
};
}
// look for a link
element = target.closest('[data-linkid]');
if (element) {
return {
model: this.diagramModel.getLink(element.getAttribute('data-linkid')),
element
};
}
// a node maybe
element = target.closest('[data-nodeid]');
if (element) {
return {
model: this.diagramModel.getNode(element.getAttribute('data-nodeid')),
element
};
}
// just the canvas
return null;
}
/**
* @param {?} event
* @return {?}
*/
onMouseDown(event) {
if (event.button === 3) {
return;
}
/** @type {?} */
const selectedModel = this.getMouseElement(event);
// canvas selected
if (selectedModel === null) {
// multiple selection
if (event.shiftKey) {
// initiate multiple selection selector
/** @type {?} */
const relative = this.diagramModel.getDiagramEngine().getRelativePoint(event.clientX, event.clientY);
this.startFiringAction(new SelectingAction(relative.x, relative.y));
}
else {
// drag canvas action
this.diagramModel.clearSelection();
this.startFiringAction(new MoveCanvasAction(event.clientX, event.clientY, this.diagramModel));
}
}
else if (selectedModel.model instanceof PortModel) {
// its a port element, we want to drag a link
if (!this.diagramModel.getDiagramEngine().isModelLocked(selectedModel.model)) {
/** @type {?} */
const relative = this.diagramModel.getDiagramEngine().getRelativeMousePoint(event);
/** @type {?} */
const sourcePort = selectedModel.model;
/** @type {?} */
const link = sourcePort.createLinkModel();
link.setSourcePort(sourcePort);
if (link) {
link.removeMiddlePoints();
if (link.getSourcePort() !== sourcePort) {
link.setSourcePort(sourcePort);
}
link.setTargetPort(null);
link.getFirstPoint().setCoords(relative);
link.getLastPoint().setCoords(relative);
this.diagramModel.clearSelection();
link.getLastPoint().setSelected();
this.diagramModel.addLink(link);
this.startFiringAction(new MoveItemsAction(event.clientX, event.clientY, this.diagramModel.getDiagramEngine()));
}
}
else {
this.diagramModel.clearSelection();
}
}
else {
// its some other element, probably want to move it
if (!event.shiftKey && !selectedModel.model.getSelected()) {
this.diagramModel.clearSelection();
}
selectedModel.model.setSelected();
this.startFiringAction(new MoveItemsAction(event.clientX, event.clientY, this.diagramModel.getDiagramEngine()));
}
// create mouseMove and mouseUp listeners
this.mouseMoveListener = this.renderer.listen(document, 'mousemove', this.onMouseMove);
this.mouseUpListener = this.renderer.listen(document, 'mouseup', this.onMouseUp);
}
/**
* @param {?} event
* @return {?}
*/
onMouseWheel(event) {
if (this.allowCanvasZoon) {
event.preventDefault();
event.stopPropagation();
/** @type {?} */
const currentZoomLevel = this.diagramModel.getZoomLevel();
/** @type {?} */
const oldZoomFactor = currentZoomLevel / 100;
/** @type {?} */
let scrollDelta = this.inverseZoom ? -event.deltaY : event.deltaY;
// check if it is pinch gesture
if (event.ctrlKey && scrollDelta % 1 !== 0) {
/* Chrome and Firefox sends wheel event with deltaY that
have fractional part, also `ctrlKey` prop of the event is true
though ctrl isn't pressed
*/
scrollDelta /= 3;
}
else {
scrollDelta /= 60;
}
if (currentZoomLevel + scrollDelta > 10) {
this.diagramModel.setZoomLevel(currentZoomLevel + scrollDelta);
}
/** @type {?} */
const zoomFactor = this.diagramModel.getZoomLevel() / 100;
/** @type {?} */
const boundingRect = ((/** @type {?} */ (event.currentTarget))).getBoundingClientRect();
/** @type {?} */
const clientWidth = boundingRect.width;
/** @type {?} */
const clientHeight = boundingRect.height;
// compute difference between rect before and after scroll
/** @type {?} */
const widthDiff = clientWidth * zoomFactor - clientWidth * oldZoomFactor;
/** @type {?} */
const heightDiff = clientHeight * zoomFactor - clientHeight * oldZoomFactor;
// compute mouse coords relative to canvas
/** @type {?} */
const clientX = event.clientX - boundingRect.left;
/** @type {?} */
const clientY = event.clientY - boundingRect.top;
// compute width and height increment factor
/** @type {?} */
const xFactor = (clientX - this.diagramModel.getOffsetX()) / oldZoomFactor / clientWidth;
/** @type {?} */
const yFactor = (clientY - this.diagramModel.getOffsetY()) / oldZoomFactor / clientHeight;
this.diagramModel.setOffset(this.diagramModel.getOffsetX() - widthDiff * xFactor, this.diagramModel.getOffsetY() - heightDiff * yFactor);
}
}
}
NgxDiagramComponent.decorators = [
{ type: Component, args: [{
selector: 'ngdx-diagram',
template: "<div class=\"ngdx-diagram\" #canvas (mousedown)=\"onMouseDown($event)\" (wheel)=\"onMouseWheel($event)\">\n\t<!-- Nodes Layer -->\n\t<div\n\t\tclass=\"ngdx-nodes-layer\"\n\t\t[ngStyle]=\"{\n\t\t\ttransform:\n\t\t\t\t'translate(' +\n\t\t\t\t(diagramModel.selectOffsetX() | async) +\n\t\t\t\t'px, ' +\n\t\t\t\t(diagramModel.selectOffsetY() | async) +\n\t\t\t\t'px) scale(' +\n\t\t\t\t(diagramModel.selectZoomLevel() | async) / 100.0 +\n\t\t\t\t')'\n\t\t}\"\n\t>\n\t\t<ng-template #nodesLayer></ng-template>\n\t</div>\n\n\t<!-- Links Layer -->\n\t<div\n\t\tclass=\"ngdx-links-layer\"\n\t\t[ngStyle]=\"{\n\t\t\ttransform:\n\t\t\t\t'translate(' +\n\t\t\t\t(diagramModel.selectOffsetX() | async) +\n\t\t\t\t'px, ' +\n\t\t\t\t(diagramModel.selectOffsetY() | async) +\n\t\t\t\t'px) scale(' +\n\t\t\t\t(diagramModel.selectZoomLevel() | async) / 100.0 +\n\t\t\t\t')'\n\t\t}\"\n\t>\n\t\t<ng-template #linksLayer></ng-template>\n\t</div>\n\n\t<!-- Selection Box -->\n\t<div\n\t\t*ngIf=\"shouldDrawSelectionBox() && selectAction() | async as action\"\n\t\tclass=\"selector\"\n\t\t[ngStyle]=\"{\n\t\t\ttop: action.dimensions.top + 'px',\n\t\t\tleft: action.dimensions.left + 'px',\n\t\t\twidth: action.dimensions.width + 'px',\n\t\t\theight: action.dimensions.height + 'px'\n\t\t}\"\n\t></div>\n</div>\n",
changeDetection: ChangeDetectionStrategy.OnPush,
styles: [".ngdx-diagram{position:relative;flex-grow:1;display:flex;cursor:move;overflow:hidden}.ngdx-diagram .selector{position:absolute;background-color:rgba(0,192,255,.2);border:2px solid #00c0ff}.ngdx-diagram .ngdx-nodes-layer{position:absolute;height:100%;width:100%;transform-origin:0 0;overflow:visible!important;pointer-events:none;z-index:150;top:0;bottom:0;left:0;right:0}.ngdx-diagram .ngdx-links-layer{position:absolute;height:100%;width:100%;transform-origin:0 0;overflow:visible!important;pointer-events:none;z-index:100;top:0;bottom:0;left:0;right:0}"]
}] }
];
/** @nocollapse */
NgxDiagramComponent.ctorParameters = () => [
{ type: Renderer2 },
{ type: ChangeDetectorRef }
];
NgxDiagramComponent.propDecorators = {
diagramModel: [{ type: Input, args: ['model',] }],
allowCanvasZoon: [{ type: Input }],
allowCanvasTranslation: [{ type: Input }],
inverseZoom: [{ type: Input }],
allowLooseLinks: [{ type: Input }],
actionStartedFiring: [{ type: Output }],
actionStillFiring: [{ type: Output }],
actionStoppedFiring: [{ type: Output }],
nodesLayer: [{ type: ViewChild, args: ['nodesLayer', { read: ViewContainerRef, static: true },] }],
linksLayer: [{ type: ViewChild, args: ['linksLayer', { read: ViewContainerRef, static: true },] }],
canvas: [{ type: ViewChild, args: ['canvas', { read: ElementRef, static: true },] }]
};
if (false) {
/** @type {?} */
NgxDiagramComponent.prototype.diagramModel;
/** @type {?} */
NgxDiagramComponent.prototype.allowCanvasZoon;
/** @type {?} */
NgxDiagramComponent.prototype.allowCanvasTranslation;
/** @type {?} */
NgxDiagramComponent.prototype.inverseZoom;
/** @type {?} */
NgxDiagramComponent.prototype.allowLooseLinks;
/** @type {?} */
NgxDiagramComponent.prototype.actionStartedFiring;
/** @type {?} */
NgxDiagramComponent.prototype.actionStillFiring;
/** @type {?} */
NgxDiagramComponent.prototype.actionStoppedFiring;
/** @type {?} */
NgxDiagramComponent.prototype.nodesLayer;
/** @type {?} */
NgxDiagramComponent.prototype.linksLayer;
/** @type {?} */
NgxDiagramComponent.prototype.canvas;
/**
* @type {?}
* @private
*/
NgxDiagramComponent.prototype.nodes$;
/**
* @type {?}
* @private
*/
NgxDiagramComponent.prototype.links$;
/**
* @type {?}
* @private
*/
NgxDiagramComponent.prototype.action$;
/**
* @type {?}
* @private
*/
NgxDiagramComponent.prototype.nodesRendered$;
/**
* @type {?}
* @private
*/
NgxDiagramComponent.prototype.destroyed$;
/**
* @type {?}
* @private
*/
NgxDiagramComponent.prototype.mouseUpListener;
/**
* @type {?}
* @private
*/
NgxDiagramComponent.prototype.mouseMoveListener;
/** @type {?} */
NgxDiagramComponent.prototype.onMouseUp;
/** @type {?} */
NgxDiagramComponent.prototype.onMouseMove;
/**
* @type {?}
* @private
*/
NgxDiagramComponent.prototype.renderer;
/**
* @type {?}
* @private
*/
NgxDiagramComponent.prototype.cdRef;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGlhZ3JhbS5jb21wb25lbnQuanMiLCJzb3VyY2VSb290Ijoibmc6Ly9uZ3gtZGlhZ3JhbXMvIiwic291cmNlcyI6WyJsaWIvY29udGFpbmVycy9kaWFncmFtL2RpYWdyYW0uY29tcG9uZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBQUEsT0FBTyxFQUNOLFNBQVMsRUFFVCxLQUFLLEVBQ0wsU0FBUyxFQUNULE1BQU0sRUFDTixZQUFZLEVBQ1osU0FBUyxFQUNULGdCQUFnQixFQUNoQixVQUFVLEVBRVYsdUJBQXVCLEVBQ3ZCLGlCQUFpQixFQUVqQixNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFDMUQsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBRXBELE9BQU8sRUFBRSxlQUFlLEVBQWMsYUFBYSxFQUFFLGFBQWEsRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUNqRixPQUFPLEVBQUUsTUFBTSxFQUFFLFNBQVMsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQ25ELE9BQU8sRUFBYyxnQkFBZ0IsRUFBRSxlQUFlLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFFakcsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBQ2xFLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUV0RCxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDcEQsT0FBTyxFQUFFLElBQUksRUFBRSxNQUFNLFFBQVEsQ0FBQztBQVE5QixNQUFNLE9BQU8sbUJBQW1COzs7OztJQXlCL0IsWUFBb0IsUUFBbUIsRUFBVSxLQUF3QjtRQUFyRCxhQUFRLEdBQVIsUUFBUSxDQUFXO1FBQVUsVUFBSyxHQUFMLEtBQUssQ0FBbUI7UUF0QmhFLG9CQUFlLEdBQUcsSUFBSSxDQUFDO1FBQ3ZCLDJCQUFzQixHQUFHLElBQUksQ0FB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QkFDaEUsU0FBUyxTQUFDLFFBQVEsRUFBRSxFQUFFLElBQUksRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRTs7OztJQVp2RCwyQ0FBMkM7O0lBQzNDLDhDQUFnQzs7SUFDaEMscURBQXVDOztJQUN2QywwQ0FBNEI7O0lBQzVCLDhDQUFnQzs7SUFFaEMsa0RBQTZFOztJQUM3RSxnREFBMkU7O0lBQzNFLGtEQUE2RTs7SUFFN0UseUNBQWdHOztJQUNoRyx5Q0FBZ0c7O0lBQ2hHLHFDQUE0RTs7Ozs7SUFFNUUscUNBQXVEOzs7OztJQUN2RCxxQ0FBdUQ7Ozs7O0lBQ3ZELHNDQUF5RTs7Ozs7SUFDekUsNkNBQWlEOzs7OztJQUNqRCx5Q0FBa0U7Ozs7O0lBRWxFLDhDQUFtQzs7Ozs7SUFDbkMsZ0RBQXFDOztJQXNKckMsd0NBK0ZFOztJQUVGLDBDQThFRTs7Ozs7SUFuVVUsdUNBQTJCOzs7OztJQUFFLG9DQUFnQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG5cdENvbXBvbmVudCxcblx0T25Jbml0LFxuXHRJbnB1dCxcblx0UmVuZGVyZXIyLFxuXHRPdXRwdXQsXG5cdEV2ZW50RW1pdHRlcixcblx0Vmlld0NoaWxkLFxuXHRWaWV3Q29udGFpbmVyUmVmLFxuXHRFbGVtZW50UmVmLFxuXHRBZnRlclZpZXdJbml0LFxuXHRDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneSxcblx0Q2hhbmdlRGV0ZWN0b3JSZWYsXG5cdE9uRGVzdHJveVxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IERpYWdyYW1Nb2RlbCB9IGZyb20gJy4uLy4uL21vZGVscy9kaWFncmFtLm1vZGVsJztcbmltcG9ydCB7IE5vZGVNb2Rlb