UNPKG

ngx-diagrams

Version:

> Light Weight, Modular, Typed Diagram Engine for Angular

110 lines 20 kB
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