ngx-diagrams
Version:
> Light Weight, Modular, Typed Diagram Engine for Angular
110 lines • 20 kB
JavaScript
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ViewChild, ViewContainerRef } from '@angular/core';
import { combineLatest } from 'rxjs';
import { filter, takeUntil } from 'rxjs/operators';
import { createValueState } from '../../../state/state';
import { generateCurvePath, generateDynamicPath } from '../../../utils/tool-kit.util';
import { DefaultLinkModel } from '../../models/default-link.model';
export class DefaultLinkComponent extends DefaultLinkModel {
constructor(cdRef) {
super({ type: 'ngdx-default-link' });
this.cdRef = cdRef;
this.path$ = createValueState(null, this.entityPipe('path'));
this.points$ = createValueState([], this.entityPipe('points'));
}
trackByPoints(i, point) {
return point.id;
}
ngOnInit() {
if (this.diagramEngine.getSmartRouting()) {
this.pathFinding = this.diagramEngine.getPathfinding();
}
}
ngAfterViewInit() {
const firstPCoords$ = this.getFirstPoint().selectCoords();
const lastPCoords$ = this.getLastPoint().selectCoords();
// Observe link coords and update drawing accordingly
combineLatest([firstPCoords$, lastPCoords$])
.pipe(takeUntil(this.onEntityDestroy()))
.subscribe(([firstPCoords, lastPCoords]) => {
const points = [firstPCoords, lastPCoords];
if (this.diagramEngine.getSmartRouting()) {
// first step: calculate a direct path between the points being linked
const directPathCoords = this.pathFinding.calculateDirectPath(firstPCoords, lastPCoords);
const routingMatrix = this.diagramEngine.getRoutingMatrix();
// now we need to extract, from the routing matrix, the very first walkable points
// so they can be used as origin and destination of the link to be created
const smartLink = this.pathFinding.calculateLinkStartEndCoords(routingMatrix, directPathCoords);
if (smartLink) {
const { start, end, pathToStart, pathToEnd } = smartLink;
// second step: calculate a path avoiding hitting other elements
const simplifiedPath = this.pathFinding.calculateDynamicPath(routingMatrix, start, end, pathToStart, pathToEnd);
const smartPath = generateDynamicPath(simplifiedPath);
this.path$.set(smartPath).emit();
}
}
else {
// handle regular links
// draw the smoothing
// if the points are too close, just draw a straight line
const isHorizontal = Math.abs(firstPCoords.x - lastPCoords.x) > Math.abs(firstPCoords.y - lastPCoords.y);
const xOrY = isHorizontal ? 'x' : 'y';
let isStraight = false;
if (Math.abs(points[0][xOrY] - points[1][xOrY]) < 50) {
isStraight = true;
}
const path = generateCurvePath(firstPCoords, lastPCoords, isStraight ? 0 : this.curvyness);
this.path$.set(path).emit();
}
const label = this.getLabel();
// update label position
if (label) {
label.setCoords(this.calcCenterOfPath(firstPCoords, lastPCoords));
// TODO: check whether we want the label to rotate along with the line
// label.setRotation(this.calcLabelIncline(firstPCoords, lastPCoords));
}
// TODO: handle the multiple lines in between the points
// https://github.com/projectstorm/react-diagrams/blob/master/src/defaults/widgets/DefaultLinkWidget.tsx#L344-L371
this.cdRef.detectChanges();
});
// observe link label and draw/remove accordingly
this.selectLabel()
.pipe(filter(Boolean))
.subscribe((label) => {
this.diagramEngine.generateWidgetForLabel(label, this.labelLayer);
this.cdRef.detectChanges();
});
}
calcLabelIncline(firstPoint, secondPoint) {
const dy = secondPoint.y - firstPoint.y;
const dx = secondPoint.x - firstPoint.x;
if (dx === 0) {
return 0;
}
let inclineAngel = (Math.atan(dy / dx) * 180) / Math.PI;
if (inclineAngel < 0) {
inclineAngel += 180;
}
return inclineAngel;
}
calcCenterOfPath(firstPoint, secondPoint) {
return { x: (firstPoint.x + secondPoint.x) / 2 + 20, y: (firstPoint.y + secondPoint.y) / 2 + 20 };
}
selectPath() {
return this.path$.value$;
}
}
DefaultLinkComponent.decorators = [
{ type: Component, args: [{
selector: 'ngdx-default-link',
template: "<!-- Label Host -->\n<ng-template #labelLayer></ng-template>\n\n<svg class=\"link-container\">\n <!-- Link -->\n <g [id]=\"id\">\n <path\n [attr.stroke-width]=\"width\"\n [attr.stroke]=\"selectColor() | async\"\n [attr.d]=\"selectPath() | async\"\n class=\"default-link\"\n (mouseleave)=\"setHovered(false)\"\n (mouseenter)=\"setHovered()\"\n [ngClass]=\"{ hovered: selectHovered() | async }\"\n ></path>\n <path\n class=\"default-link\"\n (mouseleave)=\"setHovered(false)\"\n (mouseenter)=\"setHovered()\"\n [attr.stroke-width]=\"20\"\n [attr.stroke]=\"selectColor() | async\"\n [attr.stroke-linecap]=\"'round'\"\n [attr.data-linkid]=\"id\"\n [attr.stroke-opacity]=\"(selectHovered() | async) ? '0.1' : '0'\"\n [attr.d]=\"selectPath() | async\"\n ></path>\n </g>\n\n <!-- Points -->\n <g *ngFor=\"let point of getPoints(); trackBy: trackByPoints\" [id]=\"point.id\">\n <circle\n fill=\"currentColor\"\n [attr.cx]=\"point.selectX() | async\"\n [attr.cy]=\"point.selectY() | async\"\n r=\"5\"\n class=\"default-point\"\n [ngClass]=\"{ hovered: point.selectHovered() | async }\"\n />\n <circle\n [attr.data-pointid]=\"point.id\"\n [attr.data-linkid]=\"id\"\n (mouseleave)=\"point.setHovered(false); setHovered(false)\"\n (mouseenter)=\"point.setHovered(); setHovered()\"\n [attr.cx]=\"point.selectX() | async\"\n [attr.cy]=\"point.selectY() | async\"\n r=\"15\"\n [attr.opacity]=\"0\"\n [ngClass]=\"{ selected: point.selectSelected() | async }\"\n />\n </g>\n</svg>\n",
changeDetection: ChangeDetectionStrategy.OnPush,
styles: [".link-container{pointer-events:all;position:relative}.default-link,.link-container{fill:none;overflow:visible}@-webkit-keyframes dash{0%{stroke-dashoffset:24}to{stroke-dashoffset:0}}@keyframes dash{0%{stroke-dashoffset:24}to{stroke-dashoffset:0}}.default-link.hovered{-webkit-animation:dash 1s linear infinite;animation:dash 1s linear infinite;stroke:#00c0ff;stroke-dasharray:10,2}.default-point{color:#d3d3d3;overflow:visible;pointer-events:all}.default-point.hovered{color:#00c0ff}"]
},] }
];
DefaultLinkComponent.ctorParameters = () => [
{ type: ChangeDetectorRef }
];
DefaultLinkComponent.propDecorators = {
labelLayer: [{ type: ViewChild, args: ['labelLayer', { read: ViewContainerRef, static: true },] }]
};
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVmYXVsdC1saW5rLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIuLi8uLi8uLi8uLi9saWJzL25neC1kaWFncmFtcy9zcmMvIiwic291cmNlcyI6WyJsaWIvZGVmYXVsdHMvY29tcG9uZW50cy9kZWZhdWx0LWxpbmsvZGVmYXVsdC1saW5rLmNvbXBvbmVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBRUwsdUJBQXVCLEVBQ3ZCLGlCQUFpQixFQUNqQixTQUFTLEVBRVQsU0FBUyxFQUNULGdCQUFnQixFQUNqQixNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQUUsYUFBYSxFQUFjLE1BQU0sTUFBTSxDQUFDO0FBQ2pELE9BQU8sRUFBRSxNQUFNLEVBQUUsU0FBUyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFLbkQsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDeEQsT0FBTyxFQUFFLGlCQUFpQixFQUFFLG1CQUFtQixFQUFFLE1BQU0sOEJBQThCLENBQUM7QUFDdEYsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFRbkUsTUFBTSxPQUFPLG9CQUFxQixTQUFRLGdCQUFnQjtJQVN4RCxZQUFvQixLQUF3QjtRQUMxQyxLQUFLLENBQUMsRUFBRSxJQUFJLEVBQUUsbUJBQW1CLEVBQUUsQ0FBQyxDQUFDO1FBRG5CLFVBQUssR0FBTCxLQUFLLENBQW1CO1FBTDVDLFVBQUssR0FBRyxnQkFBZ0IsQ0FBUyxJQUFJLEVBQUUsSUFBSSxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDO1FBQ2hFLFlBQU8sR0FBRyxnQkFBZ0IsQ0FBZSxFQUFFLEVBQUUsSUFBSSxDQUFDLFVBQVUsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDO0lBTXhFLENBQUM7SUFFRCxhQUFhLENBQUMsQ0FBUyxFQUFFLEtBQWlCO1FBQ3hDLE9BQU8sS0FBSyxDQUFDLEVBQUUsQ0FBQztJQUNsQixDQUFD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LENBQUM7U0FDckI7UUFFRCxPQUFPLFlBQVksQ0FBQztJQUN0QixDQUFDO0lBRUQsZ0JBQWdCLENBQUMsVUFBa0IsRUFBRSxXQUFtQjtRQUN0RCxPQUFPLEVBQUUsQ0FBQyxFQUFFLENBQUMsVUFBVSxDQUFDLENBQUMsR0FBRyxXQUFXLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDLEVBQUUsQ0FBQyxVQUFVLENBQUMsQ0FBQyxHQUFHLFdBQVcsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUM7SUFDcEcsQ0FBQztJQUVELFVBQVU7UUFDUixPQUFPLElBQUksQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDO0lBQzNCLENBQUM7OztZQTNIRixTQUFTLFNBQUM7Z0JBQ1QsUUFBUSxFQUFFLG1CQUFtQjtnQkFDN0IsOG5EQUE0QztnQkFFNUMsZUFBZSxFQUFFLHVCQUF1QixDQUFDLE1BQU07O2FBQ2hEOzs7WUFyQkMsaUJBQWlCOzs7eUJBdUJoQixTQUFTLFNBQUMsWUFBWSxFQUFFLEVBQUUsSUFBSSxFQUFFLGdCQUFnQixFQUFFLE1BQU0sRUFBRSxJQUFJLEVBQUUiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBBZnRlclZpZXdJbml0LFxuICBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneSxcbiAgQ2hhbmdlRGV0ZWN0b3JSZWYsXG4gIENvbXBvbmVudCxcbiAgT25Jbml0LFxuICBWaWV3Q2hpbGQsXG4gIFZpZXdDb250YWluZXJSZWZcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBjb21iaW5lTGF0ZXN0LCBPYnNlcnZhYmxlIH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyBmaWx0ZXIsIHRha2VVbnRpbCB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcbmltcG9ydCB7IENvb3JkcyB9IGZyb20gJy4uLy4uLy4uL2ludGVyZmFjZXMnO1xuaW1wb3J0IHsgTGFiZWxNb2RlbCB9IGZyb20gJy4uLy4uLy4uL21vZGVscy9sYWJlbC5tb2RlbCc7XG5pbXBvcnQgeyBQb2ludE1vZGVsIH0gZnJvbSAnLi4vLi4vLi4vbW9kZWxzL3BvaW50Lm1vZGVsJztcbmltcG9ydCB7IFBhdGhGaW5kaW5nIH0gZnJvbSAnLi4vLi4vLi4vcGx1Z2lucy9zbWFydC1yb3V0aW5nLnBsdWdpbic7XG5pbXBvcnQgeyBjcmVhdGVWYWx1ZVN0YXRlIH0gZnJvbSAnLi4vLi4vLi4vc3RhdGUvc3RhdGUnO1xuaW1wb3J0IHsgZ2VuZXJhdGVDdXJ2ZVBhdGgsIGdlbmVyYXRlRHluYW1pY1BhdGggfSBmcm9tICcuLi8uLi8uLi91dGlscy90b29sLWtpdC51dGlsJztcbmltcG9ydCB7IERlZmF1bHRMaW5rTW9kZWwgfSBmcm9tICcuLi8uLi9tb2RlbHMvZGVmYXVsdC1saW5rLm1vZGVsJztcblxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnbmdkeC1kZWZhdWx0LWxpbmsnLFxuICB0ZW1wbGF0ZVVybDogJy4vZGVmYXVsdC1saW5rLmNvbXBvbmVudC5odG1sJyxcbiAgc3R5bGVVcmxzOiBbJy4vZGVmYXVsdC1saW5rLmNvbXBvbmVudC5zY3NzJ10sXG4gIGNoYW5nZURldGVjdGlvbjogQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3kuT25QdXNoXG59KVxuZXhwb3J0IGNsYXNzIERlZmF1bHRMaW5rQ29tcG9uZW50IGV4dGVuZHMgRGVmYXVsdExpbmtNb2RlbCBpbXBsZW1lbnRzIEFmdGVyVmlld0luaXQsIE9uSW5pdCB7XG4gIEBWaWV3Q2hpbGQoJ2xhYmVsTGF5ZXInLCB7IHJlYWQ6IFZpZXdDb250YWluZXJSZWYsIHN0YXRpYzogdHJ1ZSB9KVxuICBsYWJlbExheWVyOiBWaWV3Q29udGFpbmVyUmVmO1xuXG4gIHBhdGgkID0gY3JlYXRlVmFsdWVTdGF0ZTxzdHJpbmc+KG51bGwsIHRoaXMuZW50aXR5UGlwZSgncGF0aCcpKTtcbiAgcG9pbnRzJCA9IGNyZWF0ZVZhbHVlU3RhdGU8UG9pbnRNb2RlbFtdPihbXSwgdGhpcy5lbnRpdHlQaXBlKCdwb2ludHMnKSk7XG5cbiAgcGF0aEZpbmRpbmc6IFBhdGhGaW5kaW5nOyAvLyBvbmx5IHNldCB3aGVuIHNtYXJ0IHJvdXRpbmcgaXMgYWN0aXZlXG5cbiAgY29uc3RydWN0b3IocHJpdmF0ZSBjZFJlZjogQ2hhbmdlRGV0ZWN0b3JSZWYpIHtcbiAgICBzdXBlcih7IHR5cGU6ICduZ2R4LWRlZmF1bHQtbGluaycgfSk7XG4gIH1cblxuICB0cmFja0J5UG9pbnRzKGk6IG51bWJlciwgcG9pbnQ6IFBvaW50TW9kZWwpIHtcbiAgICByZXR1cm4gcG9pbnQuaWQ7XG4gIH1cblxuICBuZ09uSW5pdCgpIHtcbiAgICBpZiAodGhpcy5kaWFncmFtRW5naW5lLmdldFNtYXJ0Um91dGluZygpKSB7XG4gICAgICB0aGlzLnBhdGhGaW5kaW5nID0gdGhpcy5kaWFncmFtRW5naW5lLmdldFBhdGhmaW5kaW5nKCk7XG4gICAgfVxuICB9XG5cbiAgbmdBZnRlclZpZXdJbml0KCkge1xuICAgIGNvbnN0IGZpcnN0UENvb3JkcyQgPSB0aGlzLmdldEZpcnN0UG9pbnQoKS5zZWxlY3RDb29yZHMoKTtcbiAgICBjb25zdCBsYXN0UENvb3JkcyQgPSB0aGlzLmdldExhc3RQb2ludCgpLnNlbGVjdENvb3JkcygpO1xuXG4gICAgLy8gT2JzZXJ2ZSBsaW5rIGNvb3JkcyBhbmQgdXBkYXRlIGRyYXdpbmcgYWNjb3JkaW5nbHlcbiAgICBjb21iaW5lTGF0ZXN0KFtmaXJzdFBDb29yZHMkLCBsYXN0UENvb3JkcyRdKVxuICAgICAgLnBpcGUodGFrZVVudGlsKHRoaXMub25FbnRpdHlEZXN0cm95KCkpKVxuICAgICAgLnN1YnNjcmliZSgoW2ZpcnN0UENvb3JkcywgbGFzdFBDb29yZHNdKSA9PiB7XG4gICAgICAgIGNvbnN0IHBvaW50cyA9IFtmaXJzdFBDb29yZHMsIGxhc3RQQ29vcmRzXTtcblxuICAgICAgICBpZiAodGhpcy5kaWFncmFtRW5naW5lLmdldFNtYXJ0Um91dGluZygpKSB7XG4gICAgICAgICAgLy8gZmlyc3Qgc3RlcDogY2FsY3VsYXRlIGEgZGlyZWN0IHBhdGggYmV0d2VlbiB0aGUgcG9pbnRzIGJlaW5nIGxpbmtlZFxuICAgICAgICAgIGNvbnN0IGRpcmVjdFBhdGhDb29yZHMgPSB0aGlzLnBhdGhGaW5kaW5nLmNhbGN1bGF0ZURpcmVjdFBhdGgoZmlyc3RQQ29vcmRzLCBsYXN0UENvb3Jkcyk7XG4gICAgICAgICAgY29uc3Qgcm91dGluZ01hdHJpeCA9IHRoaXMuZGlhZ3JhbUVuZ2luZS5nZXRSb3V0aW5nTWF0cml4KCk7XG5cbiAgICAgICAgICAvLyBub3cgd2UgbmVlZCB0byBleHRyYWN0LCBmcm9tIHRoZSByb3V0aW5nIG1hdHJpeCwgdGhlIHZlcnkgZmlyc3Qgd2Fsa2FibGUgcG9pbnRzXG4gICAgICAgICAgLy8gc28gdGhleSBjYW4gYmUgdXNlZCBhcyBvcmlnaW4gYW5kIGRlc3RpbmF0aW9uIG9mIHRoZSBsaW5rIHRvIGJlIGNyZWF0ZWRcbiAgICAgICAgICBjb25zdCBzbWFydExpbmsgPSB0aGlzLnBhdGhGaW5kaW5nLmNhbGN1bGF0ZUxpbmtTdGFydEVuZENvb3Jkcyhyb3V0aW5nTWF0cml4LCBkaXJlY3RQYXRoQ29vcmRzKTtcblxuICAgICAgICAgIGlmIChzbWFydExpbmspIHtcbiAgICAgICAgICAgIGNvbnN0IHsgc3RhcnQsIGVuZCwgcGF0aFRvU3RhcnQsIHBhdGhUb0VuZCB9ID0gc21hcnRMaW5rO1xuICAgICAgICAgICAgLy8gc2Vjb25kIHN0ZXA6IGNhbGN1bGF0ZSBhIHBhdGggYXZvaWRpbmcgaGl0dGluZyBvdGhlciBlbGVtZW50c1xuICAgICAgICAgICAgY29uc3Qgc2ltcGxpZmllZFBhdGggPSB0aGlzLnBhdGhGaW5kaW5nLmNhbGN1bGF0ZUR5bmFtaWNQYXRoKFxuICAgICAgICAgICAgICByb3V0aW5nTWF0cml4LFxuICAgICAgICAgICAgICBzdGFydCxcbiAgICAgICAgICAgICAgZW5kLFxuICAgICAgICAgICAgICBwYXRoVG9TdGFydCxcbiAgICAgICAgICAgICAgcGF0aFRvRW5kXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgY29uc3Qgc21hcnRQYXRoID0gZ2VuZXJhdGVEeW5hbWljUGF0aChzaW1wbGlmaWVkUGF0aCk7XG4gICAgICAgICAgICB0aGlzLnBhdGgkLnNldChzbWFydFBhdGgpLmVtaXQoKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgLy8gaGFuZGxlIHJlZ3VsYXIgbGlua3NcbiAgICAgICAgICAvLyBkcmF3IHRoZSBzbW9vdGhpbmdcbiAgICAgICAgICAvLyBpZiB0aGUgcG9pbnRzIGFyZSB0b28gY2xvc2UsIGp1c3QgZHJhdyBhIHN0cmFpZ2h0IGxpbmVcbiAgICAgICAgICBjb25zdCBpc0hvcml6b250YWwgPSBNYXRoLmFicyhmaXJzdFBDb29yZHMueCAtIGxhc3RQQ29vcmRzLngpID4gTWF0aC5hYnMoZmlyc3RQQ29vcmRzLnkgLSBsYXN0UENvb3Jkcy55KTtcbiAgICAgICAgICBjb25zdCB4T3JZID0gaXNIb3Jpem9udGFsID8gJ3gnIDogJ3knO1xuICAgICAgICAgIGxldCBpc1N0cmFpZ2h0ID0gZmFsc2U7XG4gICAgICAgICAgaWYgKE1hdGguYWJzKHBvaW50c1swXVt4T3JZXSAtIHBvaW50c1sxXVt4T3JZXSkgPCA1MCkge1xuICAgICAgICAgICAgaXNTdHJhaWdodCA9IHRydWU7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgY29uc3QgcGF0aCA9IGdlbmVyYXRlQ3VydmVQYXRoKGZpcnN0UENvb3JkcywgbGFzdFBDb29yZHMsIGlzU3RyYWlnaHQgPyAwIDogdGhpcy5jdXJ2eW5lc3MpO1xuICAgICAgICAgIHRoaXMucGF0aCQuc2V0KHBhdGgpLmVtaXQoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGxhYmVsID0gdGhpcy5nZXRMYWJlbCgpO1xuICAgICAgICAvLyB1cGRhdGUgbGFiZWwgcG9zaXRpb25cbiAgICAgICAgaWYgKGxhYmVsKSB7XG4gICAgICAgICAgbGFiZWwuc2V0Q29vcmRzKHRoaXMuY2FsY0NlbnRlck9mUGF0aChmaXJzdFBDb29yZHMsIGxhc3RQQ29vcmRzKSk7XG5cbiAgICAgICAgICAvLyBUT0RPOiBjaGVjayB3aGV0aGVyIHdlIHdhbnQgdGhlIGxhYmVsIHRvIHJvdGF0ZSBhbG9uZyB3aXRoIHRoZSBsaW5lXG4gICAgICAgICAgLy8gbGFiZWwuc2V0Um90YXRpb24odGhpcy5jYWxjTGFiZWxJbmNsaW5lKGZpcnN0UENvb3JkcywgbGFzdFBDb29yZHMpKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFRPRE86IGhhbmRsZSB0aGUgbXVsdGlwbGUgbGluZXMgaW4gYmV0d2VlbiB0aGUgcG9pbnRzXG4gICAgICAgIC8vIGh0dHBzOi8vZ2l0aHViLmNvbS9wcm9qZWN0c3Rvcm0vcmVhY3QtZGlhZ3JhbXMvYmxvYi9tYXN0ZXIvc3JjL2RlZmF1bHRzL3dpZGdldHMvRGVmYXVsdExpbmtXaWRnZXQudHN4I0wzNDQtTDM3MVxuXG4gICAgICAgIHRoaXMuY2RSZWYuZGV0ZWN0Q2hhbmdlcygpO1xuICAgICAgfSk7XG5cbiAgICAvLyBvYnNlcnZlIGxpbmsgbGFiZWwgYW5kIGRyYXcvcmVtb3ZlIGFjY29yZGluZ2x5XG4gICAgdGhpcy5zZWxlY3RMYWJlbCgpXG4gICAgICAucGlwZShmaWx0ZXIoQm9vbGVhbikpXG4gICAgICAuc3Vic2NyaWJlKChsYWJlbDogTGFiZWxNb2RlbCkgPT4ge1xuICAgICAgICB0aGlzLmRpYWdyYW1FbmdpbmUuZ2VuZXJhdGVXaWRnZXRGb3JMYWJlbChsYWJlbCwgdGhpcy5sYWJlbExheWVyKTtcbiAgICAgICAgdGhpcy5jZFJlZi5kZXRlY3RDaGFuZ2VzKCk7XG4gICAgICB9KTtcbiAgfVxuXG4gIGNhbGNMYWJlbEluY2xpbmUoZmlyc3RQb2ludDogQ29vcmRzLCBzZWNvbmRQb2ludDogQ29vcmRzKTogbnVtYmVyIHtcbiAgICBjb25zdCBkeSA9IHNlY29uZFBvaW50LnkgLSBmaXJzdFBvaW50Lnk7XG4gICAgY29uc3QgZHggPSBzZWNvbmRQb2ludC54IC0gZmlyc3RQb2ludC54O1xuXG4gICAgaWYgKGR4ID09PSAwKSB7XG4gICAgICByZXR1cm4gMDtcbiAgICB9XG5cbiAgICBsZXQgaW5jbGluZUFuZ2VsID0gKE1hdGguYXRhbihkeSAvIGR4KSAqIDE4MCkgLyBNYXRoLlBJO1xuXG4gICAgaWYgKGluY2xpbmVBbmdlbCA8IDApIHtcbiAgICAgIGluY2xpbmVBbmdlbCArPSAxODA7XG4gICAgfVxuXG4gICAgcmV0dXJuIGluY2xpbmVBbmdlbDtcbiAgfVxuXG4gIGNhbGNDZW50ZXJPZlBhdGgoZmlyc3RQb2ludDogQ29vcmRzLCBzZWNvbmRQb2ludDogQ29vcmRzKTogQ29vcmRzIHtcbiAgICByZXR1cm4geyB4OiAoZmlyc3RQb2ludC54ICsgc2Vjb25kUG9pbnQueCkgLyAyICsgMjAsIHk6IChmaXJzdFBvaW50LnkgKyBzZWNvbmRQb2ludC55KSAvIDIgKyAyMCB9O1xuICB9XG5cbiAgc2VsZWN0UGF0aCgpOiBPYnNlcnZhYmxlPHN0cmluZz4ge1xuICAgIHJldHVybiB0aGlzLnBhdGgkLnZhbHVlJDtcbiAgfVxufVxuIl19