This is an automated email from the ASF dual-hosted git repository.

linxinyuan pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/texera.git


The following commit(s) were added to refs/heads/main by this push:
     new bfca0024e8 feat(gui): show region layer on workflow editor (#3753)
bfca0024e8 is described below

commit bfca0024e809ef162991f47155b29c19d7db3ff9
Author: Xinyuan Lin <[email protected]>
AuthorDate: Sun Oct 19 22:18:43 2025 -0700

    feat(gui): show region layer on workflow editor (#3753)
---
 .../architecture/controller/Controller.scala       |  12 +
 .../controller/WorkflowScheduler.scala             |   2 +
 .../engine/architecture/scheduling/Schedule.scala  |   2 +
 .../websocket/response/RegionUpdateEvent.scala}    |  14 +-
 frontend/package.json                              |   4 +
 .../workspace/component/menu/menu.component.html   |  10 +-
 .../app/workspace/component/menu/menu.component.ts |   5 +
 .../workflow-editor/workflow-editor.component.scss |  13 +-
 .../workflow-editor/workflow-editor.component.ts   |  62 +++
 .../execute-workflow/execute-workflow.service.ts   |   9 +
 .../workflow-graph/model/joint-graph-wrapper.ts    |  23 +-
 .../model/workflow-action.service.ts               |   2 +
 .../types/workflow-websocket.interface.ts          |   5 +
 frontend/tsconfig.json                             |   1 +
 frontend/yarn.lock                                 | 417 ++++++++++++++++++++-
 15 files changed, 539 insertions(+), 42 deletions(-)

diff --git 
a/amber/src/main/scala/org/apache/amber/engine/architecture/controller/Controller.scala
 
b/amber/src/main/scala/org/apache/amber/engine/architecture/controller/Controller.scala
index 93fb4bff1b..67f94398d3 100644
--- 
a/amber/src/main/scala/org/apache/amber/engine/architecture/controller/Controller.scala
+++ 
b/amber/src/main/scala/org/apache/amber/engine/architecture/controller/Controller.scala
@@ -21,6 +21,7 @@ package org.apache.amber.engine.architecture.controller
 
 import akka.actor.SupervisorStrategy.Stop
 import akka.actor.{AllForOneStrategy, Props, SupervisorStrategy}
+import org.apache.texera.web.model.websocket.response.RegionUpdateEvent
 import org.apache.amber.config.ApplicationConfig
 import org.apache.amber.core.virtualidentity.ChannelIdentity
 import org.apache.amber.core.workflow.{PhysicalPlan, WorkflowContext}
@@ -42,6 +43,7 @@ import org.apache.amber.engine.common.ambermessage.{
 }
 import org.apache.amber.engine.common.virtualidentity.util.{CLIENT, 
CONTROLLER, SELF}
 import org.apache.amber.engine.common.{CheckpointState, SerializedState}
+import org.apache.texera.web.SessionState
 
 import scala.concurrent.duration.DurationInt
 
@@ -111,6 +113,16 @@ class Controller(
   override def initState(): Unit = {
     attachRuntimeServicesToCPState()
     cp.workflowScheduler.updateSchedule(physicalPlan)
+
+    val regions: List[List[String]] =
+      cp.workflowScheduler.getSchedule.getRegions.map { region =>
+        region.physicalOps.map(_.id.logicalOpId.id).toList
+      }
+
+    SessionState.getAllSessionStates.foreach { state =>
+      state.send(RegionUpdateEvent(regions))
+    }
+
     val controllerRestoreConf = controllerConfig.stateRestoreConfOpt
     if (controllerRestoreConf.isDefined) {
       globalReplayManager.markRecoveryStatus(CONTROLLER, isRecovering = true)
diff --git 
a/amber/src/main/scala/org/apache/amber/engine/architecture/controller/WorkflowScheduler.scala
 
b/amber/src/main/scala/org/apache/amber/engine/architecture/controller/WorkflowScheduler.scala
index 4f0cc13e66..6fd8c3ff03 100644
--- 
a/amber/src/main/scala/org/apache/amber/engine/architecture/controller/WorkflowScheduler.scala
+++ 
b/amber/src/main/scala/org/apache/amber/engine/architecture/controller/WorkflowScheduler.scala
@@ -34,6 +34,8 @@ class WorkflowScheduler(
   var physicalPlan: PhysicalPlan = _
   private var schedule: Schedule = _
 
+  def getSchedule: Schedule = schedule
+
   /**
     * Update the schedule to be executed, based on the given physicalPlan.
     */
diff --git 
a/amber/src/main/scala/org/apache/amber/engine/architecture/scheduling/Schedule.scala
 
b/amber/src/main/scala/org/apache/amber/engine/architecture/scheduling/Schedule.scala
index 7f3bc1e3ca..421b7aa325 100644
--- 
a/amber/src/main/scala/org/apache/amber/engine/architecture/scheduling/Schedule.scala
+++ 
b/amber/src/main/scala/org/apache/amber/engine/architecture/scheduling/Schedule.scala
@@ -22,6 +22,8 @@ package org.apache.amber.engine.architecture.scheduling
 case class Schedule(private val levelSets: Map[Int, Set[Region]]) extends 
Iterator[Set[Region]] {
   private var currentLevel = levelSets.keys.minOption.getOrElse(0)
 
+  def getRegions: List[Region] = levelSets.values.flatten.toList
+
   override def hasNext: Boolean = levelSets.isDefinedAt(currentLevel)
 
   override def next(): Set[Region] = {
diff --git 
a/amber/src/main/scala/org/apache/amber/engine/architecture/scheduling/Schedule.scala
 
b/amber/src/main/scala/org/apache/texera/web/model/websocket/response/RegionUpdateEvent.scala
similarity index 66%
copy from 
amber/src/main/scala/org/apache/amber/engine/architecture/scheduling/Schedule.scala
copy to 
amber/src/main/scala/org/apache/texera/web/model/websocket/response/RegionUpdateEvent.scala
index 7f3bc1e3ca..1cf644ecac 100644
--- 
a/amber/src/main/scala/org/apache/amber/engine/architecture/scheduling/Schedule.scala
+++ 
b/amber/src/main/scala/org/apache/texera/web/model/websocket/response/RegionUpdateEvent.scala
@@ -17,16 +17,8 @@
  * under the License.
  */
 
-package org.apache.amber.engine.architecture.scheduling
+package org.apache.texera.web.model.websocket.response
 
-case class Schedule(private val levelSets: Map[Int, Set[Region]]) extends 
Iterator[Set[Region]] {
-  private var currentLevel = levelSets.keys.minOption.getOrElse(0)
+import org.apache.texera.web.model.websocket.event.TexeraWebSocketEvent
 
-  override def hasNext: Boolean = levelSets.isDefinedAt(currentLevel)
-
-  override def next(): Set[Region] = {
-    val regions = levelSets(currentLevel)
-    currentLevel += 1
-    regions
-  }
-}
+case class RegionUpdateEvent(regions: List[List[String]]) extends 
TexeraWebSocketEvent
diff --git a/frontend/package.json b/frontend/package.json
index e8aefd32f0..f1a0e0cc80 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -47,7 +47,9 @@
     "@types/plotly.js-basic-dist-min": "2.12.4",
     "ajv": "8.10.0",
     "backbone": "1.4.1",
+    "concaveman": "2.0.0",
     "content-disposition": "0.5.4",
+    "d3": "6.4.0",
     "dagre": "0.8.5",
     "deep-map": "2.0.0",
     "edit-distance": "1.0.4",
@@ -111,7 +113,9 @@
     "@nrwl/nx-cloud": "19.1.0",
     "@nx/angular": "20.0.3",
     "@types/backbone": "1.4.15",
+    "@types/concaveman": "1.1.6",
     "@types/content-disposition": "0",
+    "@types/d3-shape": "2.1.2",
     "@types/dagre": "0.7.47",
     "@types/file-saver": "2.0.5",
     "@types/graphlib": "2.1.8",
diff --git a/frontend/src/app/workspace/component/menu/menu.component.html 
b/frontend/src/app/workspace/component/menu/menu.component.html
index dde9a8aff9..fa4bdc09e3 100644
--- a/frontend/src/app/workspace/component/menu/menu.component.html
+++ b/frontend/src/app/workspace/component/menu/menu.component.html
@@ -164,8 +164,14 @@
                   >Grid</label
                 >
               </li>
-            </ul>
-            <ul nz-menu>
+              <li nz-menu-item>
+                <label
+                  nz-checkbox
+                  [(ngModel)]="showRegion"
+                  (ngModelChange)="toggleRegion()"
+                  >Region</label
+                >
+              </li>
               <li nz-menu-item>
                 <label
                   nz-checkbox
diff --git a/frontend/src/app/workspace/component/menu/menu.component.ts 
b/frontend/src/app/workspace/component/menu/menu.component.ts
index ae804b0e1d..1096b3af0d 100644
--- a/frontend/src/app/workspace/component/menu/menu.component.ts
+++ b/frontend/src/app/workspace/component/menu/menu.component.ts
@@ -88,6 +88,7 @@ export class MenuComponent implements OnInit, OnDestroy {
   public isWorkflowModifiable: boolean = false;
   public workflowId?: number;
   public isExportDeactivate: boolean = false;
+  public showRegion: boolean = false;
   public showGrid: boolean = false;
   public showNumWorkers: boolean = false;
   protected readonly DASHBOARD_USER_WORKFLOW = DASHBOARD_USER_WORKFLOW;
@@ -469,6 +470,10 @@ export class MenuComponent implements OnInit, OnDestroy {
     
this.workflowActionService.getJointGraphWrapper().mainPaper.setGridSize(this.showGrid
 ? 2 : 1);
   }
 
+  public toggleRegion(): void {
+    
this.workflowActionService.getJointGraphWrapper().mainPaper.el.classList.toggle("hide-region",
 !this.showRegion);
+  }
+
   /**
    * This method will run the autoLayout function
    *
diff --git 
a/frontend/src/app/workspace/component/workflow-editor/workflow-editor.component.scss
 
b/frontend/src/app/workspace/component/workflow-editor/workflow-editor.component.scss
index a51b289dab..72caad0296 100644
--- 
a/frontend/src/app/workspace/component/workflow-editor/workflow-editor.component.scss
+++ 
b/frontend/src/app/workspace/component/workflow-editor/workflow-editor.component.scss
@@ -25,17 +25,8 @@
   height: 100%;
 }
 
-::ng-deep #workflow-editor .connection-wrap {
-  stroke-width: 0;
-}
-
-::ng-deep #workflow-editor .link-tools .tool-remove path {
-  fill: #d8656a;
-  transform: translate(-12px, -12px);
-}
-
-::ng-deep #workflow-editor .link-tools .tool-remove circle {
-  fill-opacity: 0;
+::ng-deep .hide-region .region {
+  display: none;
 }
 
 ::ng-deep .hide-worker-count .operator-worker-count {
diff --git 
a/frontend/src/app/workspace/component/workflow-editor/workflow-editor.component.ts
 
b/frontend/src/app/workspace/component/workflow-editor/workflow-editor.component.ts
index b18f4baa86..e7780e7aea 100644
--- 
a/frontend/src/app/workspace/component/workflow-editor/workflow-editor.component.ts
+++ 
b/frontend/src/app/workspace/component/workflow-editor/workflow-editor.component.ts
@@ -41,6 +41,8 @@ import * as _ from "lodash";
 import * as joint from "jointjs";
 import { isDefined } from "../../../common/util/predicate";
 import { GuiConfigService } from "../../../common/service/gui-config.service";
+import { line, curveCatmullRomClosed } from "d3-shape";
+import concaveman from "concaveman";
 
 // jointjs interactive options for enabling and disabling interactivity
 // 
https://resources.jointjs.com/docs/jointjs/v3.2/joint.html#dia.Paper.prototype.options.interactive
@@ -161,6 +163,7 @@ export class WorkflowEditorComponent implements OnInit, 
AfterViewInit, OnDestroy
     this.handlePortHighlightEvent();
     this.registerPortDisplayNameChangeHandler();
     this.handleOperatorStatisticsUpdate();
+    this.handleRegionUpdate();
     this.handleOperatorSuggestionHighlightEvent();
     this.handleElementDelete();
     this.handleElementSelectAll();
@@ -330,6 +333,65 @@ export class WorkflowEditorComponent implements OnInit, 
AfterViewInit, OnDestroy
       });
   }
 
+  private handleRegionUpdate(): void {
+    this.editor.classList.add("hide-region");
+    const Region = joint.dia.Element.define(
+      "region",
+      {
+        attrs: {
+          body: {
+            fill: "rgba(255,213,79,0.2)",
+            pointerEvents: "none",
+            class: "region",
+          },
+        },
+      },
+      {
+        markup: [{ tagName: "path", selector: "body" }],
+      }
+    );
+
+    let regionMap: { regionElement: joint.dia.Element; operators: 
joint.dia.Cell[] }[] = [];
+    // update region elements on execution
+    this.executeWorkflowService
+      .getRegionUpdateStream()
+      .pipe(untilDestroyed(this))
+      .subscribe(regions => {
+        this.paper.model
+          .getCells()
+          .filter(element => element instanceof Region)
+          .forEach(element => element.remove());
+
+        regionMap = regions.map(region => {
+          const element = new Region();
+          const ops = region.map(id => this.paper.getModelById(id));
+          this.paper.model.addCell(element);
+          this.updateRegionElement(element, ops);
+          return { regionElement: element, operators: ops };
+        });
+      });
+
+    this.paper.model.on("change:position", operator => {
+      regionMap
+        .filter(region => region.operators.includes(operator))
+        .forEach(region => this.updateRegionElement(region.regionElement, 
region.operators));
+    });
+  }
+
+  private updateRegionElement(regionElement: joint.dia.Element, operators: 
joint.dia.Cell[]) {
+    const points = operators.flatMap(op => {
+      const { x, y, width, height } = op.getBBox(),
+        padding = 15;
+      return [
+        [x - padding, y - padding],
+        [x + width + padding, y - padding],
+        [x - padding, y + height + padding + 10],
+        [x + width + padding, y + height + padding + 10],
+      ];
+    });
+    regionElement.attr("body/d", 
line().curve(curveCatmullRomClosed)(concaveman(points, 2, 0) as [number, 
number][]));
+  }
+
   /**
    * Handles restore offset default event by translating jointJS paper
    *  back to original position
diff --git 
a/frontend/src/app/workspace/service/execute-workflow/execute-workflow.service.ts
 
b/frontend/src/app/workspace/service/execute-workflow/execute-workflow.service.ts
index 4621241014..3d9ca84b5a 100644
--- 
a/frontend/src/app/workspace/service/execute-workflow/execute-workflow.service.ts
+++ 
b/frontend/src/app/workspace/service/execute-workflow/execute-workflow.service.ts
@@ -85,6 +85,8 @@ export class ExecuteWorkflowService {
     current: ExecutionStateInfo;
   }>();
 
+  private regionUpdateStream = new Subject<readonly string[][]>();
+
   // TODO: move this to another service, or redesign how this
   //   information is stored on the frontend.
   private assignedWorkerIds: Map<string, readonly string[]> = new Map();
@@ -99,6 +101,9 @@ export class ExecuteWorkflowService {
   ) {
     workflowWebsocketService.websocketEvent().subscribe(event => {
       switch (event.type) {
+        case "RegionUpdateEvent":
+          this.regionUpdateStream.next(event.regions);
+          break;
         case "WorkerAssignmentUpdateEvent":
           this.assignedWorkerIds.set(event.operatorId, event.workerIds);
           break;
@@ -329,6 +334,10 @@ export class ExecuteWorkflowService {
     return this.executionStateStream.asObservable();
   }
 
+  public getRegionUpdateStream(): Observable<readonly string[][]> {
+    return this.regionUpdateStream.asObservable();
+  }
+
   public resetExecutionState(): void {
     this.currentState = {
       state: ExecutionState.Uninitialized,
diff --git 
a/frontend/src/app/workspace/service/workflow-graph/model/joint-graph-wrapper.ts
 
b/frontend/src/app/workspace/service/workflow-graph/model/joint-graph-wrapper.ts
index a519bac1a2..2d32bb43cc 100644
--- 
a/frontend/src/app/workspace/service/workflow-graph/model/joint-graph-wrapper.ts
+++ 
b/frontend/src/app/workspace/service/workflow-graph/model/joint-graph-wrapper.ts
@@ -585,16 +585,19 @@ export class JointGraphWrapper {
   }
 
   public autoLayoutJoint(): void {
-    joint.layout.DirectedGraph.layout(this.jointGraph, {
-      dagre: dagre,
-      graphlib: graphlib,
-      nodeSep: 100,
-      edgeSep: 150,
-      rankSep: 80,
-      ranker: "tight-tree",
-      rankDir: "LR",
-      resizeClusters: true,
-    });
+    joint.layout.DirectedGraph.layout(
+      [...this.jointGraph.getElements().filter(el => el.attributes.type !== 
"region"), ...this.jointGraph.getLinks()],
+      {
+        dagre: dagre,
+        graphlib: graphlib,
+        nodeSep: 100,
+        edgeSep: 150,
+        rankSep: 80,
+        ranker: "tight-tree",
+        rankDir: "LR",
+        resizeClusters: true,
+      }
+    );
   }
 
   /**
diff --git 
a/frontend/src/app/workspace/service/workflow-graph/model/workflow-action.service.ts
 
b/frontend/src/app/workspace/service/workflow-graph/model/workflow-action.service.ts
index 54e0a14779..40092419fd 100644
--- 
a/frontend/src/app/workspace/service/workflow-graph/model/workflow-action.service.ts
+++ 
b/frontend/src/app/workspace/service/workflow-graph/model/workflow-action.service.ts
@@ -636,6 +636,8 @@ export class WorkflowActionService {
         .getAllCommentBoxes()
         .forEach(commentBox => this.deleteCommentBox(commentBox.commentBoxID));
 
+      this.jointGraphWrapper.jointGraph.clear();
+
       if (workflow === undefined) {
         this.setNewSharedModel();
         return;
diff --git a/frontend/src/app/workspace/types/workflow-websocket.interface.ts 
b/frontend/src/app/workspace/types/workflow-websocket.interface.ts
index f611931846..3ab8e34385 100644
--- a/frontend/src/app/workspace/types/workflow-websocket.interface.ts
+++ b/frontend/src/app/workspace/types/workflow-websocket.interface.ts
@@ -173,6 +173,10 @@ export type ClusterStatusUpdateEvent = Readonly<{
   numWorkers: number;
 }>;
 
+export type RegionUpdateEvent = Readonly<{
+  regions: readonly string[][];
+}>;
+
 export type ModifyLogicResponse = Readonly<{
   opId: string;
   isValid: boolean;
@@ -229,6 +233,7 @@ export type TexeraWebsocketEventTypeMap = {
   ModifyLogicCompletedEvent: ModifyLogicCompletedEvent;
   ExecutionDurationUpdateEvent: ExecutionDurationUpdateEvent;
   ClusterStatusUpdateEvent: ClusterStatusUpdateEvent;
+  RegionUpdateEvent: RegionUpdateEvent;
 };
 
 // helper type definitions to generate the request and event types
diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json
index 6753cba7fe..8e06ca2207 100644
--- a/frontend/tsconfig.json
+++ b/frontend/tsconfig.json
@@ -1,6 +1,7 @@
 {
   "compileOnSave": false,
   "compilerOptions": {
+    "allowSyntheticDefaultImports": true,
     "paths": {
       "path": ["./node_modules/path-browserify"]
     },
diff --git a/frontend/yarn.lock b/frontend/yarn.lock
index ff9e9634f7..394dcd7880 100644
--- a/frontend/yarn.lock
+++ b/frontend/yarn.lock
@@ -5076,6 +5076,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@types/concaveman@npm:1.1.6":
+  version: 1.1.6
+  resolution: "@types/concaveman@npm:1.1.6"
+  checksum: 
10c0/5cc36f8d85eeb15e976d4592c0cffca42607d1de14180fc15d5518fd309a714f05fcf9ecf03f43432fd014905aa78801a4004773ce00293424263738467e65da
+  languageName: node
+  linkType: hard
+
 "@types/connect-history-api-fallback@npm:^1.3.5, 
@types/connect-history-api-fallback@npm:^1.5.4":
   version: 1.5.4
   resolution: "@types/connect-history-api-fallback@npm:1.5.4"
@@ -5118,6 +5125,22 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@types/d3-path@npm:^2":
+  version: 2.0.4
+  resolution: "@types/d3-path@npm:2.0.4"
+  checksum: 
10c0/82214a9644cfffe0c1f9a7aab00e3912aaba89115c60d94ecf716d282eac71671761962a9e911a8ebc457777e3db42f80c355b61010e5e27218f6aed32128d39
+  languageName: node
+  linkType: hard
+
+"@types/d3-shape@npm:2.1.2":
+  version: 2.1.2
+  resolution: "@types/d3-shape@npm:2.1.2"
+  dependencies:
+    "@types/d3-path": "npm:^2"
+  checksum: 
10c0/f32e49cc41089ba9658716e14626831b20f564ac95be9a363fbd119913e223aa771dd703a2a602a2db8f25ba2eada1a73c12c2cff057526e0c3f9519756e5a4c
+  languageName: node
+  linkType: hard
+
 "@types/dagre@npm:0.7.47":
   version: 0.7.47
   resolution: "@types/dagre@npm:0.7.47"
@@ -7686,6 +7709,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"commander@npm:2, commander@npm:^2.20.0":
+  version: 2.20.3
+  resolution: "commander@npm:2.20.3"
+  checksum: 
10c0/74c781a5248c2402a0a3e966a0a2bba3c054aad144f5c023364be83265e796b20565aa9feff624132ff629aa64e16999fa40a743c10c12f7c61e96a794b99288
+  languageName: node
+  linkType: hard
+
 "commander@npm:7, commander@npm:^7.2.0":
   version: 7.2.0
   resolution: "commander@npm:7.2.0"
@@ -7693,13 +7723,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"commander@npm:^2.20.0":
-  version: 2.20.3
-  resolution: "commander@npm:2.20.3"
-  checksum: 
10c0/74c781a5248c2402a0a3e966a0a2bba3c054aad144f5c023364be83265e796b20565aa9feff624132ff629aa64e16999fa40a743c10c12f7c61e96a794b99288
-  languageName: node
-  linkType: hard
-
 "commander@npm:^8.3.0":
   version: 8.3.0
   resolution: "commander@npm:8.3.0"
@@ -7766,6 +7789,18 @@ __metadata:
   languageName: node
   linkType: hard
 
+"concaveman@npm:2.0.0":
+  version: 2.0.0
+  resolution: "concaveman@npm:2.0.0"
+  dependencies:
+    point-in-polygon: "npm:^1.1.0"
+    rbush: "npm:^4.0.1"
+    robust-predicates: "npm:^3.0.2"
+    tinyqueue: "npm:^3.0.0"
+  checksum: 
10c0/d277ee4dd5e5af21f0a22d056e1edad66db8f5515a9feb92d95f40407d819c17a0b4cd7f5a07a028d72cac05e85305dee0118036bc295424740f01af08ecda98
+  languageName: node
+  linkType: hard
+
 "concurrently@npm:7.4.0":
   version: 7.4.0
   resolution: "concurrently@npm:7.4.0"
@@ -8333,6 +8368,22 @@ __metadata:
   languageName: node
   linkType: hard
 
+"d3-array@npm:2, d3-array@npm:^2.3.0, d3-array@npm:^2.5.0":
+  version: 2.12.1
+  resolution: "d3-array@npm:2.12.1"
+  dependencies:
+    internmap: "npm:^1.0.0"
+  checksum: 
10c0/7eca10427a9f113a4ca6a0f7301127cab26043fd5e362631ef5a0edd1c4b2dd70c56ed317566700c31e4a6d88b55f3951aaba192291817f243b730cb2352882e
+  languageName: node
+  linkType: hard
+
+"d3-axis@npm:2":
+  version: 2.1.0
+  resolution: "d3-axis@npm:2.1.0"
+  checksum: 
10c0/812558c0a016f8541e4704837b4428060695e2397e00a374caab5ae060a8ea6254bb097a4cfb7e01deff61da8a91c582eda614659ada5fd590da902a397428cc
+  languageName: node
+  linkType: hard
+
 "d3-axis@npm:3":
   version: 3.0.0
   resolution: "d3-axis@npm:3.0.0"
@@ -8340,6 +8391,19 @@ __metadata:
   languageName: node
   linkType: hard
 
+"d3-brush@npm:2":
+  version: 2.1.0
+  resolution: "d3-brush@npm:2.1.0"
+  dependencies:
+    d3-dispatch: "npm:1 - 2"
+    d3-drag: "npm:2"
+    d3-interpolate: "npm:1 - 2"
+    d3-selection: "npm:2"
+    d3-transition: "npm:2"
+  checksum: 
10c0/f4221f815f8b0fb5af42a2c5baf7cb884067fdddfe5e3d9ae8b603912a47c205e138b8cdcb19a693feac46aa790c0dc9204c893e4b09cfdb944d31bde0b81126
+  languageName: node
+  linkType: hard
+
 "d3-brush@npm:3":
   version: 3.0.0
   resolution: "d3-brush@npm:3.0.0"
@@ -8353,6 +8417,15 @@ __metadata:
   languageName: node
   linkType: hard
 
+"d3-chord@npm:2":
+  version: 2.0.0
+  resolution: "d3-chord@npm:2.0.0"
+  dependencies:
+    d3-path: "npm:1 - 2"
+  checksum: 
10c0/675c4941cd9ea8dcf462622409a42b5de4120198b5016bf9a13e67074487b30a29ab5b7adbae3cab6ee56820255c320a56657fdf55538c4c7439cb9a4248dbb4
+  languageName: node
+  linkType: hard
+
 "d3-chord@npm:3":
   version: 3.0.1
   resolution: "d3-chord@npm:3.0.1"
@@ -8362,6 +8435,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"d3-color@npm:1 - 2, d3-color@npm:2":
+  version: 2.0.0
+  resolution: "d3-color@npm:2.0.0"
+  checksum: 
10c0/5aa58dfb78e3db764373a904eabb643dc024ff6071128a41e86faafa100e0e17a796e06ac3f2662e9937242bb75b8286788629773d76936f11c17bd5fe5e15cd
+  languageName: node
+  linkType: hard
+
 "d3-color@npm:1 - 3, d3-color@npm:3":
   version: 3.1.0
   resolution: "d3-color@npm:3.1.0"
@@ -8369,6 +8449,15 @@ __metadata:
   languageName: node
   linkType: hard
 
+"d3-contour@npm:2":
+  version: 2.0.0
+  resolution: "d3-contour@npm:2.0.0"
+  dependencies:
+    d3-array: "npm:2"
+  checksum: 
10c0/00b58abff5648438928571efc75a56e7459edcbb63ad807bcb38de13b337ac4a83286dabe33f53562ee5ebd2d83da31835cf46a1775fe35e03101772769d10ac
+  languageName: node
+  linkType: hard
+
 "d3-contour@npm:4":
   version: 4.0.2
   resolution: "d3-contour@npm:4.0.2"
@@ -8378,6 +8467,15 @@ __metadata:
   languageName: node
   linkType: hard
 
+"d3-delaunay@npm:5":
+  version: 5.3.0
+  resolution: "d3-delaunay@npm:5.3.0"
+  dependencies:
+    delaunator: "npm:4"
+  checksum: 
10c0/214aaddd01c58cadcfeea917ff7b7c3202083ac66fe5948d14558385d1ce495b33498ce10a3188ff144377d3da2f2ad72c2c3885407c325a24266c8f4c09347e
+  languageName: node
+  linkType: hard
+
 "d3-delaunay@npm:6":
   version: 6.0.4
   resolution: "d3-delaunay@npm:6.0.4"
@@ -8387,6 +8485,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"d3-dispatch@npm:1 - 2, d3-dispatch@npm:2":
+  version: 2.0.0
+  resolution: "d3-dispatch@npm:2.0.0"
+  checksum: 
10c0/379f7ce1510f529da00a34016630e92e41c0f6bbffef7b849f4e46733c188c67418df266a9a541cda17572b5286e32fbaf66308fe04dcfe52aa551830825bc93
+  languageName: node
+  linkType: hard
+
 "d3-dispatch@npm:1 - 3, d3-dispatch@npm:3":
   version: 3.0.1
   resolution: "d3-dispatch@npm:3.0.1"
@@ -8394,6 +8499,16 @@ __metadata:
   languageName: node
   linkType: hard
 
+"d3-drag@npm:2":
+  version: 2.0.0
+  resolution: "d3-drag@npm:2.0.0"
+  dependencies:
+    d3-dispatch: "npm:1 - 2"
+    d3-selection: "npm:2"
+  checksum: 
10c0/a6f2cfea47aa888b56476454554b37befb0d332f326704913142c6a89b295edfc0947a9fb5afdd0c6d0028878b832a975c80df55d009ab7ccf7b59faa99e926c
+  languageName: node
+  linkType: hard
+
 "d3-drag@npm:2 - 3, d3-drag@npm:3":
   version: 3.0.0
   resolution: "d3-drag@npm:3.0.0"
@@ -8404,6 +8519,27 @@ __metadata:
   languageName: node
   linkType: hard
 
+"d3-dsv@npm:1 - 2, d3-dsv@npm:2":
+  version: 2.0.0
+  resolution: "d3-dsv@npm:2.0.0"
+  dependencies:
+    commander: "npm:2"
+    iconv-lite: "npm:0.4"
+    rw: "npm:1"
+  bin:
+    csv2json: bin/dsv2json
+    csv2tsv: bin/dsv2dsv
+    dsv2dsv: bin/dsv2dsv
+    dsv2json: bin/dsv2json
+    json2csv: bin/json2dsv
+    json2dsv: bin/json2dsv
+    json2tsv: bin/json2dsv
+    tsv2csv: bin/dsv2dsv
+    tsv2json: bin/dsv2json
+  checksum: 
10c0/b5e4a0945664a941ad37d3c5ee8c8cbb3c99712ff7f36b2420446ebfc3b3909eb3d9ef2682b4a77afa6a6c5f5af1d659e17d6678863d95b244aed479b6c7c5c3
+  languageName: node
+  linkType: hard
+
 "d3-dsv@npm:1 - 3, d3-dsv@npm:3":
   version: 3.0.1
   resolution: "d3-dsv@npm:3.0.1"
@@ -8425,6 +8561,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"d3-ease@npm:1 - 2, d3-ease@npm:2":
+  version: 2.0.0
+  resolution: "d3-ease@npm:2.0.0"
+  checksum: 
10c0/4c2e74417739b73f5d185675be0a72b19df1f729b87c457d4b13976f7eef5c1f54739b4ccd71d9730521c959cfac28a56f5f4040dd2baf5729ac7e4adce344f1
+  languageName: node
+  linkType: hard
+
 "d3-ease@npm:1 - 3, d3-ease@npm:3":
   version: 3.0.1
   resolution: "d3-ease@npm:3.0.1"
@@ -8432,6 +8575,15 @@ __metadata:
   languageName: node
   linkType: hard
 
+"d3-fetch@npm:2":
+  version: 2.0.0
+  resolution: "d3-fetch@npm:2.0.0"
+  dependencies:
+    d3-dsv: "npm:1 - 2"
+  checksum: 
10c0/c508e1fb9d0aa04af04d8021a658ce2726239c265ffe0762d9fda3f02a1d1958d87984b486a41141660f61258f5977deff84d87767422876aed12dca3407bf73
+  languageName: node
+  linkType: hard
+
 "d3-fetch@npm:3":
   version: 3.0.1
   resolution: "d3-fetch@npm:3.0.1"
@@ -8441,6 +8593,17 @@ __metadata:
   languageName: node
   linkType: hard
 
+"d3-force@npm:2":
+  version: 2.1.1
+  resolution: "d3-force@npm:2.1.1"
+  dependencies:
+    d3-dispatch: "npm:1 - 2"
+    d3-quadtree: "npm:1 - 2"
+    d3-timer: "npm:1 - 2"
+  checksum: 
10c0/0044ad969c524fa32d39d414fb698d183a10b7a9ec9369ac04aa00cc026bc1262308971d70bf20873adfb3d73f557aea9203797d40bd7d7247ed9714be946fb4
+  languageName: node
+  linkType: hard
+
 "d3-force@npm:3":
   version: 3.0.0
   resolution: "d3-force@npm:3.0.0"
@@ -8452,6 +8615,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"d3-format@npm:1 - 2, d3-format@npm:2":
+  version: 2.0.0
+  resolution: "d3-format@npm:2.0.0"
+  checksum: 
10c0/c869af459e20767dc3d9cbb2946ba79cc266ae4fb35d11c50c63fc89ea4ed168c702c7e3db94d503b3618de9609bf3bf2d855ef53e21109ddd7eb9c8f3fcf8a1
+  languageName: node
+  linkType: hard
+
 "d3-format@npm:1 - 3, d3-format@npm:3":
   version: 3.1.0
   resolution: "d3-format@npm:3.1.0"
@@ -8459,6 +8629,15 @@ __metadata:
   languageName: node
   linkType: hard
 
+"d3-geo@npm:2":
+  version: 2.0.2
+  resolution: "d3-geo@npm:2.0.2"
+  dependencies:
+    d3-array: "npm:^2.5.0"
+  checksum: 
10c0/6836feb33036f03ec1dc728d64171f3eb40ee2c1c0f2e28232055aa317e5e2d481075294babb9553596e2080496eda119b8a43c51f71c893e6258ccf002bd7f8
+  languageName: node
+  linkType: hard
+
 "d3-geo@npm:3":
   version: 3.1.1
   resolution: "d3-geo@npm:3.1.1"
@@ -8468,6 +8647,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"d3-hierarchy@npm:2":
+  version: 2.0.0
+  resolution: "d3-hierarchy@npm:2.0.0"
+  checksum: 
10c0/3216f9b8537ae2bf331006630f2075a81df4943edff077a60e19ca6f9a619c8494bf45bf7d89b409160b49edd1a49c0050002cdc8a9ae6e3672d20018a821fac
+  languageName: node
+  linkType: hard
+
 "d3-hierarchy@npm:3":
   version: 3.1.2
   resolution: "d3-hierarchy@npm:3.1.2"
@@ -8475,6 +8661,15 @@ __metadata:
   languageName: node
   linkType: hard
 
+"d3-interpolate@npm:1 - 2, d3-interpolate@npm:1.2.0 - 2, d3-interpolate@npm:2":
+  version: 2.0.1
+  resolution: "d3-interpolate@npm:2.0.1"
+  dependencies:
+    d3-color: "npm:1 - 2"
+  checksum: 
10c0/2a5725b0c9c7fef3e8878cf75ad67be851b1472de3dda1f694c441786a1a32e198ddfaa6880d6b280401c1af5b844b61ccdd63d85d1607c1e6bb3a3f0bf532ea
+  languageName: node
+  linkType: hard
+
 "d3-interpolate@npm:1 - 3, d3-interpolate@npm:1.2.0 - 3, d3-interpolate@npm:3":
   version: 3.0.1
   resolution: "d3-interpolate@npm:3.0.1"
@@ -8484,6 +8679,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"d3-path@npm:1 - 2, d3-path@npm:2":
+  version: 2.0.0
+  resolution: "d3-path@npm:2.0.0"
+  checksum: 
10c0/ef206f83c1123d4ad364c23b6fe877a7cd8afa76c30e13bd0588cd9b7c4ed4b577ebfd9499cdcac63268d7ae29c0a53ec38d6623a7c98585f3c118323e8f473f
+  languageName: node
+  linkType: hard
+
 "d3-path@npm:1 - 3, d3-path@npm:3, d3-path@npm:^3.1.0":
   version: 3.1.0
   resolution: "d3-path@npm:3.1.0"
@@ -8491,6 +8693,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"d3-polygon@npm:2":
+  version: 2.0.0
+  resolution: "d3-polygon@npm:2.0.0"
+  checksum: 
10c0/cb2f24cbdd0743ecaf7d0d7e060a00fd4ed8b1fbeb43b6db16878f7a8145ed5bedd60055d5f96b4ffc9aff3fd731926534af66007855e9eddb106c99a153ff5f
+  languageName: node
+  linkType: hard
+
 "d3-polygon@npm:3":
   version: 3.0.1
   resolution: "d3-polygon@npm:3.0.1"
@@ -8498,6 +8707,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"d3-quadtree@npm:1 - 2, d3-quadtree@npm:2":
+  version: 2.0.0
+  resolution: "d3-quadtree@npm:2.0.0"
+  checksum: 
10c0/b8dcbda82a04915018ea5309bcdc045971afbea293d87d32a34c31c69351c153a9e1a4d0ea77163a8ebe8f4fd9a6b114a7360e436f34552f284c1457275eda97
+  languageName: node
+  linkType: hard
+
 "d3-quadtree@npm:1 - 3, d3-quadtree@npm:3":
   version: 3.0.1
   resolution: "d3-quadtree@npm:3.0.1"
@@ -8505,6 +8721,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"d3-random@npm:2":
+  version: 2.2.2
+  resolution: "d3-random@npm:2.2.2"
+  checksum: 
10c0/2c7413c4c626272cf12945ff14dacffdccc531989b551f8cfdd9c0266ae902cd9ffffc9ff98b693594a5ff342fb0f22e70afcce908cc6c43fb082bd52ace5acf
+  languageName: node
+  linkType: hard
+
 "d3-random@npm:3":
   version: 3.0.1
   resolution: "d3-random@npm:3.0.1"
@@ -8512,6 +8735,16 @@ __metadata:
   languageName: node
   linkType: hard
 
+"d3-scale-chromatic@npm:2":
+  version: 2.0.0
+  resolution: "d3-scale-chromatic@npm:2.0.0"
+  dependencies:
+    d3-color: "npm:1 - 2"
+    d3-interpolate: "npm:1 - 2"
+  checksum: 
10c0/93cafe497b00046b1d4e237a8bb8981fbb35ba03070f420bd913872f6e9d2c9628ed8bb8c84c6a6ffe16029359fa74b646c5c5129732ef4186ab059a77da3021
+  languageName: node
+  linkType: hard
+
 "d3-scale-chromatic@npm:3":
   version: 3.1.0
   resolution: "d3-scale-chromatic@npm:3.1.0"
@@ -8522,6 +8755,19 @@ __metadata:
   languageName: node
   linkType: hard
 
+"d3-scale@npm:3":
+  version: 3.3.0
+  resolution: "d3-scale@npm:3.3.0"
+  dependencies:
+    d3-array: "npm:^2.3.0"
+    d3-format: "npm:1 - 2"
+    d3-interpolate: "npm:1.2.0 - 2"
+    d3-time: "npm:^2.1.1"
+    d3-time-format: "npm:2 - 3"
+  checksum: 
10c0/cb63c271ec9c5b632c245c63e0d0716b32adcc468247972c552f5be62fb34a17f71e4ac29fd8976704369f4b958bc6789c61a49427efe2160ae979d7843569dc
+  languageName: node
+  linkType: hard
+
 "d3-scale@npm:4":
   version: 4.0.2
   resolution: "d3-scale@npm:4.0.2"
@@ -8535,6 +8781,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"d3-selection@npm:2":
+  version: 2.0.0
+  resolution: "d3-selection@npm:2.0.0"
+  checksum: 
10c0/cd38f5e0baf2011f421e909ff5748235b18510175b7433ddddb04df325a4a03d7db07da09993afb464d5f050174c13cb5d843da902e71e3e8eb5f06c28fc8689
+  languageName: node
+  linkType: hard
+
 "d3-selection@npm:2 - 3, d3-selection@npm:3":
   version: 3.0.0
   resolution: "d3-selection@npm:3.0.0"
@@ -8542,6 +8795,15 @@ __metadata:
   languageName: node
   linkType: hard
 
+"d3-shape@npm:2":
+  version: 2.1.0
+  resolution: "d3-shape@npm:2.1.0"
+  dependencies:
+    d3-path: "npm:1 - 2"
+  checksum: 
10c0/d86c84322b0ccd550df93ec4986359548cb2c25c9fae326984a59d1caeeb40c78f62678bb93951eed65536bc2d8efa446b13386acb79875234dc79dbcf16dbd7
+  languageName: node
+  linkType: hard
+
 "d3-shape@npm:3":
   version: 3.2.0
   resolution: "d3-shape@npm:3.2.0"
@@ -8551,6 +8813,15 @@ __metadata:
   languageName: node
   linkType: hard
 
+"d3-time-format@npm:2 - 3, d3-time-format@npm:3":
+  version: 3.0.0
+  resolution: "d3-time-format@npm:3.0.0"
+  dependencies:
+    d3-time: "npm:1 - 2"
+  checksum: 
10c0/0abe3379f07d1c12ce8930cdddad1223c99cd3e4eac05cf409b5a7953e9ebed56a95a64b0977f63958cfb6101fa4a2a85533a5eae40df84f22c0117dbf5e8982
+  languageName: node
+  linkType: hard
+
 "d3-time-format@npm:2 - 4, d3-time-format@npm:4":
   version: 4.1.0
   resolution: "d3-time-format@npm:4.1.0"
@@ -8560,6 +8831,15 @@ __metadata:
   languageName: node
   linkType: hard
 
+"d3-time@npm:1 - 2, d3-time@npm:2, d3-time@npm:^2.1.1":
+  version: 2.1.1
+  resolution: "d3-time@npm:2.1.1"
+  dependencies:
+    d3-array: "npm:2"
+  checksum: 
10c0/4a01770a857bc37d2bafb8f00250e0e6a1fcc8051aea93e5eed168d8ee93e92da508a75ab5e42fc5472aa37e2a83aac68afaf3f12d9167c184ce781faadf5682
+  languageName: node
+  linkType: hard
+
 "d3-time@npm:1 - 3, d3-time@npm:2.1.1 - 3, d3-time@npm:3":
   version: 3.1.0
   resolution: "d3-time@npm:3.1.0"
@@ -8569,6 +8849,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"d3-timer@npm:1 - 2, d3-timer@npm:2":
+  version: 2.0.0
+  resolution: "d3-timer@npm:2.0.0"
+  checksum: 
10c0/95f92ed8edbd0844c023de543ebca4d6aba7f9f8b2ecdbc3d61e01e4df5e74ffbce81238a3c4fd63d118bb1d05ca6331522df565fab146a2790e5c6a847f6275
+  languageName: node
+  linkType: hard
+
 "d3-timer@npm:1 - 3, d3-timer@npm:3":
   version: 3.0.1
   resolution: "d3-timer@npm:3.0.1"
@@ -8576,6 +8863,21 @@ __metadata:
   languageName: node
   linkType: hard
 
+"d3-transition@npm:2":
+  version: 2.0.0
+  resolution: "d3-transition@npm:2.0.0"
+  dependencies:
+    d3-color: "npm:1 - 2"
+    d3-dispatch: "npm:1 - 2"
+    d3-ease: "npm:1 - 2"
+    d3-interpolate: "npm:1 - 2"
+    d3-timer: "npm:1 - 2"
+  peerDependencies:
+    d3-selection: 2
+  checksum: 
10c0/a775365c90acfcf5745fb18146ce0a5cb71bfdf69433f4d12cc286da0f88b3b1fbdd6782ccfe8e60de95133107cd8a47a4736fa19e94ffb08f1000e6cd9ebdb6
+  languageName: node
+  linkType: hard
+
 "d3-transition@npm:2 - 3, d3-transition@npm:3":
   version: 3.0.1
   resolution: "d3-transition@npm:3.0.1"
@@ -8591,6 +8893,19 @@ __metadata:
   languageName: node
   linkType: hard
 
+"d3-zoom@npm:2":
+  version: 2.0.0
+  resolution: "d3-zoom@npm:2.0.0"
+  dependencies:
+    d3-dispatch: "npm:1 - 2"
+    d3-drag: "npm:2"
+    d3-interpolate: "npm:1 - 2"
+    d3-selection: "npm:2"
+    d3-transition: "npm:2"
+  checksum: 
10c0/d21bc3f5f7b92809d4bf75889ef6c91e708becc6a148148bc80847b2efdf96233c4437d96b9e1623dde33922e63d505debec1616906448780e0017a04aa7c09f
+  languageName: node
+  linkType: hard
+
 "d3-zoom@npm:3":
   version: 3.0.0
   resolution: "d3-zoom@npm:3.0.0"
@@ -8604,6 +8919,44 @@ __metadata:
   languageName: node
   linkType: hard
 
+"d3@npm:6.4.0":
+  version: 6.4.0
+  resolution: "d3@npm:6.4.0"
+  dependencies:
+    d3-array: "npm:2"
+    d3-axis: "npm:2"
+    d3-brush: "npm:2"
+    d3-chord: "npm:2"
+    d3-color: "npm:2"
+    d3-contour: "npm:2"
+    d3-delaunay: "npm:5"
+    d3-dispatch: "npm:2"
+    d3-drag: "npm:2"
+    d3-dsv: "npm:2"
+    d3-ease: "npm:2"
+    d3-fetch: "npm:2"
+    d3-force: "npm:2"
+    d3-format: "npm:2"
+    d3-geo: "npm:2"
+    d3-hierarchy: "npm:2"
+    d3-interpolate: "npm:2"
+    d3-path: "npm:2"
+    d3-polygon: "npm:2"
+    d3-quadtree: "npm:2"
+    d3-random: "npm:2"
+    d3-scale: "npm:3"
+    d3-scale-chromatic: "npm:2"
+    d3-selection: "npm:2"
+    d3-shape: "npm:2"
+    d3-time: "npm:2"
+    d3-time-format: "npm:3"
+    d3-timer: "npm:2"
+    d3-transition: "npm:2"
+    d3-zoom: "npm:2"
+  checksum: 
10c0/1f5e523c6004ee8610638fd51c9e68543ddcb875184f359ef0be8b6dfba5ff4b0139228e9ec1d9c0f035ef90055001897d69c451bfbe60142d4e99429769d951
+  languageName: node
+  linkType: hard
+
 "d3@npm:^7.4.0, d3@npm:^7.8.2":
   version: 7.9.0
   resolution: "d3@npm:7.9.0"
@@ -8909,6 +9262,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"delaunator@npm:4":
+  version: 4.0.1
+  resolution: "delaunator@npm:4.0.1"
+  checksum: 
10c0/8d5be959a4bf79e5297ca58a3dc223434302200ac0efc2cee5434755b557957a824ee32328ed97f69df93d3819e063f3b4637dd6db4d14d50aa8591aeb6f98a7
+  languageName: node
+  linkType: hard
+
 "delaunator@npm:5":
   version: 5.0.1
   resolution: "delaunator@npm:5.0.1"
@@ -11287,7 +11647,9 @@ __metadata:
     "@nx/angular": "npm:20.0.3"
     "@stoplight/json-ref-resolver": "npm:3.1.5"
     "@types/backbone": "npm:1.4.15"
+    "@types/concaveman": "npm:1.1.6"
     "@types/content-disposition": "npm:0"
+    "@types/d3-shape": "npm:2.1.2"
     "@types/dagre": "npm:0.7.47"
     "@types/file-saver": "npm:2.0.5"
     "@types/graphlib": "npm:2.1.8"
@@ -11306,8 +11668,10 @@ __metadata:
     ajv: "npm:8.10.0"
     babel-plugin-dynamic-import-node: "npm:2.3.3"
     backbone: "npm:1.4.1"
+    concaveman: "npm:2.0.0"
     concurrently: "npm:7.4.0"
     content-disposition: "npm:0.5.4"
+    d3: "npm:6.4.0"
     dagre: "npm:0.8.5"
     deep-map: "npm:2.0.0"
     edit-distance: "npm:1.0.4"
@@ -11805,7 +12169,7 @@ __metadata:
   languageName: node
   linkType: hard
 
-"iconv-lite@npm:0.4.24, iconv-lite@npm:^0.4.24":
+"iconv-lite@npm:0.4, iconv-lite@npm:0.4.24, iconv-lite@npm:^0.4.24":
   version: 0.4.24
   resolution: "iconv-lite@npm:0.4.24"
   dependencies:
@@ -12009,6 +12373,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"internmap@npm:^1.0.0":
+  version: 1.0.1
+  resolution: "internmap@npm:1.0.1"
+  checksum: 
10c0/60942be815ca19da643b6d4f23bd0bf4e8c97abbd080fb963fe67583b60bdfb3530448ad4486bae40810e92317bded9995cc31411218acc750d72cd4e8646eee
+  languageName: node
+  linkType: hard
+
 "ip-address@npm:^9.0.5":
   version: 9.0.5
   resolution: "ip-address@npm:9.0.5"
@@ -15417,6 +15788,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"point-in-polygon@npm:^1.1.0":
+  version: 1.1.0
+  resolution: "point-in-polygon@npm:1.1.0"
+  checksum: 
10c0/de00419585ee25555d97585b7a23eeb2464a87ef29404264bee55654ca2ecab5a5a99d33e689c07d045faf80091e838f44a1fd130bdd6134493df53114947343
+  languageName: node
+  linkType: hard
+
 "popper.js@npm:1.16.1":
   version: 1.16.1
   resolution: "popper.js@npm:1.16.1"
@@ -16092,6 +16470,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"quickselect@npm:^3.0.0":
+  version: 3.0.0
+  resolution: "quickselect@npm:3.0.0"
+  checksum: 
10c0/3a0d33b0ec06841d953accdfd735aa3d8b7922cddd12970544a2c4b0278871280d8f5ba496803600693c1e7b7b2fb57c31d2b14d99132f478888006a1be6e6b7
+  languageName: node
+  linkType: hard
+
 "quill-cursors@npm:3.1.2":
   version: 3.1.2
   resolution: "quill-cursors@npm:3.1.2"
@@ -16170,6 +16555,15 @@ __metadata:
   languageName: node
   linkType: hard
 
+"rbush@npm:^4.0.1":
+  version: 4.0.1
+  resolution: "rbush@npm:4.0.1"
+  dependencies:
+    quickselect: "npm:^3.0.0"
+  checksum: 
10c0/1d3c2e2c8b8111a6bcac0b36348ef55c977bc533a7a7bef44c423e24de531e43749bcf5b939008de69d97d3c6e7cf0e9040cecb4492358e6d562ea85165a1620
+  languageName: node
+  linkType: hard
+
 "react-is@npm:^18.0.0":
   version: 18.3.1
   resolution: "react-is@npm:18.3.1"
@@ -17844,6 +18238,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"tinyqueue@npm:^3.0.0":
+  version: 3.0.0
+  resolution: "tinyqueue@npm:3.0.0"
+  checksum: 
10c0/edd6f1a6146aa3aa7bc85b44b3aacf44cddfa805b0901019272d7e9235894b4f28b2f9d09c1bce500ae48883b03708b6b871aa33920e895d2943720f7a9ad3ba
+  languageName: node
+  linkType: hard
+
 "tmp@npm:^0.0.33":
   version: 0.0.33
   resolution: "tmp@npm:0.0.33"


Reply via email to