From 3428df6dcd740cc9810d9b17164dcb15697c3c59 Mon Sep 17 00:00:00 2001
From: Michael Behrisch <m.behrisch@uu.nl>
Date: Fri, 11 Mar 2022 10:33:27 +0100
Subject: [PATCH] chore: :bug: deletes old graph-layouts testing library

Was only used for trying nx's publishable library functionalities.
---
 .../graph-layout/src/lib/cytoscape-layouts.ts |   66 +-
 .../src/lib/layout-creator-usecase.spec.ts    |   38 +-
 libs/shared/graph-layouts/.eslintrc.json      |   18 -
 libs/shared/graph-layouts/README.md           |   11 -
 libs/shared/graph-layouts/dist/README.md      |   11 -
 libs/shared/graph-layouts/jest.config.js      |   14 -
 .../node_modules/.yarn-integrity              |   18 -
 .../node_modules/events/.airtap.yml           |   15 -
 .../node_modules/events/.github/FUNDING.yml   |   12 -
 .../node_modules/events/.travis.yml           |   18 -
 .../node_modules/events/History.md            |  118 -
 .../graph-layouts/node_modules/events/LICENSE |   22 -
 .../node_modules/events/Readme.md             |   50 -
 .../node_modules/events/events.js             |  497 --
 .../node_modules/events/package.json          |   37 -
 .../node_modules/events/security.md           |   10 -
 .../events/tests/add-listeners.js             |  111 -
 .../events/tests/check-listener-leaks.js      |  101 -
 .../node_modules/events/tests/common.js       |  104 -
 .../node_modules/events/tests/errors.js       |   13 -
 .../node_modules/events/tests/events-list.js  |   28 -
 .../node_modules/events/tests/events-once.js  |  234 -
 .../node_modules/events/tests/index.js        |   64 -
 .../events/tests/legacy-compat.js             |   16 -
 .../events/tests/listener-count.js            |   37 -
 .../events/tests/listeners-side-effects.js    |   56 -
 .../node_modules/events/tests/listeners.js    |  168 -
 .../events/tests/max-listeners.js             |   47 -
 .../node_modules/events/tests/method-names.js |   35 -
 .../events/tests/modify-in-emit.js            |   90 -
 .../node_modules/events/tests/num-args.js     |   60 -
 .../node_modules/events/tests/once.js         |   83 -
 .../node_modules/events/tests/prepend.js      |   31 -
 .../events/tests/remove-all-listeners.js      |  133 -
 .../events/tests/remove-listeners.js          |  212 -
 .../tests/set-max-listeners-side-effects.js   |   31 -
 .../events/tests/special-event-names.js       |   45 -
 .../node_modules/events/tests/subclass.js     |   66 -
 .../node_modules/events/tests/symbols.js      |   25 -
 .../node_modules/graphology/LICENSE.txt       |   21 -
 .../node_modules/graphology/README.md         |    9 -
 .../graphology/dist/graphology.cjs.js         | 5463 --------------
 .../graphology/dist/graphology.d.ts           |   36 -
 .../graphology/dist/graphology.esm.js         | 6671 -----------------
 .../graphology/dist/graphology.umd.js         | 6125 ---------------
 .../graphology/dist/graphology.umd.min.js     |    2 -
 .../node_modules/graphology/package.json      |   84 -
 .../graphology/specs/attributes.js            |  992 ---
 .../node_modules/graphology/specs/events.js   |  426 --
 .../node_modules/graphology/specs/helpers.js  |  101 -
 .../node_modules/graphology/specs/index.js    |   78 -
 .../graphology/specs/instantiation.js         |  211 -
 .../graphology/specs/iteration/edges.js       |  894 ---
 .../graphology/specs/iteration/index.js       |  161 -
 .../graphology/specs/iteration/neighbors.js   |  284 -
 .../graphology/specs/iteration/nodes.js       |  248 -
 .../node_modules/graphology/specs/known.js    |   50 -
 .../node_modules/graphology/specs/misc.js     |  112 -
 .../node_modules/graphology/specs/mutation.js |  883 ---
 .../graphology/specs/properties.js            |  214 -
 .../node_modules/graphology/specs/read.js     |  909 ---
 .../graphology/specs/serialization.js         |  171 -
 .../node_modules/graphology/specs/utils.js    |  249 -
 .../node_modules/obliterator/LICENSE.txt      |   21 -
 .../node_modules/obliterator/README.md        |  415 -
 .../node_modules/obliterator/chain.d.ts       |    5 -
 .../node_modules/obliterator/chain.js         |   46 -
 .../obliterator/combinations.d.ts             |    4 -
 .../node_modules/obliterator/combinations.js  |   76 -
 .../node_modules/obliterator/consume.d.ts     |    1 -
 .../node_modules/obliterator/consume.js       |   29 -
 .../node_modules/obliterator/every.d.ts       |    8 -
 .../node_modules/obliterator/every.js         |   27 -
 .../node_modules/obliterator/filter.d.ts      |    8 -
 .../node_modules/obliterator/filter.js        |   28 -
 .../node_modules/obliterator/find.d.ts        |    8 -
 .../node_modules/obliterator/find.js          |   27 -
 .../obliterator/foreach-with-null-keys.d.ts   |   29 -
 .../obliterator/foreach-with-null-keys.js     |   83 -
 .../node_modules/obliterator/foreach.d.ts     |   24 -
 .../node_modules/obliterator/foreach.js       |   73 -
 .../node_modules/obliterator/includes.d.ts    |    6 -
 .../node_modules/obliterator/includes.js      |   27 -
 .../node_modules/obliterator/index.d.ts       |   20 -
 .../node_modules/obliterator/index.js         |   26 -
 .../node_modules/obliterator/iter.d.ts        |    1 -
 .../node_modules/obliterator/iter.js          |   46 -
 .../node_modules/obliterator/iterator.d.ts    |   18 -
 .../node_modules/obliterator/iterator.js      |   96 -
 .../node_modules/obliterator/map.d.ts         |    8 -
 .../node_modules/obliterator/map.js           |   29 -
 .../node_modules/obliterator/match.d.ts       |    4 -
 .../node_modules/obliterator/match.js         |   43 -
 .../node_modules/obliterator/package.json     |   46 -
 .../obliterator/permutations.d.ts             |    4 -
 .../node_modules/obliterator/permutations.js  |   94 -
 .../node_modules/obliterator/power-set.d.ts   |    3 -
 .../node_modules/obliterator/power-set.js     |   27 -
 .../node_modules/obliterator/range.d.ts       |   10 -
 .../node_modules/obliterator/range.js         |   44 -
 .../node_modules/obliterator/some.d.ts        |    8 -
 .../node_modules/obliterator/some.js          |   27 -
 .../node_modules/obliterator/split.d.ts       |    4 -
 .../node_modules/obliterator/split.js         |   68 -
 .../node_modules/obliterator/support.js       |    2 -
 .../node_modules/obliterator/take-into.d.ts   |    9 -
 .../node_modules/obliterator/take-into.js     |   39 -
 .../node_modules/obliterator/take.d.ts        |    6 -
 .../node_modules/obliterator/take.js          |   39 -
 .../node_modules/obliterator/types.d.ts       |    7 -
 libs/shared/graph-layouts/package.json        |    8 -
 libs/shared/graph-layouts/project.json        |   33 -
 libs/shared/graph-layouts/src/index.ts        |    1 -
 .../src/lib/cytoscape-layouts.ts              |   54 -
 .../src/lib/graphology-layouts.ts             |  170 -
 .../src/lib/layout-creator-usecase.spec.ts    |  140 -
 .../src/lib/layout-creator-usecase.ts         |   77 -
 libs/shared/graph-layouts/src/lib/layout.ts   |   21 -
 libs/shared/graph-layouts/tsconfig.json       |   23 -
 libs/shared/graph-layouts/tsconfig.lib.json   |   10 -
 libs/shared/graph-layouts/tsconfig.spec.json  |   10 -
 libs/shared/graph-layouts/yarn.lock           |   21 -
 122 files changed, 94 insertions(+), 29286 deletions(-)
 delete mode 100644 libs/shared/graph-layouts/.eslintrc.json
 delete mode 100644 libs/shared/graph-layouts/README.md
 delete mode 100644 libs/shared/graph-layouts/dist/README.md
 delete mode 100644 libs/shared/graph-layouts/jest.config.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/.yarn-integrity
 delete mode 100644 libs/shared/graph-layouts/node_modules/events/.airtap.yml
 delete mode 100644 libs/shared/graph-layouts/node_modules/events/.github/FUNDING.yml
 delete mode 100644 libs/shared/graph-layouts/node_modules/events/.travis.yml
 delete mode 100644 libs/shared/graph-layouts/node_modules/events/History.md
 delete mode 100644 libs/shared/graph-layouts/node_modules/events/LICENSE
 delete mode 100644 libs/shared/graph-layouts/node_modules/events/Readme.md
 delete mode 100644 libs/shared/graph-layouts/node_modules/events/events.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/events/package.json
 delete mode 100644 libs/shared/graph-layouts/node_modules/events/security.md
 delete mode 100644 libs/shared/graph-layouts/node_modules/events/tests/add-listeners.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/events/tests/check-listener-leaks.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/events/tests/common.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/events/tests/errors.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/events/tests/events-list.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/events/tests/events-once.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/events/tests/index.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/events/tests/legacy-compat.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/events/tests/listener-count.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/events/tests/listeners-side-effects.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/events/tests/listeners.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/events/tests/max-listeners.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/events/tests/method-names.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/events/tests/modify-in-emit.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/events/tests/num-args.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/events/tests/once.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/events/tests/prepend.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/events/tests/remove-all-listeners.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/events/tests/remove-listeners.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/events/tests/set-max-listeners-side-effects.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/events/tests/special-event-names.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/events/tests/subclass.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/events/tests/symbols.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/graphology/LICENSE.txt
 delete mode 100644 libs/shared/graph-layouts/node_modules/graphology/README.md
 delete mode 100644 libs/shared/graph-layouts/node_modules/graphology/dist/graphology.cjs.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/graphology/dist/graphology.d.ts
 delete mode 100644 libs/shared/graph-layouts/node_modules/graphology/dist/graphology.esm.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/graphology/dist/graphology.umd.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/graphology/dist/graphology.umd.min.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/graphology/package.json
 delete mode 100644 libs/shared/graph-layouts/node_modules/graphology/specs/attributes.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/graphology/specs/events.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/graphology/specs/helpers.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/graphology/specs/index.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/graphology/specs/instantiation.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/graphology/specs/iteration/edges.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/graphology/specs/iteration/index.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/graphology/specs/iteration/neighbors.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/graphology/specs/iteration/nodes.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/graphology/specs/known.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/graphology/specs/misc.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/graphology/specs/mutation.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/graphology/specs/properties.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/graphology/specs/read.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/graphology/specs/serialization.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/graphology/specs/utils.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/obliterator/LICENSE.txt
 delete mode 100644 libs/shared/graph-layouts/node_modules/obliterator/README.md
 delete mode 100644 libs/shared/graph-layouts/node_modules/obliterator/chain.d.ts
 delete mode 100644 libs/shared/graph-layouts/node_modules/obliterator/chain.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/obliterator/combinations.d.ts
 delete mode 100644 libs/shared/graph-layouts/node_modules/obliterator/combinations.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/obliterator/consume.d.ts
 delete mode 100644 libs/shared/graph-layouts/node_modules/obliterator/consume.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/obliterator/every.d.ts
 delete mode 100644 libs/shared/graph-layouts/node_modules/obliterator/every.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/obliterator/filter.d.ts
 delete mode 100644 libs/shared/graph-layouts/node_modules/obliterator/filter.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/obliterator/find.d.ts
 delete mode 100644 libs/shared/graph-layouts/node_modules/obliterator/find.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/obliterator/foreach-with-null-keys.d.ts
 delete mode 100644 libs/shared/graph-layouts/node_modules/obliterator/foreach-with-null-keys.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/obliterator/foreach.d.ts
 delete mode 100644 libs/shared/graph-layouts/node_modules/obliterator/foreach.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/obliterator/includes.d.ts
 delete mode 100644 libs/shared/graph-layouts/node_modules/obliterator/includes.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/obliterator/index.d.ts
 delete mode 100644 libs/shared/graph-layouts/node_modules/obliterator/index.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/obliterator/iter.d.ts
 delete mode 100644 libs/shared/graph-layouts/node_modules/obliterator/iter.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/obliterator/iterator.d.ts
 delete mode 100644 libs/shared/graph-layouts/node_modules/obliterator/iterator.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/obliterator/map.d.ts
 delete mode 100644 libs/shared/graph-layouts/node_modules/obliterator/map.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/obliterator/match.d.ts
 delete mode 100644 libs/shared/graph-layouts/node_modules/obliterator/match.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/obliterator/package.json
 delete mode 100644 libs/shared/graph-layouts/node_modules/obliterator/permutations.d.ts
 delete mode 100644 libs/shared/graph-layouts/node_modules/obliterator/permutations.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/obliterator/power-set.d.ts
 delete mode 100644 libs/shared/graph-layouts/node_modules/obliterator/power-set.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/obliterator/range.d.ts
 delete mode 100644 libs/shared/graph-layouts/node_modules/obliterator/range.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/obliterator/some.d.ts
 delete mode 100644 libs/shared/graph-layouts/node_modules/obliterator/some.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/obliterator/split.d.ts
 delete mode 100644 libs/shared/graph-layouts/node_modules/obliterator/split.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/obliterator/support.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/obliterator/take-into.d.ts
 delete mode 100644 libs/shared/graph-layouts/node_modules/obliterator/take-into.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/obliterator/take.d.ts
 delete mode 100644 libs/shared/graph-layouts/node_modules/obliterator/take.js
 delete mode 100644 libs/shared/graph-layouts/node_modules/obliterator/types.d.ts
 delete mode 100644 libs/shared/graph-layouts/package.json
 delete mode 100644 libs/shared/graph-layouts/project.json
 delete mode 100644 libs/shared/graph-layouts/src/index.ts
 delete mode 100644 libs/shared/graph-layouts/src/lib/cytoscape-layouts.ts
 delete mode 100644 libs/shared/graph-layouts/src/lib/graphology-layouts.ts
 delete mode 100644 libs/shared/graph-layouts/src/lib/layout-creator-usecase.spec.ts
 delete mode 100644 libs/shared/graph-layouts/src/lib/layout-creator-usecase.ts
 delete mode 100644 libs/shared/graph-layouts/src/lib/layout.ts
 delete mode 100644 libs/shared/graph-layouts/tsconfig.json
 delete mode 100644 libs/shared/graph-layouts/tsconfig.lib.json
 delete mode 100644 libs/shared/graph-layouts/tsconfig.spec.json
 delete mode 100644 libs/shared/graph-layouts/yarn.lock

diff --git a/libs/shared/graph-layout/src/lib/cytoscape-layouts.ts b/libs/shared/graph-layout/src/lib/cytoscape-layouts.ts
index 325377b8f..c188ae5a3 100644
--- a/libs/shared/graph-layout/src/lib/cytoscape-layouts.ts
+++ b/libs/shared/graph-layout/src/lib/cytoscape-layouts.ts
@@ -1,24 +1,66 @@
+import Graph from 'graphology';
+import { Attributes } from 'graphology-types';
 import { Layout } from './layout';
 import { ILayoutFactory, LayoutAlgorithm } from './layout-creator-usecase';
 
+import cytoscape from 'cytoscape';
+import klay from 'cytoscape-klay';
+
+cytoscape.use( klay );
+
 export type CytoscapeProvider = 'Cytoscape';
 
 export type CytoscapeLayoutAlgorithms =
-  | `${CytoscapeProvider}_coupe`
-  | `${CytoscapeProvider}_i4`;
+  | `${CytoscapeProvider}_klay`
+  | `${CytoscapeProvider}_dagre`
+  | `${CytoscapeProvider}_elk`
+  | `${CytoscapeProvider}_fcose`
+  | `${CytoscapeProvider}_cose-bilkent`
+  | `${CytoscapeProvider}_cise`;
+
 
+  
+type CytoNode = {
+  data: {
+    id: string;
+    type: string;
+    source?: string;
+    target?: string;
+    position?: {
+      x: number;
+      y: number;
+    };
+  };
+};
 /**
- * This is a ConcreteCreator
+ * This is the Cytoscape Factory
  */
 export class CytoscapeFactory
   implements ILayoutFactory<CytoscapeLayoutAlgorithms>
 {
   createLayout(LayoutAlgorithm: CytoscapeLayoutAlgorithms): Cytoscape | null {
     switch (LayoutAlgorithm) {
-      case 'Cytoscape_coupe':
-        return new CytoscapeCoupe();
-      case 'Cytoscape_i4':
-        return new CytoscapeI4();
+      case 'Cytoscape_klay':
+        //https://github.com/cytoscape/cytoscape.js-klay
+        return new CytoscapeKlay();
+      // case 'Cytoscape_dagre':
+      //   //https://github.com/cytoscape/cytoscape.js-dagre
+      //   return new CytoscapeCoupe();
+      // case 'Cytoscape_elk':
+      //   //https://github.com/cytoscape/cytoscape.js-elk
+      //   return new CytoscapeI4();
+
+      //   case 'Cytoscape_fcose':
+      //     //https://github.com/iVis-at-Bilkent/cytoscape.js-fcose
+      //   return new CytoscapeI4();
+
+      //   case 'Cytoscape_cose-bilkent':
+      //     //https://github.com/cytoscape/cytoscape.js-cose-bilkent
+      //   return new CytoscapeI4();
+
+      //   case 'Cytoscape_cise':
+      //     //https://github.com/iVis-at-Bilkent/cytoscape.js-cise
+      //   return new CytoscapeI4();
       default:
         return null;
     }
@@ -38,9 +80,15 @@ export abstract class Cytoscape extends Layout<CytoscapeProvider> {
 /**
  * This is a ConcreteProduct
  */
-class CytoscapeI4 extends Cytoscape {
+class CytoscapeKlay extends Cytoscape {
   constructor() {
-    super('Cytoscape_i4');
+    super('Cytoscape_klay');
+  }
+
+  public override layout(
+    graph: Graph<Attributes, Attributes, Attributes>
+  ): void {
+
   }
 }
 
diff --git a/libs/shared/graph-layout/src/lib/layout-creator-usecase.spec.ts b/libs/shared/graph-layout/src/lib/layout-creator-usecase.spec.ts
index 903a079dc..d6ff588a2 100644
--- a/libs/shared/graph-layout/src/lib/layout-creator-usecase.spec.ts
+++ b/libs/shared/graph-layout/src/lib/layout-creator-usecase.spec.ts
@@ -16,7 +16,7 @@ const TIMEOUT = 10;
 /**
  * @jest-environment jsdom
  */
-describe('LayoutFactory', () => {
+describe('LayoutFactory Graphology Libries', () => {
   /**
    * @jest-environment jsdom
    */
@@ -154,3 +154,39 @@ describe('LayoutFactory', () => {
     });
   }, TIMEOUT);
 });
+
+
+describe('LayoutFactory Cytoscape Libraries', () => {
+  /**
+   * @jest-environment jsdom
+   */
+  it('should work with noverlap from graphology ', () => {
+    const graph = new MultiGraph();
+
+    // Adding some nodes
+    // graph.addNode('John', { x: 0, y: 0, width: 200, height: 200 });
+    // graph.addNode('Martha', { x: 0, y: 0 });
+    graph.addNode('John');
+    graph.addNode('Martha');
+
+    // Adding an edge
+    graph.addEdge('John', 'Martha');
+
+    const layoutFactory = new LayoutFactory();
+    const layoutAlgorithm = layoutFactory.createLayout(
+      'Cytoscape_dagre'
+    );
+    layoutAlgorithm?.layout(graph);
+
+    // const positionMap = new Set<string>();
+    graph.forEachNode((node, attr) => {
+      expect(graph.getNodeAttribute(node, 'x')).toBeDefined();
+      expect(graph.getNodeAttribute(node, 'y')).toBeDefined();
+      
+      // const pos = '' + attr['x'] + '' + attr['y'];
+      // expect(positionMap.has(pos)).toBeFalsy();
+      // positionMap.add(pos);
+    });
+  }, TIMEOUT);
+
+});
\ No newline at end of file
diff --git a/libs/shared/graph-layouts/.eslintrc.json b/libs/shared/graph-layouts/.eslintrc.json
deleted file mode 100644
index 3456be9b9..000000000
--- a/libs/shared/graph-layouts/.eslintrc.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
-  "extends": ["../../../.eslintrc.json"],
-  "ignorePatterns": ["!**/*"],
-  "overrides": [
-    {
-      "files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
-      "rules": {}
-    },
-    {
-      "files": ["*.ts", "*.tsx"],
-      "rules": {}
-    },
-    {
-      "files": ["*.js", "*.jsx"],
-      "rules": {}
-    }
-  ]
-}
diff --git a/libs/shared/graph-layouts/README.md b/libs/shared/graph-layouts/README.md
deleted file mode 100644
index b30ee66b0..000000000
--- a/libs/shared/graph-layouts/README.md
+++ /dev/null
@@ -1,11 +0,0 @@
-# shared-graph-layouts
-
-This library was generated with [Nx](https://nx.dev).
-
-## Building
-
-Run `nx build shared-graph-layouts` to build the library.
-
-## Running unit tests
-
-Run `nx test shared-graph-layouts` to execute the unit tests via [Jest](https://jestjs.io).
diff --git a/libs/shared/graph-layouts/dist/README.md b/libs/shared/graph-layouts/dist/README.md
deleted file mode 100644
index b30ee66b0..000000000
--- a/libs/shared/graph-layouts/dist/README.md
+++ /dev/null
@@ -1,11 +0,0 @@
-# shared-graph-layouts
-
-This library was generated with [Nx](https://nx.dev).
-
-## Building
-
-Run `nx build shared-graph-layouts` to build the library.
-
-## Running unit tests
-
-Run `nx test shared-graph-layouts` to execute the unit tests via [Jest](https://jestjs.io).
diff --git a/libs/shared/graph-layouts/jest.config.js b/libs/shared/graph-layouts/jest.config.js
deleted file mode 100644
index 89ea43d51..000000000
--- a/libs/shared/graph-layouts/jest.config.js
+++ /dev/null
@@ -1,14 +0,0 @@
-module.exports = {
-  displayName: 'shared-graph-layouts',
-  preset: '../../../jest.preset.js',
-  globals: {
-    'ts-jest': {
-      tsconfig: '<rootDir>/tsconfig.spec.json',
-    },
-  },
-  transform: {
-    '^.+\\.[tj]s$': 'ts-jest',
-  },
-  moduleFileExtensions: ['ts', 'js', 'html'],
-  coverageDirectory: '../../../coverage/libs/shared/graph-layouts',
-};
diff --git a/libs/shared/graph-layouts/node_modules/.yarn-integrity b/libs/shared/graph-layouts/node_modules/.yarn-integrity
deleted file mode 100644
index f5558a47e..000000000
--- a/libs/shared/graph-layouts/node_modules/.yarn-integrity
+++ /dev/null
@@ -1,18 +0,0 @@
-{
-  "systemParams": "win32-x64-83",
-  "modulesFolders": [
-    "node_modules"
-  ],
-  "flags": [],
-  "linkedModules": [],
-  "topLevelPatterns": [
-    "graphology@^0.24.1"
-  ],
-  "lockfileEntries": {
-    "events@^3.3.0": "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400",
-    "graphology@^0.24.1": "https://registry.yarnpkg.com/graphology/-/graphology-0.24.1.tgz#035e452e294b01168cf5c85d5dd0a4b7e4837d87",
-    "obliterator@^2.0.2": "https://registry.yarnpkg.com/obliterator/-/obliterator-2.0.2.tgz#25f50dc92e1181371b9d8209d11890f1a3c2fc21"
-  },
-  "files": [],
-  "artifacts": {}
-}
\ No newline at end of file
diff --git a/libs/shared/graph-layouts/node_modules/events/.airtap.yml b/libs/shared/graph-layouts/node_modules/events/.airtap.yml
deleted file mode 100644
index c7a8a87d5..000000000
--- a/libs/shared/graph-layouts/node_modules/events/.airtap.yml
+++ /dev/null
@@ -1,15 +0,0 @@
-sauce_connect: true
-loopback: airtap.local
-browsers:
-  - name: chrome
-    version: latest
-  - name: firefox
-    version: latest
-  - name: safari
-    version: 9..latest
-  - name: iphone
-    version: latest
-  - name: ie
-    version: 9..latest
-  - name: microsoftedge
-    version: 13..latest
diff --git a/libs/shared/graph-layouts/node_modules/events/.github/FUNDING.yml b/libs/shared/graph-layouts/node_modules/events/.github/FUNDING.yml
deleted file mode 100644
index 8b8cb78ba..000000000
--- a/libs/shared/graph-layouts/node_modules/events/.github/FUNDING.yml
+++ /dev/null
@@ -1,12 +0,0 @@
-# These are supported funding model platforms
-
-github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
-patreon: # Replace with a single Patreon username
-open_collective: # Replace with a single Open Collective username
-ko_fi: # Replace with a single Ko-fi username
-tidelift: npm/events
-community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
-liberapay: # Replace with a single Liberapay username
-issuehunt: # Replace with a single IssueHunt username
-otechie: # Replace with a single Otechie username
-custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
diff --git a/libs/shared/graph-layouts/node_modules/events/.travis.yml b/libs/shared/graph-layouts/node_modules/events/.travis.yml
deleted file mode 100644
index 486dc3c4c..000000000
--- a/libs/shared/graph-layouts/node_modules/events/.travis.yml
+++ /dev/null
@@ -1,18 +0,0 @@
-dist: xenial
-os: linux
-language: node_js
-node_js:
-  - 'stable'
-  - 'lts/*'
-  - '0.12'
-script:
-  - npm test
-  - if [ "${TRAVIS_PULL_REQUEST}" = "false" ] && [ "${TRAVIS_NODE_VERSION}" = "stable" ]; then npm run test:browsers; fi
-addons:
-  sauce_connect: true
-  hosts:
-    - airtap.local
-env:
-  global:
-  - secure: XcBiD8yReflut9q7leKsigDZ0mI3qTKH+QrNVY8DaqlomJOZw8aOrVuX9Jz12l86ZJ41nbxmKnRNkFzcVr9mbP9YaeTb3DpeOBWmvaoSfud9Wnc16VfXtc1FCcwDhSVcSiM3UtnrmFU5cH+Dw1LPh5PbfylYOS/nJxUvG0FFLqI=
-  - secure: jNWtEbqhUdQ0xXDHvCYfUbKYeJCi6a7B4LsrcxYCyWWn4NIgncE5x2YbB+FSUUFVYfz0dsn5RKP1oHB99f0laUEo18HBNkrAS/rtyOdVzcpJjbQ6kgSILGjnJD/Ty1B57Rcz3iyev5Y7bLZ6Y1FbDnk/i9/l0faOGz8vTC3Vdkc=
diff --git a/libs/shared/graph-layouts/node_modules/events/History.md b/libs/shared/graph-layouts/node_modules/events/History.md
deleted file mode 100644
index f48bf210d..000000000
--- a/libs/shared/graph-layouts/node_modules/events/History.md
+++ /dev/null
@@ -1,118 +0,0 @@
-# 3.3.0
-
- - Support EventTarget emitters in `events.once` from Node.js 12.11.0.
-
-   Now you can use the `events.once` function with objects that implement the EventTarget interface. This interface is used widely in
-   the DOM and other web APIs.
-
-   ```js
-   var events = require('events');
-   var assert = require('assert');
-
-   async function connect() {
-     var ws = new WebSocket('wss://example.com');
-     await events.once(ws, 'open');
-     assert(ws.readyState === WebSocket.OPEN);
-   }
-
-   async function onClick() {
-     await events.once(document.body, 'click');
-     alert('you clicked the page!');
-   }
-   ```
-
-# 3.2.0
-
- - Add `events.once` from Node.js 11.13.0.
-
-   To use this function, Promises must be supported in the environment. Use a polyfill like `es6-promise` if you support older browsers.
-
-# 3.1.0 (2020-01-08)
-
-`events` now matches the Node.js 11.12.0 API.
-
-  - pass through return value in wrapped `emitter.once()` listeners
-
-    Now, this works:
-    ```js
-    emitter.once('myevent', function () { return 1; });
-    var listener = emitter.rawListeners('myevent')[0]
-    assert(listener() === 1);
-    ```
-    Previously, `listener()` would return undefined regardless of the implementation.
-
-    Ported from https://github.com/nodejs/node/commit/acc506c2d2771dab8d7bba6d3452bc5180dff7cf
-
-  - Reduce code duplication in listener type check ([#67](https://github.com/Gozala/events/pull/67) by [@friederbluemle](https://github.com/friederbluemle)).
-  - Improve `emitter.once()` performance in some engines
-
-# 3.0.0 (2018-05-25)
-
-**This version drops support for IE8.** `events` no longer includes polyfills
-for ES5 features. If you need to support older environments, use an ES5 shim
-like [es5-shim](https://npmjs.com/package/es5-shim). Both the shim and sham
-versions of es5-shim are necessary.
-
-  - Update to events code from Node.js 10.x
-    - (semver major) Adds `off()` method
-  - Port more tests from Node.js
-  - Switch browser tests to airtap, making things more reliable
-
-# 2.1.0 (2018-05-25)
-
-  - add Emitter#rawListeners from Node.js v9.4
-
-# 2.0.0 (2018-02-02)
-
-  - Update to events code from node.js 8.x
-    - Adds `prependListener()` and `prependOnceListener()`
-    - Adds `eventNames()` method
-    - (semver major) Unwrap `once()` listeners in `listeners()`
-  - copy tests from node.js
-
-Note that this version doubles the gzipped size, jumping from 1.1KB to 2.1KB,
-due to new methods and runtime performance improvements. Be aware of that when
-upgrading.
-
-# 1.1.1 (2016-06-22)
-
-  - add more context to errors if they are not instanceof Error
-
-# 1.1.0 (2015-09-29)
-
-  - add Emitter#listerCount (to match node v4 api)
-
-# 1.0.2 (2014-08-28)
-
-  - remove un-reachable code
-  - update devDeps
-
-## 1.0.1 / 2014-05-11
-
-  - check for console.trace before using it
-
-## 1.0.0 / 2013-12-10
-
-  - Update to latest events code from node.js 0.10
-  - copy tests from node.js
-
-## 0.4.0 / 2011-07-03 ##
-
-  - Switching to graphquire@0.8.0
-
-## 0.3.0 / 2011-07-03 ##
-
-  - Switching to URL based module require.
-
-## 0.2.0 / 2011-06-10 ##
-
-  - Simplified package structure.
-  - Graphquire for dependency management.
-
-## 0.1.1 / 2011-05-16 ##
-
-  - Unhandled errors are logged via console.error
-
-## 0.1.0 / 2011-04-22 ##
-
-  - Initial release
diff --git a/libs/shared/graph-layouts/node_modules/events/LICENSE b/libs/shared/graph-layouts/node_modules/events/LICENSE
deleted file mode 100644
index 52ed3b0a6..000000000
--- a/libs/shared/graph-layouts/node_modules/events/LICENSE
+++ /dev/null
@@ -1,22 +0,0 @@
-MIT
-
-Copyright Joyent, Inc. and other Node contributors.
-
-Permission is hereby granted, free of charge, to any person obtaining a
-copy of this software and associated documentation files (the
-"Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Software, and to permit
-persons to whom the Software is furnished to do so, subject to the
-following conditions:
-
-The above copyright notice and this permission notice shall be included
-in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
-NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
-DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
-USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/libs/shared/graph-layouts/node_modules/events/Readme.md b/libs/shared/graph-layouts/node_modules/events/Readme.md
deleted file mode 100644
index 80849c0b2..000000000
--- a/libs/shared/graph-layouts/node_modules/events/Readme.md
+++ /dev/null
@@ -1,50 +0,0 @@
-# events [![Build Status](https://travis-ci.org/Gozala/events.png?branch=master)](https://travis-ci.org/Gozala/events)
-
-> Node's event emitter for all engines.
-
-This implements the Node.js [`events`][node.js docs] module for environments that do not have it, like browsers.
-
-> `events` currently matches the **Node.js 11.13.0** API.
-
-Note that the `events` module uses ES5 features. If you need to support very old browsers like IE8, use a shim like [`es5-shim`](https://www.npmjs.com/package/es5-shim). You need both the shim and the sham versions of `es5-shim`.
-
-This module is maintained, but only by very few people. If you'd like to help, let us know in the [Maintainer Needed](https://github.com/Gozala/events/issues/43) issue!
-
-## Install
-
-You usually do not have to install `events` yourself! If your code runs in Node.js, `events` is built in. If your code runs in the browser, bundlers like [browserify](https://github.com/browserify/browserify) or [webpack](https://github.com/webpack/webpack) also include the `events` module.
-
-But if none of those apply, with npm do:
-
-```
-npm install events
-```
-
-## Usage
-
-```javascript
-var EventEmitter = require('events')
-
-var ee = new EventEmitter()
-ee.on('message', function (text) {
-  console.log(text)
-})
-ee.emit('message', 'hello world')
-```
-
-## API
-
-See the [Node.js EventEmitter docs][node.js docs]. `events` currently matches the Node.js 11.13.0 API.
-
-## Contributing
-
-PRs are very welcome! The main way to contribute to `events` is by porting features, bugfixes and tests from Node.js. Ideally, code contributions to this module are copy-pasted from Node.js and transpiled to ES5, rather than reimplemented from scratch. Matching the Node.js code as closely as possible makes maintenance simpler when new changes land in Node.js.
-This module intends to provide exactly the same API as Node.js, so features that are not available in the core `events` module will not be accepted. Feature requests should instead be directed at [nodejs/node](https://github.com/nodejs/node) and will be added to this module once they are implemented in Node.js.
-
-If there is a difference in behaviour between Node.js's `events` module and this module, please open an issue!
-
-## License
-
-[MIT](./LICENSE)
-
-[node.js docs]: https://nodejs.org/dist/v11.13.0/docs/api/events.html
diff --git a/libs/shared/graph-layouts/node_modules/events/events.js b/libs/shared/graph-layouts/node_modules/events/events.js
deleted file mode 100644
index 34b69a0b4..000000000
--- a/libs/shared/graph-layouts/node_modules/events/events.js
+++ /dev/null
@@ -1,497 +0,0 @@
-// Copyright Joyent, Inc. and other Node contributors.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a
-// copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to permit
-// persons to whom the Software is furnished to do so, subject to the
-// following conditions:
-//
-// The above copyright notice and this permission notice shall be included
-// in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
-// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
-// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
-// USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-'use strict';
-
-var R = typeof Reflect === 'object' ? Reflect : null
-var ReflectApply = R && typeof R.apply === 'function'
-  ? R.apply
-  : function ReflectApply(target, receiver, args) {
-    return Function.prototype.apply.call(target, receiver, args);
-  }
-
-var ReflectOwnKeys
-if (R && typeof R.ownKeys === 'function') {
-  ReflectOwnKeys = R.ownKeys
-} else if (Object.getOwnPropertySymbols) {
-  ReflectOwnKeys = function ReflectOwnKeys(target) {
-    return Object.getOwnPropertyNames(target)
-      .concat(Object.getOwnPropertySymbols(target));
-  };
-} else {
-  ReflectOwnKeys = function ReflectOwnKeys(target) {
-    return Object.getOwnPropertyNames(target);
-  };
-}
-
-function ProcessEmitWarning(warning) {
-  if (console && console.warn) console.warn(warning);
-}
-
-var NumberIsNaN = Number.isNaN || function NumberIsNaN(value) {
-  return value !== value;
-}
-
-function EventEmitter() {
-  EventEmitter.init.call(this);
-}
-module.exports = EventEmitter;
-module.exports.once = once;
-
-// Backwards-compat with node 0.10.x
-EventEmitter.EventEmitter = EventEmitter;
-
-EventEmitter.prototype._events = undefined;
-EventEmitter.prototype._eventsCount = 0;
-EventEmitter.prototype._maxListeners = undefined;
-
-// By default EventEmitters will print a warning if more than 10 listeners are
-// added to it. This is a useful default which helps finding memory leaks.
-var defaultMaxListeners = 10;
-
-function checkListener(listener) {
-  if (typeof listener !== 'function') {
-    throw new TypeError('The "listener" argument must be of type Function. Received type ' + typeof listener);
-  }
-}
-
-Object.defineProperty(EventEmitter, 'defaultMaxListeners', {
-  enumerable: true,
-  get: function() {
-    return defaultMaxListeners;
-  },
-  set: function(arg) {
-    if (typeof arg !== 'number' || arg < 0 || NumberIsNaN(arg)) {
-      throw new RangeError('The value of "defaultMaxListeners" is out of range. It must be a non-negative number. Received ' + arg + '.');
-    }
-    defaultMaxListeners = arg;
-  }
-});
-
-EventEmitter.init = function() {
-
-  if (this._events === undefined ||
-      this._events === Object.getPrototypeOf(this)._events) {
-    this._events = Object.create(null);
-    this._eventsCount = 0;
-  }
-
-  this._maxListeners = this._maxListeners || undefined;
-};
-
-// Obviously not all Emitters should be limited to 10. This function allows
-// that to be increased. Set to zero for unlimited.
-EventEmitter.prototype.setMaxListeners = function setMaxListeners(n) {
-  if (typeof n !== 'number' || n < 0 || NumberIsNaN(n)) {
-    throw new RangeError('The value of "n" is out of range. It must be a non-negative number. Received ' + n + '.');
-  }
-  this._maxListeners = n;
-  return this;
-};
-
-function _getMaxListeners(that) {
-  if (that._maxListeners === undefined)
-    return EventEmitter.defaultMaxListeners;
-  return that._maxListeners;
-}
-
-EventEmitter.prototype.getMaxListeners = function getMaxListeners() {
-  return _getMaxListeners(this);
-};
-
-EventEmitter.prototype.emit = function emit(type) {
-  var args = [];
-  for (var i = 1; i < arguments.length; i++) args.push(arguments[i]);
-  var doError = (type === 'error');
-
-  var events = this._events;
-  if (events !== undefined)
-    doError = (doError && events.error === undefined);
-  else if (!doError)
-    return false;
-
-  // If there is no 'error' event listener then throw.
-  if (doError) {
-    var er;
-    if (args.length > 0)
-      er = args[0];
-    if (er instanceof Error) {
-      // Note: The comments on the `throw` lines are intentional, they show
-      // up in Node's output if this results in an unhandled exception.
-      throw er; // Unhandled 'error' event
-    }
-    // At least give some kind of context to the user
-    var err = new Error('Unhandled error.' + (er ? ' (' + er.message + ')' : ''));
-    err.context = er;
-    throw err; // Unhandled 'error' event
-  }
-
-  var handler = events[type];
-
-  if (handler === undefined)
-    return false;
-
-  if (typeof handler === 'function') {
-    ReflectApply(handler, this, args);
-  } else {
-    var len = handler.length;
-    var listeners = arrayClone(handler, len);
-    for (var i = 0; i < len; ++i)
-      ReflectApply(listeners[i], this, args);
-  }
-
-  return true;
-};
-
-function _addListener(target, type, listener, prepend) {
-  var m;
-  var events;
-  var existing;
-
-  checkListener(listener);
-
-  events = target._events;
-  if (events === undefined) {
-    events = target._events = Object.create(null);
-    target._eventsCount = 0;
-  } else {
-    // To avoid recursion in the case that type === "newListener"! Before
-    // adding it to the listeners, first emit "newListener".
-    if (events.newListener !== undefined) {
-      target.emit('newListener', type,
-                  listener.listener ? listener.listener : listener);
-
-      // Re-assign `events` because a newListener handler could have caused the
-      // this._events to be assigned to a new object
-      events = target._events;
-    }
-    existing = events[type];
-  }
-
-  if (existing === undefined) {
-    // Optimize the case of one listener. Don't need the extra array object.
-    existing = events[type] = listener;
-    ++target._eventsCount;
-  } else {
-    if (typeof existing === 'function') {
-      // Adding the second element, need to change to array.
-      existing = events[type] =
-        prepend ? [listener, existing] : [existing, listener];
-      // If we've already got an array, just append.
-    } else if (prepend) {
-      existing.unshift(listener);
-    } else {
-      existing.push(listener);
-    }
-
-    // Check for listener leak
-    m = _getMaxListeners(target);
-    if (m > 0 && existing.length > m && !existing.warned) {
-      existing.warned = true;
-      // No error code for this since it is a Warning
-      // eslint-disable-next-line no-restricted-syntax
-      var w = new Error('Possible EventEmitter memory leak detected. ' +
-                          existing.length + ' ' + String(type) + ' listeners ' +
-                          'added. Use emitter.setMaxListeners() to ' +
-                          'increase limit');
-      w.name = 'MaxListenersExceededWarning';
-      w.emitter = target;
-      w.type = type;
-      w.count = existing.length;
-      ProcessEmitWarning(w);
-    }
-  }
-
-  return target;
-}
-
-EventEmitter.prototype.addListener = function addListener(type, listener) {
-  return _addListener(this, type, listener, false);
-};
-
-EventEmitter.prototype.on = EventEmitter.prototype.addListener;
-
-EventEmitter.prototype.prependListener =
-    function prependListener(type, listener) {
-      return _addListener(this, type, listener, true);
-    };
-
-function onceWrapper() {
-  if (!this.fired) {
-    this.target.removeListener(this.type, this.wrapFn);
-    this.fired = true;
-    if (arguments.length === 0)
-      return this.listener.call(this.target);
-    return this.listener.apply(this.target, arguments);
-  }
-}
-
-function _onceWrap(target, type, listener) {
-  var state = { fired: false, wrapFn: undefined, target: target, type: type, listener: listener };
-  var wrapped = onceWrapper.bind(state);
-  wrapped.listener = listener;
-  state.wrapFn = wrapped;
-  return wrapped;
-}
-
-EventEmitter.prototype.once = function once(type, listener) {
-  checkListener(listener);
-  this.on(type, _onceWrap(this, type, listener));
-  return this;
-};
-
-EventEmitter.prototype.prependOnceListener =
-    function prependOnceListener(type, listener) {
-      checkListener(listener);
-      this.prependListener(type, _onceWrap(this, type, listener));
-      return this;
-    };
-
-// Emits a 'removeListener' event if and only if the listener was removed.
-EventEmitter.prototype.removeListener =
-    function removeListener(type, listener) {
-      var list, events, position, i, originalListener;
-
-      checkListener(listener);
-
-      events = this._events;
-      if (events === undefined)
-        return this;
-
-      list = events[type];
-      if (list === undefined)
-        return this;
-
-      if (list === listener || list.listener === listener) {
-        if (--this._eventsCount === 0)
-          this._events = Object.create(null);
-        else {
-          delete events[type];
-          if (events.removeListener)
-            this.emit('removeListener', type, list.listener || listener);
-        }
-      } else if (typeof list !== 'function') {
-        position = -1;
-
-        for (i = list.length - 1; i >= 0; i--) {
-          if (list[i] === listener || list[i].listener === listener) {
-            originalListener = list[i].listener;
-            position = i;
-            break;
-          }
-        }
-
-        if (position < 0)
-          return this;
-
-        if (position === 0)
-          list.shift();
-        else {
-          spliceOne(list, position);
-        }
-
-        if (list.length === 1)
-          events[type] = list[0];
-
-        if (events.removeListener !== undefined)
-          this.emit('removeListener', type, originalListener || listener);
-      }
-
-      return this;
-    };
-
-EventEmitter.prototype.off = EventEmitter.prototype.removeListener;
-
-EventEmitter.prototype.removeAllListeners =
-    function removeAllListeners(type) {
-      var listeners, events, i;
-
-      events = this._events;
-      if (events === undefined)
-        return this;
-
-      // not listening for removeListener, no need to emit
-      if (events.removeListener === undefined) {
-        if (arguments.length === 0) {
-          this._events = Object.create(null);
-          this._eventsCount = 0;
-        } else if (events[type] !== undefined) {
-          if (--this._eventsCount === 0)
-            this._events = Object.create(null);
-          else
-            delete events[type];
-        }
-        return this;
-      }
-
-      // emit removeListener for all listeners on all events
-      if (arguments.length === 0) {
-        var keys = Object.keys(events);
-        var key;
-        for (i = 0; i < keys.length; ++i) {
-          key = keys[i];
-          if (key === 'removeListener') continue;
-          this.removeAllListeners(key);
-        }
-        this.removeAllListeners('removeListener');
-        this._events = Object.create(null);
-        this._eventsCount = 0;
-        return this;
-      }
-
-      listeners = events[type];
-
-      if (typeof listeners === 'function') {
-        this.removeListener(type, listeners);
-      } else if (listeners !== undefined) {
-        // LIFO order
-        for (i = listeners.length - 1; i >= 0; i--) {
-          this.removeListener(type, listeners[i]);
-        }
-      }
-
-      return this;
-    };
-
-function _listeners(target, type, unwrap) {
-  var events = target._events;
-
-  if (events === undefined)
-    return [];
-
-  var evlistener = events[type];
-  if (evlistener === undefined)
-    return [];
-
-  if (typeof evlistener === 'function')
-    return unwrap ? [evlistener.listener || evlistener] : [evlistener];
-
-  return unwrap ?
-    unwrapListeners(evlistener) : arrayClone(evlistener, evlistener.length);
-}
-
-EventEmitter.prototype.listeners = function listeners(type) {
-  return _listeners(this, type, true);
-};
-
-EventEmitter.prototype.rawListeners = function rawListeners(type) {
-  return _listeners(this, type, false);
-};
-
-EventEmitter.listenerCount = function(emitter, type) {
-  if (typeof emitter.listenerCount === 'function') {
-    return emitter.listenerCount(type);
-  } else {
-    return listenerCount.call(emitter, type);
-  }
-};
-
-EventEmitter.prototype.listenerCount = listenerCount;
-function listenerCount(type) {
-  var events = this._events;
-
-  if (events !== undefined) {
-    var evlistener = events[type];
-
-    if (typeof evlistener === 'function') {
-      return 1;
-    } else if (evlistener !== undefined) {
-      return evlistener.length;
-    }
-  }
-
-  return 0;
-}
-
-EventEmitter.prototype.eventNames = function eventNames() {
-  return this._eventsCount > 0 ? ReflectOwnKeys(this._events) : [];
-};
-
-function arrayClone(arr, n) {
-  var copy = new Array(n);
-  for (var i = 0; i < n; ++i)
-    copy[i] = arr[i];
-  return copy;
-}
-
-function spliceOne(list, index) {
-  for (; index + 1 < list.length; index++)
-    list[index] = list[index + 1];
-  list.pop();
-}
-
-function unwrapListeners(arr) {
-  var ret = new Array(arr.length);
-  for (var i = 0; i < ret.length; ++i) {
-    ret[i] = arr[i].listener || arr[i];
-  }
-  return ret;
-}
-
-function once(emitter, name) {
-  return new Promise(function (resolve, reject) {
-    function errorListener(err) {
-      emitter.removeListener(name, resolver);
-      reject(err);
-    }
-
-    function resolver() {
-      if (typeof emitter.removeListener === 'function') {
-        emitter.removeListener('error', errorListener);
-      }
-      resolve([].slice.call(arguments));
-    };
-
-    eventTargetAgnosticAddListener(emitter, name, resolver, { once: true });
-    if (name !== 'error') {
-      addErrorHandlerIfEventEmitter(emitter, errorListener, { once: true });
-    }
-  });
-}
-
-function addErrorHandlerIfEventEmitter(emitter, handler, flags) {
-  if (typeof emitter.on === 'function') {
-    eventTargetAgnosticAddListener(emitter, 'error', handler, flags);
-  }
-}
-
-function eventTargetAgnosticAddListener(emitter, name, listener, flags) {
-  if (typeof emitter.on === 'function') {
-    if (flags.once) {
-      emitter.once(name, listener);
-    } else {
-      emitter.on(name, listener);
-    }
-  } else if (typeof emitter.addEventListener === 'function') {
-    // EventTarget does not have `error` event semantics like Node
-    // EventEmitters, we do not listen for `error` events here.
-    emitter.addEventListener(name, function wrapListener(arg) {
-      // IE does not have builtin `{ once: true }` support so we
-      // have to do it manually.
-      if (flags.once) {
-        emitter.removeEventListener(name, wrapListener);
-      }
-      listener(arg);
-    });
-  } else {
-    throw new TypeError('The "emitter" argument must be of type EventEmitter. Received type ' + typeof emitter);
-  }
-}
diff --git a/libs/shared/graph-layouts/node_modules/events/package.json b/libs/shared/graph-layouts/node_modules/events/package.json
deleted file mode 100644
index b9580d881..000000000
--- a/libs/shared/graph-layouts/node_modules/events/package.json
+++ /dev/null
@@ -1,37 +0,0 @@
-{
-  "name": "events",
-  "version": "3.3.0",
-  "description": "Node's event emitter for all engines.",
-  "keywords": [
-    "events",
-    "eventEmitter",
-    "eventDispatcher",
-    "listeners"
-  ],
-  "author": "Irakli Gozalishvili <rfobic@gmail.com> (http://jeditoolkit.com)",
-  "repository": {
-    "type": "git",
-    "url": "git://github.com/Gozala/events.git",
-    "web": "https://github.com/Gozala/events"
-  },
-  "bugs": {
-    "url": "http://github.com/Gozala/events/issues/"
-  },
-  "main": "./events.js",
-  "engines": {
-    "node": ">=0.8.x"
-  },
-  "devDependencies": {
-    "airtap": "^1.0.0",
-    "functions-have-names": "^1.2.1",
-    "has": "^1.0.3",
-    "has-symbols": "^1.0.1",
-    "isarray": "^2.0.5",
-    "tape": "^5.0.0"
-  },
-  "scripts": {
-    "test": "node tests/index.js",
-    "test:browsers": "airtap -- tests/index.js"
-  },
-  "license": "MIT"
-}
diff --git a/libs/shared/graph-layouts/node_modules/events/security.md b/libs/shared/graph-layouts/node_modules/events/security.md
deleted file mode 100644
index a14ace6a5..000000000
--- a/libs/shared/graph-layouts/node_modules/events/security.md
+++ /dev/null
@@ -1,10 +0,0 @@
-# Security Policy
-
-## Supported Versions
-Only the latest major version is supported at any given time.
-
-## Reporting a Vulnerability
-
-To report a security vulnerability, please use the
-[Tidelift security contact](https://tidelift.com/security).
-Tidelift will coordinate the fix and disclosure.
diff --git a/libs/shared/graph-layouts/node_modules/events/tests/add-listeners.js b/libs/shared/graph-layouts/node_modules/events/tests/add-listeners.js
deleted file mode 100644
index 9b578272b..000000000
--- a/libs/shared/graph-layouts/node_modules/events/tests/add-listeners.js
+++ /dev/null
@@ -1,111 +0,0 @@
-// Copyright Joyent, Inc. and other Node contributors.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a
-// copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to permit
-// persons to whom the Software is furnished to do so, subject to the
-// following conditions:
-//
-// The above copyright notice and this permission notice shall be included
-// in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
-// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
-// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
-// USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-var common = require('./common');
-var assert = require('assert');
-var EventEmitter = require('../');
-
-{
-  var ee = new EventEmitter();
-  var events_new_listener_emitted = [];
-  var listeners_new_listener_emitted = [];
-
-  // Sanity check
-  assert.strictEqual(ee.addListener, ee.on);
-
-  ee.on('newListener', function(event, listener) {
-    // Don't track newListener listeners.
-    if (event === 'newListener')
-      return;
-
-    events_new_listener_emitted.push(event);
-    listeners_new_listener_emitted.push(listener);
-  });
-
-  var hello = common.mustCall(function(a, b) {
-    assert.strictEqual('a', a);
-    assert.strictEqual('b', b);
-  });
-
-  ee.once('newListener', function(name, listener) {
-    assert.strictEqual(name, 'hello');
-    assert.strictEqual(listener, hello);
-
-    var listeners = this.listeners('hello');
-    assert.ok(Array.isArray(listeners));
-    assert.strictEqual(listeners.length, 0);
-  });
-
-  ee.on('hello', hello);
-  ee.once('foo', assert.fail);
-
-  assert.ok(Array.isArray(events_new_listener_emitted));
-  assert.strictEqual(events_new_listener_emitted.length, 2);
-  assert.strictEqual(events_new_listener_emitted[0], 'hello');
-  assert.strictEqual(events_new_listener_emitted[1], 'foo');
-
-  assert.ok(Array.isArray(listeners_new_listener_emitted));
-  assert.strictEqual(listeners_new_listener_emitted.length, 2);
-  assert.strictEqual(listeners_new_listener_emitted[0], hello);
-  assert.strictEqual(listeners_new_listener_emitted[1], assert.fail);
-
-  ee.emit('hello', 'a', 'b');
-}
-
-// just make sure that this doesn't throw:
-{
-  var f = new EventEmitter();
-
-  f.setMaxListeners(0);
-}
-
-{
-  var listen1 = function() {};
-  var listen2 = function() {};
-  var ee = new EventEmitter();
-
-  ee.once('newListener', function() {
-    var listeners = ee.listeners('hello');
-    assert.ok(Array.isArray(listeners));
-    assert.strictEqual(listeners.length, 0);
-    ee.once('newListener', function() {
-      var listeners = ee.listeners('hello');
-      assert.ok(Array.isArray(listeners));
-      assert.strictEqual(listeners.length, 0);
-    });
-    ee.on('hello', listen2);
-  });
-  ee.on('hello', listen1);
-  // The order of listeners on an event is not always the order in which the
-  // listeners were added.
-  var listeners = ee.listeners('hello');
-  assert.ok(Array.isArray(listeners));
-  assert.strictEqual(listeners.length, 2);
-  assert.strictEqual(listeners[0], listen2);
-  assert.strictEqual(listeners[1], listen1);
-}
-
-// Verify that the listener must be a function
-assert.throws(function() {
-  var ee = new EventEmitter();
-
-  ee.on('foo', null);
-}, /^TypeError: The "listener" argument must be of type Function. Received type object$/);
diff --git a/libs/shared/graph-layouts/node_modules/events/tests/check-listener-leaks.js b/libs/shared/graph-layouts/node_modules/events/tests/check-listener-leaks.js
deleted file mode 100644
index 7fce48f37..000000000
--- a/libs/shared/graph-layouts/node_modules/events/tests/check-listener-leaks.js
+++ /dev/null
@@ -1,101 +0,0 @@
-// Copyright Joyent, Inc. and other Node contributors.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a
-// copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to permit
-// persons to whom the Software is furnished to do so, subject to the
-// following conditions:
-//
-// The above copyright notice and this permission notice shall be included
-// in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
-// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
-// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
-// USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-var common = require('./common');
-var assert = require('assert');
-var events = require('../');
-
-// Redirect warning output to tape.
-var consoleWarn = console.warn;
-console.warn = common.test.comment;
-
-common.test.on('end', function () {
-  console.warn = consoleWarn;
-});
-
-// default
-{
-  var e = new events.EventEmitter();
-
-  for (var i = 0; i < 10; i++) {
-    e.on('default', common.mustNotCall());
-  }
-  assert.ok(!e._events['default'].hasOwnProperty('warned'));
-  e.on('default', common.mustNotCall());
-  assert.ok(e._events['default'].warned);
-
-  // specific
-  e.setMaxListeners(5);
-  for (var i = 0; i < 5; i++) {
-    e.on('specific', common.mustNotCall());
-  }
-  assert.ok(!e._events['specific'].hasOwnProperty('warned'));
-  e.on('specific', common.mustNotCall());
-  assert.ok(e._events['specific'].warned);
-
-  // only one
-  e.setMaxListeners(1);
-  e.on('only one', common.mustNotCall());
-  assert.ok(!e._events['only one'].hasOwnProperty('warned'));
-  e.on('only one', common.mustNotCall());
-  assert.ok(e._events['only one'].hasOwnProperty('warned'));
-
-  // unlimited
-  e.setMaxListeners(0);
-  for (var i = 0; i < 1000; i++) {
-    e.on('unlimited', common.mustNotCall());
-  }
-  assert.ok(!e._events['unlimited'].hasOwnProperty('warned'));
-}
-
-// process-wide
-{
-  events.EventEmitter.defaultMaxListeners = 42;
-  var e = new events.EventEmitter();
-
-  for (var i = 0; i < 42; ++i) {
-    e.on('fortytwo', common.mustNotCall());
-  }
-  assert.ok(!e._events['fortytwo'].hasOwnProperty('warned'));
-  e.on('fortytwo', common.mustNotCall());
-  assert.ok(e._events['fortytwo'].hasOwnProperty('warned'));
-  delete e._events['fortytwo'].warned;
-
-  events.EventEmitter.defaultMaxListeners = 44;
-  e.on('fortytwo', common.mustNotCall());
-  assert.ok(!e._events['fortytwo'].hasOwnProperty('warned'));
-  e.on('fortytwo', common.mustNotCall());
-  assert.ok(e._events['fortytwo'].hasOwnProperty('warned'));
-}
-
-// but _maxListeners still has precedence over defaultMaxListeners
-{
-  events.EventEmitter.defaultMaxListeners = 42;
-  var e = new events.EventEmitter();
-  e.setMaxListeners(1);
-  e.on('uno', common.mustNotCall());
-  assert.ok(!e._events['uno'].hasOwnProperty('warned'));
-  e.on('uno', common.mustNotCall());
-  assert.ok(e._events['uno'].hasOwnProperty('warned'));
-
-  // chainable
-  assert.strictEqual(e, e.setMaxListeners(1));
-}
diff --git a/libs/shared/graph-layouts/node_modules/events/tests/common.js b/libs/shared/graph-layouts/node_modules/events/tests/common.js
deleted file mode 100644
index 49569b05f..000000000
--- a/libs/shared/graph-layouts/node_modules/events/tests/common.js
+++ /dev/null
@@ -1,104 +0,0 @@
-// Copyright Joyent, Inc. and other Node contributors.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a
-// copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to permit
-// persons to whom the Software is furnished to do so, subject to the
-// following conditions:
-//
-// The above copyright notice and this permission notice shall be included
-// in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
-// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
-// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
-// USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-var test = require('tape');
-var assert = require('assert');
-
-var noop = function() {};
-
-var mustCallChecks = [];
-
-function runCallChecks(exitCode) {
-  if (exitCode !== 0) return;
-
-  var failed = filter(mustCallChecks, function(context) {
-    if ('minimum' in context) {
-      context.messageSegment = 'at least ' + context.minimum;
-      return context.actual < context.minimum;
-    } else {
-      context.messageSegment = 'exactly ' + context.exact;
-      return context.actual !== context.exact;
-    }
-  });
-
-  for (var i = 0; i < failed.length; i++) {
-    var context = failed[i];
-    console.log('Mismatched %s function calls. Expected %s, actual %d.',
-        context.name,
-        context.messageSegment,
-        context.actual);
-    // IE8 has no .stack
-    if (context.stack) console.log(context.stack.split('\n').slice(2).join('\n'));
-  }
-
-  assert.strictEqual(failed.length, 0);
-}
-
-exports.mustCall = function(fn, exact) {
-  return _mustCallInner(fn, exact, 'exact');
-};
-
-function _mustCallInner(fn, criteria, field) {
-  if (typeof criteria == 'undefined') criteria = 1;
-
-  if (typeof fn === 'number') {
-    criteria = fn;
-    fn = noop;
-  } else if (fn === undefined) {
-    fn = noop;
-  }
-
-  if (typeof criteria !== 'number')
-    throw new TypeError('Invalid ' + field + ' value: ' + criteria);
-
-  var context = {
-    actual: 0,
-    stack: (new Error()).stack,
-    name: fn.name || '<anonymous>'
-  };
-
-  context[field] = criteria;
-
-  // add the exit listener only once to avoid listener leak warnings
-  if (mustCallChecks.length === 0) test.onFinish(function() { runCallChecks(0); });
-
-  mustCallChecks.push(context);
-
-  return function() {
-    context.actual++;
-    return fn.apply(this, arguments);
-  };
-}
-
-exports.mustNotCall = function(msg) {
-  return function mustNotCall() {
-    assert.fail(msg || 'function should not have been called');
-  };
-};
-
-function filter(arr, fn) {
-  if (arr.filter) return arr.filter(fn);
-  var filtered = [];
-  for (var i = 0; i < arr.length; i++) {
-    if (fn(arr[i], i, arr)) filtered.push(arr[i]);
-  }
-  return filtered
-}
diff --git a/libs/shared/graph-layouts/node_modules/events/tests/errors.js b/libs/shared/graph-layouts/node_modules/events/tests/errors.js
deleted file mode 100644
index a23df437f..000000000
--- a/libs/shared/graph-layouts/node_modules/events/tests/errors.js
+++ /dev/null
@@ -1,13 +0,0 @@
-'use strict';
-var assert = require('assert');
-var EventEmitter = require('../');
-
-var EE = new EventEmitter();
-
-assert.throws(function () {
-  EE.emit('error', 'Accepts a string');
-}, 'Error: Unhandled error. (Accepts a string)');
-
-assert.throws(function () {
-  EE.emit('error', { message: 'Error!' });
-}, 'Unhandled error. ([object Object])');
diff --git a/libs/shared/graph-layouts/node_modules/events/tests/events-list.js b/libs/shared/graph-layouts/node_modules/events/tests/events-list.js
deleted file mode 100644
index 08aa62177..000000000
--- a/libs/shared/graph-layouts/node_modules/events/tests/events-list.js
+++ /dev/null
@@ -1,28 +0,0 @@
-'use strict';
-
-var EventEmitter = require('../');
-var assert = require('assert');
-
-var EE = new EventEmitter();
-var m = function() {};
-EE.on('foo', function() {});
-assert.equal(1, EE.eventNames().length);
-assert.equal('foo', EE.eventNames()[0]);
-EE.on('bar', m);
-assert.equal(2, EE.eventNames().length);
-assert.equal('foo', EE.eventNames()[0]);
-assert.equal('bar', EE.eventNames()[1]);
-EE.removeListener('bar', m);
-assert.equal(1, EE.eventNames().length);
-assert.equal('foo', EE.eventNames()[0]);
-
-if (typeof Symbol !== 'undefined') {
-  var s = Symbol('s');
-  EE.on(s, m);
-  assert.equal(2, EE.eventNames().length);
-  assert.equal('foo', EE.eventNames()[0]);
-  assert.equal(s, EE.eventNames()[1]);
-  EE.removeListener(s, m);
-  assert.equal(1, EE.eventNames().length);
-  assert.equal('foo', EE.eventNames()[0]);
-}
diff --git a/libs/shared/graph-layouts/node_modules/events/tests/events-once.js b/libs/shared/graph-layouts/node_modules/events/tests/events-once.js
deleted file mode 100644
index dae864963..000000000
--- a/libs/shared/graph-layouts/node_modules/events/tests/events-once.js
+++ /dev/null
@@ -1,234 +0,0 @@
-'use strict';
-
-var common = require('./common');
-var EventEmitter = require('../').EventEmitter;
-var once = require('../').once;
-var has = require('has');
-var assert = require('assert');
-
-function Event(type) {
-  this.type = type;
-}
-
-function EventTargetMock() {
-  this.events = {};
-
-  this.addEventListener = common.mustCall(this.addEventListener);
-  this.removeEventListener = common.mustCall(this.removeEventListener);
-}
-
-EventTargetMock.prototype.addEventListener = function addEventListener(name, listener, options) {
-  if (!(name in this.events)) {
-    this.events[name] = { listeners: [], options: options || {} }
-  }
-  this.events[name].listeners.push(listener);
-};
-
-EventTargetMock.prototype.removeEventListener = function removeEventListener(name, callback) {
-  if (!(name in this.events)) {
-    return;
-  }
-  var event = this.events[name];
-  var stack = event.listeners;
-
-  for (var i = 0, l = stack.length; i < l; i++) {
-    if (stack[i] === callback) {
-      stack.splice(i, 1);
-      if (stack.length === 0) {
-        delete this.events[name];
-      }
-      return;
-    }
-  }
-};
-
-EventTargetMock.prototype.dispatchEvent = function dispatchEvent(arg) {
-  if (!(arg.type in this.events)) {
-    return true;
-  }
-
-  var event = this.events[arg.type];
-  var stack = event.listeners.slice();
-
-  for (var i = 0, l = stack.length; i < l; i++) {
-    stack[i].call(null, arg);
-    if (event.options.once) {
-      this.removeEventListener(arg.type, stack[i]);
-    }
-  }
-  return !arg.defaultPrevented;
-};
-
-function onceAnEvent() {
-  var ee = new EventEmitter();
-
-  process.nextTick(function () {
-    ee.emit('myevent', 42);
-  });
-
-  return once(ee, 'myevent').then(function (args) {
-    var value = args[0]
-    assert.strictEqual(value, 42);
-    assert.strictEqual(ee.listenerCount('error'), 0);
-    assert.strictEqual(ee.listenerCount('myevent'), 0);
-  });
-}
-
-function onceAnEventWithTwoArgs() {
-  var ee = new EventEmitter();
-
-  process.nextTick(function () {
-    ee.emit('myevent', 42, 24);
-  });
-
-  return once(ee, 'myevent').then(function (value) {
-    assert.strictEqual(value.length, 2);
-    assert.strictEqual(value[0], 42);
-    assert.strictEqual(value[1], 24);
-  });
-}
-
-function catchesErrors() {
-  var ee = new EventEmitter();
-
-  var expected = new Error('kaboom');
-  var err;
-  process.nextTick(function () {
-    ee.emit('error', expected);
-  });
-
-  return once(ee, 'myevent').then(function () {
-    throw new Error('should reject')
-  }, function (err) {
-    assert.strictEqual(err, expected);
-    assert.strictEqual(ee.listenerCount('error'), 0);
-    assert.strictEqual(ee.listenerCount('myevent'), 0);
-  });
-}
-
-function stopListeningAfterCatchingError() {
-  var ee = new EventEmitter();
-
-  var expected = new Error('kaboom');
-  var err;
-  process.nextTick(function () {
-    ee.emit('error', expected);
-    ee.emit('myevent', 42, 24);
-  });
-
-  // process.on('multipleResolves', common.mustNotCall());
-
-  return once(ee, 'myevent').then(common.mustNotCall, function (err) {
-    // process.removeAllListeners('multipleResolves');
-    assert.strictEqual(err, expected);
-    assert.strictEqual(ee.listenerCount('error'), 0);
-    assert.strictEqual(ee.listenerCount('myevent'), 0);
-  });
-}
-
-function onceError() {
-  var ee = new EventEmitter();
-
-  var expected = new Error('kaboom');
-  process.nextTick(function () {
-    ee.emit('error', expected);
-  });
-
-  var promise = once(ee, 'error');
-  assert.strictEqual(ee.listenerCount('error'), 1);
-  return promise.then(function (args) {
-    var err = args[0]
-    assert.strictEqual(err, expected);
-    assert.strictEqual(ee.listenerCount('error'), 0);
-    assert.strictEqual(ee.listenerCount('myevent'), 0);
-  });
-}
-
-function onceWithEventTarget() {
-  var et = new EventTargetMock();
-  var event = new Event('myevent');
-  process.nextTick(function () {
-    et.dispatchEvent(event);
-  });
-  return once(et, 'myevent').then(function (args) {
-    var value = args[0];
-    assert.strictEqual(value, event);
-    assert.strictEqual(has(et.events, 'myevent'), false);
-  });
-}
-
-function onceWithEventTargetError() {
-  var et = new EventTargetMock();
-  var error = new Event('error');
-  process.nextTick(function () {
-    et.dispatchEvent(error);
-  });
-  return once(et, 'error').then(function (args) {
-    var err = args[0];
-    assert.strictEqual(err, error);
-    assert.strictEqual(has(et.events, 'error'), false);
-  });
-}
-
-function prioritizesEventEmitter() {
-  var ee = new EventEmitter();
-  ee.addEventListener = assert.fail;
-  ee.removeAllListeners = assert.fail;
-  process.nextTick(function () {
-    ee.emit('foo');
-  });
-  return once(ee, 'foo');
-}
-
-var allTests = [
-  onceAnEvent(),
-  onceAnEventWithTwoArgs(),
-  catchesErrors(),
-  stopListeningAfterCatchingError(),
-  onceError(),
-  onceWithEventTarget(),
-  onceWithEventTargetError(),
-  prioritizesEventEmitter()
-];
-
-var hasBrowserEventTarget = false;
-try {
-  hasBrowserEventTarget = typeof (new window.EventTarget().addEventListener) === 'function' &&
-    new window.Event('xyz').type === 'xyz';
-} catch (err) {}
-
-if (hasBrowserEventTarget) {
-  var onceWithBrowserEventTarget = function onceWithBrowserEventTarget() {
-    var et = new window.EventTarget();
-    var event = new window.Event('myevent');
-    process.nextTick(function () {
-      et.dispatchEvent(event);
-    });
-    return once(et, 'myevent').then(function (args) {
-      var value = args[0];
-      assert.strictEqual(value, event);
-      assert.strictEqual(has(et.events, 'myevent'), false);
-    });
-  }
-
-  var onceWithBrowserEventTargetError = function onceWithBrowserEventTargetError() {
-    var et = new window.EventTarget();
-    var error = new window.Event('error');
-    process.nextTick(function () {
-      et.dispatchEvent(error);
-    });
-    return once(et, 'error').then(function (args) {
-      var err = args[0];
-      assert.strictEqual(err, error);
-      assert.strictEqual(has(et.events, 'error'), false);
-    });
-  }
-
-  common.test.comment('Testing with browser built-in EventTarget');
-  allTests.push([
-    onceWithBrowserEventTarget(),
-    onceWithBrowserEventTargetError()
-  ]);
-}
-
-module.exports = Promise.all(allTests);
diff --git a/libs/shared/graph-layouts/node_modules/events/tests/index.js b/libs/shared/graph-layouts/node_modules/events/tests/index.js
deleted file mode 100644
index 2d739e670..000000000
--- a/libs/shared/graph-layouts/node_modules/events/tests/index.js
+++ /dev/null
@@ -1,64 +0,0 @@
-var test = require('tape');
-var functionsHaveNames = require('functions-have-names');
-var hasSymbols = require('has-symbols');
-
-require('./legacy-compat');
-var common = require('./common');
-
-// we do this to easily wrap each file in a mocha test
-// and also have browserify be able to statically analyze this file
-var orig_require = require;
-var require = function(file) {
-    test(file, function(t) {
-        // Store the tape object so tests can access it.
-        t.on('end', function () { delete common.test; });
-        common.test = t;
-
-        try {
-          var exp = orig_require(file);
-          if (exp && exp.then) {
-            exp.then(function () { t.end(); }, t.fail);
-            return;
-          }
-        } catch (err) {
-          t.fail(err);
-        }
-        t.end();
-    });
-};
-
-require('./add-listeners.js');
-require('./check-listener-leaks.js');
-require('./errors.js');
-require('./events-list.js');
-if (typeof Promise === 'function') {
-  require('./events-once.js');
-} else {
-  // Promise support is not available.
-  test('./events-once.js', { skip: true }, function () {});
-}
-require('./listener-count.js');
-require('./listeners-side-effects.js');
-require('./listeners.js');
-require('./max-listeners.js');
-if (functionsHaveNames()) {
-  require('./method-names.js');
-} else {
-  // Function.name is not supported in IE
-  test('./method-names.js', { skip: true }, function () {});
-}
-require('./modify-in-emit.js');
-require('./num-args.js');
-require('./once.js');
-require('./prepend.js');
-require('./set-max-listeners-side-effects.js');
-require('./special-event-names.js');
-require('./subclass.js');
-if (hasSymbols()) {
-  require('./symbols.js');
-} else {
-  // Symbol is not available.
-  test('./symbols.js', { skip: true }, function () {});
-}
-require('./remove-all-listeners.js');
-require('./remove-listeners.js');
diff --git a/libs/shared/graph-layouts/node_modules/events/tests/legacy-compat.js b/libs/shared/graph-layouts/node_modules/events/tests/legacy-compat.js
deleted file mode 100644
index a402be6e2..000000000
--- a/libs/shared/graph-layouts/node_modules/events/tests/legacy-compat.js
+++ /dev/null
@@ -1,16 +0,0 @@
-// sigh... life is hard
-if (!global.console) {
-    console = {}
-}
-
-var fns = ['log', 'error', 'trace'];
-for (var i=0 ; i<fns.length ; ++i) {
-    var fn = fns[i];
-    if (!console[fn]) {
-        console[fn] = function() {};
-    }
-}
-
-if (!Array.isArray) {
-    Array.isArray = require('isarray');
-}
diff --git a/libs/shared/graph-layouts/node_modules/events/tests/listener-count.js b/libs/shared/graph-layouts/node_modules/events/tests/listener-count.js
deleted file mode 100644
index 9d422d872..000000000
--- a/libs/shared/graph-layouts/node_modules/events/tests/listener-count.js
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright Joyent, Inc. and other Node contributors.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a
-// copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to permit
-// persons to whom the Software is furnished to do so, subject to the
-// following conditions:
-//
-// The above copyright notice and this permission notice shall be included
-// in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
-// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
-// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
-// USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-require('./common');
-var assert = require('assert');
-var EventEmitter = require('../');
-
-var emitter = new EventEmitter();
-emitter.on('foo', function() {});
-emitter.on('foo', function() {});
-emitter.on('baz', function() {});
-// Allow any type
-emitter.on(123, function() {});
-
-assert.strictEqual(EventEmitter.listenerCount(emitter, 'foo'), 2);
-assert.strictEqual(emitter.listenerCount('foo'), 2);
-assert.strictEqual(emitter.listenerCount('bar'), 0);
-assert.strictEqual(emitter.listenerCount('baz'), 1);
-assert.strictEqual(emitter.listenerCount(123), 1);
diff --git a/libs/shared/graph-layouts/node_modules/events/tests/listeners-side-effects.js b/libs/shared/graph-layouts/node_modules/events/tests/listeners-side-effects.js
deleted file mode 100644
index 180f83312..000000000
--- a/libs/shared/graph-layouts/node_modules/events/tests/listeners-side-effects.js
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright Joyent, Inc. and other Node contributors.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a
-// copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to permit
-// persons to whom the Software is furnished to do so, subject to the
-// following conditions:
-//
-// The above copyright notice and this permission notice shall be included
-// in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
-// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
-// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
-// USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-require('./common');
-var assert = require('assert');
-
-var EventEmitter = require('../').EventEmitter;
-
-var e = new EventEmitter();
-var fl;  // foo listeners
-
-fl = e.listeners('foo');
-assert.ok(Array.isArray(fl));
-assert.strictEqual(fl.length, 0);
-if (Object.create) assert.ok(!(e._events instanceof Object));
-assert.strictEqual(Object.keys(e._events).length, 0);
-
-e.on('foo', assert.fail);
-fl = e.listeners('foo');
-assert.strictEqual(e._events.foo, assert.fail);
-assert.ok(Array.isArray(fl));
-assert.strictEqual(fl.length, 1);
-assert.strictEqual(fl[0], assert.fail);
-
-e.listeners('bar');
-
-e.on('foo', assert.ok);
-fl = e.listeners('foo');
-
-assert.ok(Array.isArray(e._events.foo));
-assert.strictEqual(e._events.foo.length, 2);
-assert.strictEqual(e._events.foo[0], assert.fail);
-assert.strictEqual(e._events.foo[1], assert.ok);
-
-assert.ok(Array.isArray(fl));
-assert.strictEqual(fl.length, 2);
-assert.strictEqual(fl[0], assert.fail);
-assert.strictEqual(fl[1], assert.ok);
diff --git a/libs/shared/graph-layouts/node_modules/events/tests/listeners.js b/libs/shared/graph-layouts/node_modules/events/tests/listeners.js
deleted file mode 100644
index 1909d2dfe..000000000
--- a/libs/shared/graph-layouts/node_modules/events/tests/listeners.js
+++ /dev/null
@@ -1,168 +0,0 @@
-// Copyright Joyent, Inc. and other Node contributors.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a
-// copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to permit
-// persons to whom the Software is furnished to do so, subject to the
-// following conditions:
-//
-// The above copyright notice and this permission notice shall be included
-// in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
-// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
-// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
-// USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-require('./common');
-var assert = require('assert');
-var events = require('../');
-var util = require('util');
-
-function listener() {}
-function listener2() {}
-function listener3() {
-  return 0;
-}
-function listener4() {
-  return 1;
-}
-
-function TestStream() {}
-util.inherits(TestStream, events.EventEmitter);
-
-{
-  var ee = new events.EventEmitter();
-  ee.on('foo', listener);
-  var fooListeners = ee.listeners('foo');
-
-  var listeners = ee.listeners('foo');
-  assert.ok(Array.isArray(listeners));
-  assert.strictEqual(listeners.length, 1);
-  assert.strictEqual(listeners[0], listener);
-
-  ee.removeAllListeners('foo');
-  listeners = ee.listeners('foo');
-  assert.ok(Array.isArray(listeners));
-  assert.strictEqual(listeners.length, 0);
-
-  assert.ok(Array.isArray(fooListeners));
-  assert.strictEqual(fooListeners.length, 1);
-  assert.strictEqual(fooListeners[0], listener);
-}
-
-{
-  var ee = new events.EventEmitter();
-  ee.on('foo', listener);
-
-  var eeListenersCopy = ee.listeners('foo');
-  assert.ok(Array.isArray(eeListenersCopy));
-  assert.strictEqual(eeListenersCopy.length, 1);
-  assert.strictEqual(eeListenersCopy[0], listener);
-
-  var listeners = ee.listeners('foo');
-  assert.ok(Array.isArray(listeners));
-  assert.strictEqual(listeners.length, 1);
-  assert.strictEqual(listeners[0], listener);
-
-  eeListenersCopy.push(listener2);
-  listeners = ee.listeners('foo');
-  
-  assert.ok(Array.isArray(listeners));
-  assert.strictEqual(listeners.length, 1);
-  assert.strictEqual(listeners[0], listener);
-
-  assert.strictEqual(eeListenersCopy.length, 2);
-  assert.strictEqual(eeListenersCopy[0], listener);
-  assert.strictEqual(eeListenersCopy[1], listener2);
-}
-
-{
-  var ee = new events.EventEmitter();
-  ee.on('foo', listener);
-  var eeListenersCopy = ee.listeners('foo');
-  ee.on('foo', listener2);
-
-  var listeners = ee.listeners('foo');
-  assert.ok(Array.isArray(listeners));
-  assert.strictEqual(listeners.length, 2);
-  assert.strictEqual(listeners[0], listener);
-  assert.strictEqual(listeners[1], listener2);
-
-  assert.ok(Array.isArray(eeListenersCopy));
-  assert.strictEqual(eeListenersCopy.length, 1);
-  assert.strictEqual(eeListenersCopy[0], listener);
-}
-
-{
-  var ee = new events.EventEmitter();
-  ee.once('foo', listener);
-  var listeners = ee.listeners('foo');
-  assert.ok(Array.isArray(listeners));
-  assert.strictEqual(listeners.length, 1);
-  assert.strictEqual(listeners[0], listener);
-}
-
-{
-  var ee = new events.EventEmitter();
-  ee.on('foo', listener);
-  ee.once('foo', listener2);
-
-  var listeners = ee.listeners('foo');
-  assert.ok(Array.isArray(listeners));
-  assert.strictEqual(listeners.length, 2);
-  assert.strictEqual(listeners[0], listener);
-  assert.strictEqual(listeners[1], listener2);
-}
-
-{
-  var ee = new events.EventEmitter();
-  ee._events = undefined;
-  var listeners = ee.listeners('foo');
-  assert.ok(Array.isArray(listeners));
-  assert.strictEqual(listeners.length, 0);
-}
-
-{
-  var s = new TestStream();
-  var listeners = s.listeners('foo');
-  assert.ok(Array.isArray(listeners));
-  assert.strictEqual(listeners.length, 0);
-}
-
-
-{
-  var ee = new events.EventEmitter();
-  ee.on('foo', listener);
-  var wrappedListener = ee.rawListeners('foo');
-  assert.strictEqual(wrappedListener.length, 1);
-  assert.strictEqual(wrappedListener[0], listener);
-  assert.notStrictEqual(wrappedListener, ee.rawListeners('foo'));
-  ee.once('foo', listener);
-  var wrappedListeners = ee.rawListeners('foo');
-  assert.strictEqual(wrappedListeners.length, 2);
-  assert.strictEqual(wrappedListeners[0], listener);
-  assert.notStrictEqual(wrappedListeners[1], listener);
-  assert.strictEqual(wrappedListeners[1].listener, listener);
-  assert.notStrictEqual(wrappedListeners, ee.rawListeners('foo'));
-  ee.emit('foo');
-  assert.strictEqual(wrappedListeners.length, 2);
-  assert.strictEqual(wrappedListeners[1].listener, listener);
-}
-
-{
-  var ee = new events.EventEmitter();
-  ee.once('foo', listener3);
-  ee.on('foo', listener4);
-  var rawListeners = ee.rawListeners('foo');
-  assert.strictEqual(rawListeners.length, 2);
-  assert.strictEqual(rawListeners[0](), 0);
-  var rawListener = ee.rawListeners('foo');
-  assert.strictEqual(rawListener.length, 1);
-  assert.strictEqual(rawListener[0](), 1);
-}
diff --git a/libs/shared/graph-layouts/node_modules/events/tests/max-listeners.js b/libs/shared/graph-layouts/node_modules/events/tests/max-listeners.js
deleted file mode 100644
index 0b4395385..000000000
--- a/libs/shared/graph-layouts/node_modules/events/tests/max-listeners.js
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright Joyent, Inc. and other Node contributors.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a
-// copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to permit
-// persons to whom the Software is furnished to do so, subject to the
-// following conditions:
-//
-// The above copyright notice and this permission notice shall be included
-// in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
-// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
-// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
-// USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-var common = require('./common');
-var assert = require('assert');
-var events = require('../');
-var e = new events.EventEmitter();
-
-var hasDefineProperty = !!Object.defineProperty;
-try { Object.defineProperty({}, 'x', { value: 0 }); } catch (err) { hasDefineProperty = false }
-
-e.on('maxListeners', common.mustCall());
-
-// Should not corrupt the 'maxListeners' queue.
-e.setMaxListeners(42);
-
-var throwsObjs = [NaN, -1, 'and even this'];
-var maxError = /^RangeError: The value of "n" is out of range\. It must be a non-negative number\./;
-var defError = /^RangeError: The value of "defaultMaxListeners" is out of range\. It must be a non-negative number\./;
-
-for (var i = 0; i < throwsObjs.length; i++) {
-  var obj = throwsObjs[i];
-  assert.throws(function() { e.setMaxListeners(obj); }, maxError);
-  if (hasDefineProperty) {
-    assert.throws(function() { events.defaultMaxListeners = obj; }, defError);
-  }
-}
-
-e.emit('maxListeners');
diff --git a/libs/shared/graph-layouts/node_modules/events/tests/method-names.js b/libs/shared/graph-layouts/node_modules/events/tests/method-names.js
deleted file mode 100644
index 364a161fe..000000000
--- a/libs/shared/graph-layouts/node_modules/events/tests/method-names.js
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright Joyent, Inc. and other Node contributors.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a
-// copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to permit
-// persons to whom the Software is furnished to do so, subject to the
-// following conditions:
-//
-// The above copyright notice and this permission notice shall be included
-// in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
-// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
-// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
-// USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-'use strict';
-require('./common');
-var assert = require('assert');
-var events = require('../');
-
-var E = events.EventEmitter.prototype;
-assert.strictEqual(E.constructor.name, 'EventEmitter');
-assert.strictEqual(E.on, E.addListener);  // Same method.
-assert.strictEqual(E.off, E.removeListener);  // Same method.
-Object.getOwnPropertyNames(E).forEach(function(name) {
-  if (name === 'constructor' || name === 'on' || name === 'off') return;
-  if (typeof E[name] !== 'function') return;
-  assert.strictEqual(E[name].name, name);
-});
diff --git a/libs/shared/graph-layouts/node_modules/events/tests/modify-in-emit.js b/libs/shared/graph-layouts/node_modules/events/tests/modify-in-emit.js
deleted file mode 100644
index 53fa63395..000000000
--- a/libs/shared/graph-layouts/node_modules/events/tests/modify-in-emit.js
+++ /dev/null
@@ -1,90 +0,0 @@
-// Copyright Joyent, Inc. and other Node contributors.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a
-// copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to permit
-// persons to whom the Software is furnished to do so, subject to the
-// following conditions:
-//
-// The above copyright notice and this permission notice shall be included
-// in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
-// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
-// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
-// USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-require('./common');
-var assert = require('assert');
-var events = require('../');
-
-var callbacks_called = [];
-
-var e = new events.EventEmitter();
-
-function callback1() {
-  callbacks_called.push('callback1');
-  e.on('foo', callback2);
-  e.on('foo', callback3);
-  e.removeListener('foo', callback1);
-}
-
-function callback2() {
-  callbacks_called.push('callback2');
-  e.removeListener('foo', callback2);
-}
-
-function callback3() {
-  callbacks_called.push('callback3');
-  e.removeListener('foo', callback3);
-}
-
-e.on('foo', callback1);
-assert.strictEqual(e.listeners('foo').length, 1);
-
-e.emit('foo');
-assert.strictEqual(e.listeners('foo').length, 2);
-assert.ok(Array.isArray(callbacks_called));
-assert.strictEqual(callbacks_called.length, 1);
-assert.strictEqual(callbacks_called[0], 'callback1');
-
-e.emit('foo');
-assert.strictEqual(e.listeners('foo').length, 0);
-assert.ok(Array.isArray(callbacks_called));
-assert.strictEqual(callbacks_called.length, 3);
-assert.strictEqual(callbacks_called[0], 'callback1');
-assert.strictEqual(callbacks_called[1], 'callback2');
-assert.strictEqual(callbacks_called[2], 'callback3');
-
-e.emit('foo');
-assert.strictEqual(e.listeners('foo').length, 0);
-assert.ok(Array.isArray(callbacks_called));
-assert.strictEqual(callbacks_called.length, 3);
-assert.strictEqual(callbacks_called[0], 'callback1');
-assert.strictEqual(callbacks_called[1], 'callback2');
-assert.strictEqual(callbacks_called[2], 'callback3');
-
-e.on('foo', callback1);
-e.on('foo', callback2);
-assert.strictEqual(e.listeners('foo').length, 2);
-e.removeAllListeners('foo');
-assert.strictEqual(e.listeners('foo').length, 0);
-
-// Verify that removing callbacks while in emit allows emits to propagate to
-// all listeners
-callbacks_called = [];
-
-e.on('foo', callback2);
-e.on('foo', callback3);
-assert.strictEqual(2, e.listeners('foo').length);
-e.emit('foo');
-assert.ok(Array.isArray(callbacks_called));
-assert.strictEqual(callbacks_called.length, 2);
-assert.strictEqual(callbacks_called[0], 'callback2');
-assert.strictEqual(callbacks_called[1], 'callback3');
-assert.strictEqual(0, e.listeners('foo').length);
diff --git a/libs/shared/graph-layouts/node_modules/events/tests/num-args.js b/libs/shared/graph-layouts/node_modules/events/tests/num-args.js
deleted file mode 100644
index c9b0deb9c..000000000
--- a/libs/shared/graph-layouts/node_modules/events/tests/num-args.js
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright Joyent, Inc. and other Node contributors.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a
-// copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to permit
-// persons to whom the Software is furnished to do so, subject to the
-// following conditions:
-//
-// The above copyright notice and this permission notice shall be included
-// in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
-// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
-// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
-// USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-require('./common');
-var assert = require('assert');
-var events = require('../');
-
-var e = new events.EventEmitter();
-var num_args_emitted = [];
-
-e.on('numArgs', function() {
-  var numArgs = arguments.length;
-  num_args_emitted.push(numArgs);
-});
-
-e.on('foo', function() {
-  num_args_emitted.push(arguments.length);
-});
-
-e.on('foo', function() {
-  num_args_emitted.push(arguments.length);
-});
-
-e.emit('numArgs');
-e.emit('numArgs', null);
-e.emit('numArgs', null, null);
-e.emit('numArgs', null, null, null);
-e.emit('numArgs', null, null, null, null);
-e.emit('numArgs', null, null, null, null, null);
-
-e.emit('foo', null, null, null, null);
-
-assert.ok(Array.isArray(num_args_emitted));
-assert.strictEqual(num_args_emitted.length, 8);
-assert.strictEqual(num_args_emitted[0], 0);
-assert.strictEqual(num_args_emitted[1], 1);
-assert.strictEqual(num_args_emitted[2], 2);
-assert.strictEqual(num_args_emitted[3], 3);
-assert.strictEqual(num_args_emitted[4], 4);
-assert.strictEqual(num_args_emitted[5], 5);
-assert.strictEqual(num_args_emitted[6], 4);
-assert.strictEqual(num_args_emitted[6], 4);
diff --git a/libs/shared/graph-layouts/node_modules/events/tests/once.js b/libs/shared/graph-layouts/node_modules/events/tests/once.js
deleted file mode 100644
index 4b36c055e..000000000
--- a/libs/shared/graph-layouts/node_modules/events/tests/once.js
+++ /dev/null
@@ -1,83 +0,0 @@
-// Copyright Joyent, Inc. and other Node contributors.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a
-// copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to permit
-// persons to whom the Software is furnished to do so, subject to the
-// following conditions:
-//
-// The above copyright notice and this permission notice shall be included
-// in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
-// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
-// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
-// USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-var common = require('./common');
-var assert = require('assert');
-var EventEmitter = require('../');
-
-var e = new EventEmitter();
-
-e.once('hello', common.mustCall());
-
-e.emit('hello', 'a', 'b');
-e.emit('hello', 'a', 'b');
-e.emit('hello', 'a', 'b');
-e.emit('hello', 'a', 'b');
-
-function remove() {
-  assert.fail('once->foo should not be emitted');
-}
-
-e.once('foo', remove);
-e.removeListener('foo', remove);
-e.emit('foo');
-
-e.once('e', common.mustCall(function() {
-  e.emit('e');
-}));
-
-e.once('e', common.mustCall());
-
-e.emit('e');
-
-// Verify that the listener must be a function
-assert.throws(function() {
-  var ee = new EventEmitter();
-
-  ee.once('foo', null);
-}, /^TypeError: The "listener" argument must be of type Function. Received type object$/);
-
-{
-  // once() has different code paths based on the number of arguments being
-  // emitted. Verify that all of the cases are covered.
-  var maxArgs = 4;
-
-  for (var i = 0; i <= maxArgs; ++i) {
-    var ee = new EventEmitter();
-    var args = ['foo'];
-
-    for (var j = 0; j < i; ++j)
-      args.push(j);
-
-    ee.once('foo', common.mustCall(function() {
-      var params = Array.prototype.slice.call(arguments);
-      var restArgs = args.slice(1);
-      assert.ok(Array.isArray(params));
-      assert.strictEqual(params.length, restArgs.length);
-      for (var index = 0; index < params.length; index++) {
-        var param = params[index];
-        assert.strictEqual(param, restArgs[index]);
-      }
-  	}));
-
-    EventEmitter.prototype.emit.apply(ee, args);
-  }
-}
diff --git a/libs/shared/graph-layouts/node_modules/events/tests/prepend.js b/libs/shared/graph-layouts/node_modules/events/tests/prepend.js
deleted file mode 100644
index 79afde0bf..000000000
--- a/libs/shared/graph-layouts/node_modules/events/tests/prepend.js
+++ /dev/null
@@ -1,31 +0,0 @@
-'use strict';
-
-var common = require('./common');
-var EventEmitter = require('../');
-var assert = require('assert');
-
-var myEE = new EventEmitter();
-var m = 0;
-// This one comes last.
-myEE.on('foo', common.mustCall(function () {
-  assert.strictEqual(m, 2);
-}));
-
-// This one comes second.
-myEE.prependListener('foo', common.mustCall(function () {
-  assert.strictEqual(m++, 1);
-}));
-
-// This one comes first.
-myEE.prependOnceListener('foo',
-                         common.mustCall(function () {
-                           assert.strictEqual(m++, 0);
-                         }));
-
-myEE.emit('foo');
-
-// Verify that the listener must be a function
-assert.throws(function () {
-  var ee = new EventEmitter();
-  ee.prependOnceListener('foo', null);
-}, 'TypeError: The "listener" argument must be of type Function. Received type object');
diff --git a/libs/shared/graph-layouts/node_modules/events/tests/remove-all-listeners.js b/libs/shared/graph-layouts/node_modules/events/tests/remove-all-listeners.js
deleted file mode 100644
index 622941cfa..000000000
--- a/libs/shared/graph-layouts/node_modules/events/tests/remove-all-listeners.js
+++ /dev/null
@@ -1,133 +0,0 @@
-// Copyright Joyent, Inc. and other Node contributors.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a
-// copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to permit
-// persons to whom the Software is furnished to do so, subject to the
-// following conditions:
-//
-// The above copyright notice and this permission notice shall be included
-// in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
-// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
-// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
-// USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-var common = require('./common');
-var assert = require('assert');
-var events = require('../');
-var test = require('tape');
-
-function expect(expected) {
-  var actual = [];
-  test.onFinish(function() {
-    var sortedActual = actual.sort();
-    var sortedExpected = expected.sort();
-    assert.strictEqual(sortedActual.length, sortedExpected.length);
-    for (var index = 0; index < sortedActual.length; index++) {
-      var value = sortedActual[index];
-      assert.strictEqual(value, sortedExpected[index]);
-    }
-  });
-  function listener(name) {
-    actual.push(name);
-  }
-  return common.mustCall(listener, expected.length);
-}
-
-{
-  var ee = new events.EventEmitter();
-  var noop = common.mustNotCall();
-  ee.on('foo', noop);
-  ee.on('bar', noop);
-  ee.on('baz', noop);
-  ee.on('baz', noop);
-  var fooListeners = ee.listeners('foo');
-  var barListeners = ee.listeners('bar');
-  var bazListeners = ee.listeners('baz');
-  ee.on('removeListener', expect(['bar', 'baz', 'baz']));
-  ee.removeAllListeners('bar');
-  ee.removeAllListeners('baz');
-
-  var listeners = ee.listeners('foo');
-  assert.ok(Array.isArray(listeners));
-  assert.strictEqual(listeners.length, 1);
-  assert.strictEqual(listeners[0], noop);
-
-  listeners = ee.listeners('bar');
-  assert.ok(Array.isArray(listeners));
-  assert.strictEqual(listeners.length, 0);
-  listeners = ee.listeners('baz');
-  assert.ok(Array.isArray(listeners));
-  assert.strictEqual(listeners.length, 0);
-  // After calling removeAllListeners(),
-  // the old listeners array should stay unchanged.
-  assert.strictEqual(fooListeners.length, 1);
-  assert.strictEqual(fooListeners[0], noop);
-  assert.strictEqual(barListeners.length, 1);
-  assert.strictEqual(barListeners[0], noop);
-  assert.strictEqual(bazListeners.length, 2);
-  assert.strictEqual(bazListeners[0], noop);
-  assert.strictEqual(bazListeners[1], noop);
-  // After calling removeAllListeners(),
-  // new listeners arrays is different from the old.
-  assert.notStrictEqual(ee.listeners('bar'), barListeners);
-  assert.notStrictEqual(ee.listeners('baz'), bazListeners);
-}
-
-{
-  var ee = new events.EventEmitter();
-  ee.on('foo', common.mustNotCall());
-  ee.on('bar', common.mustNotCall());
-  // Expect LIFO order
-  ee.on('removeListener', expect(['foo', 'bar', 'removeListener']));
-  ee.on('removeListener', expect(['foo', 'bar']));
-  ee.removeAllListeners();
-
-  var listeners = ee.listeners('foo');
-  assert.ok(Array.isArray(listeners));
-  assert.strictEqual(listeners.length, 0);
-  listeners = ee.listeners('bar');
-  assert.ok(Array.isArray(listeners));
-  assert.strictEqual(listeners.length, 0);
-}
-
-{
-  var ee = new events.EventEmitter();
-  ee.on('removeListener', common.mustNotCall());
-  // Check for regression where removeAllListeners() throws when
-  // there exists a 'removeListener' listener, but there exists
-  // no listeners for the provided event type.
-  assert.doesNotThrow(function () { ee.removeAllListeners(ee, 'foo') });
-}
-
-{
-  var ee = new events.EventEmitter();
-  var expectLength = 2;
-  ee.on('removeListener', function() {
-    assert.strictEqual(expectLength--, this.listeners('baz').length);
-  });
-  ee.on('baz', common.mustNotCall());
-  ee.on('baz', common.mustNotCall());
-  ee.on('baz', common.mustNotCall());
-  assert.strictEqual(ee.listeners('baz').length, expectLength + 1);
-  ee.removeAllListeners('baz');
-  assert.strictEqual(ee.listeners('baz').length, 0);
-}
-
-{
-  var ee = new events.EventEmitter();
-  assert.strictEqual(ee, ee.removeAllListeners());
-}
-
-{
-  var ee = new events.EventEmitter();
-  ee._events = undefined;
-  assert.strictEqual(ee, ee.removeAllListeners());
-}
diff --git a/libs/shared/graph-layouts/node_modules/events/tests/remove-listeners.js b/libs/shared/graph-layouts/node_modules/events/tests/remove-listeners.js
deleted file mode 100644
index 18e4d1651..000000000
--- a/libs/shared/graph-layouts/node_modules/events/tests/remove-listeners.js
+++ /dev/null
@@ -1,212 +0,0 @@
-// Copyright Joyent, Inc. and other Node contributors.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a
-// copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to permit
-// persons to whom the Software is furnished to do so, subject to the
-// following conditions:
-//
-// The above copyright notice and this permission notice shall be included
-// in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
-// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
-// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
-// USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-var common = require('./common');
-var assert = require('assert');
-var EventEmitter = require('../');
-
-var listener1 = function listener1() {};
-var listener2 = function listener2() {};
-
-{
-  var ee = new EventEmitter();
-  ee.on('hello', listener1);
-  ee.on('removeListener', common.mustCall(function(name, cb) {
-    assert.strictEqual(name, 'hello');
-    assert.strictEqual(cb, listener1);
-  }));
-  ee.removeListener('hello', listener1);
-  var listeners = ee.listeners('hello');
-  assert.ok(Array.isArray(listeners));
-  assert.strictEqual(listeners.length, 0);
-}
-
-{
-  var ee = new EventEmitter();
-  ee.on('hello', listener1);
-  ee.on('removeListener', common.mustNotCall());
-  ee.removeListener('hello', listener2);
-
-  var listeners = ee.listeners('hello');
-  assert.ok(Array.isArray(listeners));
-  assert.strictEqual(listeners.length, 1);
-  assert.strictEqual(listeners[0], listener1);
-}
-
-{
-  var ee = new EventEmitter();
-  ee.on('hello', listener1);
-  ee.on('hello', listener2);
-
-  var listeners;
-  ee.once('removeListener', common.mustCall(function(name, cb) {
-    assert.strictEqual(name, 'hello');
-    assert.strictEqual(cb, listener1);
-    listeners = ee.listeners('hello');
-    assert.ok(Array.isArray(listeners));
-    assert.strictEqual(listeners.length, 1);
-    assert.strictEqual(listeners[0], listener2);
-  }));
-  ee.removeListener('hello', listener1);
-  listeners = ee.listeners('hello');
-  assert.ok(Array.isArray(listeners));
-  assert.strictEqual(listeners.length, 1);
-  assert.strictEqual(listeners[0], listener2);
-  ee.once('removeListener', common.mustCall(function(name, cb) {
-    assert.strictEqual(name, 'hello');
-    assert.strictEqual(cb, listener2);
-    listeners = ee.listeners('hello');
-    assert.ok(Array.isArray(listeners));
-    assert.strictEqual(listeners.length, 0);
-  }));
-  ee.removeListener('hello', listener2);
-  listeners = ee.listeners('hello');
-  assert.ok(Array.isArray(listeners));
-  assert.strictEqual(listeners.length, 0);
-}
-
-{
-  var ee = new EventEmitter();
-
-  function remove1() {
-    assert.fail('remove1 should not have been called');
-  }
-
-  function remove2() {
-    assert.fail('remove2 should not have been called');
-  }
-
-  ee.on('removeListener', common.mustCall(function(name, cb) {
-    if (cb !== remove1) return;
-    this.removeListener('quux', remove2);
-    this.emit('quux');
-  }, 2));
-  ee.on('quux', remove1);
-  ee.on('quux', remove2);
-  ee.removeListener('quux', remove1);
-}
-
-{
-  var ee = new EventEmitter();
-  ee.on('hello', listener1);
-  ee.on('hello', listener2);
-
-  var listeners;
-  ee.once('removeListener', common.mustCall(function(name, cb) {
-    assert.strictEqual(name, 'hello');
-    assert.strictEqual(cb, listener1);
-    listeners = ee.listeners('hello');
-    assert.ok(Array.isArray(listeners));
-    assert.strictEqual(listeners.length, 1);
-    assert.strictEqual(listeners[0], listener2);
-    ee.once('removeListener', common.mustCall(function(name, cb) {
-      assert.strictEqual(name, 'hello');
-      assert.strictEqual(cb, listener2);
-      listeners = ee.listeners('hello');
-      assert.ok(Array.isArray(listeners));
-      assert.strictEqual(listeners.length, 0);
-    }));
-    ee.removeListener('hello', listener2);
-    listeners = ee.listeners('hello');
-    assert.ok(Array.isArray(listeners));
-    assert.strictEqual(listeners.length, 0);
-  }));
-  ee.removeListener('hello', listener1);
-  listeners = ee.listeners('hello');
-  assert.ok(Array.isArray(listeners));
-  assert.strictEqual(listeners.length, 0);
-}
-
-{
-  var ee = new EventEmitter();
-  var listener3 = common.mustCall(function() {
-    ee.removeListener('hello', listener4);
-  }, 2);
-  var listener4 = common.mustCall();
-
-  ee.on('hello', listener3);
-  ee.on('hello', listener4);
-
-  // listener4 will still be called although it is removed by listener 3.
-  ee.emit('hello');
-  // This is so because the interal listener array at time of emit
-  // was [listener3,listener4]
-
-  // Interal listener array [listener3]
-  ee.emit('hello');
-}
-
-{
-  var ee = new EventEmitter();
-
-  ee.once('hello', listener1);
-  ee.on('removeListener', common.mustCall(function(eventName, listener) {
-    assert.strictEqual(eventName, 'hello');
-    assert.strictEqual(listener, listener1);
-  }));
-  ee.emit('hello');
-}
-
-{
-  var ee = new EventEmitter();
-
-  assert.strictEqual(ee, ee.removeListener('foo', function() {}));
-}
-
-// Verify that the removed listener must be a function
-assert.throws(function() {
-  var ee = new EventEmitter();
-
-  ee.removeListener('foo', null);
-}, /^TypeError: The "listener" argument must be of type Function\. Received type object$/);
-
-{
-  var ee = new EventEmitter();
-  var listener = function() {};
-  ee._events = undefined;
-  var e = ee.removeListener('foo', listener);
-  assert.strictEqual(e, ee);
-}
-
-{
-  var ee = new EventEmitter();
-
-  ee.on('foo', listener1);
-  ee.on('foo', listener2);
-  var listeners = ee.listeners('foo');
-  assert.ok(Array.isArray(listeners));
-  assert.strictEqual(listeners.length, 2);
-  assert.strictEqual(listeners[0], listener1);
-  assert.strictEqual(listeners[1], listener2);
-
-  ee.removeListener('foo', listener1);
-  assert.strictEqual(ee._events.foo, listener2);
-
-  ee.on('foo', listener1);
-  listeners = ee.listeners('foo');
-  assert.ok(Array.isArray(listeners));
-  assert.strictEqual(listeners.length, 2);
-  assert.strictEqual(listeners[0], listener2);
-  assert.strictEqual(listeners[1], listener1);
-
-  ee.removeListener('foo', listener1);
-  assert.strictEqual(ee._events.foo, listener2);
-}
diff --git a/libs/shared/graph-layouts/node_modules/events/tests/set-max-listeners-side-effects.js b/libs/shared/graph-layouts/node_modules/events/tests/set-max-listeners-side-effects.js
deleted file mode 100644
index 13dbb671e..000000000
--- a/libs/shared/graph-layouts/node_modules/events/tests/set-max-listeners-side-effects.js
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright Joyent, Inc. and other Node contributors.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a
-// copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to permit
-// persons to whom the Software is furnished to do so, subject to the
-// following conditions:
-//
-// The above copyright notice and this permission notice shall be included
-// in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
-// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
-// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
-// USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-require('./common');
-var assert = require('assert');
-var events = require('../');
-
-var e = new events.EventEmitter();
-
-if (Object.create) assert.ok(!(e._events instanceof Object));
-assert.strictEqual(Object.keys(e._events).length, 0);
-e.setMaxListeners(5);
-assert.strictEqual(Object.keys(e._events).length, 0);
diff --git a/libs/shared/graph-layouts/node_modules/events/tests/special-event-names.js b/libs/shared/graph-layouts/node_modules/events/tests/special-event-names.js
deleted file mode 100644
index a2f0b744a..000000000
--- a/libs/shared/graph-layouts/node_modules/events/tests/special-event-names.js
+++ /dev/null
@@ -1,45 +0,0 @@
-'use strict';
-
-var common = require('./common');
-var EventEmitter = require('../');
-var assert = require('assert');
-
-var ee = new EventEmitter();
-var handler = function() {};
-
-assert.strictEqual(ee.eventNames().length, 0);
-
-assert.strictEqual(ee._events.hasOwnProperty, undefined);
-assert.strictEqual(ee._events.toString, undefined);
-
-ee.on('__defineGetter__', handler);
-ee.on('toString', handler);
-ee.on('__proto__', handler);
-
-assert.strictEqual(ee.eventNames()[0], '__defineGetter__');
-assert.strictEqual(ee.eventNames()[1], 'toString');
-
-assert.strictEqual(ee.listeners('__defineGetter__').length, 1);
-assert.strictEqual(ee.listeners('__defineGetter__')[0], handler);
-assert.strictEqual(ee.listeners('toString').length, 1);
-assert.strictEqual(ee.listeners('toString')[0], handler);
-
-// Only run __proto__ tests if that property can actually be set
-if ({ __proto__: 'ok' }.__proto__ === 'ok') {
-  assert.strictEqual(ee.eventNames().length, 3);
-  assert.strictEqual(ee.eventNames()[2], '__proto__');
-  assert.strictEqual(ee.listeners('__proto__').length, 1);
-  assert.strictEqual(ee.listeners('__proto__')[0], handler);
-
-  ee.on('__proto__', common.mustCall(function(val) {
-    assert.strictEqual(val, 1);
-  }));
-  ee.emit('__proto__', 1);
-
-  process.on('__proto__', common.mustCall(function(val) {
-    assert.strictEqual(val, 1);
-  }));
-  process.emit('__proto__', 1);
-} else {
-  console.log('# skipped __proto__')
-}
diff --git a/libs/shared/graph-layouts/node_modules/events/tests/subclass.js b/libs/shared/graph-layouts/node_modules/events/tests/subclass.js
deleted file mode 100644
index bd033fff4..000000000
--- a/libs/shared/graph-layouts/node_modules/events/tests/subclass.js
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright Joyent, Inc. and other Node contributors.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a
-// copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to permit
-// persons to whom the Software is furnished to do so, subject to the
-// following conditions:
-//
-// The above copyright notice and this permission notice shall be included
-// in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
-// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
-// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
-// USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-var common = require('./common');
-var test = require('tape');
-var assert = require('assert');
-var EventEmitter = require('../').EventEmitter;
-var util = require('util');
-
-util.inherits(MyEE, EventEmitter);
-
-function MyEE(cb) {
-  this.once(1, cb);
-  this.emit(1);
-  this.removeAllListeners();
-  EventEmitter.call(this);
-}
-
-var myee = new MyEE(common.mustCall());
-
-
-util.inherits(ErrorEE, EventEmitter);
-function ErrorEE() {
-  this.emit('error', new Error('blerg'));
-}
-
-assert.throws(function() {
-  new ErrorEE();
-}, /blerg/);
-
-test.onFinish(function() {
-  assert.ok(!(myee._events instanceof Object));
-  assert.strictEqual(Object.keys(myee._events).length, 0);
-});
-
-
-function MyEE2() {
-  EventEmitter.call(this);
-}
-
-MyEE2.prototype = new EventEmitter();
-
-var ee1 = new MyEE2();
-var ee2 = new MyEE2();
-
-ee1.on('x', function() {});
-
-assert.strictEqual(ee2.listenerCount('x'), 0);
diff --git a/libs/shared/graph-layouts/node_modules/events/tests/symbols.js b/libs/shared/graph-layouts/node_modules/events/tests/symbols.js
deleted file mode 100644
index 0721f0ec0..000000000
--- a/libs/shared/graph-layouts/node_modules/events/tests/symbols.js
+++ /dev/null
@@ -1,25 +0,0 @@
-'use strict';
-
-var common = require('./common');
-var EventEmitter = require('../');
-var assert = require('assert');
-
-var ee = new EventEmitter();
-var foo = Symbol('foo');
-var listener = common.mustCall();
-
-ee.on(foo, listener);
-assert.strictEqual(ee.listeners(foo).length, 1);
-assert.strictEqual(ee.listeners(foo)[0], listener);
-
-ee.emit(foo);
-
-ee.removeAllListeners();
-assert.strictEqual(ee.listeners(foo).length, 0);
-
-ee.on(foo, listener);
-assert.strictEqual(ee.listeners(foo).length, 1);
-assert.strictEqual(ee.listeners(foo)[0], listener);
-
-ee.removeListener(foo, listener);
-assert.strictEqual(ee.listeners(foo).length, 0);
diff --git a/libs/shared/graph-layouts/node_modules/graphology/LICENSE.txt b/libs/shared/graph-layouts/node_modules/graphology/LICENSE.txt
deleted file mode 100644
index 158967c8d..000000000
--- a/libs/shared/graph-layouts/node_modules/graphology/LICENSE.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2016-2021 Guillaume Plique (Yomguithereal)
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
diff --git a/libs/shared/graph-layouts/node_modules/graphology/README.md b/libs/shared/graph-layouts/node_modules/graphology/README.md
deleted file mode 100644
index cb1dd4452..000000000
--- a/libs/shared/graph-layouts/node_modules/graphology/README.md
+++ /dev/null
@@ -1,9 +0,0 @@
-# Graphology
-
-`graphology` is a specification for a robust & multipurpose JavaScript `Graph` object and aiming at supporting various kinds of graphs under a same unified interface.
-
-You will also find here the source for the reference implementation of this specification.
-
-## Documentation
-
-Full documentation for the library/specs is available [here](https://graphology.github.io).
diff --git a/libs/shared/graph-layouts/node_modules/graphology/dist/graphology.cjs.js b/libs/shared/graph-layouts/node_modules/graphology/dist/graphology.cjs.js
deleted file mode 100644
index 9bd8ac9c7..000000000
--- a/libs/shared/graph-layouts/node_modules/graphology/dist/graphology.cjs.js
+++ /dev/null
@@ -1,5463 +0,0 @@
-'use strict';
-
-var events = require('events');
-var Iterator = require('obliterator/iterator');
-var take = require('obliterator/take');
-var chain = require('obliterator/chain');
-
-function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
-
-var Iterator__default = /*#__PURE__*/_interopDefaultLegacy(Iterator);
-var take__default = /*#__PURE__*/_interopDefaultLegacy(take);
-var chain__default = /*#__PURE__*/_interopDefaultLegacy(chain);
-
-function _typeof(obj) {
-  "@babel/helpers - typeof";
-
-  return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) {
-    return typeof obj;
-  } : function (obj) {
-    return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
-  }, _typeof(obj);
-}
-
-function _inheritsLoose(subClass, superClass) {
-  subClass.prototype = Object.create(superClass.prototype);
-  subClass.prototype.constructor = subClass;
-
-  _setPrototypeOf(subClass, superClass);
-}
-
-function _getPrototypeOf(o) {
-  _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) {
-    return o.__proto__ || Object.getPrototypeOf(o);
-  };
-  return _getPrototypeOf(o);
-}
-
-function _setPrototypeOf(o, p) {
-  _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {
-    o.__proto__ = p;
-    return o;
-  };
-
-  return _setPrototypeOf(o, p);
-}
-
-function _isNativeReflectConstruct() {
-  if (typeof Reflect === "undefined" || !Reflect.construct) return false;
-  if (Reflect.construct.sham) return false;
-  if (typeof Proxy === "function") return true;
-
-  try {
-    Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}));
-    return true;
-  } catch (e) {
-    return false;
-  }
-}
-
-function _construct(Parent, args, Class) {
-  if (_isNativeReflectConstruct()) {
-    _construct = Reflect.construct;
-  } else {
-    _construct = function _construct(Parent, args, Class) {
-      var a = [null];
-      a.push.apply(a, args);
-      var Constructor = Function.bind.apply(Parent, a);
-      var instance = new Constructor();
-      if (Class) _setPrototypeOf(instance, Class.prototype);
-      return instance;
-    };
-  }
-
-  return _construct.apply(null, arguments);
-}
-
-function _isNativeFunction(fn) {
-  return Function.toString.call(fn).indexOf("[native code]") !== -1;
-}
-
-function _wrapNativeSuper(Class) {
-  var _cache = typeof Map === "function" ? new Map() : undefined;
-
-  _wrapNativeSuper = function _wrapNativeSuper(Class) {
-    if (Class === null || !_isNativeFunction(Class)) return Class;
-
-    if (typeof Class !== "function") {
-      throw new TypeError("Super expression must either be null or a function");
-    }
-
-    if (typeof _cache !== "undefined") {
-      if (_cache.has(Class)) return _cache.get(Class);
-
-      _cache.set(Class, Wrapper);
-    }
-
-    function Wrapper() {
-      return _construct(Class, arguments, _getPrototypeOf(this).constructor);
-    }
-
-    Wrapper.prototype = Object.create(Class.prototype, {
-      constructor: {
-        value: Wrapper,
-        enumerable: false,
-        writable: true,
-        configurable: true
-      }
-    });
-    return _setPrototypeOf(Wrapper, Class);
-  };
-
-  return _wrapNativeSuper(Class);
-}
-
-function _assertThisInitialized(self) {
-  if (self === void 0) {
-    throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
-  }
-
-  return self;
-}
-
-/**
- * Graphology Utilities
- * =====================
- *
- * Collection of helpful functions used by the implementation.
- */
-
-/**
- * Object.assign-like polyfill.
- *
- * @param  {object} target       - First object.
- * @param  {object} [...objects] - Objects to merge.
- * @return {object}
- */
-function assignPolyfill() {
-  var target = arguments[0];
-
-  for (var i = 1, l = arguments.length; i < l; i++) {
-    if (!arguments[i]) continue;
-
-    for (var k in arguments[i]) {
-      target[k] = arguments[i][k];
-    }
-  }
-
-  return target;
-}
-
-var assign = assignPolyfill;
-if (typeof Object.assign === 'function') assign = Object.assign;
-/**
- * Function returning the first matching edge for given path.
- * Note: this function does not check the existence of source & target. This
- * must be performed by the caller.
- *
- * @param  {Graph}  graph  - Target graph.
- * @param  {any}    source - Source node.
- * @param  {any}    target - Target node.
- * @param  {string} type   - Type of the edge (mixed, directed or undirected).
- * @return {string|null}
- */
-
-function getMatchingEdge(graph, source, target, type) {
-  var sourceData = graph._nodes.get(source);
-
-  var edge = null;
-  if (!sourceData) return edge;
-
-  if (type === 'mixed') {
-    edge = sourceData.out && sourceData.out[target] || sourceData.undirected && sourceData.undirected[target];
-  } else if (type === 'directed') {
-    edge = sourceData.out && sourceData.out[target];
-  } else {
-    edge = sourceData.undirected && sourceData.undirected[target];
-  }
-
-  return edge;
-}
-/**
- * Checks whether the given value is a Graph implementation instance.
- *
- * @param  {mixed}   value - Target value.
- * @return {boolean}
- */
-
-function isGraph(value) {
-  return value !== null && _typeof(value) === 'object' && typeof value.addUndirectedEdgeWithKey === 'function' && typeof value.dropNode === 'function';
-}
-/**
- * Checks whether the given value is a plain object.
- *
- * @param  {mixed}   value - Target value.
- * @return {boolean}
- */
-
-function isPlainObject(value) {
-  return _typeof(value) === 'object' && value !== null && value.constructor === Object;
-}
-/**
- * Checks whether the given object is empty.
- *
- * @param  {object}  o - Target Object.
- * @return {boolean}
- */
-
-function isEmpty(o) {
-  var k;
-
-  for (k in o) {
-    return false;
-  }
-
-  return true;
-}
-/**
- * Creates a "private" property for the given member name by concealing it
- * using the `enumerable` option.
- *
- * @param {object} target - Target object.
- * @param {string} name   - Member name.
- */
-
-function privateProperty(target, name, value) {
-  Object.defineProperty(target, name, {
-    enumerable: false,
-    configurable: false,
-    writable: true,
-    value: value
-  });
-}
-/**
- * Creates a read-only property for the given member name & the given getter.
- *
- * @param {object}   target - Target object.
- * @param {string}   name   - Member name.
- * @param {mixed}    value  - The attached getter or fixed value.
- */
-
-function readOnlyProperty(target, name, value) {
-  var descriptor = {
-    enumerable: true,
-    configurable: true
-  };
-
-  if (typeof value === 'function') {
-    descriptor.get = value;
-  } else {
-    descriptor.value = value;
-    descriptor.writable = false;
-  }
-
-  Object.defineProperty(target, name, descriptor);
-}
-/**
- * Returns whether the given object constitute valid hints.
- *
- * @param {object} hints - Target object.
- */
-
-function validateHints(hints) {
-  if (!isPlainObject(hints)) return false;
-  if (hints.attributes && !Array.isArray(hints.attributes)) return false;
-  return true;
-}
-/**
- * Creates a function generating incremental ids for edges.
- *
- * @return {function}
- */
-
-function incrementalIdStartingFromRandomByte() {
-  var i = Math.floor(Math.random() * 256) & 0xff;
-  return function () {
-    return i++;
-  };
-}
-
-/**
- * Graphology Custom Errors
- * =========================
- *
- * Defining custom errors for ease of use & easy unit tests across
- * implementations (normalized typology rather than relying on error
- * messages to check whether the correct error was found).
- */
-var GraphError = /*#__PURE__*/function (_Error) {
-  _inheritsLoose(GraphError, _Error);
-
-  function GraphError(message) {
-    var _this;
-
-    _this = _Error.call(this) || this;
-    _this.name = 'GraphError';
-    _this.message = message;
-    return _this;
-  }
-
-  return GraphError;
-}( /*#__PURE__*/_wrapNativeSuper(Error));
-var InvalidArgumentsGraphError = /*#__PURE__*/function (_GraphError) {
-  _inheritsLoose(InvalidArgumentsGraphError, _GraphError);
-
-  function InvalidArgumentsGraphError(message) {
-    var _this2;
-
-    _this2 = _GraphError.call(this, message) || this;
-    _this2.name = 'InvalidArgumentsGraphError'; // This is V8 specific to enhance stack readability
-
-    if (typeof Error.captureStackTrace === 'function') Error.captureStackTrace(_assertThisInitialized(_this2), InvalidArgumentsGraphError.prototype.constructor);
-    return _this2;
-  }
-
-  return InvalidArgumentsGraphError;
-}(GraphError);
-var NotFoundGraphError = /*#__PURE__*/function (_GraphError2) {
-  _inheritsLoose(NotFoundGraphError, _GraphError2);
-
-  function NotFoundGraphError(message) {
-    var _this3;
-
-    _this3 = _GraphError2.call(this, message) || this;
-    _this3.name = 'NotFoundGraphError'; // This is V8 specific to enhance stack readability
-
-    if (typeof Error.captureStackTrace === 'function') Error.captureStackTrace(_assertThisInitialized(_this3), NotFoundGraphError.prototype.constructor);
-    return _this3;
-  }
-
-  return NotFoundGraphError;
-}(GraphError);
-var UsageGraphError = /*#__PURE__*/function (_GraphError3) {
-  _inheritsLoose(UsageGraphError, _GraphError3);
-
-  function UsageGraphError(message) {
-    var _this4;
-
-    _this4 = _GraphError3.call(this, message) || this;
-    _this4.name = 'UsageGraphError'; // This is V8 specific to enhance stack readability
-
-    if (typeof Error.captureStackTrace === 'function') Error.captureStackTrace(_assertThisInitialized(_this4), UsageGraphError.prototype.constructor);
-    return _this4;
-  }
-
-  return UsageGraphError;
-}(GraphError);
-
-/**
- * Graphology Internal Data Classes
- * =================================
- *
- * Internal classes hopefully reduced to structs by engines & storing
- * necessary information for nodes & edges.
- *
- * Note that those classes don't rely on the `class` keyword to avoid some
- * cruft introduced by most of ES2015 transpilers.
- */
-
-/**
- * MixedNodeData class.
- *
- * @constructor
- * @param {string} string     - The node's key.
- * @param {object} attributes - Node's attributes.
- */
-function MixedNodeData(key, attributes) {
-  // Attributes
-  this.key = key;
-  this.attributes = attributes;
-  this.clear();
-}
-
-MixedNodeData.prototype.clear = function () {
-  // Degrees
-  this.inDegree = 0;
-  this.outDegree = 0;
-  this.undirectedDegree = 0; // Indices
-
-  this["in"] = {};
-  this.out = {};
-  this.undirected = {};
-};
-/**
- * DirectedNodeData class.
- *
- * @constructor
- * @param {string} string     - The node's key.
- * @param {object} attributes - Node's attributes.
- */
-
-
-function DirectedNodeData(key, attributes) {
-  // Attributes
-  this.key = key;
-  this.attributes = attributes;
-  this.clear();
-}
-
-DirectedNodeData.prototype.clear = function () {
-  // Degrees
-  this.inDegree = 0;
-  this.outDegree = 0; // Indices
-
-  this["in"] = {};
-  this.out = {};
-};
-/**
- * UndirectedNodeData class.
- *
- * @constructor
- * @param {string} string     - The node's key.
- * @param {object} attributes - Node's attributes.
- */
-
-
-function UndirectedNodeData(key, attributes) {
-  // Attributes
-  this.key = key;
-  this.attributes = attributes;
-  this.clear();
-}
-
-UndirectedNodeData.prototype.clear = function () {
-  // Degrees
-  this.undirectedDegree = 0; // Indices
-
-  this.undirected = {};
-};
-/**
- * EdgeData class.
- *
- * @constructor
- * @param {boolean} undirected   - Whether the edge is undirected.
- * @param {string}  string       - The edge's key.
- * @param {string}  source       - Source of the edge.
- * @param {string}  target       - Target of the edge.
- * @param {object}  attributes   - Edge's attributes.
- */
-
-
-function EdgeData(undirected, key, source, target, attributes) {
-  // Attributes
-  this.key = key;
-  this.attributes = attributes;
-  this.undirected = undirected; // Extremities
-
-  this.source = source;
-  this.target = target;
-}
-
-EdgeData.prototype.attach = function () {
-  var outKey = 'out';
-  var inKey = 'in';
-  if (this.undirected) outKey = inKey = 'undirected';
-  var source = this.source.key;
-  var target = this.target.key; // Handling source
-
-  this.source[outKey][target] = this;
-  if (this.undirected && source === target) return; // Handling target
-
-  this.target[inKey][source] = this;
-};
-
-EdgeData.prototype.attachMulti = function () {
-  var outKey = 'out';
-  var inKey = 'in';
-  var source = this.source.key;
-  var target = this.target.key;
-  if (this.undirected) outKey = inKey = 'undirected'; // Handling source
-
-  var adj = this.source[outKey];
-  var head = adj[target];
-
-  if (typeof head === 'undefined') {
-    adj[target] = this; // Self-loop optimization
-
-    if (!(this.undirected && source === target)) {
-      // Handling target
-      this.target[inKey][source] = this;
-    }
-
-    return;
-  } // Prepending to doubly-linked list
-
-
-  head.previous = this;
-  this.next = head; // Pointing to new head
-  // NOTE: use mutating swap later to avoid lookup?
-
-  adj[target] = this;
-  this.target[inKey][source] = this;
-};
-
-EdgeData.prototype.detach = function () {
-  var source = this.source.key;
-  var target = this.target.key;
-  var outKey = 'out';
-  var inKey = 'in';
-  if (this.undirected) outKey = inKey = 'undirected';
-  delete this.source[outKey][target]; // No-op delete in case of undirected self-loop
-
-  delete this.target[inKey][source];
-};
-
-EdgeData.prototype.detachMulti = function () {
-  var source = this.source.key;
-  var target = this.target.key;
-  var outKey = 'out';
-  var inKey = 'in';
-  if (this.undirected) outKey = inKey = 'undirected'; // Deleting from doubly-linked list
-
-  if (this.previous === undefined) {
-    // We are dealing with the head
-    // Should we delete the adjacency entry because it is now empty?
-    if (this.next === undefined) {
-      delete this.source[outKey][target]; // No-op delete in case of undirected self-loop
-
-      delete this.target[inKey][source];
-    } else {
-      // Detaching
-      this.next.previous = undefined; // NOTE: could avoid the lookups by creating a #.become mutating method
-
-      this.source[outKey][target] = this.next; // No-op delete in case of undirected self-loop
-
-      this.target[inKey][source] = this.next;
-    }
-  } else {
-    // We are dealing with another list node
-    this.previous.next = this.next; // If not last
-
-    if (this.next !== undefined) {
-      this.next.previous = this.previous;
-    }
-  }
-};
-
-/**
- * Graphology Node Attributes methods
- * ===================================
- */
-var NODE = 0;
-var SOURCE = 1;
-var TARGET = 2;
-var OPPOSITE = 3;
-
-function findRelevantNodeData(graph, method, mode, nodeOrEdge, nameOrEdge, add1, add2) {
-  var nodeData, edgeData, arg1, arg2;
-  nodeOrEdge = '' + nodeOrEdge;
-
-  if (mode === NODE) {
-    nodeData = graph._nodes.get(nodeOrEdge);
-    if (!nodeData) throw new NotFoundGraphError("Graph.".concat(method, ": could not find the \"").concat(nodeOrEdge, "\" node in the graph."));
-    arg1 = nameOrEdge;
-    arg2 = add1;
-  } else if (mode === OPPOSITE) {
-    nameOrEdge = '' + nameOrEdge;
-    edgeData = graph._edges.get(nameOrEdge);
-    if (!edgeData) throw new NotFoundGraphError("Graph.".concat(method, ": could not find the \"").concat(nameOrEdge, "\" edge in the graph."));
-    var source = edgeData.source.key;
-    var target = edgeData.target.key;
-
-    if (nodeOrEdge === source) {
-      nodeData = edgeData.target;
-    } else if (nodeOrEdge === target) {
-      nodeData = edgeData.source;
-    } else {
-      throw new NotFoundGraphError("Graph.".concat(method, ": the \"").concat(nodeOrEdge, "\" node is not attached to the \"").concat(nameOrEdge, "\" edge (").concat(source, ", ").concat(target, ")."));
-    }
-
-    arg1 = add1;
-    arg2 = add2;
-  } else {
-    edgeData = graph._edges.get(nodeOrEdge);
-    if (!edgeData) throw new NotFoundGraphError("Graph.".concat(method, ": could not find the \"").concat(nodeOrEdge, "\" edge in the graph."));
-
-    if (mode === SOURCE) {
-      nodeData = edgeData.source;
-    } else {
-      nodeData = edgeData.target;
-    }
-
-    arg1 = nameOrEdge;
-    arg2 = add1;
-  }
-
-  return [nodeData, arg1, arg2];
-}
-
-function attachNodeAttributeGetter(Class, method, mode) {
-  Class.prototype[method] = function (nodeOrEdge, nameOrEdge, add1) {
-    var _findRelevantNodeData = findRelevantNodeData(this, method, mode, nodeOrEdge, nameOrEdge, add1),
-        data = _findRelevantNodeData[0],
-        name = _findRelevantNodeData[1];
-
-    return data.attributes[name];
-  };
-}
-
-function attachNodeAttributesGetter(Class, method, mode) {
-  Class.prototype[method] = function (nodeOrEdge, nameOrEdge) {
-    var _findRelevantNodeData2 = findRelevantNodeData(this, method, mode, nodeOrEdge, nameOrEdge),
-        data = _findRelevantNodeData2[0];
-
-    return data.attributes;
-  };
-}
-
-function attachNodeAttributeChecker(Class, method, mode) {
-  Class.prototype[method] = function (nodeOrEdge, nameOrEdge, add1) {
-    var _findRelevantNodeData3 = findRelevantNodeData(this, method, mode, nodeOrEdge, nameOrEdge, add1),
-        data = _findRelevantNodeData3[0],
-        name = _findRelevantNodeData3[1];
-
-    return data.attributes.hasOwnProperty(name);
-  };
-}
-
-function attachNodeAttributeSetter(Class, method, mode) {
-  Class.prototype[method] = function (nodeOrEdge, nameOrEdge, add1, add2) {
-    var _findRelevantNodeData4 = findRelevantNodeData(this, method, mode, nodeOrEdge, nameOrEdge, add1, add2),
-        data = _findRelevantNodeData4[0],
-        name = _findRelevantNodeData4[1],
-        value = _findRelevantNodeData4[2];
-
-    data.attributes[name] = value; // Emitting
-
-    this.emit('nodeAttributesUpdated', {
-      key: data.key,
-      type: 'set',
-      attributes: data.attributes,
-      name: name
-    });
-    return this;
-  };
-}
-
-function attachNodeAttributeUpdater(Class, method, mode) {
-  Class.prototype[method] = function (nodeOrEdge, nameOrEdge, add1, add2) {
-    var _findRelevantNodeData5 = findRelevantNodeData(this, method, mode, nodeOrEdge, nameOrEdge, add1, add2),
-        data = _findRelevantNodeData5[0],
-        name = _findRelevantNodeData5[1],
-        updater = _findRelevantNodeData5[2];
-
-    if (typeof updater !== 'function') throw new InvalidArgumentsGraphError("Graph.".concat(method, ": updater should be a function."));
-    var attributes = data.attributes;
-    var value = updater(attributes[name]);
-    attributes[name] = value; // Emitting
-
-    this.emit('nodeAttributesUpdated', {
-      key: data.key,
-      type: 'set',
-      attributes: data.attributes,
-      name: name
-    });
-    return this;
-  };
-}
-
-function attachNodeAttributeRemover(Class, method, mode) {
-  Class.prototype[method] = function (nodeOrEdge, nameOrEdge, add1) {
-    var _findRelevantNodeData6 = findRelevantNodeData(this, method, mode, nodeOrEdge, nameOrEdge, add1),
-        data = _findRelevantNodeData6[0],
-        name = _findRelevantNodeData6[1];
-
-    delete data.attributes[name]; // Emitting
-
-    this.emit('nodeAttributesUpdated', {
-      key: data.key,
-      type: 'remove',
-      attributes: data.attributes,
-      name: name
-    });
-    return this;
-  };
-}
-
-function attachNodeAttributesReplacer(Class, method, mode) {
-  Class.prototype[method] = function (nodeOrEdge, nameOrEdge, add1) {
-    var _findRelevantNodeData7 = findRelevantNodeData(this, method, mode, nodeOrEdge, nameOrEdge, add1),
-        data = _findRelevantNodeData7[0],
-        attributes = _findRelevantNodeData7[1];
-
-    if (!isPlainObject(attributes)) throw new InvalidArgumentsGraphError("Graph.".concat(method, ": provided attributes are not a plain object."));
-    data.attributes = attributes; // Emitting
-
-    this.emit('nodeAttributesUpdated', {
-      key: data.key,
-      type: 'replace',
-      attributes: data.attributes
-    });
-    return this;
-  };
-}
-
-function attachNodeAttributesMerger(Class, method, mode) {
-  Class.prototype[method] = function (nodeOrEdge, nameOrEdge, add1) {
-    var _findRelevantNodeData8 = findRelevantNodeData(this, method, mode, nodeOrEdge, nameOrEdge, add1),
-        data = _findRelevantNodeData8[0],
-        attributes = _findRelevantNodeData8[1];
-
-    if (!isPlainObject(attributes)) throw new InvalidArgumentsGraphError("Graph.".concat(method, ": provided attributes are not a plain object."));
-    assign(data.attributes, attributes); // Emitting
-
-    this.emit('nodeAttributesUpdated', {
-      key: data.key,
-      type: 'merge',
-      attributes: data.attributes,
-      data: attributes
-    });
-    return this;
-  };
-}
-
-function attachNodeAttributesUpdater(Class, method, mode) {
-  Class.prototype[method] = function (nodeOrEdge, nameOrEdge, add1) {
-    var _findRelevantNodeData9 = findRelevantNodeData(this, method, mode, nodeOrEdge, nameOrEdge, add1),
-        data = _findRelevantNodeData9[0],
-        updater = _findRelevantNodeData9[1];
-
-    if (typeof updater !== 'function') throw new InvalidArgumentsGraphError("Graph.".concat(method, ": provided updater is not a function."));
-    data.attributes = updater(data.attributes); // Emitting
-
-    this.emit('nodeAttributesUpdated', {
-      key: data.key,
-      type: 'update',
-      attributes: data.attributes
-    });
-    return this;
-  };
-}
-/**
- * List of methods to attach.
- */
-
-
-var NODE_ATTRIBUTES_METHODS = [{
-  name: function name(element) {
-    return "get".concat(element, "Attribute");
-  },
-  attacher: attachNodeAttributeGetter
-}, {
-  name: function name(element) {
-    return "get".concat(element, "Attributes");
-  },
-  attacher: attachNodeAttributesGetter
-}, {
-  name: function name(element) {
-    return "has".concat(element, "Attribute");
-  },
-  attacher: attachNodeAttributeChecker
-}, {
-  name: function name(element) {
-    return "set".concat(element, "Attribute");
-  },
-  attacher: attachNodeAttributeSetter
-}, {
-  name: function name(element) {
-    return "update".concat(element, "Attribute");
-  },
-  attacher: attachNodeAttributeUpdater
-}, {
-  name: function name(element) {
-    return "remove".concat(element, "Attribute");
-  },
-  attacher: attachNodeAttributeRemover
-}, {
-  name: function name(element) {
-    return "replace".concat(element, "Attributes");
-  },
-  attacher: attachNodeAttributesReplacer
-}, {
-  name: function name(element) {
-    return "merge".concat(element, "Attributes");
-  },
-  attacher: attachNodeAttributesMerger
-}, {
-  name: function name(element) {
-    return "update".concat(element, "Attributes");
-  },
-  attacher: attachNodeAttributesUpdater
-}];
-/**
- * Attach every attributes-related methods to a Graph class.
- *
- * @param {function} Graph - Target class.
- */
-
-function attachNodeAttributesMethods(Graph) {
-  NODE_ATTRIBUTES_METHODS.forEach(function (_ref) {
-    var name = _ref.name,
-        attacher = _ref.attacher;
-    // For nodes
-    attacher(Graph, name('Node'), NODE); // For sources
-
-    attacher(Graph, name('Source'), SOURCE); // For targets
-
-    attacher(Graph, name('Target'), TARGET); // For opposites
-
-    attacher(Graph, name('Opposite'), OPPOSITE);
-  });
-}
-
-/**
- * Graphology Edge Attributes methods
- * ===================================
- */
-/**
- * Attach an attribute getter method onto the provided class.
- *
- * @param {function} Class         - Target class.
- * @param {string}   method        - Method name.
- * @param {string}   type          - Type of the edge to find.
- */
-
-function attachEdgeAttributeGetter(Class, method, type) {
-  /**
-   * Get the desired attribute for the given element (node or edge).
-   *
-   * Arity 2:
-   * @param  {any}    element - Target element.
-   * @param  {string} name    - Attribute's name.
-   *
-   * Arity 3 (only for edges):
-   * @param  {any}     source - Source element.
-   * @param  {any}     target - Target element.
-   * @param  {string}  name   - Attribute's name.
-   *
-   * @return {mixed}          - The attribute's value.
-   *
-   * @throws {Error} - Will throw if too many arguments are provided.
-   * @throws {Error} - Will throw if any of the elements is not found.
-   */
-  Class.prototype[method] = function (element, name) {
-    var data;
-    if (this.type !== 'mixed' && type !== 'mixed' && type !== this.type) throw new UsageGraphError("Graph.".concat(method, ": cannot find this type of edges in your ").concat(this.type, " graph."));
-
-    if (arguments.length > 2) {
-      if (this.multi) throw new UsageGraphError("Graph.".concat(method, ": cannot use a {source,target} combo when asking about an edge's attributes in a MultiGraph since we cannot infer the one you want information about."));
-      var source = '' + element;
-      var target = '' + name;
-      name = arguments[2];
-      data = getMatchingEdge(this, source, target, type);
-      if (!data) throw new NotFoundGraphError("Graph.".concat(method, ": could not find an edge for the given path (\"").concat(source, "\" - \"").concat(target, "\")."));
-    } else {
-      if (type !== 'mixed') throw new UsageGraphError("Graph.".concat(method, ": calling this method with only a key (vs. a source and target) does not make sense since an edge with this key could have the other type."));
-      element = '' + element;
-      data = this._edges.get(element);
-      if (!data) throw new NotFoundGraphError("Graph.".concat(method, ": could not find the \"").concat(element, "\" edge in the graph."));
-    }
-
-    return data.attributes[name];
-  };
-}
-/**
- * Attach an attributes getter method onto the provided class.
- *
- * @param {function} Class       - Target class.
- * @param {string}   method      - Method name.
- * @param {string}   type        - Type of the edge to find.
- */
-
-
-function attachEdgeAttributesGetter(Class, method, type) {
-  /**
-   * Retrieves all the target element's attributes.
-   *
-   * Arity 2:
-   * @param  {any}    element - Target element.
-   *
-   * Arity 3 (only for edges):
-   * @param  {any}     source - Source element.
-   * @param  {any}     target - Target element.
-   *
-   * @return {object}          - The element's attributes.
-   *
-   * @throws {Error} - Will throw if too many arguments are provided.
-   * @throws {Error} - Will throw if any of the elements is not found.
-   */
-  Class.prototype[method] = function (element) {
-    var data;
-    if (this.type !== 'mixed' && type !== 'mixed' && type !== this.type) throw new UsageGraphError("Graph.".concat(method, ": cannot find this type of edges in your ").concat(this.type, " graph."));
-
-    if (arguments.length > 1) {
-      if (this.multi) throw new UsageGraphError("Graph.".concat(method, ": cannot use a {source,target} combo when asking about an edge's attributes in a MultiGraph since we cannot infer the one you want information about."));
-      var source = '' + element,
-          target = '' + arguments[1];
-      data = getMatchingEdge(this, source, target, type);
-      if (!data) throw new NotFoundGraphError("Graph.".concat(method, ": could not find an edge for the given path (\"").concat(source, "\" - \"").concat(target, "\")."));
-    } else {
-      if (type !== 'mixed') throw new UsageGraphError("Graph.".concat(method, ": calling this method with only a key (vs. a source and target) does not make sense since an edge with this key could have the other type."));
-      element = '' + element;
-      data = this._edges.get(element);
-      if (!data) throw new NotFoundGraphError("Graph.".concat(method, ": could not find the \"").concat(element, "\" edge in the graph."));
-    }
-
-    return data.attributes;
-  };
-}
-/**
- * Attach an attribute checker method onto the provided class.
- *
- * @param {function} Class       - Target class.
- * @param {string}   method      - Method name.
- * @param {string}   type        - Type of the edge to find.
- */
-
-
-function attachEdgeAttributeChecker(Class, method, type) {
-  /**
-   * Checks whether the desired attribute is set for the given element (node or edge).
-   *
-   * Arity 2:
-   * @param  {any}    element - Target element.
-   * @param  {string} name    - Attribute's name.
-   *
-   * Arity 3 (only for edges):
-   * @param  {any}     source - Source element.
-   * @param  {any}     target - Target element.
-   * @param  {string}  name   - Attribute's name.
-   *
-   * @return {boolean}
-   *
-   * @throws {Error} - Will throw if too many arguments are provided.
-   * @throws {Error} - Will throw if any of the elements is not found.
-   */
-  Class.prototype[method] = function (element, name) {
-    var data;
-    if (this.type !== 'mixed' && type !== 'mixed' && type !== this.type) throw new UsageGraphError("Graph.".concat(method, ": cannot find this type of edges in your ").concat(this.type, " graph."));
-
-    if (arguments.length > 2) {
-      if (this.multi) throw new UsageGraphError("Graph.".concat(method, ": cannot use a {source,target} combo when asking about an edge's attributes in a MultiGraph since we cannot infer the one you want information about."));
-      var source = '' + element;
-      var target = '' + name;
-      name = arguments[2];
-      data = getMatchingEdge(this, source, target, type);
-      if (!data) throw new NotFoundGraphError("Graph.".concat(method, ": could not find an edge for the given path (\"").concat(source, "\" - \"").concat(target, "\")."));
-    } else {
-      if (type !== 'mixed') throw new UsageGraphError("Graph.".concat(method, ": calling this method with only a key (vs. a source and target) does not make sense since an edge with this key could have the other type."));
-      element = '' + element;
-      data = this._edges.get(element);
-      if (!data) throw new NotFoundGraphError("Graph.".concat(method, ": could not find the \"").concat(element, "\" edge in the graph."));
-    }
-
-    return data.attributes.hasOwnProperty(name);
-  };
-}
-/**
- * Attach an attribute setter method onto the provided class.
- *
- * @param {function} Class         - Target class.
- * @param {string}   method        - Method name.
- * @param {string}   type          - Type of the edge to find.
- */
-
-
-function attachEdgeAttributeSetter(Class, method, type) {
-  /**
-   * Set the desired attribute for the given element (node or edge).
-   *
-   * Arity 2:
-   * @param  {any}    element - Target element.
-   * @param  {string} name    - Attribute's name.
-   * @param  {mixed}  value   - New attribute value.
-   *
-   * Arity 3 (only for edges):
-   * @param  {any}     source - Source element.
-   * @param  {any}     target - Target element.
-   * @param  {string}  name   - Attribute's name.
-   * @param  {mixed}  value   - New attribute value.
-   *
-   * @return {Graph}          - Returns itself for chaining.
-   *
-   * @throws {Error} - Will throw if too many arguments are provided.
-   * @throws {Error} - Will throw if any of the elements is not found.
-   */
-  Class.prototype[method] = function (element, name, value) {
-    var data;
-    if (this.type !== 'mixed' && type !== 'mixed' && type !== this.type) throw new UsageGraphError("Graph.".concat(method, ": cannot find this type of edges in your ").concat(this.type, " graph."));
-
-    if (arguments.length > 3) {
-      if (this.multi) throw new UsageGraphError("Graph.".concat(method, ": cannot use a {source,target} combo when asking about an edge's attributes in a MultiGraph since we cannot infer the one you want information about."));
-      var source = '' + element;
-      var target = '' + name;
-      name = arguments[2];
-      value = arguments[3];
-      data = getMatchingEdge(this, source, target, type);
-      if (!data) throw new NotFoundGraphError("Graph.".concat(method, ": could not find an edge for the given path (\"").concat(source, "\" - \"").concat(target, "\")."));
-    } else {
-      if (type !== 'mixed') throw new UsageGraphError("Graph.".concat(method, ": calling this method with only a key (vs. a source and target) does not make sense since an edge with this key could have the other type."));
-      element = '' + element;
-      data = this._edges.get(element);
-      if (!data) throw new NotFoundGraphError("Graph.".concat(method, ": could not find the \"").concat(element, "\" edge in the graph."));
-    }
-
-    data.attributes[name] = value; // Emitting
-
-    this.emit('edgeAttributesUpdated', {
-      key: data.key,
-      type: 'set',
-      attributes: data.attributes,
-      name: name
-    });
-    return this;
-  };
-}
-/**
- * Attach an attribute updater method onto the provided class.
- *
- * @param {function} Class         - Target class.
- * @param {string}   method        - Method name.
- * @param {string}   type          - Type of the edge to find.
- */
-
-
-function attachEdgeAttributeUpdater(Class, method, type) {
-  /**
-   * Update the desired attribute for the given element (node or edge) using
-   * the provided function.
-   *
-   * Arity 2:
-   * @param  {any}      element - Target element.
-   * @param  {string}   name    - Attribute's name.
-   * @param  {function} updater - Updater function.
-   *
-   * Arity 3 (only for edges):
-   * @param  {any}      source  - Source element.
-   * @param  {any}      target  - Target element.
-   * @param  {string}   name    - Attribute's name.
-   * @param  {function} updater - Updater function.
-   *
-   * @return {Graph}            - Returns itself for chaining.
-   *
-   * @throws {Error} - Will throw if too many arguments are provided.
-   * @throws {Error} - Will throw if any of the elements is not found.
-   */
-  Class.prototype[method] = function (element, name, updater) {
-    var data;
-    if (this.type !== 'mixed' && type !== 'mixed' && type !== this.type) throw new UsageGraphError("Graph.".concat(method, ": cannot find this type of edges in your ").concat(this.type, " graph."));
-
-    if (arguments.length > 3) {
-      if (this.multi) throw new UsageGraphError("Graph.".concat(method, ": cannot use a {source,target} combo when asking about an edge's attributes in a MultiGraph since we cannot infer the one you want information about."));
-      var source = '' + element;
-      var target = '' + name;
-      name = arguments[2];
-      updater = arguments[3];
-      data = getMatchingEdge(this, source, target, type);
-      if (!data) throw new NotFoundGraphError("Graph.".concat(method, ": could not find an edge for the given path (\"").concat(source, "\" - \"").concat(target, "\")."));
-    } else {
-      if (type !== 'mixed') throw new UsageGraphError("Graph.".concat(method, ": calling this method with only a key (vs. a source and target) does not make sense since an edge with this key could have the other type."));
-      element = '' + element;
-      data = this._edges.get(element);
-      if (!data) throw new NotFoundGraphError("Graph.".concat(method, ": could not find the \"").concat(element, "\" edge in the graph."));
-    }
-
-    if (typeof updater !== 'function') throw new InvalidArgumentsGraphError("Graph.".concat(method, ": updater should be a function."));
-    data.attributes[name] = updater(data.attributes[name]); // Emitting
-
-    this.emit('edgeAttributesUpdated', {
-      key: data.key,
-      type: 'set',
-      attributes: data.attributes,
-      name: name
-    });
-    return this;
-  };
-}
-/**
- * Attach an attribute remover method onto the provided class.
- *
- * @param {function} Class         - Target class.
- * @param {string}   method        - Method name.
- * @param {string}   type          - Type of the edge to find.
- */
-
-
-function attachEdgeAttributeRemover(Class, method, type) {
-  /**
-   * Remove the desired attribute for the given element (node or edge).
-   *
-   * Arity 2:
-   * @param  {any}    element - Target element.
-   * @param  {string} name    - Attribute's name.
-   *
-   * Arity 3 (only for edges):
-   * @param  {any}     source - Source element.
-   * @param  {any}     target - Target element.
-   * @param  {string}  name   - Attribute's name.
-   *
-   * @return {Graph}          - Returns itself for chaining.
-   *
-   * @throws {Error} - Will throw if too many arguments are provided.
-   * @throws {Error} - Will throw if any of the elements is not found.
-   */
-  Class.prototype[method] = function (element, name) {
-    var data;
-    if (this.type !== 'mixed' && type !== 'mixed' && type !== this.type) throw new UsageGraphError("Graph.".concat(method, ": cannot find this type of edges in your ").concat(this.type, " graph."));
-
-    if (arguments.length > 2) {
-      if (this.multi) throw new UsageGraphError("Graph.".concat(method, ": cannot use a {source,target} combo when asking about an edge's attributes in a MultiGraph since we cannot infer the one you want information about."));
-      var source = '' + element;
-      var target = '' + name;
-      name = arguments[2];
-      data = getMatchingEdge(this, source, target, type);
-      if (!data) throw new NotFoundGraphError("Graph.".concat(method, ": could not find an edge for the given path (\"").concat(source, "\" - \"").concat(target, "\")."));
-    } else {
-      if (type !== 'mixed') throw new UsageGraphError("Graph.".concat(method, ": calling this method with only a key (vs. a source and target) does not make sense since an edge with this key could have the other type."));
-      element = '' + element;
-      data = this._edges.get(element);
-      if (!data) throw new NotFoundGraphError("Graph.".concat(method, ": could not find the \"").concat(element, "\" edge in the graph."));
-    }
-
-    delete data.attributes[name]; // Emitting
-
-    this.emit('edgeAttributesUpdated', {
-      key: data.key,
-      type: 'remove',
-      attributes: data.attributes,
-      name: name
-    });
-    return this;
-  };
-}
-/**
- * Attach an attribute replacer method onto the provided class.
- *
- * @param {function} Class         - Target class.
- * @param {string}   method        - Method name.
- * @param {string}   type          - Type of the edge to find.
- */
-
-
-function attachEdgeAttributesReplacer(Class, method, type) {
-  /**
-   * Replace the attributes for the given element (node or edge).
-   *
-   * Arity 2:
-   * @param  {any}    element    - Target element.
-   * @param  {object} attributes - New attributes.
-   *
-   * Arity 3 (only for edges):
-   * @param  {any}     source     - Source element.
-   * @param  {any}     target     - Target element.
-   * @param  {object}  attributes - New attributes.
-   *
-   * @return {Graph}              - Returns itself for chaining.
-   *
-   * @throws {Error} - Will throw if too many arguments are provided.
-   * @throws {Error} - Will throw if any of the elements is not found.
-   */
-  Class.prototype[method] = function (element, attributes) {
-    var data;
-    if (this.type !== 'mixed' && type !== 'mixed' && type !== this.type) throw new UsageGraphError("Graph.".concat(method, ": cannot find this type of edges in your ").concat(this.type, " graph."));
-
-    if (arguments.length > 2) {
-      if (this.multi) throw new UsageGraphError("Graph.".concat(method, ": cannot use a {source,target} combo when asking about an edge's attributes in a MultiGraph since we cannot infer the one you want information about."));
-      var source = '' + element,
-          target = '' + attributes;
-      attributes = arguments[2];
-      data = getMatchingEdge(this, source, target, type);
-      if (!data) throw new NotFoundGraphError("Graph.".concat(method, ": could not find an edge for the given path (\"").concat(source, "\" - \"").concat(target, "\")."));
-    } else {
-      if (type !== 'mixed') throw new UsageGraphError("Graph.".concat(method, ": calling this method with only a key (vs. a source and target) does not make sense since an edge with this key could have the other type."));
-      element = '' + element;
-      data = this._edges.get(element);
-      if (!data) throw new NotFoundGraphError("Graph.".concat(method, ": could not find the \"").concat(element, "\" edge in the graph."));
-    }
-
-    if (!isPlainObject(attributes)) throw new InvalidArgumentsGraphError("Graph.".concat(method, ": provided attributes are not a plain object."));
-    data.attributes = attributes; // Emitting
-
-    this.emit('edgeAttributesUpdated', {
-      key: data.key,
-      type: 'replace',
-      attributes: data.attributes
-    });
-    return this;
-  };
-}
-/**
- * Attach an attribute merger method onto the provided class.
- *
- * @param {function} Class         - Target class.
- * @param {string}   method        - Method name.
- * @param {string}   type          - Type of the edge to find.
- */
-
-
-function attachEdgeAttributesMerger(Class, method, type) {
-  /**
-   * Merge the attributes for the given element (node or edge).
-   *
-   * Arity 2:
-   * @param  {any}    element    - Target element.
-   * @param  {object} attributes - Attributes to merge.
-   *
-   * Arity 3 (only for edges):
-   * @param  {any}     source     - Source element.
-   * @param  {any}     target     - Target element.
-   * @param  {object}  attributes - Attributes to merge.
-   *
-   * @return {Graph}              - Returns itself for chaining.
-   *
-   * @throws {Error} - Will throw if too many arguments are provided.
-   * @throws {Error} - Will throw if any of the elements is not found.
-   */
-  Class.prototype[method] = function (element, attributes) {
-    var data;
-    if (this.type !== 'mixed' && type !== 'mixed' && type !== this.type) throw new UsageGraphError("Graph.".concat(method, ": cannot find this type of edges in your ").concat(this.type, " graph."));
-
-    if (arguments.length > 2) {
-      if (this.multi) throw new UsageGraphError("Graph.".concat(method, ": cannot use a {source,target} combo when asking about an edge's attributes in a MultiGraph since we cannot infer the one you want information about."));
-      var source = '' + element,
-          target = '' + attributes;
-      attributes = arguments[2];
-      data = getMatchingEdge(this, source, target, type);
-      if (!data) throw new NotFoundGraphError("Graph.".concat(method, ": could not find an edge for the given path (\"").concat(source, "\" - \"").concat(target, "\")."));
-    } else {
-      if (type !== 'mixed') throw new UsageGraphError("Graph.".concat(method, ": calling this method with only a key (vs. a source and target) does not make sense since an edge with this key could have the other type."));
-      element = '' + element;
-      data = this._edges.get(element);
-      if (!data) throw new NotFoundGraphError("Graph.".concat(method, ": could not find the \"").concat(element, "\" edge in the graph."));
-    }
-
-    if (!isPlainObject(attributes)) throw new InvalidArgumentsGraphError("Graph.".concat(method, ": provided attributes are not a plain object."));
-    assign(data.attributes, attributes); // Emitting
-
-    this.emit('edgeAttributesUpdated', {
-      key: data.key,
-      type: 'merge',
-      attributes: data.attributes,
-      data: attributes
-    });
-    return this;
-  };
-}
-/**
- * Attach an attribute updater method onto the provided class.
- *
- * @param {function} Class         - Target class.
- * @param {string}   method        - Method name.
- * @param {string}   type          - Type of the edge to find.
- */
-
-
-function attachEdgeAttributesUpdater(Class, method, type) {
-  /**
-   * Update the attributes of the given element (node or edge).
-   *
-   * Arity 2:
-   * @param  {any}      element - Target element.
-   * @param  {function} updater - Updater function.
-   *
-   * Arity 3 (only for edges):
-   * @param  {any}      source  - Source element.
-   * @param  {any}      target  - Target element.
-   * @param  {function} updater - Updater function.
-   *
-   * @return {Graph}            - Returns itself for chaining.
-   *
-   * @throws {Error} - Will throw if too many arguments are provided.
-   * @throws {Error} - Will throw if any of the elements is not found.
-   */
-  Class.prototype[method] = function (element, updater) {
-    var data;
-    if (this.type !== 'mixed' && type !== 'mixed' && type !== this.type) throw new UsageGraphError("Graph.".concat(method, ": cannot find this type of edges in your ").concat(this.type, " graph."));
-
-    if (arguments.length > 2) {
-      if (this.multi) throw new UsageGraphError("Graph.".concat(method, ": cannot use a {source,target} combo when asking about an edge's attributes in a MultiGraph since we cannot infer the one you want information about."));
-      var source = '' + element,
-          target = '' + updater;
-      updater = arguments[2];
-      data = getMatchingEdge(this, source, target, type);
-      if (!data) throw new NotFoundGraphError("Graph.".concat(method, ": could not find an edge for the given path (\"").concat(source, "\" - \"").concat(target, "\")."));
-    } else {
-      if (type !== 'mixed') throw new UsageGraphError("Graph.".concat(method, ": calling this method with only a key (vs. a source and target) does not make sense since an edge with this key could have the other type."));
-      element = '' + element;
-      data = this._edges.get(element);
-      if (!data) throw new NotFoundGraphError("Graph.".concat(method, ": could not find the \"").concat(element, "\" edge in the graph."));
-    }
-
-    if (typeof updater !== 'function') throw new InvalidArgumentsGraphError("Graph.".concat(method, ": provided updater is not a function."));
-    data.attributes = updater(data.attributes); // Emitting
-
-    this.emit('edgeAttributesUpdated', {
-      key: data.key,
-      type: 'update',
-      attributes: data.attributes
-    });
-    return this;
-  };
-}
-/**
- * List of methods to attach.
- */
-
-
-var EDGE_ATTRIBUTES_METHODS = [{
-  name: function name(element) {
-    return "get".concat(element, "Attribute");
-  },
-  attacher: attachEdgeAttributeGetter
-}, {
-  name: function name(element) {
-    return "get".concat(element, "Attributes");
-  },
-  attacher: attachEdgeAttributesGetter
-}, {
-  name: function name(element) {
-    return "has".concat(element, "Attribute");
-  },
-  attacher: attachEdgeAttributeChecker
-}, {
-  name: function name(element) {
-    return "set".concat(element, "Attribute");
-  },
-  attacher: attachEdgeAttributeSetter
-}, {
-  name: function name(element) {
-    return "update".concat(element, "Attribute");
-  },
-  attacher: attachEdgeAttributeUpdater
-}, {
-  name: function name(element) {
-    return "remove".concat(element, "Attribute");
-  },
-  attacher: attachEdgeAttributeRemover
-}, {
-  name: function name(element) {
-    return "replace".concat(element, "Attributes");
-  },
-  attacher: attachEdgeAttributesReplacer
-}, {
-  name: function name(element) {
-    return "merge".concat(element, "Attributes");
-  },
-  attacher: attachEdgeAttributesMerger
-}, {
-  name: function name(element) {
-    return "update".concat(element, "Attributes");
-  },
-  attacher: attachEdgeAttributesUpdater
-}];
-/**
- * Attach every attributes-related methods to a Graph class.
- *
- * @param {function} Graph - Target class.
- */
-
-function attachEdgeAttributesMethods(Graph) {
-  EDGE_ATTRIBUTES_METHODS.forEach(function (_ref) {
-    var name = _ref.name,
-        attacher = _ref.attacher;
-    // For edges
-    attacher(Graph, name('Edge'), 'mixed'); // For directed edges
-
-    attacher(Graph, name('DirectedEdge'), 'directed'); // For undirected edges
-
-    attacher(Graph, name('UndirectedEdge'), 'undirected');
-  });
-}
-
-/**
- * Graphology Edge Iteration
- * ==========================
- *
- * Attaching some methods to the Graph class to be able to iterate over a
- * graph's edges.
- */
-/**
- * Definitions.
- */
-
-var EDGES_ITERATION = [{
-  name: 'edges',
-  type: 'mixed'
-}, {
-  name: 'inEdges',
-  type: 'directed',
-  direction: 'in'
-}, {
-  name: 'outEdges',
-  type: 'directed',
-  direction: 'out'
-}, {
-  name: 'inboundEdges',
-  type: 'mixed',
-  direction: 'in'
-}, {
-  name: 'outboundEdges',
-  type: 'mixed',
-  direction: 'out'
-}, {
-  name: 'directedEdges',
-  type: 'directed'
-}, {
-  name: 'undirectedEdges',
-  type: 'undirected'
-}];
-/**
- * Function iterating over edges from the given object to match one of them.
- *
- * @param {object}   object   - Target object.
- * @param {function} callback - Function to call.
- */
-
-function forEachSimple(breakable, object, callback, avoid) {
-  var shouldBreak = false;
-
-  for (var k in object) {
-    if (k === avoid) continue;
-    var edgeData = object[k];
-    shouldBreak = callback(edgeData.key, edgeData.attributes, edgeData.source.key, edgeData.target.key, edgeData.source.attributes, edgeData.target.attributes, edgeData.undirected);
-    if (breakable && shouldBreak) return edgeData.key;
-  }
-
-  return;
-}
-
-function forEachMulti(breakable, object, callback, avoid) {
-  var edgeData, source, target;
-  var shouldBreak = false;
-
-  for (var k in object) {
-    if (k === avoid) continue;
-    edgeData = object[k];
-
-    do {
-      source = edgeData.source;
-      target = edgeData.target;
-      shouldBreak = callback(edgeData.key, edgeData.attributes, source.key, target.key, source.attributes, target.attributes, edgeData.undirected);
-      if (breakable && shouldBreak) return edgeData.key;
-      edgeData = edgeData.next;
-    } while (edgeData !== undefined);
-  }
-
-  return;
-}
-/**
- * Function returning an iterator over edges from the given object.
- *
- * @param  {object}   object - Target object.
- * @return {Iterator}
- */
-
-
-function createIterator(object, avoid) {
-  var keys = Object.keys(object);
-  var l = keys.length;
-  var edgeData;
-  var i = 0;
-  return new Iterator__default["default"](function next() {
-    do {
-      if (!edgeData) {
-        if (i >= l) return {
-          done: true
-        };
-        var k = keys[i++];
-
-        if (k === avoid) {
-          edgeData = undefined;
-          continue;
-        }
-
-        edgeData = object[k];
-      } else {
-        edgeData = edgeData.next;
-      }
-    } while (!edgeData);
-
-    return {
-      done: false,
-      value: {
-        edge: edgeData.key,
-        attributes: edgeData.attributes,
-        source: edgeData.source.key,
-        target: edgeData.target.key,
-        sourceAttributes: edgeData.source.attributes,
-        targetAttributes: edgeData.target.attributes,
-        undirected: edgeData.undirected
-      }
-    };
-  });
-}
-/**
- * Function iterating over the egdes from the object at given key to match
- * one of them.
- *
- * @param {object}   object   - Target object.
- * @param {mixed}    k        - Neighbor key.
- * @param {function} callback - Callback to use.
- */
-
-
-function forEachForKeySimple(breakable, object, k, callback) {
-  var edgeData = object[k];
-  if (!edgeData) return;
-  var sourceData = edgeData.source;
-  var targetData = edgeData.target;
-  if (callback(edgeData.key, edgeData.attributes, sourceData.key, targetData.key, sourceData.attributes, targetData.attributes, edgeData.undirected) && breakable) return edgeData.key;
-}
-
-function forEachForKeyMulti(breakable, object, k, callback) {
-  var edgeData = object[k];
-  if (!edgeData) return;
-  var shouldBreak = false;
-
-  do {
-    shouldBreak = callback(edgeData.key, edgeData.attributes, edgeData.source.key, edgeData.target.key, edgeData.source.attributes, edgeData.target.attributes, edgeData.undirected);
-    if (breakable && shouldBreak) return edgeData.key;
-    edgeData = edgeData.next;
-  } while (edgeData !== undefined);
-
-  return;
-}
-/**
- * Function returning an iterator over the egdes from the object at given key.
- *
- * @param  {object}   object   - Target object.
- * @param  {mixed}    k        - Neighbor key.
- * @return {Iterator}
- */
-
-
-function createIteratorForKey(object, k) {
-  var edgeData = object[k];
-
-  if (edgeData.next !== undefined) {
-    return new Iterator__default["default"](function () {
-      if (!edgeData) return {
-        done: true
-      };
-      var value = {
-        edge: edgeData.key,
-        attributes: edgeData.attributes,
-        source: edgeData.source.key,
-        target: edgeData.target.key,
-        sourceAttributes: edgeData.source.attributes,
-        targetAttributes: edgeData.target.attributes,
-        undirected: edgeData.undirected
-      };
-      edgeData = edgeData.next;
-      return {
-        done: false,
-        value: value
-      };
-    });
-  }
-
-  return Iterator__default["default"].of({
-    edge: edgeData.key,
-    attributes: edgeData.attributes,
-    source: edgeData.source.key,
-    target: edgeData.target.key,
-    sourceAttributes: edgeData.source.attributes,
-    targetAttributes: edgeData.target.attributes,
-    undirected: edgeData.undirected
-  });
-}
-/**
- * Function creating an array of edges for the given type.
- *
- * @param  {Graph}   graph - Target Graph instance.
- * @param  {string}  type  - Type of edges to retrieve.
- * @return {array}         - Array of edges.
- */
-
-
-function createEdgeArray(graph, type) {
-  if (graph.size === 0) return [];
-
-  if (type === 'mixed' || type === graph.type) {
-    if (typeof Array.from === 'function') return Array.from(graph._edges.keys());
-    return take__default["default"](graph._edges.keys(), graph._edges.size);
-  }
-
-  var size = type === 'undirected' ? graph.undirectedSize : graph.directedSize;
-  var list = new Array(size),
-      mask = type === 'undirected';
-
-  var iterator = graph._edges.values();
-
-  var i = 0;
-  var step, data;
-
-  while (step = iterator.next(), step.done !== true) {
-    data = step.value;
-    if (data.undirected === mask) list[i++] = data.key;
-  }
-
-  return list;
-}
-/**
- * Function iterating over a graph's edges using a callback to match one of
- * them.
- *
- * @param  {Graph}    graph    - Target Graph instance.
- * @param  {string}   type     - Type of edges to retrieve.
- * @param  {function} callback - Function to call.
- */
-
-
-function forEachEdge(breakable, graph, type, callback) {
-  if (graph.size === 0) return;
-  var shouldFilter = type !== 'mixed' && type !== graph.type;
-  var mask = type === 'undirected';
-  var step, data;
-  var shouldBreak = false;
-
-  var iterator = graph._edges.values();
-
-  while (step = iterator.next(), step.done !== true) {
-    data = step.value;
-    if (shouldFilter && data.undirected !== mask) continue;
-    var _data = data,
-        key = _data.key,
-        attributes = _data.attributes,
-        source = _data.source,
-        target = _data.target;
-    shouldBreak = callback(key, attributes, source.key, target.key, source.attributes, target.attributes, data.undirected);
-    if (breakable && shouldBreak) return key;
-  }
-
-  return;
-}
-/**
- * Function creating an iterator of edges for the given type.
- *
- * @param  {Graph}    graph - Target Graph instance.
- * @param  {string}   type  - Type of edges to retrieve.
- * @return {Iterator}
- */
-
-
-function createEdgeIterator(graph, type) {
-  if (graph.size === 0) return Iterator__default["default"].empty();
-  var shouldFilter = type !== 'mixed' && type !== graph.type;
-  var mask = type === 'undirected';
-
-  var iterator = graph._edges.values();
-
-  return new Iterator__default["default"](function next() {
-    var step, data; // eslint-disable-next-line no-constant-condition
-
-    while (true) {
-      step = iterator.next();
-      if (step.done) return step;
-      data = step.value;
-      if (shouldFilter && data.undirected !== mask) continue;
-      break;
-    }
-
-    var value = {
-      edge: data.key,
-      attributes: data.attributes,
-      source: data.source.key,
-      target: data.target.key,
-      sourceAttributes: data.source.attributes,
-      targetAttributes: data.target.attributes,
-      undirected: data.undirected
-    };
-    return {
-      value: value,
-      done: false
-    };
-  });
-}
-/**
- * Function iterating over a node's edges using a callback to match one of them.
- *
- * @param  {boolean}  multi     - Whether the graph is multi or not.
- * @param  {string}   type      - Type of edges to retrieve.
- * @param  {string}   direction - In or out?
- * @param  {any}      nodeData  - Target node's data.
- * @param  {function} callback  - Function to call.
- */
-
-
-function forEachEdgeForNode(breakable, multi, type, direction, nodeData, callback) {
-  var fn = multi ? forEachMulti : forEachSimple;
-  var found;
-
-  if (type !== 'undirected') {
-    if (direction !== 'out') {
-      found = fn(breakable, nodeData["in"], callback);
-      if (breakable && found) return found;
-    }
-
-    if (direction !== 'in') {
-      found = fn(breakable, nodeData.out, callback, !direction ? nodeData.key : undefined);
-      if (breakable && found) return found;
-    }
-  }
-
-  if (type !== 'directed') {
-    found = fn(breakable, nodeData.undirected, callback);
-    if (breakable && found) return found;
-  }
-
-  return;
-}
-/**
- * Function creating an array of edges for the given type & the given node.
- *
- * @param  {boolean} multi     - Whether the graph is multi or not.
- * @param  {string}  type      - Type of edges to retrieve.
- * @param  {string}  direction - In or out?
- * @param  {any}     nodeData  - Target node's data.
- * @return {array}             - Array of edges.
- */
-
-
-function createEdgeArrayForNode(multi, type, direction, nodeData) {
-  var edges = []; // TODO: possibility to know size beforehand or factorize with map
-
-  forEachEdgeForNode(false, multi, type, direction, nodeData, function (key) {
-    edges.push(key);
-  });
-  return edges;
-}
-/**
- * Function iterating over a node's edges using a callback.
- *
- * @param  {string}   type      - Type of edges to retrieve.
- * @param  {string}   direction - In or out?
- * @param  {any}      nodeData  - Target node's data.
- * @return {Iterator}
- */
-
-
-function createEdgeIteratorForNode(type, direction, nodeData) {
-  var iterator = Iterator__default["default"].empty();
-
-  if (type !== 'undirected') {
-    if (direction !== 'out' && typeof nodeData["in"] !== 'undefined') iterator = chain__default["default"](iterator, createIterator(nodeData["in"]));
-    if (direction !== 'in' && typeof nodeData.out !== 'undefined') iterator = chain__default["default"](iterator, createIterator(nodeData.out, !direction ? nodeData.key : undefined));
-  }
-
-  if (type !== 'directed' && typeof nodeData.undirected !== 'undefined') {
-    iterator = chain__default["default"](iterator, createIterator(nodeData.undirected));
-  }
-
-  return iterator;
-}
-/**
- * Function iterating over edges for the given path using a callback to match
- * one of them.
- *
- * @param  {string}   type       - Type of edges to retrieve.
- * @param  {boolean}  multi      - Whether the graph is multi.
- * @param  {string}   direction  - In or out?
- * @param  {NodeData} sourceData - Source node's data.
- * @param  {string}   target     - Target node.
- * @param  {function} callback   - Function to call.
- */
-
-
-function forEachEdgeForPath(breakable, type, multi, direction, sourceData, target, callback) {
-  var fn = multi ? forEachForKeyMulti : forEachForKeySimple;
-  var found;
-
-  if (type !== 'undirected') {
-    if (typeof sourceData["in"] !== 'undefined' && direction !== 'out') {
-      found = fn(breakable, sourceData["in"], target, callback);
-      if (breakable && found) return found;
-    }
-
-    if (typeof sourceData.out !== 'undefined' && direction !== 'in' && (direction || sourceData.key !== target)) {
-      found = fn(breakable, sourceData.out, target, callback);
-      if (breakable && found) return found;
-    }
-  }
-
-  if (type !== 'directed') {
-    if (typeof sourceData.undirected !== 'undefined') {
-      found = fn(breakable, sourceData.undirected, target, callback);
-      if (breakable && found) return found;
-    }
-  }
-
-  return;
-}
-/**
- * Function creating an array of edges for the given path.
- *
- * @param  {string}   type       - Type of edges to retrieve.
- * @param  {boolean}  multi      - Whether the graph is multi.
- * @param  {string}   direction  - In or out?
- * @param  {NodeData} sourceData - Source node's data.
- * @param  {any}      target     - Target node.
- * @return {array}               - Array of edges.
- */
-
-
-function createEdgeArrayForPath(type, multi, direction, sourceData, target) {
-  var edges = []; // TODO: possibility to know size beforehand or factorize with map
-
-  forEachEdgeForPath(false, type, multi, direction, sourceData, target, function (key) {
-    edges.push(key);
-  });
-  return edges;
-}
-/**
- * Function returning an iterator over edges for the given path.
- *
- * @param  {string}   type       - Type of edges to retrieve.
- * @param  {string}   direction  - In or out?
- * @param  {NodeData} sourceData - Source node's data.
- * @param  {string}   target     - Target node.
- * @param  {function} callback   - Function to call.
- */
-
-
-function createEdgeIteratorForPath(type, direction, sourceData, target) {
-  var iterator = Iterator__default["default"].empty();
-
-  if (type !== 'undirected') {
-    if (typeof sourceData["in"] !== 'undefined' && direction !== 'out' && target in sourceData["in"]) iterator = chain__default["default"](iterator, createIteratorForKey(sourceData["in"], target));
-    if (typeof sourceData.out !== 'undefined' && direction !== 'in' && target in sourceData.out && (direction || sourceData.key !== target)) iterator = chain__default["default"](iterator, createIteratorForKey(sourceData.out, target));
-  }
-
-  if (type !== 'directed') {
-    if (typeof sourceData.undirected !== 'undefined' && target in sourceData.undirected) iterator = chain__default["default"](iterator, createIteratorForKey(sourceData.undirected, target));
-  }
-
-  return iterator;
-}
-/**
- * Function attaching an edge array creator method to the Graph prototype.
- *
- * @param {function} Class       - Target class.
- * @param {object}   description - Method description.
- */
-
-
-function attachEdgeArrayCreator(Class, description) {
-  var name = description.name,
-      type = description.type,
-      direction = description.direction;
-  /**
-   * Function returning an array of certain edges.
-   *
-   * Arity 0: Return all the relevant edges.
-   *
-   * Arity 1: Return all of a node's relevant edges.
-   * @param  {any}   node   - Target node.
-   *
-   * Arity 2: Return the relevant edges across the given path.
-   * @param  {any}   source - Source node.
-   * @param  {any}   target - Target node.
-   *
-   * @return {array|number} - The edges or the number of edges.
-   *
-   * @throws {Error} - Will throw if there are too many arguments.
-   */
-
-  Class.prototype[name] = function (source, target) {
-    // Early termination
-    if (type !== 'mixed' && this.type !== 'mixed' && type !== this.type) return [];
-    if (!arguments.length) return createEdgeArray(this, type);
-
-    if (arguments.length === 1) {
-      source = '' + source;
-
-      var nodeData = this._nodes.get(source);
-
-      if (typeof nodeData === 'undefined') throw new NotFoundGraphError("Graph.".concat(name, ": could not find the \"").concat(source, "\" node in the graph.")); // Iterating over a node's edges
-
-      return createEdgeArrayForNode(this.multi, type === 'mixed' ? this.type : type, direction, nodeData);
-    }
-
-    if (arguments.length === 2) {
-      source = '' + source;
-      target = '' + target;
-
-      var sourceData = this._nodes.get(source);
-
-      if (!sourceData) throw new NotFoundGraphError("Graph.".concat(name, ":  could not find the \"").concat(source, "\" source node in the graph."));
-      if (!this._nodes.has(target)) throw new NotFoundGraphError("Graph.".concat(name, ":  could not find the \"").concat(target, "\" target node in the graph.")); // Iterating over the edges between source & target
-
-      return createEdgeArrayForPath(type, this.multi, direction, sourceData, target);
-    }
-
-    throw new InvalidArgumentsGraphError("Graph.".concat(name, ": too many arguments (expecting 0, 1 or 2 and got ").concat(arguments.length, ")."));
-  };
-}
-/**
- * Function attaching a edge callback iterator method to the Graph prototype.
- *
- * @param {function} Class       - Target class.
- * @param {object}   description - Method description.
- */
-
-
-function attachForEachEdge(Class, description) {
-  var name = description.name,
-      type = description.type,
-      direction = description.direction;
-  var forEachName = 'forEach' + name[0].toUpperCase() + name.slice(1, -1);
-  /**
-   * Function iterating over the graph's relevant edges by applying the given
-   * callback.
-   *
-   * Arity 1: Iterate over all the relevant edges.
-   * @param  {function} callback - Callback to use.
-   *
-   * Arity 2: Iterate over all of a node's relevant edges.
-   * @param  {any}      node     - Target node.
-   * @param  {function} callback - Callback to use.
-   *
-   * Arity 3: Iterate over the relevant edges across the given path.
-   * @param  {any}      source   - Source node.
-   * @param  {any}      target   - Target node.
-   * @param  {function} callback - Callback to use.
-   *
-   * @return {undefined}
-   *
-   * @throws {Error} - Will throw if there are too many arguments.
-   */
-
-  Class.prototype[forEachName] = function (source, target, callback) {
-    // Early termination
-    if (type !== 'mixed' && this.type !== 'mixed' && type !== this.type) return;
-
-    if (arguments.length === 1) {
-      callback = source;
-      return forEachEdge(false, this, type, callback);
-    }
-
-    if (arguments.length === 2) {
-      source = '' + source;
-      callback = target;
-
-      var nodeData = this._nodes.get(source);
-
-      if (typeof nodeData === 'undefined') throw new NotFoundGraphError("Graph.".concat(forEachName, ": could not find the \"").concat(source, "\" node in the graph.")); // Iterating over a node's edges
-      // TODO: maybe attach the sub method to the instance dynamically?
-
-      return forEachEdgeForNode(false, this.multi, type === 'mixed' ? this.type : type, direction, nodeData, callback);
-    }
-
-    if (arguments.length === 3) {
-      source = '' + source;
-      target = '' + target;
-
-      var sourceData = this._nodes.get(source);
-
-      if (!sourceData) throw new NotFoundGraphError("Graph.".concat(forEachName, ":  could not find the \"").concat(source, "\" source node in the graph."));
-      if (!this._nodes.has(target)) throw new NotFoundGraphError("Graph.".concat(forEachName, ":  could not find the \"").concat(target, "\" target node in the graph.")); // Iterating over the edges between source & target
-
-      return forEachEdgeForPath(false, type, this.multi, direction, sourceData, target, callback);
-    }
-
-    throw new InvalidArgumentsGraphError("Graph.".concat(forEachName, ": too many arguments (expecting 1, 2 or 3 and got ").concat(arguments.length, ")."));
-  };
-  /**
-   * Function mapping the graph's relevant edges by applying the given
-   * callback.
-   *
-   * Arity 1: Map all the relevant edges.
-   * @param  {function} callback - Callback to use.
-   *
-   * Arity 2: Map all of a node's relevant edges.
-   * @param  {any}      node     - Target node.
-   * @param  {function} callback - Callback to use.
-   *
-   * Arity 3: Map the relevant edges across the given path.
-   * @param  {any}      source   - Source node.
-   * @param  {any}      target   - Target node.
-   * @param  {function} callback - Callback to use.
-   *
-   * @return {undefined}
-   *
-   * @throws {Error} - Will throw if there are too many arguments.
-   */
-
-
-  var mapName = 'map' + name[0].toUpperCase() + name.slice(1);
-
-  Class.prototype[mapName] = function () {
-    var args = Array.prototype.slice.call(arguments);
-    var callback = args.pop();
-    var result; // We know the result length beforehand
-
-    if (args.length === 0) {
-      var length = 0;
-      if (type !== 'directed') length += this.undirectedSize;
-      if (type !== 'undirected') length += this.directedSize;
-      result = new Array(length);
-      var i = 0;
-      args.push(function (e, ea, s, t, sa, ta, u) {
-        result[i++] = callback(e, ea, s, t, sa, ta, u);
-      });
-    } // We don't know the result length beforehand
-    // TODO: we can in some instances of simple graphs, knowing degree
-    else {
-      result = [];
-      args.push(function (e, ea, s, t, sa, ta, u) {
-        result.push(callback(e, ea, s, t, sa, ta, u));
-      });
-    }
-
-    this[forEachName].apply(this, args);
-    return result;
-  };
-  /**
-   * Function filtering the graph's relevant edges using the provided predicate
-   * function.
-   *
-   * Arity 1: Filter all the relevant edges.
-   * @param  {function} predicate - Predicate to use.
-   *
-   * Arity 2: Filter all of a node's relevant edges.
-   * @param  {any}      node      - Target node.
-   * @param  {function} predicate - Predicate to use.
-   *
-   * Arity 3: Filter the relevant edges across the given path.
-   * @param  {any}      source    - Source node.
-   * @param  {any}      target    - Target node.
-   * @param  {function} predicate - Predicate to use.
-   *
-   * @return {undefined}
-   *
-   * @throws {Error} - Will throw if there are too many arguments.
-   */
-
-
-  var filterName = 'filter' + name[0].toUpperCase() + name.slice(1);
-
-  Class.prototype[filterName] = function () {
-    var args = Array.prototype.slice.call(arguments);
-    var callback = args.pop();
-    var result = [];
-    args.push(function (e, ea, s, t, sa, ta, u) {
-      if (callback(e, ea, s, t, sa, ta, u)) result.push(e);
-    });
-    this[forEachName].apply(this, args);
-    return result;
-  };
-  /**
-   * Function reducing the graph's relevant edges using the provided accumulator
-   * function.
-   *
-   * Arity 1: Reduce all the relevant edges.
-   * @param  {function} accumulator  - Accumulator to use.
-   * @param  {any}      initialValue - Initial value.
-   *
-   * Arity 2: Reduce all of a node's relevant edges.
-   * @param  {any}      node         - Target node.
-   * @param  {function} accumulator  - Accumulator to use.
-   * @param  {any}      initialValue - Initial value.
-   *
-   * Arity 3: Reduce the relevant edges across the given path.
-   * @param  {any}      source       - Source node.
-   * @param  {any}      target       - Target node.
-   * @param  {function} accumulator  - Accumulator to use.
-   * @param  {any}      initialValue - Initial value.
-   *
-   * @return {undefined}
-   *
-   * @throws {Error} - Will throw if there are too many arguments.
-   */
-
-
-  var reduceName = 'reduce' + name[0].toUpperCase() + name.slice(1);
-
-  Class.prototype[reduceName] = function () {
-    var args = Array.prototype.slice.call(arguments);
-
-    if (args.length < 2 || args.length > 4) {
-      throw new InvalidArgumentsGraphError("Graph.".concat(reduceName, ": invalid number of arguments (expecting 2, 3 or 4 and got ").concat(args.length, ")."));
-    }
-
-    if (typeof args[args.length - 1] === 'function' && typeof args[args.length - 2] !== 'function') {
-      throw new InvalidArgumentsGraphError("Graph.".concat(reduceName, ": missing initial value. You must provide it because the callback takes more than one argument and we cannot infer the initial value from the first iteration, as you could with a simple array."));
-    }
-
-    var callback;
-    var initialValue;
-
-    if (args.length === 2) {
-      callback = args[0];
-      initialValue = args[1];
-      args = [];
-    } else if (args.length === 3) {
-      callback = args[1];
-      initialValue = args[2];
-      args = [args[0]];
-    } else if (args.length === 4) {
-      callback = args[2];
-      initialValue = args[3];
-      args = [args[0], args[1]];
-    }
-
-    var accumulator = initialValue;
-    args.push(function (e, ea, s, t, sa, ta, u) {
-      accumulator = callback(accumulator, e, ea, s, t, sa, ta, u);
-    });
-    this[forEachName].apply(this, args);
-    return accumulator;
-  };
-}
-/**
- * Function attaching a breakable edge callback iterator method to the Graph
- * prototype.
- *
- * @param {function} Class       - Target class.
- * @param {object}   description - Method description.
- */
-
-
-function attachFindEdge(Class, description) {
-  var name = description.name,
-      type = description.type,
-      direction = description.direction;
-  var findEdgeName = 'find' + name[0].toUpperCase() + name.slice(1, -1);
-  /**
-   * Function iterating over the graph's relevant edges in order to match
-   * one of them using the provided predicate function.
-   *
-   * Arity 1: Iterate over all the relevant edges.
-   * @param  {function} callback - Callback to use.
-   *
-   * Arity 2: Iterate over all of a node's relevant edges.
-   * @param  {any}      node     - Target node.
-   * @param  {function} callback - Callback to use.
-   *
-   * Arity 3: Iterate over the relevant edges across the given path.
-   * @param  {any}      source   - Source node.
-   * @param  {any}      target   - Target node.
-   * @param  {function} callback - Callback to use.
-   *
-   * @return {undefined}
-   *
-   * @throws {Error} - Will throw if there are too many arguments.
-   */
-
-  Class.prototype[findEdgeName] = function (source, target, callback) {
-    // Early termination
-    if (type !== 'mixed' && this.type !== 'mixed' && type !== this.type) return false;
-
-    if (arguments.length === 1) {
-      callback = source;
-      return forEachEdge(true, this, type, callback);
-    }
-
-    if (arguments.length === 2) {
-      source = '' + source;
-      callback = target;
-
-      var nodeData = this._nodes.get(source);
-
-      if (typeof nodeData === 'undefined') throw new NotFoundGraphError("Graph.".concat(findEdgeName, ": could not find the \"").concat(source, "\" node in the graph.")); // Iterating over a node's edges
-      // TODO: maybe attach the sub method to the instance dynamically?
-
-      return forEachEdgeForNode(true, this.multi, type === 'mixed' ? this.type : type, direction, nodeData, callback);
-    }
-
-    if (arguments.length === 3) {
-      source = '' + source;
-      target = '' + target;
-
-      var sourceData = this._nodes.get(source);
-
-      if (!sourceData) throw new NotFoundGraphError("Graph.".concat(findEdgeName, ":  could not find the \"").concat(source, "\" source node in the graph."));
-      if (!this._nodes.has(target)) throw new NotFoundGraphError("Graph.".concat(findEdgeName, ":  could not find the \"").concat(target, "\" target node in the graph.")); // Iterating over the edges between source & target
-
-      return forEachEdgeForPath(true, type, this.multi, direction, sourceData, target, callback);
-    }
-
-    throw new InvalidArgumentsGraphError("Graph.".concat(findEdgeName, ": too many arguments (expecting 1, 2 or 3 and got ").concat(arguments.length, ")."));
-  };
-  /**
-   * Function iterating over the graph's relevant edges in order to assert
-   * whether any one of them matches the provided predicate function.
-   *
-   * Arity 1: Iterate over all the relevant edges.
-   * @param  {function} callback - Callback to use.
-   *
-   * Arity 2: Iterate over all of a node's relevant edges.
-   * @param  {any}      node     - Target node.
-   * @param  {function} callback - Callback to use.
-   *
-   * Arity 3: Iterate over the relevant edges across the given path.
-   * @param  {any}      source   - Source node.
-   * @param  {any}      target   - Target node.
-   * @param  {function} callback - Callback to use.
-   *
-   * @return {undefined}
-   *
-   * @throws {Error} - Will throw if there are too many arguments.
-   */
-
-
-  var someName = 'some' + name[0].toUpperCase() + name.slice(1, -1);
-
-  Class.prototype[someName] = function () {
-    var args = Array.prototype.slice.call(arguments);
-    var callback = args.pop();
-    args.push(function (e, ea, s, t, sa, ta, u) {
-      return callback(e, ea, s, t, sa, ta, u);
-    });
-    var found = this[findEdgeName].apply(this, args);
-    if (found) return true;
-    return false;
-  };
-  /**
-   * Function iterating over the graph's relevant edges in order to assert
-   * whether all of them matche the provided predicate function.
-   *
-   * Arity 1: Iterate over all the relevant edges.
-   * @param  {function} callback - Callback to use.
-   *
-   * Arity 2: Iterate over all of a node's relevant edges.
-   * @param  {any}      node     - Target node.
-   * @param  {function} callback - Callback to use.
-   *
-   * Arity 3: Iterate over the relevant edges across the given path.
-   * @param  {any}      source   - Source node.
-   * @param  {any}      target   - Target node.
-   * @param  {function} callback - Callback to use.
-   *
-   * @return {undefined}
-   *
-   * @throws {Error} - Will throw if there are too many arguments.
-   */
-
-
-  var everyName = 'every' + name[0].toUpperCase() + name.slice(1, -1);
-
-  Class.prototype[everyName] = function () {
-    var args = Array.prototype.slice.call(arguments);
-    var callback = args.pop();
-    args.push(function (e, ea, s, t, sa, ta, u) {
-      return !callback(e, ea, s, t, sa, ta, u);
-    });
-    var found = this[findEdgeName].apply(this, args);
-    if (found) return false;
-    return true;
-  };
-}
-/**
- * Function attaching an edge iterator method to the Graph prototype.
- *
- * @param {function} Class       - Target class.
- * @param {object}   description - Method description.
- */
-
-
-function attachEdgeIteratorCreator(Class, description) {
-  var originalName = description.name,
-      type = description.type,
-      direction = description.direction;
-  var name = originalName.slice(0, -1) + 'Entries';
-  /**
-   * Function returning an iterator over the graph's edges.
-   *
-   * Arity 0: Iterate over all the relevant edges.
-   *
-   * Arity 1: Iterate over all of a node's relevant edges.
-   * @param  {any}   node   - Target node.
-   *
-   * Arity 2: Iterate over the relevant edges across the given path.
-   * @param  {any}   source - Source node.
-   * @param  {any}   target - Target node.
-   *
-   * @return {array|number} - The edges or the number of edges.
-   *
-   * @throws {Error} - Will throw if there are too many arguments.
-   */
-
-  Class.prototype[name] = function (source, target) {
-    // Early termination
-    if (type !== 'mixed' && this.type !== 'mixed' && type !== this.type) return Iterator__default["default"].empty();
-    if (!arguments.length) return createEdgeIterator(this, type);
-
-    if (arguments.length === 1) {
-      source = '' + source;
-
-      var sourceData = this._nodes.get(source);
-
-      if (!sourceData) throw new NotFoundGraphError("Graph.".concat(name, ": could not find the \"").concat(source, "\" node in the graph.")); // Iterating over a node's edges
-
-      return createEdgeIteratorForNode(type, direction, sourceData);
-    }
-
-    if (arguments.length === 2) {
-      source = '' + source;
-      target = '' + target;
-
-      var _sourceData = this._nodes.get(source);
-
-      if (!_sourceData) throw new NotFoundGraphError("Graph.".concat(name, ":  could not find the \"").concat(source, "\" source node in the graph."));
-      if (!this._nodes.has(target)) throw new NotFoundGraphError("Graph.".concat(name, ":  could not find the \"").concat(target, "\" target node in the graph.")); // Iterating over the edges between source & target
-
-      return createEdgeIteratorForPath(type, direction, _sourceData, target);
-    }
-
-    throw new InvalidArgumentsGraphError("Graph.".concat(name, ": too many arguments (expecting 0, 1 or 2 and got ").concat(arguments.length, ")."));
-  };
-}
-/**
- * Function attaching every edge iteration method to the Graph class.
- *
- * @param {function} Graph - Graph class.
- */
-
-
-function attachEdgeIterationMethods(Graph) {
-  EDGES_ITERATION.forEach(function (description) {
-    attachEdgeArrayCreator(Graph, description);
-    attachForEachEdge(Graph, description);
-    attachFindEdge(Graph, description);
-    attachEdgeIteratorCreator(Graph, description);
-  });
-}
-
-/**
- * Graphology Neighbor Iteration
- * ==============================
- *
- * Attaching some methods to the Graph class to be able to iterate over
- * neighbors.
- */
-/**
- * Definitions.
- */
-
-var NEIGHBORS_ITERATION = [{
-  name: 'neighbors',
-  type: 'mixed'
-}, {
-  name: 'inNeighbors',
-  type: 'directed',
-  direction: 'in'
-}, {
-  name: 'outNeighbors',
-  type: 'directed',
-  direction: 'out'
-}, {
-  name: 'inboundNeighbors',
-  type: 'mixed',
-  direction: 'in'
-}, {
-  name: 'outboundNeighbors',
-  type: 'mixed',
-  direction: 'out'
-}, {
-  name: 'directedNeighbors',
-  type: 'directed'
-}, {
-  name: 'undirectedNeighbors',
-  type: 'undirected'
-}];
-/**
- * Helpers.
- */
-
-function CompositeSetWrapper() {
-  this.A = null;
-  this.B = null;
-}
-
-CompositeSetWrapper.prototype.wrap = function (set) {
-  if (this.A === null) this.A = set;else if (this.B === null) this.B = set;
-};
-
-CompositeSetWrapper.prototype.has = function (key) {
-  if (this.A !== null && key in this.A) return true;
-  if (this.B !== null && key in this.B) return true;
-  return false;
-};
-/**
- * Function iterating over the given node's relevant neighbors to match
- * one of them using a predicated function.
- *
- * @param  {string}   type      - Type of neighbors.
- * @param  {string}   direction - Direction.
- * @param  {any}      nodeData  - Target node's data.
- * @param  {function} callback  - Callback to use.
- */
-
-
-function forEachInObjectOnce(breakable, visited, nodeData, object, callback) {
-  for (var k in object) {
-    var edgeData = object[k];
-    var sourceData = edgeData.source;
-    var targetData = edgeData.target;
-    var neighborData = sourceData === nodeData ? targetData : sourceData;
-    if (visited && visited.has(neighborData.key)) continue;
-    var shouldBreak = callback(neighborData.key, neighborData.attributes);
-    if (breakable && shouldBreak) return neighborData.key;
-  }
-
-  return;
-}
-
-function forEachNeighbor(breakable, type, direction, nodeData, callback) {
-  // If we want only undirected or in or out, we can roll some optimizations
-  if (type !== 'mixed') {
-    if (type === 'undirected') return forEachInObjectOnce(breakable, null, nodeData, nodeData.undirected, callback);
-    if (typeof direction === 'string') return forEachInObjectOnce(breakable, null, nodeData, nodeData[direction], callback);
-  } // Else we need to keep a set of neighbors not to return duplicates
-  // We cheat by querying the other adjacencies
-
-
-  var visited = new CompositeSetWrapper();
-  var found;
-
-  if (type !== 'undirected') {
-    if (direction !== 'out') {
-      found = forEachInObjectOnce(breakable, null, nodeData, nodeData["in"], callback);
-      if (breakable && found) return found;
-      visited.wrap(nodeData["in"]);
-    }
-
-    if (direction !== 'in') {
-      found = forEachInObjectOnce(breakable, visited, nodeData, nodeData.out, callback);
-      if (breakable && found) return found;
-      visited.wrap(nodeData.out);
-    }
-  }
-
-  if (type !== 'directed') {
-    found = forEachInObjectOnce(breakable, visited, nodeData, nodeData.undirected, callback);
-    if (breakable && found) return found;
-  }
-
-  return;
-}
-/**
- * Function creating an array of relevant neighbors for the given node.
- *
- * @param  {string}       type      - Type of neighbors.
- * @param  {string}       direction - Direction.
- * @param  {any}          nodeData  - Target node's data.
- * @return {Array}                  - The list of neighbors.
- */
-
-
-function createNeighborArrayForNode(type, direction, nodeData) {
-  // If we want only undirected or in or out, we can roll some optimizations
-  if (type !== 'mixed') {
-    if (type === 'undirected') return Object.keys(nodeData.undirected);
-    if (typeof direction === 'string') return Object.keys(nodeData[direction]);
-  }
-
-  var neighbors = [];
-  forEachNeighbor(false, type, direction, nodeData, function (key) {
-    neighbors.push(key);
-  });
-  return neighbors;
-}
-/**
- * Function returning an iterator over the given node's relevant neighbors.
- *
- * @param  {string}   type      - Type of neighbors.
- * @param  {string}   direction - Direction.
- * @param  {any}      nodeData  - Target node's data.
- * @return {Iterator}
- */
-
-
-function createDedupedObjectIterator(visited, nodeData, object) {
-  var keys = Object.keys(object);
-  var l = keys.length;
-  var i = 0;
-  return new Iterator__default["default"](function next() {
-    var neighborData = null;
-
-    do {
-      if (i >= l) {
-        if (visited) visited.wrap(object);
-        return {
-          done: true
-        };
-      }
-
-      var edgeData = object[keys[i++]];
-      var sourceData = edgeData.source;
-      var targetData = edgeData.target;
-      neighborData = sourceData === nodeData ? targetData : sourceData;
-
-      if (visited && visited.has(neighborData.key)) {
-        neighborData = null;
-        continue;
-      }
-    } while (neighborData === null);
-
-    return {
-      done: false,
-      value: {
-        neighbor: neighborData.key,
-        attributes: neighborData.attributes
-      }
-    };
-  });
-}
-
-function createNeighborIterator(type, direction, nodeData) {
-  // If we want only undirected or in or out, we can roll some optimizations
-  if (type !== 'mixed') {
-    if (type === 'undirected') return createDedupedObjectIterator(null, nodeData, nodeData.undirected);
-    if (typeof direction === 'string') return createDedupedObjectIterator(null, nodeData, nodeData[direction]);
-  }
-
-  var iterator = Iterator__default["default"].empty(); // Else we need to keep a set of neighbors not to return duplicates
-  // We cheat by querying the other adjacencies
-
-  var visited = new CompositeSetWrapper();
-
-  if (type !== 'undirected') {
-    if (direction !== 'out') {
-      iterator = chain__default["default"](iterator, createDedupedObjectIterator(visited, nodeData, nodeData["in"]));
-    }
-
-    if (direction !== 'in') {
-      iterator = chain__default["default"](iterator, createDedupedObjectIterator(visited, nodeData, nodeData.out));
-    }
-  }
-
-  if (type !== 'directed') {
-    iterator = chain__default["default"](iterator, createDedupedObjectIterator(visited, nodeData, nodeData.undirected));
-  }
-
-  return iterator;
-}
-/**
- * Function attaching a neighbors array creator method to the Graph prototype.
- *
- * @param {function} Class       - Target class.
- * @param {object}   description - Method description.
- */
-
-
-function attachNeighborArrayCreator(Class, description) {
-  var name = description.name,
-      type = description.type,
-      direction = description.direction;
-  /**
-   * Function returning an array of certain neighbors.
-   *
-   * @param  {any}   node   - Target node.
-   * @return {array} - The neighbors of neighbors.
-   *
-   * @throws {Error} - Will throw if node is not found in the graph.
-   */
-
-  Class.prototype[name] = function (node) {
-    // Early termination
-    if (type !== 'mixed' && this.type !== 'mixed' && type !== this.type) return [];
-    node = '' + node;
-
-    var nodeData = this._nodes.get(node);
-
-    if (typeof nodeData === 'undefined') throw new NotFoundGraphError("Graph.".concat(name, ": could not find the \"").concat(node, "\" node in the graph.")); // Here, we want to iterate over a node's relevant neighbors
-
-    return createNeighborArrayForNode(type === 'mixed' ? this.type : type, direction, nodeData);
-  };
-}
-/**
- * Function attaching a neighbors callback iterator method to the Graph prototype.
- *
- * @param {function} Class       - Target class.
- * @param {object}   description - Method description.
- */
-
-
-function attachForEachNeighbor(Class, description) {
-  var name = description.name,
-      type = description.type,
-      direction = description.direction;
-  var forEachName = 'forEach' + name[0].toUpperCase() + name.slice(1, -1);
-  /**
-   * Function iterating over all the relevant neighbors using a callback.
-   *
-   * @param  {any}      node     - Target node.
-   * @param  {function} callback - Callback to use.
-   * @return {undefined}
-   *
-   * @throws {Error} - Will throw if there are too many arguments.
-   */
-
-  Class.prototype[forEachName] = function (node, callback) {
-    // Early termination
-    if (type !== 'mixed' && this.type !== 'mixed' && type !== this.type) return;
-    node = '' + node;
-
-    var nodeData = this._nodes.get(node);
-
-    if (typeof nodeData === 'undefined') throw new NotFoundGraphError("Graph.".concat(forEachName, ": could not find the \"").concat(node, "\" node in the graph.")); // Here, we want to iterate over a node's relevant neighbors
-
-    forEachNeighbor(false, type === 'mixed' ? this.type : type, direction, nodeData, callback);
-  };
-  /**
-   * Function mapping the relevant neighbors using a callback.
-   *
-   * @param  {any}      node     - Target node.
-   * @param  {function} callback - Callback to use.
-   *
-   * @throws {Error} - Will throw if there are too many arguments.
-   */
-
-
-  var mapName = 'map' + name[0].toUpperCase() + name.slice(1);
-
-  Class.prototype[mapName] = function (node, callback) {
-    // TODO: optimize when size is known beforehand
-    var result = [];
-    this[forEachName](node, function (n, a) {
-      result.push(callback(n, a));
-    });
-    return result;
-  };
-  /**
-   * Function filtering the relevant neighbors using a callback.
-   *
-   * @param  {any}      node     - Target node.
-   * @param  {function} callback - Callback to use.
-   *
-   * @throws {Error} - Will throw if there are too many arguments.
-   */
-
-
-  var filterName = 'filter' + name[0].toUpperCase() + name.slice(1);
-
-  Class.prototype[filterName] = function (node, callback) {
-    var result = [];
-    this[forEachName](node, function (n, a) {
-      if (callback(n, a)) result.push(n);
-    });
-    return result;
-  };
-  /**
-   * Function reducing the relevant neighbors using a callback.
-   *
-   * @param  {any}      node     - Target node.
-   * @param  {function} callback - Callback to use.
-   *
-   * @throws {Error} - Will throw if there are too many arguments.
-   */
-
-
-  var reduceName = 'reduce' + name[0].toUpperCase() + name.slice(1);
-
-  Class.prototype[reduceName] = function (node, callback, initialValue) {
-    if (arguments.length < 3) throw new InvalidArgumentsGraphError("Graph.".concat(reduceName, ": missing initial value. You must provide it because the callback takes more than one argument and we cannot infer the initial value from the first iteration, as you could with a simple array."));
-    var accumulator = initialValue;
-    this[forEachName](node, function (n, a) {
-      accumulator = callback(accumulator, n, a);
-    });
-    return accumulator;
-  };
-}
-/**
- * Function attaching a breakable neighbors callback iterator method to the
- * Graph prototype.
- *
- * @param {function} Class       - Target class.
- * @param {object}   description - Method description.
- */
-
-
-function attachFindNeighbor(Class, description) {
-  var name = description.name,
-      type = description.type,
-      direction = description.direction;
-  var capitalizedSingular = name[0].toUpperCase() + name.slice(1, -1);
-  var findName = 'find' + capitalizedSingular;
-  /**
-   * Function iterating over all the relevant neighbors using a callback.
-   *
-   * @param  {any}      node     - Target node.
-   * @param  {function} callback - Callback to use.
-   * @return {undefined}
-   *
-   * @throws {Error} - Will throw if there are too many arguments.
-   */
-
-  Class.prototype[findName] = function (node, callback) {
-    // Early termination
-    if (type !== 'mixed' && this.type !== 'mixed' && type !== this.type) return;
-    node = '' + node;
-
-    var nodeData = this._nodes.get(node);
-
-    if (typeof nodeData === 'undefined') throw new NotFoundGraphError("Graph.".concat(findName, ": could not find the \"").concat(node, "\" node in the graph.")); // Here, we want to iterate over a node's relevant neighbors
-
-    return forEachNeighbor(true, type === 'mixed' ? this.type : type, direction, nodeData, callback);
-  };
-  /**
-   * Function iterating over all the relevant neighbors to find if any of them
-   * matches the given predicate.
-   *
-   * @param  {any}      node     - Target node.
-   * @param  {function} callback - Callback to use.
-   * @return {boolean}
-   *
-   * @throws {Error} - Will throw if there are too many arguments.
-   */
-
-
-  var someName = 'some' + capitalizedSingular;
-
-  Class.prototype[someName] = function (node, callback) {
-    var found = this[findName](node, callback);
-    if (found) return true;
-    return false;
-  };
-  /**
-   * Function iterating over all the relevant neighbors to find if all of them
-   * matche the given predicate.
-   *
-   * @param  {any}      node     - Target node.
-   * @param  {function} callback - Callback to use.
-   * @return {boolean}
-   *
-   * @throws {Error} - Will throw if there are too many arguments.
-   */
-
-
-  var everyName = 'every' + capitalizedSingular;
-
-  Class.prototype[everyName] = function (node, callback) {
-    var found = this[findName](node, function (n, a) {
-      return !callback(n, a);
-    });
-    if (found) return false;
-    return true;
-  };
-}
-/**
- * Function attaching a neighbors callback iterator method to the Graph prototype.
- *
- * @param {function} Class       - Target class.
- * @param {object}   description - Method description.
- */
-
-
-function attachNeighborIteratorCreator(Class, description) {
-  var name = description.name,
-      type = description.type,
-      direction = description.direction;
-  var iteratorName = name.slice(0, -1) + 'Entries';
-  /**
-   * Function returning an iterator over all the relevant neighbors.
-   *
-   * @param  {any}      node     - Target node.
-   * @return {Iterator}
-   *
-   * @throws {Error} - Will throw if there are too many arguments.
-   */
-
-  Class.prototype[iteratorName] = function (node) {
-    // Early termination
-    if (type !== 'mixed' && this.type !== 'mixed' && type !== this.type) return Iterator__default["default"].empty();
-    node = '' + node;
-
-    var nodeData = this._nodes.get(node);
-
-    if (typeof nodeData === 'undefined') throw new NotFoundGraphError("Graph.".concat(iteratorName, ": could not find the \"").concat(node, "\" node in the graph.")); // Here, we want to iterate over a node's relevant neighbors
-
-    return createNeighborIterator(type === 'mixed' ? this.type : type, direction, nodeData);
-  };
-}
-/**
- * Function attaching every neighbor iteration method to the Graph class.
- *
- * @param {function} Graph - Graph class.
- */
-
-
-function attachNeighborIterationMethods(Graph) {
-  NEIGHBORS_ITERATION.forEach(function (description) {
-    attachNeighborArrayCreator(Graph, description);
-    attachForEachNeighbor(Graph, description);
-    attachFindNeighbor(Graph, description);
-    attachNeighborIteratorCreator(Graph, description);
-  });
-}
-
-/**
- * Graphology Adjacency Iteration
- * ===============================
- *
- * Attaching some methods to the Graph class to be able to iterate over a
- * graph's adjacency.
- */
-
-/**
- * Function iterating over a simple graph's adjacency using a callback.
- *
- * @param {boolean}  breakable         - Can we break?
- * @param {boolean}  assymetric        - Whether to emit undirected edges only once.
- * @param {boolean}  disconnectedNodes - Whether to emit disconnected nodes.
- * @param {Graph}    graph             - Target Graph instance.
- * @param {callback} function          - Iteration callback.
- */
-function forEachAdjacency(breakable, assymetric, disconnectedNodes, graph, callback) {
-  var iterator = graph._nodes.values();
-
-  var type = graph.type;
-  var step, sourceData, neighbor, adj, edgeData, targetData, shouldBreak;
-
-  while (step = iterator.next(), step.done !== true) {
-    var hasEdges = false;
-    sourceData = step.value;
-
-    if (type !== 'undirected') {
-      adj = sourceData.out;
-
-      for (neighbor in adj) {
-        edgeData = adj[neighbor];
-
-        do {
-          targetData = edgeData.target;
-          hasEdges = true;
-          shouldBreak = callback(sourceData.key, targetData.key, sourceData.attributes, targetData.attributes, edgeData.key, edgeData.attributes, edgeData.undirected);
-          if (breakable && shouldBreak) return edgeData;
-          edgeData = edgeData.next;
-        } while (edgeData);
-      }
-    }
-
-    if (type !== 'directed') {
-      adj = sourceData.undirected;
-
-      for (neighbor in adj) {
-        if (assymetric && sourceData.key > neighbor) continue;
-        edgeData = adj[neighbor];
-
-        do {
-          targetData = edgeData.target;
-          if (targetData.key !== neighbor) targetData = edgeData.source;
-          hasEdges = true;
-          shouldBreak = callback(sourceData.key, targetData.key, sourceData.attributes, targetData.attributes, edgeData.key, edgeData.attributes, edgeData.undirected);
-          if (breakable && shouldBreak) return edgeData;
-          edgeData = edgeData.next;
-        } while (edgeData);
-      }
-    }
-
-    if (disconnectedNodes && !hasEdges) {
-      shouldBreak = callback(sourceData.key, null, sourceData.attributes, null, null, null, null);
-      if (breakable && shouldBreak) return null;
-    }
-  }
-
-  return;
-}
-
-/**
- * Graphology Serialization Utilities
- * ===================================
- *
- * Collection of functions used by the graph serialization schemes.
- */
-/**
- * Formats internal node data into a serialized node.
- *
- * @param  {any}    key  - The node's key.
- * @param  {object} data - Internal node's data.
- * @return {array}       - The serialized node.
- */
-
-function serializeNode(key, data) {
-  var serialized = {
-    key: key
-  };
-  if (!isEmpty(data.attributes)) serialized.attributes = assign({}, data.attributes);
-  return serialized;
-}
-/**
- * Formats internal edge data into a serialized edge.
- *
- * @param  {any}    key  - The edge's key.
- * @param  {object} data - Internal edge's data.
- * @return {array}       - The serialized edge.
- */
-
-function serializeEdge(key, data) {
-  var serialized = {
-    key: key,
-    source: data.source.key,
-    target: data.target.key
-  };
-  if (!isEmpty(data.attributes)) serialized.attributes = assign({}, data.attributes);
-  if (data.undirected) serialized.undirected = true;
-  return serialized;
-}
-/**
- * Checks whether the given value is a serialized node.
- *
- * @param  {mixed} value - Target value.
- * @return {string|null}
- */
-
-function validateSerializedNode(value) {
-  if (!isPlainObject(value)) throw new InvalidArgumentsGraphError('Graph.import: invalid serialized node. A serialized node should be a plain object with at least a "key" property.');
-  if (!('key' in value)) throw new InvalidArgumentsGraphError('Graph.import: serialized node is missing its key.');
-  if ('attributes' in value && (!isPlainObject(value.attributes) || value.attributes === null)) throw new InvalidArgumentsGraphError('Graph.import: invalid attributes. Attributes should be a plain object, null or omitted.');
-}
-/**
- * Checks whether the given value is a serialized edge.
- *
- * @param  {mixed} value - Target value.
- * @return {string|null}
- */
-
-function validateSerializedEdge(value) {
-  if (!isPlainObject(value)) throw new InvalidArgumentsGraphError('Graph.import: invalid serialized edge. A serialized edge should be a plain object with at least a "source" & "target" property.');
-  if (!('source' in value)) throw new InvalidArgumentsGraphError('Graph.import: serialized edge is missing its source.');
-  if (!('target' in value)) throw new InvalidArgumentsGraphError('Graph.import: serialized edge is missing its target.');
-  if ('attributes' in value && (!isPlainObject(value.attributes) || value.attributes === null)) throw new InvalidArgumentsGraphError('Graph.import: invalid attributes. Attributes should be a plain object, null or omitted.');
-  if ('undirected' in value && typeof value.undirected !== 'boolean') throw new InvalidArgumentsGraphError('Graph.import: invalid undirectedness information. Undirected should be boolean or omitted.');
-}
-
-/**
- * Constants.
- */
-
-var INSTANCE_ID = incrementalIdStartingFromRandomByte();
-/**
- * Enums.
- */
-
-var TYPES = new Set(['directed', 'undirected', 'mixed']);
-var EMITTER_PROPS = new Set(['domain', '_events', '_eventsCount', '_maxListeners']);
-var EDGE_ADD_METHODS = [{
-  name: function name(verb) {
-    return "".concat(verb, "Edge");
-  },
-  generateKey: true
-}, {
-  name: function name(verb) {
-    return "".concat(verb, "DirectedEdge");
-  },
-  generateKey: true,
-  type: 'directed'
-}, {
-  name: function name(verb) {
-    return "".concat(verb, "UndirectedEdge");
-  },
-  generateKey: true,
-  type: 'undirected'
-}, {
-  name: function name(verb) {
-    return "".concat(verb, "EdgeWithKey");
-  }
-}, {
-  name: function name(verb) {
-    return "".concat(verb, "DirectedEdgeWithKey");
-  },
-  type: 'directed'
-}, {
-  name: function name(verb) {
-    return "".concat(verb, "UndirectedEdgeWithKey");
-  },
-  type: 'undirected'
-}];
-/**
- * Default options.
- */
-
-var DEFAULTS = {
-  allowSelfLoops: true,
-  multi: false,
-  type: 'mixed'
-};
-/**
- * Abstract functions used by the Graph class for various methods.
- */
-
-/**
- * Internal method used to add a node to the given graph
- *
- * @param  {Graph}   graph           - Target graph.
- * @param  {any}     node            - The node's key.
- * @param  {object}  [attributes]    - Optional attributes.
- * @return {NodeData}                - Created node data.
- */
-
-function _addNode(graph, node, attributes) {
-  if (attributes && !isPlainObject(attributes)) throw new InvalidArgumentsGraphError("Graph.addNode: invalid attributes. Expecting an object but got \"".concat(attributes, "\"")); // String coercion
-
-  node = '' + node;
-  attributes = attributes || {};
-  if (graph._nodes.has(node)) throw new UsageGraphError("Graph.addNode: the \"".concat(node, "\" node already exist in the graph."));
-  var data = new graph.NodeDataClass(node, attributes); // Adding the node to internal register
-
-  graph._nodes.set(node, data); // Emitting
-
-
-  graph.emit('nodeAdded', {
-    key: node,
-    attributes: attributes
-  });
-  return data;
-}
-/**
- * Same as the above but without sanity checks because we call this in contexts
- * where necessary checks were already done.
- */
-
-
-function unsafeAddNode(graph, node, attributes) {
-  var data = new graph.NodeDataClass(node, attributes);
-
-  graph._nodes.set(node, data);
-
-  graph.emit('nodeAdded', {
-    key: node,
-    attributes: attributes
-  });
-  return data;
-}
-/**
- * Internal method used to add an arbitrary edge to the given graph.
- *
- * @param  {Graph}   graph           - Target graph.
- * @param  {string}  name            - Name of the child method for errors.
- * @param  {boolean} mustGenerateKey - Should the graph generate an id?
- * @param  {boolean} undirected      - Whether the edge is undirected.
- * @param  {any}     edge            - The edge's key.
- * @param  {any}     source          - The source node.
- * @param  {any}     target          - The target node.
- * @param  {object}  [attributes]    - Optional attributes.
- * @return {any}                     - The edge.
- *
- * @throws {Error} - Will throw if the graph is of the wrong type.
- * @throws {Error} - Will throw if the given attributes are not an object.
- * @throws {Error} - Will throw if source or target doesn't exist.
- * @throws {Error} - Will throw if the edge already exist.
- */
-
-
-function addEdge(graph, name, mustGenerateKey, undirected, edge, source, target, attributes) {
-  // Checking validity of operation
-  if (!undirected && graph.type === 'undirected') throw new UsageGraphError("Graph.".concat(name, ": you cannot add a directed edge to an undirected graph. Use the #.addEdge or #.addUndirectedEdge instead."));
-  if (undirected && graph.type === 'directed') throw new UsageGraphError("Graph.".concat(name, ": you cannot add an undirected edge to a directed graph. Use the #.addEdge or #.addDirectedEdge instead."));
-  if (attributes && !isPlainObject(attributes)) throw new InvalidArgumentsGraphError("Graph.".concat(name, ": invalid attributes. Expecting an object but got \"").concat(attributes, "\"")); // Coercion of source & target:
-
-  source = '' + source;
-  target = '' + target;
-  attributes = attributes || {};
-  if (!graph.allowSelfLoops && source === target) throw new UsageGraphError("Graph.".concat(name, ": source & target are the same (\"").concat(source, "\"), thus creating a loop explicitly forbidden by this graph 'allowSelfLoops' option set to false."));
-
-  var sourceData = graph._nodes.get(source),
-      targetData = graph._nodes.get(target);
-
-  if (!sourceData) throw new NotFoundGraphError("Graph.".concat(name, ": source node \"").concat(source, "\" not found."));
-  if (!targetData) throw new NotFoundGraphError("Graph.".concat(name, ": target node \"").concat(target, "\" not found.")); // Must the graph generate an id for this edge?
-
-  var eventData = {
-    key: null,
-    undirected: undirected,
-    source: source,
-    target: target,
-    attributes: attributes
-  };
-
-  if (mustGenerateKey) {
-    // NOTE: in this case we can guarantee that the key does not already
-    // exist and is already correctly casted as a string
-    edge = graph._edgeKeyGenerator();
-  } else {
-    // Coercion of edge key
-    edge = '' + edge; // Here, we have a key collision
-
-    if (graph._edges.has(edge)) throw new UsageGraphError("Graph.".concat(name, ": the \"").concat(edge, "\" edge already exists in the graph."));
-  } // Here, we might have a source / target collision
-
-
-  if (!graph.multi && (undirected ? typeof sourceData.undirected[target] !== 'undefined' : typeof sourceData.out[target] !== 'undefined')) {
-    throw new UsageGraphError("Graph.".concat(name, ": an edge linking \"").concat(source, "\" to \"").concat(target, "\" already exists. If you really want to add multiple edges linking those nodes, you should create a multi graph by using the 'multi' option."));
-  } // Storing some data
-
-
-  var edgeData = new EdgeData(undirected, edge, sourceData, targetData, attributes); // Adding the edge to the internal register
-
-  graph._edges.set(edge, edgeData); // Incrementing node degree counters
-
-
-  var isSelfLoop = source === target;
-
-  if (undirected) {
-    sourceData.undirectedDegree++;
-    targetData.undirectedDegree++;
-    if (isSelfLoop) graph._undirectedSelfLoopCount++;
-  } else {
-    sourceData.outDegree++;
-    targetData.inDegree++;
-    if (isSelfLoop) graph._directedSelfLoopCount++;
-  } // Updating relevant index
-
-
-  if (graph.multi) edgeData.attachMulti();else edgeData.attach();
-  if (undirected) graph._undirectedSize++;else graph._directedSize++; // Emitting
-
-  eventData.key = edge;
-  graph.emit('edgeAdded', eventData);
-  return edge;
-}
-/**
- * Internal method used to add an arbitrary edge to the given graph.
- *
- * @param  {Graph}   graph           - Target graph.
- * @param  {string}  name            - Name of the child method for errors.
- * @param  {boolean} mustGenerateKey - Should the graph generate an id?
- * @param  {boolean} undirected      - Whether the edge is undirected.
- * @param  {any}     edge            - The edge's key.
- * @param  {any}     source          - The source node.
- * @param  {any}     target          - The target node.
- * @param  {object}  [attributes]    - Optional attributes.
- * @param  {boolean} [asUpdater]       - Are we updating or merging?
- * @return {any}                     - The edge.
- *
- * @throws {Error} - Will throw if the graph is of the wrong type.
- * @throws {Error} - Will throw if the given attributes are not an object.
- * @throws {Error} - Will throw if source or target doesn't exist.
- * @throws {Error} - Will throw if the edge already exist.
- */
-
-
-function mergeEdge(graph, name, mustGenerateKey, undirected, edge, source, target, attributes, asUpdater) {
-  // Checking validity of operation
-  if (!undirected && graph.type === 'undirected') throw new UsageGraphError("Graph.".concat(name, ": you cannot merge/update a directed edge to an undirected graph. Use the #.mergeEdge/#.updateEdge or #.addUndirectedEdge instead."));
-  if (undirected && graph.type === 'directed') throw new UsageGraphError("Graph.".concat(name, ": you cannot merge/update an undirected edge to a directed graph. Use the #.mergeEdge/#.updateEdge or #.addDirectedEdge instead."));
-
-  if (attributes) {
-    if (asUpdater) {
-      if (typeof attributes !== 'function') throw new InvalidArgumentsGraphError("Graph.".concat(name, ": invalid updater function. Expecting a function but got \"").concat(attributes, "\""));
-    } else {
-      if (!isPlainObject(attributes)) throw new InvalidArgumentsGraphError("Graph.".concat(name, ": invalid attributes. Expecting an object but got \"").concat(attributes, "\""));
-    }
-  } // Coercion of source & target:
-
-
-  source = '' + source;
-  target = '' + target;
-  var updater;
-
-  if (asUpdater) {
-    updater = attributes;
-    attributes = undefined;
-  }
-
-  if (!graph.allowSelfLoops && source === target) throw new UsageGraphError("Graph.".concat(name, ": source & target are the same (\"").concat(source, "\"), thus creating a loop explicitly forbidden by this graph 'allowSelfLoops' option set to false."));
-
-  var sourceData = graph._nodes.get(source);
-
-  var targetData = graph._nodes.get(target);
-
-  var edgeData; // Do we need to handle duplicate?
-
-  var alreadyExistingEdgeData;
-
-  if (!mustGenerateKey) {
-    edgeData = graph._edges.get(edge);
-
-    if (edgeData) {
-      // Here, we need to ensure, if the user gave a key, that source & target
-      // are consistent
-      if (edgeData.source.key !== source || edgeData.target.key !== target) {
-        // If source or target inconsistent
-        if (!undirected || edgeData.source.key !== target || edgeData.target.key !== source) {
-          // If directed, or source/target aren't flipped
-          throw new UsageGraphError("Graph.".concat(name, ": inconsistency detected when attempting to merge the \"").concat(edge, "\" edge with \"").concat(source, "\" source & \"").concat(target, "\" target vs. (\"").concat(edgeData.source.key, "\", \"").concat(edgeData.target.key, "\")."));
-        }
-      }
-
-      alreadyExistingEdgeData = edgeData;
-    }
-  } // Here, we might have a source / target collision
-
-
-  if (!alreadyExistingEdgeData && !graph.multi && sourceData) {
-    alreadyExistingEdgeData = undirected ? sourceData.undirected[target] : sourceData.out[target];
-  } // Handling duplicates
-
-
-  if (alreadyExistingEdgeData) {
-    var info = [alreadyExistingEdgeData.key, false, false, false]; // We can skip the attribute merging part if the user did not provide them
-
-    if (asUpdater ? !updater : !attributes) return info; // Updating the attributes
-
-    if (asUpdater) {
-      var oldAttributes = alreadyExistingEdgeData.attributes;
-      alreadyExistingEdgeData.attributes = updater(oldAttributes);
-      graph.emit('edgeAttributesUpdated', {
-        type: 'replace',
-        key: alreadyExistingEdgeData.key,
-        attributes: alreadyExistingEdgeData.attributes
-      });
-    } // Merging the attributes
-    else {
-      assign(alreadyExistingEdgeData.attributes, attributes);
-      graph.emit('edgeAttributesUpdated', {
-        type: 'merge',
-        key: alreadyExistingEdgeData.key,
-        attributes: alreadyExistingEdgeData.attributes,
-        data: attributes
-      });
-    }
-
-    return info;
-  }
-
-  attributes = attributes || {};
-  if (asUpdater && updater) attributes = updater(attributes); // Must the graph generate an id for this edge?
-
-  var eventData = {
-    key: null,
-    undirected: undirected,
-    source: source,
-    target: target,
-    attributes: attributes
-  };
-
-  if (mustGenerateKey) {
-    // NOTE: in this case we can guarantee that the key does not already
-    // exist and is already correctly casted as a string
-    edge = graph._edgeKeyGenerator();
-  } else {
-    // Coercion of edge key
-    edge = '' + edge; // Here, we have a key collision
-
-    if (graph._edges.has(edge)) throw new UsageGraphError("Graph.".concat(name, ": the \"").concat(edge, "\" edge already exists in the graph."));
-  }
-
-  var sourceWasAdded = false;
-  var targetWasAdded = false;
-
-  if (!sourceData) {
-    sourceData = unsafeAddNode(graph, source, {});
-    sourceWasAdded = true;
-
-    if (source === target) {
-      targetData = sourceData;
-      targetWasAdded = true;
-    }
-  }
-
-  if (!targetData) {
-    targetData = unsafeAddNode(graph, target, {});
-    targetWasAdded = true;
-  } // Storing some data
-
-
-  edgeData = new EdgeData(undirected, edge, sourceData, targetData, attributes); // Adding the edge to the internal register
-
-  graph._edges.set(edge, edgeData); // Incrementing node degree counters
-
-
-  var isSelfLoop = source === target;
-
-  if (undirected) {
-    sourceData.undirectedDegree++;
-    targetData.undirectedDegree++;
-    if (isSelfLoop) graph._undirectedSelfLoopCount++;
-  } else {
-    sourceData.outDegree++;
-    targetData.inDegree++;
-    if (isSelfLoop) graph._directedSelfLoopCount++;
-  } // Updating relevant index
-
-
-  if (graph.multi) edgeData.attachMulti();else edgeData.attach();
-  if (undirected) graph._undirectedSize++;else graph._directedSize++; // Emitting
-
-  eventData.key = edge;
-  graph.emit('edgeAdded', eventData);
-  return [edge, true, sourceWasAdded, targetWasAdded];
-}
-/**
- * Internal method used to drop an edge.
- *
- * @param  {Graph}    graph    - Target graph.
- * @param  {EdgeData} edgeData - Data of the edge to drop.
- */
-
-
-function dropEdgeFromData(graph, edgeData) {
-  // Dropping the edge from the register
-  graph._edges["delete"](edgeData.key); // Updating related degrees
-
-
-  var sourceData = edgeData.source,
-      targetData = edgeData.target,
-      attributes = edgeData.attributes;
-  var undirected = edgeData.undirected;
-  var isSelfLoop = sourceData === targetData;
-
-  if (undirected) {
-    sourceData.undirectedDegree--;
-    targetData.undirectedDegree--;
-    if (isSelfLoop) graph._undirectedSelfLoopCount--;
-  } else {
-    sourceData.outDegree--;
-    targetData.inDegree--;
-    if (isSelfLoop) graph._directedSelfLoopCount--;
-  } // Clearing index
-
-
-  if (graph.multi) edgeData.detachMulti();else edgeData.detach();
-  if (undirected) graph._undirectedSize--;else graph._directedSize--; // Emitting
-
-  graph.emit('edgeDropped', {
-    key: edgeData.key,
-    attributes: attributes,
-    source: sourceData.key,
-    target: targetData.key,
-    undirected: undirected
-  });
-}
-/**
- * Graph class
- *
- * @constructor
- * @param  {object}  [options] - Options:
- * @param  {boolean}   [allowSelfLoops] - Allow self loops?
- * @param  {string}    [type]           - Type of the graph.
- * @param  {boolean}   [map]            - Allow references as keys?
- * @param  {boolean}   [multi]          - Allow parallel edges?
- *
- * @throws {Error} - Will throw if the arguments are not valid.
- */
-
-
-var Graph = /*#__PURE__*/function (_EventEmitter) {
-  _inheritsLoose(Graph, _EventEmitter);
-
-  function Graph(options) {
-    var _this;
-
-    _this = _EventEmitter.call(this) || this; //-- Solving options
-
-    options = assign({}, DEFAULTS, options); // Enforcing options validity
-
-    if (typeof options.multi !== 'boolean') throw new InvalidArgumentsGraphError("Graph.constructor: invalid 'multi' option. Expecting a boolean but got \"".concat(options.multi, "\"."));
-    if (!TYPES.has(options.type)) throw new InvalidArgumentsGraphError("Graph.constructor: invalid 'type' option. Should be one of \"mixed\", \"directed\" or \"undirected\" but got \"".concat(options.type, "\"."));
-    if (typeof options.allowSelfLoops !== 'boolean') throw new InvalidArgumentsGraphError("Graph.constructor: invalid 'allowSelfLoops' option. Expecting a boolean but got \"".concat(options.allowSelfLoops, "\".")); //-- Private properties
-    // Utilities
-
-    var NodeDataClass = options.type === 'mixed' ? MixedNodeData : options.type === 'directed' ? DirectedNodeData : UndirectedNodeData;
-    privateProperty(_assertThisInitialized(_this), 'NodeDataClass', NodeDataClass); // Internal edge key generator
-    // NOTE: this internal generator produce keys that are strings
-    // composed of a weird prefix, an incremental instance id starting from
-    // a random byte and finally an internal instance incremental id.
-    // All this to avoid intra-frame and cross-frame adversarial inputs
-    // that can force a single #.addEdge call to degenerate into a O(n)
-    // available key search loop.
-    // It also ensures that automatically generated edge keys are unlikely
-    // to produce collisions with arbitrary keys given by users.
-
-    var instancePrefix = 'geid_' + INSTANCE_ID() + '_';
-    var edgeId = 0;
-
-    var edgeKeyGenerator = function edgeKeyGenerator() {
-      var availableEdgeKey;
-
-      do {
-        availableEdgeKey = instancePrefix + edgeId++;
-      } while (_this._edges.has(availableEdgeKey));
-
-      return availableEdgeKey;
-    }; // Indexes
-
-
-    privateProperty(_assertThisInitialized(_this), '_attributes', {});
-    privateProperty(_assertThisInitialized(_this), '_nodes', new Map());
-    privateProperty(_assertThisInitialized(_this), '_edges', new Map());
-    privateProperty(_assertThisInitialized(_this), '_directedSize', 0);
-    privateProperty(_assertThisInitialized(_this), '_undirectedSize', 0);
-    privateProperty(_assertThisInitialized(_this), '_directedSelfLoopCount', 0);
-    privateProperty(_assertThisInitialized(_this), '_undirectedSelfLoopCount', 0);
-    privateProperty(_assertThisInitialized(_this), '_edgeKeyGenerator', edgeKeyGenerator); // Options
-
-    privateProperty(_assertThisInitialized(_this), '_options', options); // Emitter properties
-
-    EMITTER_PROPS.forEach(function (prop) {
-      return privateProperty(_assertThisInitialized(_this), prop, _this[prop]);
-    }); //-- Properties readers
-
-    readOnlyProperty(_assertThisInitialized(_this), 'order', function () {
-      return _this._nodes.size;
-    });
-    readOnlyProperty(_assertThisInitialized(_this), 'size', function () {
-      return _this._edges.size;
-    });
-    readOnlyProperty(_assertThisInitialized(_this), 'directedSize', function () {
-      return _this._directedSize;
-    });
-    readOnlyProperty(_assertThisInitialized(_this), 'undirectedSize', function () {
-      return _this._undirectedSize;
-    });
-    readOnlyProperty(_assertThisInitialized(_this), 'selfLoopCount', function () {
-      return _this._directedSelfLoopCount + _this._undirectedSelfLoopCount;
-    });
-    readOnlyProperty(_assertThisInitialized(_this), 'directedSelfLoopCount', function () {
-      return _this._directedSelfLoopCount;
-    });
-    readOnlyProperty(_assertThisInitialized(_this), 'undirectedSelfLoopCount', function () {
-      return _this._undirectedSelfLoopCount;
-    });
-    readOnlyProperty(_assertThisInitialized(_this), 'multi', _this._options.multi);
-    readOnlyProperty(_assertThisInitialized(_this), 'type', _this._options.type);
-    readOnlyProperty(_assertThisInitialized(_this), 'allowSelfLoops', _this._options.allowSelfLoops);
-    readOnlyProperty(_assertThisInitialized(_this), 'implementation', function () {
-      return 'graphology';
-    });
-    return _this;
-  }
-
-  var _proto = Graph.prototype;
-
-  _proto._resetInstanceCounters = function _resetInstanceCounters() {
-    this._directedSize = 0;
-    this._undirectedSize = 0;
-    this._directedSelfLoopCount = 0;
-    this._undirectedSelfLoopCount = 0;
-  }
-  /**---------------------------------------------------------------------------
-   * Read
-   **---------------------------------------------------------------------------
-   */
-
-  /**
-   * Method returning whether the given node is found in the graph.
-   *
-   * @param  {any}     node - The node.
-   * @return {boolean}
-   */
-  ;
-
-  _proto.hasNode = function hasNode(node) {
-    return this._nodes.has('' + node);
-  }
-  /**
-   * Method returning whether the given directed edge is found in the graph.
-   *
-   * Arity 1:
-   * @param  {any}     edge - The edge's key.
-   *
-   * Arity 2:
-   * @param  {any}     source - The edge's source.
-   * @param  {any}     target - The edge's target.
-   *
-   * @return {boolean}
-   *
-   * @throws {Error} - Will throw if the arguments are invalid.
-   */
-  ;
-
-  _proto.hasDirectedEdge = function hasDirectedEdge(source, target) {
-    // Early termination
-    if (this.type === 'undirected') return false;
-
-    if (arguments.length === 1) {
-      var edge = '' + source;
-
-      var edgeData = this._edges.get(edge);
-
-      return !!edgeData && !edgeData.undirected;
-    } else if (arguments.length === 2) {
-      source = '' + source;
-      target = '' + target; // If the node source or the target is not in the graph we break
-
-      var nodeData = this._nodes.get(source);
-
-      if (!nodeData) return false; // Is there a directed edge pointing toward target?
-
-      var edges = nodeData.out[target];
-      if (!edges) return false;
-      return this.multi ? !!edges.size : true;
-    }
-
-    throw new InvalidArgumentsGraphError("Graph.hasDirectedEdge: invalid arity (".concat(arguments.length, ", instead of 1 or 2). You can either ask for an edge id or for the existence of an edge between a source & a target."));
-  }
-  /**
-   * Method returning whether the given undirected edge is found in the graph.
-   *
-   * Arity 1:
-   * @param  {any}     edge - The edge's key.
-   *
-   * Arity 2:
-   * @param  {any}     source - The edge's source.
-   * @param  {any}     target - The edge's target.
-   *
-   * @return {boolean}
-   *
-   * @throws {Error} - Will throw if the arguments are invalid.
-   */
-  ;
-
-  _proto.hasUndirectedEdge = function hasUndirectedEdge(source, target) {
-    // Early termination
-    if (this.type === 'directed') return false;
-
-    if (arguments.length === 1) {
-      var edge = '' + source;
-
-      var edgeData = this._edges.get(edge);
-
-      return !!edgeData && edgeData.undirected;
-    } else if (arguments.length === 2) {
-      source = '' + source;
-      target = '' + target; // If the node source or the target is not in the graph we break
-
-      var nodeData = this._nodes.get(source);
-
-      if (!nodeData) return false; // Is there a directed edge pointing toward target?
-
-      var edges = nodeData.undirected[target];
-      if (!edges) return false;
-      return this.multi ? !!edges.size : true;
-    }
-
-    throw new InvalidArgumentsGraphError("Graph.hasDirectedEdge: invalid arity (".concat(arguments.length, ", instead of 1 or 2). You can either ask for an edge id or for the existence of an edge between a source & a target."));
-  }
-  /**
-   * Method returning whether the given edge is found in the graph.
-   *
-   * Arity 1:
-   * @param  {any}     edge - The edge's key.
-   *
-   * Arity 2:
-   * @param  {any}     source - The edge's source.
-   * @param  {any}     target - The edge's target.
-   *
-   * @return {boolean}
-   *
-   * @throws {Error} - Will throw if the arguments are invalid.
-   */
-  ;
-
-  _proto.hasEdge = function hasEdge(source, target) {
-    if (arguments.length === 1) {
-      var edge = '' + source;
-      return this._edges.has(edge);
-    } else if (arguments.length === 2) {
-      source = '' + source;
-      target = '' + target; // If the node source or the target is not in the graph we break
-
-      var nodeData = this._nodes.get(source);
-
-      if (!nodeData) return false; // Is there a directed edge pointing toward target?
-
-      var edges = typeof nodeData.out !== 'undefined' && nodeData.out[target];
-      if (!edges) edges = typeof nodeData.undirected !== 'undefined' && nodeData.undirected[target];
-      if (!edges) return false;
-      return this.multi ? !!edges.size : true;
-    }
-
-    throw new InvalidArgumentsGraphError("Graph.hasEdge: invalid arity (".concat(arguments.length, ", instead of 1 or 2). You can either ask for an edge id or for the existence of an edge between a source & a target."));
-  }
-  /**
-   * Method returning the edge matching source & target in a directed fashion.
-   *
-   * @param  {any} source - The edge's source.
-   * @param  {any} target - The edge's target.
-   *
-   * @return {any|undefined}
-   *
-   * @throws {Error} - Will throw if the graph is multi.
-   * @throws {Error} - Will throw if source or target doesn't exist.
-   */
-  ;
-
-  _proto.directedEdge = function directedEdge(source, target) {
-    if (this.type === 'undirected') return;
-    source = '' + source;
-    target = '' + target;
-    if (this.multi) throw new UsageGraphError('Graph.directedEdge: this method is irrelevant with multigraphs since there might be multiple edges between source & target. See #.directedEdges instead.');
-
-    var sourceData = this._nodes.get(source);
-
-    if (!sourceData) throw new NotFoundGraphError("Graph.directedEdge: could not find the \"".concat(source, "\" source node in the graph."));
-    if (!this._nodes.has(target)) throw new NotFoundGraphError("Graph.directedEdge: could not find the \"".concat(target, "\" target node in the graph."));
-    var edgeData = sourceData.out && sourceData.out[target] || undefined;
-    if (edgeData) return edgeData.key;
-  }
-  /**
-   * Method returning the edge matching source & target in a undirected fashion.
-   *
-   * @param  {any} source - The edge's source.
-   * @param  {any} target - The edge's target.
-   *
-   * @return {any|undefined}
-   *
-   * @throws {Error} - Will throw if the graph is multi.
-   * @throws {Error} - Will throw if source or target doesn't exist.
-   */
-  ;
-
-  _proto.undirectedEdge = function undirectedEdge(source, target) {
-    if (this.type === 'directed') return;
-    source = '' + source;
-    target = '' + target;
-    if (this.multi) throw new UsageGraphError('Graph.undirectedEdge: this method is irrelevant with multigraphs since there might be multiple edges between source & target. See #.undirectedEdges instead.');
-
-    var sourceData = this._nodes.get(source);
-
-    if (!sourceData) throw new NotFoundGraphError("Graph.undirectedEdge: could not find the \"".concat(source, "\" source node in the graph."));
-    if (!this._nodes.has(target)) throw new NotFoundGraphError("Graph.undirectedEdge: could not find the \"".concat(target, "\" target node in the graph."));
-    var edgeData = sourceData.undirected && sourceData.undirected[target] || undefined;
-    if (edgeData) return edgeData.key;
-  }
-  /**
-   * Method returning the edge matching source & target in a mixed fashion.
-   *
-   * @param  {any} source - The edge's source.
-   * @param  {any} target - The edge's target.
-   *
-   * @return {any|undefined}
-   *
-   * @throws {Error} - Will throw if the graph is multi.
-   * @throws {Error} - Will throw if source or target doesn't exist.
-   */
-  ;
-
-  _proto.edge = function edge(source, target) {
-    if (this.multi) throw new UsageGraphError('Graph.edge: this method is irrelevant with multigraphs since there might be multiple edges between source & target. See #.edges instead.');
-    source = '' + source;
-    target = '' + target;
-
-    var sourceData = this._nodes.get(source);
-
-    if (!sourceData) throw new NotFoundGraphError("Graph.edge: could not find the \"".concat(source, "\" source node in the graph."));
-    if (!this._nodes.has(target)) throw new NotFoundGraphError("Graph.edge: could not find the \"".concat(target, "\" target node in the graph."));
-    var edgeData = sourceData.out && sourceData.out[target] || sourceData.undirected && sourceData.undirected[target] || undefined;
-    if (edgeData) return edgeData.key;
-  }
-  /**
-   * Method returning whether two nodes are directed neighbors.
-   *
-   * @param  {any}     node     - The node's key.
-   * @param  {any}     neighbor - The neighbor's key.
-   * @return {boolean}
-   *
-   * @throws {Error} - Will throw if the node isn't in the graph.
-   */
-  ;
-
-  _proto.areDirectedNeighbors = function areDirectedNeighbors(node, neighbor) {
-    node = '' + node;
-    neighbor = '' + neighbor;
-
-    var nodeData = this._nodes.get(node);
-
-    if (!nodeData) throw new NotFoundGraphError("Graph.areDirectedNeighbors: could not find the \"".concat(node, "\" node in the graph."));
-    if (this.type === 'undirected') return false;
-    return neighbor in nodeData["in"] || neighbor in nodeData.out;
-  }
-  /**
-   * Method returning whether two nodes are out neighbors.
-   *
-   * @param  {any}     node     - The node's key.
-   * @param  {any}     neighbor - The neighbor's key.
-   * @return {boolean}
-   *
-   * @throws {Error} - Will throw if the node isn't in the graph.
-   */
-  ;
-
-  _proto.areOutNeighbors = function areOutNeighbors(node, neighbor) {
-    node = '' + node;
-    neighbor = '' + neighbor;
-
-    var nodeData = this._nodes.get(node);
-
-    if (!nodeData) throw new NotFoundGraphError("Graph.areOutNeighbors: could not find the \"".concat(node, "\" node in the graph."));
-    if (this.type === 'undirected') return false;
-    return neighbor in nodeData.out;
-  }
-  /**
-   * Method returning whether two nodes are in neighbors.
-   *
-   * @param  {any}     node     - The node's key.
-   * @param  {any}     neighbor - The neighbor's key.
-   * @return {boolean}
-   *
-   * @throws {Error} - Will throw if the node isn't in the graph.
-   */
-  ;
-
-  _proto.areInNeighbors = function areInNeighbors(node, neighbor) {
-    node = '' + node;
-    neighbor = '' + neighbor;
-
-    var nodeData = this._nodes.get(node);
-
-    if (!nodeData) throw new NotFoundGraphError("Graph.areInNeighbors: could not find the \"".concat(node, "\" node in the graph."));
-    if (this.type === 'undirected') return false;
-    return neighbor in nodeData["in"];
-  }
-  /**
-   * Method returning whether two nodes are undirected neighbors.
-   *
-   * @param  {any}     node     - The node's key.
-   * @param  {any}     neighbor - The neighbor's key.
-   * @return {boolean}
-   *
-   * @throws {Error} - Will throw if the node isn't in the graph.
-   */
-  ;
-
-  _proto.areUndirectedNeighbors = function areUndirectedNeighbors(node, neighbor) {
-    node = '' + node;
-    neighbor = '' + neighbor;
-
-    var nodeData = this._nodes.get(node);
-
-    if (!nodeData) throw new NotFoundGraphError("Graph.areUndirectedNeighbors: could not find the \"".concat(node, "\" node in the graph."));
-    if (this.type === 'directed') return false;
-    return neighbor in nodeData.undirected;
-  }
-  /**
-   * Method returning whether two nodes are neighbors.
-   *
-   * @param  {any}     node     - The node's key.
-   * @param  {any}     neighbor - The neighbor's key.
-   * @return {boolean}
-   *
-   * @throws {Error} - Will throw if the node isn't in the graph.
-   */
-  ;
-
-  _proto.areNeighbors = function areNeighbors(node, neighbor) {
-    node = '' + node;
-    neighbor = '' + neighbor;
-
-    var nodeData = this._nodes.get(node);
-
-    if (!nodeData) throw new NotFoundGraphError("Graph.areNeighbors: could not find the \"".concat(node, "\" node in the graph."));
-
-    if (this.type !== 'undirected') {
-      if (neighbor in nodeData["in"] || neighbor in nodeData.out) return true;
-    }
-
-    if (this.type !== 'directed') {
-      if (neighbor in nodeData.undirected) return true;
-    }
-
-    return false;
-  }
-  /**
-   * Method returning whether two nodes are inbound neighbors.
-   *
-   * @param  {any}     node     - The node's key.
-   * @param  {any}     neighbor - The neighbor's key.
-   * @return {boolean}
-   *
-   * @throws {Error} - Will throw if the node isn't in the graph.
-   */
-  ;
-
-  _proto.areInboundNeighbors = function areInboundNeighbors(node, neighbor) {
-    node = '' + node;
-    neighbor = '' + neighbor;
-
-    var nodeData = this._nodes.get(node);
-
-    if (!nodeData) throw new NotFoundGraphError("Graph.areInboundNeighbors: could not find the \"".concat(node, "\" node in the graph."));
-
-    if (this.type !== 'undirected') {
-      if (neighbor in nodeData["in"]) return true;
-    }
-
-    if (this.type !== 'directed') {
-      if (neighbor in nodeData.undirected) return true;
-    }
-
-    return false;
-  }
-  /**
-   * Method returning whether two nodes are outbound neighbors.
-   *
-   * @param  {any}     node     - The node's key.
-   * @param  {any}     neighbor - The neighbor's key.
-   * @return {boolean}
-   *
-   * @throws {Error} - Will throw if the node isn't in the graph.
-   */
-  ;
-
-  _proto.areOutboundNeighbors = function areOutboundNeighbors(node, neighbor) {
-    node = '' + node;
-    neighbor = '' + neighbor;
-
-    var nodeData = this._nodes.get(node);
-
-    if (!nodeData) throw new NotFoundGraphError("Graph.areOutboundNeighbors: could not find the \"".concat(node, "\" node in the graph."));
-
-    if (this.type !== 'undirected') {
-      if (neighbor in nodeData.out) return true;
-    }
-
-    if (this.type !== 'directed') {
-      if (neighbor in nodeData.undirected) return true;
-    }
-
-    return false;
-  }
-  /**
-   * Method returning the given node's in degree.
-   *
-   * @param  {any}     node - The node's key.
-   * @return {number}       - The node's in degree.
-   *
-   * @throws {Error} - Will throw if the node isn't in the graph.
-   */
-  ;
-
-  _proto.inDegree = function inDegree(node) {
-    node = '' + node;
-
-    var nodeData = this._nodes.get(node);
-
-    if (!nodeData) throw new NotFoundGraphError("Graph.inDegree: could not find the \"".concat(node, "\" node in the graph."));
-    if (this.type === 'undirected') return 0;
-    return nodeData.inDegree;
-  }
-  /**
-   * Method returning the given node's out degree.
-   *
-   * @param  {any}     node - The node's key.
-   * @return {number}       - The node's in degree.
-   *
-   * @throws {Error} - Will throw if the node isn't in the graph.
-   */
-  ;
-
-  _proto.outDegree = function outDegree(node) {
-    node = '' + node;
-
-    var nodeData = this._nodes.get(node);
-
-    if (!nodeData) throw new NotFoundGraphError("Graph.outDegree: could not find the \"".concat(node, "\" node in the graph."));
-    if (this.type === 'undirected') return 0;
-    return nodeData.outDegree;
-  }
-  /**
-   * Method returning the given node's directed degree.
-   *
-   * @param  {any}     node - The node's key.
-   * @return {number}       - The node's in degree.
-   *
-   * @throws {Error} - Will throw if the node isn't in the graph.
-   */
-  ;
-
-  _proto.directedDegree = function directedDegree(node) {
-    node = '' + node;
-
-    var nodeData = this._nodes.get(node);
-
-    if (!nodeData) throw new NotFoundGraphError("Graph.directedDegree: could not find the \"".concat(node, "\" node in the graph."));
-    if (this.type === 'undirected') return 0;
-    return nodeData.inDegree + nodeData.outDegree;
-  }
-  /**
-   * Method returning the given node's undirected degree.
-   *
-   * @param  {any}     node - The node's key.
-   * @return {number}       - The node's in degree.
-   *
-   * @throws {Error} - Will throw if the node isn't in the graph.
-   */
-  ;
-
-  _proto.undirectedDegree = function undirectedDegree(node) {
-    node = '' + node;
-
-    var nodeData = this._nodes.get(node);
-
-    if (!nodeData) throw new NotFoundGraphError("Graph.undirectedDegree: could not find the \"".concat(node, "\" node in the graph."));
-    if (this.type === 'directed') return 0;
-    return nodeData.undirectedDegree;
-  }
-  /**
-   * Method returning the given node's inbound degree.
-   *
-   * @param  {any}     node - The node's key.
-   * @return {number}       - The node's inbound degree.
-   *
-   * @throws {Error} - Will throw if the node isn't in the graph.
-   */
-  ;
-
-  _proto.inboundDegree = function inboundDegree(node) {
-    node = '' + node;
-
-    var nodeData = this._nodes.get(node);
-
-    if (!nodeData) throw new NotFoundGraphError("Graph.inboundDegree: could not find the \"".concat(node, "\" node in the graph."));
-    var degree = 0;
-
-    if (this.type !== 'directed') {
-      degree += nodeData.undirectedDegree;
-    }
-
-    if (this.type !== 'undirected') {
-      degree += nodeData.inDegree;
-    }
-
-    return degree;
-  }
-  /**
-   * Method returning the given node's outbound degree.
-   *
-   * @param  {any}     node - The node's key.
-   * @return {number}       - The node's outbound degree.
-   *
-   * @throws {Error} - Will throw if the node isn't in the graph.
-   */
-  ;
-
-  _proto.outboundDegree = function outboundDegree(node) {
-    node = '' + node;
-
-    var nodeData = this._nodes.get(node);
-
-    if (!nodeData) throw new NotFoundGraphError("Graph.outboundDegree: could not find the \"".concat(node, "\" node in the graph."));
-    var degree = 0;
-
-    if (this.type !== 'directed') {
-      degree += nodeData.undirectedDegree;
-    }
-
-    if (this.type !== 'undirected') {
-      degree += nodeData.outDegree;
-    }
-
-    return degree;
-  }
-  /**
-   * Method returning the given node's directed degree.
-   *
-   * @param  {any}     node - The node's key.
-   * @return {number}       - The node's degree.
-   *
-   * @throws {Error} - Will throw if the node isn't in the graph.
-   */
-  ;
-
-  _proto.degree = function degree(node) {
-    node = '' + node;
-
-    var nodeData = this._nodes.get(node);
-
-    if (!nodeData) throw new NotFoundGraphError("Graph.degree: could not find the \"".concat(node, "\" node in the graph."));
-    var degree = 0;
-
-    if (this.type !== 'directed') {
-      degree += nodeData.undirectedDegree;
-    }
-
-    if (this.type !== 'undirected') {
-      degree += nodeData.inDegree + nodeData.outDegree;
-    }
-
-    return degree;
-  }
-  /**
-   * Method returning the given node's in degree without considering self loops.
-   *
-   * @param  {any}     node - The node's key.
-   * @return {number}       - The node's in degree.
-   *
-   * @throws {Error} - Will throw if the node isn't in the graph.
-   */
-  ;
-
-  _proto.inDegreeWithoutSelfLoops = function inDegreeWithoutSelfLoops(node) {
-    node = '' + node;
-
-    var nodeData = this._nodes.get(node);
-
-    if (!nodeData) throw new NotFoundGraphError("Graph.inDegreeWithoutSelfLoops: could not find the \"".concat(node, "\" node in the graph."));
-    if (this.type === 'undirected') return 0;
-    var self = nodeData["in"][node];
-    var loops = self ? this.multi ? self.size : 1 : 0;
-    return nodeData.inDegree - loops;
-  }
-  /**
-   * Method returning the given node's out degree without considering self loops.
-   *
-   * @param  {any}     node - The node's key.
-   * @return {number}       - The node's in degree.
-   *
-   * @throws {Error} - Will throw if the node isn't in the graph.
-   */
-  ;
-
-  _proto.outDegreeWithoutSelfLoops = function outDegreeWithoutSelfLoops(node) {
-    node = '' + node;
-
-    var nodeData = this._nodes.get(node);
-
-    if (!nodeData) throw new NotFoundGraphError("Graph.outDegreeWithoutSelfLoops: could not find the \"".concat(node, "\" node in the graph."));
-    if (this.type === 'undirected') return 0;
-    var self = nodeData.out[node];
-    var loops = self ? this.multi ? self.size : 1 : 0;
-    return nodeData.outDegree - loops;
-  }
-  /**
-   * Method returning the given node's directed degree without considering self loops.
-   *
-   * @param  {any}     node - The node's key.
-   * @return {number}       - The node's in degree.
-   *
-   * @throws {Error} - Will throw if the node isn't in the graph.
-   */
-  ;
-
-  _proto.directedDegreeWithoutSelfLoops = function directedDegreeWithoutSelfLoops(node) {
-    node = '' + node;
-
-    var nodeData = this._nodes.get(node);
-
-    if (!nodeData) throw new NotFoundGraphError("Graph.directedDegreeWithoutSelfLoops: could not find the \"".concat(node, "\" node in the graph."));
-    if (this.type === 'undirected') return 0;
-    var self = nodeData.out[node];
-    var loops = self ? this.multi ? self.size : 1 : 0;
-    return nodeData.inDegree + nodeData.outDegree - loops * 2;
-  }
-  /**
-   * Method returning the given node's undirected degree without considering self loops.
-   *
-   * @param  {any}     node - The node's key.
-   * @return {number}       - The node's in degree.
-   *
-   * @throws {Error} - Will throw if the node isn't in the graph.
-   */
-  ;
-
-  _proto.undirectedDegreeWithoutSelfLoops = function undirectedDegreeWithoutSelfLoops(node) {
-    node = '' + node;
-
-    var nodeData = this._nodes.get(node);
-
-    if (!nodeData) throw new NotFoundGraphError("Graph.undirectedDegreeWithoutSelfLoops: could not find the \"".concat(node, "\" node in the graph."));
-    if (this.type === 'directed') return 0;
-    var self = nodeData.undirected[node];
-    var loops = self ? this.multi ? self.size : 1 : 0;
-    return nodeData.undirectedDegree - loops * 2;
-  }
-  /**
-   * Method returning the given node's inbound degree without considering self loops.
-   *
-   * @param  {any}     node - The node's key.
-   * @return {number}       - The node's inbound degree.
-   *
-   * @throws {Error} - Will throw if the node isn't in the graph.
-   */
-  ;
-
-  _proto.inboundDegreeWithoutSelfLoops = function inboundDegreeWithoutSelfLoops(node) {
-    node = '' + node;
-
-    var nodeData = this._nodes.get(node);
-
-    if (!nodeData) throw new NotFoundGraphError("Graph.inboundDegreeWithoutSelfLoops: could not find the \"".concat(node, "\" node in the graph."));
-    var self;
-    var degree = 0;
-    var loops = 0;
-
-    if (this.type !== 'directed') {
-      degree += nodeData.undirectedDegree;
-      self = nodeData.undirected[node];
-      loops += (self ? this.multi ? self.size : 1 : 0) * 2;
-    }
-
-    if (this.type !== 'undirected') {
-      degree += nodeData.inDegree;
-      self = nodeData.out[node];
-      loops += self ? this.multi ? self.size : 1 : 0;
-    }
-
-    return degree - loops;
-  }
-  /**
-   * Method returning the given node's outbound degree without considering self loops.
-   *
-   * @param  {any}     node - The node's key.
-   * @return {number}       - The node's outbound degree.
-   *
-   * @throws {Error} - Will throw if the node isn't in the graph.
-   */
-  ;
-
-  _proto.outboundDegreeWithoutSelfLoops = function outboundDegreeWithoutSelfLoops(node) {
-    node = '' + node;
-
-    var nodeData = this._nodes.get(node);
-
-    if (!nodeData) throw new NotFoundGraphError("Graph.outboundDegreeWithoutSelfLoops: could not find the \"".concat(node, "\" node in the graph."));
-    var self;
-    var degree = 0;
-    var loops = 0;
-
-    if (this.type !== 'directed') {
-      degree += nodeData.undirectedDegree;
-      self = nodeData.undirected[node];
-      loops += (self ? this.multi ? self.size : 1 : 0) * 2;
-    }
-
-    if (this.type !== 'undirected') {
-      degree += nodeData.outDegree;
-      self = nodeData["in"][node];
-      loops += self ? this.multi ? self.size : 1 : 0;
-    }
-
-    return degree - loops;
-  }
-  /**
-   * Method returning the given node's directed degree without considering self loops.
-   *
-   * @param  {any}     node - The node's key.
-   * @return {number}       - The node's degree.
-   *
-   * @throws {Error} - Will throw if the node isn't in the graph.
-   */
-  ;
-
-  _proto.degreeWithoutSelfLoops = function degreeWithoutSelfLoops(node) {
-    node = '' + node;
-
-    var nodeData = this._nodes.get(node);
-
-    if (!nodeData) throw new NotFoundGraphError("Graph.degreeWithoutSelfLoops: could not find the \"".concat(node, "\" node in the graph."));
-    var self;
-    var degree = 0;
-    var loops = 0;
-
-    if (this.type !== 'directed') {
-      degree += nodeData.undirectedDegree;
-      self = nodeData.undirected[node];
-      loops += (self ? this.multi ? self.size : 1 : 0) * 2;
-    }
-
-    if (this.type !== 'undirected') {
-      degree += nodeData.inDegree + nodeData.outDegree;
-      self = nodeData.out[node];
-      loops += (self ? this.multi ? self.size : 1 : 0) * 2;
-    }
-
-    return degree - loops;
-  }
-  /**
-   * Method returning the given edge's source.
-   *
-   * @param  {any} edge - The edge's key.
-   * @return {any}      - The edge's source.
-   *
-   * @throws {Error} - Will throw if the edge isn't in the graph.
-   */
-  ;
-
-  _proto.source = function source(edge) {
-    edge = '' + edge;
-
-    var data = this._edges.get(edge);
-
-    if (!data) throw new NotFoundGraphError("Graph.source: could not find the \"".concat(edge, "\" edge in the graph."));
-    return data.source.key;
-  }
-  /**
-   * Method returning the given edge's target.
-   *
-   * @param  {any} edge - The edge's key.
-   * @return {any}      - The edge's target.
-   *
-   * @throws {Error} - Will throw if the edge isn't in the graph.
-   */
-  ;
-
-  _proto.target = function target(edge) {
-    edge = '' + edge;
-
-    var data = this._edges.get(edge);
-
-    if (!data) throw new NotFoundGraphError("Graph.target: could not find the \"".concat(edge, "\" edge in the graph."));
-    return data.target.key;
-  }
-  /**
-   * Method returning the given edge's extremities.
-   *
-   * @param  {any}   edge - The edge's key.
-   * @return {array}      - The edge's extremities.
-   *
-   * @throws {Error} - Will throw if the edge isn't in the graph.
-   */
-  ;
-
-  _proto.extremities = function extremities(edge) {
-    edge = '' + edge;
-
-    var edgeData = this._edges.get(edge);
-
-    if (!edgeData) throw new NotFoundGraphError("Graph.extremities: could not find the \"".concat(edge, "\" edge in the graph."));
-    return [edgeData.source.key, edgeData.target.key];
-  }
-  /**
-   * Given a node & an edge, returns the other extremity of the edge.
-   *
-   * @param  {any}   node - The node's key.
-   * @param  {any}   edge - The edge's key.
-   * @return {any}        - The related node.
-   *
-   * @throws {Error} - Will throw if the edge isn't in the graph or if the
-   *                   edge & node are not related.
-   */
-  ;
-
-  _proto.opposite = function opposite(node, edge) {
-    node = '' + node;
-    edge = '' + edge;
-
-    var data = this._edges.get(edge);
-
-    if (!data) throw new NotFoundGraphError("Graph.opposite: could not find the \"".concat(edge, "\" edge in the graph."));
-    var source = data.source.key;
-    var target = data.target.key;
-    if (node === source) return target;
-    if (node === target) return source;
-    throw new NotFoundGraphError("Graph.opposite: the \"".concat(node, "\" node is not attached to the \"").concat(edge, "\" edge (").concat(source, ", ").concat(target, ")."));
-  }
-  /**
-   * Returns whether the given edge has the given node as extremity.
-   *
-   * @param  {any}     edge - The edge's key.
-   * @param  {any}     node - The node's key.
-   * @return {boolean}      - The related node.
-   *
-   * @throws {Error} - Will throw if either the node or the edge isn't in the graph.
-   */
-  ;
-
-  _proto.hasExtremity = function hasExtremity(edge, node) {
-    edge = '' + edge;
-    node = '' + node;
-
-    var data = this._edges.get(edge);
-
-    if (!data) throw new NotFoundGraphError("Graph.hasExtremity: could not find the \"".concat(edge, "\" edge in the graph."));
-    return data.source.key === node || data.target.key === node;
-  }
-  /**
-   * Method returning whether the given edge is undirected.
-   *
-   * @param  {any}     edge - The edge's key.
-   * @return {boolean}
-   *
-   * @throws {Error} - Will throw if the edge isn't in the graph.
-   */
-  ;
-
-  _proto.isUndirected = function isUndirected(edge) {
-    edge = '' + edge;
-
-    var data = this._edges.get(edge);
-
-    if (!data) throw new NotFoundGraphError("Graph.isUndirected: could not find the \"".concat(edge, "\" edge in the graph."));
-    return data.undirected;
-  }
-  /**
-   * Method returning whether the given edge is directed.
-   *
-   * @param  {any}     edge - The edge's key.
-   * @return {boolean}
-   *
-   * @throws {Error} - Will throw if the edge isn't in the graph.
-   */
-  ;
-
-  _proto.isDirected = function isDirected(edge) {
-    edge = '' + edge;
-
-    var data = this._edges.get(edge);
-
-    if (!data) throw new NotFoundGraphError("Graph.isDirected: could not find the \"".concat(edge, "\" edge in the graph."));
-    return !data.undirected;
-  }
-  /**
-   * Method returning whether the given edge is a self loop.
-   *
-   * @param  {any}     edge - The edge's key.
-   * @return {boolean}
-   *
-   * @throws {Error} - Will throw if the edge isn't in the graph.
-   */
-  ;
-
-  _proto.isSelfLoop = function isSelfLoop(edge) {
-    edge = '' + edge;
-
-    var data = this._edges.get(edge);
-
-    if (!data) throw new NotFoundGraphError("Graph.isSelfLoop: could not find the \"".concat(edge, "\" edge in the graph."));
-    return data.source === data.target;
-  }
-  /**---------------------------------------------------------------------------
-   * Mutation
-   **---------------------------------------------------------------------------
-   */
-
-  /**
-   * Method used to add a node to the graph.
-   *
-   * @param  {any}    node         - The node.
-   * @param  {object} [attributes] - Optional attributes.
-   * @return {any}                 - The node.
-   *
-   * @throws {Error} - Will throw if the given node already exist.
-   * @throws {Error} - Will throw if the given attributes are not an object.
-   */
-  ;
-
-  _proto.addNode = function addNode(node, attributes) {
-    var nodeData = _addNode(this, node, attributes);
-
-    return nodeData.key;
-  }
-  /**
-   * Method used to merge a node into the graph.
-   *
-   * @param  {any}    node         - The node.
-   * @param  {object} [attributes] - Optional attributes.
-   * @return {any}                 - The node.
-   */
-  ;
-
-  _proto.mergeNode = function mergeNode(node, attributes) {
-    if (attributes && !isPlainObject(attributes)) throw new InvalidArgumentsGraphError("Graph.mergeNode: invalid attributes. Expecting an object but got \"".concat(attributes, "\"")); // String coercion
-
-    node = '' + node;
-    attributes = attributes || {}; // If the node already exists, we merge the attributes
-
-    var data = this._nodes.get(node);
-
-    if (data) {
-      if (attributes) {
-        assign(data.attributes, attributes);
-        this.emit('nodeAttributesUpdated', {
-          type: 'merge',
-          key: node,
-          attributes: data.attributes,
-          data: attributes
-        });
-      }
-
-      return [node, false];
-    }
-
-    data = new this.NodeDataClass(node, attributes); // Adding the node to internal register
-
-    this._nodes.set(node, data); // Emitting
-
-
-    this.emit('nodeAdded', {
-      key: node,
-      attributes: attributes
-    });
-    return [node, true];
-  }
-  /**
-   * Method used to add a node if it does not exist in the graph or else to
-   * update its attributes using a function.
-   *
-   * @param  {any}      node      - The node.
-   * @param  {function} [updater] - Optional updater function.
-   * @return {any}                - The node.
-   */
-  ;
-
-  _proto.updateNode = function updateNode(node, updater) {
-    if (updater && typeof updater !== 'function') throw new InvalidArgumentsGraphError("Graph.updateNode: invalid updater function. Expecting a function but got \"".concat(updater, "\"")); // String coercion
-
-    node = '' + node; // If the node already exists, we update the attributes
-
-    var data = this._nodes.get(node);
-
-    if (data) {
-      if (updater) {
-        var oldAttributes = data.attributes;
-        data.attributes = updater(oldAttributes);
-        this.emit('nodeAttributesUpdated', {
-          type: 'replace',
-          key: node,
-          attributes: data.attributes
-        });
-      }
-
-      return [node, false];
-    }
-
-    var attributes = updater ? updater({}) : {};
-    data = new this.NodeDataClass(node, attributes); // Adding the node to internal register
-
-    this._nodes.set(node, data); // Emitting
-
-
-    this.emit('nodeAdded', {
-      key: node,
-      attributes: attributes
-    });
-    return [node, true];
-  }
-  /**
-   * Method used to drop a single node & all its attached edges from the graph.
-   *
-   * @param  {any}    node - The node.
-   * @return {Graph}
-   *
-   * @throws {Error} - Will throw if the node doesn't exist.
-   */
-  ;
-
-  _proto.dropNode = function dropNode(node) {
-    node = '' + node;
-
-    var nodeData = this._nodes.get(node);
-
-    if (!nodeData) throw new NotFoundGraphError("Graph.dropNode: could not find the \"".concat(node, "\" node in the graph."));
-    var edgeData; // Removing attached edges
-    // NOTE: we could be faster here, but this is such a pain to maintain
-
-    if (this.type !== 'undirected') {
-      for (var neighbor in nodeData.out) {
-        edgeData = nodeData.out[neighbor];
-
-        do {
-          dropEdgeFromData(this, edgeData);
-          edgeData = edgeData.next;
-        } while (edgeData);
-      }
-
-      for (var _neighbor in nodeData["in"]) {
-        edgeData = nodeData["in"][_neighbor];
-
-        do {
-          dropEdgeFromData(this, edgeData);
-          edgeData = edgeData.next;
-        } while (edgeData);
-      }
-    }
-
-    if (this.type !== 'directed') {
-      for (var _neighbor2 in nodeData.undirected) {
-        edgeData = nodeData.undirected[_neighbor2];
-
-        do {
-          dropEdgeFromData(this, edgeData);
-          edgeData = edgeData.next;
-        } while (edgeData);
-      }
-    } // Dropping the node from the register
-
-
-    this._nodes["delete"](node); // Emitting
-
-
-    this.emit('nodeDropped', {
-      key: node,
-      attributes: nodeData.attributes
-    });
-  }
-  /**
-   * Method used to drop a single edge from the graph.
-   *
-   * Arity 1:
-   * @param  {any}    edge - The edge.
-   *
-   * Arity 2:
-   * @param  {any}    source - Source node.
-   * @param  {any}    target - Target node.
-   *
-   * @return {Graph}
-   *
-   * @throws {Error} - Will throw if the edge doesn't exist.
-   */
-  ;
-
-  _proto.dropEdge = function dropEdge(edge) {
-    var edgeData;
-
-    if (arguments.length > 1) {
-      var source = '' + arguments[0];
-      var target = '' + arguments[1];
-      edgeData = getMatchingEdge(this, source, target, this.type);
-      if (!edgeData) throw new NotFoundGraphError("Graph.dropEdge: could not find the \"".concat(source, "\" -> \"").concat(target, "\" edge in the graph."));
-    } else {
-      edge = '' + edge;
-      edgeData = this._edges.get(edge);
-      if (!edgeData) throw new NotFoundGraphError("Graph.dropEdge: could not find the \"".concat(edge, "\" edge in the graph."));
-    }
-
-    dropEdgeFromData(this, edgeData);
-    return this;
-  }
-  /**
-   * Method used to drop a single directed edge from the graph.
-   *
-   * @param  {any}    source - Source node.
-   * @param  {any}    target - Target node.
-   *
-   * @return {Graph}
-   *
-   * @throws {Error} - Will throw if the edge doesn't exist.
-   */
-  ;
-
-  _proto.dropDirectedEdge = function dropDirectedEdge(source, target) {
-    if (arguments.length < 2) throw new UsageGraphError('Graph.dropDirectedEdge: it does not make sense to try and drop a directed edge by key. What if the edge with this key is undirected? Use #.dropEdge for this purpose instead.');
-    if (this.multi) throw new UsageGraphError('Graph.dropDirectedEdge: cannot use a {source,target} combo when dropping an edge in a MultiGraph since we cannot infer the one you want to delete as there could be multiple ones.');
-    source = '' + source;
-    target = '' + target;
-    var edgeData = getMatchingEdge(this, source, target, 'directed');
-    if (!edgeData) throw new NotFoundGraphError("Graph.dropDirectedEdge: could not find a \"".concat(source, "\" -> \"").concat(target, "\" edge in the graph."));
-    dropEdgeFromData(this, edgeData);
-    return this;
-  }
-  /**
-   * Method used to drop a single undirected edge from the graph.
-   *
-   * @param  {any}    source - Source node.
-   * @param  {any}    target - Target node.
-   *
-   * @return {Graph}
-   *
-   * @throws {Error} - Will throw if the edge doesn't exist.
-   */
-  ;
-
-  _proto.dropUndirectedEdge = function dropUndirectedEdge(source, target) {
-    if (arguments.length < 2) throw new UsageGraphError('Graph.dropUndirectedEdge: it does not make sense to drop a directed edge by key. What if the edge with this key is undirected? Use #.dropEdge for this purpose instead.');
-    if (this.multi) throw new UsageGraphError('Graph.dropUndirectedEdge: cannot use a {source,target} combo when dropping an edge in a MultiGraph since we cannot infer the one you want to delete as there could be multiple ones.');
-    var edgeData = getMatchingEdge(this, source, target, 'undirected');
-    if (!edgeData) throw new NotFoundGraphError("Graph.dropUndirectedEdge: could not find a \"".concat(source, "\" -> \"").concat(target, "\" edge in the graph."));
-    dropEdgeFromData(this, edgeData);
-    return this;
-  }
-  /**
-   * Method used to remove every edge & every node from the graph.
-   *
-   * @return {Graph}
-   */
-  ;
-
-  _proto.clear = function clear() {
-    // Clearing edges
-    this._edges.clear(); // Clearing nodes
-
-
-    this._nodes.clear(); // Reset counters
-
-
-    this._resetInstanceCounters(); // Emitting
-
-
-    this.emit('cleared');
-  }
-  /**
-   * Method used to remove every edge from the graph.
-   *
-   * @return {Graph}
-   */
-  ;
-
-  _proto.clearEdges = function clearEdges() {
-    // Clearing structure index
-    var iterator = this._nodes.values();
-
-    var step;
-
-    while (step = iterator.next(), step.done !== true) {
-      step.value.clear();
-    } // Clearing edges
-
-
-    this._edges.clear(); // Reset counters
-
-
-    this._resetInstanceCounters(); // Emitting
-
-
-    this.emit('edgesCleared');
-  }
-  /**---------------------------------------------------------------------------
-   * Attributes-related methods
-   **---------------------------------------------------------------------------
-   */
-
-  /**
-   * Method returning the desired graph's attribute.
-   *
-   * @param  {string} name - Name of the attribute.
-   * @return {any}
-   */
-  ;
-
-  _proto.getAttribute = function getAttribute(name) {
-    return this._attributes[name];
-  }
-  /**
-   * Method returning the graph's attributes.
-   *
-   * @return {object}
-   */
-  ;
-
-  _proto.getAttributes = function getAttributes() {
-    return this._attributes;
-  }
-  /**
-   * Method returning whether the graph has the desired attribute.
-   *
-   * @param  {string}  name - Name of the attribute.
-   * @return {boolean}
-   */
-  ;
-
-  _proto.hasAttribute = function hasAttribute(name) {
-    return this._attributes.hasOwnProperty(name);
-  }
-  /**
-   * Method setting a value for the desired graph's attribute.
-   *
-   * @param  {string}  name  - Name of the attribute.
-   * @param  {any}     value - Value for the attribute.
-   * @return {Graph}
-   */
-  ;
-
-  _proto.setAttribute = function setAttribute(name, value) {
-    this._attributes[name] = value; // Emitting
-
-    this.emit('attributesUpdated', {
-      type: 'set',
-      attributes: this._attributes,
-      name: name
-    });
-    return this;
-  }
-  /**
-   * Method using a function to update the desired graph's attribute's value.
-   *
-   * @param  {string}   name    - Name of the attribute.
-   * @param  {function} updater - Function use to update the attribute's value.
-   * @return {Graph}
-   */
-  ;
-
-  _proto.updateAttribute = function updateAttribute(name, updater) {
-    if (typeof updater !== 'function') throw new InvalidArgumentsGraphError('Graph.updateAttribute: updater should be a function.');
-    var value = this._attributes[name];
-    this._attributes[name] = updater(value); // Emitting
-
-    this.emit('attributesUpdated', {
-      type: 'set',
-      attributes: this._attributes,
-      name: name
-    });
-    return this;
-  }
-  /**
-   * Method removing the desired graph's attribute.
-   *
-   * @param  {string} name  - Name of the attribute.
-   * @return {Graph}
-   */
-  ;
-
-  _proto.removeAttribute = function removeAttribute(name) {
-    delete this._attributes[name]; // Emitting
-
-    this.emit('attributesUpdated', {
-      type: 'remove',
-      attributes: this._attributes,
-      name: name
-    });
-    return this;
-  }
-  /**
-   * Method replacing the graph's attributes.
-   *
-   * @param  {object} attributes - New attributes.
-   * @return {Graph}
-   *
-   * @throws {Error} - Will throw if given attributes are not a plain object.
-   */
-  ;
-
-  _proto.replaceAttributes = function replaceAttributes(attributes) {
-    if (!isPlainObject(attributes)) throw new InvalidArgumentsGraphError('Graph.replaceAttributes: provided attributes are not a plain object.');
-    this._attributes = attributes; // Emitting
-
-    this.emit('attributesUpdated', {
-      type: 'replace',
-      attributes: this._attributes
-    });
-    return this;
-  }
-  /**
-   * Method merging the graph's attributes.
-   *
-   * @param  {object} attributes - Attributes to merge.
-   * @return {Graph}
-   *
-   * @throws {Error} - Will throw if given attributes are not a plain object.
-   */
-  ;
-
-  _proto.mergeAttributes = function mergeAttributes(attributes) {
-    if (!isPlainObject(attributes)) throw new InvalidArgumentsGraphError('Graph.mergeAttributes: provided attributes are not a plain object.');
-    assign(this._attributes, attributes); // Emitting
-
-    this.emit('attributesUpdated', {
-      type: 'merge',
-      attributes: this._attributes,
-      data: attributes
-    });
-    return this;
-  }
-  /**
-   * Method updating the graph's attributes.
-   *
-   * @param  {function} updater - Function used to update the attributes.
-   * @return {Graph}
-   *
-   * @throws {Error} - Will throw if given updater is not a function.
-   */
-  ;
-
-  _proto.updateAttributes = function updateAttributes(updater) {
-    if (typeof updater !== 'function') throw new InvalidArgumentsGraphError('Graph.updateAttributes: provided updater is not a function.');
-    this._attributes = updater(this._attributes); // Emitting
-
-    this.emit('attributesUpdated', {
-      type: 'update',
-      attributes: this._attributes
-    });
-    return this;
-  }
-  /**
-   * Method used to update each node's attributes using the given function.
-   *
-   * @param {function}  updater - Updater function to use.
-   * @param {object}    [hints] - Optional hints.
-   */
-  ;
-
-  _proto.updateEachNodeAttributes = function updateEachNodeAttributes(updater, hints) {
-    if (typeof updater !== 'function') throw new InvalidArgumentsGraphError('Graph.updateEachNodeAttributes: expecting an updater function.');
-    if (hints && !validateHints(hints)) throw new InvalidArgumentsGraphError('Graph.updateEachNodeAttributes: invalid hints. Expecting an object having the following shape: {attributes?: [string]}');
-
-    var iterator = this._nodes.values();
-
-    var step, nodeData;
-
-    while (step = iterator.next(), step.done !== true) {
-      nodeData = step.value;
-      nodeData.attributes = updater(nodeData.key, nodeData.attributes);
-    }
-
-    this.emit('eachNodeAttributesUpdated', {
-      hints: hints ? hints : null
-    });
-  }
-  /**
-   * Method used to update each edge's attributes using the given function.
-   *
-   * @param {function}  updater - Updater function to use.
-   * @param {object}    [hints] - Optional hints.
-   */
-  ;
-
-  _proto.updateEachEdgeAttributes = function updateEachEdgeAttributes(updater, hints) {
-    if (typeof updater !== 'function') throw new InvalidArgumentsGraphError('Graph.updateEachEdgeAttributes: expecting an updater function.');
-    if (hints && !validateHints(hints)) throw new InvalidArgumentsGraphError('Graph.updateEachEdgeAttributes: invalid hints. Expecting an object having the following shape: {attributes?: [string]}');
-
-    var iterator = this._edges.values();
-
-    var step, edgeData, sourceData, targetData;
-
-    while (step = iterator.next(), step.done !== true) {
-      edgeData = step.value;
-      sourceData = edgeData.source;
-      targetData = edgeData.target;
-      edgeData.attributes = updater(edgeData.key, edgeData.attributes, sourceData.key, targetData.key, sourceData.attributes, targetData.attributes, edgeData.undirected);
-    }
-
-    this.emit('eachEdgeAttributesUpdated', {
-      hints: hints ? hints : null
-    });
-  }
-  /**---------------------------------------------------------------------------
-   * Iteration-related methods
-   **---------------------------------------------------------------------------
-   */
-
-  /**
-   * Method iterating over the graph's adjacency using the given callback.
-   *
-   * @param  {function}  callback - Callback to use.
-   */
-  ;
-
-  _proto.forEachAdjacencyEntry = function forEachAdjacencyEntry(callback) {
-    if (typeof callback !== 'function') throw new InvalidArgumentsGraphError('Graph.forEachAdjacencyEntry: expecting a callback.');
-    forEachAdjacency(false, false, false, this, callback);
-  };
-
-  _proto.forEachAdjacencyEntryWithOrphans = function forEachAdjacencyEntryWithOrphans(callback) {
-    if (typeof callback !== 'function') throw new InvalidArgumentsGraphError('Graph.forEachAdjacencyEntryWithOrphans: expecting a callback.');
-    forEachAdjacency(false, false, true, this, callback);
-  }
-  /**
-   * Method iterating over the graph's assymetric adjacency using the given callback.
-   *
-   * @param  {function}  callback - Callback to use.
-   */
-  ;
-
-  _proto.forEachAssymetricAdjacencyEntry = function forEachAssymetricAdjacencyEntry(callback) {
-    if (typeof callback !== 'function') throw new InvalidArgumentsGraphError('Graph.forEachAssymetricAdjacencyEntry: expecting a callback.');
-    forEachAdjacency(false, true, false, this, callback);
-  };
-
-  _proto.forEachAssymetricAdjacencyEntryWithOrphans = function forEachAssymetricAdjacencyEntryWithOrphans(callback) {
-    if (typeof callback !== 'function') throw new InvalidArgumentsGraphError('Graph.forEachAssymetricAdjacencyEntryWithOrphans: expecting a callback.');
-    forEachAdjacency(false, true, true, this, callback);
-  }
-  /**
-   * Method returning the list of the graph's nodes.
-   *
-   * @return {array} - The nodes.
-   */
-  ;
-
-  _proto.nodes = function nodes() {
-    if (typeof Array.from === 'function') return Array.from(this._nodes.keys());
-    return take__default["default"](this._nodes.keys(), this._nodes.size);
-  }
-  /**
-   * Method iterating over the graph's nodes using the given callback.
-   *
-   * @param  {function}  callback - Callback (key, attributes, index).
-   */
-  ;
-
-  _proto.forEachNode = function forEachNode(callback) {
-    if (typeof callback !== 'function') throw new InvalidArgumentsGraphError('Graph.forEachNode: expecting a callback.');
-
-    var iterator = this._nodes.values();
-
-    var step, nodeData;
-
-    while (step = iterator.next(), step.done !== true) {
-      nodeData = step.value;
-      callback(nodeData.key, nodeData.attributes);
-    }
-  }
-  /**
-   * Method iterating attempting to find a node matching the given predicate
-   * function.
-   *
-   * @param  {function}  callback - Callback (key, attributes).
-   */
-  ;
-
-  _proto.findNode = function findNode(callback) {
-    if (typeof callback !== 'function') throw new InvalidArgumentsGraphError('Graph.findNode: expecting a callback.');
-
-    var iterator = this._nodes.values();
-
-    var step, nodeData;
-
-    while (step = iterator.next(), step.done !== true) {
-      nodeData = step.value;
-      if (callback(nodeData.key, nodeData.attributes)) return nodeData.key;
-    }
-
-    return;
-  }
-  /**
-   * Method mapping nodes.
-   *
-   * @param  {function}  callback - Callback (key, attributes).
-   */
-  ;
-
-  _proto.mapNodes = function mapNodes(callback) {
-    if (typeof callback !== 'function') throw new InvalidArgumentsGraphError('Graph.mapNode: expecting a callback.');
-
-    var iterator = this._nodes.values();
-
-    var step, nodeData;
-    var result = new Array(this.order);
-    var i = 0;
-
-    while (step = iterator.next(), step.done !== true) {
-      nodeData = step.value;
-      result[i++] = callback(nodeData.key, nodeData.attributes);
-    }
-
-    return result;
-  }
-  /**
-   * Method returning whether some node verify the given predicate.
-   *
-   * @param  {function}  callback - Callback (key, attributes).
-   */
-  ;
-
-  _proto.someNode = function someNode(callback) {
-    if (typeof callback !== 'function') throw new InvalidArgumentsGraphError('Graph.someNode: expecting a callback.');
-
-    var iterator = this._nodes.values();
-
-    var step, nodeData;
-
-    while (step = iterator.next(), step.done !== true) {
-      nodeData = step.value;
-      if (callback(nodeData.key, nodeData.attributes)) return true;
-    }
-
-    return false;
-  }
-  /**
-   * Method returning whether all node verify the given predicate.
-   *
-   * @param  {function}  callback - Callback (key, attributes).
-   */
-  ;
-
-  _proto.everyNode = function everyNode(callback) {
-    if (typeof callback !== 'function') throw new InvalidArgumentsGraphError('Graph.everyNode: expecting a callback.');
-
-    var iterator = this._nodes.values();
-
-    var step, nodeData;
-
-    while (step = iterator.next(), step.done !== true) {
-      nodeData = step.value;
-      if (!callback(nodeData.key, nodeData.attributes)) return false;
-    }
-
-    return true;
-  }
-  /**
-   * Method filtering nodes.
-   *
-   * @param  {function}  callback - Callback (key, attributes).
-   */
-  ;
-
-  _proto.filterNodes = function filterNodes(callback) {
-    if (typeof callback !== 'function') throw new InvalidArgumentsGraphError('Graph.filterNodes: expecting a callback.');
-
-    var iterator = this._nodes.values();
-
-    var step, nodeData;
-    var result = [];
-
-    while (step = iterator.next(), step.done !== true) {
-      nodeData = step.value;
-      if (callback(nodeData.key, nodeData.attributes)) result.push(nodeData.key);
-    }
-
-    return result;
-  }
-  /**
-   * Method reducing nodes.
-   *
-   * @param  {function}  callback - Callback (accumulator, key, attributes).
-   */
-  ;
-
-  _proto.reduceNodes = function reduceNodes(callback, initialValue) {
-    if (typeof callback !== 'function') throw new InvalidArgumentsGraphError('Graph.reduceNodes: expecting a callback.');
-    if (arguments.length < 2) throw new InvalidArgumentsGraphError('Graph.reduceNodes: missing initial value. You must provide it because the callback takes more than one argument and we cannot infer the initial value from the first iteration, as you could with a simple array.');
-    var accumulator = initialValue;
-
-    var iterator = this._nodes.values();
-
-    var step, nodeData;
-
-    while (step = iterator.next(), step.done !== true) {
-      nodeData = step.value;
-      accumulator = callback(accumulator, nodeData.key, nodeData.attributes);
-    }
-
-    return accumulator;
-  }
-  /**
-   * Method returning an iterator over the graph's node entries.
-   *
-   * @return {Iterator}
-   */
-  ;
-
-  _proto.nodeEntries = function nodeEntries() {
-    var iterator = this._nodes.values();
-
-    return new Iterator__default["default"](function () {
-      var step = iterator.next();
-      if (step.done) return step;
-      var data = step.value;
-      return {
-        value: {
-          node: data.key,
-          attributes: data.attributes
-        },
-        done: false
-      };
-    });
-  }
-  /**---------------------------------------------------------------------------
-   * Serialization
-   **---------------------------------------------------------------------------
-   */
-
-  /**
-   * Method used to export the whole graph.
-   *
-   * @return {object} - The serialized graph.
-   */
-  ;
-
-  _proto["export"] = function _export() {
-    var nodes = new Array(this._nodes.size);
-    var i = 0;
-
-    this._nodes.forEach(function (data, key) {
-      nodes[i++] = serializeNode(key, data);
-    });
-
-    var edges = new Array(this._edges.size);
-    i = 0;
-
-    this._edges.forEach(function (data, key) {
-      edges[i++] = serializeEdge(key, data);
-    });
-
-    return {
-      options: {
-        type: this.type,
-        multi: this.multi,
-        allowSelfLoops: this.allowSelfLoops
-      },
-      attributes: this.getAttributes(),
-      nodes: nodes,
-      edges: edges
-    };
-  }
-  /**
-   * Method used to import a serialized graph.
-   *
-   * @param  {object|Graph} data  - The serialized graph.
-   * @param  {boolean}      merge - Whether to merge data.
-   * @return {Graph}              - Returns itself for chaining.
-   */
-  ;
-
-  _proto["import"] = function _import(data) {
-    var _this2 = this;
-
-    var merge = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
-
-    // Importing a Graph instance directly
-    if (isGraph(data)) {
-      // Nodes
-      data.forEachNode(function (n, a) {
-        if (merge) _this2.mergeNode(n, a);else _this2.addNode(n, a);
-      }); // Edges
-
-      data.forEachEdge(function (e, a, s, t, _sa, _ta, u) {
-        if (merge) {
-          if (u) _this2.mergeUndirectedEdgeWithKey(e, s, t, a);else _this2.mergeDirectedEdgeWithKey(e, s, t, a);
-        } else {
-          if (u) _this2.addUndirectedEdgeWithKey(e, s, t, a);else _this2.addDirectedEdgeWithKey(e, s, t, a);
-        }
-      });
-      return this;
-    } // Importing a serialized graph
-
-
-    if (!isPlainObject(data)) throw new InvalidArgumentsGraphError('Graph.import: invalid argument. Expecting a serialized graph or, alternatively, a Graph instance.');
-
-    if (data.attributes) {
-      if (!isPlainObject(data.attributes)) throw new InvalidArgumentsGraphError('Graph.import: invalid attributes. Expecting a plain object.');
-      if (merge) this.mergeAttributes(data.attributes);else this.replaceAttributes(data.attributes);
-    }
-
-    var i, l, list, node, edge;
-
-    if (data.nodes) {
-      list = data.nodes;
-      if (!Array.isArray(list)) throw new InvalidArgumentsGraphError('Graph.import: invalid nodes. Expecting an array.');
-
-      for (i = 0, l = list.length; i < l; i++) {
-        node = list[i]; // Validating
-
-        validateSerializedNode(node); // Adding the node
-
-        var _node = node,
-            key = _node.key,
-            attributes = _node.attributes;
-        if (merge) this.mergeNode(key, attributes);else this.addNode(key, attributes);
-      }
-    }
-
-    if (data.edges) {
-      list = data.edges;
-      if (!Array.isArray(list)) throw new InvalidArgumentsGraphError('Graph.import: invalid edges. Expecting an array.');
-
-      for (i = 0, l = list.length; i < l; i++) {
-        edge = list[i]; // Validating
-
-        validateSerializedEdge(edge); // Adding the edge
-
-        var _edge = edge,
-            source = _edge.source,
-            target = _edge.target,
-            _attributes = _edge.attributes,
-            _edge$undirected = _edge.undirected,
-            undirected = _edge$undirected === void 0 ? false : _edge$undirected;
-        var method = void 0;
-
-        if ('key' in edge) {
-          method = merge ? undirected ? this.mergeUndirectedEdgeWithKey : this.mergeDirectedEdgeWithKey : undirected ? this.addUndirectedEdgeWithKey : this.addDirectedEdgeWithKey;
-          method.call(this, edge.key, source, target, _attributes);
-        } else {
-          method = merge ? undirected ? this.mergeUndirectedEdge : this.mergeDirectedEdge : undirected ? this.addUndirectedEdge : this.addDirectedEdge;
-          method.call(this, source, target, _attributes);
-        }
-      }
-    }
-
-    return this;
-  }
-  /**---------------------------------------------------------------------------
-   * Utils
-   **---------------------------------------------------------------------------
-   */
-
-  /**
-   * Method returning a null copy of the graph, i.e. a graph without nodes
-   * & edges but with the exact same options.
-   *
-   * @param  {object} options - Options to merge with the current ones.
-   * @return {Graph}          - The null copy.
-   */
-  ;
-
-  _proto.nullCopy = function nullCopy(options) {
-    var graph = new Graph(assign({}, this._options, options));
-    graph.replaceAttributes(assign({}, this.getAttributes()));
-    return graph;
-  }
-  /**
-   * Method returning an empty copy of the graph, i.e. a graph without edges but
-   * with the exact same options.
-   *
-   * @param  {object} options - Options to merge with the current ones.
-   * @return {Graph}          - The empty copy.
-   */
-  ;
-
-  _proto.emptyCopy = function emptyCopy(options) {
-    var graph = this.nullCopy(options);
-
-    this._nodes.forEach(function (nodeData, key) {
-      var attributes = assign({}, nodeData.attributes); // NOTE: no need to emit events since user cannot access the instance yet
-
-      nodeData = new graph.NodeDataClass(key, attributes);
-
-      graph._nodes.set(key, nodeData);
-    });
-
-    return graph;
-  }
-  /**
-   * Method returning an exact copy of the graph.
-   *
-   * @param  {object} options - Upgrade options.
-   * @return {Graph}          - The copy.
-   */
-  ;
-
-  _proto.copy = function copy(options) {
-    options = options || {};
-    if (typeof options.type === 'string' && options.type !== this.type && options.type !== 'mixed') throw new UsageGraphError("Graph.copy: cannot create an incompatible copy from \"".concat(this.type, "\" type to \"").concat(options.type, "\" because this would mean losing information about the current graph."));
-    if (typeof options.multi === 'boolean' && options.multi !== this.multi && options.multi !== true) throw new UsageGraphError('Graph.copy: cannot create an incompatible copy by downgrading a multi graph to a simple one because this would mean losing information about the current graph.');
-    if (typeof options.allowSelfLoops === 'boolean' && options.allowSelfLoops !== this.allowSelfLoops && options.allowSelfLoops !== true) throw new UsageGraphError('Graph.copy: cannot create an incompatible copy from a graph allowing self loops to one that does not because this would mean losing information about the current graph.');
-    var graph = this.emptyCopy(options);
-
-    var iterator = this._edges.values();
-
-    var step, edgeData;
-
-    while (step = iterator.next(), step.done !== true) {
-      edgeData = step.value; // NOTE: no need to emit events since user cannot access the instance yet
-
-      addEdge(graph, 'copy', false, edgeData.undirected, edgeData.key, edgeData.source.key, edgeData.target.key, assign({}, edgeData.attributes));
-    }
-
-    return graph;
-  }
-  /**---------------------------------------------------------------------------
-   * Known methods
-   **---------------------------------------------------------------------------
-   */
-
-  /**
-   * Method used by JavaScript to perform JSON serialization.
-   *
-   * @return {object} - The serialized graph.
-   */
-  ;
-
-  _proto.toJSON = function toJSON() {
-    return this["export"]();
-  }
-  /**
-   * Method returning [object Graph].
-   */
-  ;
-
-  _proto.toString = function toString() {
-    return '[object Graph]';
-  }
-  /**
-   * Method used internally by node's console to display a custom object.
-   *
-   * @return {object} - Formatted object representation of the graph.
-   */
-  ;
-
-  _proto.inspect = function inspect() {
-    var _this3 = this;
-
-    var nodes = {};
-
-    this._nodes.forEach(function (data, key) {
-      nodes[key] = data.attributes;
-    });
-
-    var edges = {},
-        multiIndex = {};
-
-    this._edges.forEach(function (data, key) {
-      var direction = data.undirected ? '--' : '->';
-      var label = '';
-      var source = data.source.key;
-      var target = data.target.key;
-      var tmp;
-
-      if (data.undirected && source > target) {
-        tmp = source;
-        source = target;
-        target = tmp;
-      }
-
-      var desc = "(".concat(source, ")").concat(direction, "(").concat(target, ")");
-
-      if (!key.startsWith('geid_')) {
-        label += "[".concat(key, "]: ");
-      } else if (_this3.multi) {
-        if (typeof multiIndex[desc] === 'undefined') {
-          multiIndex[desc] = 0;
-        } else {
-          multiIndex[desc]++;
-        }
-
-        label += "".concat(multiIndex[desc], ". ");
-      }
-
-      label += desc;
-      edges[label] = data.attributes;
-    });
-
-    var dummy = {};
-
-    for (var k in this) {
-      if (this.hasOwnProperty(k) && !EMITTER_PROPS.has(k) && typeof this[k] !== 'function' && _typeof(k) !== 'symbol') dummy[k] = this[k];
-    }
-
-    dummy.attributes = this._attributes;
-    dummy.nodes = nodes;
-    dummy.edges = edges;
-    privateProperty(dummy, 'constructor', this.constructor);
-    return dummy;
-  };
-
-  return Graph;
-}(events.EventEmitter);
-if (typeof Symbol !== 'undefined') Graph.prototype[Symbol["for"]('nodejs.util.inspect.custom')] = Graph.prototype.inspect;
-/**
- * Related to edge addition.
- */
-
-EDGE_ADD_METHODS.forEach(function (method) {
-  ['add', 'merge', 'update'].forEach(function (verb) {
-    var name = method.name(verb);
-    var fn = verb === 'add' ? addEdge : mergeEdge;
-
-    if (method.generateKey) {
-      Graph.prototype[name] = function (source, target, attributes) {
-        return fn(this, name, true, (method.type || this.type) === 'undirected', null, source, target, attributes, verb === 'update');
-      };
-    } else {
-      Graph.prototype[name] = function (edge, source, target, attributes) {
-        return fn(this, name, false, (method.type || this.type) === 'undirected', edge, source, target, attributes, verb === 'update');
-      };
-    }
-  });
-});
-/**
- * Attributes-related.
- */
-
-attachNodeAttributesMethods(Graph);
-attachEdgeAttributesMethods(Graph);
-/**
- * Edge iteration-related.
- */
-
-attachEdgeIterationMethods(Graph);
-/**
- * Neighbor iteration-related.
- */
-
-attachNeighborIterationMethods(Graph);
-
-/**
- * Alternative constructors.
- */
-
-var DirectedGraph = /*#__PURE__*/function (_Graph) {
-  _inheritsLoose(DirectedGraph, _Graph);
-
-  function DirectedGraph(options) {
-    var finalOptions = assign({
-      type: 'directed'
-    }, options);
-    if ('multi' in finalOptions && finalOptions.multi !== false) throw new InvalidArgumentsGraphError('DirectedGraph.from: inconsistent indication that the graph should be multi in given options!');
-    if (finalOptions.type !== 'directed') throw new InvalidArgumentsGraphError('DirectedGraph.from: inconsistent "' + finalOptions.type + '" type in given options!');
-    return _Graph.call(this, finalOptions) || this;
-  }
-
-  return DirectedGraph;
-}(Graph);
-
-var UndirectedGraph = /*#__PURE__*/function (_Graph2) {
-  _inheritsLoose(UndirectedGraph, _Graph2);
-
-  function UndirectedGraph(options) {
-    var finalOptions = assign({
-      type: 'undirected'
-    }, options);
-    if ('multi' in finalOptions && finalOptions.multi !== false) throw new InvalidArgumentsGraphError('UndirectedGraph.from: inconsistent indication that the graph should be multi in given options!');
-    if (finalOptions.type !== 'undirected') throw new InvalidArgumentsGraphError('UndirectedGraph.from: inconsistent "' + finalOptions.type + '" type in given options!');
-    return _Graph2.call(this, finalOptions) || this;
-  }
-
-  return UndirectedGraph;
-}(Graph);
-
-var MultiGraph = /*#__PURE__*/function (_Graph3) {
-  _inheritsLoose(MultiGraph, _Graph3);
-
-  function MultiGraph(options) {
-    var finalOptions = assign({
-      multi: true
-    }, options);
-    if ('multi' in finalOptions && finalOptions.multi !== true) throw new InvalidArgumentsGraphError('MultiGraph.from: inconsistent indication that the graph should be simple in given options!');
-    return _Graph3.call(this, finalOptions) || this;
-  }
-
-  return MultiGraph;
-}(Graph);
-
-var MultiDirectedGraph = /*#__PURE__*/function (_Graph4) {
-  _inheritsLoose(MultiDirectedGraph, _Graph4);
-
-  function MultiDirectedGraph(options) {
-    var finalOptions = assign({
-      type: 'directed',
-      multi: true
-    }, options);
-    if ('multi' in finalOptions && finalOptions.multi !== true) throw new InvalidArgumentsGraphError('MultiDirectedGraph.from: inconsistent indication that the graph should be simple in given options!');
-    if (finalOptions.type !== 'directed') throw new InvalidArgumentsGraphError('MultiDirectedGraph.from: inconsistent "' + finalOptions.type + '" type in given options!');
-    return _Graph4.call(this, finalOptions) || this;
-  }
-
-  return MultiDirectedGraph;
-}(Graph);
-
-var MultiUndirectedGraph = /*#__PURE__*/function (_Graph5) {
-  _inheritsLoose(MultiUndirectedGraph, _Graph5);
-
-  function MultiUndirectedGraph(options) {
-    var finalOptions = assign({
-      type: 'undirected',
-      multi: true
-    }, options);
-    if ('multi' in finalOptions && finalOptions.multi !== true) throw new InvalidArgumentsGraphError('MultiUndirectedGraph.from: inconsistent indication that the graph should be simple in given options!');
-    if (finalOptions.type !== 'undirected') throw new InvalidArgumentsGraphError('MultiUndirectedGraph.from: inconsistent "' + finalOptions.type + '" type in given options!');
-    return _Graph5.call(this, finalOptions) || this;
-  }
-
-  return MultiUndirectedGraph;
-}(Graph);
-/**
- * Attaching static #.from method to each of the constructors.
- */
-
-
-function attachStaticFromMethod(Class) {
-  /**
-   * Builds a graph from serialized data or another graph's data.
-   *
-   * @param  {Graph|SerializedGraph} data      - Hydratation data.
-   * @param  {object}                [options] - Options.
-   * @return {Class}
-   */
-  Class.from = function (data, options) {
-    // Merging given options with serialized ones
-    var finalOptions = assign({}, data.options, options);
-    var instance = new Class(finalOptions);
-    instance["import"](data);
-    return instance;
-  };
-}
-
-attachStaticFromMethod(Graph);
-attachStaticFromMethod(DirectedGraph);
-attachStaticFromMethod(UndirectedGraph);
-attachStaticFromMethod(MultiGraph);
-attachStaticFromMethod(MultiDirectedGraph);
-attachStaticFromMethod(MultiUndirectedGraph);
-Graph.Graph = Graph;
-Graph.DirectedGraph = DirectedGraph;
-Graph.UndirectedGraph = UndirectedGraph;
-Graph.MultiGraph = MultiGraph;
-Graph.MultiDirectedGraph = MultiDirectedGraph;
-Graph.MultiUndirectedGraph = MultiUndirectedGraph;
-Graph.InvalidArgumentsGraphError = InvalidArgumentsGraphError;
-Graph.NotFoundGraphError = NotFoundGraphError;
-Graph.UsageGraphError = UsageGraphError;
-
-/**
- * Graphology CommonJS Endoint
- * ============================
- *
- * Endpoint for CommonJS modules consumers.
- */
-
-module.exports = Graph;
-//# sourceMappingURL=graphology.cjs.js.map
diff --git a/libs/shared/graph-layouts/node_modules/graphology/dist/graphology.d.ts b/libs/shared/graph-layouts/node_modules/graphology/dist/graphology.d.ts
deleted file mode 100644
index d2f14ffca..000000000
--- a/libs/shared/graph-layouts/node_modules/graphology/dist/graphology.d.ts
+++ /dev/null
@@ -1,36 +0,0 @@
-import {AbstractGraph, Attributes} from 'graphology-types';
-
-export default class Graph<
-  NodeAttributes extends Attributes = Attributes,
-  EdgeAttributes extends Attributes = Attributes,
-  GraphAttributes extends Attributes = Attributes
-> extends AbstractGraph<NodeAttributes, EdgeAttributes, GraphAttributes> {}
-export class DirectedGraph<
-  NodeAttributes extends Attributes = Attributes,
-  EdgeAttributes extends Attributes = Attributes,
-  GraphAttributes extends Attributes = Attributes
-> extends Graph<NodeAttributes, EdgeAttributes, GraphAttributes> {}
-export class UndirectedGraph<
-  NodeAttributes extends Attributes = Attributes,
-  EdgeAttributes extends Attributes = Attributes,
-  GraphAttributes extends Attributes = Attributes
-> extends Graph<NodeAttributes, EdgeAttributes, GraphAttributes> {}
-export class MultiGraph<
-  NodeAttributes extends Attributes = Attributes,
-  EdgeAttributes extends Attributes = Attributes,
-  GraphAttributes extends Attributes = Attributes
-> extends Graph<NodeAttributes, EdgeAttributes, GraphAttributes> {}
-export class MultiDirectedGraph<
-  NodeAttributes extends Attributes = Attributes,
-  EdgeAttributes extends Attributes = Attributes,
-  GraphAttributes extends Attributes = Attributes
-> extends Graph<NodeAttributes, EdgeAttributes, GraphAttributes> {}
-export class MultiUndirectedGraph<
-  NodeAttributes extends Attributes = Attributes,
-  EdgeAttributes extends Attributes = Attributes,
-  GraphAttributes extends Attributes = Attributes
-> extends Graph<NodeAttributes, EdgeAttributes, GraphAttributes> {}
-
-export class InvalidArgumentsGraphError extends Error {}
-export class NotFoundGraphError extends Error {}
-export class UsageGraphError extends Error {}
diff --git a/libs/shared/graph-layouts/node_modules/graphology/dist/graphology.esm.js b/libs/shared/graph-layouts/node_modules/graphology/dist/graphology.esm.js
deleted file mode 100644
index f89b5be2e..000000000
--- a/libs/shared/graph-layouts/node_modules/graphology/dist/graphology.esm.js
+++ /dev/null
@@ -1,6671 +0,0 @@
-import { EventEmitter } from 'events';
-import Iterator from 'obliterator/iterator';
-import take from 'obliterator/take';
-import chain from 'obliterator/chain';
-
-/**
- * Graphology Utilities
- * =====================
- *
- * Collection of helpful functions used by the implementation.
- */
-
-/**
- * Object.assign-like polyfill.
- *
- * @param  {object} target       - First object.
- * @param  {object} [...objects] - Objects to merge.
- * @return {object}
- */
-function assignPolyfill() {
-  const target = arguments[0];
-
-  for (let i = 1, l = arguments.length; i < l; i++) {
-    if (!arguments[i]) continue;
-
-    for (const k in arguments[i]) target[k] = arguments[i][k];
-  }
-
-  return target;
-}
-
-let assign = assignPolyfill;
-
-if (typeof Object.assign === 'function') assign = Object.assign;
-
-/**
- * Function returning the first matching edge for given path.
- * Note: this function does not check the existence of source & target. This
- * must be performed by the caller.
- *
- * @param  {Graph}  graph  - Target graph.
- * @param  {any}    source - Source node.
- * @param  {any}    target - Target node.
- * @param  {string} type   - Type of the edge (mixed, directed or undirected).
- * @return {string|null}
- */
-function getMatchingEdge(graph, source, target, type) {
-  const sourceData = graph._nodes.get(source);
-
-  let edge = null;
-
-  if (!sourceData) return edge;
-
-  if (type === 'mixed') {
-    edge =
-      (sourceData.out && sourceData.out[target]) ||
-      (sourceData.undirected && sourceData.undirected[target]);
-  } else if (type === 'directed') {
-    edge = sourceData.out && sourceData.out[target];
-  } else {
-    edge = sourceData.undirected && sourceData.undirected[target];
-  }
-
-  return edge;
-}
-
-/**
- * Checks whether the given value is a Graph implementation instance.
- *
- * @param  {mixed}   value - Target value.
- * @return {boolean}
- */
-function isGraph(value) {
-  return (
-    value !== null &&
-    typeof value === 'object' &&
-    typeof value.addUndirectedEdgeWithKey === 'function' &&
-    typeof value.dropNode === 'function'
-  );
-}
-
-/**
- * Checks whether the given value is a plain object.
- *
- * @param  {mixed}   value - Target value.
- * @return {boolean}
- */
-function isPlainObject(value) {
-  return (
-    typeof value === 'object' && value !== null && value.constructor === Object
-  );
-}
-
-/**
- * Checks whether the given object is empty.
- *
- * @param  {object}  o - Target Object.
- * @return {boolean}
- */
-function isEmpty(o) {
-  let k;
-
-  for (k in o) return false;
-
-  return true;
-}
-
-/**
- * Creates a "private" property for the given member name by concealing it
- * using the `enumerable` option.
- *
- * @param {object} target - Target object.
- * @param {string} name   - Member name.
- */
-function privateProperty(target, name, value) {
-  Object.defineProperty(target, name, {
-    enumerable: false,
-    configurable: false,
-    writable: true,
-    value
-  });
-}
-
-/**
- * Creates a read-only property for the given member name & the given getter.
- *
- * @param {object}   target - Target object.
- * @param {string}   name   - Member name.
- * @param {mixed}    value  - The attached getter or fixed value.
- */
-function readOnlyProperty(target, name, value) {
-  const descriptor = {
-    enumerable: true,
-    configurable: true
-  };
-
-  if (typeof value === 'function') {
-    descriptor.get = value;
-  } else {
-    descriptor.value = value;
-    descriptor.writable = false;
-  }
-
-  Object.defineProperty(target, name, descriptor);
-}
-
-/**
- * Returns whether the given object constitute valid hints.
- *
- * @param {object} hints - Target object.
- */
-function validateHints(hints) {
-  if (!isPlainObject(hints)) return false;
-
-  if (hints.attributes && !Array.isArray(hints.attributes)) return false;
-
-  return true;
-}
-
-/**
- * Creates a function generating incremental ids for edges.
- *
- * @return {function}
- */
-function incrementalIdStartingFromRandomByte() {
-  let i = Math.floor(Math.random() * 256) & 0xff;
-
-  return () => {
-    return i++;
-  };
-}
-
-/**
- * Graphology Custom Errors
- * =========================
- *
- * Defining custom errors for ease of use & easy unit tests across
- * implementations (normalized typology rather than relying on error
- * messages to check whether the correct error was found).
- */
-class GraphError extends Error {
-  constructor(message) {
-    super();
-    this.name = 'GraphError';
-    this.message = message;
-  }
-}
-
-class InvalidArgumentsGraphError extends GraphError {
-  constructor(message) {
-    super(message);
-    this.name = 'InvalidArgumentsGraphError';
-
-    // This is V8 specific to enhance stack readability
-    if (typeof Error.captureStackTrace === 'function')
-      Error.captureStackTrace(
-        this,
-        InvalidArgumentsGraphError.prototype.constructor
-      );
-  }
-}
-
-class NotFoundGraphError extends GraphError {
-  constructor(message) {
-    super(message);
-    this.name = 'NotFoundGraphError';
-
-    // This is V8 specific to enhance stack readability
-    if (typeof Error.captureStackTrace === 'function')
-      Error.captureStackTrace(this, NotFoundGraphError.prototype.constructor);
-  }
-}
-
-class UsageGraphError extends GraphError {
-  constructor(message) {
-    super(message);
-    this.name = 'UsageGraphError';
-
-    // This is V8 specific to enhance stack readability
-    if (typeof Error.captureStackTrace === 'function')
-      Error.captureStackTrace(this, UsageGraphError.prototype.constructor);
-  }
-}
-
-/**
- * Graphology Internal Data Classes
- * =================================
- *
- * Internal classes hopefully reduced to structs by engines & storing
- * necessary information for nodes & edges.
- *
- * Note that those classes don't rely on the `class` keyword to avoid some
- * cruft introduced by most of ES2015 transpilers.
- */
-
-/**
- * MixedNodeData class.
- *
- * @constructor
- * @param {string} string     - The node's key.
- * @param {object} attributes - Node's attributes.
- */
-function MixedNodeData(key, attributes) {
-  // Attributes
-  this.key = key;
-  this.attributes = attributes;
-
-  this.clear();
-}
-
-MixedNodeData.prototype.clear = function () {
-  // Degrees
-  this.inDegree = 0;
-  this.outDegree = 0;
-  this.undirectedDegree = 0;
-
-  // Indices
-  this.in = {};
-  this.out = {};
-  this.undirected = {};
-};
-
-/**
- * DirectedNodeData class.
- *
- * @constructor
- * @param {string} string     - The node's key.
- * @param {object} attributes - Node's attributes.
- */
-function DirectedNodeData(key, attributes) {
-  // Attributes
-  this.key = key;
-  this.attributes = attributes;
-
-  this.clear();
-}
-
-DirectedNodeData.prototype.clear = function () {
-  // Degrees
-  this.inDegree = 0;
-  this.outDegree = 0;
-
-  // Indices
-  this.in = {};
-  this.out = {};
-};
-
-/**
- * UndirectedNodeData class.
- *
- * @constructor
- * @param {string} string     - The node's key.
- * @param {object} attributes - Node's attributes.
- */
-function UndirectedNodeData(key, attributes) {
-  // Attributes
-  this.key = key;
-  this.attributes = attributes;
-
-  this.clear();
-}
-
-UndirectedNodeData.prototype.clear = function () {
-  // Degrees
-  this.undirectedDegree = 0;
-
-  // Indices
-  this.undirected = {};
-};
-
-/**
- * EdgeData class.
- *
- * @constructor
- * @param {boolean} undirected   - Whether the edge is undirected.
- * @param {string}  string       - The edge's key.
- * @param {string}  source       - Source of the edge.
- * @param {string}  target       - Target of the edge.
- * @param {object}  attributes   - Edge's attributes.
- */
-function EdgeData(undirected, key, source, target, attributes) {
-  // Attributes
-  this.key = key;
-  this.attributes = attributes;
-  this.undirected = undirected;
-
-  // Extremities
-  this.source = source;
-  this.target = target;
-}
-
-EdgeData.prototype.attach = function () {
-  let outKey = 'out';
-  let inKey = 'in';
-
-  if (this.undirected) outKey = inKey = 'undirected';
-
-  const source = this.source.key;
-  const target = this.target.key;
-
-  // Handling source
-  this.source[outKey][target] = this;
-
-  if (this.undirected && source === target) return;
-
-  // Handling target
-  this.target[inKey][source] = this;
-};
-
-EdgeData.prototype.attachMulti = function () {
-  let outKey = 'out';
-  let inKey = 'in';
-
-  const source = this.source.key;
-  const target = this.target.key;
-
-  if (this.undirected) outKey = inKey = 'undirected';
-
-  // Handling source
-  const adj = this.source[outKey];
-  const head = adj[target];
-
-  if (typeof head === 'undefined') {
-    adj[target] = this;
-
-    // Self-loop optimization
-    if (!(this.undirected && source === target)) {
-      // Handling target
-      this.target[inKey][source] = this;
-    }
-
-    return;
-  }
-
-  // Prepending to doubly-linked list
-  head.previous = this;
-  this.next = head;
-
-  // Pointing to new head
-  // NOTE: use mutating swap later to avoid lookup?
-  adj[target] = this;
-  this.target[inKey][source] = this;
-};
-
-EdgeData.prototype.detach = function () {
-  const source = this.source.key;
-  const target = this.target.key;
-
-  let outKey = 'out';
-  let inKey = 'in';
-
-  if (this.undirected) outKey = inKey = 'undirected';
-
-  delete this.source[outKey][target];
-
-  // No-op delete in case of undirected self-loop
-  delete this.target[inKey][source];
-};
-
-EdgeData.prototype.detachMulti = function () {
-  const source = this.source.key;
-  const target = this.target.key;
-
-  let outKey = 'out';
-  let inKey = 'in';
-
-  if (this.undirected) outKey = inKey = 'undirected';
-
-  // Deleting from doubly-linked list
-  if (this.previous === undefined) {
-    // We are dealing with the head
-
-    // Should we delete the adjacency entry because it is now empty?
-    if (this.next === undefined) {
-      delete this.source[outKey][target];
-
-      // No-op delete in case of undirected self-loop
-      delete this.target[inKey][source];
-    } else {
-      // Detaching
-      this.next.previous = undefined;
-
-      // NOTE: could avoid the lookups by creating a #.become mutating method
-      this.source[outKey][target] = this.next;
-
-      // No-op delete in case of undirected self-loop
-      this.target[inKey][source] = this.next;
-    }
-  } else {
-    // We are dealing with another list node
-    this.previous.next = this.next;
-
-    // If not last
-    if (this.next !== undefined) {
-      this.next.previous = this.previous;
-    }
-  }
-};
-
-/**
- * Graphology Node Attributes methods
- * ===================================
- */
-
-const NODE = 0;
-const SOURCE = 1;
-const TARGET = 2;
-const OPPOSITE = 3;
-
-function findRelevantNodeData(
-  graph,
-  method,
-  mode,
-  nodeOrEdge,
-  nameOrEdge,
-  add1,
-  add2
-) {
-  let nodeData, edgeData, arg1, arg2;
-
-  nodeOrEdge = '' + nodeOrEdge;
-
-  if (mode === NODE) {
-    nodeData = graph._nodes.get(nodeOrEdge);
-
-    if (!nodeData)
-      throw new NotFoundGraphError(
-        `Graph.${method}: could not find the "${nodeOrEdge}" node in the graph.`
-      );
-
-    arg1 = nameOrEdge;
-    arg2 = add1;
-  } else if (mode === OPPOSITE) {
-    nameOrEdge = '' + nameOrEdge;
-
-    edgeData = graph._edges.get(nameOrEdge);
-
-    if (!edgeData)
-      throw new NotFoundGraphError(
-        `Graph.${method}: could not find the "${nameOrEdge}" edge in the graph.`
-      );
-
-    const source = edgeData.source.key;
-    const target = edgeData.target.key;
-
-    if (nodeOrEdge === source) {
-      nodeData = edgeData.target;
-    } else if (nodeOrEdge === target) {
-      nodeData = edgeData.source;
-    } else {
-      throw new NotFoundGraphError(
-        `Graph.${method}: the "${nodeOrEdge}" node is not attached to the "${nameOrEdge}" edge (${source}, ${target}).`
-      );
-    }
-
-    arg1 = add1;
-    arg2 = add2;
-  } else {
-    edgeData = graph._edges.get(nodeOrEdge);
-
-    if (!edgeData)
-      throw new NotFoundGraphError(
-        `Graph.${method}: could not find the "${nodeOrEdge}" edge in the graph.`
-      );
-
-    if (mode === SOURCE) {
-      nodeData = edgeData.source;
-    } else {
-      nodeData = edgeData.target;
-    }
-
-    arg1 = nameOrEdge;
-    arg2 = add1;
-  }
-
-  return [nodeData, arg1, arg2];
-}
-
-function attachNodeAttributeGetter(Class, method, mode) {
-  Class.prototype[method] = function (nodeOrEdge, nameOrEdge, add1) {
-    const [data, name] = findRelevantNodeData(
-      this,
-      method,
-      mode,
-      nodeOrEdge,
-      nameOrEdge,
-      add1
-    );
-
-    return data.attributes[name];
-  };
-}
-
-function attachNodeAttributesGetter(Class, method, mode) {
-  Class.prototype[method] = function (nodeOrEdge, nameOrEdge) {
-    const [data] = findRelevantNodeData(
-      this,
-      method,
-      mode,
-      nodeOrEdge,
-      nameOrEdge
-    );
-
-    return data.attributes;
-  };
-}
-
-function attachNodeAttributeChecker(Class, method, mode) {
-  Class.prototype[method] = function (nodeOrEdge, nameOrEdge, add1) {
-    const [data, name] = findRelevantNodeData(
-      this,
-      method,
-      mode,
-      nodeOrEdge,
-      nameOrEdge,
-      add1
-    );
-
-    return data.attributes.hasOwnProperty(name);
-  };
-}
-
-function attachNodeAttributeSetter(Class, method, mode) {
-  Class.prototype[method] = function (nodeOrEdge, nameOrEdge, add1, add2) {
-    const [data, name, value] = findRelevantNodeData(
-      this,
-      method,
-      mode,
-      nodeOrEdge,
-      nameOrEdge,
-      add1,
-      add2
-    );
-
-    data.attributes[name] = value;
-
-    // Emitting
-    this.emit('nodeAttributesUpdated', {
-      key: data.key,
-      type: 'set',
-      attributes: data.attributes,
-      name
-    });
-
-    return this;
-  };
-}
-
-function attachNodeAttributeUpdater(Class, method, mode) {
-  Class.prototype[method] = function (nodeOrEdge, nameOrEdge, add1, add2) {
-    const [data, name, updater] = findRelevantNodeData(
-      this,
-      method,
-      mode,
-      nodeOrEdge,
-      nameOrEdge,
-      add1,
-      add2
-    );
-
-    if (typeof updater !== 'function')
-      throw new InvalidArgumentsGraphError(
-        `Graph.${method}: updater should be a function.`
-      );
-
-    const attributes = data.attributes;
-    const value = updater(attributes[name]);
-
-    attributes[name] = value;
-
-    // Emitting
-    this.emit('nodeAttributesUpdated', {
-      key: data.key,
-      type: 'set',
-      attributes: data.attributes,
-      name
-    });
-
-    return this;
-  };
-}
-
-function attachNodeAttributeRemover(Class, method, mode) {
-  Class.prototype[method] = function (nodeOrEdge, nameOrEdge, add1) {
-    const [data, name] = findRelevantNodeData(
-      this,
-      method,
-      mode,
-      nodeOrEdge,
-      nameOrEdge,
-      add1
-    );
-
-    delete data.attributes[name];
-
-    // Emitting
-    this.emit('nodeAttributesUpdated', {
-      key: data.key,
-      type: 'remove',
-      attributes: data.attributes,
-      name
-    });
-
-    return this;
-  };
-}
-
-function attachNodeAttributesReplacer(Class, method, mode) {
-  Class.prototype[method] = function (nodeOrEdge, nameOrEdge, add1) {
-    const [data, attributes] = findRelevantNodeData(
-      this,
-      method,
-      mode,
-      nodeOrEdge,
-      nameOrEdge,
-      add1
-    );
-
-    if (!isPlainObject(attributes))
-      throw new InvalidArgumentsGraphError(
-        `Graph.${method}: provided attributes are not a plain object.`
-      );
-
-    data.attributes = attributes;
-
-    // Emitting
-    this.emit('nodeAttributesUpdated', {
-      key: data.key,
-      type: 'replace',
-      attributes: data.attributes
-    });
-
-    return this;
-  };
-}
-
-function attachNodeAttributesMerger(Class, method, mode) {
-  Class.prototype[method] = function (nodeOrEdge, nameOrEdge, add1) {
-    const [data, attributes] = findRelevantNodeData(
-      this,
-      method,
-      mode,
-      nodeOrEdge,
-      nameOrEdge,
-      add1
-    );
-
-    if (!isPlainObject(attributes))
-      throw new InvalidArgumentsGraphError(
-        `Graph.${method}: provided attributes are not a plain object.`
-      );
-
-    assign(data.attributes, attributes);
-
-    // Emitting
-    this.emit('nodeAttributesUpdated', {
-      key: data.key,
-      type: 'merge',
-      attributes: data.attributes,
-      data: attributes
-    });
-
-    return this;
-  };
-}
-
-function attachNodeAttributesUpdater(Class, method, mode) {
-  Class.prototype[method] = function (nodeOrEdge, nameOrEdge, add1) {
-    const [data, updater] = findRelevantNodeData(
-      this,
-      method,
-      mode,
-      nodeOrEdge,
-      nameOrEdge,
-      add1
-    );
-
-    if (typeof updater !== 'function')
-      throw new InvalidArgumentsGraphError(
-        `Graph.${method}: provided updater is not a function.`
-      );
-
-    data.attributes = updater(data.attributes);
-
-    // Emitting
-    this.emit('nodeAttributesUpdated', {
-      key: data.key,
-      type: 'update',
-      attributes: data.attributes
-    });
-
-    return this;
-  };
-}
-
-/**
- * List of methods to attach.
- */
-const NODE_ATTRIBUTES_METHODS = [
-  {
-    name: element => `get${element}Attribute`,
-    attacher: attachNodeAttributeGetter
-  },
-  {
-    name: element => `get${element}Attributes`,
-    attacher: attachNodeAttributesGetter
-  },
-  {
-    name: element => `has${element}Attribute`,
-    attacher: attachNodeAttributeChecker
-  },
-  {
-    name: element => `set${element}Attribute`,
-    attacher: attachNodeAttributeSetter
-  },
-  {
-    name: element => `update${element}Attribute`,
-    attacher: attachNodeAttributeUpdater
-  },
-  {
-    name: element => `remove${element}Attribute`,
-    attacher: attachNodeAttributeRemover
-  },
-  {
-    name: element => `replace${element}Attributes`,
-    attacher: attachNodeAttributesReplacer
-  },
-  {
-    name: element => `merge${element}Attributes`,
-    attacher: attachNodeAttributesMerger
-  },
-  {
-    name: element => `update${element}Attributes`,
-    attacher: attachNodeAttributesUpdater
-  }
-];
-
-/**
- * Attach every attributes-related methods to a Graph class.
- *
- * @param {function} Graph - Target class.
- */
-function attachNodeAttributesMethods(Graph) {
-  NODE_ATTRIBUTES_METHODS.forEach(function ({name, attacher}) {
-    // For nodes
-    attacher(Graph, name('Node'), NODE);
-
-    // For sources
-    attacher(Graph, name('Source'), SOURCE);
-
-    // For targets
-    attacher(Graph, name('Target'), TARGET);
-
-    // For opposites
-    attacher(Graph, name('Opposite'), OPPOSITE);
-  });
-}
-
-/**
- * Graphology Edge Attributes methods
- * ===================================
- */
-
-/**
- * Attach an attribute getter method onto the provided class.
- *
- * @param {function} Class         - Target class.
- * @param {string}   method        - Method name.
- * @param {string}   type          - Type of the edge to find.
- */
-function attachEdgeAttributeGetter(Class, method, type) {
-  /**
-   * Get the desired attribute for the given element (node or edge).
-   *
-   * Arity 2:
-   * @param  {any}    element - Target element.
-   * @param  {string} name    - Attribute's name.
-   *
-   * Arity 3 (only for edges):
-   * @param  {any}     source - Source element.
-   * @param  {any}     target - Target element.
-   * @param  {string}  name   - Attribute's name.
-   *
-   * @return {mixed}          - The attribute's value.
-   *
-   * @throws {Error} - Will throw if too many arguments are provided.
-   * @throws {Error} - Will throw if any of the elements is not found.
-   */
-  Class.prototype[method] = function (element, name) {
-    let data;
-
-    if (this.type !== 'mixed' && type !== 'mixed' && type !== this.type)
-      throw new UsageGraphError(
-        `Graph.${method}: cannot find this type of edges in your ${this.type} graph.`
-      );
-
-    if (arguments.length > 2) {
-      if (this.multi)
-        throw new UsageGraphError(
-          `Graph.${method}: cannot use a {source,target} combo when asking about an edge's attributes in a MultiGraph since we cannot infer the one you want information about.`
-        );
-
-      const source = '' + element;
-      const target = '' + name;
-
-      name = arguments[2];
-
-      data = getMatchingEdge(this, source, target, type);
-
-      if (!data)
-        throw new NotFoundGraphError(
-          `Graph.${method}: could not find an edge for the given path ("${source}" - "${target}").`
-        );
-    } else {
-      if (type !== 'mixed')
-        throw new UsageGraphError(
-          `Graph.${method}: calling this method with only a key (vs. a source and target) does not make sense since an edge with this key could have the other type.`
-        );
-
-      element = '' + element;
-      data = this._edges.get(element);
-
-      if (!data)
-        throw new NotFoundGraphError(
-          `Graph.${method}: could not find the "${element}" edge in the graph.`
-        );
-    }
-
-    return data.attributes[name];
-  };
-}
-
-/**
- * Attach an attributes getter method onto the provided class.
- *
- * @param {function} Class       - Target class.
- * @param {string}   method      - Method name.
- * @param {string}   type        - Type of the edge to find.
- */
-function attachEdgeAttributesGetter(Class, method, type) {
-  /**
-   * Retrieves all the target element's attributes.
-   *
-   * Arity 2:
-   * @param  {any}    element - Target element.
-   *
-   * Arity 3 (only for edges):
-   * @param  {any}     source - Source element.
-   * @param  {any}     target - Target element.
-   *
-   * @return {object}          - The element's attributes.
-   *
-   * @throws {Error} - Will throw if too many arguments are provided.
-   * @throws {Error} - Will throw if any of the elements is not found.
-   */
-  Class.prototype[method] = function (element) {
-    let data;
-
-    if (this.type !== 'mixed' && type !== 'mixed' && type !== this.type)
-      throw new UsageGraphError(
-        `Graph.${method}: cannot find this type of edges in your ${this.type} graph.`
-      );
-
-    if (arguments.length > 1) {
-      if (this.multi)
-        throw new UsageGraphError(
-          `Graph.${method}: cannot use a {source,target} combo when asking about an edge's attributes in a MultiGraph since we cannot infer the one you want information about.`
-        );
-
-      const source = '' + element,
-        target = '' + arguments[1];
-
-      data = getMatchingEdge(this, source, target, type);
-
-      if (!data)
-        throw new NotFoundGraphError(
-          `Graph.${method}: could not find an edge for the given path ("${source}" - "${target}").`
-        );
-    } else {
-      if (type !== 'mixed')
-        throw new UsageGraphError(
-          `Graph.${method}: calling this method with only a key (vs. a source and target) does not make sense since an edge with this key could have the other type.`
-        );
-
-      element = '' + element;
-      data = this._edges.get(element);
-
-      if (!data)
-        throw new NotFoundGraphError(
-          `Graph.${method}: could not find the "${element}" edge in the graph.`
-        );
-    }
-
-    return data.attributes;
-  };
-}
-
-/**
- * Attach an attribute checker method onto the provided class.
- *
- * @param {function} Class       - Target class.
- * @param {string}   method      - Method name.
- * @param {string}   type        - Type of the edge to find.
- */
-function attachEdgeAttributeChecker(Class, method, type) {
-  /**
-   * Checks whether the desired attribute is set for the given element (node or edge).
-   *
-   * Arity 2:
-   * @param  {any}    element - Target element.
-   * @param  {string} name    - Attribute's name.
-   *
-   * Arity 3 (only for edges):
-   * @param  {any}     source - Source element.
-   * @param  {any}     target - Target element.
-   * @param  {string}  name   - Attribute's name.
-   *
-   * @return {boolean}
-   *
-   * @throws {Error} - Will throw if too many arguments are provided.
-   * @throws {Error} - Will throw if any of the elements is not found.
-   */
-  Class.prototype[method] = function (element, name) {
-    let data;
-
-    if (this.type !== 'mixed' && type !== 'mixed' && type !== this.type)
-      throw new UsageGraphError(
-        `Graph.${method}: cannot find this type of edges in your ${this.type} graph.`
-      );
-
-    if (arguments.length > 2) {
-      if (this.multi)
-        throw new UsageGraphError(
-          `Graph.${method}: cannot use a {source,target} combo when asking about an edge's attributes in a MultiGraph since we cannot infer the one you want information about.`
-        );
-
-      const source = '' + element;
-      const target = '' + name;
-
-      name = arguments[2];
-
-      data = getMatchingEdge(this, source, target, type);
-
-      if (!data)
-        throw new NotFoundGraphError(
-          `Graph.${method}: could not find an edge for the given path ("${source}" - "${target}").`
-        );
-    } else {
-      if (type !== 'mixed')
-        throw new UsageGraphError(
-          `Graph.${method}: calling this method with only a key (vs. a source and target) does not make sense since an edge with this key could have the other type.`
-        );
-
-      element = '' + element;
-      data = this._edges.get(element);
-
-      if (!data)
-        throw new NotFoundGraphError(
-          `Graph.${method}: could not find the "${element}" edge in the graph.`
-        );
-    }
-
-    return data.attributes.hasOwnProperty(name);
-  };
-}
-
-/**
- * Attach an attribute setter method onto the provided class.
- *
- * @param {function} Class         - Target class.
- * @param {string}   method        - Method name.
- * @param {string}   type          - Type of the edge to find.
- */
-function attachEdgeAttributeSetter(Class, method, type) {
-  /**
-   * Set the desired attribute for the given element (node or edge).
-   *
-   * Arity 2:
-   * @param  {any}    element - Target element.
-   * @param  {string} name    - Attribute's name.
-   * @param  {mixed}  value   - New attribute value.
-   *
-   * Arity 3 (only for edges):
-   * @param  {any}     source - Source element.
-   * @param  {any}     target - Target element.
-   * @param  {string}  name   - Attribute's name.
-   * @param  {mixed}  value   - New attribute value.
-   *
-   * @return {Graph}          - Returns itself for chaining.
-   *
-   * @throws {Error} - Will throw if too many arguments are provided.
-   * @throws {Error} - Will throw if any of the elements is not found.
-   */
-  Class.prototype[method] = function (element, name, value) {
-    let data;
-
-    if (this.type !== 'mixed' && type !== 'mixed' && type !== this.type)
-      throw new UsageGraphError(
-        `Graph.${method}: cannot find this type of edges in your ${this.type} graph.`
-      );
-
-    if (arguments.length > 3) {
-      if (this.multi)
-        throw new UsageGraphError(
-          `Graph.${method}: cannot use a {source,target} combo when asking about an edge's attributes in a MultiGraph since we cannot infer the one you want information about.`
-        );
-
-      const source = '' + element;
-      const target = '' + name;
-
-      name = arguments[2];
-      value = arguments[3];
-
-      data = getMatchingEdge(this, source, target, type);
-
-      if (!data)
-        throw new NotFoundGraphError(
-          `Graph.${method}: could not find an edge for the given path ("${source}" - "${target}").`
-        );
-    } else {
-      if (type !== 'mixed')
-        throw new UsageGraphError(
-          `Graph.${method}: calling this method with only a key (vs. a source and target) does not make sense since an edge with this key could have the other type.`
-        );
-
-      element = '' + element;
-      data = this._edges.get(element);
-
-      if (!data)
-        throw new NotFoundGraphError(
-          `Graph.${method}: could not find the "${element}" edge in the graph.`
-        );
-    }
-
-    data.attributes[name] = value;
-
-    // Emitting
-    this.emit('edgeAttributesUpdated', {
-      key: data.key,
-      type: 'set',
-      attributes: data.attributes,
-      name
-    });
-
-    return this;
-  };
-}
-
-/**
- * Attach an attribute updater method onto the provided class.
- *
- * @param {function} Class         - Target class.
- * @param {string}   method        - Method name.
- * @param {string}   type          - Type of the edge to find.
- */
-function attachEdgeAttributeUpdater(Class, method, type) {
-  /**
-   * Update the desired attribute for the given element (node or edge) using
-   * the provided function.
-   *
-   * Arity 2:
-   * @param  {any}      element - Target element.
-   * @param  {string}   name    - Attribute's name.
-   * @param  {function} updater - Updater function.
-   *
-   * Arity 3 (only for edges):
-   * @param  {any}      source  - Source element.
-   * @param  {any}      target  - Target element.
-   * @param  {string}   name    - Attribute's name.
-   * @param  {function} updater - Updater function.
-   *
-   * @return {Graph}            - Returns itself for chaining.
-   *
-   * @throws {Error} - Will throw if too many arguments are provided.
-   * @throws {Error} - Will throw if any of the elements is not found.
-   */
-  Class.prototype[method] = function (element, name, updater) {
-    let data;
-
-    if (this.type !== 'mixed' && type !== 'mixed' && type !== this.type)
-      throw new UsageGraphError(
-        `Graph.${method}: cannot find this type of edges in your ${this.type} graph.`
-      );
-
-    if (arguments.length > 3) {
-      if (this.multi)
-        throw new UsageGraphError(
-          `Graph.${method}: cannot use a {source,target} combo when asking about an edge's attributes in a MultiGraph since we cannot infer the one you want information about.`
-        );
-
-      const source = '' + element;
-      const target = '' + name;
-
-      name = arguments[2];
-      updater = arguments[3];
-
-      data = getMatchingEdge(this, source, target, type);
-
-      if (!data)
-        throw new NotFoundGraphError(
-          `Graph.${method}: could not find an edge for the given path ("${source}" - "${target}").`
-        );
-    } else {
-      if (type !== 'mixed')
-        throw new UsageGraphError(
-          `Graph.${method}: calling this method with only a key (vs. a source and target) does not make sense since an edge with this key could have the other type.`
-        );
-
-      element = '' + element;
-      data = this._edges.get(element);
-
-      if (!data)
-        throw new NotFoundGraphError(
-          `Graph.${method}: could not find the "${element}" edge in the graph.`
-        );
-    }
-
-    if (typeof updater !== 'function')
-      throw new InvalidArgumentsGraphError(
-        `Graph.${method}: updater should be a function.`
-      );
-
-    data.attributes[name] = updater(data.attributes[name]);
-
-    // Emitting
-    this.emit('edgeAttributesUpdated', {
-      key: data.key,
-      type: 'set',
-      attributes: data.attributes,
-      name
-    });
-
-    return this;
-  };
-}
-
-/**
- * Attach an attribute remover method onto the provided class.
- *
- * @param {function} Class         - Target class.
- * @param {string}   method        - Method name.
- * @param {string}   type          - Type of the edge to find.
- */
-function attachEdgeAttributeRemover(Class, method, type) {
-  /**
-   * Remove the desired attribute for the given element (node or edge).
-   *
-   * Arity 2:
-   * @param  {any}    element - Target element.
-   * @param  {string} name    - Attribute's name.
-   *
-   * Arity 3 (only for edges):
-   * @param  {any}     source - Source element.
-   * @param  {any}     target - Target element.
-   * @param  {string}  name   - Attribute's name.
-   *
-   * @return {Graph}          - Returns itself for chaining.
-   *
-   * @throws {Error} - Will throw if too many arguments are provided.
-   * @throws {Error} - Will throw if any of the elements is not found.
-   */
-  Class.prototype[method] = function (element, name) {
-    let data;
-
-    if (this.type !== 'mixed' && type !== 'mixed' && type !== this.type)
-      throw new UsageGraphError(
-        `Graph.${method}: cannot find this type of edges in your ${this.type} graph.`
-      );
-
-    if (arguments.length > 2) {
-      if (this.multi)
-        throw new UsageGraphError(
-          `Graph.${method}: cannot use a {source,target} combo when asking about an edge's attributes in a MultiGraph since we cannot infer the one you want information about.`
-        );
-
-      const source = '' + element;
-      const target = '' + name;
-
-      name = arguments[2];
-
-      data = getMatchingEdge(this, source, target, type);
-
-      if (!data)
-        throw new NotFoundGraphError(
-          `Graph.${method}: could not find an edge for the given path ("${source}" - "${target}").`
-        );
-    } else {
-      if (type !== 'mixed')
-        throw new UsageGraphError(
-          `Graph.${method}: calling this method with only a key (vs. a source and target) does not make sense since an edge with this key could have the other type.`
-        );
-
-      element = '' + element;
-      data = this._edges.get(element);
-
-      if (!data)
-        throw new NotFoundGraphError(
-          `Graph.${method}: could not find the "${element}" edge in the graph.`
-        );
-    }
-
-    delete data.attributes[name];
-
-    // Emitting
-    this.emit('edgeAttributesUpdated', {
-      key: data.key,
-      type: 'remove',
-      attributes: data.attributes,
-      name
-    });
-
-    return this;
-  };
-}
-
-/**
- * Attach an attribute replacer method onto the provided class.
- *
- * @param {function} Class         - Target class.
- * @param {string}   method        - Method name.
- * @param {string}   type          - Type of the edge to find.
- */
-function attachEdgeAttributesReplacer(Class, method, type) {
-  /**
-   * Replace the attributes for the given element (node or edge).
-   *
-   * Arity 2:
-   * @param  {any}    element    - Target element.
-   * @param  {object} attributes - New attributes.
-   *
-   * Arity 3 (only for edges):
-   * @param  {any}     source     - Source element.
-   * @param  {any}     target     - Target element.
-   * @param  {object}  attributes - New attributes.
-   *
-   * @return {Graph}              - Returns itself for chaining.
-   *
-   * @throws {Error} - Will throw if too many arguments are provided.
-   * @throws {Error} - Will throw if any of the elements is not found.
-   */
-  Class.prototype[method] = function (element, attributes) {
-    let data;
-
-    if (this.type !== 'mixed' && type !== 'mixed' && type !== this.type)
-      throw new UsageGraphError(
-        `Graph.${method}: cannot find this type of edges in your ${this.type} graph.`
-      );
-
-    if (arguments.length > 2) {
-      if (this.multi)
-        throw new UsageGraphError(
-          `Graph.${method}: cannot use a {source,target} combo when asking about an edge's attributes in a MultiGraph since we cannot infer the one you want information about.`
-        );
-
-      const source = '' + element,
-        target = '' + attributes;
-
-      attributes = arguments[2];
-
-      data = getMatchingEdge(this, source, target, type);
-
-      if (!data)
-        throw new NotFoundGraphError(
-          `Graph.${method}: could not find an edge for the given path ("${source}" - "${target}").`
-        );
-    } else {
-      if (type !== 'mixed')
-        throw new UsageGraphError(
-          `Graph.${method}: calling this method with only a key (vs. a source and target) does not make sense since an edge with this key could have the other type.`
-        );
-
-      element = '' + element;
-      data = this._edges.get(element);
-
-      if (!data)
-        throw new NotFoundGraphError(
-          `Graph.${method}: could not find the "${element}" edge in the graph.`
-        );
-    }
-
-    if (!isPlainObject(attributes))
-      throw new InvalidArgumentsGraphError(
-        `Graph.${method}: provided attributes are not a plain object.`
-      );
-
-    data.attributes = attributes;
-
-    // Emitting
-    this.emit('edgeAttributesUpdated', {
-      key: data.key,
-      type: 'replace',
-      attributes: data.attributes
-    });
-
-    return this;
-  };
-}
-
-/**
- * Attach an attribute merger method onto the provided class.
- *
- * @param {function} Class         - Target class.
- * @param {string}   method        - Method name.
- * @param {string}   type          - Type of the edge to find.
- */
-function attachEdgeAttributesMerger(Class, method, type) {
-  /**
-   * Merge the attributes for the given element (node or edge).
-   *
-   * Arity 2:
-   * @param  {any}    element    - Target element.
-   * @param  {object} attributes - Attributes to merge.
-   *
-   * Arity 3 (only for edges):
-   * @param  {any}     source     - Source element.
-   * @param  {any}     target     - Target element.
-   * @param  {object}  attributes - Attributes to merge.
-   *
-   * @return {Graph}              - Returns itself for chaining.
-   *
-   * @throws {Error} - Will throw if too many arguments are provided.
-   * @throws {Error} - Will throw if any of the elements is not found.
-   */
-  Class.prototype[method] = function (element, attributes) {
-    let data;
-
-    if (this.type !== 'mixed' && type !== 'mixed' && type !== this.type)
-      throw new UsageGraphError(
-        `Graph.${method}: cannot find this type of edges in your ${this.type} graph.`
-      );
-
-    if (arguments.length > 2) {
-      if (this.multi)
-        throw new UsageGraphError(
-          `Graph.${method}: cannot use a {source,target} combo when asking about an edge's attributes in a MultiGraph since we cannot infer the one you want information about.`
-        );
-
-      const source = '' + element,
-        target = '' + attributes;
-
-      attributes = arguments[2];
-
-      data = getMatchingEdge(this, source, target, type);
-
-      if (!data)
-        throw new NotFoundGraphError(
-          `Graph.${method}: could not find an edge for the given path ("${source}" - "${target}").`
-        );
-    } else {
-      if (type !== 'mixed')
-        throw new UsageGraphError(
-          `Graph.${method}: calling this method with only a key (vs. a source and target) does not make sense since an edge with this key could have the other type.`
-        );
-
-      element = '' + element;
-      data = this._edges.get(element);
-
-      if (!data)
-        throw new NotFoundGraphError(
-          `Graph.${method}: could not find the "${element}" edge in the graph.`
-        );
-    }
-
-    if (!isPlainObject(attributes))
-      throw new InvalidArgumentsGraphError(
-        `Graph.${method}: provided attributes are not a plain object.`
-      );
-
-    assign(data.attributes, attributes);
-
-    // Emitting
-    this.emit('edgeAttributesUpdated', {
-      key: data.key,
-      type: 'merge',
-      attributes: data.attributes,
-      data: attributes
-    });
-
-    return this;
-  };
-}
-
-/**
- * Attach an attribute updater method onto the provided class.
- *
- * @param {function} Class         - Target class.
- * @param {string}   method        - Method name.
- * @param {string}   type          - Type of the edge to find.
- */
-function attachEdgeAttributesUpdater(Class, method, type) {
-  /**
-   * Update the attributes of the given element (node or edge).
-   *
-   * Arity 2:
-   * @param  {any}      element - Target element.
-   * @param  {function} updater - Updater function.
-   *
-   * Arity 3 (only for edges):
-   * @param  {any}      source  - Source element.
-   * @param  {any}      target  - Target element.
-   * @param  {function} updater - Updater function.
-   *
-   * @return {Graph}            - Returns itself for chaining.
-   *
-   * @throws {Error} - Will throw if too many arguments are provided.
-   * @throws {Error} - Will throw if any of the elements is not found.
-   */
-  Class.prototype[method] = function (element, updater) {
-    let data;
-
-    if (this.type !== 'mixed' && type !== 'mixed' && type !== this.type)
-      throw new UsageGraphError(
-        `Graph.${method}: cannot find this type of edges in your ${this.type} graph.`
-      );
-
-    if (arguments.length > 2) {
-      if (this.multi)
-        throw new UsageGraphError(
-          `Graph.${method}: cannot use a {source,target} combo when asking about an edge's attributes in a MultiGraph since we cannot infer the one you want information about.`
-        );
-
-      const source = '' + element,
-        target = '' + updater;
-
-      updater = arguments[2];
-
-      data = getMatchingEdge(this, source, target, type);
-
-      if (!data)
-        throw new NotFoundGraphError(
-          `Graph.${method}: could not find an edge for the given path ("${source}" - "${target}").`
-        );
-    } else {
-      if (type !== 'mixed')
-        throw new UsageGraphError(
-          `Graph.${method}: calling this method with only a key (vs. a source and target) does not make sense since an edge with this key could have the other type.`
-        );
-
-      element = '' + element;
-      data = this._edges.get(element);
-
-      if (!data)
-        throw new NotFoundGraphError(
-          `Graph.${method}: could not find the "${element}" edge in the graph.`
-        );
-    }
-
-    if (typeof updater !== 'function')
-      throw new InvalidArgumentsGraphError(
-        `Graph.${method}: provided updater is not a function.`
-      );
-
-    data.attributes = updater(data.attributes);
-
-    // Emitting
-    this.emit('edgeAttributesUpdated', {
-      key: data.key,
-      type: 'update',
-      attributes: data.attributes
-    });
-
-    return this;
-  };
-}
-
-/**
- * List of methods to attach.
- */
-const EDGE_ATTRIBUTES_METHODS = [
-  {
-    name: element => `get${element}Attribute`,
-    attacher: attachEdgeAttributeGetter
-  },
-  {
-    name: element => `get${element}Attributes`,
-    attacher: attachEdgeAttributesGetter
-  },
-  {
-    name: element => `has${element}Attribute`,
-    attacher: attachEdgeAttributeChecker
-  },
-  {
-    name: element => `set${element}Attribute`,
-    attacher: attachEdgeAttributeSetter
-  },
-  {
-    name: element => `update${element}Attribute`,
-    attacher: attachEdgeAttributeUpdater
-  },
-  {
-    name: element => `remove${element}Attribute`,
-    attacher: attachEdgeAttributeRemover
-  },
-  {
-    name: element => `replace${element}Attributes`,
-    attacher: attachEdgeAttributesReplacer
-  },
-  {
-    name: element => `merge${element}Attributes`,
-    attacher: attachEdgeAttributesMerger
-  },
-  {
-    name: element => `update${element}Attributes`,
-    attacher: attachEdgeAttributesUpdater
-  }
-];
-
-/**
- * Attach every attributes-related methods to a Graph class.
- *
- * @param {function} Graph - Target class.
- */
-function attachEdgeAttributesMethods(Graph) {
-  EDGE_ATTRIBUTES_METHODS.forEach(function ({name, attacher}) {
-    // For edges
-    attacher(Graph, name('Edge'), 'mixed');
-
-    // For directed edges
-    attacher(Graph, name('DirectedEdge'), 'directed');
-
-    // For undirected edges
-    attacher(Graph, name('UndirectedEdge'), 'undirected');
-  });
-}
-
-/**
- * Graphology Edge Iteration
- * ==========================
- *
- * Attaching some methods to the Graph class to be able to iterate over a
- * graph's edges.
- */
-
-/**
- * Definitions.
- */
-const EDGES_ITERATION = [
-  {
-    name: 'edges',
-    type: 'mixed'
-  },
-  {
-    name: 'inEdges',
-    type: 'directed',
-    direction: 'in'
-  },
-  {
-    name: 'outEdges',
-    type: 'directed',
-    direction: 'out'
-  },
-  {
-    name: 'inboundEdges',
-    type: 'mixed',
-    direction: 'in'
-  },
-  {
-    name: 'outboundEdges',
-    type: 'mixed',
-    direction: 'out'
-  },
-  {
-    name: 'directedEdges',
-    type: 'directed'
-  },
-  {
-    name: 'undirectedEdges',
-    type: 'undirected'
-  }
-];
-
-/**
- * Function iterating over edges from the given object to match one of them.
- *
- * @param {object}   object   - Target object.
- * @param {function} callback - Function to call.
- */
-function forEachSimple(breakable, object, callback, avoid) {
-  let shouldBreak = false;
-
-  for (const k in object) {
-    if (k === avoid) continue;
-
-    const edgeData = object[k];
-
-    shouldBreak = callback(
-      edgeData.key,
-      edgeData.attributes,
-      edgeData.source.key,
-      edgeData.target.key,
-      edgeData.source.attributes,
-      edgeData.target.attributes,
-      edgeData.undirected
-    );
-
-    if (breakable && shouldBreak) return edgeData.key;
-  }
-
-  return;
-}
-
-function forEachMulti(breakable, object, callback, avoid) {
-  let edgeData, source, target;
-
-  let shouldBreak = false;
-
-  for (const k in object) {
-    if (k === avoid) continue;
-
-    edgeData = object[k];
-
-    do {
-      source = edgeData.source;
-      target = edgeData.target;
-
-      shouldBreak = callback(
-        edgeData.key,
-        edgeData.attributes,
-        source.key,
-        target.key,
-        source.attributes,
-        target.attributes,
-        edgeData.undirected
-      );
-
-      if (breakable && shouldBreak) return edgeData.key;
-
-      edgeData = edgeData.next;
-    } while (edgeData !== undefined);
-  }
-
-  return;
-}
-
-/**
- * Function returning an iterator over edges from the given object.
- *
- * @param  {object}   object - Target object.
- * @return {Iterator}
- */
-function createIterator(object, avoid) {
-  const keys = Object.keys(object);
-  const l = keys.length;
-
-  let edgeData;
-  let i = 0;
-
-  return new Iterator(function next() {
-    do {
-      if (!edgeData) {
-        if (i >= l) return {done: true};
-
-        const k = keys[i++];
-
-        if (k === avoid) {
-          edgeData = undefined;
-          continue;
-        }
-
-        edgeData = object[k];
-      } else {
-        edgeData = edgeData.next;
-      }
-    } while (!edgeData);
-
-    return {
-      done: false,
-      value: {
-        edge: edgeData.key,
-        attributes: edgeData.attributes,
-        source: edgeData.source.key,
-        target: edgeData.target.key,
-        sourceAttributes: edgeData.source.attributes,
-        targetAttributes: edgeData.target.attributes,
-        undirected: edgeData.undirected
-      }
-    };
-  });
-}
-
-/**
- * Function iterating over the egdes from the object at given key to match
- * one of them.
- *
- * @param {object}   object   - Target object.
- * @param {mixed}    k        - Neighbor key.
- * @param {function} callback - Callback to use.
- */
-function forEachForKeySimple(breakable, object, k, callback) {
-  const edgeData = object[k];
-
-  if (!edgeData) return;
-
-  const sourceData = edgeData.source;
-  const targetData = edgeData.target;
-
-  if (
-    callback(
-      edgeData.key,
-      edgeData.attributes,
-      sourceData.key,
-      targetData.key,
-      sourceData.attributes,
-      targetData.attributes,
-      edgeData.undirected
-    ) &&
-    breakable
-  )
-    return edgeData.key;
-}
-
-function forEachForKeyMulti(breakable, object, k, callback) {
-  let edgeData = object[k];
-
-  if (!edgeData) return;
-
-  let shouldBreak = false;
-
-  do {
-    shouldBreak = callback(
-      edgeData.key,
-      edgeData.attributes,
-      edgeData.source.key,
-      edgeData.target.key,
-      edgeData.source.attributes,
-      edgeData.target.attributes,
-      edgeData.undirected
-    );
-
-    if (breakable && shouldBreak) return edgeData.key;
-
-    edgeData = edgeData.next;
-  } while (edgeData !== undefined);
-
-  return;
-}
-
-/**
- * Function returning an iterator over the egdes from the object at given key.
- *
- * @param  {object}   object   - Target object.
- * @param  {mixed}    k        - Neighbor key.
- * @return {Iterator}
- */
-function createIteratorForKey(object, k) {
-  let edgeData = object[k];
-
-  if (edgeData.next !== undefined) {
-    return new Iterator(function () {
-      if (!edgeData) return {done: true};
-
-      const value = {
-        edge: edgeData.key,
-        attributes: edgeData.attributes,
-        source: edgeData.source.key,
-        target: edgeData.target.key,
-        sourceAttributes: edgeData.source.attributes,
-        targetAttributes: edgeData.target.attributes,
-        undirected: edgeData.undirected
-      };
-
-      edgeData = edgeData.next;
-
-      return {
-        done: false,
-        value
-      };
-    });
-  }
-
-  return Iterator.of({
-    edge: edgeData.key,
-    attributes: edgeData.attributes,
-    source: edgeData.source.key,
-    target: edgeData.target.key,
-    sourceAttributes: edgeData.source.attributes,
-    targetAttributes: edgeData.target.attributes,
-    undirected: edgeData.undirected
-  });
-}
-
-/**
- * Function creating an array of edges for the given type.
- *
- * @param  {Graph}   graph - Target Graph instance.
- * @param  {string}  type  - Type of edges to retrieve.
- * @return {array}         - Array of edges.
- */
-function createEdgeArray(graph, type) {
-  if (graph.size === 0) return [];
-
-  if (type === 'mixed' || type === graph.type) {
-    if (typeof Array.from === 'function')
-      return Array.from(graph._edges.keys());
-
-    return take(graph._edges.keys(), graph._edges.size);
-  }
-
-  const size =
-    type === 'undirected' ? graph.undirectedSize : graph.directedSize;
-
-  const list = new Array(size),
-    mask = type === 'undirected';
-
-  const iterator = graph._edges.values();
-
-  let i = 0;
-  let step, data;
-
-  while (((step = iterator.next()), step.done !== true)) {
-    data = step.value;
-
-    if (data.undirected === mask) list[i++] = data.key;
-  }
-
-  return list;
-}
-
-/**
- * Function iterating over a graph's edges using a callback to match one of
- * them.
- *
- * @param  {Graph}    graph    - Target Graph instance.
- * @param  {string}   type     - Type of edges to retrieve.
- * @param  {function} callback - Function to call.
- */
-function forEachEdge(breakable, graph, type, callback) {
-  if (graph.size === 0) return;
-
-  const shouldFilter = type !== 'mixed' && type !== graph.type;
-  const mask = type === 'undirected';
-
-  let step, data;
-  let shouldBreak = false;
-  const iterator = graph._edges.values();
-
-  while (((step = iterator.next()), step.done !== true)) {
-    data = step.value;
-
-    if (shouldFilter && data.undirected !== mask) continue;
-
-    const {key, attributes, source, target} = data;
-
-    shouldBreak = callback(
-      key,
-      attributes,
-      source.key,
-      target.key,
-      source.attributes,
-      target.attributes,
-      data.undirected
-    );
-
-    if (breakable && shouldBreak) return key;
-  }
-
-  return;
-}
-
-/**
- * Function creating an iterator of edges for the given type.
- *
- * @param  {Graph}    graph - Target Graph instance.
- * @param  {string}   type  - Type of edges to retrieve.
- * @return {Iterator}
- */
-function createEdgeIterator(graph, type) {
-  if (graph.size === 0) return Iterator.empty();
-
-  const shouldFilter = type !== 'mixed' && type !== graph.type;
-  const mask = type === 'undirected';
-
-  const iterator = graph._edges.values();
-
-  return new Iterator(function next() {
-    let step, data;
-
-    // eslint-disable-next-line no-constant-condition
-    while (true) {
-      step = iterator.next();
-
-      if (step.done) return step;
-
-      data = step.value;
-
-      if (shouldFilter && data.undirected !== mask) continue;
-
-      break;
-    }
-
-    const value = {
-      edge: data.key,
-      attributes: data.attributes,
-      source: data.source.key,
-      target: data.target.key,
-      sourceAttributes: data.source.attributes,
-      targetAttributes: data.target.attributes,
-      undirected: data.undirected
-    };
-
-    return {value, done: false};
-  });
-}
-
-/**
- * Function iterating over a node's edges using a callback to match one of them.
- *
- * @param  {boolean}  multi     - Whether the graph is multi or not.
- * @param  {string}   type      - Type of edges to retrieve.
- * @param  {string}   direction - In or out?
- * @param  {any}      nodeData  - Target node's data.
- * @param  {function} callback  - Function to call.
- */
-function forEachEdgeForNode(
-  breakable,
-  multi,
-  type,
-  direction,
-  nodeData,
-  callback
-) {
-  const fn = multi ? forEachMulti : forEachSimple;
-
-  let found;
-
-  if (type !== 'undirected') {
-    if (direction !== 'out') {
-      found = fn(breakable, nodeData.in, callback);
-
-      if (breakable && found) return found;
-    }
-    if (direction !== 'in') {
-      found = fn(
-        breakable,
-        nodeData.out,
-        callback,
-        !direction ? nodeData.key : undefined
-      );
-
-      if (breakable && found) return found;
-    }
-  }
-
-  if (type !== 'directed') {
-    found = fn(breakable, nodeData.undirected, callback);
-
-    if (breakable && found) return found;
-  }
-
-  return;
-}
-
-/**
- * Function creating an array of edges for the given type & the given node.
- *
- * @param  {boolean} multi     - Whether the graph is multi or not.
- * @param  {string}  type      - Type of edges to retrieve.
- * @param  {string}  direction - In or out?
- * @param  {any}     nodeData  - Target node's data.
- * @return {array}             - Array of edges.
- */
-function createEdgeArrayForNode(multi, type, direction, nodeData) {
-  const edges = []; // TODO: possibility to know size beforehand or factorize with map
-
-  forEachEdgeForNode(false, multi, type, direction, nodeData, function (key) {
-    edges.push(key);
-  });
-
-  return edges;
-}
-
-/**
- * Function iterating over a node's edges using a callback.
- *
- * @param  {string}   type      - Type of edges to retrieve.
- * @param  {string}   direction - In or out?
- * @param  {any}      nodeData  - Target node's data.
- * @return {Iterator}
- */
-function createEdgeIteratorForNode(type, direction, nodeData) {
-  let iterator = Iterator.empty();
-
-  if (type !== 'undirected') {
-    if (direction !== 'out' && typeof nodeData.in !== 'undefined')
-      iterator = chain(iterator, createIterator(nodeData.in));
-    if (direction !== 'in' && typeof nodeData.out !== 'undefined')
-      iterator = chain(
-        iterator,
-        createIterator(nodeData.out, !direction ? nodeData.key : undefined)
-      );
-  }
-
-  if (type !== 'directed' && typeof nodeData.undirected !== 'undefined') {
-    iterator = chain(iterator, createIterator(nodeData.undirected));
-  }
-
-  return iterator;
-}
-
-/**
- * Function iterating over edges for the given path using a callback to match
- * one of them.
- *
- * @param  {string}   type       - Type of edges to retrieve.
- * @param  {boolean}  multi      - Whether the graph is multi.
- * @param  {string}   direction  - In or out?
- * @param  {NodeData} sourceData - Source node's data.
- * @param  {string}   target     - Target node.
- * @param  {function} callback   - Function to call.
- */
-function forEachEdgeForPath(
-  breakable,
-  type,
-  multi,
-  direction,
-  sourceData,
-  target,
-  callback
-) {
-  const fn = multi ? forEachForKeyMulti : forEachForKeySimple;
-
-  let found;
-
-  if (type !== 'undirected') {
-    if (typeof sourceData.in !== 'undefined' && direction !== 'out') {
-      found = fn(breakable, sourceData.in, target, callback);
-
-      if (breakable && found) return found;
-    }
-
-    if (
-      typeof sourceData.out !== 'undefined' &&
-      direction !== 'in' &&
-      (direction || sourceData.key !== target)
-    ) {
-      found = fn(breakable, sourceData.out, target, callback);
-
-      if (breakable && found) return found;
-    }
-  }
-
-  if (type !== 'directed') {
-    if (typeof sourceData.undirected !== 'undefined') {
-      found = fn(breakable, sourceData.undirected, target, callback);
-
-      if (breakable && found) return found;
-    }
-  }
-
-  return;
-}
-
-/**
- * Function creating an array of edges for the given path.
- *
- * @param  {string}   type       - Type of edges to retrieve.
- * @param  {boolean}  multi      - Whether the graph is multi.
- * @param  {string}   direction  - In or out?
- * @param  {NodeData} sourceData - Source node's data.
- * @param  {any}      target     - Target node.
- * @return {array}               - Array of edges.
- */
-function createEdgeArrayForPath(type, multi, direction, sourceData, target) {
-  const edges = []; // TODO: possibility to know size beforehand or factorize with map
-
-  forEachEdgeForPath(
-    false,
-    type,
-    multi,
-    direction,
-    sourceData,
-    target,
-    function (key) {
-      edges.push(key);
-    }
-  );
-
-  return edges;
-}
-
-/**
- * Function returning an iterator over edges for the given path.
- *
- * @param  {string}   type       - Type of edges to retrieve.
- * @param  {string}   direction  - In or out?
- * @param  {NodeData} sourceData - Source node's data.
- * @param  {string}   target     - Target node.
- * @param  {function} callback   - Function to call.
- */
-function createEdgeIteratorForPath(type, direction, sourceData, target) {
-  let iterator = Iterator.empty();
-
-  if (type !== 'undirected') {
-    if (
-      typeof sourceData.in !== 'undefined' &&
-      direction !== 'out' &&
-      target in sourceData.in
-    )
-      iterator = chain(iterator, createIteratorForKey(sourceData.in, target));
-
-    if (
-      typeof sourceData.out !== 'undefined' &&
-      direction !== 'in' &&
-      target in sourceData.out &&
-      (direction || sourceData.key !== target)
-    )
-      iterator = chain(iterator, createIteratorForKey(sourceData.out, target));
-  }
-
-  if (type !== 'directed') {
-    if (
-      typeof sourceData.undirected !== 'undefined' &&
-      target in sourceData.undirected
-    )
-      iterator = chain(
-        iterator,
-        createIteratorForKey(sourceData.undirected, target)
-      );
-  }
-
-  return iterator;
-}
-
-/**
- * Function attaching an edge array creator method to the Graph prototype.
- *
- * @param {function} Class       - Target class.
- * @param {object}   description - Method description.
- */
-function attachEdgeArrayCreator(Class, description) {
-  const {name, type, direction} = description;
-
-  /**
-   * Function returning an array of certain edges.
-   *
-   * Arity 0: Return all the relevant edges.
-   *
-   * Arity 1: Return all of a node's relevant edges.
-   * @param  {any}   node   - Target node.
-   *
-   * Arity 2: Return the relevant edges across the given path.
-   * @param  {any}   source - Source node.
-   * @param  {any}   target - Target node.
-   *
-   * @return {array|number} - The edges or the number of edges.
-   *
-   * @throws {Error} - Will throw if there are too many arguments.
-   */
-  Class.prototype[name] = function (source, target) {
-    // Early termination
-    if (type !== 'mixed' && this.type !== 'mixed' && type !== this.type)
-      return [];
-
-    if (!arguments.length) return createEdgeArray(this, type);
-
-    if (arguments.length === 1) {
-      source = '' + source;
-
-      const nodeData = this._nodes.get(source);
-
-      if (typeof nodeData === 'undefined')
-        throw new NotFoundGraphError(
-          `Graph.${name}: could not find the "${source}" node in the graph.`
-        );
-
-      // Iterating over a node's edges
-      return createEdgeArrayForNode(
-        this.multi,
-        type === 'mixed' ? this.type : type,
-        direction,
-        nodeData
-      );
-    }
-
-    if (arguments.length === 2) {
-      source = '' + source;
-      target = '' + target;
-
-      const sourceData = this._nodes.get(source);
-
-      if (!sourceData)
-        throw new NotFoundGraphError(
-          `Graph.${name}:  could not find the "${source}" source node in the graph.`
-        );
-
-      if (!this._nodes.has(target))
-        throw new NotFoundGraphError(
-          `Graph.${name}:  could not find the "${target}" target node in the graph.`
-        );
-
-      // Iterating over the edges between source & target
-      return createEdgeArrayForPath(
-        type,
-        this.multi,
-        direction,
-        sourceData,
-        target
-      );
-    }
-
-    throw new InvalidArgumentsGraphError(
-      `Graph.${name}: too many arguments (expecting 0, 1 or 2 and got ${arguments.length}).`
-    );
-  };
-}
-
-/**
- * Function attaching a edge callback iterator method to the Graph prototype.
- *
- * @param {function} Class       - Target class.
- * @param {object}   description - Method description.
- */
-function attachForEachEdge(Class, description) {
-  const {name, type, direction} = description;
-
-  const forEachName = 'forEach' + name[0].toUpperCase() + name.slice(1, -1);
-
-  /**
-   * Function iterating over the graph's relevant edges by applying the given
-   * callback.
-   *
-   * Arity 1: Iterate over all the relevant edges.
-   * @param  {function} callback - Callback to use.
-   *
-   * Arity 2: Iterate over all of a node's relevant edges.
-   * @param  {any}      node     - Target node.
-   * @param  {function} callback - Callback to use.
-   *
-   * Arity 3: Iterate over the relevant edges across the given path.
-   * @param  {any}      source   - Source node.
-   * @param  {any}      target   - Target node.
-   * @param  {function} callback - Callback to use.
-   *
-   * @return {undefined}
-   *
-   * @throws {Error} - Will throw if there are too many arguments.
-   */
-  Class.prototype[forEachName] = function (source, target, callback) {
-    // Early termination
-    if (type !== 'mixed' && this.type !== 'mixed' && type !== this.type) return;
-
-    if (arguments.length === 1) {
-      callback = source;
-      return forEachEdge(false, this, type, callback);
-    }
-
-    if (arguments.length === 2) {
-      source = '' + source;
-      callback = target;
-
-      const nodeData = this._nodes.get(source);
-
-      if (typeof nodeData === 'undefined')
-        throw new NotFoundGraphError(
-          `Graph.${forEachName}: could not find the "${source}" node in the graph.`
-        );
-
-      // Iterating over a node's edges
-      // TODO: maybe attach the sub method to the instance dynamically?
-      return forEachEdgeForNode(
-        false,
-        this.multi,
-        type === 'mixed' ? this.type : type,
-        direction,
-        nodeData,
-        callback
-      );
-    }
-
-    if (arguments.length === 3) {
-      source = '' + source;
-      target = '' + target;
-
-      const sourceData = this._nodes.get(source);
-
-      if (!sourceData)
-        throw new NotFoundGraphError(
-          `Graph.${forEachName}:  could not find the "${source}" source node in the graph.`
-        );
-
-      if (!this._nodes.has(target))
-        throw new NotFoundGraphError(
-          `Graph.${forEachName}:  could not find the "${target}" target node in the graph.`
-        );
-
-      // Iterating over the edges between source & target
-      return forEachEdgeForPath(
-        false,
-        type,
-        this.multi,
-        direction,
-        sourceData,
-        target,
-        callback
-      );
-    }
-
-    throw new InvalidArgumentsGraphError(
-      `Graph.${forEachName}: too many arguments (expecting 1, 2 or 3 and got ${arguments.length}).`
-    );
-  };
-
-  /**
-   * Function mapping the graph's relevant edges by applying the given
-   * callback.
-   *
-   * Arity 1: Map all the relevant edges.
-   * @param  {function} callback - Callback to use.
-   *
-   * Arity 2: Map all of a node's relevant edges.
-   * @param  {any}      node     - Target node.
-   * @param  {function} callback - Callback to use.
-   *
-   * Arity 3: Map the relevant edges across the given path.
-   * @param  {any}      source   - Source node.
-   * @param  {any}      target   - Target node.
-   * @param  {function} callback - Callback to use.
-   *
-   * @return {undefined}
-   *
-   * @throws {Error} - Will throw if there are too many arguments.
-   */
-  const mapName = 'map' + name[0].toUpperCase() + name.slice(1);
-
-  Class.prototype[mapName] = function () {
-    const args = Array.prototype.slice.call(arguments);
-    const callback = args.pop();
-
-    let result;
-
-    // We know the result length beforehand
-    if (args.length === 0) {
-      let length = 0;
-
-      if (type !== 'directed') length += this.undirectedSize;
-      if (type !== 'undirected') length += this.directedSize;
-
-      result = new Array(length);
-
-      let i = 0;
-
-      args.push((e, ea, s, t, sa, ta, u) => {
-        result[i++] = callback(e, ea, s, t, sa, ta, u);
-      });
-    }
-
-    // We don't know the result length beforehand
-    // TODO: we can in some instances of simple graphs, knowing degree
-    else {
-      result = [];
-
-      args.push((e, ea, s, t, sa, ta, u) => {
-        result.push(callback(e, ea, s, t, sa, ta, u));
-      });
-    }
-
-    this[forEachName].apply(this, args);
-
-    return result;
-  };
-
-  /**
-   * Function filtering the graph's relevant edges using the provided predicate
-   * function.
-   *
-   * Arity 1: Filter all the relevant edges.
-   * @param  {function} predicate - Predicate to use.
-   *
-   * Arity 2: Filter all of a node's relevant edges.
-   * @param  {any}      node      - Target node.
-   * @param  {function} predicate - Predicate to use.
-   *
-   * Arity 3: Filter the relevant edges across the given path.
-   * @param  {any}      source    - Source node.
-   * @param  {any}      target    - Target node.
-   * @param  {function} predicate - Predicate to use.
-   *
-   * @return {undefined}
-   *
-   * @throws {Error} - Will throw if there are too many arguments.
-   */
-  const filterName = 'filter' + name[0].toUpperCase() + name.slice(1);
-
-  Class.prototype[filterName] = function () {
-    const args = Array.prototype.slice.call(arguments);
-    const callback = args.pop();
-
-    const result = [];
-
-    args.push((e, ea, s, t, sa, ta, u) => {
-      if (callback(e, ea, s, t, sa, ta, u)) result.push(e);
-    });
-
-    this[forEachName].apply(this, args);
-
-    return result;
-  };
-
-  /**
-   * Function reducing the graph's relevant edges using the provided accumulator
-   * function.
-   *
-   * Arity 1: Reduce all the relevant edges.
-   * @param  {function} accumulator  - Accumulator to use.
-   * @param  {any}      initialValue - Initial value.
-   *
-   * Arity 2: Reduce all of a node's relevant edges.
-   * @param  {any}      node         - Target node.
-   * @param  {function} accumulator  - Accumulator to use.
-   * @param  {any}      initialValue - Initial value.
-   *
-   * Arity 3: Reduce the relevant edges across the given path.
-   * @param  {any}      source       - Source node.
-   * @param  {any}      target       - Target node.
-   * @param  {function} accumulator  - Accumulator to use.
-   * @param  {any}      initialValue - Initial value.
-   *
-   * @return {undefined}
-   *
-   * @throws {Error} - Will throw if there are too many arguments.
-   */
-  const reduceName = 'reduce' + name[0].toUpperCase() + name.slice(1);
-
-  Class.prototype[reduceName] = function () {
-    let args = Array.prototype.slice.call(arguments);
-
-    if (args.length < 2 || args.length > 4) {
-      throw new InvalidArgumentsGraphError(
-        `Graph.${reduceName}: invalid number of arguments (expecting 2, 3 or 4 and got ${args.length}).`
-      );
-    }
-
-    if (
-      typeof args[args.length - 1] === 'function' &&
-      typeof args[args.length - 2] !== 'function'
-    ) {
-      throw new InvalidArgumentsGraphError(
-        `Graph.${reduceName}: missing initial value. You must provide it because the callback takes more than one argument and we cannot infer the initial value from the first iteration, as you could with a simple array.`
-      );
-    }
-
-    let callback;
-    let initialValue;
-
-    if (args.length === 2) {
-      callback = args[0];
-      initialValue = args[1];
-      args = [];
-    } else if (args.length === 3) {
-      callback = args[1];
-      initialValue = args[2];
-      args = [args[0]];
-    } else if (args.length === 4) {
-      callback = args[2];
-      initialValue = args[3];
-      args = [args[0], args[1]];
-    }
-
-    let accumulator = initialValue;
-
-    args.push((e, ea, s, t, sa, ta, u) => {
-      accumulator = callback(accumulator, e, ea, s, t, sa, ta, u);
-    });
-
-    this[forEachName].apply(this, args);
-
-    return accumulator;
-  };
-}
-
-/**
- * Function attaching a breakable edge callback iterator method to the Graph
- * prototype.
- *
- * @param {function} Class       - Target class.
- * @param {object}   description - Method description.
- */
-function attachFindEdge(Class, description) {
-  const {name, type, direction} = description;
-
-  const findEdgeName = 'find' + name[0].toUpperCase() + name.slice(1, -1);
-
-  /**
-   * Function iterating over the graph's relevant edges in order to match
-   * one of them using the provided predicate function.
-   *
-   * Arity 1: Iterate over all the relevant edges.
-   * @param  {function} callback - Callback to use.
-   *
-   * Arity 2: Iterate over all of a node's relevant edges.
-   * @param  {any}      node     - Target node.
-   * @param  {function} callback - Callback to use.
-   *
-   * Arity 3: Iterate over the relevant edges across the given path.
-   * @param  {any}      source   - Source node.
-   * @param  {any}      target   - Target node.
-   * @param  {function} callback - Callback to use.
-   *
-   * @return {undefined}
-   *
-   * @throws {Error} - Will throw if there are too many arguments.
-   */
-  Class.prototype[findEdgeName] = function (source, target, callback) {
-    // Early termination
-    if (type !== 'mixed' && this.type !== 'mixed' && type !== this.type)
-      return false;
-
-    if (arguments.length === 1) {
-      callback = source;
-      return forEachEdge(true, this, type, callback);
-    }
-
-    if (arguments.length === 2) {
-      source = '' + source;
-      callback = target;
-
-      const nodeData = this._nodes.get(source);
-
-      if (typeof nodeData === 'undefined')
-        throw new NotFoundGraphError(
-          `Graph.${findEdgeName}: could not find the "${source}" node in the graph.`
-        );
-
-      // Iterating over a node's edges
-      // TODO: maybe attach the sub method to the instance dynamically?
-      return forEachEdgeForNode(
-        true,
-        this.multi,
-        type === 'mixed' ? this.type : type,
-        direction,
-        nodeData,
-        callback
-      );
-    }
-
-    if (arguments.length === 3) {
-      source = '' + source;
-      target = '' + target;
-
-      const sourceData = this._nodes.get(source);
-
-      if (!sourceData)
-        throw new NotFoundGraphError(
-          `Graph.${findEdgeName}:  could not find the "${source}" source node in the graph.`
-        );
-
-      if (!this._nodes.has(target))
-        throw new NotFoundGraphError(
-          `Graph.${findEdgeName}:  could not find the "${target}" target node in the graph.`
-        );
-
-      // Iterating over the edges between source & target
-      return forEachEdgeForPath(
-        true,
-        type,
-        this.multi,
-        direction,
-        sourceData,
-        target,
-        callback
-      );
-    }
-
-    throw new InvalidArgumentsGraphError(
-      `Graph.${findEdgeName}: too many arguments (expecting 1, 2 or 3 and got ${arguments.length}).`
-    );
-  };
-
-  /**
-   * Function iterating over the graph's relevant edges in order to assert
-   * whether any one of them matches the provided predicate function.
-   *
-   * Arity 1: Iterate over all the relevant edges.
-   * @param  {function} callback - Callback to use.
-   *
-   * Arity 2: Iterate over all of a node's relevant edges.
-   * @param  {any}      node     - Target node.
-   * @param  {function} callback - Callback to use.
-   *
-   * Arity 3: Iterate over the relevant edges across the given path.
-   * @param  {any}      source   - Source node.
-   * @param  {any}      target   - Target node.
-   * @param  {function} callback - Callback to use.
-   *
-   * @return {undefined}
-   *
-   * @throws {Error} - Will throw if there are too many arguments.
-   */
-  const someName = 'some' + name[0].toUpperCase() + name.slice(1, -1);
-
-  Class.prototype[someName] = function () {
-    const args = Array.prototype.slice.call(arguments);
-    const callback = args.pop();
-
-    args.push((e, ea, s, t, sa, ta, u) => {
-      return callback(e, ea, s, t, sa, ta, u);
-    });
-
-    const found = this[findEdgeName].apply(this, args);
-
-    if (found) return true;
-
-    return false;
-  };
-
-  /**
-   * Function iterating over the graph's relevant edges in order to assert
-   * whether all of them matche the provided predicate function.
-   *
-   * Arity 1: Iterate over all the relevant edges.
-   * @param  {function} callback - Callback to use.
-   *
-   * Arity 2: Iterate over all of a node's relevant edges.
-   * @param  {any}      node     - Target node.
-   * @param  {function} callback - Callback to use.
-   *
-   * Arity 3: Iterate over the relevant edges across the given path.
-   * @param  {any}      source   - Source node.
-   * @param  {any}      target   - Target node.
-   * @param  {function} callback - Callback to use.
-   *
-   * @return {undefined}
-   *
-   * @throws {Error} - Will throw if there are too many arguments.
-   */
-  const everyName = 'every' + name[0].toUpperCase() + name.slice(1, -1);
-
-  Class.prototype[everyName] = function () {
-    const args = Array.prototype.slice.call(arguments);
-    const callback = args.pop();
-
-    args.push((e, ea, s, t, sa, ta, u) => {
-      return !callback(e, ea, s, t, sa, ta, u);
-    });
-
-    const found = this[findEdgeName].apply(this, args);
-
-    if (found) return false;
-
-    return true;
-  };
-}
-
-/**
- * Function attaching an edge iterator method to the Graph prototype.
- *
- * @param {function} Class       - Target class.
- * @param {object}   description - Method description.
- */
-function attachEdgeIteratorCreator(Class, description) {
-  const {name: originalName, type, direction} = description;
-
-  const name = originalName.slice(0, -1) + 'Entries';
-
-  /**
-   * Function returning an iterator over the graph's edges.
-   *
-   * Arity 0: Iterate over all the relevant edges.
-   *
-   * Arity 1: Iterate over all of a node's relevant edges.
-   * @param  {any}   node   - Target node.
-   *
-   * Arity 2: Iterate over the relevant edges across the given path.
-   * @param  {any}   source - Source node.
-   * @param  {any}   target - Target node.
-   *
-   * @return {array|number} - The edges or the number of edges.
-   *
-   * @throws {Error} - Will throw if there are too many arguments.
-   */
-  Class.prototype[name] = function (source, target) {
-    // Early termination
-    if (type !== 'mixed' && this.type !== 'mixed' && type !== this.type)
-      return Iterator.empty();
-
-    if (!arguments.length) return createEdgeIterator(this, type);
-
-    if (arguments.length === 1) {
-      source = '' + source;
-
-      const sourceData = this._nodes.get(source);
-
-      if (!sourceData)
-        throw new NotFoundGraphError(
-          `Graph.${name}: could not find the "${source}" node in the graph.`
-        );
-
-      // Iterating over a node's edges
-      return createEdgeIteratorForNode(type, direction, sourceData);
-    }
-
-    if (arguments.length === 2) {
-      source = '' + source;
-      target = '' + target;
-
-      const sourceData = this._nodes.get(source);
-
-      if (!sourceData)
-        throw new NotFoundGraphError(
-          `Graph.${name}:  could not find the "${source}" source node in the graph.`
-        );
-
-      if (!this._nodes.has(target))
-        throw new NotFoundGraphError(
-          `Graph.${name}:  could not find the "${target}" target node in the graph.`
-        );
-
-      // Iterating over the edges between source & target
-      return createEdgeIteratorForPath(type, direction, sourceData, target);
-    }
-
-    throw new InvalidArgumentsGraphError(
-      `Graph.${name}: too many arguments (expecting 0, 1 or 2 and got ${arguments.length}).`
-    );
-  };
-}
-
-/**
- * Function attaching every edge iteration method to the Graph class.
- *
- * @param {function} Graph - Graph class.
- */
-function attachEdgeIterationMethods(Graph) {
-  EDGES_ITERATION.forEach(description => {
-    attachEdgeArrayCreator(Graph, description);
-    attachForEachEdge(Graph, description);
-    attachFindEdge(Graph, description);
-    attachEdgeIteratorCreator(Graph, description);
-  });
-}
-
-/**
- * Graphology Neighbor Iteration
- * ==============================
- *
- * Attaching some methods to the Graph class to be able to iterate over
- * neighbors.
- */
-
-/**
- * Definitions.
- */
-const NEIGHBORS_ITERATION = [
-  {
-    name: 'neighbors',
-    type: 'mixed'
-  },
-  {
-    name: 'inNeighbors',
-    type: 'directed',
-    direction: 'in'
-  },
-  {
-    name: 'outNeighbors',
-    type: 'directed',
-    direction: 'out'
-  },
-  {
-    name: 'inboundNeighbors',
-    type: 'mixed',
-    direction: 'in'
-  },
-  {
-    name: 'outboundNeighbors',
-    type: 'mixed',
-    direction: 'out'
-  },
-  {
-    name: 'directedNeighbors',
-    type: 'directed'
-  },
-  {
-    name: 'undirectedNeighbors',
-    type: 'undirected'
-  }
-];
-
-/**
- * Helpers.
- */
-function CompositeSetWrapper() {
-  this.A = null;
-  this.B = null;
-}
-
-CompositeSetWrapper.prototype.wrap = function (set) {
-  if (this.A === null) this.A = set;
-  else if (this.B === null) this.B = set;
-};
-
-CompositeSetWrapper.prototype.has = function (key) {
-  if (this.A !== null && key in this.A) return true;
-  if (this.B !== null && key in this.B) return true;
-  return false;
-};
-
-/**
- * Function iterating over the given node's relevant neighbors to match
- * one of them using a predicated function.
- *
- * @param  {string}   type      - Type of neighbors.
- * @param  {string}   direction - Direction.
- * @param  {any}      nodeData  - Target node's data.
- * @param  {function} callback  - Callback to use.
- */
-function forEachInObjectOnce(breakable, visited, nodeData, object, callback) {
-  for (const k in object) {
-    const edgeData = object[k];
-
-    const sourceData = edgeData.source;
-    const targetData = edgeData.target;
-
-    const neighborData = sourceData === nodeData ? targetData : sourceData;
-
-    if (visited && visited.has(neighborData.key)) continue;
-
-    const shouldBreak = callback(neighborData.key, neighborData.attributes);
-
-    if (breakable && shouldBreak) return neighborData.key;
-  }
-
-  return;
-}
-
-function forEachNeighbor(breakable, type, direction, nodeData, callback) {
-  // If we want only undirected or in or out, we can roll some optimizations
-  if (type !== 'mixed') {
-    if (type === 'undirected')
-      return forEachInObjectOnce(
-        breakable,
-        null,
-        nodeData,
-        nodeData.undirected,
-        callback
-      );
-
-    if (typeof direction === 'string')
-      return forEachInObjectOnce(
-        breakable,
-        null,
-        nodeData,
-        nodeData[direction],
-        callback
-      );
-  }
-
-  // Else we need to keep a set of neighbors not to return duplicates
-  // We cheat by querying the other adjacencies
-  const visited = new CompositeSetWrapper();
-
-  let found;
-
-  if (type !== 'undirected') {
-    if (direction !== 'out') {
-      found = forEachInObjectOnce(
-        breakable,
-        null,
-        nodeData,
-        nodeData.in,
-        callback
-      );
-
-      if (breakable && found) return found;
-
-      visited.wrap(nodeData.in);
-    }
-    if (direction !== 'in') {
-      found = forEachInObjectOnce(
-        breakable,
-        visited,
-        nodeData,
-        nodeData.out,
-        callback
-      );
-
-      if (breakable && found) return found;
-
-      visited.wrap(nodeData.out);
-    }
-  }
-
-  if (type !== 'directed') {
-    found = forEachInObjectOnce(
-      breakable,
-      visited,
-      nodeData,
-      nodeData.undirected,
-      callback
-    );
-
-    if (breakable && found) return found;
-  }
-
-  return;
-}
-
-/**
- * Function creating an array of relevant neighbors for the given node.
- *
- * @param  {string}       type      - Type of neighbors.
- * @param  {string}       direction - Direction.
- * @param  {any}          nodeData  - Target node's data.
- * @return {Array}                  - The list of neighbors.
- */
-function createNeighborArrayForNode(type, direction, nodeData) {
-  // If we want only undirected or in or out, we can roll some optimizations
-  if (type !== 'mixed') {
-    if (type === 'undirected') return Object.keys(nodeData.undirected);
-
-    if (typeof direction === 'string') return Object.keys(nodeData[direction]);
-  }
-
-  const neighbors = [];
-
-  forEachNeighbor(false, type, direction, nodeData, function (key) {
-    neighbors.push(key);
-  });
-
-  return neighbors;
-}
-
-/**
- * Function returning an iterator over the given node's relevant neighbors.
- *
- * @param  {string}   type      - Type of neighbors.
- * @param  {string}   direction - Direction.
- * @param  {any}      nodeData  - Target node's data.
- * @return {Iterator}
- */
-function createDedupedObjectIterator(visited, nodeData, object) {
-  const keys = Object.keys(object);
-  const l = keys.length;
-
-  let i = 0;
-
-  return new Iterator(function next() {
-    let neighborData = null;
-
-    do {
-      if (i >= l) {
-        if (visited) visited.wrap(object);
-        return {done: true};
-      }
-
-      const edgeData = object[keys[i++]];
-
-      const sourceData = edgeData.source;
-      const targetData = edgeData.target;
-
-      neighborData = sourceData === nodeData ? targetData : sourceData;
-
-      if (visited && visited.has(neighborData.key)) {
-        neighborData = null;
-        continue;
-      }
-    } while (neighborData === null);
-
-    return {
-      done: false,
-      value: {neighbor: neighborData.key, attributes: neighborData.attributes}
-    };
-  });
-}
-
-function createNeighborIterator(type, direction, nodeData) {
-  // If we want only undirected or in or out, we can roll some optimizations
-  if (type !== 'mixed') {
-    if (type === 'undirected')
-      return createDedupedObjectIterator(null, nodeData, nodeData.undirected);
-
-    if (typeof direction === 'string')
-      return createDedupedObjectIterator(null, nodeData, nodeData[direction]);
-  }
-
-  let iterator = Iterator.empty();
-
-  // Else we need to keep a set of neighbors not to return duplicates
-  // We cheat by querying the other adjacencies
-  const visited = new CompositeSetWrapper();
-
-  if (type !== 'undirected') {
-    if (direction !== 'out') {
-      iterator = chain(
-        iterator,
-        createDedupedObjectIterator(visited, nodeData, nodeData.in)
-      );
-    }
-    if (direction !== 'in') {
-      iterator = chain(
-        iterator,
-        createDedupedObjectIterator(visited, nodeData, nodeData.out)
-      );
-    }
-  }
-
-  if (type !== 'directed') {
-    iterator = chain(
-      iterator,
-      createDedupedObjectIterator(visited, nodeData, nodeData.undirected)
-    );
-  }
-
-  return iterator;
-}
-
-/**
- * Function attaching a neighbors array creator method to the Graph prototype.
- *
- * @param {function} Class       - Target class.
- * @param {object}   description - Method description.
- */
-function attachNeighborArrayCreator(Class, description) {
-  const {name, type, direction} = description;
-
-  /**
-   * Function returning an array of certain neighbors.
-   *
-   * @param  {any}   node   - Target node.
-   * @return {array} - The neighbors of neighbors.
-   *
-   * @throws {Error} - Will throw if node is not found in the graph.
-   */
-  Class.prototype[name] = function (node) {
-    // Early termination
-    if (type !== 'mixed' && this.type !== 'mixed' && type !== this.type)
-      return [];
-
-    node = '' + node;
-
-    const nodeData = this._nodes.get(node);
-
-    if (typeof nodeData === 'undefined')
-      throw new NotFoundGraphError(
-        `Graph.${name}: could not find the "${node}" node in the graph.`
-      );
-
-    // Here, we want to iterate over a node's relevant neighbors
-    return createNeighborArrayForNode(
-      type === 'mixed' ? this.type : type,
-      direction,
-      nodeData
-    );
-  };
-}
-
-/**
- * Function attaching a neighbors callback iterator method to the Graph prototype.
- *
- * @param {function} Class       - Target class.
- * @param {object}   description - Method description.
- */
-function attachForEachNeighbor(Class, description) {
-  const {name, type, direction} = description;
-
-  const forEachName = 'forEach' + name[0].toUpperCase() + name.slice(1, -1);
-
-  /**
-   * Function iterating over all the relevant neighbors using a callback.
-   *
-   * @param  {any}      node     - Target node.
-   * @param  {function} callback - Callback to use.
-   * @return {undefined}
-   *
-   * @throws {Error} - Will throw if there are too many arguments.
-   */
-  Class.prototype[forEachName] = function (node, callback) {
-    // Early termination
-    if (type !== 'mixed' && this.type !== 'mixed' && type !== this.type) return;
-
-    node = '' + node;
-
-    const nodeData = this._nodes.get(node);
-
-    if (typeof nodeData === 'undefined')
-      throw new NotFoundGraphError(
-        `Graph.${forEachName}: could not find the "${node}" node in the graph.`
-      );
-
-    // Here, we want to iterate over a node's relevant neighbors
-    forEachNeighbor(
-      false,
-      type === 'mixed' ? this.type : type,
-      direction,
-      nodeData,
-      callback
-    );
-  };
-
-  /**
-   * Function mapping the relevant neighbors using a callback.
-   *
-   * @param  {any}      node     - Target node.
-   * @param  {function} callback - Callback to use.
-   *
-   * @throws {Error} - Will throw if there are too many arguments.
-   */
-  const mapName = 'map' + name[0].toUpperCase() + name.slice(1);
-
-  Class.prototype[mapName] = function (node, callback) {
-    // TODO: optimize when size is known beforehand
-    const result = [];
-
-    this[forEachName](node, (n, a) => {
-      result.push(callback(n, a));
-    });
-
-    return result;
-  };
-
-  /**
-   * Function filtering the relevant neighbors using a callback.
-   *
-   * @param  {any}      node     - Target node.
-   * @param  {function} callback - Callback to use.
-   *
-   * @throws {Error} - Will throw if there are too many arguments.
-   */
-  const filterName = 'filter' + name[0].toUpperCase() + name.slice(1);
-
-  Class.prototype[filterName] = function (node, callback) {
-    const result = [];
-
-    this[forEachName](node, (n, a) => {
-      if (callback(n, a)) result.push(n);
-    });
-
-    return result;
-  };
-
-  /**
-   * Function reducing the relevant neighbors using a callback.
-   *
-   * @param  {any}      node     - Target node.
-   * @param  {function} callback - Callback to use.
-   *
-   * @throws {Error} - Will throw if there are too many arguments.
-   */
-  const reduceName = 'reduce' + name[0].toUpperCase() + name.slice(1);
-
-  Class.prototype[reduceName] = function (node, callback, initialValue) {
-    if (arguments.length < 3)
-      throw new InvalidArgumentsGraphError(
-        `Graph.${reduceName}: missing initial value. You must provide it because the callback takes more than one argument and we cannot infer the initial value from the first iteration, as you could with a simple array.`
-      );
-
-    let accumulator = initialValue;
-
-    this[forEachName](node, (n, a) => {
-      accumulator = callback(accumulator, n, a);
-    });
-
-    return accumulator;
-  };
-}
-
-/**
- * Function attaching a breakable neighbors callback iterator method to the
- * Graph prototype.
- *
- * @param {function} Class       - Target class.
- * @param {object}   description - Method description.
- */
-function attachFindNeighbor(Class, description) {
-  const {name, type, direction} = description;
-
-  const capitalizedSingular = name[0].toUpperCase() + name.slice(1, -1);
-
-  const findName = 'find' + capitalizedSingular;
-
-  /**
-   * Function iterating over all the relevant neighbors using a callback.
-   *
-   * @param  {any}      node     - Target node.
-   * @param  {function} callback - Callback to use.
-   * @return {undefined}
-   *
-   * @throws {Error} - Will throw if there are too many arguments.
-   */
-  Class.prototype[findName] = function (node, callback) {
-    // Early termination
-    if (type !== 'mixed' && this.type !== 'mixed' && type !== this.type) return;
-
-    node = '' + node;
-
-    const nodeData = this._nodes.get(node);
-
-    if (typeof nodeData === 'undefined')
-      throw new NotFoundGraphError(
-        `Graph.${findName}: could not find the "${node}" node in the graph.`
-      );
-
-    // Here, we want to iterate over a node's relevant neighbors
-    return forEachNeighbor(
-      true,
-      type === 'mixed' ? this.type : type,
-      direction,
-      nodeData,
-      callback
-    );
-  };
-
-  /**
-   * Function iterating over all the relevant neighbors to find if any of them
-   * matches the given predicate.
-   *
-   * @param  {any}      node     - Target node.
-   * @param  {function} callback - Callback to use.
-   * @return {boolean}
-   *
-   * @throws {Error} - Will throw if there are too many arguments.
-   */
-  const someName = 'some' + capitalizedSingular;
-
-  Class.prototype[someName] = function (node, callback) {
-    const found = this[findName](node, callback);
-
-    if (found) return true;
-
-    return false;
-  };
-
-  /**
-   * Function iterating over all the relevant neighbors to find if all of them
-   * matche the given predicate.
-   *
-   * @param  {any}      node     - Target node.
-   * @param  {function} callback - Callback to use.
-   * @return {boolean}
-   *
-   * @throws {Error} - Will throw if there are too many arguments.
-   */
-  const everyName = 'every' + capitalizedSingular;
-
-  Class.prototype[everyName] = function (node, callback) {
-    const found = this[findName](node, (n, a) => {
-      return !callback(n, a);
-    });
-
-    if (found) return false;
-
-    return true;
-  };
-}
-
-/**
- * Function attaching a neighbors callback iterator method to the Graph prototype.
- *
- * @param {function} Class       - Target class.
- * @param {object}   description - Method description.
- */
-function attachNeighborIteratorCreator(Class, description) {
-  const {name, type, direction} = description;
-
-  const iteratorName = name.slice(0, -1) + 'Entries';
-
-  /**
-   * Function returning an iterator over all the relevant neighbors.
-   *
-   * @param  {any}      node     - Target node.
-   * @return {Iterator}
-   *
-   * @throws {Error} - Will throw if there are too many arguments.
-   */
-  Class.prototype[iteratorName] = function (node) {
-    // Early termination
-    if (type !== 'mixed' && this.type !== 'mixed' && type !== this.type)
-      return Iterator.empty();
-
-    node = '' + node;
-
-    const nodeData = this._nodes.get(node);
-
-    if (typeof nodeData === 'undefined')
-      throw new NotFoundGraphError(
-        `Graph.${iteratorName}: could not find the "${node}" node in the graph.`
-      );
-
-    // Here, we want to iterate over a node's relevant neighbors
-    return createNeighborIterator(
-      type === 'mixed' ? this.type : type,
-      direction,
-      nodeData
-    );
-  };
-}
-
-/**
- * Function attaching every neighbor iteration method to the Graph class.
- *
- * @param {function} Graph - Graph class.
- */
-function attachNeighborIterationMethods(Graph) {
-  NEIGHBORS_ITERATION.forEach(description => {
-    attachNeighborArrayCreator(Graph, description);
-    attachForEachNeighbor(Graph, description);
-    attachFindNeighbor(Graph, description);
-    attachNeighborIteratorCreator(Graph, description);
-  });
-}
-
-/**
- * Graphology Adjacency Iteration
- * ===============================
- *
- * Attaching some methods to the Graph class to be able to iterate over a
- * graph's adjacency.
- */
-
-/**
- * Function iterating over a simple graph's adjacency using a callback.
- *
- * @param {boolean}  breakable         - Can we break?
- * @param {boolean}  assymetric        - Whether to emit undirected edges only once.
- * @param {boolean}  disconnectedNodes - Whether to emit disconnected nodes.
- * @param {Graph}    graph             - Target Graph instance.
- * @param {callback} function          - Iteration callback.
- */
-function forEachAdjacency(
-  breakable,
-  assymetric,
-  disconnectedNodes,
-  graph,
-  callback
-) {
-  const iterator = graph._nodes.values();
-
-  const type = graph.type;
-
-  let step, sourceData, neighbor, adj, edgeData, targetData, shouldBreak;
-
-  while (((step = iterator.next()), step.done !== true)) {
-    let hasEdges = false;
-
-    sourceData = step.value;
-
-    if (type !== 'undirected') {
-      adj = sourceData.out;
-
-      for (neighbor in adj) {
-        edgeData = adj[neighbor];
-
-        do {
-          targetData = edgeData.target;
-
-          hasEdges = true;
-          shouldBreak = callback(
-            sourceData.key,
-            targetData.key,
-            sourceData.attributes,
-            targetData.attributes,
-            edgeData.key,
-            edgeData.attributes,
-            edgeData.undirected
-          );
-
-          if (breakable && shouldBreak) return edgeData;
-
-          edgeData = edgeData.next;
-        } while (edgeData);
-      }
-    }
-
-    if (type !== 'directed') {
-      adj = sourceData.undirected;
-
-      for (neighbor in adj) {
-        if (assymetric && sourceData.key > neighbor) continue;
-
-        edgeData = adj[neighbor];
-
-        do {
-          targetData = edgeData.target;
-
-          if (targetData.key !== neighbor) targetData = edgeData.source;
-
-          hasEdges = true;
-          shouldBreak = callback(
-            sourceData.key,
-            targetData.key,
-            sourceData.attributes,
-            targetData.attributes,
-            edgeData.key,
-            edgeData.attributes,
-            edgeData.undirected
-          );
-
-          if (breakable && shouldBreak) return edgeData;
-
-          edgeData = edgeData.next;
-        } while (edgeData);
-      }
-    }
-
-    if (disconnectedNodes && !hasEdges) {
-      shouldBreak = callback(
-        sourceData.key,
-        null,
-        sourceData.attributes,
-        null,
-        null,
-        null,
-        null
-      );
-
-      if (breakable && shouldBreak) return null;
-    }
-  }
-
-  return;
-}
-
-/**
- * Graphology Serialization Utilities
- * ===================================
- *
- * Collection of functions used by the graph serialization schemes.
- */
-
-/**
- * Formats internal node data into a serialized node.
- *
- * @param  {any}    key  - The node's key.
- * @param  {object} data - Internal node's data.
- * @return {array}       - The serialized node.
- */
-function serializeNode(key, data) {
-  const serialized = {key};
-
-  if (!isEmpty(data.attributes))
-    serialized.attributes = assign({}, data.attributes);
-
-  return serialized;
-}
-
-/**
- * Formats internal edge data into a serialized edge.
- *
- * @param  {any}    key  - The edge's key.
- * @param  {object} data - Internal edge's data.
- * @return {array}       - The serialized edge.
- */
-function serializeEdge(key, data) {
-  const serialized = {
-    key,
-    source: data.source.key,
-    target: data.target.key
-  };
-
-  if (!isEmpty(data.attributes))
-    serialized.attributes = assign({}, data.attributes);
-
-  if (data.undirected) serialized.undirected = true;
-
-  return serialized;
-}
-
-/**
- * Checks whether the given value is a serialized node.
- *
- * @param  {mixed} value - Target value.
- * @return {string|null}
- */
-function validateSerializedNode(value) {
-  if (!isPlainObject(value))
-    throw new InvalidArgumentsGraphError(
-      'Graph.import: invalid serialized node. A serialized node should be a plain object with at least a "key" property.'
-    );
-
-  if (!('key' in value))
-    throw new InvalidArgumentsGraphError(
-      'Graph.import: serialized node is missing its key.'
-    );
-
-  if (
-    'attributes' in value &&
-    (!isPlainObject(value.attributes) || value.attributes === null)
-  )
-    throw new InvalidArgumentsGraphError(
-      'Graph.import: invalid attributes. Attributes should be a plain object, null or omitted.'
-    );
-}
-
-/**
- * Checks whether the given value is a serialized edge.
- *
- * @param  {mixed} value - Target value.
- * @return {string|null}
- */
-function validateSerializedEdge(value) {
-  if (!isPlainObject(value))
-    throw new InvalidArgumentsGraphError(
-      'Graph.import: invalid serialized edge. A serialized edge should be a plain object with at least a "source" & "target" property.'
-    );
-
-  if (!('source' in value))
-    throw new InvalidArgumentsGraphError(
-      'Graph.import: serialized edge is missing its source.'
-    );
-
-  if (!('target' in value))
-    throw new InvalidArgumentsGraphError(
-      'Graph.import: serialized edge is missing its target.'
-    );
-
-  if (
-    'attributes' in value &&
-    (!isPlainObject(value.attributes) || value.attributes === null)
-  )
-    throw new InvalidArgumentsGraphError(
-      'Graph.import: invalid attributes. Attributes should be a plain object, null or omitted.'
-    );
-
-  if ('undirected' in value && typeof value.undirected !== 'boolean')
-    throw new InvalidArgumentsGraphError(
-      'Graph.import: invalid undirectedness information. Undirected should be boolean or omitted.'
-    );
-}
-
-/* eslint no-nested-ternary: 0 */
-
-/**
- * Constants.
- */
-const INSTANCE_ID = incrementalIdStartingFromRandomByte();
-
-/**
- * Enums.
- */
-const TYPES = new Set(['directed', 'undirected', 'mixed']);
-
-const EMITTER_PROPS = new Set([
-  'domain',
-  '_events',
-  '_eventsCount',
-  '_maxListeners'
-]);
-
-const EDGE_ADD_METHODS = [
-  {
-    name: verb => `${verb}Edge`,
-    generateKey: true
-  },
-  {
-    name: verb => `${verb}DirectedEdge`,
-    generateKey: true,
-    type: 'directed'
-  },
-  {
-    name: verb => `${verb}UndirectedEdge`,
-    generateKey: true,
-    type: 'undirected'
-  },
-  {
-    name: verb => `${verb}EdgeWithKey`
-  },
-  {
-    name: verb => `${verb}DirectedEdgeWithKey`,
-    type: 'directed'
-  },
-  {
-    name: verb => `${verb}UndirectedEdgeWithKey`,
-    type: 'undirected'
-  }
-];
-
-/**
- * Default options.
- */
-const DEFAULTS = {
-  allowSelfLoops: true,
-  multi: false,
-  type: 'mixed'
-};
-
-/**
- * Abstract functions used by the Graph class for various methods.
- */
-
-/**
- * Internal method used to add a node to the given graph
- *
- * @param  {Graph}   graph           - Target graph.
- * @param  {any}     node            - The node's key.
- * @param  {object}  [attributes]    - Optional attributes.
- * @return {NodeData}                - Created node data.
- */
-function addNode(graph, node, attributes) {
-  if (attributes && !isPlainObject(attributes))
-    throw new InvalidArgumentsGraphError(
-      `Graph.addNode: invalid attributes. Expecting an object but got "${attributes}"`
-    );
-
-  // String coercion
-  node = '' + node;
-  attributes = attributes || {};
-
-  if (graph._nodes.has(node))
-    throw new UsageGraphError(
-      `Graph.addNode: the "${node}" node already exist in the graph.`
-    );
-
-  const data = new graph.NodeDataClass(node, attributes);
-
-  // Adding the node to internal register
-  graph._nodes.set(node, data);
-
-  // Emitting
-  graph.emit('nodeAdded', {
-    key: node,
-    attributes
-  });
-
-  return data;
-}
-
-/**
- * Same as the above but without sanity checks because we call this in contexts
- * where necessary checks were already done.
- */
-function unsafeAddNode(graph, node, attributes) {
-  const data = new graph.NodeDataClass(node, attributes);
-
-  graph._nodes.set(node, data);
-
-  graph.emit('nodeAdded', {
-    key: node,
-    attributes
-  });
-
-  return data;
-}
-
-/**
- * Internal method used to add an arbitrary edge to the given graph.
- *
- * @param  {Graph}   graph           - Target graph.
- * @param  {string}  name            - Name of the child method for errors.
- * @param  {boolean} mustGenerateKey - Should the graph generate an id?
- * @param  {boolean} undirected      - Whether the edge is undirected.
- * @param  {any}     edge            - The edge's key.
- * @param  {any}     source          - The source node.
- * @param  {any}     target          - The target node.
- * @param  {object}  [attributes]    - Optional attributes.
- * @return {any}                     - The edge.
- *
- * @throws {Error} - Will throw if the graph is of the wrong type.
- * @throws {Error} - Will throw if the given attributes are not an object.
- * @throws {Error} - Will throw if source or target doesn't exist.
- * @throws {Error} - Will throw if the edge already exist.
- */
-function addEdge(
-  graph,
-  name,
-  mustGenerateKey,
-  undirected,
-  edge,
-  source,
-  target,
-  attributes
-) {
-  // Checking validity of operation
-  if (!undirected && graph.type === 'undirected')
-    throw new UsageGraphError(
-      `Graph.${name}: you cannot add a directed edge to an undirected graph. Use the #.addEdge or #.addUndirectedEdge instead.`
-    );
-
-  if (undirected && graph.type === 'directed')
-    throw new UsageGraphError(
-      `Graph.${name}: you cannot add an undirected edge to a directed graph. Use the #.addEdge or #.addDirectedEdge instead.`
-    );
-
-  if (attributes && !isPlainObject(attributes))
-    throw new InvalidArgumentsGraphError(
-      `Graph.${name}: invalid attributes. Expecting an object but got "${attributes}"`
-    );
-
-  // Coercion of source & target:
-  source = '' + source;
-  target = '' + target;
-  attributes = attributes || {};
-
-  if (!graph.allowSelfLoops && source === target)
-    throw new UsageGraphError(
-      `Graph.${name}: source & target are the same ("${source}"), thus creating a loop explicitly forbidden by this graph 'allowSelfLoops' option set to false.`
-    );
-
-  const sourceData = graph._nodes.get(source),
-    targetData = graph._nodes.get(target);
-
-  if (!sourceData)
-    throw new NotFoundGraphError(
-      `Graph.${name}: source node "${source}" not found.`
-    );
-
-  if (!targetData)
-    throw new NotFoundGraphError(
-      `Graph.${name}: target node "${target}" not found.`
-    );
-
-  // Must the graph generate an id for this edge?
-  const eventData = {
-    key: null,
-    undirected,
-    source,
-    target,
-    attributes
-  };
-
-  if (mustGenerateKey) {
-    // NOTE: in this case we can guarantee that the key does not already
-    // exist and is already correctly casted as a string
-    edge = graph._edgeKeyGenerator();
-  } else {
-    // Coercion of edge key
-    edge = '' + edge;
-
-    // Here, we have a key collision
-    if (graph._edges.has(edge))
-      throw new UsageGraphError(
-        `Graph.${name}: the "${edge}" edge already exists in the graph.`
-      );
-  }
-
-  // Here, we might have a source / target collision
-  if (
-    !graph.multi &&
-    (undirected
-      ? typeof sourceData.undirected[target] !== 'undefined'
-      : typeof sourceData.out[target] !== 'undefined')
-  ) {
-    throw new UsageGraphError(
-      `Graph.${name}: an edge linking "${source}" to "${target}" already exists. If you really want to add multiple edges linking those nodes, you should create a multi graph by using the 'multi' option.`
-    );
-  }
-
-  // Storing some data
-  const edgeData = new EdgeData(
-    undirected,
-    edge,
-    sourceData,
-    targetData,
-    attributes
-  );
-
-  // Adding the edge to the internal register
-  graph._edges.set(edge, edgeData);
-
-  // Incrementing node degree counters
-  const isSelfLoop = source === target;
-
-  if (undirected) {
-    sourceData.undirectedDegree++;
-    targetData.undirectedDegree++;
-
-    if (isSelfLoop) graph._undirectedSelfLoopCount++;
-  } else {
-    sourceData.outDegree++;
-    targetData.inDegree++;
-
-    if (isSelfLoop) graph._directedSelfLoopCount++;
-  }
-
-  // Updating relevant index
-  if (graph.multi) edgeData.attachMulti();
-  else edgeData.attach();
-
-  if (undirected) graph._undirectedSize++;
-  else graph._directedSize++;
-
-  // Emitting
-  eventData.key = edge;
-
-  graph.emit('edgeAdded', eventData);
-
-  return edge;
-}
-
-/**
- * Internal method used to add an arbitrary edge to the given graph.
- *
- * @param  {Graph}   graph           - Target graph.
- * @param  {string}  name            - Name of the child method for errors.
- * @param  {boolean} mustGenerateKey - Should the graph generate an id?
- * @param  {boolean} undirected      - Whether the edge is undirected.
- * @param  {any}     edge            - The edge's key.
- * @param  {any}     source          - The source node.
- * @param  {any}     target          - The target node.
- * @param  {object}  [attributes]    - Optional attributes.
- * @param  {boolean} [asUpdater]       - Are we updating or merging?
- * @return {any}                     - The edge.
- *
- * @throws {Error} - Will throw if the graph is of the wrong type.
- * @throws {Error} - Will throw if the given attributes are not an object.
- * @throws {Error} - Will throw if source or target doesn't exist.
- * @throws {Error} - Will throw if the edge already exist.
- */
-function mergeEdge(
-  graph,
-  name,
-  mustGenerateKey,
-  undirected,
-  edge,
-  source,
-  target,
-  attributes,
-  asUpdater
-) {
-  // Checking validity of operation
-  if (!undirected && graph.type === 'undirected')
-    throw new UsageGraphError(
-      `Graph.${name}: you cannot merge/update a directed edge to an undirected graph. Use the #.mergeEdge/#.updateEdge or #.addUndirectedEdge instead.`
-    );
-
-  if (undirected && graph.type === 'directed')
-    throw new UsageGraphError(
-      `Graph.${name}: you cannot merge/update an undirected edge to a directed graph. Use the #.mergeEdge/#.updateEdge or #.addDirectedEdge instead.`
-    );
-
-  if (attributes) {
-    if (asUpdater) {
-      if (typeof attributes !== 'function')
-        throw new InvalidArgumentsGraphError(
-          `Graph.${name}: invalid updater function. Expecting a function but got "${attributes}"`
-        );
-    } else {
-      if (!isPlainObject(attributes))
-        throw new InvalidArgumentsGraphError(
-          `Graph.${name}: invalid attributes. Expecting an object but got "${attributes}"`
-        );
-    }
-  }
-
-  // Coercion of source & target:
-  source = '' + source;
-  target = '' + target;
-
-  let updater;
-
-  if (asUpdater) {
-    updater = attributes;
-    attributes = undefined;
-  }
-
-  if (!graph.allowSelfLoops && source === target)
-    throw new UsageGraphError(
-      `Graph.${name}: source & target are the same ("${source}"), thus creating a loop explicitly forbidden by this graph 'allowSelfLoops' option set to false.`
-    );
-
-  let sourceData = graph._nodes.get(source);
-  let targetData = graph._nodes.get(target);
-  let edgeData;
-
-  // Do we need to handle duplicate?
-  let alreadyExistingEdgeData;
-
-  if (!mustGenerateKey) {
-    edgeData = graph._edges.get(edge);
-
-    if (edgeData) {
-      // Here, we need to ensure, if the user gave a key, that source & target
-      // are consistent
-      if (edgeData.source.key !== source || edgeData.target.key !== target) {
-        // If source or target inconsistent
-        if (
-          !undirected ||
-          edgeData.source.key !== target ||
-          edgeData.target.key !== source
-        ) {
-          // If directed, or source/target aren't flipped
-          throw new UsageGraphError(
-            `Graph.${name}: inconsistency detected when attempting to merge the "${edge}" edge with "${source}" source & "${target}" target vs. ("${edgeData.source.key}", "${edgeData.target.key}").`
-          );
-        }
-      }
-
-      alreadyExistingEdgeData = edgeData;
-    }
-  }
-
-  // Here, we might have a source / target collision
-  if (!alreadyExistingEdgeData && !graph.multi && sourceData) {
-    alreadyExistingEdgeData = undirected
-      ? sourceData.undirected[target]
-      : sourceData.out[target];
-  }
-
-  // Handling duplicates
-  if (alreadyExistingEdgeData) {
-    const info = [alreadyExistingEdgeData.key, false, false, false];
-
-    // We can skip the attribute merging part if the user did not provide them
-    if (asUpdater ? !updater : !attributes) return info;
-
-    // Updating the attributes
-    if (asUpdater) {
-      const oldAttributes = alreadyExistingEdgeData.attributes;
-      alreadyExistingEdgeData.attributes = updater(oldAttributes);
-
-      graph.emit('edgeAttributesUpdated', {
-        type: 'replace',
-        key: alreadyExistingEdgeData.key,
-        attributes: alreadyExistingEdgeData.attributes
-      });
-    }
-
-    // Merging the attributes
-    else {
-      assign(alreadyExistingEdgeData.attributes, attributes);
-
-      graph.emit('edgeAttributesUpdated', {
-        type: 'merge',
-        key: alreadyExistingEdgeData.key,
-        attributes: alreadyExistingEdgeData.attributes,
-        data: attributes
-      });
-    }
-
-    return info;
-  }
-
-  attributes = attributes || {};
-
-  if (asUpdater && updater) attributes = updater(attributes);
-
-  // Must the graph generate an id for this edge?
-  const eventData = {
-    key: null,
-    undirected,
-    source,
-    target,
-    attributes
-  };
-
-  if (mustGenerateKey) {
-    // NOTE: in this case we can guarantee that the key does not already
-    // exist and is already correctly casted as a string
-    edge = graph._edgeKeyGenerator();
-  } else {
-    // Coercion of edge key
-    edge = '' + edge;
-
-    // Here, we have a key collision
-    if (graph._edges.has(edge))
-      throw new UsageGraphError(
-        `Graph.${name}: the "${edge}" edge already exists in the graph.`
-      );
-  }
-
-  let sourceWasAdded = false;
-  let targetWasAdded = false;
-
-  if (!sourceData) {
-    sourceData = unsafeAddNode(graph, source, {});
-    sourceWasAdded = true;
-
-    if (source === target) {
-      targetData = sourceData;
-      targetWasAdded = true;
-    }
-  }
-  if (!targetData) {
-    targetData = unsafeAddNode(graph, target, {});
-    targetWasAdded = true;
-  }
-
-  // Storing some data
-  edgeData = new EdgeData(undirected, edge, sourceData, targetData, attributes);
-
-  // Adding the edge to the internal register
-  graph._edges.set(edge, edgeData);
-
-  // Incrementing node degree counters
-  const isSelfLoop = source === target;
-
-  if (undirected) {
-    sourceData.undirectedDegree++;
-    targetData.undirectedDegree++;
-
-    if (isSelfLoop) graph._undirectedSelfLoopCount++;
-  } else {
-    sourceData.outDegree++;
-    targetData.inDegree++;
-
-    if (isSelfLoop) graph._directedSelfLoopCount++;
-  }
-
-  // Updating relevant index
-  if (graph.multi) edgeData.attachMulti();
-  else edgeData.attach();
-
-  if (undirected) graph._undirectedSize++;
-  else graph._directedSize++;
-
-  // Emitting
-  eventData.key = edge;
-
-  graph.emit('edgeAdded', eventData);
-
-  return [edge, true, sourceWasAdded, targetWasAdded];
-}
-
-/**
- * Internal method used to drop an edge.
- *
- * @param  {Graph}    graph    - Target graph.
- * @param  {EdgeData} edgeData - Data of the edge to drop.
- */
-function dropEdgeFromData(graph, edgeData) {
-  // Dropping the edge from the register
-  graph._edges.delete(edgeData.key);
-
-  // Updating related degrees
-  const {source: sourceData, target: targetData, attributes} = edgeData;
-
-  const undirected = edgeData.undirected;
-
-  const isSelfLoop = sourceData === targetData;
-
-  if (undirected) {
-    sourceData.undirectedDegree--;
-    targetData.undirectedDegree--;
-
-    if (isSelfLoop) graph._undirectedSelfLoopCount--;
-  } else {
-    sourceData.outDegree--;
-    targetData.inDegree--;
-
-    if (isSelfLoop) graph._directedSelfLoopCount--;
-  }
-
-  // Clearing index
-  if (graph.multi) edgeData.detachMulti();
-  else edgeData.detach();
-
-  if (undirected) graph._undirectedSize--;
-  else graph._directedSize--;
-
-  // Emitting
-  graph.emit('edgeDropped', {
-    key: edgeData.key,
-    attributes,
-    source: sourceData.key,
-    target: targetData.key,
-    undirected
-  });
-}
-
-/**
- * Graph class
- *
- * @constructor
- * @param  {object}  [options] - Options:
- * @param  {boolean}   [allowSelfLoops] - Allow self loops?
- * @param  {string}    [type]           - Type of the graph.
- * @param  {boolean}   [map]            - Allow references as keys?
- * @param  {boolean}   [multi]          - Allow parallel edges?
- *
- * @throws {Error} - Will throw if the arguments are not valid.
- */
-class Graph extends EventEmitter {
-  constructor(options) {
-    super();
-
-    //-- Solving options
-    options = assign({}, DEFAULTS, options);
-
-    // Enforcing options validity
-    if (typeof options.multi !== 'boolean')
-      throw new InvalidArgumentsGraphError(
-        `Graph.constructor: invalid 'multi' option. Expecting a boolean but got "${options.multi}".`
-      );
-
-    if (!TYPES.has(options.type))
-      throw new InvalidArgumentsGraphError(
-        `Graph.constructor: invalid 'type' option. Should be one of "mixed", "directed" or "undirected" but got "${options.type}".`
-      );
-
-    if (typeof options.allowSelfLoops !== 'boolean')
-      throw new InvalidArgumentsGraphError(
-        `Graph.constructor: invalid 'allowSelfLoops' option. Expecting a boolean but got "${options.allowSelfLoops}".`
-      );
-
-    //-- Private properties
-
-    // Utilities
-    const NodeDataClass =
-      options.type === 'mixed'
-        ? MixedNodeData
-        : options.type === 'directed'
-        ? DirectedNodeData
-        : UndirectedNodeData;
-
-    privateProperty(this, 'NodeDataClass', NodeDataClass);
-
-    // Internal edge key generator
-
-    // NOTE: this internal generator produce keys that are strings
-    // composed of a weird prefix, an incremental instance id starting from
-    // a random byte and finally an internal instance incremental id.
-    // All this to avoid intra-frame and cross-frame adversarial inputs
-    // that can force a single #.addEdge call to degenerate into a O(n)
-    // available key search loop.
-
-    // It also ensures that automatically generated edge keys are unlikely
-    // to produce collisions with arbitrary keys given by users.
-    const instancePrefix = 'geid_' + INSTANCE_ID() + '_';
-    let edgeId = 0;
-
-    const edgeKeyGenerator = () => {
-      let availableEdgeKey;
-
-      do {
-        availableEdgeKey = instancePrefix + edgeId++;
-      } while (this._edges.has(availableEdgeKey));
-
-      return availableEdgeKey;
-    };
-
-    // Indexes
-    privateProperty(this, '_attributes', {});
-    privateProperty(this, '_nodes', new Map());
-    privateProperty(this, '_edges', new Map());
-    privateProperty(this, '_directedSize', 0);
-    privateProperty(this, '_undirectedSize', 0);
-    privateProperty(this, '_directedSelfLoopCount', 0);
-    privateProperty(this, '_undirectedSelfLoopCount', 0);
-    privateProperty(this, '_edgeKeyGenerator', edgeKeyGenerator);
-
-    // Options
-    privateProperty(this, '_options', options);
-
-    // Emitter properties
-    EMITTER_PROPS.forEach(prop => privateProperty(this, prop, this[prop]));
-
-    //-- Properties readers
-    readOnlyProperty(this, 'order', () => this._nodes.size);
-    readOnlyProperty(this, 'size', () => this._edges.size);
-    readOnlyProperty(this, 'directedSize', () => this._directedSize);
-    readOnlyProperty(this, 'undirectedSize', () => this._undirectedSize);
-    readOnlyProperty(
-      this,
-      'selfLoopCount',
-      () => this._directedSelfLoopCount + this._undirectedSelfLoopCount
-    );
-    readOnlyProperty(
-      this,
-      'directedSelfLoopCount',
-      () => this._directedSelfLoopCount
-    );
-    readOnlyProperty(
-      this,
-      'undirectedSelfLoopCount',
-      () => this._undirectedSelfLoopCount
-    );
-    readOnlyProperty(this, 'multi', this._options.multi);
-    readOnlyProperty(this, 'type', this._options.type);
-    readOnlyProperty(this, 'allowSelfLoops', this._options.allowSelfLoops);
-    readOnlyProperty(this, 'implementation', () => 'graphology');
-  }
-
-  _resetInstanceCounters() {
-    this._directedSize = 0;
-    this._undirectedSize = 0;
-    this._directedSelfLoopCount = 0;
-    this._undirectedSelfLoopCount = 0;
-  }
-
-  /**---------------------------------------------------------------------------
-   * Read
-   **---------------------------------------------------------------------------
-   */
-
-  /**
-   * Method returning whether the given node is found in the graph.
-   *
-   * @param  {any}     node - The node.
-   * @return {boolean}
-   */
-  hasNode(node) {
-    return this._nodes.has('' + node);
-  }
-
-  /**
-   * Method returning whether the given directed edge is found in the graph.
-   *
-   * Arity 1:
-   * @param  {any}     edge - The edge's key.
-   *
-   * Arity 2:
-   * @param  {any}     source - The edge's source.
-   * @param  {any}     target - The edge's target.
-   *
-   * @return {boolean}
-   *
-   * @throws {Error} - Will throw if the arguments are invalid.
-   */
-  hasDirectedEdge(source, target) {
-    // Early termination
-    if (this.type === 'undirected') return false;
-
-    if (arguments.length === 1) {
-      const edge = '' + source;
-
-      const edgeData = this._edges.get(edge);
-
-      return !!edgeData && !edgeData.undirected;
-    } else if (arguments.length === 2) {
-      source = '' + source;
-      target = '' + target;
-
-      // If the node source or the target is not in the graph we break
-      const nodeData = this._nodes.get(source);
-
-      if (!nodeData) return false;
-
-      // Is there a directed edge pointing toward target?
-      const edges = nodeData.out[target];
-
-      if (!edges) return false;
-
-      return this.multi ? !!edges.size : true;
-    }
-
-    throw new InvalidArgumentsGraphError(
-      `Graph.hasDirectedEdge: invalid arity (${arguments.length}, instead of 1 or 2). You can either ask for an edge id or for the existence of an edge between a source & a target.`
-    );
-  }
-
-  /**
-   * Method returning whether the given undirected edge is found in the graph.
-   *
-   * Arity 1:
-   * @param  {any}     edge - The edge's key.
-   *
-   * Arity 2:
-   * @param  {any}     source - The edge's source.
-   * @param  {any}     target - The edge's target.
-   *
-   * @return {boolean}
-   *
-   * @throws {Error} - Will throw if the arguments are invalid.
-   */
-  hasUndirectedEdge(source, target) {
-    // Early termination
-    if (this.type === 'directed') return false;
-
-    if (arguments.length === 1) {
-      const edge = '' + source;
-
-      const edgeData = this._edges.get(edge);
-
-      return !!edgeData && edgeData.undirected;
-    } else if (arguments.length === 2) {
-      source = '' + source;
-      target = '' + target;
-
-      // If the node source or the target is not in the graph we break
-      const nodeData = this._nodes.get(source);
-
-      if (!nodeData) return false;
-
-      // Is there a directed edge pointing toward target?
-      const edges = nodeData.undirected[target];
-
-      if (!edges) return false;
-
-      return this.multi ? !!edges.size : true;
-    }
-
-    throw new InvalidArgumentsGraphError(
-      `Graph.hasDirectedEdge: invalid arity (${arguments.length}, instead of 1 or 2). You can either ask for an edge id or for the existence of an edge between a source & a target.`
-    );
-  }
-
-  /**
-   * Method returning whether the given edge is found in the graph.
-   *
-   * Arity 1:
-   * @param  {any}     edge - The edge's key.
-   *
-   * Arity 2:
-   * @param  {any}     source - The edge's source.
-   * @param  {any}     target - The edge's target.
-   *
-   * @return {boolean}
-   *
-   * @throws {Error} - Will throw if the arguments are invalid.
-   */
-  hasEdge(source, target) {
-    if (arguments.length === 1) {
-      const edge = '' + source;
-
-      return this._edges.has(edge);
-    } else if (arguments.length === 2) {
-      source = '' + source;
-      target = '' + target;
-
-      // If the node source or the target is not in the graph we break
-      const nodeData = this._nodes.get(source);
-
-      if (!nodeData) return false;
-
-      // Is there a directed edge pointing toward target?
-      let edges = typeof nodeData.out !== 'undefined' && nodeData.out[target];
-
-      if (!edges)
-        edges =
-          typeof nodeData.undirected !== 'undefined' &&
-          nodeData.undirected[target];
-
-      if (!edges) return false;
-
-      return this.multi ? !!edges.size : true;
-    }
-
-    throw new InvalidArgumentsGraphError(
-      `Graph.hasEdge: invalid arity (${arguments.length}, instead of 1 or 2). You can either ask for an edge id or for the existence of an edge between a source & a target.`
-    );
-  }
-
-  /**
-   * Method returning the edge matching source & target in a directed fashion.
-   *
-   * @param  {any} source - The edge's source.
-   * @param  {any} target - The edge's target.
-   *
-   * @return {any|undefined}
-   *
-   * @throws {Error} - Will throw if the graph is multi.
-   * @throws {Error} - Will throw if source or target doesn't exist.
-   */
-  directedEdge(source, target) {
-    if (this.type === 'undirected') return;
-
-    source = '' + source;
-    target = '' + target;
-
-    if (this.multi)
-      throw new UsageGraphError(
-        'Graph.directedEdge: this method is irrelevant with multigraphs since there might be multiple edges between source & target. See #.directedEdges instead.'
-      );
-
-    const sourceData = this._nodes.get(source);
-
-    if (!sourceData)
-      throw new NotFoundGraphError(
-        `Graph.directedEdge: could not find the "${source}" source node in the graph.`
-      );
-
-    if (!this._nodes.has(target))
-      throw new NotFoundGraphError(
-        `Graph.directedEdge: could not find the "${target}" target node in the graph.`
-      );
-
-    const edgeData = (sourceData.out && sourceData.out[target]) || undefined;
-
-    if (edgeData) return edgeData.key;
-  }
-
-  /**
-   * Method returning the edge matching source & target in a undirected fashion.
-   *
-   * @param  {any} source - The edge's source.
-   * @param  {any} target - The edge's target.
-   *
-   * @return {any|undefined}
-   *
-   * @throws {Error} - Will throw if the graph is multi.
-   * @throws {Error} - Will throw if source or target doesn't exist.
-   */
-  undirectedEdge(source, target) {
-    if (this.type === 'directed') return;
-
-    source = '' + source;
-    target = '' + target;
-
-    if (this.multi)
-      throw new UsageGraphError(
-        'Graph.undirectedEdge: this method is irrelevant with multigraphs since there might be multiple edges between source & target. See #.undirectedEdges instead.'
-      );
-
-    const sourceData = this._nodes.get(source);
-
-    if (!sourceData)
-      throw new NotFoundGraphError(
-        `Graph.undirectedEdge: could not find the "${source}" source node in the graph.`
-      );
-
-    if (!this._nodes.has(target))
-      throw new NotFoundGraphError(
-        `Graph.undirectedEdge: could not find the "${target}" target node in the graph.`
-      );
-
-    const edgeData =
-      (sourceData.undirected && sourceData.undirected[target]) || undefined;
-
-    if (edgeData) return edgeData.key;
-  }
-
-  /**
-   * Method returning the edge matching source & target in a mixed fashion.
-   *
-   * @param  {any} source - The edge's source.
-   * @param  {any} target - The edge's target.
-   *
-   * @return {any|undefined}
-   *
-   * @throws {Error} - Will throw if the graph is multi.
-   * @throws {Error} - Will throw if source or target doesn't exist.
-   */
-  edge(source, target) {
-    if (this.multi)
-      throw new UsageGraphError(
-        'Graph.edge: this method is irrelevant with multigraphs since there might be multiple edges between source & target. See #.edges instead.'
-      );
-
-    source = '' + source;
-    target = '' + target;
-
-    const sourceData = this._nodes.get(source);
-
-    if (!sourceData)
-      throw new NotFoundGraphError(
-        `Graph.edge: could not find the "${source}" source node in the graph.`
-      );
-
-    if (!this._nodes.has(target))
-      throw new NotFoundGraphError(
-        `Graph.edge: could not find the "${target}" target node in the graph.`
-      );
-
-    const edgeData =
-      (sourceData.out && sourceData.out[target]) ||
-      (sourceData.undirected && sourceData.undirected[target]) ||
-      undefined;
-
-    if (edgeData) return edgeData.key;
-  }
-
-  /**
-   * Method returning whether two nodes are directed neighbors.
-   *
-   * @param  {any}     node     - The node's key.
-   * @param  {any}     neighbor - The neighbor's key.
-   * @return {boolean}
-   *
-   * @throws {Error} - Will throw if the node isn't in the graph.
-   */
-  areDirectedNeighbors(node, neighbor) {
-    node = '' + node;
-    neighbor = '' + neighbor;
-
-    const nodeData = this._nodes.get(node);
-
-    if (!nodeData)
-      throw new NotFoundGraphError(
-        `Graph.areDirectedNeighbors: could not find the "${node}" node in the graph.`
-      );
-
-    if (this.type === 'undirected') return false;
-
-    return neighbor in nodeData.in || neighbor in nodeData.out;
-  }
-
-  /**
-   * Method returning whether two nodes are out neighbors.
-   *
-   * @param  {any}     node     - The node's key.
-   * @param  {any}     neighbor - The neighbor's key.
-   * @return {boolean}
-   *
-   * @throws {Error} - Will throw if the node isn't in the graph.
-   */
-  areOutNeighbors(node, neighbor) {
-    node = '' + node;
-    neighbor = '' + neighbor;
-
-    const nodeData = this._nodes.get(node);
-
-    if (!nodeData)
-      throw new NotFoundGraphError(
-        `Graph.areOutNeighbors: could not find the "${node}" node in the graph.`
-      );
-
-    if (this.type === 'undirected') return false;
-
-    return neighbor in nodeData.out;
-  }
-
-  /**
-   * Method returning whether two nodes are in neighbors.
-   *
-   * @param  {any}     node     - The node's key.
-   * @param  {any}     neighbor - The neighbor's key.
-   * @return {boolean}
-   *
-   * @throws {Error} - Will throw if the node isn't in the graph.
-   */
-  areInNeighbors(node, neighbor) {
-    node = '' + node;
-    neighbor = '' + neighbor;
-
-    const nodeData = this._nodes.get(node);
-
-    if (!nodeData)
-      throw new NotFoundGraphError(
-        `Graph.areInNeighbors: could not find the "${node}" node in the graph.`
-      );
-
-    if (this.type === 'undirected') return false;
-
-    return neighbor in nodeData.in;
-  }
-
-  /**
-   * Method returning whether two nodes are undirected neighbors.
-   *
-   * @param  {any}     node     - The node's key.
-   * @param  {any}     neighbor - The neighbor's key.
-   * @return {boolean}
-   *
-   * @throws {Error} - Will throw if the node isn't in the graph.
-   */
-  areUndirectedNeighbors(node, neighbor) {
-    node = '' + node;
-    neighbor = '' + neighbor;
-
-    const nodeData = this._nodes.get(node);
-
-    if (!nodeData)
-      throw new NotFoundGraphError(
-        `Graph.areUndirectedNeighbors: could not find the "${node}" node in the graph.`
-      );
-
-    if (this.type === 'directed') return false;
-
-    return neighbor in nodeData.undirected;
-  }
-
-  /**
-   * Method returning whether two nodes are neighbors.
-   *
-   * @param  {any}     node     - The node's key.
-   * @param  {any}     neighbor - The neighbor's key.
-   * @return {boolean}
-   *
-   * @throws {Error} - Will throw if the node isn't in the graph.
-   */
-  areNeighbors(node, neighbor) {
-    node = '' + node;
-    neighbor = '' + neighbor;
-
-    const nodeData = this._nodes.get(node);
-
-    if (!nodeData)
-      throw new NotFoundGraphError(
-        `Graph.areNeighbors: could not find the "${node}" node in the graph.`
-      );
-
-    if (this.type !== 'undirected') {
-      if (neighbor in nodeData.in || neighbor in nodeData.out) return true;
-    }
-
-    if (this.type !== 'directed') {
-      if (neighbor in nodeData.undirected) return true;
-    }
-
-    return false;
-  }
-
-  /**
-   * Method returning whether two nodes are inbound neighbors.
-   *
-   * @param  {any}     node     - The node's key.
-   * @param  {any}     neighbor - The neighbor's key.
-   * @return {boolean}
-   *
-   * @throws {Error} - Will throw if the node isn't in the graph.
-   */
-  areInboundNeighbors(node, neighbor) {
-    node = '' + node;
-    neighbor = '' + neighbor;
-
-    const nodeData = this._nodes.get(node);
-
-    if (!nodeData)
-      throw new NotFoundGraphError(
-        `Graph.areInboundNeighbors: could not find the "${node}" node in the graph.`
-      );
-
-    if (this.type !== 'undirected') {
-      if (neighbor in nodeData.in) return true;
-    }
-
-    if (this.type !== 'directed') {
-      if (neighbor in nodeData.undirected) return true;
-    }
-
-    return false;
-  }
-
-  /**
-   * Method returning whether two nodes are outbound neighbors.
-   *
-   * @param  {any}     node     - The node's key.
-   * @param  {any}     neighbor - The neighbor's key.
-   * @return {boolean}
-   *
-   * @throws {Error} - Will throw if the node isn't in the graph.
-   */
-  areOutboundNeighbors(node, neighbor) {
-    node = '' + node;
-    neighbor = '' + neighbor;
-
-    const nodeData = this._nodes.get(node);
-
-    if (!nodeData)
-      throw new NotFoundGraphError(
-        `Graph.areOutboundNeighbors: could not find the "${node}" node in the graph.`
-      );
-
-    if (this.type !== 'undirected') {
-      if (neighbor in nodeData.out) return true;
-    }
-
-    if (this.type !== 'directed') {
-      if (neighbor in nodeData.undirected) return true;
-    }
-
-    return false;
-  }
-
-  /**
-   * Method returning the given node's in degree.
-   *
-   * @param  {any}     node - The node's key.
-   * @return {number}       - The node's in degree.
-   *
-   * @throws {Error} - Will throw if the node isn't in the graph.
-   */
-  inDegree(node) {
-    node = '' + node;
-
-    const nodeData = this._nodes.get(node);
-
-    if (!nodeData)
-      throw new NotFoundGraphError(
-        `Graph.inDegree: could not find the "${node}" node in the graph.`
-      );
-
-    if (this.type === 'undirected') return 0;
-
-    return nodeData.inDegree;
-  }
-
-  /**
-   * Method returning the given node's out degree.
-   *
-   * @param  {any}     node - The node's key.
-   * @return {number}       - The node's in degree.
-   *
-   * @throws {Error} - Will throw if the node isn't in the graph.
-   */
-  outDegree(node) {
-    node = '' + node;
-
-    const nodeData = this._nodes.get(node);
-
-    if (!nodeData)
-      throw new NotFoundGraphError(
-        `Graph.outDegree: could not find the "${node}" node in the graph.`
-      );
-
-    if (this.type === 'undirected') return 0;
-
-    return nodeData.outDegree;
-  }
-
-  /**
-   * Method returning the given node's directed degree.
-   *
-   * @param  {any}     node - The node's key.
-   * @return {number}       - The node's in degree.
-   *
-   * @throws {Error} - Will throw if the node isn't in the graph.
-   */
-  directedDegree(node) {
-    node = '' + node;
-
-    const nodeData = this._nodes.get(node);
-
-    if (!nodeData)
-      throw new NotFoundGraphError(
-        `Graph.directedDegree: could not find the "${node}" node in the graph.`
-      );
-
-    if (this.type === 'undirected') return 0;
-
-    return nodeData.inDegree + nodeData.outDegree;
-  }
-
-  /**
-   * Method returning the given node's undirected degree.
-   *
-   * @param  {any}     node - The node's key.
-   * @return {number}       - The node's in degree.
-   *
-   * @throws {Error} - Will throw if the node isn't in the graph.
-   */
-  undirectedDegree(node) {
-    node = '' + node;
-
-    const nodeData = this._nodes.get(node);
-
-    if (!nodeData)
-      throw new NotFoundGraphError(
-        `Graph.undirectedDegree: could not find the "${node}" node in the graph.`
-      );
-
-    if (this.type === 'directed') return 0;
-
-    return nodeData.undirectedDegree;
-  }
-
-  /**
-   * Method returning the given node's inbound degree.
-   *
-   * @param  {any}     node - The node's key.
-   * @return {number}       - The node's inbound degree.
-   *
-   * @throws {Error} - Will throw if the node isn't in the graph.
-   */
-  inboundDegree(node) {
-    node = '' + node;
-
-    const nodeData = this._nodes.get(node);
-
-    if (!nodeData)
-      throw new NotFoundGraphError(
-        `Graph.inboundDegree: could not find the "${node}" node in the graph.`
-      );
-
-    let degree = 0;
-
-    if (this.type !== 'directed') {
-      degree += nodeData.undirectedDegree;
-    }
-
-    if (this.type !== 'undirected') {
-      degree += nodeData.inDegree;
-    }
-
-    return degree;
-  }
-
-  /**
-   * Method returning the given node's outbound degree.
-   *
-   * @param  {any}     node - The node's key.
-   * @return {number}       - The node's outbound degree.
-   *
-   * @throws {Error} - Will throw if the node isn't in the graph.
-   */
-  outboundDegree(node) {
-    node = '' + node;
-
-    const nodeData = this._nodes.get(node);
-
-    if (!nodeData)
-      throw new NotFoundGraphError(
-        `Graph.outboundDegree: could not find the "${node}" node in the graph.`
-      );
-
-    let degree = 0;
-
-    if (this.type !== 'directed') {
-      degree += nodeData.undirectedDegree;
-    }
-
-    if (this.type !== 'undirected') {
-      degree += nodeData.outDegree;
-    }
-
-    return degree;
-  }
-
-  /**
-   * Method returning the given node's directed degree.
-   *
-   * @param  {any}     node - The node's key.
-   * @return {number}       - The node's degree.
-   *
-   * @throws {Error} - Will throw if the node isn't in the graph.
-   */
-  degree(node) {
-    node = '' + node;
-
-    const nodeData = this._nodes.get(node);
-
-    if (!nodeData)
-      throw new NotFoundGraphError(
-        `Graph.degree: could not find the "${node}" node in the graph.`
-      );
-
-    let degree = 0;
-
-    if (this.type !== 'directed') {
-      degree += nodeData.undirectedDegree;
-    }
-
-    if (this.type !== 'undirected') {
-      degree += nodeData.inDegree + nodeData.outDegree;
-    }
-
-    return degree;
-  }
-
-  /**
-   * Method returning the given node's in degree without considering self loops.
-   *
-   * @param  {any}     node - The node's key.
-   * @return {number}       - The node's in degree.
-   *
-   * @throws {Error} - Will throw if the node isn't in the graph.
-   */
-  inDegreeWithoutSelfLoops(node) {
-    node = '' + node;
-
-    const nodeData = this._nodes.get(node);
-
-    if (!nodeData)
-      throw new NotFoundGraphError(
-        `Graph.inDegreeWithoutSelfLoops: could not find the "${node}" node in the graph.`
-      );
-
-    if (this.type === 'undirected') return 0;
-
-    const self = nodeData.in[node];
-    const loops = self ? (this.multi ? self.size : 1) : 0;
-
-    return nodeData.inDegree - loops;
-  }
-
-  /**
-   * Method returning the given node's out degree without considering self loops.
-   *
-   * @param  {any}     node - The node's key.
-   * @return {number}       - The node's in degree.
-   *
-   * @throws {Error} - Will throw if the node isn't in the graph.
-   */
-  outDegreeWithoutSelfLoops(node) {
-    node = '' + node;
-
-    const nodeData = this._nodes.get(node);
-
-    if (!nodeData)
-      throw new NotFoundGraphError(
-        `Graph.outDegreeWithoutSelfLoops: could not find the "${node}" node in the graph.`
-      );
-
-    if (this.type === 'undirected') return 0;
-
-    const self = nodeData.out[node];
-    const loops = self ? (this.multi ? self.size : 1) : 0;
-
-    return nodeData.outDegree - loops;
-  }
-
-  /**
-   * Method returning the given node's directed degree without considering self loops.
-   *
-   * @param  {any}     node - The node's key.
-   * @return {number}       - The node's in degree.
-   *
-   * @throws {Error} - Will throw if the node isn't in the graph.
-   */
-  directedDegreeWithoutSelfLoops(node) {
-    node = '' + node;
-
-    const nodeData = this._nodes.get(node);
-
-    if (!nodeData)
-      throw new NotFoundGraphError(
-        `Graph.directedDegreeWithoutSelfLoops: could not find the "${node}" node in the graph.`
-      );
-
-    if (this.type === 'undirected') return 0;
-
-    const self = nodeData.out[node];
-    const loops = self ? (this.multi ? self.size : 1) : 0;
-
-    return nodeData.inDegree + nodeData.outDegree - loops * 2;
-  }
-
-  /**
-   * Method returning the given node's undirected degree without considering self loops.
-   *
-   * @param  {any}     node - The node's key.
-   * @return {number}       - The node's in degree.
-   *
-   * @throws {Error} - Will throw if the node isn't in the graph.
-   */
-  undirectedDegreeWithoutSelfLoops(node) {
-    node = '' + node;
-
-    const nodeData = this._nodes.get(node);
-
-    if (!nodeData)
-      throw new NotFoundGraphError(
-        `Graph.undirectedDegreeWithoutSelfLoops: could not find the "${node}" node in the graph.`
-      );
-
-    if (this.type === 'directed') return 0;
-
-    const self = nodeData.undirected[node];
-    const loops = self ? (this.multi ? self.size : 1) : 0;
-
-    return nodeData.undirectedDegree - loops * 2;
-  }
-
-  /**
-   * Method returning the given node's inbound degree without considering self loops.
-   *
-   * @param  {any}     node - The node's key.
-   * @return {number}       - The node's inbound degree.
-   *
-   * @throws {Error} - Will throw if the node isn't in the graph.
-   */
-  inboundDegreeWithoutSelfLoops(node) {
-    node = '' + node;
-
-    const nodeData = this._nodes.get(node);
-
-    if (!nodeData)
-      throw new NotFoundGraphError(
-        `Graph.inboundDegreeWithoutSelfLoops: could not find the "${node}" node in the graph.`
-      );
-
-    let self;
-    let degree = 0;
-    let loops = 0;
-
-    if (this.type !== 'directed') {
-      degree += nodeData.undirectedDegree;
-
-      self = nodeData.undirected[node];
-      loops += (self ? (this.multi ? self.size : 1) : 0) * 2;
-    }
-
-    if (this.type !== 'undirected') {
-      degree += nodeData.inDegree;
-
-      self = nodeData.out[node];
-      loops += self ? (this.multi ? self.size : 1) : 0;
-    }
-
-    return degree - loops;
-  }
-
-  /**
-   * Method returning the given node's outbound degree without considering self loops.
-   *
-   * @param  {any}     node - The node's key.
-   * @return {number}       - The node's outbound degree.
-   *
-   * @throws {Error} - Will throw if the node isn't in the graph.
-   */
-  outboundDegreeWithoutSelfLoops(node) {
-    node = '' + node;
-
-    const nodeData = this._nodes.get(node);
-
-    if (!nodeData)
-      throw new NotFoundGraphError(
-        `Graph.outboundDegreeWithoutSelfLoops: could not find the "${node}" node in the graph.`
-      );
-
-    let self;
-    let degree = 0;
-    let loops = 0;
-
-    if (this.type !== 'directed') {
-      degree += nodeData.undirectedDegree;
-
-      self = nodeData.undirected[node];
-      loops += (self ? (this.multi ? self.size : 1) : 0) * 2;
-    }
-
-    if (this.type !== 'undirected') {
-      degree += nodeData.outDegree;
-
-      self = nodeData.in[node];
-      loops += self ? (this.multi ? self.size : 1) : 0;
-    }
-
-    return degree - loops;
-  }
-
-  /**
-   * Method returning the given node's directed degree without considering self loops.
-   *
-   * @param  {any}     node - The node's key.
-   * @return {number}       - The node's degree.
-   *
-   * @throws {Error} - Will throw if the node isn't in the graph.
-   */
-  degreeWithoutSelfLoops(node) {
-    node = '' + node;
-
-    const nodeData = this._nodes.get(node);
-
-    if (!nodeData)
-      throw new NotFoundGraphError(
-        `Graph.degreeWithoutSelfLoops: could not find the "${node}" node in the graph.`
-      );
-
-    let self;
-    let degree = 0;
-    let loops = 0;
-
-    if (this.type !== 'directed') {
-      degree += nodeData.undirectedDegree;
-
-      self = nodeData.undirected[node];
-      loops += (self ? (this.multi ? self.size : 1) : 0) * 2;
-    }
-
-    if (this.type !== 'undirected') {
-      degree += nodeData.inDegree + nodeData.outDegree;
-
-      self = nodeData.out[node];
-      loops += (self ? (this.multi ? self.size : 1) : 0) * 2;
-    }
-
-    return degree - loops;
-  }
-
-  /**
-   * Method returning the given edge's source.
-   *
-   * @param  {any} edge - The edge's key.
-   * @return {any}      - The edge's source.
-   *
-   * @throws {Error} - Will throw if the edge isn't in the graph.
-   */
-  source(edge) {
-    edge = '' + edge;
-
-    const data = this._edges.get(edge);
-
-    if (!data)
-      throw new NotFoundGraphError(
-        `Graph.source: could not find the "${edge}" edge in the graph.`
-      );
-
-    return data.source.key;
-  }
-
-  /**
-   * Method returning the given edge's target.
-   *
-   * @param  {any} edge - The edge's key.
-   * @return {any}      - The edge's target.
-   *
-   * @throws {Error} - Will throw if the edge isn't in the graph.
-   */
-  target(edge) {
-    edge = '' + edge;
-
-    const data = this._edges.get(edge);
-
-    if (!data)
-      throw new NotFoundGraphError(
-        `Graph.target: could not find the "${edge}" edge in the graph.`
-      );
-
-    return data.target.key;
-  }
-
-  /**
-   * Method returning the given edge's extremities.
-   *
-   * @param  {any}   edge - The edge's key.
-   * @return {array}      - The edge's extremities.
-   *
-   * @throws {Error} - Will throw if the edge isn't in the graph.
-   */
-  extremities(edge) {
-    edge = '' + edge;
-
-    const edgeData = this._edges.get(edge);
-
-    if (!edgeData)
-      throw new NotFoundGraphError(
-        `Graph.extremities: could not find the "${edge}" edge in the graph.`
-      );
-
-    return [edgeData.source.key, edgeData.target.key];
-  }
-
-  /**
-   * Given a node & an edge, returns the other extremity of the edge.
-   *
-   * @param  {any}   node - The node's key.
-   * @param  {any}   edge - The edge's key.
-   * @return {any}        - The related node.
-   *
-   * @throws {Error} - Will throw if the edge isn't in the graph or if the
-   *                   edge & node are not related.
-   */
-  opposite(node, edge) {
-    node = '' + node;
-    edge = '' + edge;
-
-    const data = this._edges.get(edge);
-
-    if (!data)
-      throw new NotFoundGraphError(
-        `Graph.opposite: could not find the "${edge}" edge in the graph.`
-      );
-
-    const source = data.source.key;
-    const target = data.target.key;
-
-    if (node === source) return target;
-    if (node === target) return source;
-
-    throw new NotFoundGraphError(
-      `Graph.opposite: the "${node}" node is not attached to the "${edge}" edge (${source}, ${target}).`
-    );
-  }
-
-  /**
-   * Returns whether the given edge has the given node as extremity.
-   *
-   * @param  {any}     edge - The edge's key.
-   * @param  {any}     node - The node's key.
-   * @return {boolean}      - The related node.
-   *
-   * @throws {Error} - Will throw if either the node or the edge isn't in the graph.
-   */
-  hasExtremity(edge, node) {
-    edge = '' + edge;
-    node = '' + node;
-
-    const data = this._edges.get(edge);
-
-    if (!data)
-      throw new NotFoundGraphError(
-        `Graph.hasExtremity: could not find the "${edge}" edge in the graph.`
-      );
-
-    return data.source.key === node || data.target.key === node;
-  }
-
-  /**
-   * Method returning whether the given edge is undirected.
-   *
-   * @param  {any}     edge - The edge's key.
-   * @return {boolean}
-   *
-   * @throws {Error} - Will throw if the edge isn't in the graph.
-   */
-  isUndirected(edge) {
-    edge = '' + edge;
-
-    const data = this._edges.get(edge);
-
-    if (!data)
-      throw new NotFoundGraphError(
-        `Graph.isUndirected: could not find the "${edge}" edge in the graph.`
-      );
-
-    return data.undirected;
-  }
-
-  /**
-   * Method returning whether the given edge is directed.
-   *
-   * @param  {any}     edge - The edge's key.
-   * @return {boolean}
-   *
-   * @throws {Error} - Will throw if the edge isn't in the graph.
-   */
-  isDirected(edge) {
-    edge = '' + edge;
-
-    const data = this._edges.get(edge);
-
-    if (!data)
-      throw new NotFoundGraphError(
-        `Graph.isDirected: could not find the "${edge}" edge in the graph.`
-      );
-
-    return !data.undirected;
-  }
-
-  /**
-   * Method returning whether the given edge is a self loop.
-   *
-   * @param  {any}     edge - The edge's key.
-   * @return {boolean}
-   *
-   * @throws {Error} - Will throw if the edge isn't in the graph.
-   */
-  isSelfLoop(edge) {
-    edge = '' + edge;
-
-    const data = this._edges.get(edge);
-
-    if (!data)
-      throw new NotFoundGraphError(
-        `Graph.isSelfLoop: could not find the "${edge}" edge in the graph.`
-      );
-
-    return data.source === data.target;
-  }
-
-  /**---------------------------------------------------------------------------
-   * Mutation
-   **---------------------------------------------------------------------------
-   */
-
-  /**
-   * Method used to add a node to the graph.
-   *
-   * @param  {any}    node         - The node.
-   * @param  {object} [attributes] - Optional attributes.
-   * @return {any}                 - The node.
-   *
-   * @throws {Error} - Will throw if the given node already exist.
-   * @throws {Error} - Will throw if the given attributes are not an object.
-   */
-  addNode(node, attributes) {
-    const nodeData = addNode(this, node, attributes);
-
-    return nodeData.key;
-  }
-
-  /**
-   * Method used to merge a node into the graph.
-   *
-   * @param  {any}    node         - The node.
-   * @param  {object} [attributes] - Optional attributes.
-   * @return {any}                 - The node.
-   */
-  mergeNode(node, attributes) {
-    if (attributes && !isPlainObject(attributes))
-      throw new InvalidArgumentsGraphError(
-        `Graph.mergeNode: invalid attributes. Expecting an object but got "${attributes}"`
-      );
-
-    // String coercion
-    node = '' + node;
-    attributes = attributes || {};
-
-    // If the node already exists, we merge the attributes
-    let data = this._nodes.get(node);
-
-    if (data) {
-      if (attributes) {
-        assign(data.attributes, attributes);
-
-        this.emit('nodeAttributesUpdated', {
-          type: 'merge',
-          key: node,
-          attributes: data.attributes,
-          data: attributes
-        });
-      }
-      return [node, false];
-    }
-
-    data = new this.NodeDataClass(node, attributes);
-
-    // Adding the node to internal register
-    this._nodes.set(node, data);
-
-    // Emitting
-    this.emit('nodeAdded', {
-      key: node,
-      attributes
-    });
-
-    return [node, true];
-  }
-
-  /**
-   * Method used to add a node if it does not exist in the graph or else to
-   * update its attributes using a function.
-   *
-   * @param  {any}      node      - The node.
-   * @param  {function} [updater] - Optional updater function.
-   * @return {any}                - The node.
-   */
-  updateNode(node, updater) {
-    if (updater && typeof updater !== 'function')
-      throw new InvalidArgumentsGraphError(
-        `Graph.updateNode: invalid updater function. Expecting a function but got "${updater}"`
-      );
-
-    // String coercion
-    node = '' + node;
-
-    // If the node already exists, we update the attributes
-    let data = this._nodes.get(node);
-
-    if (data) {
-      if (updater) {
-        const oldAttributes = data.attributes;
-        data.attributes = updater(oldAttributes);
-
-        this.emit('nodeAttributesUpdated', {
-          type: 'replace',
-          key: node,
-          attributes: data.attributes
-        });
-      }
-      return [node, false];
-    }
-
-    const attributes = updater ? updater({}) : {};
-
-    data = new this.NodeDataClass(node, attributes);
-
-    // Adding the node to internal register
-    this._nodes.set(node, data);
-
-    // Emitting
-    this.emit('nodeAdded', {
-      key: node,
-      attributes
-    });
-
-    return [node, true];
-  }
-
-  /**
-   * Method used to drop a single node & all its attached edges from the graph.
-   *
-   * @param  {any}    node - The node.
-   * @return {Graph}
-   *
-   * @throws {Error} - Will throw if the node doesn't exist.
-   */
-  dropNode(node) {
-    node = '' + node;
-
-    const nodeData = this._nodes.get(node);
-
-    if (!nodeData)
-      throw new NotFoundGraphError(
-        `Graph.dropNode: could not find the "${node}" node in the graph.`
-      );
-
-    let edgeData;
-
-    // Removing attached edges
-    // NOTE: we could be faster here, but this is such a pain to maintain
-    if (this.type !== 'undirected') {
-      for (const neighbor in nodeData.out) {
-        edgeData = nodeData.out[neighbor];
-
-        do {
-          dropEdgeFromData(this, edgeData);
-          edgeData = edgeData.next;
-        } while (edgeData);
-      }
-
-      for (const neighbor in nodeData.in) {
-        edgeData = nodeData.in[neighbor];
-
-        do {
-          dropEdgeFromData(this, edgeData);
-          edgeData = edgeData.next;
-        } while (edgeData);
-      }
-    }
-
-    if (this.type !== 'directed') {
-      for (const neighbor in nodeData.undirected) {
-        edgeData = nodeData.undirected[neighbor];
-
-        do {
-          dropEdgeFromData(this, edgeData);
-          edgeData = edgeData.next;
-        } while (edgeData);
-      }
-    }
-
-    // Dropping the node from the register
-    this._nodes.delete(node);
-
-    // Emitting
-    this.emit('nodeDropped', {
-      key: node,
-      attributes: nodeData.attributes
-    });
-  }
-
-  /**
-   * Method used to drop a single edge from the graph.
-   *
-   * Arity 1:
-   * @param  {any}    edge - The edge.
-   *
-   * Arity 2:
-   * @param  {any}    source - Source node.
-   * @param  {any}    target - Target node.
-   *
-   * @return {Graph}
-   *
-   * @throws {Error} - Will throw if the edge doesn't exist.
-   */
-  dropEdge(edge) {
-    let edgeData;
-
-    if (arguments.length > 1) {
-      const source = '' + arguments[0];
-      const target = '' + arguments[1];
-
-      edgeData = getMatchingEdge(this, source, target, this.type);
-
-      if (!edgeData)
-        throw new NotFoundGraphError(
-          `Graph.dropEdge: could not find the "${source}" -> "${target}" edge in the graph.`
-        );
-    } else {
-      edge = '' + edge;
-
-      edgeData = this._edges.get(edge);
-
-      if (!edgeData)
-        throw new NotFoundGraphError(
-          `Graph.dropEdge: could not find the "${edge}" edge in the graph.`
-        );
-    }
-
-    dropEdgeFromData(this, edgeData);
-
-    return this;
-  }
-
-  /**
-   * Method used to drop a single directed edge from the graph.
-   *
-   * @param  {any}    source - Source node.
-   * @param  {any}    target - Target node.
-   *
-   * @return {Graph}
-   *
-   * @throws {Error} - Will throw if the edge doesn't exist.
-   */
-  dropDirectedEdge(source, target) {
-    if (arguments.length < 2)
-      throw new UsageGraphError(
-        'Graph.dropDirectedEdge: it does not make sense to try and drop a directed edge by key. What if the edge with this key is undirected? Use #.dropEdge for this purpose instead.'
-      );
-
-    if (this.multi)
-      throw new UsageGraphError(
-        'Graph.dropDirectedEdge: cannot use a {source,target} combo when dropping an edge in a MultiGraph since we cannot infer the one you want to delete as there could be multiple ones.'
-      );
-
-    source = '' + source;
-    target = '' + target;
-
-    const edgeData = getMatchingEdge(this, source, target, 'directed');
-
-    if (!edgeData)
-      throw new NotFoundGraphError(
-        `Graph.dropDirectedEdge: could not find a "${source}" -> "${target}" edge in the graph.`
-      );
-
-    dropEdgeFromData(this, edgeData);
-
-    return this;
-  }
-
-  /**
-   * Method used to drop a single undirected edge from the graph.
-   *
-   * @param  {any}    source - Source node.
-   * @param  {any}    target - Target node.
-   *
-   * @return {Graph}
-   *
-   * @throws {Error} - Will throw if the edge doesn't exist.
-   */
-  dropUndirectedEdge(source, target) {
-    if (arguments.length < 2)
-      throw new UsageGraphError(
-        'Graph.dropUndirectedEdge: it does not make sense to drop a directed edge by key. What if the edge with this key is undirected? Use #.dropEdge for this purpose instead.'
-      );
-
-    if (this.multi)
-      throw new UsageGraphError(
-        'Graph.dropUndirectedEdge: cannot use a {source,target} combo when dropping an edge in a MultiGraph since we cannot infer the one you want to delete as there could be multiple ones.'
-      );
-
-    const edgeData = getMatchingEdge(this, source, target, 'undirected');
-
-    if (!edgeData)
-      throw new NotFoundGraphError(
-        `Graph.dropUndirectedEdge: could not find a "${source}" -> "${target}" edge in the graph.`
-      );
-
-    dropEdgeFromData(this, edgeData);
-
-    return this;
-  }
-
-  /**
-   * Method used to remove every edge & every node from the graph.
-   *
-   * @return {Graph}
-   */
-  clear() {
-    // Clearing edges
-    this._edges.clear();
-
-    // Clearing nodes
-    this._nodes.clear();
-
-    // Reset counters
-    this._resetInstanceCounters();
-
-    // Emitting
-    this.emit('cleared');
-  }
-
-  /**
-   * Method used to remove every edge from the graph.
-   *
-   * @return {Graph}
-   */
-  clearEdges() {
-    // Clearing structure index
-    const iterator = this._nodes.values();
-
-    let step;
-
-    while (((step = iterator.next()), step.done !== true)) {
-      step.value.clear();
-    }
-
-    // Clearing edges
-    this._edges.clear();
-
-    // Reset counters
-    this._resetInstanceCounters();
-
-    // Emitting
-    this.emit('edgesCleared');
-  }
-
-  /**---------------------------------------------------------------------------
-   * Attributes-related methods
-   **---------------------------------------------------------------------------
-   */
-
-  /**
-   * Method returning the desired graph's attribute.
-   *
-   * @param  {string} name - Name of the attribute.
-   * @return {any}
-   */
-  getAttribute(name) {
-    return this._attributes[name];
-  }
-
-  /**
-   * Method returning the graph's attributes.
-   *
-   * @return {object}
-   */
-  getAttributes() {
-    return this._attributes;
-  }
-
-  /**
-   * Method returning whether the graph has the desired attribute.
-   *
-   * @param  {string}  name - Name of the attribute.
-   * @return {boolean}
-   */
-  hasAttribute(name) {
-    return this._attributes.hasOwnProperty(name);
-  }
-
-  /**
-   * Method setting a value for the desired graph's attribute.
-   *
-   * @param  {string}  name  - Name of the attribute.
-   * @param  {any}     value - Value for the attribute.
-   * @return {Graph}
-   */
-  setAttribute(name, value) {
-    this._attributes[name] = value;
-
-    // Emitting
-    this.emit('attributesUpdated', {
-      type: 'set',
-      attributes: this._attributes,
-      name
-    });
-
-    return this;
-  }
-
-  /**
-   * Method using a function to update the desired graph's attribute's value.
-   *
-   * @param  {string}   name    - Name of the attribute.
-   * @param  {function} updater - Function use to update the attribute's value.
-   * @return {Graph}
-   */
-  updateAttribute(name, updater) {
-    if (typeof updater !== 'function')
-      throw new InvalidArgumentsGraphError(
-        'Graph.updateAttribute: updater should be a function.'
-      );
-
-    const value = this._attributes[name];
-
-    this._attributes[name] = updater(value);
-
-    // Emitting
-    this.emit('attributesUpdated', {
-      type: 'set',
-      attributes: this._attributes,
-      name
-    });
-
-    return this;
-  }
-
-  /**
-   * Method removing the desired graph's attribute.
-   *
-   * @param  {string} name  - Name of the attribute.
-   * @return {Graph}
-   */
-  removeAttribute(name) {
-    delete this._attributes[name];
-
-    // Emitting
-    this.emit('attributesUpdated', {
-      type: 'remove',
-      attributes: this._attributes,
-      name
-    });
-
-    return this;
-  }
-
-  /**
-   * Method replacing the graph's attributes.
-   *
-   * @param  {object} attributes - New attributes.
-   * @return {Graph}
-   *
-   * @throws {Error} - Will throw if given attributes are not a plain object.
-   */
-  replaceAttributes(attributes) {
-    if (!isPlainObject(attributes))
-      throw new InvalidArgumentsGraphError(
-        'Graph.replaceAttributes: provided attributes are not a plain object.'
-      );
-
-    this._attributes = attributes;
-
-    // Emitting
-    this.emit('attributesUpdated', {
-      type: 'replace',
-      attributes: this._attributes
-    });
-
-    return this;
-  }
-
-  /**
-   * Method merging the graph's attributes.
-   *
-   * @param  {object} attributes - Attributes to merge.
-   * @return {Graph}
-   *
-   * @throws {Error} - Will throw if given attributes are not a plain object.
-   */
-  mergeAttributes(attributes) {
-    if (!isPlainObject(attributes))
-      throw new InvalidArgumentsGraphError(
-        'Graph.mergeAttributes: provided attributes are not a plain object.'
-      );
-
-    assign(this._attributes, attributes);
-
-    // Emitting
-    this.emit('attributesUpdated', {
-      type: 'merge',
-      attributes: this._attributes,
-      data: attributes
-    });
-
-    return this;
-  }
-
-  /**
-   * Method updating the graph's attributes.
-   *
-   * @param  {function} updater - Function used to update the attributes.
-   * @return {Graph}
-   *
-   * @throws {Error} - Will throw if given updater is not a function.
-   */
-  updateAttributes(updater) {
-    if (typeof updater !== 'function')
-      throw new InvalidArgumentsGraphError(
-        'Graph.updateAttributes: provided updater is not a function.'
-      );
-
-    this._attributes = updater(this._attributes);
-
-    // Emitting
-    this.emit('attributesUpdated', {
-      type: 'update',
-      attributes: this._attributes
-    });
-
-    return this;
-  }
-
-  /**
-   * Method used to update each node's attributes using the given function.
-   *
-   * @param {function}  updater - Updater function to use.
-   * @param {object}    [hints] - Optional hints.
-   */
-  updateEachNodeAttributes(updater, hints) {
-    if (typeof updater !== 'function')
-      throw new InvalidArgumentsGraphError(
-        'Graph.updateEachNodeAttributes: expecting an updater function.'
-      );
-
-    if (hints && !validateHints(hints))
-      throw new InvalidArgumentsGraphError(
-        'Graph.updateEachNodeAttributes: invalid hints. Expecting an object having the following shape: {attributes?: [string]}'
-      );
-
-    const iterator = this._nodes.values();
-
-    let step, nodeData;
-
-    while (((step = iterator.next()), step.done !== true)) {
-      nodeData = step.value;
-      nodeData.attributes = updater(nodeData.key, nodeData.attributes);
-    }
-
-    this.emit('eachNodeAttributesUpdated', {
-      hints: hints ? hints : null
-    });
-  }
-
-  /**
-   * Method used to update each edge's attributes using the given function.
-   *
-   * @param {function}  updater - Updater function to use.
-   * @param {object}    [hints] - Optional hints.
-   */
-  updateEachEdgeAttributes(updater, hints) {
-    if (typeof updater !== 'function')
-      throw new InvalidArgumentsGraphError(
-        'Graph.updateEachEdgeAttributes: expecting an updater function.'
-      );
-
-    if (hints && !validateHints(hints))
-      throw new InvalidArgumentsGraphError(
-        'Graph.updateEachEdgeAttributes: invalid hints. Expecting an object having the following shape: {attributes?: [string]}'
-      );
-
-    const iterator = this._edges.values();
-
-    let step, edgeData, sourceData, targetData;
-
-    while (((step = iterator.next()), step.done !== true)) {
-      edgeData = step.value;
-      sourceData = edgeData.source;
-      targetData = edgeData.target;
-
-      edgeData.attributes = updater(
-        edgeData.key,
-        edgeData.attributes,
-        sourceData.key,
-        targetData.key,
-        sourceData.attributes,
-        targetData.attributes,
-        edgeData.undirected
-      );
-    }
-
-    this.emit('eachEdgeAttributesUpdated', {
-      hints: hints ? hints : null
-    });
-  }
-
-  /**---------------------------------------------------------------------------
-   * Iteration-related methods
-   **---------------------------------------------------------------------------
-   */
-
-  /**
-   * Method iterating over the graph's adjacency using the given callback.
-   *
-   * @param  {function}  callback - Callback to use.
-   */
-  forEachAdjacencyEntry(callback) {
-    if (typeof callback !== 'function')
-      throw new InvalidArgumentsGraphError(
-        'Graph.forEachAdjacencyEntry: expecting a callback.'
-      );
-
-    forEachAdjacency(false, false, false, this, callback);
-  }
-  forEachAdjacencyEntryWithOrphans(callback) {
-    if (typeof callback !== 'function')
-      throw new InvalidArgumentsGraphError(
-        'Graph.forEachAdjacencyEntryWithOrphans: expecting a callback.'
-      );
-
-    forEachAdjacency(false, false, true, this, callback);
-  }
-
-  /**
-   * Method iterating over the graph's assymetric adjacency using the given callback.
-   *
-   * @param  {function}  callback - Callback to use.
-   */
-  forEachAssymetricAdjacencyEntry(callback) {
-    if (typeof callback !== 'function')
-      throw new InvalidArgumentsGraphError(
-        'Graph.forEachAssymetricAdjacencyEntry: expecting a callback.'
-      );
-
-    forEachAdjacency(false, true, false, this, callback);
-  }
-  forEachAssymetricAdjacencyEntryWithOrphans(callback) {
-    if (typeof callback !== 'function')
-      throw new InvalidArgumentsGraphError(
-        'Graph.forEachAssymetricAdjacencyEntryWithOrphans: expecting a callback.'
-      );
-
-    forEachAdjacency(false, true, true, this, callback);
-  }
-
-  /**
-   * Method returning the list of the graph's nodes.
-   *
-   * @return {array} - The nodes.
-   */
-  nodes() {
-    if (typeof Array.from === 'function') return Array.from(this._nodes.keys());
-
-    return take(this._nodes.keys(), this._nodes.size);
-  }
-
-  /**
-   * Method iterating over the graph's nodes using the given callback.
-   *
-   * @param  {function}  callback - Callback (key, attributes, index).
-   */
-  forEachNode(callback) {
-    if (typeof callback !== 'function')
-      throw new InvalidArgumentsGraphError(
-        'Graph.forEachNode: expecting a callback.'
-      );
-
-    const iterator = this._nodes.values();
-
-    let step, nodeData;
-
-    while (((step = iterator.next()), step.done !== true)) {
-      nodeData = step.value;
-      callback(nodeData.key, nodeData.attributes);
-    }
-  }
-
-  /**
-   * Method iterating attempting to find a node matching the given predicate
-   * function.
-   *
-   * @param  {function}  callback - Callback (key, attributes).
-   */
-  findNode(callback) {
-    if (typeof callback !== 'function')
-      throw new InvalidArgumentsGraphError(
-        'Graph.findNode: expecting a callback.'
-      );
-
-    const iterator = this._nodes.values();
-
-    let step, nodeData;
-
-    while (((step = iterator.next()), step.done !== true)) {
-      nodeData = step.value;
-
-      if (callback(nodeData.key, nodeData.attributes)) return nodeData.key;
-    }
-
-    return;
-  }
-
-  /**
-   * Method mapping nodes.
-   *
-   * @param  {function}  callback - Callback (key, attributes).
-   */
-  mapNodes(callback) {
-    if (typeof callback !== 'function')
-      throw new InvalidArgumentsGraphError(
-        'Graph.mapNode: expecting a callback.'
-      );
-
-    const iterator = this._nodes.values();
-
-    let step, nodeData;
-
-    const result = new Array(this.order);
-    let i = 0;
-
-    while (((step = iterator.next()), step.done !== true)) {
-      nodeData = step.value;
-      result[i++] = callback(nodeData.key, nodeData.attributes);
-    }
-
-    return result;
-  }
-
-  /**
-   * Method returning whether some node verify the given predicate.
-   *
-   * @param  {function}  callback - Callback (key, attributes).
-   */
-  someNode(callback) {
-    if (typeof callback !== 'function')
-      throw new InvalidArgumentsGraphError(
-        'Graph.someNode: expecting a callback.'
-      );
-
-    const iterator = this._nodes.values();
-
-    let step, nodeData;
-
-    while (((step = iterator.next()), step.done !== true)) {
-      nodeData = step.value;
-
-      if (callback(nodeData.key, nodeData.attributes)) return true;
-    }
-
-    return false;
-  }
-
-  /**
-   * Method returning whether all node verify the given predicate.
-   *
-   * @param  {function}  callback - Callback (key, attributes).
-   */
-  everyNode(callback) {
-    if (typeof callback !== 'function')
-      throw new InvalidArgumentsGraphError(
-        'Graph.everyNode: expecting a callback.'
-      );
-
-    const iterator = this._nodes.values();
-
-    let step, nodeData;
-
-    while (((step = iterator.next()), step.done !== true)) {
-      nodeData = step.value;
-
-      if (!callback(nodeData.key, nodeData.attributes)) return false;
-    }
-
-    return true;
-  }
-
-  /**
-   * Method filtering nodes.
-   *
-   * @param  {function}  callback - Callback (key, attributes).
-   */
-  filterNodes(callback) {
-    if (typeof callback !== 'function')
-      throw new InvalidArgumentsGraphError(
-        'Graph.filterNodes: expecting a callback.'
-      );
-
-    const iterator = this._nodes.values();
-
-    let step, nodeData;
-
-    const result = [];
-
-    while (((step = iterator.next()), step.done !== true)) {
-      nodeData = step.value;
-
-      if (callback(nodeData.key, nodeData.attributes))
-        result.push(nodeData.key);
-    }
-
-    return result;
-  }
-
-  /**
-   * Method reducing nodes.
-   *
-   * @param  {function}  callback - Callback (accumulator, key, attributes).
-   */
-  reduceNodes(callback, initialValue) {
-    if (typeof callback !== 'function')
-      throw new InvalidArgumentsGraphError(
-        'Graph.reduceNodes: expecting a callback.'
-      );
-
-    if (arguments.length < 2)
-      throw new InvalidArgumentsGraphError(
-        'Graph.reduceNodes: missing initial value. You must provide it because the callback takes more than one argument and we cannot infer the initial value from the first iteration, as you could with a simple array.'
-      );
-
-    let accumulator = initialValue;
-
-    const iterator = this._nodes.values();
-
-    let step, nodeData;
-
-    while (((step = iterator.next()), step.done !== true)) {
-      nodeData = step.value;
-      accumulator = callback(accumulator, nodeData.key, nodeData.attributes);
-    }
-
-    return accumulator;
-  }
-
-  /**
-   * Method returning an iterator over the graph's node entries.
-   *
-   * @return {Iterator}
-   */
-  nodeEntries() {
-    const iterator = this._nodes.values();
-
-    return new Iterator(() => {
-      const step = iterator.next();
-
-      if (step.done) return step;
-
-      const data = step.value;
-
-      return {
-        value: {node: data.key, attributes: data.attributes},
-        done: false
-      };
-    });
-  }
-
-  /**---------------------------------------------------------------------------
-   * Serialization
-   **---------------------------------------------------------------------------
-   */
-
-  /**
-   * Method used to export the whole graph.
-   *
-   * @return {object} - The serialized graph.
-   */
-  export() {
-    const nodes = new Array(this._nodes.size);
-
-    let i = 0;
-
-    this._nodes.forEach((data, key) => {
-      nodes[i++] = serializeNode(key, data);
-    });
-
-    const edges = new Array(this._edges.size);
-
-    i = 0;
-
-    this._edges.forEach((data, key) => {
-      edges[i++] = serializeEdge(key, data);
-    });
-
-    return {
-      options: {
-        type: this.type,
-        multi: this.multi,
-        allowSelfLoops: this.allowSelfLoops
-      },
-      attributes: this.getAttributes(),
-      nodes,
-      edges
-    };
-  }
-
-  /**
-   * Method used to import a serialized graph.
-   *
-   * @param  {object|Graph} data  - The serialized graph.
-   * @param  {boolean}      merge - Whether to merge data.
-   * @return {Graph}              - Returns itself for chaining.
-   */
-  import(data, merge = false) {
-    // Importing a Graph instance directly
-    if (isGraph(data)) {
-      // Nodes
-      data.forEachNode((n, a) => {
-        if (merge) this.mergeNode(n, a);
-        else this.addNode(n, a);
-      });
-
-      // Edges
-      data.forEachEdge((e, a, s, t, _sa, _ta, u) => {
-        if (merge) {
-          if (u) this.mergeUndirectedEdgeWithKey(e, s, t, a);
-          else this.mergeDirectedEdgeWithKey(e, s, t, a);
-        } else {
-          if (u) this.addUndirectedEdgeWithKey(e, s, t, a);
-          else this.addDirectedEdgeWithKey(e, s, t, a);
-        }
-      });
-
-      return this;
-    }
-
-    // Importing a serialized graph
-    if (!isPlainObject(data))
-      throw new InvalidArgumentsGraphError(
-        'Graph.import: invalid argument. Expecting a serialized graph or, alternatively, a Graph instance.'
-      );
-
-    if (data.attributes) {
-      if (!isPlainObject(data.attributes))
-        throw new InvalidArgumentsGraphError(
-          'Graph.import: invalid attributes. Expecting a plain object.'
-        );
-
-      if (merge) this.mergeAttributes(data.attributes);
-      else this.replaceAttributes(data.attributes);
-    }
-
-    let i, l, list, node, edge;
-
-    if (data.nodes) {
-      list = data.nodes;
-
-      if (!Array.isArray(list))
-        throw new InvalidArgumentsGraphError(
-          'Graph.import: invalid nodes. Expecting an array.'
-        );
-
-      for (i = 0, l = list.length; i < l; i++) {
-        node = list[i];
-
-        // Validating
-        validateSerializedNode(node);
-
-        // Adding the node
-        const {key, attributes} = node;
-
-        if (merge) this.mergeNode(key, attributes);
-        else this.addNode(key, attributes);
-      }
-    }
-
-    if (data.edges) {
-      list = data.edges;
-
-      if (!Array.isArray(list))
-        throw new InvalidArgumentsGraphError(
-          'Graph.import: invalid edges. Expecting an array.'
-        );
-
-      for (i = 0, l = list.length; i < l; i++) {
-        edge = list[i];
-
-        // Validating
-        validateSerializedEdge(edge);
-
-        // Adding the edge
-        const {source, target, attributes, undirected = false} = edge;
-
-        let method;
-
-        if ('key' in edge) {
-          method = merge
-            ? undirected
-              ? this.mergeUndirectedEdgeWithKey
-              : this.mergeDirectedEdgeWithKey
-            : undirected
-            ? this.addUndirectedEdgeWithKey
-            : this.addDirectedEdgeWithKey;
-
-          method.call(this, edge.key, source, target, attributes);
-        } else {
-          method = merge
-            ? undirected
-              ? this.mergeUndirectedEdge
-              : this.mergeDirectedEdge
-            : undirected
-            ? this.addUndirectedEdge
-            : this.addDirectedEdge;
-
-          method.call(this, source, target, attributes);
-        }
-      }
-    }
-
-    return this;
-  }
-
-  /**---------------------------------------------------------------------------
-   * Utils
-   **---------------------------------------------------------------------------
-   */
-
-  /**
-   * Method returning a null copy of the graph, i.e. a graph without nodes
-   * & edges but with the exact same options.
-   *
-   * @param  {object} options - Options to merge with the current ones.
-   * @return {Graph}          - The null copy.
-   */
-  nullCopy(options) {
-    const graph = new Graph(assign({}, this._options, options));
-    graph.replaceAttributes(assign({}, this.getAttributes()));
-    return graph;
-  }
-
-  /**
-   * Method returning an empty copy of the graph, i.e. a graph without edges but
-   * with the exact same options.
-   *
-   * @param  {object} options - Options to merge with the current ones.
-   * @return {Graph}          - The empty copy.
-   */
-  emptyCopy(options) {
-    const graph = this.nullCopy(options);
-
-    this._nodes.forEach((nodeData, key) => {
-      const attributes = assign({}, nodeData.attributes);
-
-      // NOTE: no need to emit events since user cannot access the instance yet
-      nodeData = new graph.NodeDataClass(key, attributes);
-      graph._nodes.set(key, nodeData);
-    });
-
-    return graph;
-  }
-
-  /**
-   * Method returning an exact copy of the graph.
-   *
-   * @param  {object} options - Upgrade options.
-   * @return {Graph}          - The copy.
-   */
-  copy(options) {
-    options = options || {};
-
-    if (
-      typeof options.type === 'string' &&
-      options.type !== this.type &&
-      options.type !== 'mixed'
-    )
-      throw new UsageGraphError(
-        `Graph.copy: cannot create an incompatible copy from "${this.type}" type to "${options.type}" because this would mean losing information about the current graph.`
-      );
-
-    if (
-      typeof options.multi === 'boolean' &&
-      options.multi !== this.multi &&
-      options.multi !== true
-    )
-      throw new UsageGraphError(
-        'Graph.copy: cannot create an incompatible copy by downgrading a multi graph to a simple one because this would mean losing information about the current graph.'
-      );
-
-    if (
-      typeof options.allowSelfLoops === 'boolean' &&
-      options.allowSelfLoops !== this.allowSelfLoops &&
-      options.allowSelfLoops !== true
-    )
-      throw new UsageGraphError(
-        'Graph.copy: cannot create an incompatible copy from a graph allowing self loops to one that does not because this would mean losing information about the current graph.'
-      );
-
-    const graph = this.emptyCopy(options);
-
-    const iterator = this._edges.values();
-
-    let step, edgeData;
-
-    while (((step = iterator.next()), step.done !== true)) {
-      edgeData = step.value;
-
-      // NOTE: no need to emit events since user cannot access the instance yet
-      addEdge(
-        graph,
-        'copy',
-        false,
-        edgeData.undirected,
-        edgeData.key,
-        edgeData.source.key,
-        edgeData.target.key,
-        assign({}, edgeData.attributes)
-      );
-    }
-
-    return graph;
-  }
-
-  /**---------------------------------------------------------------------------
-   * Known methods
-   **---------------------------------------------------------------------------
-   */
-
-  /**
-   * Method used by JavaScript to perform JSON serialization.
-   *
-   * @return {object} - The serialized graph.
-   */
-  toJSON() {
-    return this.export();
-  }
-
-  /**
-   * Method returning [object Graph].
-   */
-  toString() {
-    return '[object Graph]';
-  }
-
-  /**
-   * Method used internally by node's console to display a custom object.
-   *
-   * @return {object} - Formatted object representation of the graph.
-   */
-  inspect() {
-    const nodes = {};
-    this._nodes.forEach((data, key) => {
-      nodes[key] = data.attributes;
-    });
-
-    const edges = {},
-      multiIndex = {};
-
-    this._edges.forEach((data, key) => {
-      const direction = data.undirected ? '--' : '->';
-
-      let label = '';
-
-      let source = data.source.key;
-      let target = data.target.key;
-      let tmp;
-
-      if (data.undirected && source > target) {
-        tmp = source;
-        source = target;
-        target = tmp;
-      }
-
-      const desc = `(${source})${direction}(${target})`;
-
-      if (!key.startsWith('geid_')) {
-        label += `[${key}]: `;
-      } else if (this.multi) {
-        if (typeof multiIndex[desc] === 'undefined') {
-          multiIndex[desc] = 0;
-        } else {
-          multiIndex[desc]++;
-        }
-
-        label += `${multiIndex[desc]}. `;
-      }
-
-      label += desc;
-
-      edges[label] = data.attributes;
-    });
-
-    const dummy = {};
-
-    for (const k in this) {
-      if (
-        this.hasOwnProperty(k) &&
-        !EMITTER_PROPS.has(k) &&
-        typeof this[k] !== 'function' &&
-        typeof k !== 'symbol'
-      )
-        dummy[k] = this[k];
-    }
-
-    dummy.attributes = this._attributes;
-    dummy.nodes = nodes;
-    dummy.edges = edges;
-
-    privateProperty(dummy, 'constructor', this.constructor);
-
-    return dummy;
-  }
-}
-
-/**
- * Attaching methods to the prototype.
- *
- * Here, we are attaching a wide variety of methods to the Graph class'
- * prototype when those are very numerous and when their creation is
- * abstracted.
- */
-
-/**
- * Attaching custom inspect method for node >= 10.
- */
-if (typeof Symbol !== 'undefined')
-  Graph.prototype[Symbol.for('nodejs.util.inspect.custom')] =
-    Graph.prototype.inspect;
-
-/**
- * Related to edge addition.
- */
-EDGE_ADD_METHODS.forEach(method => {
-  ['add', 'merge', 'update'].forEach(verb => {
-    const name = method.name(verb);
-    const fn = verb === 'add' ? addEdge : mergeEdge;
-
-    if (method.generateKey) {
-      Graph.prototype[name] = function (source, target, attributes) {
-        return fn(
-          this,
-          name,
-          true,
-          (method.type || this.type) === 'undirected',
-          null,
-          source,
-          target,
-          attributes,
-          verb === 'update'
-        );
-      };
-    } else {
-      Graph.prototype[name] = function (edge, source, target, attributes) {
-        return fn(
-          this,
-          name,
-          false,
-          (method.type || this.type) === 'undirected',
-          edge,
-          source,
-          target,
-          attributes,
-          verb === 'update'
-        );
-      };
-    }
-  });
-});
-
-/**
- * Attributes-related.
- */
-attachNodeAttributesMethods(Graph);
-attachEdgeAttributesMethods(Graph);
-
-/**
- * Edge iteration-related.
- */
-attachEdgeIterationMethods(Graph);
-
-/**
- * Neighbor iteration-related.
- */
-attachNeighborIterationMethods(Graph);
-
-/**
- * Graphology Helper Classes
- * ==========================
- *
- * Building some higher-order classes instantiating the graph with
- * predefinite options.
- */
-
-/**
- * Alternative constructors.
- */
-class DirectedGraph extends Graph {
-  constructor(options) {
-    const finalOptions = assign({type: 'directed'}, options);
-
-    if ('multi' in finalOptions && finalOptions.multi !== false)
-      throw new InvalidArgumentsGraphError(
-        'DirectedGraph.from: inconsistent indication that the graph should be multi in given options!'
-      );
-
-    if (finalOptions.type !== 'directed')
-      throw new InvalidArgumentsGraphError(
-        'DirectedGraph.from: inconsistent "' +
-          finalOptions.type +
-          '" type in given options!'
-      );
-
-    super(finalOptions);
-  }
-}
-class UndirectedGraph extends Graph {
-  constructor(options) {
-    const finalOptions = assign({type: 'undirected'}, options);
-
-    if ('multi' in finalOptions && finalOptions.multi !== false)
-      throw new InvalidArgumentsGraphError(
-        'UndirectedGraph.from: inconsistent indication that the graph should be multi in given options!'
-      );
-
-    if (finalOptions.type !== 'undirected')
-      throw new InvalidArgumentsGraphError(
-        'UndirectedGraph.from: inconsistent "' +
-          finalOptions.type +
-          '" type in given options!'
-      );
-
-    super(finalOptions);
-  }
-}
-class MultiGraph extends Graph {
-  constructor(options) {
-    const finalOptions = assign({multi: true}, options);
-
-    if ('multi' in finalOptions && finalOptions.multi !== true)
-      throw new InvalidArgumentsGraphError(
-        'MultiGraph.from: inconsistent indication that the graph should be simple in given options!'
-      );
-
-    super(finalOptions);
-  }
-}
-class MultiDirectedGraph extends Graph {
-  constructor(options) {
-    const finalOptions = assign({type: 'directed', multi: true}, options);
-
-    if ('multi' in finalOptions && finalOptions.multi !== true)
-      throw new InvalidArgumentsGraphError(
-        'MultiDirectedGraph.from: inconsistent indication that the graph should be simple in given options!'
-      );
-
-    if (finalOptions.type !== 'directed')
-      throw new InvalidArgumentsGraphError(
-        'MultiDirectedGraph.from: inconsistent "' +
-          finalOptions.type +
-          '" type in given options!'
-      );
-
-    super(finalOptions);
-  }
-}
-class MultiUndirectedGraph extends Graph {
-  constructor(options) {
-    const finalOptions = assign({type: 'undirected', multi: true}, options);
-
-    if ('multi' in finalOptions && finalOptions.multi !== true)
-      throw new InvalidArgumentsGraphError(
-        'MultiUndirectedGraph.from: inconsistent indication that the graph should be simple in given options!'
-      );
-
-    if (finalOptions.type !== 'undirected')
-      throw new InvalidArgumentsGraphError(
-        'MultiUndirectedGraph.from: inconsistent "' +
-          finalOptions.type +
-          '" type in given options!'
-      );
-
-    super(finalOptions);
-  }
-}
-
-/**
- * Attaching static #.from method to each of the constructors.
- */
-function attachStaticFromMethod(Class) {
-  /**
-   * Builds a graph from serialized data or another graph's data.
-   *
-   * @param  {Graph|SerializedGraph} data      - Hydratation data.
-   * @param  {object}                [options] - Options.
-   * @return {Class}
-   */
-  Class.from = function (data, options) {
-    // Merging given options with serialized ones
-    const finalOptions = assign({}, data.options, options);
-
-    const instance = new Class(finalOptions);
-    instance.import(data);
-
-    return instance;
-  };
-}
-
-attachStaticFromMethod(Graph);
-attachStaticFromMethod(DirectedGraph);
-attachStaticFromMethod(UndirectedGraph);
-attachStaticFromMethod(MultiGraph);
-attachStaticFromMethod(MultiDirectedGraph);
-attachStaticFromMethod(MultiUndirectedGraph);
-
-Graph.Graph = Graph;
-Graph.DirectedGraph = DirectedGraph;
-Graph.UndirectedGraph = UndirectedGraph;
-Graph.MultiGraph = MultiGraph;
-Graph.MultiDirectedGraph = MultiDirectedGraph;
-Graph.MultiUndirectedGraph = MultiUndirectedGraph;
-
-Graph.InvalidArgumentsGraphError = InvalidArgumentsGraphError;
-Graph.NotFoundGraphError = NotFoundGraphError;
-Graph.UsageGraphError = UsageGraphError;
-
-/**
- * Graphology ESM Endoint
- * =======================
- *
- * Endpoint for ESM modules consumers.
- */
-
-export { DirectedGraph, Graph, InvalidArgumentsGraphError, MultiDirectedGraph, MultiGraph, MultiUndirectedGraph, NotFoundGraphError, UndirectedGraph, UsageGraphError, Graph as default };
-//# sourceMappingURL=graphology.esm.js.map
diff --git a/libs/shared/graph-layouts/node_modules/graphology/dist/graphology.umd.js b/libs/shared/graph-layouts/node_modules/graphology/dist/graphology.umd.js
deleted file mode 100644
index d3d07b30a..000000000
--- a/libs/shared/graph-layouts/node_modules/graphology/dist/graphology.umd.js
+++ /dev/null
@@ -1,6125 +0,0 @@
-(function (global, factory) {
-  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
-  typeof define === 'function' && define.amd ? define(factory) :
-  (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.graphology = factory());
-})(this, (function () { 'use strict';
-
-  function _typeof(obj) {
-    "@babel/helpers - typeof";
-
-    return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) {
-      return typeof obj;
-    } : function (obj) {
-      return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
-    }, _typeof(obj);
-  }
-
-  function _inheritsLoose(subClass, superClass) {
-    subClass.prototype = Object.create(superClass.prototype);
-    subClass.prototype.constructor = subClass;
-
-    _setPrototypeOf(subClass, superClass);
-  }
-
-  function _getPrototypeOf(o) {
-    _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) {
-      return o.__proto__ || Object.getPrototypeOf(o);
-    };
-    return _getPrototypeOf(o);
-  }
-
-  function _setPrototypeOf(o, p) {
-    _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {
-      o.__proto__ = p;
-      return o;
-    };
-
-    return _setPrototypeOf(o, p);
-  }
-
-  function _isNativeReflectConstruct() {
-    if (typeof Reflect === "undefined" || !Reflect.construct) return false;
-    if (Reflect.construct.sham) return false;
-    if (typeof Proxy === "function") return true;
-
-    try {
-      Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}));
-      return true;
-    } catch (e) {
-      return false;
-    }
-  }
-
-  function _construct(Parent, args, Class) {
-    if (_isNativeReflectConstruct()) {
-      _construct = Reflect.construct;
-    } else {
-      _construct = function _construct(Parent, args, Class) {
-        var a = [null];
-        a.push.apply(a, args);
-        var Constructor = Function.bind.apply(Parent, a);
-        var instance = new Constructor();
-        if (Class) _setPrototypeOf(instance, Class.prototype);
-        return instance;
-      };
-    }
-
-    return _construct.apply(null, arguments);
-  }
-
-  function _isNativeFunction(fn) {
-    return Function.toString.call(fn).indexOf("[native code]") !== -1;
-  }
-
-  function _wrapNativeSuper(Class) {
-    var _cache = typeof Map === "function" ? new Map() : undefined;
-
-    _wrapNativeSuper = function _wrapNativeSuper(Class) {
-      if (Class === null || !_isNativeFunction(Class)) return Class;
-
-      if (typeof Class !== "function") {
-        throw new TypeError("Super expression must either be null or a function");
-      }
-
-      if (typeof _cache !== "undefined") {
-        if (_cache.has(Class)) return _cache.get(Class);
-
-        _cache.set(Class, Wrapper);
-      }
-
-      function Wrapper() {
-        return _construct(Class, arguments, _getPrototypeOf(this).constructor);
-      }
-
-      Wrapper.prototype = Object.create(Class.prototype, {
-        constructor: {
-          value: Wrapper,
-          enumerable: false,
-          writable: true,
-          configurable: true
-        }
-      });
-      return _setPrototypeOf(Wrapper, Class);
-    };
-
-    return _wrapNativeSuper(Class);
-  }
-
-  function _assertThisInitialized(self) {
-    if (self === void 0) {
-      throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
-    }
-
-    return self;
-  }
-
-  /**
-   * Graphology Utilities
-   * =====================
-   *
-   * Collection of helpful functions used by the implementation.
-   */
-
-  /**
-   * Object.assign-like polyfill.
-   *
-   * @param  {object} target       - First object.
-   * @param  {object} [...objects] - Objects to merge.
-   * @return {object}
-   */
-  function assignPolyfill() {
-    var target = arguments[0];
-
-    for (var i = 1, l = arguments.length; i < l; i++) {
-      if (!arguments[i]) continue;
-
-      for (var k in arguments[i]) {
-        target[k] = arguments[i][k];
-      }
-    }
-
-    return target;
-  }
-
-  var assign = assignPolyfill;
-  if (typeof Object.assign === 'function') assign = Object.assign;
-  /**
-   * Function returning the first matching edge for given path.
-   * Note: this function does not check the existence of source & target. This
-   * must be performed by the caller.
-   *
-   * @param  {Graph}  graph  - Target graph.
-   * @param  {any}    source - Source node.
-   * @param  {any}    target - Target node.
-   * @param  {string} type   - Type of the edge (mixed, directed or undirected).
-   * @return {string|null}
-   */
-
-  function getMatchingEdge(graph, source, target, type) {
-    var sourceData = graph._nodes.get(source);
-
-    var edge = null;
-    if (!sourceData) return edge;
-
-    if (type === 'mixed') {
-      edge = sourceData.out && sourceData.out[target] || sourceData.undirected && sourceData.undirected[target];
-    } else if (type === 'directed') {
-      edge = sourceData.out && sourceData.out[target];
-    } else {
-      edge = sourceData.undirected && sourceData.undirected[target];
-    }
-
-    return edge;
-  }
-  /**
-   * Checks whether the given value is a Graph implementation instance.
-   *
-   * @param  {mixed}   value - Target value.
-   * @return {boolean}
-   */
-
-  function isGraph(value) {
-    return value !== null && _typeof(value) === 'object' && typeof value.addUndirectedEdgeWithKey === 'function' && typeof value.dropNode === 'function';
-  }
-  /**
-   * Checks whether the given value is a plain object.
-   *
-   * @param  {mixed}   value - Target value.
-   * @return {boolean}
-   */
-
-  function isPlainObject(value) {
-    return _typeof(value) === 'object' && value !== null && value.constructor === Object;
-  }
-  /**
-   * Checks whether the given object is empty.
-   *
-   * @param  {object}  o - Target Object.
-   * @return {boolean}
-   */
-
-  function isEmpty(o) {
-    var k;
-
-    for (k in o) {
-      return false;
-    }
-
-    return true;
-  }
-  /**
-   * Creates a "private" property for the given member name by concealing it
-   * using the `enumerable` option.
-   *
-   * @param {object} target - Target object.
-   * @param {string} name   - Member name.
-   */
-
-  function privateProperty(target, name, value) {
-    Object.defineProperty(target, name, {
-      enumerable: false,
-      configurable: false,
-      writable: true,
-      value: value
-    });
-  }
-  /**
-   * Creates a read-only property for the given member name & the given getter.
-   *
-   * @param {object}   target - Target object.
-   * @param {string}   name   - Member name.
-   * @param {mixed}    value  - The attached getter or fixed value.
-   */
-
-  function readOnlyProperty(target, name, value) {
-    var descriptor = {
-      enumerable: true,
-      configurable: true
-    };
-
-    if (typeof value === 'function') {
-      descriptor.get = value;
-    } else {
-      descriptor.value = value;
-      descriptor.writable = false;
-    }
-
-    Object.defineProperty(target, name, descriptor);
-  }
-  /**
-   * Returns whether the given object constitute valid hints.
-   *
-   * @param {object} hints - Target object.
-   */
-
-  function validateHints(hints) {
-    if (!isPlainObject(hints)) return false;
-    if (hints.attributes && !Array.isArray(hints.attributes)) return false;
-    return true;
-  }
-  /**
-   * Creates a function generating incremental ids for edges.
-   *
-   * @return {function}
-   */
-
-  function incrementalIdStartingFromRandomByte() {
-    var i = Math.floor(Math.random() * 256) & 0xff;
-    return function () {
-      return i++;
-    };
-  }
-
-  var events = {exports: {}};
-
-  var R = typeof Reflect === 'object' ? Reflect : null;
-  var ReflectApply = R && typeof R.apply === 'function' ? R.apply : function ReflectApply(target, receiver, args) {
-    return Function.prototype.apply.call(target, receiver, args);
-  };
-  var ReflectOwnKeys;
-
-  if (R && typeof R.ownKeys === 'function') {
-    ReflectOwnKeys = R.ownKeys;
-  } else if (Object.getOwnPropertySymbols) {
-    ReflectOwnKeys = function ReflectOwnKeys(target) {
-      return Object.getOwnPropertyNames(target).concat(Object.getOwnPropertySymbols(target));
-    };
-  } else {
-    ReflectOwnKeys = function ReflectOwnKeys(target) {
-      return Object.getOwnPropertyNames(target);
-    };
-  }
-
-  function ProcessEmitWarning(warning) {
-    if (console && console.warn) console.warn(warning);
-  }
-
-  var NumberIsNaN = Number.isNaN || function NumberIsNaN(value) {
-    return value !== value;
-  };
-
-  function EventEmitter() {
-    EventEmitter.init.call(this);
-  }
-
-  events.exports = EventEmitter;
-  events.exports.once = once; // Backwards-compat with node 0.10.x
-
-  EventEmitter.EventEmitter = EventEmitter;
-  EventEmitter.prototype._events = undefined;
-  EventEmitter.prototype._eventsCount = 0;
-  EventEmitter.prototype._maxListeners = undefined; // By default EventEmitters will print a warning if more than 10 listeners are
-  // added to it. This is a useful default which helps finding memory leaks.
-
-  var defaultMaxListeners = 10;
-
-  function checkListener(listener) {
-    if (typeof listener !== 'function') {
-      throw new TypeError('The "listener" argument must be of type Function. Received type ' + typeof listener);
-    }
-  }
-
-  Object.defineProperty(EventEmitter, 'defaultMaxListeners', {
-    enumerable: true,
-    get: function () {
-      return defaultMaxListeners;
-    },
-    set: function (arg) {
-      if (typeof arg !== 'number' || arg < 0 || NumberIsNaN(arg)) {
-        throw new RangeError('The value of "defaultMaxListeners" is out of range. It must be a non-negative number. Received ' + arg + '.');
-      }
-
-      defaultMaxListeners = arg;
-    }
-  });
-
-  EventEmitter.init = function () {
-    if (this._events === undefined || this._events === Object.getPrototypeOf(this)._events) {
-      this._events = Object.create(null);
-      this._eventsCount = 0;
-    }
-
-    this._maxListeners = this._maxListeners || undefined;
-  }; // Obviously not all Emitters should be limited to 10. This function allows
-  // that to be increased. Set to zero for unlimited.
-
-
-  EventEmitter.prototype.setMaxListeners = function setMaxListeners(n) {
-    if (typeof n !== 'number' || n < 0 || NumberIsNaN(n)) {
-      throw new RangeError('The value of "n" is out of range. It must be a non-negative number. Received ' + n + '.');
-    }
-
-    this._maxListeners = n;
-    return this;
-  };
-
-  function _getMaxListeners(that) {
-    if (that._maxListeners === undefined) return EventEmitter.defaultMaxListeners;
-    return that._maxListeners;
-  }
-
-  EventEmitter.prototype.getMaxListeners = function getMaxListeners() {
-    return _getMaxListeners(this);
-  };
-
-  EventEmitter.prototype.emit = function emit(type) {
-    var args = [];
-
-    for (var i = 1; i < arguments.length; i++) args.push(arguments[i]);
-
-    var doError = type === 'error';
-    var events = this._events;
-    if (events !== undefined) doError = doError && events.error === undefined;else if (!doError) return false; // If there is no 'error' event listener then throw.
-
-    if (doError) {
-      var er;
-      if (args.length > 0) er = args[0];
-
-      if (er instanceof Error) {
-        // Note: The comments on the `throw` lines are intentional, they show
-        // up in Node's output if this results in an unhandled exception.
-        throw er; // Unhandled 'error' event
-      } // At least give some kind of context to the user
-
-
-      var err = new Error('Unhandled error.' + (er ? ' (' + er.message + ')' : ''));
-      err.context = er;
-      throw err; // Unhandled 'error' event
-    }
-
-    var handler = events[type];
-    if (handler === undefined) return false;
-
-    if (typeof handler === 'function') {
-      ReflectApply(handler, this, args);
-    } else {
-      var len = handler.length;
-      var listeners = arrayClone(handler, len);
-
-      for (var i = 0; i < len; ++i) ReflectApply(listeners[i], this, args);
-    }
-
-    return true;
-  };
-
-  function _addListener(target, type, listener, prepend) {
-    var m;
-    var events;
-    var existing;
-    checkListener(listener);
-    events = target._events;
-
-    if (events === undefined) {
-      events = target._events = Object.create(null);
-      target._eventsCount = 0;
-    } else {
-      // To avoid recursion in the case that type === "newListener"! Before
-      // adding it to the listeners, first emit "newListener".
-      if (events.newListener !== undefined) {
-        target.emit('newListener', type, listener.listener ? listener.listener : listener); // Re-assign `events` because a newListener handler could have caused the
-        // this._events to be assigned to a new object
-
-        events = target._events;
-      }
-
-      existing = events[type];
-    }
-
-    if (existing === undefined) {
-      // Optimize the case of one listener. Don't need the extra array object.
-      existing = events[type] = listener;
-      ++target._eventsCount;
-    } else {
-      if (typeof existing === 'function') {
-        // Adding the second element, need to change to array.
-        existing = events[type] = prepend ? [listener, existing] : [existing, listener]; // If we've already got an array, just append.
-      } else if (prepend) {
-        existing.unshift(listener);
-      } else {
-        existing.push(listener);
-      } // Check for listener leak
-
-
-      m = _getMaxListeners(target);
-
-      if (m > 0 && existing.length > m && !existing.warned) {
-        existing.warned = true; // No error code for this since it is a Warning
-        // eslint-disable-next-line no-restricted-syntax
-
-        var w = new Error('Possible EventEmitter memory leak detected. ' + existing.length + ' ' + String(type) + ' listeners ' + 'added. Use emitter.setMaxListeners() to ' + 'increase limit');
-        w.name = 'MaxListenersExceededWarning';
-        w.emitter = target;
-        w.type = type;
-        w.count = existing.length;
-        ProcessEmitWarning(w);
-      }
-    }
-
-    return target;
-  }
-
-  EventEmitter.prototype.addListener = function addListener(type, listener) {
-    return _addListener(this, type, listener, false);
-  };
-
-  EventEmitter.prototype.on = EventEmitter.prototype.addListener;
-
-  EventEmitter.prototype.prependListener = function prependListener(type, listener) {
-    return _addListener(this, type, listener, true);
-  };
-
-  function onceWrapper() {
-    if (!this.fired) {
-      this.target.removeListener(this.type, this.wrapFn);
-      this.fired = true;
-      if (arguments.length === 0) return this.listener.call(this.target);
-      return this.listener.apply(this.target, arguments);
-    }
-  }
-
-  function _onceWrap(target, type, listener) {
-    var state = {
-      fired: false,
-      wrapFn: undefined,
-      target: target,
-      type: type,
-      listener: listener
-    };
-    var wrapped = onceWrapper.bind(state);
-    wrapped.listener = listener;
-    state.wrapFn = wrapped;
-    return wrapped;
-  }
-
-  EventEmitter.prototype.once = function once(type, listener) {
-    checkListener(listener);
-    this.on(type, _onceWrap(this, type, listener));
-    return this;
-  };
-
-  EventEmitter.prototype.prependOnceListener = function prependOnceListener(type, listener) {
-    checkListener(listener);
-    this.prependListener(type, _onceWrap(this, type, listener));
-    return this;
-  }; // Emits a 'removeListener' event if and only if the listener was removed.
-
-
-  EventEmitter.prototype.removeListener = function removeListener(type, listener) {
-    var list, events, position, i, originalListener;
-    checkListener(listener);
-    events = this._events;
-    if (events === undefined) return this;
-    list = events[type];
-    if (list === undefined) return this;
-
-    if (list === listener || list.listener === listener) {
-      if (--this._eventsCount === 0) this._events = Object.create(null);else {
-        delete events[type];
-        if (events.removeListener) this.emit('removeListener', type, list.listener || listener);
-      }
-    } else if (typeof list !== 'function') {
-      position = -1;
-
-      for (i = list.length - 1; i >= 0; i--) {
-        if (list[i] === listener || list[i].listener === listener) {
-          originalListener = list[i].listener;
-          position = i;
-          break;
-        }
-      }
-
-      if (position < 0) return this;
-      if (position === 0) list.shift();else {
-        spliceOne(list, position);
-      }
-      if (list.length === 1) events[type] = list[0];
-      if (events.removeListener !== undefined) this.emit('removeListener', type, originalListener || listener);
-    }
-
-    return this;
-  };
-
-  EventEmitter.prototype.off = EventEmitter.prototype.removeListener;
-
-  EventEmitter.prototype.removeAllListeners = function removeAllListeners(type) {
-    var listeners, events, i;
-    events = this._events;
-    if (events === undefined) return this; // not listening for removeListener, no need to emit
-
-    if (events.removeListener === undefined) {
-      if (arguments.length === 0) {
-        this._events = Object.create(null);
-        this._eventsCount = 0;
-      } else if (events[type] !== undefined) {
-        if (--this._eventsCount === 0) this._events = Object.create(null);else delete events[type];
-      }
-
-      return this;
-    } // emit removeListener for all listeners on all events
-
-
-    if (arguments.length === 0) {
-      var keys = Object.keys(events);
-      var key;
-
-      for (i = 0; i < keys.length; ++i) {
-        key = keys[i];
-        if (key === 'removeListener') continue;
-        this.removeAllListeners(key);
-      }
-
-      this.removeAllListeners('removeListener');
-      this._events = Object.create(null);
-      this._eventsCount = 0;
-      return this;
-    }
-
-    listeners = events[type];
-
-    if (typeof listeners === 'function') {
-      this.removeListener(type, listeners);
-    } else if (listeners !== undefined) {
-      // LIFO order
-      for (i = listeners.length - 1; i >= 0; i--) {
-        this.removeListener(type, listeners[i]);
-      }
-    }
-
-    return this;
-  };
-
-  function _listeners(target, type, unwrap) {
-    var events = target._events;
-    if (events === undefined) return [];
-    var evlistener = events[type];
-    if (evlistener === undefined) return [];
-    if (typeof evlistener === 'function') return unwrap ? [evlistener.listener || evlistener] : [evlistener];
-    return unwrap ? unwrapListeners(evlistener) : arrayClone(evlistener, evlistener.length);
-  }
-
-  EventEmitter.prototype.listeners = function listeners(type) {
-    return _listeners(this, type, true);
-  };
-
-  EventEmitter.prototype.rawListeners = function rawListeners(type) {
-    return _listeners(this, type, false);
-  };
-
-  EventEmitter.listenerCount = function (emitter, type) {
-    if (typeof emitter.listenerCount === 'function') {
-      return emitter.listenerCount(type);
-    } else {
-      return listenerCount.call(emitter, type);
-    }
-  };
-
-  EventEmitter.prototype.listenerCount = listenerCount;
-
-  function listenerCount(type) {
-    var events = this._events;
-
-    if (events !== undefined) {
-      var evlistener = events[type];
-
-      if (typeof evlistener === 'function') {
-        return 1;
-      } else if (evlistener !== undefined) {
-        return evlistener.length;
-      }
-    }
-
-    return 0;
-  }
-
-  EventEmitter.prototype.eventNames = function eventNames() {
-    return this._eventsCount > 0 ? ReflectOwnKeys(this._events) : [];
-  };
-
-  function arrayClone(arr, n) {
-    var copy = new Array(n);
-
-    for (var i = 0; i < n; ++i) copy[i] = arr[i];
-
-    return copy;
-  }
-
-  function spliceOne(list, index) {
-    for (; index + 1 < list.length; index++) list[index] = list[index + 1];
-
-    list.pop();
-  }
-
-  function unwrapListeners(arr) {
-    var ret = new Array(arr.length);
-
-    for (var i = 0; i < ret.length; ++i) {
-      ret[i] = arr[i].listener || arr[i];
-    }
-
-    return ret;
-  }
-
-  function once(emitter, name) {
-    return new Promise(function (resolve, reject) {
-      function errorListener(err) {
-        emitter.removeListener(name, resolver);
-        reject(err);
-      }
-
-      function resolver() {
-        if (typeof emitter.removeListener === 'function') {
-          emitter.removeListener('error', errorListener);
-        }
-
-        resolve([].slice.call(arguments));
-      }
-      eventTargetAgnosticAddListener(emitter, name, resolver, {
-        once: true
-      });
-
-      if (name !== 'error') {
-        addErrorHandlerIfEventEmitter(emitter, errorListener, {
-          once: true
-        });
-      }
-    });
-  }
-
-  function addErrorHandlerIfEventEmitter(emitter, handler, flags) {
-    if (typeof emitter.on === 'function') {
-      eventTargetAgnosticAddListener(emitter, 'error', handler, flags);
-    }
-  }
-
-  function eventTargetAgnosticAddListener(emitter, name, listener, flags) {
-    if (typeof emitter.on === 'function') {
-      if (flags.once) {
-        emitter.once(name, listener);
-      } else {
-        emitter.on(name, listener);
-      }
-    } else if (typeof emitter.addEventListener === 'function') {
-      // EventTarget does not have `error` event semantics like Node
-      // EventEmitters, we do not listen for `error` events here.
-      emitter.addEventListener(name, function wrapListener(arg) {
-        // IE does not have builtin `{ once: true }` support so we
-        // have to do it manually.
-        if (flags.once) {
-          emitter.removeEventListener(name, wrapListener);
-        }
-
-        listener(arg);
-      });
-    } else {
-      throw new TypeError('The "emitter" argument must be of type EventEmitter. Received type ' + typeof emitter);
-    }
-  }
-
-  /**
-   * Obliterator Iterator Class
-   * ===========================
-   *
-   * Simple class representing the library's iterators.
-   */
-  /**
-   * Iterator class.
-   *
-   * @constructor
-   * @param {function} next - Next function.
-   */
-
-  function Iterator$2(next) {
-    if (typeof next !== 'function') throw new Error('obliterator/iterator: expecting a function!');
-    this.next = next;
-  }
-  /**
-   * If symbols are supported, we add `next` to `Symbol.iterator`.
-   */
-
-
-  if (typeof Symbol !== 'undefined') Iterator$2.prototype[Symbol.iterator] = function () {
-    return this;
-  };
-  /**
-   * Returning an iterator of the given values.
-   *
-   * @param  {any...} values - Values.
-   * @return {Iterator}
-   */
-
-  Iterator$2.of = function () {
-    var args = arguments,
-        l = args.length,
-        i = 0;
-    return new Iterator$2(function () {
-      if (i >= l) return {
-        done: true
-      };
-      return {
-        done: false,
-        value: args[i++]
-      };
-    });
-  };
-  /**
-   * Returning an empty iterator.
-   *
-   * @return {Iterator}
-   */
-
-
-  Iterator$2.empty = function () {
-    var iterator = new Iterator$2(function () {
-      return {
-        done: true
-      };
-    });
-    return iterator;
-  };
-  /**
-   * Returning an iterator over the given indexed sequence.
-   *
-   * @param  {string|Array} sequence - Target sequence.
-   * @return {Iterator}
-   */
-
-
-  Iterator$2.fromSequence = function (sequence) {
-    var i = 0,
-        l = sequence.length;
-    return new Iterator$2(function () {
-      if (i >= l) return {
-        done: true
-      };
-      return {
-        done: false,
-        value: sequence[i++]
-      };
-    });
-  };
-  /**
-   * Returning whether the given value is an iterator.
-   *
-   * @param  {any} value - Value.
-   * @return {boolean}
-   */
-
-
-  Iterator$2.is = function (value) {
-    if (value instanceof Iterator$2) return true;
-    return typeof value === 'object' && value !== null && typeof value.next === 'function';
-  };
-  /**
-   * Exporting.
-   */
-
-
-  var iterator = Iterator$2;
-
-  var support$1 = {};
-
-  support$1.ARRAY_BUFFER_SUPPORT = typeof ArrayBuffer !== 'undefined';
-  support$1.SYMBOL_SUPPORT = typeof Symbol !== 'undefined';
-
-  /**
-   * Obliterator Iter Function
-   * ==========================
-   *
-   * Function coercing values to an iterator. It can be quite useful when needing
-   * to handle iterables and iterators the same way.
-   */
-  var Iterator$1 = iterator;
-  var support = support$1;
-  var ARRAY_BUFFER_SUPPORT = support.ARRAY_BUFFER_SUPPORT;
-  var SYMBOL_SUPPORT = support.SYMBOL_SUPPORT;
-
-  function iterOrNull(target) {
-    // Indexed sequence
-    if (typeof target === 'string' || Array.isArray(target) || ARRAY_BUFFER_SUPPORT && ArrayBuffer.isView(target)) return Iterator$1.fromSequence(target); // Invalid value
-
-    if (typeof target !== 'object' || target === null) return null; // Iterable
-
-    if (SYMBOL_SUPPORT && typeof target[Symbol.iterator] === 'function') return target[Symbol.iterator](); // Iterator duck-typing
-
-    if (typeof target.next === 'function') return target; // Invalid object
-
-    return null;
-  }
-
-  var iter$2 = function iter(target) {
-    var iterator = iterOrNull(target);
-    if (!iterator) throw new Error('obliterator: target is not iterable nor a valid iterator.');
-    return iterator;
-  };
-
-  /* eslint no-constant-condition: 0 */
-  /**
-   * Obliterator Take Function
-   * ==========================
-   *
-   * Function taking n or every value of the given iterator and returns them
-   * into an array.
-   */
-
-  var iter$1 = iter$2;
-  /**
-   * Take.
-   *
-   * @param  {Iterable} iterable - Target iterable.
-   * @param  {number}   [n]      - Optional number of items to take.
-   * @return {array}
-   */
-
-  var take = function take(iterable, n) {
-    var l = arguments.length > 1 ? n : Infinity,
-        array = l !== Infinity ? new Array(l) : [],
-        step,
-        i = 0;
-    var iterator = iter$1(iterable);
-
-    while (true) {
-      if (i === l) return array;
-      step = iterator.next();
-
-      if (step.done) {
-        if (i !== n) array.length = i;
-        return array;
-      }
-
-      array[i++] = step.value;
-    }
-  };
-
-  /**
-   * Graphology Custom Errors
-   * =========================
-   *
-   * Defining custom errors for ease of use & easy unit tests across
-   * implementations (normalized typology rather than relying on error
-   * messages to check whether the correct error was found).
-   */
-  var GraphError = /*#__PURE__*/function (_Error) {
-    _inheritsLoose(GraphError, _Error);
-
-    function GraphError(message) {
-      var _this;
-
-      _this = _Error.call(this) || this;
-      _this.name = 'GraphError';
-      _this.message = message;
-      return _this;
-    }
-
-    return GraphError;
-  }( /*#__PURE__*/_wrapNativeSuper(Error));
-  var InvalidArgumentsGraphError = /*#__PURE__*/function (_GraphError) {
-    _inheritsLoose(InvalidArgumentsGraphError, _GraphError);
-
-    function InvalidArgumentsGraphError(message) {
-      var _this2;
-
-      _this2 = _GraphError.call(this, message) || this;
-      _this2.name = 'InvalidArgumentsGraphError'; // This is V8 specific to enhance stack readability
-
-      if (typeof Error.captureStackTrace === 'function') Error.captureStackTrace(_assertThisInitialized(_this2), InvalidArgumentsGraphError.prototype.constructor);
-      return _this2;
-    }
-
-    return InvalidArgumentsGraphError;
-  }(GraphError);
-  var NotFoundGraphError = /*#__PURE__*/function (_GraphError2) {
-    _inheritsLoose(NotFoundGraphError, _GraphError2);
-
-    function NotFoundGraphError(message) {
-      var _this3;
-
-      _this3 = _GraphError2.call(this, message) || this;
-      _this3.name = 'NotFoundGraphError'; // This is V8 specific to enhance stack readability
-
-      if (typeof Error.captureStackTrace === 'function') Error.captureStackTrace(_assertThisInitialized(_this3), NotFoundGraphError.prototype.constructor);
-      return _this3;
-    }
-
-    return NotFoundGraphError;
-  }(GraphError);
-  var UsageGraphError = /*#__PURE__*/function (_GraphError3) {
-    _inheritsLoose(UsageGraphError, _GraphError3);
-
-    function UsageGraphError(message) {
-      var _this4;
-
-      _this4 = _GraphError3.call(this, message) || this;
-      _this4.name = 'UsageGraphError'; // This is V8 specific to enhance stack readability
-
-      if (typeof Error.captureStackTrace === 'function') Error.captureStackTrace(_assertThisInitialized(_this4), UsageGraphError.prototype.constructor);
-      return _this4;
-    }
-
-    return UsageGraphError;
-  }(GraphError);
-
-  /**
-   * Graphology Internal Data Classes
-   * =================================
-   *
-   * Internal classes hopefully reduced to structs by engines & storing
-   * necessary information for nodes & edges.
-   *
-   * Note that those classes don't rely on the `class` keyword to avoid some
-   * cruft introduced by most of ES2015 transpilers.
-   */
-
-  /**
-   * MixedNodeData class.
-   *
-   * @constructor
-   * @param {string} string     - The node's key.
-   * @param {object} attributes - Node's attributes.
-   */
-  function MixedNodeData(key, attributes) {
-    // Attributes
-    this.key = key;
-    this.attributes = attributes;
-    this.clear();
-  }
-
-  MixedNodeData.prototype.clear = function () {
-    // Degrees
-    this.inDegree = 0;
-    this.outDegree = 0;
-    this.undirectedDegree = 0; // Indices
-
-    this["in"] = {};
-    this.out = {};
-    this.undirected = {};
-  };
-  /**
-   * DirectedNodeData class.
-   *
-   * @constructor
-   * @param {string} string     - The node's key.
-   * @param {object} attributes - Node's attributes.
-   */
-
-
-  function DirectedNodeData(key, attributes) {
-    // Attributes
-    this.key = key;
-    this.attributes = attributes;
-    this.clear();
-  }
-
-  DirectedNodeData.prototype.clear = function () {
-    // Degrees
-    this.inDegree = 0;
-    this.outDegree = 0; // Indices
-
-    this["in"] = {};
-    this.out = {};
-  };
-  /**
-   * UndirectedNodeData class.
-   *
-   * @constructor
-   * @param {string} string     - The node's key.
-   * @param {object} attributes - Node's attributes.
-   */
-
-
-  function UndirectedNodeData(key, attributes) {
-    // Attributes
-    this.key = key;
-    this.attributes = attributes;
-    this.clear();
-  }
-
-  UndirectedNodeData.prototype.clear = function () {
-    // Degrees
-    this.undirectedDegree = 0; // Indices
-
-    this.undirected = {};
-  };
-  /**
-   * EdgeData class.
-   *
-   * @constructor
-   * @param {boolean} undirected   - Whether the edge is undirected.
-   * @param {string}  string       - The edge's key.
-   * @param {string}  source       - Source of the edge.
-   * @param {string}  target       - Target of the edge.
-   * @param {object}  attributes   - Edge's attributes.
-   */
-
-
-  function EdgeData(undirected, key, source, target, attributes) {
-    // Attributes
-    this.key = key;
-    this.attributes = attributes;
-    this.undirected = undirected; // Extremities
-
-    this.source = source;
-    this.target = target;
-  }
-
-  EdgeData.prototype.attach = function () {
-    var outKey = 'out';
-    var inKey = 'in';
-    if (this.undirected) outKey = inKey = 'undirected';
-    var source = this.source.key;
-    var target = this.target.key; // Handling source
-
-    this.source[outKey][target] = this;
-    if (this.undirected && source === target) return; // Handling target
-
-    this.target[inKey][source] = this;
-  };
-
-  EdgeData.prototype.attachMulti = function () {
-    var outKey = 'out';
-    var inKey = 'in';
-    var source = this.source.key;
-    var target = this.target.key;
-    if (this.undirected) outKey = inKey = 'undirected'; // Handling source
-
-    var adj = this.source[outKey];
-    var head = adj[target];
-
-    if (typeof head === 'undefined') {
-      adj[target] = this; // Self-loop optimization
-
-      if (!(this.undirected && source === target)) {
-        // Handling target
-        this.target[inKey][source] = this;
-      }
-
-      return;
-    } // Prepending to doubly-linked list
-
-
-    head.previous = this;
-    this.next = head; // Pointing to new head
-    // NOTE: use mutating swap later to avoid lookup?
-
-    adj[target] = this;
-    this.target[inKey][source] = this;
-  };
-
-  EdgeData.prototype.detach = function () {
-    var source = this.source.key;
-    var target = this.target.key;
-    var outKey = 'out';
-    var inKey = 'in';
-    if (this.undirected) outKey = inKey = 'undirected';
-    delete this.source[outKey][target]; // No-op delete in case of undirected self-loop
-
-    delete this.target[inKey][source];
-  };
-
-  EdgeData.prototype.detachMulti = function () {
-    var source = this.source.key;
-    var target = this.target.key;
-    var outKey = 'out';
-    var inKey = 'in';
-    if (this.undirected) outKey = inKey = 'undirected'; // Deleting from doubly-linked list
-
-    if (this.previous === undefined) {
-      // We are dealing with the head
-      // Should we delete the adjacency entry because it is now empty?
-      if (this.next === undefined) {
-        delete this.source[outKey][target]; // No-op delete in case of undirected self-loop
-
-        delete this.target[inKey][source];
-      } else {
-        // Detaching
-        this.next.previous = undefined; // NOTE: could avoid the lookups by creating a #.become mutating method
-
-        this.source[outKey][target] = this.next; // No-op delete in case of undirected self-loop
-
-        this.target[inKey][source] = this.next;
-      }
-    } else {
-      // We are dealing with another list node
-      this.previous.next = this.next; // If not last
-
-      if (this.next !== undefined) {
-        this.next.previous = this.previous;
-      }
-    }
-  };
-
-  /**
-   * Graphology Node Attributes methods
-   * ===================================
-   */
-  var NODE = 0;
-  var SOURCE = 1;
-  var TARGET = 2;
-  var OPPOSITE = 3;
-
-  function findRelevantNodeData(graph, method, mode, nodeOrEdge, nameOrEdge, add1, add2) {
-    var nodeData, edgeData, arg1, arg2;
-    nodeOrEdge = '' + nodeOrEdge;
-
-    if (mode === NODE) {
-      nodeData = graph._nodes.get(nodeOrEdge);
-      if (!nodeData) throw new NotFoundGraphError("Graph.".concat(method, ": could not find the \"").concat(nodeOrEdge, "\" node in the graph."));
-      arg1 = nameOrEdge;
-      arg2 = add1;
-    } else if (mode === OPPOSITE) {
-      nameOrEdge = '' + nameOrEdge;
-      edgeData = graph._edges.get(nameOrEdge);
-      if (!edgeData) throw new NotFoundGraphError("Graph.".concat(method, ": could not find the \"").concat(nameOrEdge, "\" edge in the graph."));
-      var source = edgeData.source.key;
-      var target = edgeData.target.key;
-
-      if (nodeOrEdge === source) {
-        nodeData = edgeData.target;
-      } else if (nodeOrEdge === target) {
-        nodeData = edgeData.source;
-      } else {
-        throw new NotFoundGraphError("Graph.".concat(method, ": the \"").concat(nodeOrEdge, "\" node is not attached to the \"").concat(nameOrEdge, "\" edge (").concat(source, ", ").concat(target, ")."));
-      }
-
-      arg1 = add1;
-      arg2 = add2;
-    } else {
-      edgeData = graph._edges.get(nodeOrEdge);
-      if (!edgeData) throw new NotFoundGraphError("Graph.".concat(method, ": could not find the \"").concat(nodeOrEdge, "\" edge in the graph."));
-
-      if (mode === SOURCE) {
-        nodeData = edgeData.source;
-      } else {
-        nodeData = edgeData.target;
-      }
-
-      arg1 = nameOrEdge;
-      arg2 = add1;
-    }
-
-    return [nodeData, arg1, arg2];
-  }
-
-  function attachNodeAttributeGetter(Class, method, mode) {
-    Class.prototype[method] = function (nodeOrEdge, nameOrEdge, add1) {
-      var _findRelevantNodeData = findRelevantNodeData(this, method, mode, nodeOrEdge, nameOrEdge, add1),
-          data = _findRelevantNodeData[0],
-          name = _findRelevantNodeData[1];
-
-      return data.attributes[name];
-    };
-  }
-
-  function attachNodeAttributesGetter(Class, method, mode) {
-    Class.prototype[method] = function (nodeOrEdge, nameOrEdge) {
-      var _findRelevantNodeData2 = findRelevantNodeData(this, method, mode, nodeOrEdge, nameOrEdge),
-          data = _findRelevantNodeData2[0];
-
-      return data.attributes;
-    };
-  }
-
-  function attachNodeAttributeChecker(Class, method, mode) {
-    Class.prototype[method] = function (nodeOrEdge, nameOrEdge, add1) {
-      var _findRelevantNodeData3 = findRelevantNodeData(this, method, mode, nodeOrEdge, nameOrEdge, add1),
-          data = _findRelevantNodeData3[0],
-          name = _findRelevantNodeData3[1];
-
-      return data.attributes.hasOwnProperty(name);
-    };
-  }
-
-  function attachNodeAttributeSetter(Class, method, mode) {
-    Class.prototype[method] = function (nodeOrEdge, nameOrEdge, add1, add2) {
-      var _findRelevantNodeData4 = findRelevantNodeData(this, method, mode, nodeOrEdge, nameOrEdge, add1, add2),
-          data = _findRelevantNodeData4[0],
-          name = _findRelevantNodeData4[1],
-          value = _findRelevantNodeData4[2];
-
-      data.attributes[name] = value; // Emitting
-
-      this.emit('nodeAttributesUpdated', {
-        key: data.key,
-        type: 'set',
-        attributes: data.attributes,
-        name: name
-      });
-      return this;
-    };
-  }
-
-  function attachNodeAttributeUpdater(Class, method, mode) {
-    Class.prototype[method] = function (nodeOrEdge, nameOrEdge, add1, add2) {
-      var _findRelevantNodeData5 = findRelevantNodeData(this, method, mode, nodeOrEdge, nameOrEdge, add1, add2),
-          data = _findRelevantNodeData5[0],
-          name = _findRelevantNodeData5[1],
-          updater = _findRelevantNodeData5[2];
-
-      if (typeof updater !== 'function') throw new InvalidArgumentsGraphError("Graph.".concat(method, ": updater should be a function."));
-      var attributes = data.attributes;
-      var value = updater(attributes[name]);
-      attributes[name] = value; // Emitting
-
-      this.emit('nodeAttributesUpdated', {
-        key: data.key,
-        type: 'set',
-        attributes: data.attributes,
-        name: name
-      });
-      return this;
-    };
-  }
-
-  function attachNodeAttributeRemover(Class, method, mode) {
-    Class.prototype[method] = function (nodeOrEdge, nameOrEdge, add1) {
-      var _findRelevantNodeData6 = findRelevantNodeData(this, method, mode, nodeOrEdge, nameOrEdge, add1),
-          data = _findRelevantNodeData6[0],
-          name = _findRelevantNodeData6[1];
-
-      delete data.attributes[name]; // Emitting
-
-      this.emit('nodeAttributesUpdated', {
-        key: data.key,
-        type: 'remove',
-        attributes: data.attributes,
-        name: name
-      });
-      return this;
-    };
-  }
-
-  function attachNodeAttributesReplacer(Class, method, mode) {
-    Class.prototype[method] = function (nodeOrEdge, nameOrEdge, add1) {
-      var _findRelevantNodeData7 = findRelevantNodeData(this, method, mode, nodeOrEdge, nameOrEdge, add1),
-          data = _findRelevantNodeData7[0],
-          attributes = _findRelevantNodeData7[1];
-
-      if (!isPlainObject(attributes)) throw new InvalidArgumentsGraphError("Graph.".concat(method, ": provided attributes are not a plain object."));
-      data.attributes = attributes; // Emitting
-
-      this.emit('nodeAttributesUpdated', {
-        key: data.key,
-        type: 'replace',
-        attributes: data.attributes
-      });
-      return this;
-    };
-  }
-
-  function attachNodeAttributesMerger(Class, method, mode) {
-    Class.prototype[method] = function (nodeOrEdge, nameOrEdge, add1) {
-      var _findRelevantNodeData8 = findRelevantNodeData(this, method, mode, nodeOrEdge, nameOrEdge, add1),
-          data = _findRelevantNodeData8[0],
-          attributes = _findRelevantNodeData8[1];
-
-      if (!isPlainObject(attributes)) throw new InvalidArgumentsGraphError("Graph.".concat(method, ": provided attributes are not a plain object."));
-      assign(data.attributes, attributes); // Emitting
-
-      this.emit('nodeAttributesUpdated', {
-        key: data.key,
-        type: 'merge',
-        attributes: data.attributes,
-        data: attributes
-      });
-      return this;
-    };
-  }
-
-  function attachNodeAttributesUpdater(Class, method, mode) {
-    Class.prototype[method] = function (nodeOrEdge, nameOrEdge, add1) {
-      var _findRelevantNodeData9 = findRelevantNodeData(this, method, mode, nodeOrEdge, nameOrEdge, add1),
-          data = _findRelevantNodeData9[0],
-          updater = _findRelevantNodeData9[1];
-
-      if (typeof updater !== 'function') throw new InvalidArgumentsGraphError("Graph.".concat(method, ": provided updater is not a function."));
-      data.attributes = updater(data.attributes); // Emitting
-
-      this.emit('nodeAttributesUpdated', {
-        key: data.key,
-        type: 'update',
-        attributes: data.attributes
-      });
-      return this;
-    };
-  }
-  /**
-   * List of methods to attach.
-   */
-
-
-  var NODE_ATTRIBUTES_METHODS = [{
-    name: function name(element) {
-      return "get".concat(element, "Attribute");
-    },
-    attacher: attachNodeAttributeGetter
-  }, {
-    name: function name(element) {
-      return "get".concat(element, "Attributes");
-    },
-    attacher: attachNodeAttributesGetter
-  }, {
-    name: function name(element) {
-      return "has".concat(element, "Attribute");
-    },
-    attacher: attachNodeAttributeChecker
-  }, {
-    name: function name(element) {
-      return "set".concat(element, "Attribute");
-    },
-    attacher: attachNodeAttributeSetter
-  }, {
-    name: function name(element) {
-      return "update".concat(element, "Attribute");
-    },
-    attacher: attachNodeAttributeUpdater
-  }, {
-    name: function name(element) {
-      return "remove".concat(element, "Attribute");
-    },
-    attacher: attachNodeAttributeRemover
-  }, {
-    name: function name(element) {
-      return "replace".concat(element, "Attributes");
-    },
-    attacher: attachNodeAttributesReplacer
-  }, {
-    name: function name(element) {
-      return "merge".concat(element, "Attributes");
-    },
-    attacher: attachNodeAttributesMerger
-  }, {
-    name: function name(element) {
-      return "update".concat(element, "Attributes");
-    },
-    attacher: attachNodeAttributesUpdater
-  }];
-  /**
-   * Attach every attributes-related methods to a Graph class.
-   *
-   * @param {function} Graph - Target class.
-   */
-
-  function attachNodeAttributesMethods(Graph) {
-    NODE_ATTRIBUTES_METHODS.forEach(function (_ref) {
-      var name = _ref.name,
-          attacher = _ref.attacher;
-      // For nodes
-      attacher(Graph, name('Node'), NODE); // For sources
-
-      attacher(Graph, name('Source'), SOURCE); // For targets
-
-      attacher(Graph, name('Target'), TARGET); // For opposites
-
-      attacher(Graph, name('Opposite'), OPPOSITE);
-    });
-  }
-
-  /**
-   * Graphology Edge Attributes methods
-   * ===================================
-   */
-  /**
-   * Attach an attribute getter method onto the provided class.
-   *
-   * @param {function} Class         - Target class.
-   * @param {string}   method        - Method name.
-   * @param {string}   type          - Type of the edge to find.
-   */
-
-  function attachEdgeAttributeGetter(Class, method, type) {
-    /**
-     * Get the desired attribute for the given element (node or edge).
-     *
-     * Arity 2:
-     * @param  {any}    element - Target element.
-     * @param  {string} name    - Attribute's name.
-     *
-     * Arity 3 (only for edges):
-     * @param  {any}     source - Source element.
-     * @param  {any}     target - Target element.
-     * @param  {string}  name   - Attribute's name.
-     *
-     * @return {mixed}          - The attribute's value.
-     *
-     * @throws {Error} - Will throw if too many arguments are provided.
-     * @throws {Error} - Will throw if any of the elements is not found.
-     */
-    Class.prototype[method] = function (element, name) {
-      var data;
-      if (this.type !== 'mixed' && type !== 'mixed' && type !== this.type) throw new UsageGraphError("Graph.".concat(method, ": cannot find this type of edges in your ").concat(this.type, " graph."));
-
-      if (arguments.length > 2) {
-        if (this.multi) throw new UsageGraphError("Graph.".concat(method, ": cannot use a {source,target} combo when asking about an edge's attributes in a MultiGraph since we cannot infer the one you want information about."));
-        var source = '' + element;
-        var target = '' + name;
-        name = arguments[2];
-        data = getMatchingEdge(this, source, target, type);
-        if (!data) throw new NotFoundGraphError("Graph.".concat(method, ": could not find an edge for the given path (\"").concat(source, "\" - \"").concat(target, "\")."));
-      } else {
-        if (type !== 'mixed') throw new UsageGraphError("Graph.".concat(method, ": calling this method with only a key (vs. a source and target) does not make sense since an edge with this key could have the other type."));
-        element = '' + element;
-        data = this._edges.get(element);
-        if (!data) throw new NotFoundGraphError("Graph.".concat(method, ": could not find the \"").concat(element, "\" edge in the graph."));
-      }
-
-      return data.attributes[name];
-    };
-  }
-  /**
-   * Attach an attributes getter method onto the provided class.
-   *
-   * @param {function} Class       - Target class.
-   * @param {string}   method      - Method name.
-   * @param {string}   type        - Type of the edge to find.
-   */
-
-
-  function attachEdgeAttributesGetter(Class, method, type) {
-    /**
-     * Retrieves all the target element's attributes.
-     *
-     * Arity 2:
-     * @param  {any}    element - Target element.
-     *
-     * Arity 3 (only for edges):
-     * @param  {any}     source - Source element.
-     * @param  {any}     target - Target element.
-     *
-     * @return {object}          - The element's attributes.
-     *
-     * @throws {Error} - Will throw if too many arguments are provided.
-     * @throws {Error} - Will throw if any of the elements is not found.
-     */
-    Class.prototype[method] = function (element) {
-      var data;
-      if (this.type !== 'mixed' && type !== 'mixed' && type !== this.type) throw new UsageGraphError("Graph.".concat(method, ": cannot find this type of edges in your ").concat(this.type, " graph."));
-
-      if (arguments.length > 1) {
-        if (this.multi) throw new UsageGraphError("Graph.".concat(method, ": cannot use a {source,target} combo when asking about an edge's attributes in a MultiGraph since we cannot infer the one you want information about."));
-        var source = '' + element,
-            target = '' + arguments[1];
-        data = getMatchingEdge(this, source, target, type);
-        if (!data) throw new NotFoundGraphError("Graph.".concat(method, ": could not find an edge for the given path (\"").concat(source, "\" - \"").concat(target, "\")."));
-      } else {
-        if (type !== 'mixed') throw new UsageGraphError("Graph.".concat(method, ": calling this method with only a key (vs. a source and target) does not make sense since an edge with this key could have the other type."));
-        element = '' + element;
-        data = this._edges.get(element);
-        if (!data) throw new NotFoundGraphError("Graph.".concat(method, ": could not find the \"").concat(element, "\" edge in the graph."));
-      }
-
-      return data.attributes;
-    };
-  }
-  /**
-   * Attach an attribute checker method onto the provided class.
-   *
-   * @param {function} Class       - Target class.
-   * @param {string}   method      - Method name.
-   * @param {string}   type        - Type of the edge to find.
-   */
-
-
-  function attachEdgeAttributeChecker(Class, method, type) {
-    /**
-     * Checks whether the desired attribute is set for the given element (node or edge).
-     *
-     * Arity 2:
-     * @param  {any}    element - Target element.
-     * @param  {string} name    - Attribute's name.
-     *
-     * Arity 3 (only for edges):
-     * @param  {any}     source - Source element.
-     * @param  {any}     target - Target element.
-     * @param  {string}  name   - Attribute's name.
-     *
-     * @return {boolean}
-     *
-     * @throws {Error} - Will throw if too many arguments are provided.
-     * @throws {Error} - Will throw if any of the elements is not found.
-     */
-    Class.prototype[method] = function (element, name) {
-      var data;
-      if (this.type !== 'mixed' && type !== 'mixed' && type !== this.type) throw new UsageGraphError("Graph.".concat(method, ": cannot find this type of edges in your ").concat(this.type, " graph."));
-
-      if (arguments.length > 2) {
-        if (this.multi) throw new UsageGraphError("Graph.".concat(method, ": cannot use a {source,target} combo when asking about an edge's attributes in a MultiGraph since we cannot infer the one you want information about."));
-        var source = '' + element;
-        var target = '' + name;
-        name = arguments[2];
-        data = getMatchingEdge(this, source, target, type);
-        if (!data) throw new NotFoundGraphError("Graph.".concat(method, ": could not find an edge for the given path (\"").concat(source, "\" - \"").concat(target, "\")."));
-      } else {
-        if (type !== 'mixed') throw new UsageGraphError("Graph.".concat(method, ": calling this method with only a key (vs. a source and target) does not make sense since an edge with this key could have the other type."));
-        element = '' + element;
-        data = this._edges.get(element);
-        if (!data) throw new NotFoundGraphError("Graph.".concat(method, ": could not find the \"").concat(element, "\" edge in the graph."));
-      }
-
-      return data.attributes.hasOwnProperty(name);
-    };
-  }
-  /**
-   * Attach an attribute setter method onto the provided class.
-   *
-   * @param {function} Class         - Target class.
-   * @param {string}   method        - Method name.
-   * @param {string}   type          - Type of the edge to find.
-   */
-
-
-  function attachEdgeAttributeSetter(Class, method, type) {
-    /**
-     * Set the desired attribute for the given element (node or edge).
-     *
-     * Arity 2:
-     * @param  {any}    element - Target element.
-     * @param  {string} name    - Attribute's name.
-     * @param  {mixed}  value   - New attribute value.
-     *
-     * Arity 3 (only for edges):
-     * @param  {any}     source - Source element.
-     * @param  {any}     target - Target element.
-     * @param  {string}  name   - Attribute's name.
-     * @param  {mixed}  value   - New attribute value.
-     *
-     * @return {Graph}          - Returns itself for chaining.
-     *
-     * @throws {Error} - Will throw if too many arguments are provided.
-     * @throws {Error} - Will throw if any of the elements is not found.
-     */
-    Class.prototype[method] = function (element, name, value) {
-      var data;
-      if (this.type !== 'mixed' && type !== 'mixed' && type !== this.type) throw new UsageGraphError("Graph.".concat(method, ": cannot find this type of edges in your ").concat(this.type, " graph."));
-
-      if (arguments.length > 3) {
-        if (this.multi) throw new UsageGraphError("Graph.".concat(method, ": cannot use a {source,target} combo when asking about an edge's attributes in a MultiGraph since we cannot infer the one you want information about."));
-        var source = '' + element;
-        var target = '' + name;
-        name = arguments[2];
-        value = arguments[3];
-        data = getMatchingEdge(this, source, target, type);
-        if (!data) throw new NotFoundGraphError("Graph.".concat(method, ": could not find an edge for the given path (\"").concat(source, "\" - \"").concat(target, "\")."));
-      } else {
-        if (type !== 'mixed') throw new UsageGraphError("Graph.".concat(method, ": calling this method with only a key (vs. a source and target) does not make sense since an edge with this key could have the other type."));
-        element = '' + element;
-        data = this._edges.get(element);
-        if (!data) throw new NotFoundGraphError("Graph.".concat(method, ": could not find the \"").concat(element, "\" edge in the graph."));
-      }
-
-      data.attributes[name] = value; // Emitting
-
-      this.emit('edgeAttributesUpdated', {
-        key: data.key,
-        type: 'set',
-        attributes: data.attributes,
-        name: name
-      });
-      return this;
-    };
-  }
-  /**
-   * Attach an attribute updater method onto the provided class.
-   *
-   * @param {function} Class         - Target class.
-   * @param {string}   method        - Method name.
-   * @param {string}   type          - Type of the edge to find.
-   */
-
-
-  function attachEdgeAttributeUpdater(Class, method, type) {
-    /**
-     * Update the desired attribute for the given element (node or edge) using
-     * the provided function.
-     *
-     * Arity 2:
-     * @param  {any}      element - Target element.
-     * @param  {string}   name    - Attribute's name.
-     * @param  {function} updater - Updater function.
-     *
-     * Arity 3 (only for edges):
-     * @param  {any}      source  - Source element.
-     * @param  {any}      target  - Target element.
-     * @param  {string}   name    - Attribute's name.
-     * @param  {function} updater - Updater function.
-     *
-     * @return {Graph}            - Returns itself for chaining.
-     *
-     * @throws {Error} - Will throw if too many arguments are provided.
-     * @throws {Error} - Will throw if any of the elements is not found.
-     */
-    Class.prototype[method] = function (element, name, updater) {
-      var data;
-      if (this.type !== 'mixed' && type !== 'mixed' && type !== this.type) throw new UsageGraphError("Graph.".concat(method, ": cannot find this type of edges in your ").concat(this.type, " graph."));
-
-      if (arguments.length > 3) {
-        if (this.multi) throw new UsageGraphError("Graph.".concat(method, ": cannot use a {source,target} combo when asking about an edge's attributes in a MultiGraph since we cannot infer the one you want information about."));
-        var source = '' + element;
-        var target = '' + name;
-        name = arguments[2];
-        updater = arguments[3];
-        data = getMatchingEdge(this, source, target, type);
-        if (!data) throw new NotFoundGraphError("Graph.".concat(method, ": could not find an edge for the given path (\"").concat(source, "\" - \"").concat(target, "\")."));
-      } else {
-        if (type !== 'mixed') throw new UsageGraphError("Graph.".concat(method, ": calling this method with only a key (vs. a source and target) does not make sense since an edge with this key could have the other type."));
-        element = '' + element;
-        data = this._edges.get(element);
-        if (!data) throw new NotFoundGraphError("Graph.".concat(method, ": could not find the \"").concat(element, "\" edge in the graph."));
-      }
-
-      if (typeof updater !== 'function') throw new InvalidArgumentsGraphError("Graph.".concat(method, ": updater should be a function."));
-      data.attributes[name] = updater(data.attributes[name]); // Emitting
-
-      this.emit('edgeAttributesUpdated', {
-        key: data.key,
-        type: 'set',
-        attributes: data.attributes,
-        name: name
-      });
-      return this;
-    };
-  }
-  /**
-   * Attach an attribute remover method onto the provided class.
-   *
-   * @param {function} Class         - Target class.
-   * @param {string}   method        - Method name.
-   * @param {string}   type          - Type of the edge to find.
-   */
-
-
-  function attachEdgeAttributeRemover(Class, method, type) {
-    /**
-     * Remove the desired attribute for the given element (node or edge).
-     *
-     * Arity 2:
-     * @param  {any}    element - Target element.
-     * @param  {string} name    - Attribute's name.
-     *
-     * Arity 3 (only for edges):
-     * @param  {any}     source - Source element.
-     * @param  {any}     target - Target element.
-     * @param  {string}  name   - Attribute's name.
-     *
-     * @return {Graph}          - Returns itself for chaining.
-     *
-     * @throws {Error} - Will throw if too many arguments are provided.
-     * @throws {Error} - Will throw if any of the elements is not found.
-     */
-    Class.prototype[method] = function (element, name) {
-      var data;
-      if (this.type !== 'mixed' && type !== 'mixed' && type !== this.type) throw new UsageGraphError("Graph.".concat(method, ": cannot find this type of edges in your ").concat(this.type, " graph."));
-
-      if (arguments.length > 2) {
-        if (this.multi) throw new UsageGraphError("Graph.".concat(method, ": cannot use a {source,target} combo when asking about an edge's attributes in a MultiGraph since we cannot infer the one you want information about."));
-        var source = '' + element;
-        var target = '' + name;
-        name = arguments[2];
-        data = getMatchingEdge(this, source, target, type);
-        if (!data) throw new NotFoundGraphError("Graph.".concat(method, ": could not find an edge for the given path (\"").concat(source, "\" - \"").concat(target, "\")."));
-      } else {
-        if (type !== 'mixed') throw new UsageGraphError("Graph.".concat(method, ": calling this method with only a key (vs. a source and target) does not make sense since an edge with this key could have the other type."));
-        element = '' + element;
-        data = this._edges.get(element);
-        if (!data) throw new NotFoundGraphError("Graph.".concat(method, ": could not find the \"").concat(element, "\" edge in the graph."));
-      }
-
-      delete data.attributes[name]; // Emitting
-
-      this.emit('edgeAttributesUpdated', {
-        key: data.key,
-        type: 'remove',
-        attributes: data.attributes,
-        name: name
-      });
-      return this;
-    };
-  }
-  /**
-   * Attach an attribute replacer method onto the provided class.
-   *
-   * @param {function} Class         - Target class.
-   * @param {string}   method        - Method name.
-   * @param {string}   type          - Type of the edge to find.
-   */
-
-
-  function attachEdgeAttributesReplacer(Class, method, type) {
-    /**
-     * Replace the attributes for the given element (node or edge).
-     *
-     * Arity 2:
-     * @param  {any}    element    - Target element.
-     * @param  {object} attributes - New attributes.
-     *
-     * Arity 3 (only for edges):
-     * @param  {any}     source     - Source element.
-     * @param  {any}     target     - Target element.
-     * @param  {object}  attributes - New attributes.
-     *
-     * @return {Graph}              - Returns itself for chaining.
-     *
-     * @throws {Error} - Will throw if too many arguments are provided.
-     * @throws {Error} - Will throw if any of the elements is not found.
-     */
-    Class.prototype[method] = function (element, attributes) {
-      var data;
-      if (this.type !== 'mixed' && type !== 'mixed' && type !== this.type) throw new UsageGraphError("Graph.".concat(method, ": cannot find this type of edges in your ").concat(this.type, " graph."));
-
-      if (arguments.length > 2) {
-        if (this.multi) throw new UsageGraphError("Graph.".concat(method, ": cannot use a {source,target} combo when asking about an edge's attributes in a MultiGraph since we cannot infer the one you want information about."));
-        var source = '' + element,
-            target = '' + attributes;
-        attributes = arguments[2];
-        data = getMatchingEdge(this, source, target, type);
-        if (!data) throw new NotFoundGraphError("Graph.".concat(method, ": could not find an edge for the given path (\"").concat(source, "\" - \"").concat(target, "\")."));
-      } else {
-        if (type !== 'mixed') throw new UsageGraphError("Graph.".concat(method, ": calling this method with only a key (vs. a source and target) does not make sense since an edge with this key could have the other type."));
-        element = '' + element;
-        data = this._edges.get(element);
-        if (!data) throw new NotFoundGraphError("Graph.".concat(method, ": could not find the \"").concat(element, "\" edge in the graph."));
-      }
-
-      if (!isPlainObject(attributes)) throw new InvalidArgumentsGraphError("Graph.".concat(method, ": provided attributes are not a plain object."));
-      data.attributes = attributes; // Emitting
-
-      this.emit('edgeAttributesUpdated', {
-        key: data.key,
-        type: 'replace',
-        attributes: data.attributes
-      });
-      return this;
-    };
-  }
-  /**
-   * Attach an attribute merger method onto the provided class.
-   *
-   * @param {function} Class         - Target class.
-   * @param {string}   method        - Method name.
-   * @param {string}   type          - Type of the edge to find.
-   */
-
-
-  function attachEdgeAttributesMerger(Class, method, type) {
-    /**
-     * Merge the attributes for the given element (node or edge).
-     *
-     * Arity 2:
-     * @param  {any}    element    - Target element.
-     * @param  {object} attributes - Attributes to merge.
-     *
-     * Arity 3 (only for edges):
-     * @param  {any}     source     - Source element.
-     * @param  {any}     target     - Target element.
-     * @param  {object}  attributes - Attributes to merge.
-     *
-     * @return {Graph}              - Returns itself for chaining.
-     *
-     * @throws {Error} - Will throw if too many arguments are provided.
-     * @throws {Error} - Will throw if any of the elements is not found.
-     */
-    Class.prototype[method] = function (element, attributes) {
-      var data;
-      if (this.type !== 'mixed' && type !== 'mixed' && type !== this.type) throw new UsageGraphError("Graph.".concat(method, ": cannot find this type of edges in your ").concat(this.type, " graph."));
-
-      if (arguments.length > 2) {
-        if (this.multi) throw new UsageGraphError("Graph.".concat(method, ": cannot use a {source,target} combo when asking about an edge's attributes in a MultiGraph since we cannot infer the one you want information about."));
-        var source = '' + element,
-            target = '' + attributes;
-        attributes = arguments[2];
-        data = getMatchingEdge(this, source, target, type);
-        if (!data) throw new NotFoundGraphError("Graph.".concat(method, ": could not find an edge for the given path (\"").concat(source, "\" - \"").concat(target, "\")."));
-      } else {
-        if (type !== 'mixed') throw new UsageGraphError("Graph.".concat(method, ": calling this method with only a key (vs. a source and target) does not make sense since an edge with this key could have the other type."));
-        element = '' + element;
-        data = this._edges.get(element);
-        if (!data) throw new NotFoundGraphError("Graph.".concat(method, ": could not find the \"").concat(element, "\" edge in the graph."));
-      }
-
-      if (!isPlainObject(attributes)) throw new InvalidArgumentsGraphError("Graph.".concat(method, ": provided attributes are not a plain object."));
-      assign(data.attributes, attributes); // Emitting
-
-      this.emit('edgeAttributesUpdated', {
-        key: data.key,
-        type: 'merge',
-        attributes: data.attributes,
-        data: attributes
-      });
-      return this;
-    };
-  }
-  /**
-   * Attach an attribute updater method onto the provided class.
-   *
-   * @param {function} Class         - Target class.
-   * @param {string}   method        - Method name.
-   * @param {string}   type          - Type of the edge to find.
-   */
-
-
-  function attachEdgeAttributesUpdater(Class, method, type) {
-    /**
-     * Update the attributes of the given element (node or edge).
-     *
-     * Arity 2:
-     * @param  {any}      element - Target element.
-     * @param  {function} updater - Updater function.
-     *
-     * Arity 3 (only for edges):
-     * @param  {any}      source  - Source element.
-     * @param  {any}      target  - Target element.
-     * @param  {function} updater - Updater function.
-     *
-     * @return {Graph}            - Returns itself for chaining.
-     *
-     * @throws {Error} - Will throw if too many arguments are provided.
-     * @throws {Error} - Will throw if any of the elements is not found.
-     */
-    Class.prototype[method] = function (element, updater) {
-      var data;
-      if (this.type !== 'mixed' && type !== 'mixed' && type !== this.type) throw new UsageGraphError("Graph.".concat(method, ": cannot find this type of edges in your ").concat(this.type, " graph."));
-
-      if (arguments.length > 2) {
-        if (this.multi) throw new UsageGraphError("Graph.".concat(method, ": cannot use a {source,target} combo when asking about an edge's attributes in a MultiGraph since we cannot infer the one you want information about."));
-        var source = '' + element,
-            target = '' + updater;
-        updater = arguments[2];
-        data = getMatchingEdge(this, source, target, type);
-        if (!data) throw new NotFoundGraphError("Graph.".concat(method, ": could not find an edge for the given path (\"").concat(source, "\" - \"").concat(target, "\")."));
-      } else {
-        if (type !== 'mixed') throw new UsageGraphError("Graph.".concat(method, ": calling this method with only a key (vs. a source and target) does not make sense since an edge with this key could have the other type."));
-        element = '' + element;
-        data = this._edges.get(element);
-        if (!data) throw new NotFoundGraphError("Graph.".concat(method, ": could not find the \"").concat(element, "\" edge in the graph."));
-      }
-
-      if (typeof updater !== 'function') throw new InvalidArgumentsGraphError("Graph.".concat(method, ": provided updater is not a function."));
-      data.attributes = updater(data.attributes); // Emitting
-
-      this.emit('edgeAttributesUpdated', {
-        key: data.key,
-        type: 'update',
-        attributes: data.attributes
-      });
-      return this;
-    };
-  }
-  /**
-   * List of methods to attach.
-   */
-
-
-  var EDGE_ATTRIBUTES_METHODS = [{
-    name: function name(element) {
-      return "get".concat(element, "Attribute");
-    },
-    attacher: attachEdgeAttributeGetter
-  }, {
-    name: function name(element) {
-      return "get".concat(element, "Attributes");
-    },
-    attacher: attachEdgeAttributesGetter
-  }, {
-    name: function name(element) {
-      return "has".concat(element, "Attribute");
-    },
-    attacher: attachEdgeAttributeChecker
-  }, {
-    name: function name(element) {
-      return "set".concat(element, "Attribute");
-    },
-    attacher: attachEdgeAttributeSetter
-  }, {
-    name: function name(element) {
-      return "update".concat(element, "Attribute");
-    },
-    attacher: attachEdgeAttributeUpdater
-  }, {
-    name: function name(element) {
-      return "remove".concat(element, "Attribute");
-    },
-    attacher: attachEdgeAttributeRemover
-  }, {
-    name: function name(element) {
-      return "replace".concat(element, "Attributes");
-    },
-    attacher: attachEdgeAttributesReplacer
-  }, {
-    name: function name(element) {
-      return "merge".concat(element, "Attributes");
-    },
-    attacher: attachEdgeAttributesMerger
-  }, {
-    name: function name(element) {
-      return "update".concat(element, "Attributes");
-    },
-    attacher: attachEdgeAttributesUpdater
-  }];
-  /**
-   * Attach every attributes-related methods to a Graph class.
-   *
-   * @param {function} Graph - Target class.
-   */
-
-  function attachEdgeAttributesMethods(Graph) {
-    EDGE_ATTRIBUTES_METHODS.forEach(function (_ref) {
-      var name = _ref.name,
-          attacher = _ref.attacher;
-      // For edges
-      attacher(Graph, name('Edge'), 'mixed'); // For directed edges
-
-      attacher(Graph, name('DirectedEdge'), 'directed'); // For undirected edges
-
-      attacher(Graph, name('UndirectedEdge'), 'undirected');
-    });
-  }
-
-  /**
-   * Obliterator Chain Function
-   * ===========================
-   *
-   * Variadic function combining the given iterables.
-   */
-  var Iterator = iterator;
-  var iter = iter$2;
-  /**
-   * Chain.
-   *
-   * @param  {...Iterator} iterables - Target iterables.
-   * @return {Iterator}
-   */
-
-  var chain = function chain() {
-    var iterables = arguments;
-    var current = null;
-    var i = -1;
-    /* eslint-disable no-constant-condition */
-
-    return new Iterator(function next() {
-      var step = null;
-
-      do {
-        if (current === null) {
-          i++;
-          if (i >= iterables.length) return {
-            done: true
-          };
-          current = iter(iterables[i]);
-        }
-
-        step = current.next();
-
-        if (step.done === true) {
-          current = null;
-          continue;
-        }
-
-        break;
-      } while (true);
-
-      return step;
-    });
-  };
-
-  /**
-   * Graphology Edge Iteration
-   * ==========================
-   *
-   * Attaching some methods to the Graph class to be able to iterate over a
-   * graph's edges.
-   */
-  /**
-   * Definitions.
-   */
-
-  var EDGES_ITERATION = [{
-    name: 'edges',
-    type: 'mixed'
-  }, {
-    name: 'inEdges',
-    type: 'directed',
-    direction: 'in'
-  }, {
-    name: 'outEdges',
-    type: 'directed',
-    direction: 'out'
-  }, {
-    name: 'inboundEdges',
-    type: 'mixed',
-    direction: 'in'
-  }, {
-    name: 'outboundEdges',
-    type: 'mixed',
-    direction: 'out'
-  }, {
-    name: 'directedEdges',
-    type: 'directed'
-  }, {
-    name: 'undirectedEdges',
-    type: 'undirected'
-  }];
-  /**
-   * Function iterating over edges from the given object to match one of them.
-   *
-   * @param {object}   object   - Target object.
-   * @param {function} callback - Function to call.
-   */
-
-  function forEachSimple(breakable, object, callback, avoid) {
-    var shouldBreak = false;
-
-    for (var k in object) {
-      if (k === avoid) continue;
-      var edgeData = object[k];
-      shouldBreak = callback(edgeData.key, edgeData.attributes, edgeData.source.key, edgeData.target.key, edgeData.source.attributes, edgeData.target.attributes, edgeData.undirected);
-      if (breakable && shouldBreak) return edgeData.key;
-    }
-
-    return;
-  }
-
-  function forEachMulti(breakable, object, callback, avoid) {
-    var edgeData, source, target;
-    var shouldBreak = false;
-
-    for (var k in object) {
-      if (k === avoid) continue;
-      edgeData = object[k];
-
-      do {
-        source = edgeData.source;
-        target = edgeData.target;
-        shouldBreak = callback(edgeData.key, edgeData.attributes, source.key, target.key, source.attributes, target.attributes, edgeData.undirected);
-        if (breakable && shouldBreak) return edgeData.key;
-        edgeData = edgeData.next;
-      } while (edgeData !== undefined);
-    }
-
-    return;
-  }
-  /**
-   * Function returning an iterator over edges from the given object.
-   *
-   * @param  {object}   object - Target object.
-   * @return {Iterator}
-   */
-
-
-  function createIterator(object, avoid) {
-    var keys = Object.keys(object);
-    var l = keys.length;
-    var edgeData;
-    var i = 0;
-    return new iterator(function next() {
-      do {
-        if (!edgeData) {
-          if (i >= l) return {
-            done: true
-          };
-          var k = keys[i++];
-
-          if (k === avoid) {
-            edgeData = undefined;
-            continue;
-          }
-
-          edgeData = object[k];
-        } else {
-          edgeData = edgeData.next;
-        }
-      } while (!edgeData);
-
-      return {
-        done: false,
-        value: {
-          edge: edgeData.key,
-          attributes: edgeData.attributes,
-          source: edgeData.source.key,
-          target: edgeData.target.key,
-          sourceAttributes: edgeData.source.attributes,
-          targetAttributes: edgeData.target.attributes,
-          undirected: edgeData.undirected
-        }
-      };
-    });
-  }
-  /**
-   * Function iterating over the egdes from the object at given key to match
-   * one of them.
-   *
-   * @param {object}   object   - Target object.
-   * @param {mixed}    k        - Neighbor key.
-   * @param {function} callback - Callback to use.
-   */
-
-
-  function forEachForKeySimple(breakable, object, k, callback) {
-    var edgeData = object[k];
-    if (!edgeData) return;
-    var sourceData = edgeData.source;
-    var targetData = edgeData.target;
-    if (callback(edgeData.key, edgeData.attributes, sourceData.key, targetData.key, sourceData.attributes, targetData.attributes, edgeData.undirected) && breakable) return edgeData.key;
-  }
-
-  function forEachForKeyMulti(breakable, object, k, callback) {
-    var edgeData = object[k];
-    if (!edgeData) return;
-    var shouldBreak = false;
-
-    do {
-      shouldBreak = callback(edgeData.key, edgeData.attributes, edgeData.source.key, edgeData.target.key, edgeData.source.attributes, edgeData.target.attributes, edgeData.undirected);
-      if (breakable && shouldBreak) return edgeData.key;
-      edgeData = edgeData.next;
-    } while (edgeData !== undefined);
-
-    return;
-  }
-  /**
-   * Function returning an iterator over the egdes from the object at given key.
-   *
-   * @param  {object}   object   - Target object.
-   * @param  {mixed}    k        - Neighbor key.
-   * @return {Iterator}
-   */
-
-
-  function createIteratorForKey(object, k) {
-    var edgeData = object[k];
-
-    if (edgeData.next !== undefined) {
-      return new iterator(function () {
-        if (!edgeData) return {
-          done: true
-        };
-        var value = {
-          edge: edgeData.key,
-          attributes: edgeData.attributes,
-          source: edgeData.source.key,
-          target: edgeData.target.key,
-          sourceAttributes: edgeData.source.attributes,
-          targetAttributes: edgeData.target.attributes,
-          undirected: edgeData.undirected
-        };
-        edgeData = edgeData.next;
-        return {
-          done: false,
-          value: value
-        };
-      });
-    }
-
-    return iterator.of({
-      edge: edgeData.key,
-      attributes: edgeData.attributes,
-      source: edgeData.source.key,
-      target: edgeData.target.key,
-      sourceAttributes: edgeData.source.attributes,
-      targetAttributes: edgeData.target.attributes,
-      undirected: edgeData.undirected
-    });
-  }
-  /**
-   * Function creating an array of edges for the given type.
-   *
-   * @param  {Graph}   graph - Target Graph instance.
-   * @param  {string}  type  - Type of edges to retrieve.
-   * @return {array}         - Array of edges.
-   */
-
-
-  function createEdgeArray(graph, type) {
-    if (graph.size === 0) return [];
-
-    if (type === 'mixed' || type === graph.type) {
-      if (typeof Array.from === 'function') return Array.from(graph._edges.keys());
-      return take(graph._edges.keys(), graph._edges.size);
-    }
-
-    var size = type === 'undirected' ? graph.undirectedSize : graph.directedSize;
-    var list = new Array(size),
-        mask = type === 'undirected';
-
-    var iterator = graph._edges.values();
-
-    var i = 0;
-    var step, data;
-
-    while (step = iterator.next(), step.done !== true) {
-      data = step.value;
-      if (data.undirected === mask) list[i++] = data.key;
-    }
-
-    return list;
-  }
-  /**
-   * Function iterating over a graph's edges using a callback to match one of
-   * them.
-   *
-   * @param  {Graph}    graph    - Target Graph instance.
-   * @param  {string}   type     - Type of edges to retrieve.
-   * @param  {function} callback - Function to call.
-   */
-
-
-  function forEachEdge(breakable, graph, type, callback) {
-    if (graph.size === 0) return;
-    var shouldFilter = type !== 'mixed' && type !== graph.type;
-    var mask = type === 'undirected';
-    var step, data;
-    var shouldBreak = false;
-
-    var iterator = graph._edges.values();
-
-    while (step = iterator.next(), step.done !== true) {
-      data = step.value;
-      if (shouldFilter && data.undirected !== mask) continue;
-      var _data = data,
-          key = _data.key,
-          attributes = _data.attributes,
-          source = _data.source,
-          target = _data.target;
-      shouldBreak = callback(key, attributes, source.key, target.key, source.attributes, target.attributes, data.undirected);
-      if (breakable && shouldBreak) return key;
-    }
-
-    return;
-  }
-  /**
-   * Function creating an iterator of edges for the given type.
-   *
-   * @param  {Graph}    graph - Target Graph instance.
-   * @param  {string}   type  - Type of edges to retrieve.
-   * @return {Iterator}
-   */
-
-
-  function createEdgeIterator(graph, type) {
-    if (graph.size === 0) return iterator.empty();
-    var shouldFilter = type !== 'mixed' && type !== graph.type;
-    var mask = type === 'undirected';
-
-    var iterator$1 = graph._edges.values();
-
-    return new iterator(function next() {
-      var step, data; // eslint-disable-next-line no-constant-condition
-
-      while (true) {
-        step = iterator$1.next();
-        if (step.done) return step;
-        data = step.value;
-        if (shouldFilter && data.undirected !== mask) continue;
-        break;
-      }
-
-      var value = {
-        edge: data.key,
-        attributes: data.attributes,
-        source: data.source.key,
-        target: data.target.key,
-        sourceAttributes: data.source.attributes,
-        targetAttributes: data.target.attributes,
-        undirected: data.undirected
-      };
-      return {
-        value: value,
-        done: false
-      };
-    });
-  }
-  /**
-   * Function iterating over a node's edges using a callback to match one of them.
-   *
-   * @param  {boolean}  multi     - Whether the graph is multi or not.
-   * @param  {string}   type      - Type of edges to retrieve.
-   * @param  {string}   direction - In or out?
-   * @param  {any}      nodeData  - Target node's data.
-   * @param  {function} callback  - Function to call.
-   */
-
-
-  function forEachEdgeForNode(breakable, multi, type, direction, nodeData, callback) {
-    var fn = multi ? forEachMulti : forEachSimple;
-    var found;
-
-    if (type !== 'undirected') {
-      if (direction !== 'out') {
-        found = fn(breakable, nodeData["in"], callback);
-        if (breakable && found) return found;
-      }
-
-      if (direction !== 'in') {
-        found = fn(breakable, nodeData.out, callback, !direction ? nodeData.key : undefined);
-        if (breakable && found) return found;
-      }
-    }
-
-    if (type !== 'directed') {
-      found = fn(breakable, nodeData.undirected, callback);
-      if (breakable && found) return found;
-    }
-
-    return;
-  }
-  /**
-   * Function creating an array of edges for the given type & the given node.
-   *
-   * @param  {boolean} multi     - Whether the graph is multi or not.
-   * @param  {string}  type      - Type of edges to retrieve.
-   * @param  {string}  direction - In or out?
-   * @param  {any}     nodeData  - Target node's data.
-   * @return {array}             - Array of edges.
-   */
-
-
-  function createEdgeArrayForNode(multi, type, direction, nodeData) {
-    var edges = []; // TODO: possibility to know size beforehand or factorize with map
-
-    forEachEdgeForNode(false, multi, type, direction, nodeData, function (key) {
-      edges.push(key);
-    });
-    return edges;
-  }
-  /**
-   * Function iterating over a node's edges using a callback.
-   *
-   * @param  {string}   type      - Type of edges to retrieve.
-   * @param  {string}   direction - In or out?
-   * @param  {any}      nodeData  - Target node's data.
-   * @return {Iterator}
-   */
-
-
-  function createEdgeIteratorForNode(type, direction, nodeData) {
-    var iterator$1 = iterator.empty();
-
-    if (type !== 'undirected') {
-      if (direction !== 'out' && typeof nodeData["in"] !== 'undefined') iterator$1 = chain(iterator$1, createIterator(nodeData["in"]));
-      if (direction !== 'in' && typeof nodeData.out !== 'undefined') iterator$1 = chain(iterator$1, createIterator(nodeData.out, !direction ? nodeData.key : undefined));
-    }
-
-    if (type !== 'directed' && typeof nodeData.undirected !== 'undefined') {
-      iterator$1 = chain(iterator$1, createIterator(nodeData.undirected));
-    }
-
-    return iterator$1;
-  }
-  /**
-   * Function iterating over edges for the given path using a callback to match
-   * one of them.
-   *
-   * @param  {string}   type       - Type of edges to retrieve.
-   * @param  {boolean}  multi      - Whether the graph is multi.
-   * @param  {string}   direction  - In or out?
-   * @param  {NodeData} sourceData - Source node's data.
-   * @param  {string}   target     - Target node.
-   * @param  {function} callback   - Function to call.
-   */
-
-
-  function forEachEdgeForPath(breakable, type, multi, direction, sourceData, target, callback) {
-    var fn = multi ? forEachForKeyMulti : forEachForKeySimple;
-    var found;
-
-    if (type !== 'undirected') {
-      if (typeof sourceData["in"] !== 'undefined' && direction !== 'out') {
-        found = fn(breakable, sourceData["in"], target, callback);
-        if (breakable && found) return found;
-      }
-
-      if (typeof sourceData.out !== 'undefined' && direction !== 'in' && (direction || sourceData.key !== target)) {
-        found = fn(breakable, sourceData.out, target, callback);
-        if (breakable && found) return found;
-      }
-    }
-
-    if (type !== 'directed') {
-      if (typeof sourceData.undirected !== 'undefined') {
-        found = fn(breakable, sourceData.undirected, target, callback);
-        if (breakable && found) return found;
-      }
-    }
-
-    return;
-  }
-  /**
-   * Function creating an array of edges for the given path.
-   *
-   * @param  {string}   type       - Type of edges to retrieve.
-   * @param  {boolean}  multi      - Whether the graph is multi.
-   * @param  {string}   direction  - In or out?
-   * @param  {NodeData} sourceData - Source node's data.
-   * @param  {any}      target     - Target node.
-   * @return {array}               - Array of edges.
-   */
-
-
-  function createEdgeArrayForPath(type, multi, direction, sourceData, target) {
-    var edges = []; // TODO: possibility to know size beforehand or factorize with map
-
-    forEachEdgeForPath(false, type, multi, direction, sourceData, target, function (key) {
-      edges.push(key);
-    });
-    return edges;
-  }
-  /**
-   * Function returning an iterator over edges for the given path.
-   *
-   * @param  {string}   type       - Type of edges to retrieve.
-   * @param  {string}   direction  - In or out?
-   * @param  {NodeData} sourceData - Source node's data.
-   * @param  {string}   target     - Target node.
-   * @param  {function} callback   - Function to call.
-   */
-
-
-  function createEdgeIteratorForPath(type, direction, sourceData, target) {
-    var iterator$1 = iterator.empty();
-
-    if (type !== 'undirected') {
-      if (typeof sourceData["in"] !== 'undefined' && direction !== 'out' && target in sourceData["in"]) iterator$1 = chain(iterator$1, createIteratorForKey(sourceData["in"], target));
-      if (typeof sourceData.out !== 'undefined' && direction !== 'in' && target in sourceData.out && (direction || sourceData.key !== target)) iterator$1 = chain(iterator$1, createIteratorForKey(sourceData.out, target));
-    }
-
-    if (type !== 'directed') {
-      if (typeof sourceData.undirected !== 'undefined' && target in sourceData.undirected) iterator$1 = chain(iterator$1, createIteratorForKey(sourceData.undirected, target));
-    }
-
-    return iterator$1;
-  }
-  /**
-   * Function attaching an edge array creator method to the Graph prototype.
-   *
-   * @param {function} Class       - Target class.
-   * @param {object}   description - Method description.
-   */
-
-
-  function attachEdgeArrayCreator(Class, description) {
-    var name = description.name,
-        type = description.type,
-        direction = description.direction;
-    /**
-     * Function returning an array of certain edges.
-     *
-     * Arity 0: Return all the relevant edges.
-     *
-     * Arity 1: Return all of a node's relevant edges.
-     * @param  {any}   node   - Target node.
-     *
-     * Arity 2: Return the relevant edges across the given path.
-     * @param  {any}   source - Source node.
-     * @param  {any}   target - Target node.
-     *
-     * @return {array|number} - The edges or the number of edges.
-     *
-     * @throws {Error} - Will throw if there are too many arguments.
-     */
-
-    Class.prototype[name] = function (source, target) {
-      // Early termination
-      if (type !== 'mixed' && this.type !== 'mixed' && type !== this.type) return [];
-      if (!arguments.length) return createEdgeArray(this, type);
-
-      if (arguments.length === 1) {
-        source = '' + source;
-
-        var nodeData = this._nodes.get(source);
-
-        if (typeof nodeData === 'undefined') throw new NotFoundGraphError("Graph.".concat(name, ": could not find the \"").concat(source, "\" node in the graph.")); // Iterating over a node's edges
-
-        return createEdgeArrayForNode(this.multi, type === 'mixed' ? this.type : type, direction, nodeData);
-      }
-
-      if (arguments.length === 2) {
-        source = '' + source;
-        target = '' + target;
-
-        var sourceData = this._nodes.get(source);
-
-        if (!sourceData) throw new NotFoundGraphError("Graph.".concat(name, ":  could not find the \"").concat(source, "\" source node in the graph."));
-        if (!this._nodes.has(target)) throw new NotFoundGraphError("Graph.".concat(name, ":  could not find the \"").concat(target, "\" target node in the graph.")); // Iterating over the edges between source & target
-
-        return createEdgeArrayForPath(type, this.multi, direction, sourceData, target);
-      }
-
-      throw new InvalidArgumentsGraphError("Graph.".concat(name, ": too many arguments (expecting 0, 1 or 2 and got ").concat(arguments.length, ")."));
-    };
-  }
-  /**
-   * Function attaching a edge callback iterator method to the Graph prototype.
-   *
-   * @param {function} Class       - Target class.
-   * @param {object}   description - Method description.
-   */
-
-
-  function attachForEachEdge(Class, description) {
-    var name = description.name,
-        type = description.type,
-        direction = description.direction;
-    var forEachName = 'forEach' + name[0].toUpperCase() + name.slice(1, -1);
-    /**
-     * Function iterating over the graph's relevant edges by applying the given
-     * callback.
-     *
-     * Arity 1: Iterate over all the relevant edges.
-     * @param  {function} callback - Callback to use.
-     *
-     * Arity 2: Iterate over all of a node's relevant edges.
-     * @param  {any}      node     - Target node.
-     * @param  {function} callback - Callback to use.
-     *
-     * Arity 3: Iterate over the relevant edges across the given path.
-     * @param  {any}      source   - Source node.
-     * @param  {any}      target   - Target node.
-     * @param  {function} callback - Callback to use.
-     *
-     * @return {undefined}
-     *
-     * @throws {Error} - Will throw if there are too many arguments.
-     */
-
-    Class.prototype[forEachName] = function (source, target, callback) {
-      // Early termination
-      if (type !== 'mixed' && this.type !== 'mixed' && type !== this.type) return;
-
-      if (arguments.length === 1) {
-        callback = source;
-        return forEachEdge(false, this, type, callback);
-      }
-
-      if (arguments.length === 2) {
-        source = '' + source;
-        callback = target;
-
-        var nodeData = this._nodes.get(source);
-
-        if (typeof nodeData === 'undefined') throw new NotFoundGraphError("Graph.".concat(forEachName, ": could not find the \"").concat(source, "\" node in the graph.")); // Iterating over a node's edges
-        // TODO: maybe attach the sub method to the instance dynamically?
-
-        return forEachEdgeForNode(false, this.multi, type === 'mixed' ? this.type : type, direction, nodeData, callback);
-      }
-
-      if (arguments.length === 3) {
-        source = '' + source;
-        target = '' + target;
-
-        var sourceData = this._nodes.get(source);
-
-        if (!sourceData) throw new NotFoundGraphError("Graph.".concat(forEachName, ":  could not find the \"").concat(source, "\" source node in the graph."));
-        if (!this._nodes.has(target)) throw new NotFoundGraphError("Graph.".concat(forEachName, ":  could not find the \"").concat(target, "\" target node in the graph.")); // Iterating over the edges between source & target
-
-        return forEachEdgeForPath(false, type, this.multi, direction, sourceData, target, callback);
-      }
-
-      throw new InvalidArgumentsGraphError("Graph.".concat(forEachName, ": too many arguments (expecting 1, 2 or 3 and got ").concat(arguments.length, ")."));
-    };
-    /**
-     * Function mapping the graph's relevant edges by applying the given
-     * callback.
-     *
-     * Arity 1: Map all the relevant edges.
-     * @param  {function} callback - Callback to use.
-     *
-     * Arity 2: Map all of a node's relevant edges.
-     * @param  {any}      node     - Target node.
-     * @param  {function} callback - Callback to use.
-     *
-     * Arity 3: Map the relevant edges across the given path.
-     * @param  {any}      source   - Source node.
-     * @param  {any}      target   - Target node.
-     * @param  {function} callback - Callback to use.
-     *
-     * @return {undefined}
-     *
-     * @throws {Error} - Will throw if there are too many arguments.
-     */
-
-
-    var mapName = 'map' + name[0].toUpperCase() + name.slice(1);
-
-    Class.prototype[mapName] = function () {
-      var args = Array.prototype.slice.call(arguments);
-      var callback = args.pop();
-      var result; // We know the result length beforehand
-
-      if (args.length === 0) {
-        var length = 0;
-        if (type !== 'directed') length += this.undirectedSize;
-        if (type !== 'undirected') length += this.directedSize;
-        result = new Array(length);
-        var i = 0;
-        args.push(function (e, ea, s, t, sa, ta, u) {
-          result[i++] = callback(e, ea, s, t, sa, ta, u);
-        });
-      } // We don't know the result length beforehand
-      // TODO: we can in some instances of simple graphs, knowing degree
-      else {
-        result = [];
-        args.push(function (e, ea, s, t, sa, ta, u) {
-          result.push(callback(e, ea, s, t, sa, ta, u));
-        });
-      }
-
-      this[forEachName].apply(this, args);
-      return result;
-    };
-    /**
-     * Function filtering the graph's relevant edges using the provided predicate
-     * function.
-     *
-     * Arity 1: Filter all the relevant edges.
-     * @param  {function} predicate - Predicate to use.
-     *
-     * Arity 2: Filter all of a node's relevant edges.
-     * @param  {any}      node      - Target node.
-     * @param  {function} predicate - Predicate to use.
-     *
-     * Arity 3: Filter the relevant edges across the given path.
-     * @param  {any}      source    - Source node.
-     * @param  {any}      target    - Target node.
-     * @param  {function} predicate - Predicate to use.
-     *
-     * @return {undefined}
-     *
-     * @throws {Error} - Will throw if there are too many arguments.
-     */
-
-
-    var filterName = 'filter' + name[0].toUpperCase() + name.slice(1);
-
-    Class.prototype[filterName] = function () {
-      var args = Array.prototype.slice.call(arguments);
-      var callback = args.pop();
-      var result = [];
-      args.push(function (e, ea, s, t, sa, ta, u) {
-        if (callback(e, ea, s, t, sa, ta, u)) result.push(e);
-      });
-      this[forEachName].apply(this, args);
-      return result;
-    };
-    /**
-     * Function reducing the graph's relevant edges using the provided accumulator
-     * function.
-     *
-     * Arity 1: Reduce all the relevant edges.
-     * @param  {function} accumulator  - Accumulator to use.
-     * @param  {any}      initialValue - Initial value.
-     *
-     * Arity 2: Reduce all of a node's relevant edges.
-     * @param  {any}      node         - Target node.
-     * @param  {function} accumulator  - Accumulator to use.
-     * @param  {any}      initialValue - Initial value.
-     *
-     * Arity 3: Reduce the relevant edges across the given path.
-     * @param  {any}      source       - Source node.
-     * @param  {any}      target       - Target node.
-     * @param  {function} accumulator  - Accumulator to use.
-     * @param  {any}      initialValue - Initial value.
-     *
-     * @return {undefined}
-     *
-     * @throws {Error} - Will throw if there are too many arguments.
-     */
-
-
-    var reduceName = 'reduce' + name[0].toUpperCase() + name.slice(1);
-
-    Class.prototype[reduceName] = function () {
-      var args = Array.prototype.slice.call(arguments);
-
-      if (args.length < 2 || args.length > 4) {
-        throw new InvalidArgumentsGraphError("Graph.".concat(reduceName, ": invalid number of arguments (expecting 2, 3 or 4 and got ").concat(args.length, ")."));
-      }
-
-      if (typeof args[args.length - 1] === 'function' && typeof args[args.length - 2] !== 'function') {
-        throw new InvalidArgumentsGraphError("Graph.".concat(reduceName, ": missing initial value. You must provide it because the callback takes more than one argument and we cannot infer the initial value from the first iteration, as you could with a simple array."));
-      }
-
-      var callback;
-      var initialValue;
-
-      if (args.length === 2) {
-        callback = args[0];
-        initialValue = args[1];
-        args = [];
-      } else if (args.length === 3) {
-        callback = args[1];
-        initialValue = args[2];
-        args = [args[0]];
-      } else if (args.length === 4) {
-        callback = args[2];
-        initialValue = args[3];
-        args = [args[0], args[1]];
-      }
-
-      var accumulator = initialValue;
-      args.push(function (e, ea, s, t, sa, ta, u) {
-        accumulator = callback(accumulator, e, ea, s, t, sa, ta, u);
-      });
-      this[forEachName].apply(this, args);
-      return accumulator;
-    };
-  }
-  /**
-   * Function attaching a breakable edge callback iterator method to the Graph
-   * prototype.
-   *
-   * @param {function} Class       - Target class.
-   * @param {object}   description - Method description.
-   */
-
-
-  function attachFindEdge(Class, description) {
-    var name = description.name,
-        type = description.type,
-        direction = description.direction;
-    var findEdgeName = 'find' + name[0].toUpperCase() + name.slice(1, -1);
-    /**
-     * Function iterating over the graph's relevant edges in order to match
-     * one of them using the provided predicate function.
-     *
-     * Arity 1: Iterate over all the relevant edges.
-     * @param  {function} callback - Callback to use.
-     *
-     * Arity 2: Iterate over all of a node's relevant edges.
-     * @param  {any}      node     - Target node.
-     * @param  {function} callback - Callback to use.
-     *
-     * Arity 3: Iterate over the relevant edges across the given path.
-     * @param  {any}      source   - Source node.
-     * @param  {any}      target   - Target node.
-     * @param  {function} callback - Callback to use.
-     *
-     * @return {undefined}
-     *
-     * @throws {Error} - Will throw if there are too many arguments.
-     */
-
-    Class.prototype[findEdgeName] = function (source, target, callback) {
-      // Early termination
-      if (type !== 'mixed' && this.type !== 'mixed' && type !== this.type) return false;
-
-      if (arguments.length === 1) {
-        callback = source;
-        return forEachEdge(true, this, type, callback);
-      }
-
-      if (arguments.length === 2) {
-        source = '' + source;
-        callback = target;
-
-        var nodeData = this._nodes.get(source);
-
-        if (typeof nodeData === 'undefined') throw new NotFoundGraphError("Graph.".concat(findEdgeName, ": could not find the \"").concat(source, "\" node in the graph.")); // Iterating over a node's edges
-        // TODO: maybe attach the sub method to the instance dynamically?
-
-        return forEachEdgeForNode(true, this.multi, type === 'mixed' ? this.type : type, direction, nodeData, callback);
-      }
-
-      if (arguments.length === 3) {
-        source = '' + source;
-        target = '' + target;
-
-        var sourceData = this._nodes.get(source);
-
-        if (!sourceData) throw new NotFoundGraphError("Graph.".concat(findEdgeName, ":  could not find the \"").concat(source, "\" source node in the graph."));
-        if (!this._nodes.has(target)) throw new NotFoundGraphError("Graph.".concat(findEdgeName, ":  could not find the \"").concat(target, "\" target node in the graph.")); // Iterating over the edges between source & target
-
-        return forEachEdgeForPath(true, type, this.multi, direction, sourceData, target, callback);
-      }
-
-      throw new InvalidArgumentsGraphError("Graph.".concat(findEdgeName, ": too many arguments (expecting 1, 2 or 3 and got ").concat(arguments.length, ")."));
-    };
-    /**
-     * Function iterating over the graph's relevant edges in order to assert
-     * whether any one of them matches the provided predicate function.
-     *
-     * Arity 1: Iterate over all the relevant edges.
-     * @param  {function} callback - Callback to use.
-     *
-     * Arity 2: Iterate over all of a node's relevant edges.
-     * @param  {any}      node     - Target node.
-     * @param  {function} callback - Callback to use.
-     *
-     * Arity 3: Iterate over the relevant edges across the given path.
-     * @param  {any}      source   - Source node.
-     * @param  {any}      target   - Target node.
-     * @param  {function} callback - Callback to use.
-     *
-     * @return {undefined}
-     *
-     * @throws {Error} - Will throw if there are too many arguments.
-     */
-
-
-    var someName = 'some' + name[0].toUpperCase() + name.slice(1, -1);
-
-    Class.prototype[someName] = function () {
-      var args = Array.prototype.slice.call(arguments);
-      var callback = args.pop();
-      args.push(function (e, ea, s, t, sa, ta, u) {
-        return callback(e, ea, s, t, sa, ta, u);
-      });
-      var found = this[findEdgeName].apply(this, args);
-      if (found) return true;
-      return false;
-    };
-    /**
-     * Function iterating over the graph's relevant edges in order to assert
-     * whether all of them matche the provided predicate function.
-     *
-     * Arity 1: Iterate over all the relevant edges.
-     * @param  {function} callback - Callback to use.
-     *
-     * Arity 2: Iterate over all of a node's relevant edges.
-     * @param  {any}      node     - Target node.
-     * @param  {function} callback - Callback to use.
-     *
-     * Arity 3: Iterate over the relevant edges across the given path.
-     * @param  {any}      source   - Source node.
-     * @param  {any}      target   - Target node.
-     * @param  {function} callback - Callback to use.
-     *
-     * @return {undefined}
-     *
-     * @throws {Error} - Will throw if there are too many arguments.
-     */
-
-
-    var everyName = 'every' + name[0].toUpperCase() + name.slice(1, -1);
-
-    Class.prototype[everyName] = function () {
-      var args = Array.prototype.slice.call(arguments);
-      var callback = args.pop();
-      args.push(function (e, ea, s, t, sa, ta, u) {
-        return !callback(e, ea, s, t, sa, ta, u);
-      });
-      var found = this[findEdgeName].apply(this, args);
-      if (found) return false;
-      return true;
-    };
-  }
-  /**
-   * Function attaching an edge iterator method to the Graph prototype.
-   *
-   * @param {function} Class       - Target class.
-   * @param {object}   description - Method description.
-   */
-
-
-  function attachEdgeIteratorCreator(Class, description) {
-    var originalName = description.name,
-        type = description.type,
-        direction = description.direction;
-    var name = originalName.slice(0, -1) + 'Entries';
-    /**
-     * Function returning an iterator over the graph's edges.
-     *
-     * Arity 0: Iterate over all the relevant edges.
-     *
-     * Arity 1: Iterate over all of a node's relevant edges.
-     * @param  {any}   node   - Target node.
-     *
-     * Arity 2: Iterate over the relevant edges across the given path.
-     * @param  {any}   source - Source node.
-     * @param  {any}   target - Target node.
-     *
-     * @return {array|number} - The edges or the number of edges.
-     *
-     * @throws {Error} - Will throw if there are too many arguments.
-     */
-
-    Class.prototype[name] = function (source, target) {
-      // Early termination
-      if (type !== 'mixed' && this.type !== 'mixed' && type !== this.type) return iterator.empty();
-      if (!arguments.length) return createEdgeIterator(this, type);
-
-      if (arguments.length === 1) {
-        source = '' + source;
-
-        var sourceData = this._nodes.get(source);
-
-        if (!sourceData) throw new NotFoundGraphError("Graph.".concat(name, ": could not find the \"").concat(source, "\" node in the graph.")); // Iterating over a node's edges
-
-        return createEdgeIteratorForNode(type, direction, sourceData);
-      }
-
-      if (arguments.length === 2) {
-        source = '' + source;
-        target = '' + target;
-
-        var _sourceData = this._nodes.get(source);
-
-        if (!_sourceData) throw new NotFoundGraphError("Graph.".concat(name, ":  could not find the \"").concat(source, "\" source node in the graph."));
-        if (!this._nodes.has(target)) throw new NotFoundGraphError("Graph.".concat(name, ":  could not find the \"").concat(target, "\" target node in the graph.")); // Iterating over the edges between source & target
-
-        return createEdgeIteratorForPath(type, direction, _sourceData, target);
-      }
-
-      throw new InvalidArgumentsGraphError("Graph.".concat(name, ": too many arguments (expecting 0, 1 or 2 and got ").concat(arguments.length, ")."));
-    };
-  }
-  /**
-   * Function attaching every edge iteration method to the Graph class.
-   *
-   * @param {function} Graph - Graph class.
-   */
-
-
-  function attachEdgeIterationMethods(Graph) {
-    EDGES_ITERATION.forEach(function (description) {
-      attachEdgeArrayCreator(Graph, description);
-      attachForEachEdge(Graph, description);
-      attachFindEdge(Graph, description);
-      attachEdgeIteratorCreator(Graph, description);
-    });
-  }
-
-  /**
-   * Graphology Neighbor Iteration
-   * ==============================
-   *
-   * Attaching some methods to the Graph class to be able to iterate over
-   * neighbors.
-   */
-  /**
-   * Definitions.
-   */
-
-  var NEIGHBORS_ITERATION = [{
-    name: 'neighbors',
-    type: 'mixed'
-  }, {
-    name: 'inNeighbors',
-    type: 'directed',
-    direction: 'in'
-  }, {
-    name: 'outNeighbors',
-    type: 'directed',
-    direction: 'out'
-  }, {
-    name: 'inboundNeighbors',
-    type: 'mixed',
-    direction: 'in'
-  }, {
-    name: 'outboundNeighbors',
-    type: 'mixed',
-    direction: 'out'
-  }, {
-    name: 'directedNeighbors',
-    type: 'directed'
-  }, {
-    name: 'undirectedNeighbors',
-    type: 'undirected'
-  }];
-  /**
-   * Helpers.
-   */
-
-  function CompositeSetWrapper() {
-    this.A = null;
-    this.B = null;
-  }
-
-  CompositeSetWrapper.prototype.wrap = function (set) {
-    if (this.A === null) this.A = set;else if (this.B === null) this.B = set;
-  };
-
-  CompositeSetWrapper.prototype.has = function (key) {
-    if (this.A !== null && key in this.A) return true;
-    if (this.B !== null && key in this.B) return true;
-    return false;
-  };
-  /**
-   * Function iterating over the given node's relevant neighbors to match
-   * one of them using a predicated function.
-   *
-   * @param  {string}   type      - Type of neighbors.
-   * @param  {string}   direction - Direction.
-   * @param  {any}      nodeData  - Target node's data.
-   * @param  {function} callback  - Callback to use.
-   */
-
-
-  function forEachInObjectOnce(breakable, visited, nodeData, object, callback) {
-    for (var k in object) {
-      var edgeData = object[k];
-      var sourceData = edgeData.source;
-      var targetData = edgeData.target;
-      var neighborData = sourceData === nodeData ? targetData : sourceData;
-      if (visited && visited.has(neighborData.key)) continue;
-      var shouldBreak = callback(neighborData.key, neighborData.attributes);
-      if (breakable && shouldBreak) return neighborData.key;
-    }
-
-    return;
-  }
-
-  function forEachNeighbor(breakable, type, direction, nodeData, callback) {
-    // If we want only undirected or in or out, we can roll some optimizations
-    if (type !== 'mixed') {
-      if (type === 'undirected') return forEachInObjectOnce(breakable, null, nodeData, nodeData.undirected, callback);
-      if (typeof direction === 'string') return forEachInObjectOnce(breakable, null, nodeData, nodeData[direction], callback);
-    } // Else we need to keep a set of neighbors not to return duplicates
-    // We cheat by querying the other adjacencies
-
-
-    var visited = new CompositeSetWrapper();
-    var found;
-
-    if (type !== 'undirected') {
-      if (direction !== 'out') {
-        found = forEachInObjectOnce(breakable, null, nodeData, nodeData["in"], callback);
-        if (breakable && found) return found;
-        visited.wrap(nodeData["in"]);
-      }
-
-      if (direction !== 'in') {
-        found = forEachInObjectOnce(breakable, visited, nodeData, nodeData.out, callback);
-        if (breakable && found) return found;
-        visited.wrap(nodeData.out);
-      }
-    }
-
-    if (type !== 'directed') {
-      found = forEachInObjectOnce(breakable, visited, nodeData, nodeData.undirected, callback);
-      if (breakable && found) return found;
-    }
-
-    return;
-  }
-  /**
-   * Function creating an array of relevant neighbors for the given node.
-   *
-   * @param  {string}       type      - Type of neighbors.
-   * @param  {string}       direction - Direction.
-   * @param  {any}          nodeData  - Target node's data.
-   * @return {Array}                  - The list of neighbors.
-   */
-
-
-  function createNeighborArrayForNode(type, direction, nodeData) {
-    // If we want only undirected or in or out, we can roll some optimizations
-    if (type !== 'mixed') {
-      if (type === 'undirected') return Object.keys(nodeData.undirected);
-      if (typeof direction === 'string') return Object.keys(nodeData[direction]);
-    }
-
-    var neighbors = [];
-    forEachNeighbor(false, type, direction, nodeData, function (key) {
-      neighbors.push(key);
-    });
-    return neighbors;
-  }
-  /**
-   * Function returning an iterator over the given node's relevant neighbors.
-   *
-   * @param  {string}   type      - Type of neighbors.
-   * @param  {string}   direction - Direction.
-   * @param  {any}      nodeData  - Target node's data.
-   * @return {Iterator}
-   */
-
-
-  function createDedupedObjectIterator(visited, nodeData, object) {
-    var keys = Object.keys(object);
-    var l = keys.length;
-    var i = 0;
-    return new iterator(function next() {
-      var neighborData = null;
-
-      do {
-        if (i >= l) {
-          if (visited) visited.wrap(object);
-          return {
-            done: true
-          };
-        }
-
-        var edgeData = object[keys[i++]];
-        var sourceData = edgeData.source;
-        var targetData = edgeData.target;
-        neighborData = sourceData === nodeData ? targetData : sourceData;
-
-        if (visited && visited.has(neighborData.key)) {
-          neighborData = null;
-          continue;
-        }
-      } while (neighborData === null);
-
-      return {
-        done: false,
-        value: {
-          neighbor: neighborData.key,
-          attributes: neighborData.attributes
-        }
-      };
-    });
-  }
-
-  function createNeighborIterator(type, direction, nodeData) {
-    // If we want only undirected or in or out, we can roll some optimizations
-    if (type !== 'mixed') {
-      if (type === 'undirected') return createDedupedObjectIterator(null, nodeData, nodeData.undirected);
-      if (typeof direction === 'string') return createDedupedObjectIterator(null, nodeData, nodeData[direction]);
-    }
-
-    var iterator$1 = iterator.empty(); // Else we need to keep a set of neighbors not to return duplicates
-    // We cheat by querying the other adjacencies
-
-    var visited = new CompositeSetWrapper();
-
-    if (type !== 'undirected') {
-      if (direction !== 'out') {
-        iterator$1 = chain(iterator$1, createDedupedObjectIterator(visited, nodeData, nodeData["in"]));
-      }
-
-      if (direction !== 'in') {
-        iterator$1 = chain(iterator$1, createDedupedObjectIterator(visited, nodeData, nodeData.out));
-      }
-    }
-
-    if (type !== 'directed') {
-      iterator$1 = chain(iterator$1, createDedupedObjectIterator(visited, nodeData, nodeData.undirected));
-    }
-
-    return iterator$1;
-  }
-  /**
-   * Function attaching a neighbors array creator method to the Graph prototype.
-   *
-   * @param {function} Class       - Target class.
-   * @param {object}   description - Method description.
-   */
-
-
-  function attachNeighborArrayCreator(Class, description) {
-    var name = description.name,
-        type = description.type,
-        direction = description.direction;
-    /**
-     * Function returning an array of certain neighbors.
-     *
-     * @param  {any}   node   - Target node.
-     * @return {array} - The neighbors of neighbors.
-     *
-     * @throws {Error} - Will throw if node is not found in the graph.
-     */
-
-    Class.prototype[name] = function (node) {
-      // Early termination
-      if (type !== 'mixed' && this.type !== 'mixed' && type !== this.type) return [];
-      node = '' + node;
-
-      var nodeData = this._nodes.get(node);
-
-      if (typeof nodeData === 'undefined') throw new NotFoundGraphError("Graph.".concat(name, ": could not find the \"").concat(node, "\" node in the graph.")); // Here, we want to iterate over a node's relevant neighbors
-
-      return createNeighborArrayForNode(type === 'mixed' ? this.type : type, direction, nodeData);
-    };
-  }
-  /**
-   * Function attaching a neighbors callback iterator method to the Graph prototype.
-   *
-   * @param {function} Class       - Target class.
-   * @param {object}   description - Method description.
-   */
-
-
-  function attachForEachNeighbor(Class, description) {
-    var name = description.name,
-        type = description.type,
-        direction = description.direction;
-    var forEachName = 'forEach' + name[0].toUpperCase() + name.slice(1, -1);
-    /**
-     * Function iterating over all the relevant neighbors using a callback.
-     *
-     * @param  {any}      node     - Target node.
-     * @param  {function} callback - Callback to use.
-     * @return {undefined}
-     *
-     * @throws {Error} - Will throw if there are too many arguments.
-     */
-
-    Class.prototype[forEachName] = function (node, callback) {
-      // Early termination
-      if (type !== 'mixed' && this.type !== 'mixed' && type !== this.type) return;
-      node = '' + node;
-
-      var nodeData = this._nodes.get(node);
-
-      if (typeof nodeData === 'undefined') throw new NotFoundGraphError("Graph.".concat(forEachName, ": could not find the \"").concat(node, "\" node in the graph.")); // Here, we want to iterate over a node's relevant neighbors
-
-      forEachNeighbor(false, type === 'mixed' ? this.type : type, direction, nodeData, callback);
-    };
-    /**
-     * Function mapping the relevant neighbors using a callback.
-     *
-     * @param  {any}      node     - Target node.
-     * @param  {function} callback - Callback to use.
-     *
-     * @throws {Error} - Will throw if there are too many arguments.
-     */
-
-
-    var mapName = 'map' + name[0].toUpperCase() + name.slice(1);
-
-    Class.prototype[mapName] = function (node, callback) {
-      // TODO: optimize when size is known beforehand
-      var result = [];
-      this[forEachName](node, function (n, a) {
-        result.push(callback(n, a));
-      });
-      return result;
-    };
-    /**
-     * Function filtering the relevant neighbors using a callback.
-     *
-     * @param  {any}      node     - Target node.
-     * @param  {function} callback - Callback to use.
-     *
-     * @throws {Error} - Will throw if there are too many arguments.
-     */
-
-
-    var filterName = 'filter' + name[0].toUpperCase() + name.slice(1);
-
-    Class.prototype[filterName] = function (node, callback) {
-      var result = [];
-      this[forEachName](node, function (n, a) {
-        if (callback(n, a)) result.push(n);
-      });
-      return result;
-    };
-    /**
-     * Function reducing the relevant neighbors using a callback.
-     *
-     * @param  {any}      node     - Target node.
-     * @param  {function} callback - Callback to use.
-     *
-     * @throws {Error} - Will throw if there are too many arguments.
-     */
-
-
-    var reduceName = 'reduce' + name[0].toUpperCase() + name.slice(1);
-
-    Class.prototype[reduceName] = function (node, callback, initialValue) {
-      if (arguments.length < 3) throw new InvalidArgumentsGraphError("Graph.".concat(reduceName, ": missing initial value. You must provide it because the callback takes more than one argument and we cannot infer the initial value from the first iteration, as you could with a simple array."));
-      var accumulator = initialValue;
-      this[forEachName](node, function (n, a) {
-        accumulator = callback(accumulator, n, a);
-      });
-      return accumulator;
-    };
-  }
-  /**
-   * Function attaching a breakable neighbors callback iterator method to the
-   * Graph prototype.
-   *
-   * @param {function} Class       - Target class.
-   * @param {object}   description - Method description.
-   */
-
-
-  function attachFindNeighbor(Class, description) {
-    var name = description.name,
-        type = description.type,
-        direction = description.direction;
-    var capitalizedSingular = name[0].toUpperCase() + name.slice(1, -1);
-    var findName = 'find' + capitalizedSingular;
-    /**
-     * Function iterating over all the relevant neighbors using a callback.
-     *
-     * @param  {any}      node     - Target node.
-     * @param  {function} callback - Callback to use.
-     * @return {undefined}
-     *
-     * @throws {Error} - Will throw if there are too many arguments.
-     */
-
-    Class.prototype[findName] = function (node, callback) {
-      // Early termination
-      if (type !== 'mixed' && this.type !== 'mixed' && type !== this.type) return;
-      node = '' + node;
-
-      var nodeData = this._nodes.get(node);
-
-      if (typeof nodeData === 'undefined') throw new NotFoundGraphError("Graph.".concat(findName, ": could not find the \"").concat(node, "\" node in the graph.")); // Here, we want to iterate over a node's relevant neighbors
-
-      return forEachNeighbor(true, type === 'mixed' ? this.type : type, direction, nodeData, callback);
-    };
-    /**
-     * Function iterating over all the relevant neighbors to find if any of them
-     * matches the given predicate.
-     *
-     * @param  {any}      node     - Target node.
-     * @param  {function} callback - Callback to use.
-     * @return {boolean}
-     *
-     * @throws {Error} - Will throw if there are too many arguments.
-     */
-
-
-    var someName = 'some' + capitalizedSingular;
-
-    Class.prototype[someName] = function (node, callback) {
-      var found = this[findName](node, callback);
-      if (found) return true;
-      return false;
-    };
-    /**
-     * Function iterating over all the relevant neighbors to find if all of them
-     * matche the given predicate.
-     *
-     * @param  {any}      node     - Target node.
-     * @param  {function} callback - Callback to use.
-     * @return {boolean}
-     *
-     * @throws {Error} - Will throw if there are too many arguments.
-     */
-
-
-    var everyName = 'every' + capitalizedSingular;
-
-    Class.prototype[everyName] = function (node, callback) {
-      var found = this[findName](node, function (n, a) {
-        return !callback(n, a);
-      });
-      if (found) return false;
-      return true;
-    };
-  }
-  /**
-   * Function attaching a neighbors callback iterator method to the Graph prototype.
-   *
-   * @param {function} Class       - Target class.
-   * @param {object}   description - Method description.
-   */
-
-
-  function attachNeighborIteratorCreator(Class, description) {
-    var name = description.name,
-        type = description.type,
-        direction = description.direction;
-    var iteratorName = name.slice(0, -1) + 'Entries';
-    /**
-     * Function returning an iterator over all the relevant neighbors.
-     *
-     * @param  {any}      node     - Target node.
-     * @return {Iterator}
-     *
-     * @throws {Error} - Will throw if there are too many arguments.
-     */
-
-    Class.prototype[iteratorName] = function (node) {
-      // Early termination
-      if (type !== 'mixed' && this.type !== 'mixed' && type !== this.type) return iterator.empty();
-      node = '' + node;
-
-      var nodeData = this._nodes.get(node);
-
-      if (typeof nodeData === 'undefined') throw new NotFoundGraphError("Graph.".concat(iteratorName, ": could not find the \"").concat(node, "\" node in the graph.")); // Here, we want to iterate over a node's relevant neighbors
-
-      return createNeighborIterator(type === 'mixed' ? this.type : type, direction, nodeData);
-    };
-  }
-  /**
-   * Function attaching every neighbor iteration method to the Graph class.
-   *
-   * @param {function} Graph - Graph class.
-   */
-
-
-  function attachNeighborIterationMethods(Graph) {
-    NEIGHBORS_ITERATION.forEach(function (description) {
-      attachNeighborArrayCreator(Graph, description);
-      attachForEachNeighbor(Graph, description);
-      attachFindNeighbor(Graph, description);
-      attachNeighborIteratorCreator(Graph, description);
-    });
-  }
-
-  /**
-   * Graphology Adjacency Iteration
-   * ===============================
-   *
-   * Attaching some methods to the Graph class to be able to iterate over a
-   * graph's adjacency.
-   */
-
-  /**
-   * Function iterating over a simple graph's adjacency using a callback.
-   *
-   * @param {boolean}  breakable         - Can we break?
-   * @param {boolean}  assymetric        - Whether to emit undirected edges only once.
-   * @param {boolean}  disconnectedNodes - Whether to emit disconnected nodes.
-   * @param {Graph}    graph             - Target Graph instance.
-   * @param {callback} function          - Iteration callback.
-   */
-  function forEachAdjacency(breakable, assymetric, disconnectedNodes, graph, callback) {
-    var iterator = graph._nodes.values();
-
-    var type = graph.type;
-    var step, sourceData, neighbor, adj, edgeData, targetData, shouldBreak;
-
-    while (step = iterator.next(), step.done !== true) {
-      var hasEdges = false;
-      sourceData = step.value;
-
-      if (type !== 'undirected') {
-        adj = sourceData.out;
-
-        for (neighbor in adj) {
-          edgeData = adj[neighbor];
-
-          do {
-            targetData = edgeData.target;
-            hasEdges = true;
-            shouldBreak = callback(sourceData.key, targetData.key, sourceData.attributes, targetData.attributes, edgeData.key, edgeData.attributes, edgeData.undirected);
-            if (breakable && shouldBreak) return edgeData;
-            edgeData = edgeData.next;
-          } while (edgeData);
-        }
-      }
-
-      if (type !== 'directed') {
-        adj = sourceData.undirected;
-
-        for (neighbor in adj) {
-          if (assymetric && sourceData.key > neighbor) continue;
-          edgeData = adj[neighbor];
-
-          do {
-            targetData = edgeData.target;
-            if (targetData.key !== neighbor) targetData = edgeData.source;
-            hasEdges = true;
-            shouldBreak = callback(sourceData.key, targetData.key, sourceData.attributes, targetData.attributes, edgeData.key, edgeData.attributes, edgeData.undirected);
-            if (breakable && shouldBreak) return edgeData;
-            edgeData = edgeData.next;
-          } while (edgeData);
-        }
-      }
-
-      if (disconnectedNodes && !hasEdges) {
-        shouldBreak = callback(sourceData.key, null, sourceData.attributes, null, null, null, null);
-        if (breakable && shouldBreak) return null;
-      }
-    }
-
-    return;
-  }
-
-  /**
-   * Graphology Serialization Utilities
-   * ===================================
-   *
-   * Collection of functions used by the graph serialization schemes.
-   */
-  /**
-   * Formats internal node data into a serialized node.
-   *
-   * @param  {any}    key  - The node's key.
-   * @param  {object} data - Internal node's data.
-   * @return {array}       - The serialized node.
-   */
-
-  function serializeNode(key, data) {
-    var serialized = {
-      key: key
-    };
-    if (!isEmpty(data.attributes)) serialized.attributes = assign({}, data.attributes);
-    return serialized;
-  }
-  /**
-   * Formats internal edge data into a serialized edge.
-   *
-   * @param  {any}    key  - The edge's key.
-   * @param  {object} data - Internal edge's data.
-   * @return {array}       - The serialized edge.
-   */
-
-  function serializeEdge(key, data) {
-    var serialized = {
-      key: key,
-      source: data.source.key,
-      target: data.target.key
-    };
-    if (!isEmpty(data.attributes)) serialized.attributes = assign({}, data.attributes);
-    if (data.undirected) serialized.undirected = true;
-    return serialized;
-  }
-  /**
-   * Checks whether the given value is a serialized node.
-   *
-   * @param  {mixed} value - Target value.
-   * @return {string|null}
-   */
-
-  function validateSerializedNode(value) {
-    if (!isPlainObject(value)) throw new InvalidArgumentsGraphError('Graph.import: invalid serialized node. A serialized node should be a plain object with at least a "key" property.');
-    if (!('key' in value)) throw new InvalidArgumentsGraphError('Graph.import: serialized node is missing its key.');
-    if ('attributes' in value && (!isPlainObject(value.attributes) || value.attributes === null)) throw new InvalidArgumentsGraphError('Graph.import: invalid attributes. Attributes should be a plain object, null or omitted.');
-  }
-  /**
-   * Checks whether the given value is a serialized edge.
-   *
-   * @param  {mixed} value - Target value.
-   * @return {string|null}
-   */
-
-  function validateSerializedEdge(value) {
-    if (!isPlainObject(value)) throw new InvalidArgumentsGraphError('Graph.import: invalid serialized edge. A serialized edge should be a plain object with at least a "source" & "target" property.');
-    if (!('source' in value)) throw new InvalidArgumentsGraphError('Graph.import: serialized edge is missing its source.');
-    if (!('target' in value)) throw new InvalidArgumentsGraphError('Graph.import: serialized edge is missing its target.');
-    if ('attributes' in value && (!isPlainObject(value.attributes) || value.attributes === null)) throw new InvalidArgumentsGraphError('Graph.import: invalid attributes. Attributes should be a plain object, null or omitted.');
-    if ('undirected' in value && typeof value.undirected !== 'boolean') throw new InvalidArgumentsGraphError('Graph.import: invalid undirectedness information. Undirected should be boolean or omitted.');
-  }
-
-  /**
-   * Constants.
-   */
-
-  var INSTANCE_ID = incrementalIdStartingFromRandomByte();
-  /**
-   * Enums.
-   */
-
-  var TYPES = new Set(['directed', 'undirected', 'mixed']);
-  var EMITTER_PROPS = new Set(['domain', '_events', '_eventsCount', '_maxListeners']);
-  var EDGE_ADD_METHODS = [{
-    name: function name(verb) {
-      return "".concat(verb, "Edge");
-    },
-    generateKey: true
-  }, {
-    name: function name(verb) {
-      return "".concat(verb, "DirectedEdge");
-    },
-    generateKey: true,
-    type: 'directed'
-  }, {
-    name: function name(verb) {
-      return "".concat(verb, "UndirectedEdge");
-    },
-    generateKey: true,
-    type: 'undirected'
-  }, {
-    name: function name(verb) {
-      return "".concat(verb, "EdgeWithKey");
-    }
-  }, {
-    name: function name(verb) {
-      return "".concat(verb, "DirectedEdgeWithKey");
-    },
-    type: 'directed'
-  }, {
-    name: function name(verb) {
-      return "".concat(verb, "UndirectedEdgeWithKey");
-    },
-    type: 'undirected'
-  }];
-  /**
-   * Default options.
-   */
-
-  var DEFAULTS = {
-    allowSelfLoops: true,
-    multi: false,
-    type: 'mixed'
-  };
-  /**
-   * Abstract functions used by the Graph class for various methods.
-   */
-
-  /**
-   * Internal method used to add a node to the given graph
-   *
-   * @param  {Graph}   graph           - Target graph.
-   * @param  {any}     node            - The node's key.
-   * @param  {object}  [attributes]    - Optional attributes.
-   * @return {NodeData}                - Created node data.
-   */
-
-  function _addNode(graph, node, attributes) {
-    if (attributes && !isPlainObject(attributes)) throw new InvalidArgumentsGraphError("Graph.addNode: invalid attributes. Expecting an object but got \"".concat(attributes, "\"")); // String coercion
-
-    node = '' + node;
-    attributes = attributes || {};
-    if (graph._nodes.has(node)) throw new UsageGraphError("Graph.addNode: the \"".concat(node, "\" node already exist in the graph."));
-    var data = new graph.NodeDataClass(node, attributes); // Adding the node to internal register
-
-    graph._nodes.set(node, data); // Emitting
-
-
-    graph.emit('nodeAdded', {
-      key: node,
-      attributes: attributes
-    });
-    return data;
-  }
-  /**
-   * Same as the above but without sanity checks because we call this in contexts
-   * where necessary checks were already done.
-   */
-
-
-  function unsafeAddNode(graph, node, attributes) {
-    var data = new graph.NodeDataClass(node, attributes);
-
-    graph._nodes.set(node, data);
-
-    graph.emit('nodeAdded', {
-      key: node,
-      attributes: attributes
-    });
-    return data;
-  }
-  /**
-   * Internal method used to add an arbitrary edge to the given graph.
-   *
-   * @param  {Graph}   graph           - Target graph.
-   * @param  {string}  name            - Name of the child method for errors.
-   * @param  {boolean} mustGenerateKey - Should the graph generate an id?
-   * @param  {boolean} undirected      - Whether the edge is undirected.
-   * @param  {any}     edge            - The edge's key.
-   * @param  {any}     source          - The source node.
-   * @param  {any}     target          - The target node.
-   * @param  {object}  [attributes]    - Optional attributes.
-   * @return {any}                     - The edge.
-   *
-   * @throws {Error} - Will throw if the graph is of the wrong type.
-   * @throws {Error} - Will throw if the given attributes are not an object.
-   * @throws {Error} - Will throw if source or target doesn't exist.
-   * @throws {Error} - Will throw if the edge already exist.
-   */
-
-
-  function addEdge(graph, name, mustGenerateKey, undirected, edge, source, target, attributes) {
-    // Checking validity of operation
-    if (!undirected && graph.type === 'undirected') throw new UsageGraphError("Graph.".concat(name, ": you cannot add a directed edge to an undirected graph. Use the #.addEdge or #.addUndirectedEdge instead."));
-    if (undirected && graph.type === 'directed') throw new UsageGraphError("Graph.".concat(name, ": you cannot add an undirected edge to a directed graph. Use the #.addEdge or #.addDirectedEdge instead."));
-    if (attributes && !isPlainObject(attributes)) throw new InvalidArgumentsGraphError("Graph.".concat(name, ": invalid attributes. Expecting an object but got \"").concat(attributes, "\"")); // Coercion of source & target:
-
-    source = '' + source;
-    target = '' + target;
-    attributes = attributes || {};
-    if (!graph.allowSelfLoops && source === target) throw new UsageGraphError("Graph.".concat(name, ": source & target are the same (\"").concat(source, "\"), thus creating a loop explicitly forbidden by this graph 'allowSelfLoops' option set to false."));
-
-    var sourceData = graph._nodes.get(source),
-        targetData = graph._nodes.get(target);
-
-    if (!sourceData) throw new NotFoundGraphError("Graph.".concat(name, ": source node \"").concat(source, "\" not found."));
-    if (!targetData) throw new NotFoundGraphError("Graph.".concat(name, ": target node \"").concat(target, "\" not found.")); // Must the graph generate an id for this edge?
-
-    var eventData = {
-      key: null,
-      undirected: undirected,
-      source: source,
-      target: target,
-      attributes: attributes
-    };
-
-    if (mustGenerateKey) {
-      // NOTE: in this case we can guarantee that the key does not already
-      // exist and is already correctly casted as a string
-      edge = graph._edgeKeyGenerator();
-    } else {
-      // Coercion of edge key
-      edge = '' + edge; // Here, we have a key collision
-
-      if (graph._edges.has(edge)) throw new UsageGraphError("Graph.".concat(name, ": the \"").concat(edge, "\" edge already exists in the graph."));
-    } // Here, we might have a source / target collision
-
-
-    if (!graph.multi && (undirected ? typeof sourceData.undirected[target] !== 'undefined' : typeof sourceData.out[target] !== 'undefined')) {
-      throw new UsageGraphError("Graph.".concat(name, ": an edge linking \"").concat(source, "\" to \"").concat(target, "\" already exists. If you really want to add multiple edges linking those nodes, you should create a multi graph by using the 'multi' option."));
-    } // Storing some data
-
-
-    var edgeData = new EdgeData(undirected, edge, sourceData, targetData, attributes); // Adding the edge to the internal register
-
-    graph._edges.set(edge, edgeData); // Incrementing node degree counters
-
-
-    var isSelfLoop = source === target;
-
-    if (undirected) {
-      sourceData.undirectedDegree++;
-      targetData.undirectedDegree++;
-      if (isSelfLoop) graph._undirectedSelfLoopCount++;
-    } else {
-      sourceData.outDegree++;
-      targetData.inDegree++;
-      if (isSelfLoop) graph._directedSelfLoopCount++;
-    } // Updating relevant index
-
-
-    if (graph.multi) edgeData.attachMulti();else edgeData.attach();
-    if (undirected) graph._undirectedSize++;else graph._directedSize++; // Emitting
-
-    eventData.key = edge;
-    graph.emit('edgeAdded', eventData);
-    return edge;
-  }
-  /**
-   * Internal method used to add an arbitrary edge to the given graph.
-   *
-   * @param  {Graph}   graph           - Target graph.
-   * @param  {string}  name            - Name of the child method for errors.
-   * @param  {boolean} mustGenerateKey - Should the graph generate an id?
-   * @param  {boolean} undirected      - Whether the edge is undirected.
-   * @param  {any}     edge            - The edge's key.
-   * @param  {any}     source          - The source node.
-   * @param  {any}     target          - The target node.
-   * @param  {object}  [attributes]    - Optional attributes.
-   * @param  {boolean} [asUpdater]       - Are we updating or merging?
-   * @return {any}                     - The edge.
-   *
-   * @throws {Error} - Will throw if the graph is of the wrong type.
-   * @throws {Error} - Will throw if the given attributes are not an object.
-   * @throws {Error} - Will throw if source or target doesn't exist.
-   * @throws {Error} - Will throw if the edge already exist.
-   */
-
-
-  function mergeEdge(graph, name, mustGenerateKey, undirected, edge, source, target, attributes, asUpdater) {
-    // Checking validity of operation
-    if (!undirected && graph.type === 'undirected') throw new UsageGraphError("Graph.".concat(name, ": you cannot merge/update a directed edge to an undirected graph. Use the #.mergeEdge/#.updateEdge or #.addUndirectedEdge instead."));
-    if (undirected && graph.type === 'directed') throw new UsageGraphError("Graph.".concat(name, ": you cannot merge/update an undirected edge to a directed graph. Use the #.mergeEdge/#.updateEdge or #.addDirectedEdge instead."));
-
-    if (attributes) {
-      if (asUpdater) {
-        if (typeof attributes !== 'function') throw new InvalidArgumentsGraphError("Graph.".concat(name, ": invalid updater function. Expecting a function but got \"").concat(attributes, "\""));
-      } else {
-        if (!isPlainObject(attributes)) throw new InvalidArgumentsGraphError("Graph.".concat(name, ": invalid attributes. Expecting an object but got \"").concat(attributes, "\""));
-      }
-    } // Coercion of source & target:
-
-
-    source = '' + source;
-    target = '' + target;
-    var updater;
-
-    if (asUpdater) {
-      updater = attributes;
-      attributes = undefined;
-    }
-
-    if (!graph.allowSelfLoops && source === target) throw new UsageGraphError("Graph.".concat(name, ": source & target are the same (\"").concat(source, "\"), thus creating a loop explicitly forbidden by this graph 'allowSelfLoops' option set to false."));
-
-    var sourceData = graph._nodes.get(source);
-
-    var targetData = graph._nodes.get(target);
-
-    var edgeData; // Do we need to handle duplicate?
-
-    var alreadyExistingEdgeData;
-
-    if (!mustGenerateKey) {
-      edgeData = graph._edges.get(edge);
-
-      if (edgeData) {
-        // Here, we need to ensure, if the user gave a key, that source & target
-        // are consistent
-        if (edgeData.source.key !== source || edgeData.target.key !== target) {
-          // If source or target inconsistent
-          if (!undirected || edgeData.source.key !== target || edgeData.target.key !== source) {
-            // If directed, or source/target aren't flipped
-            throw new UsageGraphError("Graph.".concat(name, ": inconsistency detected when attempting to merge the \"").concat(edge, "\" edge with \"").concat(source, "\" source & \"").concat(target, "\" target vs. (\"").concat(edgeData.source.key, "\", \"").concat(edgeData.target.key, "\")."));
-          }
-        }
-
-        alreadyExistingEdgeData = edgeData;
-      }
-    } // Here, we might have a source / target collision
-
-
-    if (!alreadyExistingEdgeData && !graph.multi && sourceData) {
-      alreadyExistingEdgeData = undirected ? sourceData.undirected[target] : sourceData.out[target];
-    } // Handling duplicates
-
-
-    if (alreadyExistingEdgeData) {
-      var info = [alreadyExistingEdgeData.key, false, false, false]; // We can skip the attribute merging part if the user did not provide them
-
-      if (asUpdater ? !updater : !attributes) return info; // Updating the attributes
-
-      if (asUpdater) {
-        var oldAttributes = alreadyExistingEdgeData.attributes;
-        alreadyExistingEdgeData.attributes = updater(oldAttributes);
-        graph.emit('edgeAttributesUpdated', {
-          type: 'replace',
-          key: alreadyExistingEdgeData.key,
-          attributes: alreadyExistingEdgeData.attributes
-        });
-      } // Merging the attributes
-      else {
-        assign(alreadyExistingEdgeData.attributes, attributes);
-        graph.emit('edgeAttributesUpdated', {
-          type: 'merge',
-          key: alreadyExistingEdgeData.key,
-          attributes: alreadyExistingEdgeData.attributes,
-          data: attributes
-        });
-      }
-
-      return info;
-    }
-
-    attributes = attributes || {};
-    if (asUpdater && updater) attributes = updater(attributes); // Must the graph generate an id for this edge?
-
-    var eventData = {
-      key: null,
-      undirected: undirected,
-      source: source,
-      target: target,
-      attributes: attributes
-    };
-
-    if (mustGenerateKey) {
-      // NOTE: in this case we can guarantee that the key does not already
-      // exist and is already correctly casted as a string
-      edge = graph._edgeKeyGenerator();
-    } else {
-      // Coercion of edge key
-      edge = '' + edge; // Here, we have a key collision
-
-      if (graph._edges.has(edge)) throw new UsageGraphError("Graph.".concat(name, ": the \"").concat(edge, "\" edge already exists in the graph."));
-    }
-
-    var sourceWasAdded = false;
-    var targetWasAdded = false;
-
-    if (!sourceData) {
-      sourceData = unsafeAddNode(graph, source, {});
-      sourceWasAdded = true;
-
-      if (source === target) {
-        targetData = sourceData;
-        targetWasAdded = true;
-      }
-    }
-
-    if (!targetData) {
-      targetData = unsafeAddNode(graph, target, {});
-      targetWasAdded = true;
-    } // Storing some data
-
-
-    edgeData = new EdgeData(undirected, edge, sourceData, targetData, attributes); // Adding the edge to the internal register
-
-    graph._edges.set(edge, edgeData); // Incrementing node degree counters
-
-
-    var isSelfLoop = source === target;
-
-    if (undirected) {
-      sourceData.undirectedDegree++;
-      targetData.undirectedDegree++;
-      if (isSelfLoop) graph._undirectedSelfLoopCount++;
-    } else {
-      sourceData.outDegree++;
-      targetData.inDegree++;
-      if (isSelfLoop) graph._directedSelfLoopCount++;
-    } // Updating relevant index
-
-
-    if (graph.multi) edgeData.attachMulti();else edgeData.attach();
-    if (undirected) graph._undirectedSize++;else graph._directedSize++; // Emitting
-
-    eventData.key = edge;
-    graph.emit('edgeAdded', eventData);
-    return [edge, true, sourceWasAdded, targetWasAdded];
-  }
-  /**
-   * Internal method used to drop an edge.
-   *
-   * @param  {Graph}    graph    - Target graph.
-   * @param  {EdgeData} edgeData - Data of the edge to drop.
-   */
-
-
-  function dropEdgeFromData(graph, edgeData) {
-    // Dropping the edge from the register
-    graph._edges["delete"](edgeData.key); // Updating related degrees
-
-
-    var sourceData = edgeData.source,
-        targetData = edgeData.target,
-        attributes = edgeData.attributes;
-    var undirected = edgeData.undirected;
-    var isSelfLoop = sourceData === targetData;
-
-    if (undirected) {
-      sourceData.undirectedDegree--;
-      targetData.undirectedDegree--;
-      if (isSelfLoop) graph._undirectedSelfLoopCount--;
-    } else {
-      sourceData.outDegree--;
-      targetData.inDegree--;
-      if (isSelfLoop) graph._directedSelfLoopCount--;
-    } // Clearing index
-
-
-    if (graph.multi) edgeData.detachMulti();else edgeData.detach();
-    if (undirected) graph._undirectedSize--;else graph._directedSize--; // Emitting
-
-    graph.emit('edgeDropped', {
-      key: edgeData.key,
-      attributes: attributes,
-      source: sourceData.key,
-      target: targetData.key,
-      undirected: undirected
-    });
-  }
-  /**
-   * Graph class
-   *
-   * @constructor
-   * @param  {object}  [options] - Options:
-   * @param  {boolean}   [allowSelfLoops] - Allow self loops?
-   * @param  {string}    [type]           - Type of the graph.
-   * @param  {boolean}   [map]            - Allow references as keys?
-   * @param  {boolean}   [multi]          - Allow parallel edges?
-   *
-   * @throws {Error} - Will throw if the arguments are not valid.
-   */
-
-
-  var Graph = /*#__PURE__*/function (_EventEmitter) {
-    _inheritsLoose(Graph, _EventEmitter);
-
-    function Graph(options) {
-      var _this;
-
-      _this = _EventEmitter.call(this) || this; //-- Solving options
-
-      options = assign({}, DEFAULTS, options); // Enforcing options validity
-
-      if (typeof options.multi !== 'boolean') throw new InvalidArgumentsGraphError("Graph.constructor: invalid 'multi' option. Expecting a boolean but got \"".concat(options.multi, "\"."));
-      if (!TYPES.has(options.type)) throw new InvalidArgumentsGraphError("Graph.constructor: invalid 'type' option. Should be one of \"mixed\", \"directed\" or \"undirected\" but got \"".concat(options.type, "\"."));
-      if (typeof options.allowSelfLoops !== 'boolean') throw new InvalidArgumentsGraphError("Graph.constructor: invalid 'allowSelfLoops' option. Expecting a boolean but got \"".concat(options.allowSelfLoops, "\".")); //-- Private properties
-      // Utilities
-
-      var NodeDataClass = options.type === 'mixed' ? MixedNodeData : options.type === 'directed' ? DirectedNodeData : UndirectedNodeData;
-      privateProperty(_assertThisInitialized(_this), 'NodeDataClass', NodeDataClass); // Internal edge key generator
-      // NOTE: this internal generator produce keys that are strings
-      // composed of a weird prefix, an incremental instance id starting from
-      // a random byte and finally an internal instance incremental id.
-      // All this to avoid intra-frame and cross-frame adversarial inputs
-      // that can force a single #.addEdge call to degenerate into a O(n)
-      // available key search loop.
-      // It also ensures that automatically generated edge keys are unlikely
-      // to produce collisions with arbitrary keys given by users.
-
-      var instancePrefix = 'geid_' + INSTANCE_ID() + '_';
-      var edgeId = 0;
-
-      var edgeKeyGenerator = function edgeKeyGenerator() {
-        var availableEdgeKey;
-
-        do {
-          availableEdgeKey = instancePrefix + edgeId++;
-        } while (_this._edges.has(availableEdgeKey));
-
-        return availableEdgeKey;
-      }; // Indexes
-
-
-      privateProperty(_assertThisInitialized(_this), '_attributes', {});
-      privateProperty(_assertThisInitialized(_this), '_nodes', new Map());
-      privateProperty(_assertThisInitialized(_this), '_edges', new Map());
-      privateProperty(_assertThisInitialized(_this), '_directedSize', 0);
-      privateProperty(_assertThisInitialized(_this), '_undirectedSize', 0);
-      privateProperty(_assertThisInitialized(_this), '_directedSelfLoopCount', 0);
-      privateProperty(_assertThisInitialized(_this), '_undirectedSelfLoopCount', 0);
-      privateProperty(_assertThisInitialized(_this), '_edgeKeyGenerator', edgeKeyGenerator); // Options
-
-      privateProperty(_assertThisInitialized(_this), '_options', options); // Emitter properties
-
-      EMITTER_PROPS.forEach(function (prop) {
-        return privateProperty(_assertThisInitialized(_this), prop, _this[prop]);
-      }); //-- Properties readers
-
-      readOnlyProperty(_assertThisInitialized(_this), 'order', function () {
-        return _this._nodes.size;
-      });
-      readOnlyProperty(_assertThisInitialized(_this), 'size', function () {
-        return _this._edges.size;
-      });
-      readOnlyProperty(_assertThisInitialized(_this), 'directedSize', function () {
-        return _this._directedSize;
-      });
-      readOnlyProperty(_assertThisInitialized(_this), 'undirectedSize', function () {
-        return _this._undirectedSize;
-      });
-      readOnlyProperty(_assertThisInitialized(_this), 'selfLoopCount', function () {
-        return _this._directedSelfLoopCount + _this._undirectedSelfLoopCount;
-      });
-      readOnlyProperty(_assertThisInitialized(_this), 'directedSelfLoopCount', function () {
-        return _this._directedSelfLoopCount;
-      });
-      readOnlyProperty(_assertThisInitialized(_this), 'undirectedSelfLoopCount', function () {
-        return _this._undirectedSelfLoopCount;
-      });
-      readOnlyProperty(_assertThisInitialized(_this), 'multi', _this._options.multi);
-      readOnlyProperty(_assertThisInitialized(_this), 'type', _this._options.type);
-      readOnlyProperty(_assertThisInitialized(_this), 'allowSelfLoops', _this._options.allowSelfLoops);
-      readOnlyProperty(_assertThisInitialized(_this), 'implementation', function () {
-        return 'graphology';
-      });
-      return _this;
-    }
-
-    var _proto = Graph.prototype;
-
-    _proto._resetInstanceCounters = function _resetInstanceCounters() {
-      this._directedSize = 0;
-      this._undirectedSize = 0;
-      this._directedSelfLoopCount = 0;
-      this._undirectedSelfLoopCount = 0;
-    }
-    /**---------------------------------------------------------------------------
-     * Read
-     **---------------------------------------------------------------------------
-     */
-
-    /**
-     * Method returning whether the given node is found in the graph.
-     *
-     * @param  {any}     node - The node.
-     * @return {boolean}
-     */
-    ;
-
-    _proto.hasNode = function hasNode(node) {
-      return this._nodes.has('' + node);
-    }
-    /**
-     * Method returning whether the given directed edge is found in the graph.
-     *
-     * Arity 1:
-     * @param  {any}     edge - The edge's key.
-     *
-     * Arity 2:
-     * @param  {any}     source - The edge's source.
-     * @param  {any}     target - The edge's target.
-     *
-     * @return {boolean}
-     *
-     * @throws {Error} - Will throw if the arguments are invalid.
-     */
-    ;
-
-    _proto.hasDirectedEdge = function hasDirectedEdge(source, target) {
-      // Early termination
-      if (this.type === 'undirected') return false;
-
-      if (arguments.length === 1) {
-        var edge = '' + source;
-
-        var edgeData = this._edges.get(edge);
-
-        return !!edgeData && !edgeData.undirected;
-      } else if (arguments.length === 2) {
-        source = '' + source;
-        target = '' + target; // If the node source or the target is not in the graph we break
-
-        var nodeData = this._nodes.get(source);
-
-        if (!nodeData) return false; // Is there a directed edge pointing toward target?
-
-        var edges = nodeData.out[target];
-        if (!edges) return false;
-        return this.multi ? !!edges.size : true;
-      }
-
-      throw new InvalidArgumentsGraphError("Graph.hasDirectedEdge: invalid arity (".concat(arguments.length, ", instead of 1 or 2). You can either ask for an edge id or for the existence of an edge between a source & a target."));
-    }
-    /**
-     * Method returning whether the given undirected edge is found in the graph.
-     *
-     * Arity 1:
-     * @param  {any}     edge - The edge's key.
-     *
-     * Arity 2:
-     * @param  {any}     source - The edge's source.
-     * @param  {any}     target - The edge's target.
-     *
-     * @return {boolean}
-     *
-     * @throws {Error} - Will throw if the arguments are invalid.
-     */
-    ;
-
-    _proto.hasUndirectedEdge = function hasUndirectedEdge(source, target) {
-      // Early termination
-      if (this.type === 'directed') return false;
-
-      if (arguments.length === 1) {
-        var edge = '' + source;
-
-        var edgeData = this._edges.get(edge);
-
-        return !!edgeData && edgeData.undirected;
-      } else if (arguments.length === 2) {
-        source = '' + source;
-        target = '' + target; // If the node source or the target is not in the graph we break
-
-        var nodeData = this._nodes.get(source);
-
-        if (!nodeData) return false; // Is there a directed edge pointing toward target?
-
-        var edges = nodeData.undirected[target];
-        if (!edges) return false;
-        return this.multi ? !!edges.size : true;
-      }
-
-      throw new InvalidArgumentsGraphError("Graph.hasDirectedEdge: invalid arity (".concat(arguments.length, ", instead of 1 or 2). You can either ask for an edge id or for the existence of an edge between a source & a target."));
-    }
-    /**
-     * Method returning whether the given edge is found in the graph.
-     *
-     * Arity 1:
-     * @param  {any}     edge - The edge's key.
-     *
-     * Arity 2:
-     * @param  {any}     source - The edge's source.
-     * @param  {any}     target - The edge's target.
-     *
-     * @return {boolean}
-     *
-     * @throws {Error} - Will throw if the arguments are invalid.
-     */
-    ;
-
-    _proto.hasEdge = function hasEdge(source, target) {
-      if (arguments.length === 1) {
-        var edge = '' + source;
-        return this._edges.has(edge);
-      } else if (arguments.length === 2) {
-        source = '' + source;
-        target = '' + target; // If the node source or the target is not in the graph we break
-
-        var nodeData = this._nodes.get(source);
-
-        if (!nodeData) return false; // Is there a directed edge pointing toward target?
-
-        var edges = typeof nodeData.out !== 'undefined' && nodeData.out[target];
-        if (!edges) edges = typeof nodeData.undirected !== 'undefined' && nodeData.undirected[target];
-        if (!edges) return false;
-        return this.multi ? !!edges.size : true;
-      }
-
-      throw new InvalidArgumentsGraphError("Graph.hasEdge: invalid arity (".concat(arguments.length, ", instead of 1 or 2). You can either ask for an edge id or for the existence of an edge between a source & a target."));
-    }
-    /**
-     * Method returning the edge matching source & target in a directed fashion.
-     *
-     * @param  {any} source - The edge's source.
-     * @param  {any} target - The edge's target.
-     *
-     * @return {any|undefined}
-     *
-     * @throws {Error} - Will throw if the graph is multi.
-     * @throws {Error} - Will throw if source or target doesn't exist.
-     */
-    ;
-
-    _proto.directedEdge = function directedEdge(source, target) {
-      if (this.type === 'undirected') return;
-      source = '' + source;
-      target = '' + target;
-      if (this.multi) throw new UsageGraphError('Graph.directedEdge: this method is irrelevant with multigraphs since there might be multiple edges between source & target. See #.directedEdges instead.');
-
-      var sourceData = this._nodes.get(source);
-
-      if (!sourceData) throw new NotFoundGraphError("Graph.directedEdge: could not find the \"".concat(source, "\" source node in the graph."));
-      if (!this._nodes.has(target)) throw new NotFoundGraphError("Graph.directedEdge: could not find the \"".concat(target, "\" target node in the graph."));
-      var edgeData = sourceData.out && sourceData.out[target] || undefined;
-      if (edgeData) return edgeData.key;
-    }
-    /**
-     * Method returning the edge matching source & target in a undirected fashion.
-     *
-     * @param  {any} source - The edge's source.
-     * @param  {any} target - The edge's target.
-     *
-     * @return {any|undefined}
-     *
-     * @throws {Error} - Will throw if the graph is multi.
-     * @throws {Error} - Will throw if source or target doesn't exist.
-     */
-    ;
-
-    _proto.undirectedEdge = function undirectedEdge(source, target) {
-      if (this.type === 'directed') return;
-      source = '' + source;
-      target = '' + target;
-      if (this.multi) throw new UsageGraphError('Graph.undirectedEdge: this method is irrelevant with multigraphs since there might be multiple edges between source & target. See #.undirectedEdges instead.');
-
-      var sourceData = this._nodes.get(source);
-
-      if (!sourceData) throw new NotFoundGraphError("Graph.undirectedEdge: could not find the \"".concat(source, "\" source node in the graph."));
-      if (!this._nodes.has(target)) throw new NotFoundGraphError("Graph.undirectedEdge: could not find the \"".concat(target, "\" target node in the graph."));
-      var edgeData = sourceData.undirected && sourceData.undirected[target] || undefined;
-      if (edgeData) return edgeData.key;
-    }
-    /**
-     * Method returning the edge matching source & target in a mixed fashion.
-     *
-     * @param  {any} source - The edge's source.
-     * @param  {any} target - The edge's target.
-     *
-     * @return {any|undefined}
-     *
-     * @throws {Error} - Will throw if the graph is multi.
-     * @throws {Error} - Will throw if source or target doesn't exist.
-     */
-    ;
-
-    _proto.edge = function edge(source, target) {
-      if (this.multi) throw new UsageGraphError('Graph.edge: this method is irrelevant with multigraphs since there might be multiple edges between source & target. See #.edges instead.');
-      source = '' + source;
-      target = '' + target;
-
-      var sourceData = this._nodes.get(source);
-
-      if (!sourceData) throw new NotFoundGraphError("Graph.edge: could not find the \"".concat(source, "\" source node in the graph."));
-      if (!this._nodes.has(target)) throw new NotFoundGraphError("Graph.edge: could not find the \"".concat(target, "\" target node in the graph."));
-      var edgeData = sourceData.out && sourceData.out[target] || sourceData.undirected && sourceData.undirected[target] || undefined;
-      if (edgeData) return edgeData.key;
-    }
-    /**
-     * Method returning whether two nodes are directed neighbors.
-     *
-     * @param  {any}     node     - The node's key.
-     * @param  {any}     neighbor - The neighbor's key.
-     * @return {boolean}
-     *
-     * @throws {Error} - Will throw if the node isn't in the graph.
-     */
-    ;
-
-    _proto.areDirectedNeighbors = function areDirectedNeighbors(node, neighbor) {
-      node = '' + node;
-      neighbor = '' + neighbor;
-
-      var nodeData = this._nodes.get(node);
-
-      if (!nodeData) throw new NotFoundGraphError("Graph.areDirectedNeighbors: could not find the \"".concat(node, "\" node in the graph."));
-      if (this.type === 'undirected') return false;
-      return neighbor in nodeData["in"] || neighbor in nodeData.out;
-    }
-    /**
-     * Method returning whether two nodes are out neighbors.
-     *
-     * @param  {any}     node     - The node's key.
-     * @param  {any}     neighbor - The neighbor's key.
-     * @return {boolean}
-     *
-     * @throws {Error} - Will throw if the node isn't in the graph.
-     */
-    ;
-
-    _proto.areOutNeighbors = function areOutNeighbors(node, neighbor) {
-      node = '' + node;
-      neighbor = '' + neighbor;
-
-      var nodeData = this._nodes.get(node);
-
-      if (!nodeData) throw new NotFoundGraphError("Graph.areOutNeighbors: could not find the \"".concat(node, "\" node in the graph."));
-      if (this.type === 'undirected') return false;
-      return neighbor in nodeData.out;
-    }
-    /**
-     * Method returning whether two nodes are in neighbors.
-     *
-     * @param  {any}     node     - The node's key.
-     * @param  {any}     neighbor - The neighbor's key.
-     * @return {boolean}
-     *
-     * @throws {Error} - Will throw if the node isn't in the graph.
-     */
-    ;
-
-    _proto.areInNeighbors = function areInNeighbors(node, neighbor) {
-      node = '' + node;
-      neighbor = '' + neighbor;
-
-      var nodeData = this._nodes.get(node);
-
-      if (!nodeData) throw new NotFoundGraphError("Graph.areInNeighbors: could not find the \"".concat(node, "\" node in the graph."));
-      if (this.type === 'undirected') return false;
-      return neighbor in nodeData["in"];
-    }
-    /**
-     * Method returning whether two nodes are undirected neighbors.
-     *
-     * @param  {any}     node     - The node's key.
-     * @param  {any}     neighbor - The neighbor's key.
-     * @return {boolean}
-     *
-     * @throws {Error} - Will throw if the node isn't in the graph.
-     */
-    ;
-
-    _proto.areUndirectedNeighbors = function areUndirectedNeighbors(node, neighbor) {
-      node = '' + node;
-      neighbor = '' + neighbor;
-
-      var nodeData = this._nodes.get(node);
-
-      if (!nodeData) throw new NotFoundGraphError("Graph.areUndirectedNeighbors: could not find the \"".concat(node, "\" node in the graph."));
-      if (this.type === 'directed') return false;
-      return neighbor in nodeData.undirected;
-    }
-    /**
-     * Method returning whether two nodes are neighbors.
-     *
-     * @param  {any}     node     - The node's key.
-     * @param  {any}     neighbor - The neighbor's key.
-     * @return {boolean}
-     *
-     * @throws {Error} - Will throw if the node isn't in the graph.
-     */
-    ;
-
-    _proto.areNeighbors = function areNeighbors(node, neighbor) {
-      node = '' + node;
-      neighbor = '' + neighbor;
-
-      var nodeData = this._nodes.get(node);
-
-      if (!nodeData) throw new NotFoundGraphError("Graph.areNeighbors: could not find the \"".concat(node, "\" node in the graph."));
-
-      if (this.type !== 'undirected') {
-        if (neighbor in nodeData["in"] || neighbor in nodeData.out) return true;
-      }
-
-      if (this.type !== 'directed') {
-        if (neighbor in nodeData.undirected) return true;
-      }
-
-      return false;
-    }
-    /**
-     * Method returning whether two nodes are inbound neighbors.
-     *
-     * @param  {any}     node     - The node's key.
-     * @param  {any}     neighbor - The neighbor's key.
-     * @return {boolean}
-     *
-     * @throws {Error} - Will throw if the node isn't in the graph.
-     */
-    ;
-
-    _proto.areInboundNeighbors = function areInboundNeighbors(node, neighbor) {
-      node = '' + node;
-      neighbor = '' + neighbor;
-
-      var nodeData = this._nodes.get(node);
-
-      if (!nodeData) throw new NotFoundGraphError("Graph.areInboundNeighbors: could not find the \"".concat(node, "\" node in the graph."));
-
-      if (this.type !== 'undirected') {
-        if (neighbor in nodeData["in"]) return true;
-      }
-
-      if (this.type !== 'directed') {
-        if (neighbor in nodeData.undirected) return true;
-      }
-
-      return false;
-    }
-    /**
-     * Method returning whether two nodes are outbound neighbors.
-     *
-     * @param  {any}     node     - The node's key.
-     * @param  {any}     neighbor - The neighbor's key.
-     * @return {boolean}
-     *
-     * @throws {Error} - Will throw if the node isn't in the graph.
-     */
-    ;
-
-    _proto.areOutboundNeighbors = function areOutboundNeighbors(node, neighbor) {
-      node = '' + node;
-      neighbor = '' + neighbor;
-
-      var nodeData = this._nodes.get(node);
-
-      if (!nodeData) throw new NotFoundGraphError("Graph.areOutboundNeighbors: could not find the \"".concat(node, "\" node in the graph."));
-
-      if (this.type !== 'undirected') {
-        if (neighbor in nodeData.out) return true;
-      }
-
-      if (this.type !== 'directed') {
-        if (neighbor in nodeData.undirected) return true;
-      }
-
-      return false;
-    }
-    /**
-     * Method returning the given node's in degree.
-     *
-     * @param  {any}     node - The node's key.
-     * @return {number}       - The node's in degree.
-     *
-     * @throws {Error} - Will throw if the node isn't in the graph.
-     */
-    ;
-
-    _proto.inDegree = function inDegree(node) {
-      node = '' + node;
-
-      var nodeData = this._nodes.get(node);
-
-      if (!nodeData) throw new NotFoundGraphError("Graph.inDegree: could not find the \"".concat(node, "\" node in the graph."));
-      if (this.type === 'undirected') return 0;
-      return nodeData.inDegree;
-    }
-    /**
-     * Method returning the given node's out degree.
-     *
-     * @param  {any}     node - The node's key.
-     * @return {number}       - The node's in degree.
-     *
-     * @throws {Error} - Will throw if the node isn't in the graph.
-     */
-    ;
-
-    _proto.outDegree = function outDegree(node) {
-      node = '' + node;
-
-      var nodeData = this._nodes.get(node);
-
-      if (!nodeData) throw new NotFoundGraphError("Graph.outDegree: could not find the \"".concat(node, "\" node in the graph."));
-      if (this.type === 'undirected') return 0;
-      return nodeData.outDegree;
-    }
-    /**
-     * Method returning the given node's directed degree.
-     *
-     * @param  {any}     node - The node's key.
-     * @return {number}       - The node's in degree.
-     *
-     * @throws {Error} - Will throw if the node isn't in the graph.
-     */
-    ;
-
-    _proto.directedDegree = function directedDegree(node) {
-      node = '' + node;
-
-      var nodeData = this._nodes.get(node);
-
-      if (!nodeData) throw new NotFoundGraphError("Graph.directedDegree: could not find the \"".concat(node, "\" node in the graph."));
-      if (this.type === 'undirected') return 0;
-      return nodeData.inDegree + nodeData.outDegree;
-    }
-    /**
-     * Method returning the given node's undirected degree.
-     *
-     * @param  {any}     node - The node's key.
-     * @return {number}       - The node's in degree.
-     *
-     * @throws {Error} - Will throw if the node isn't in the graph.
-     */
-    ;
-
-    _proto.undirectedDegree = function undirectedDegree(node) {
-      node = '' + node;
-
-      var nodeData = this._nodes.get(node);
-
-      if (!nodeData) throw new NotFoundGraphError("Graph.undirectedDegree: could not find the \"".concat(node, "\" node in the graph."));
-      if (this.type === 'directed') return 0;
-      return nodeData.undirectedDegree;
-    }
-    /**
-     * Method returning the given node's inbound degree.
-     *
-     * @param  {any}     node - The node's key.
-     * @return {number}       - The node's inbound degree.
-     *
-     * @throws {Error} - Will throw if the node isn't in the graph.
-     */
-    ;
-
-    _proto.inboundDegree = function inboundDegree(node) {
-      node = '' + node;
-
-      var nodeData = this._nodes.get(node);
-
-      if (!nodeData) throw new NotFoundGraphError("Graph.inboundDegree: could not find the \"".concat(node, "\" node in the graph."));
-      var degree = 0;
-
-      if (this.type !== 'directed') {
-        degree += nodeData.undirectedDegree;
-      }
-
-      if (this.type !== 'undirected') {
-        degree += nodeData.inDegree;
-      }
-
-      return degree;
-    }
-    /**
-     * Method returning the given node's outbound degree.
-     *
-     * @param  {any}     node - The node's key.
-     * @return {number}       - The node's outbound degree.
-     *
-     * @throws {Error} - Will throw if the node isn't in the graph.
-     */
-    ;
-
-    _proto.outboundDegree = function outboundDegree(node) {
-      node = '' + node;
-
-      var nodeData = this._nodes.get(node);
-
-      if (!nodeData) throw new NotFoundGraphError("Graph.outboundDegree: could not find the \"".concat(node, "\" node in the graph."));
-      var degree = 0;
-
-      if (this.type !== 'directed') {
-        degree += nodeData.undirectedDegree;
-      }
-
-      if (this.type !== 'undirected') {
-        degree += nodeData.outDegree;
-      }
-
-      return degree;
-    }
-    /**
-     * Method returning the given node's directed degree.
-     *
-     * @param  {any}     node - The node's key.
-     * @return {number}       - The node's degree.
-     *
-     * @throws {Error} - Will throw if the node isn't in the graph.
-     */
-    ;
-
-    _proto.degree = function degree(node) {
-      node = '' + node;
-
-      var nodeData = this._nodes.get(node);
-
-      if (!nodeData) throw new NotFoundGraphError("Graph.degree: could not find the \"".concat(node, "\" node in the graph."));
-      var degree = 0;
-
-      if (this.type !== 'directed') {
-        degree += nodeData.undirectedDegree;
-      }
-
-      if (this.type !== 'undirected') {
-        degree += nodeData.inDegree + nodeData.outDegree;
-      }
-
-      return degree;
-    }
-    /**
-     * Method returning the given node's in degree without considering self loops.
-     *
-     * @param  {any}     node - The node's key.
-     * @return {number}       - The node's in degree.
-     *
-     * @throws {Error} - Will throw if the node isn't in the graph.
-     */
-    ;
-
-    _proto.inDegreeWithoutSelfLoops = function inDegreeWithoutSelfLoops(node) {
-      node = '' + node;
-
-      var nodeData = this._nodes.get(node);
-
-      if (!nodeData) throw new NotFoundGraphError("Graph.inDegreeWithoutSelfLoops: could not find the \"".concat(node, "\" node in the graph."));
-      if (this.type === 'undirected') return 0;
-      var self = nodeData["in"][node];
-      var loops = self ? this.multi ? self.size : 1 : 0;
-      return nodeData.inDegree - loops;
-    }
-    /**
-     * Method returning the given node's out degree without considering self loops.
-     *
-     * @param  {any}     node - The node's key.
-     * @return {number}       - The node's in degree.
-     *
-     * @throws {Error} - Will throw if the node isn't in the graph.
-     */
-    ;
-
-    _proto.outDegreeWithoutSelfLoops = function outDegreeWithoutSelfLoops(node) {
-      node = '' + node;
-
-      var nodeData = this._nodes.get(node);
-
-      if (!nodeData) throw new NotFoundGraphError("Graph.outDegreeWithoutSelfLoops: could not find the \"".concat(node, "\" node in the graph."));
-      if (this.type === 'undirected') return 0;
-      var self = nodeData.out[node];
-      var loops = self ? this.multi ? self.size : 1 : 0;
-      return nodeData.outDegree - loops;
-    }
-    /**
-     * Method returning the given node's directed degree without considering self loops.
-     *
-     * @param  {any}     node - The node's key.
-     * @return {number}       - The node's in degree.
-     *
-     * @throws {Error} - Will throw if the node isn't in the graph.
-     */
-    ;
-
-    _proto.directedDegreeWithoutSelfLoops = function directedDegreeWithoutSelfLoops(node) {
-      node = '' + node;
-
-      var nodeData = this._nodes.get(node);
-
-      if (!nodeData) throw new NotFoundGraphError("Graph.directedDegreeWithoutSelfLoops: could not find the \"".concat(node, "\" node in the graph."));
-      if (this.type === 'undirected') return 0;
-      var self = nodeData.out[node];
-      var loops = self ? this.multi ? self.size : 1 : 0;
-      return nodeData.inDegree + nodeData.outDegree - loops * 2;
-    }
-    /**
-     * Method returning the given node's undirected degree without considering self loops.
-     *
-     * @param  {any}     node - The node's key.
-     * @return {number}       - The node's in degree.
-     *
-     * @throws {Error} - Will throw if the node isn't in the graph.
-     */
-    ;
-
-    _proto.undirectedDegreeWithoutSelfLoops = function undirectedDegreeWithoutSelfLoops(node) {
-      node = '' + node;
-
-      var nodeData = this._nodes.get(node);
-
-      if (!nodeData) throw new NotFoundGraphError("Graph.undirectedDegreeWithoutSelfLoops: could not find the \"".concat(node, "\" node in the graph."));
-      if (this.type === 'directed') return 0;
-      var self = nodeData.undirected[node];
-      var loops = self ? this.multi ? self.size : 1 : 0;
-      return nodeData.undirectedDegree - loops * 2;
-    }
-    /**
-     * Method returning the given node's inbound degree without considering self loops.
-     *
-     * @param  {any}     node - The node's key.
-     * @return {number}       - The node's inbound degree.
-     *
-     * @throws {Error} - Will throw if the node isn't in the graph.
-     */
-    ;
-
-    _proto.inboundDegreeWithoutSelfLoops = function inboundDegreeWithoutSelfLoops(node) {
-      node = '' + node;
-
-      var nodeData = this._nodes.get(node);
-
-      if (!nodeData) throw new NotFoundGraphError("Graph.inboundDegreeWithoutSelfLoops: could not find the \"".concat(node, "\" node in the graph."));
-      var self;
-      var degree = 0;
-      var loops = 0;
-
-      if (this.type !== 'directed') {
-        degree += nodeData.undirectedDegree;
-        self = nodeData.undirected[node];
-        loops += (self ? this.multi ? self.size : 1 : 0) * 2;
-      }
-
-      if (this.type !== 'undirected') {
-        degree += nodeData.inDegree;
-        self = nodeData.out[node];
-        loops += self ? this.multi ? self.size : 1 : 0;
-      }
-
-      return degree - loops;
-    }
-    /**
-     * Method returning the given node's outbound degree without considering self loops.
-     *
-     * @param  {any}     node - The node's key.
-     * @return {number}       - The node's outbound degree.
-     *
-     * @throws {Error} - Will throw if the node isn't in the graph.
-     */
-    ;
-
-    _proto.outboundDegreeWithoutSelfLoops = function outboundDegreeWithoutSelfLoops(node) {
-      node = '' + node;
-
-      var nodeData = this._nodes.get(node);
-
-      if (!nodeData) throw new NotFoundGraphError("Graph.outboundDegreeWithoutSelfLoops: could not find the \"".concat(node, "\" node in the graph."));
-      var self;
-      var degree = 0;
-      var loops = 0;
-
-      if (this.type !== 'directed') {
-        degree += nodeData.undirectedDegree;
-        self = nodeData.undirected[node];
-        loops += (self ? this.multi ? self.size : 1 : 0) * 2;
-      }
-
-      if (this.type !== 'undirected') {
-        degree += nodeData.outDegree;
-        self = nodeData["in"][node];
-        loops += self ? this.multi ? self.size : 1 : 0;
-      }
-
-      return degree - loops;
-    }
-    /**
-     * Method returning the given node's directed degree without considering self loops.
-     *
-     * @param  {any}     node - The node's key.
-     * @return {number}       - The node's degree.
-     *
-     * @throws {Error} - Will throw if the node isn't in the graph.
-     */
-    ;
-
-    _proto.degreeWithoutSelfLoops = function degreeWithoutSelfLoops(node) {
-      node = '' + node;
-
-      var nodeData = this._nodes.get(node);
-
-      if (!nodeData) throw new NotFoundGraphError("Graph.degreeWithoutSelfLoops: could not find the \"".concat(node, "\" node in the graph."));
-      var self;
-      var degree = 0;
-      var loops = 0;
-
-      if (this.type !== 'directed') {
-        degree += nodeData.undirectedDegree;
-        self = nodeData.undirected[node];
-        loops += (self ? this.multi ? self.size : 1 : 0) * 2;
-      }
-
-      if (this.type !== 'undirected') {
-        degree += nodeData.inDegree + nodeData.outDegree;
-        self = nodeData.out[node];
-        loops += (self ? this.multi ? self.size : 1 : 0) * 2;
-      }
-
-      return degree - loops;
-    }
-    /**
-     * Method returning the given edge's source.
-     *
-     * @param  {any} edge - The edge's key.
-     * @return {any}      - The edge's source.
-     *
-     * @throws {Error} - Will throw if the edge isn't in the graph.
-     */
-    ;
-
-    _proto.source = function source(edge) {
-      edge = '' + edge;
-
-      var data = this._edges.get(edge);
-
-      if (!data) throw new NotFoundGraphError("Graph.source: could not find the \"".concat(edge, "\" edge in the graph."));
-      return data.source.key;
-    }
-    /**
-     * Method returning the given edge's target.
-     *
-     * @param  {any} edge - The edge's key.
-     * @return {any}      - The edge's target.
-     *
-     * @throws {Error} - Will throw if the edge isn't in the graph.
-     */
-    ;
-
-    _proto.target = function target(edge) {
-      edge = '' + edge;
-
-      var data = this._edges.get(edge);
-
-      if (!data) throw new NotFoundGraphError("Graph.target: could not find the \"".concat(edge, "\" edge in the graph."));
-      return data.target.key;
-    }
-    /**
-     * Method returning the given edge's extremities.
-     *
-     * @param  {any}   edge - The edge's key.
-     * @return {array}      - The edge's extremities.
-     *
-     * @throws {Error} - Will throw if the edge isn't in the graph.
-     */
-    ;
-
-    _proto.extremities = function extremities(edge) {
-      edge = '' + edge;
-
-      var edgeData = this._edges.get(edge);
-
-      if (!edgeData) throw new NotFoundGraphError("Graph.extremities: could not find the \"".concat(edge, "\" edge in the graph."));
-      return [edgeData.source.key, edgeData.target.key];
-    }
-    /**
-     * Given a node & an edge, returns the other extremity of the edge.
-     *
-     * @param  {any}   node - The node's key.
-     * @param  {any}   edge - The edge's key.
-     * @return {any}        - The related node.
-     *
-     * @throws {Error} - Will throw if the edge isn't in the graph or if the
-     *                   edge & node are not related.
-     */
-    ;
-
-    _proto.opposite = function opposite(node, edge) {
-      node = '' + node;
-      edge = '' + edge;
-
-      var data = this._edges.get(edge);
-
-      if (!data) throw new NotFoundGraphError("Graph.opposite: could not find the \"".concat(edge, "\" edge in the graph."));
-      var source = data.source.key;
-      var target = data.target.key;
-      if (node === source) return target;
-      if (node === target) return source;
-      throw new NotFoundGraphError("Graph.opposite: the \"".concat(node, "\" node is not attached to the \"").concat(edge, "\" edge (").concat(source, ", ").concat(target, ")."));
-    }
-    /**
-     * Returns whether the given edge has the given node as extremity.
-     *
-     * @param  {any}     edge - The edge's key.
-     * @param  {any}     node - The node's key.
-     * @return {boolean}      - The related node.
-     *
-     * @throws {Error} - Will throw if either the node or the edge isn't in the graph.
-     */
-    ;
-
-    _proto.hasExtremity = function hasExtremity(edge, node) {
-      edge = '' + edge;
-      node = '' + node;
-
-      var data = this._edges.get(edge);
-
-      if (!data) throw new NotFoundGraphError("Graph.hasExtremity: could not find the \"".concat(edge, "\" edge in the graph."));
-      return data.source.key === node || data.target.key === node;
-    }
-    /**
-     * Method returning whether the given edge is undirected.
-     *
-     * @param  {any}     edge - The edge's key.
-     * @return {boolean}
-     *
-     * @throws {Error} - Will throw if the edge isn't in the graph.
-     */
-    ;
-
-    _proto.isUndirected = function isUndirected(edge) {
-      edge = '' + edge;
-
-      var data = this._edges.get(edge);
-
-      if (!data) throw new NotFoundGraphError("Graph.isUndirected: could not find the \"".concat(edge, "\" edge in the graph."));
-      return data.undirected;
-    }
-    /**
-     * Method returning whether the given edge is directed.
-     *
-     * @param  {any}     edge - The edge's key.
-     * @return {boolean}
-     *
-     * @throws {Error} - Will throw if the edge isn't in the graph.
-     */
-    ;
-
-    _proto.isDirected = function isDirected(edge) {
-      edge = '' + edge;
-
-      var data = this._edges.get(edge);
-
-      if (!data) throw new NotFoundGraphError("Graph.isDirected: could not find the \"".concat(edge, "\" edge in the graph."));
-      return !data.undirected;
-    }
-    /**
-     * Method returning whether the given edge is a self loop.
-     *
-     * @param  {any}     edge - The edge's key.
-     * @return {boolean}
-     *
-     * @throws {Error} - Will throw if the edge isn't in the graph.
-     */
-    ;
-
-    _proto.isSelfLoop = function isSelfLoop(edge) {
-      edge = '' + edge;
-
-      var data = this._edges.get(edge);
-
-      if (!data) throw new NotFoundGraphError("Graph.isSelfLoop: could not find the \"".concat(edge, "\" edge in the graph."));
-      return data.source === data.target;
-    }
-    /**---------------------------------------------------------------------------
-     * Mutation
-     **---------------------------------------------------------------------------
-     */
-
-    /**
-     * Method used to add a node to the graph.
-     *
-     * @param  {any}    node         - The node.
-     * @param  {object} [attributes] - Optional attributes.
-     * @return {any}                 - The node.
-     *
-     * @throws {Error} - Will throw if the given node already exist.
-     * @throws {Error} - Will throw if the given attributes are not an object.
-     */
-    ;
-
-    _proto.addNode = function addNode(node, attributes) {
-      var nodeData = _addNode(this, node, attributes);
-
-      return nodeData.key;
-    }
-    /**
-     * Method used to merge a node into the graph.
-     *
-     * @param  {any}    node         - The node.
-     * @param  {object} [attributes] - Optional attributes.
-     * @return {any}                 - The node.
-     */
-    ;
-
-    _proto.mergeNode = function mergeNode(node, attributes) {
-      if (attributes && !isPlainObject(attributes)) throw new InvalidArgumentsGraphError("Graph.mergeNode: invalid attributes. Expecting an object but got \"".concat(attributes, "\"")); // String coercion
-
-      node = '' + node;
-      attributes = attributes || {}; // If the node already exists, we merge the attributes
-
-      var data = this._nodes.get(node);
-
-      if (data) {
-        if (attributes) {
-          assign(data.attributes, attributes);
-          this.emit('nodeAttributesUpdated', {
-            type: 'merge',
-            key: node,
-            attributes: data.attributes,
-            data: attributes
-          });
-        }
-
-        return [node, false];
-      }
-
-      data = new this.NodeDataClass(node, attributes); // Adding the node to internal register
-
-      this._nodes.set(node, data); // Emitting
-
-
-      this.emit('nodeAdded', {
-        key: node,
-        attributes: attributes
-      });
-      return [node, true];
-    }
-    /**
-     * Method used to add a node if it does not exist in the graph or else to
-     * update its attributes using a function.
-     *
-     * @param  {any}      node      - The node.
-     * @param  {function} [updater] - Optional updater function.
-     * @return {any}                - The node.
-     */
-    ;
-
-    _proto.updateNode = function updateNode(node, updater) {
-      if (updater && typeof updater !== 'function') throw new InvalidArgumentsGraphError("Graph.updateNode: invalid updater function. Expecting a function but got \"".concat(updater, "\"")); // String coercion
-
-      node = '' + node; // If the node already exists, we update the attributes
-
-      var data = this._nodes.get(node);
-
-      if (data) {
-        if (updater) {
-          var oldAttributes = data.attributes;
-          data.attributes = updater(oldAttributes);
-          this.emit('nodeAttributesUpdated', {
-            type: 'replace',
-            key: node,
-            attributes: data.attributes
-          });
-        }
-
-        return [node, false];
-      }
-
-      var attributes = updater ? updater({}) : {};
-      data = new this.NodeDataClass(node, attributes); // Adding the node to internal register
-
-      this._nodes.set(node, data); // Emitting
-
-
-      this.emit('nodeAdded', {
-        key: node,
-        attributes: attributes
-      });
-      return [node, true];
-    }
-    /**
-     * Method used to drop a single node & all its attached edges from the graph.
-     *
-     * @param  {any}    node - The node.
-     * @return {Graph}
-     *
-     * @throws {Error} - Will throw if the node doesn't exist.
-     */
-    ;
-
-    _proto.dropNode = function dropNode(node) {
-      node = '' + node;
-
-      var nodeData = this._nodes.get(node);
-
-      if (!nodeData) throw new NotFoundGraphError("Graph.dropNode: could not find the \"".concat(node, "\" node in the graph."));
-      var edgeData; // Removing attached edges
-      // NOTE: we could be faster here, but this is such a pain to maintain
-
-      if (this.type !== 'undirected') {
-        for (var neighbor in nodeData.out) {
-          edgeData = nodeData.out[neighbor];
-
-          do {
-            dropEdgeFromData(this, edgeData);
-            edgeData = edgeData.next;
-          } while (edgeData);
-        }
-
-        for (var _neighbor in nodeData["in"]) {
-          edgeData = nodeData["in"][_neighbor];
-
-          do {
-            dropEdgeFromData(this, edgeData);
-            edgeData = edgeData.next;
-          } while (edgeData);
-        }
-      }
-
-      if (this.type !== 'directed') {
-        for (var _neighbor2 in nodeData.undirected) {
-          edgeData = nodeData.undirected[_neighbor2];
-
-          do {
-            dropEdgeFromData(this, edgeData);
-            edgeData = edgeData.next;
-          } while (edgeData);
-        }
-      } // Dropping the node from the register
-
-
-      this._nodes["delete"](node); // Emitting
-
-
-      this.emit('nodeDropped', {
-        key: node,
-        attributes: nodeData.attributes
-      });
-    }
-    /**
-     * Method used to drop a single edge from the graph.
-     *
-     * Arity 1:
-     * @param  {any}    edge - The edge.
-     *
-     * Arity 2:
-     * @param  {any}    source - Source node.
-     * @param  {any}    target - Target node.
-     *
-     * @return {Graph}
-     *
-     * @throws {Error} - Will throw if the edge doesn't exist.
-     */
-    ;
-
-    _proto.dropEdge = function dropEdge(edge) {
-      var edgeData;
-
-      if (arguments.length > 1) {
-        var source = '' + arguments[0];
-        var target = '' + arguments[1];
-        edgeData = getMatchingEdge(this, source, target, this.type);
-        if (!edgeData) throw new NotFoundGraphError("Graph.dropEdge: could not find the \"".concat(source, "\" -> \"").concat(target, "\" edge in the graph."));
-      } else {
-        edge = '' + edge;
-        edgeData = this._edges.get(edge);
-        if (!edgeData) throw new NotFoundGraphError("Graph.dropEdge: could not find the \"".concat(edge, "\" edge in the graph."));
-      }
-
-      dropEdgeFromData(this, edgeData);
-      return this;
-    }
-    /**
-     * Method used to drop a single directed edge from the graph.
-     *
-     * @param  {any}    source - Source node.
-     * @param  {any}    target - Target node.
-     *
-     * @return {Graph}
-     *
-     * @throws {Error} - Will throw if the edge doesn't exist.
-     */
-    ;
-
-    _proto.dropDirectedEdge = function dropDirectedEdge(source, target) {
-      if (arguments.length < 2) throw new UsageGraphError('Graph.dropDirectedEdge: it does not make sense to try and drop a directed edge by key. What if the edge with this key is undirected? Use #.dropEdge for this purpose instead.');
-      if (this.multi) throw new UsageGraphError('Graph.dropDirectedEdge: cannot use a {source,target} combo when dropping an edge in a MultiGraph since we cannot infer the one you want to delete as there could be multiple ones.');
-      source = '' + source;
-      target = '' + target;
-      var edgeData = getMatchingEdge(this, source, target, 'directed');
-      if (!edgeData) throw new NotFoundGraphError("Graph.dropDirectedEdge: could not find a \"".concat(source, "\" -> \"").concat(target, "\" edge in the graph."));
-      dropEdgeFromData(this, edgeData);
-      return this;
-    }
-    /**
-     * Method used to drop a single undirected edge from the graph.
-     *
-     * @param  {any}    source - Source node.
-     * @param  {any}    target - Target node.
-     *
-     * @return {Graph}
-     *
-     * @throws {Error} - Will throw if the edge doesn't exist.
-     */
-    ;
-
-    _proto.dropUndirectedEdge = function dropUndirectedEdge(source, target) {
-      if (arguments.length < 2) throw new UsageGraphError('Graph.dropUndirectedEdge: it does not make sense to drop a directed edge by key. What if the edge with this key is undirected? Use #.dropEdge for this purpose instead.');
-      if (this.multi) throw new UsageGraphError('Graph.dropUndirectedEdge: cannot use a {source,target} combo when dropping an edge in a MultiGraph since we cannot infer the one you want to delete as there could be multiple ones.');
-      var edgeData = getMatchingEdge(this, source, target, 'undirected');
-      if (!edgeData) throw new NotFoundGraphError("Graph.dropUndirectedEdge: could not find a \"".concat(source, "\" -> \"").concat(target, "\" edge in the graph."));
-      dropEdgeFromData(this, edgeData);
-      return this;
-    }
-    /**
-     * Method used to remove every edge & every node from the graph.
-     *
-     * @return {Graph}
-     */
-    ;
-
-    _proto.clear = function clear() {
-      // Clearing edges
-      this._edges.clear(); // Clearing nodes
-
-
-      this._nodes.clear(); // Reset counters
-
-
-      this._resetInstanceCounters(); // Emitting
-
-
-      this.emit('cleared');
-    }
-    /**
-     * Method used to remove every edge from the graph.
-     *
-     * @return {Graph}
-     */
-    ;
-
-    _proto.clearEdges = function clearEdges() {
-      // Clearing structure index
-      var iterator = this._nodes.values();
-
-      var step;
-
-      while (step = iterator.next(), step.done !== true) {
-        step.value.clear();
-      } // Clearing edges
-
-
-      this._edges.clear(); // Reset counters
-
-
-      this._resetInstanceCounters(); // Emitting
-
-
-      this.emit('edgesCleared');
-    }
-    /**---------------------------------------------------------------------------
-     * Attributes-related methods
-     **---------------------------------------------------------------------------
-     */
-
-    /**
-     * Method returning the desired graph's attribute.
-     *
-     * @param  {string} name - Name of the attribute.
-     * @return {any}
-     */
-    ;
-
-    _proto.getAttribute = function getAttribute(name) {
-      return this._attributes[name];
-    }
-    /**
-     * Method returning the graph's attributes.
-     *
-     * @return {object}
-     */
-    ;
-
-    _proto.getAttributes = function getAttributes() {
-      return this._attributes;
-    }
-    /**
-     * Method returning whether the graph has the desired attribute.
-     *
-     * @param  {string}  name - Name of the attribute.
-     * @return {boolean}
-     */
-    ;
-
-    _proto.hasAttribute = function hasAttribute(name) {
-      return this._attributes.hasOwnProperty(name);
-    }
-    /**
-     * Method setting a value for the desired graph's attribute.
-     *
-     * @param  {string}  name  - Name of the attribute.
-     * @param  {any}     value - Value for the attribute.
-     * @return {Graph}
-     */
-    ;
-
-    _proto.setAttribute = function setAttribute(name, value) {
-      this._attributes[name] = value; // Emitting
-
-      this.emit('attributesUpdated', {
-        type: 'set',
-        attributes: this._attributes,
-        name: name
-      });
-      return this;
-    }
-    /**
-     * Method using a function to update the desired graph's attribute's value.
-     *
-     * @param  {string}   name    - Name of the attribute.
-     * @param  {function} updater - Function use to update the attribute's value.
-     * @return {Graph}
-     */
-    ;
-
-    _proto.updateAttribute = function updateAttribute(name, updater) {
-      if (typeof updater !== 'function') throw new InvalidArgumentsGraphError('Graph.updateAttribute: updater should be a function.');
-      var value = this._attributes[name];
-      this._attributes[name] = updater(value); // Emitting
-
-      this.emit('attributesUpdated', {
-        type: 'set',
-        attributes: this._attributes,
-        name: name
-      });
-      return this;
-    }
-    /**
-     * Method removing the desired graph's attribute.
-     *
-     * @param  {string} name  - Name of the attribute.
-     * @return {Graph}
-     */
-    ;
-
-    _proto.removeAttribute = function removeAttribute(name) {
-      delete this._attributes[name]; // Emitting
-
-      this.emit('attributesUpdated', {
-        type: 'remove',
-        attributes: this._attributes,
-        name: name
-      });
-      return this;
-    }
-    /**
-     * Method replacing the graph's attributes.
-     *
-     * @param  {object} attributes - New attributes.
-     * @return {Graph}
-     *
-     * @throws {Error} - Will throw if given attributes are not a plain object.
-     */
-    ;
-
-    _proto.replaceAttributes = function replaceAttributes(attributes) {
-      if (!isPlainObject(attributes)) throw new InvalidArgumentsGraphError('Graph.replaceAttributes: provided attributes are not a plain object.');
-      this._attributes = attributes; // Emitting
-
-      this.emit('attributesUpdated', {
-        type: 'replace',
-        attributes: this._attributes
-      });
-      return this;
-    }
-    /**
-     * Method merging the graph's attributes.
-     *
-     * @param  {object} attributes - Attributes to merge.
-     * @return {Graph}
-     *
-     * @throws {Error} - Will throw if given attributes are not a plain object.
-     */
-    ;
-
-    _proto.mergeAttributes = function mergeAttributes(attributes) {
-      if (!isPlainObject(attributes)) throw new InvalidArgumentsGraphError('Graph.mergeAttributes: provided attributes are not a plain object.');
-      assign(this._attributes, attributes); // Emitting
-
-      this.emit('attributesUpdated', {
-        type: 'merge',
-        attributes: this._attributes,
-        data: attributes
-      });
-      return this;
-    }
-    /**
-     * Method updating the graph's attributes.
-     *
-     * @param  {function} updater - Function used to update the attributes.
-     * @return {Graph}
-     *
-     * @throws {Error} - Will throw if given updater is not a function.
-     */
-    ;
-
-    _proto.updateAttributes = function updateAttributes(updater) {
-      if (typeof updater !== 'function') throw new InvalidArgumentsGraphError('Graph.updateAttributes: provided updater is not a function.');
-      this._attributes = updater(this._attributes); // Emitting
-
-      this.emit('attributesUpdated', {
-        type: 'update',
-        attributes: this._attributes
-      });
-      return this;
-    }
-    /**
-     * Method used to update each node's attributes using the given function.
-     *
-     * @param {function}  updater - Updater function to use.
-     * @param {object}    [hints] - Optional hints.
-     */
-    ;
-
-    _proto.updateEachNodeAttributes = function updateEachNodeAttributes(updater, hints) {
-      if (typeof updater !== 'function') throw new InvalidArgumentsGraphError('Graph.updateEachNodeAttributes: expecting an updater function.');
-      if (hints && !validateHints(hints)) throw new InvalidArgumentsGraphError('Graph.updateEachNodeAttributes: invalid hints. Expecting an object having the following shape: {attributes?: [string]}');
-
-      var iterator = this._nodes.values();
-
-      var step, nodeData;
-
-      while (step = iterator.next(), step.done !== true) {
-        nodeData = step.value;
-        nodeData.attributes = updater(nodeData.key, nodeData.attributes);
-      }
-
-      this.emit('eachNodeAttributesUpdated', {
-        hints: hints ? hints : null
-      });
-    }
-    /**
-     * Method used to update each edge's attributes using the given function.
-     *
-     * @param {function}  updater - Updater function to use.
-     * @param {object}    [hints] - Optional hints.
-     */
-    ;
-
-    _proto.updateEachEdgeAttributes = function updateEachEdgeAttributes(updater, hints) {
-      if (typeof updater !== 'function') throw new InvalidArgumentsGraphError('Graph.updateEachEdgeAttributes: expecting an updater function.');
-      if (hints && !validateHints(hints)) throw new InvalidArgumentsGraphError('Graph.updateEachEdgeAttributes: invalid hints. Expecting an object having the following shape: {attributes?: [string]}');
-
-      var iterator = this._edges.values();
-
-      var step, edgeData, sourceData, targetData;
-
-      while (step = iterator.next(), step.done !== true) {
-        edgeData = step.value;
-        sourceData = edgeData.source;
-        targetData = edgeData.target;
-        edgeData.attributes = updater(edgeData.key, edgeData.attributes, sourceData.key, targetData.key, sourceData.attributes, targetData.attributes, edgeData.undirected);
-      }
-
-      this.emit('eachEdgeAttributesUpdated', {
-        hints: hints ? hints : null
-      });
-    }
-    /**---------------------------------------------------------------------------
-     * Iteration-related methods
-     **---------------------------------------------------------------------------
-     */
-
-    /**
-     * Method iterating over the graph's adjacency using the given callback.
-     *
-     * @param  {function}  callback - Callback to use.
-     */
-    ;
-
-    _proto.forEachAdjacencyEntry = function forEachAdjacencyEntry(callback) {
-      if (typeof callback !== 'function') throw new InvalidArgumentsGraphError('Graph.forEachAdjacencyEntry: expecting a callback.');
-      forEachAdjacency(false, false, false, this, callback);
-    };
-
-    _proto.forEachAdjacencyEntryWithOrphans = function forEachAdjacencyEntryWithOrphans(callback) {
-      if (typeof callback !== 'function') throw new InvalidArgumentsGraphError('Graph.forEachAdjacencyEntryWithOrphans: expecting a callback.');
-      forEachAdjacency(false, false, true, this, callback);
-    }
-    /**
-     * Method iterating over the graph's assymetric adjacency using the given callback.
-     *
-     * @param  {function}  callback - Callback to use.
-     */
-    ;
-
-    _proto.forEachAssymetricAdjacencyEntry = function forEachAssymetricAdjacencyEntry(callback) {
-      if (typeof callback !== 'function') throw new InvalidArgumentsGraphError('Graph.forEachAssymetricAdjacencyEntry: expecting a callback.');
-      forEachAdjacency(false, true, false, this, callback);
-    };
-
-    _proto.forEachAssymetricAdjacencyEntryWithOrphans = function forEachAssymetricAdjacencyEntryWithOrphans(callback) {
-      if (typeof callback !== 'function') throw new InvalidArgumentsGraphError('Graph.forEachAssymetricAdjacencyEntryWithOrphans: expecting a callback.');
-      forEachAdjacency(false, true, true, this, callback);
-    }
-    /**
-     * Method returning the list of the graph's nodes.
-     *
-     * @return {array} - The nodes.
-     */
-    ;
-
-    _proto.nodes = function nodes() {
-      if (typeof Array.from === 'function') return Array.from(this._nodes.keys());
-      return take(this._nodes.keys(), this._nodes.size);
-    }
-    /**
-     * Method iterating over the graph's nodes using the given callback.
-     *
-     * @param  {function}  callback - Callback (key, attributes, index).
-     */
-    ;
-
-    _proto.forEachNode = function forEachNode(callback) {
-      if (typeof callback !== 'function') throw new InvalidArgumentsGraphError('Graph.forEachNode: expecting a callback.');
-
-      var iterator = this._nodes.values();
-
-      var step, nodeData;
-
-      while (step = iterator.next(), step.done !== true) {
-        nodeData = step.value;
-        callback(nodeData.key, nodeData.attributes);
-      }
-    }
-    /**
-     * Method iterating attempting to find a node matching the given predicate
-     * function.
-     *
-     * @param  {function}  callback - Callback (key, attributes).
-     */
-    ;
-
-    _proto.findNode = function findNode(callback) {
-      if (typeof callback !== 'function') throw new InvalidArgumentsGraphError('Graph.findNode: expecting a callback.');
-
-      var iterator = this._nodes.values();
-
-      var step, nodeData;
-
-      while (step = iterator.next(), step.done !== true) {
-        nodeData = step.value;
-        if (callback(nodeData.key, nodeData.attributes)) return nodeData.key;
-      }
-
-      return;
-    }
-    /**
-     * Method mapping nodes.
-     *
-     * @param  {function}  callback - Callback (key, attributes).
-     */
-    ;
-
-    _proto.mapNodes = function mapNodes(callback) {
-      if (typeof callback !== 'function') throw new InvalidArgumentsGraphError('Graph.mapNode: expecting a callback.');
-
-      var iterator = this._nodes.values();
-
-      var step, nodeData;
-      var result = new Array(this.order);
-      var i = 0;
-
-      while (step = iterator.next(), step.done !== true) {
-        nodeData = step.value;
-        result[i++] = callback(nodeData.key, nodeData.attributes);
-      }
-
-      return result;
-    }
-    /**
-     * Method returning whether some node verify the given predicate.
-     *
-     * @param  {function}  callback - Callback (key, attributes).
-     */
-    ;
-
-    _proto.someNode = function someNode(callback) {
-      if (typeof callback !== 'function') throw new InvalidArgumentsGraphError('Graph.someNode: expecting a callback.');
-
-      var iterator = this._nodes.values();
-
-      var step, nodeData;
-
-      while (step = iterator.next(), step.done !== true) {
-        nodeData = step.value;
-        if (callback(nodeData.key, nodeData.attributes)) return true;
-      }
-
-      return false;
-    }
-    /**
-     * Method returning whether all node verify the given predicate.
-     *
-     * @param  {function}  callback - Callback (key, attributes).
-     */
-    ;
-
-    _proto.everyNode = function everyNode(callback) {
-      if (typeof callback !== 'function') throw new InvalidArgumentsGraphError('Graph.everyNode: expecting a callback.');
-
-      var iterator = this._nodes.values();
-
-      var step, nodeData;
-
-      while (step = iterator.next(), step.done !== true) {
-        nodeData = step.value;
-        if (!callback(nodeData.key, nodeData.attributes)) return false;
-      }
-
-      return true;
-    }
-    /**
-     * Method filtering nodes.
-     *
-     * @param  {function}  callback - Callback (key, attributes).
-     */
-    ;
-
-    _proto.filterNodes = function filterNodes(callback) {
-      if (typeof callback !== 'function') throw new InvalidArgumentsGraphError('Graph.filterNodes: expecting a callback.');
-
-      var iterator = this._nodes.values();
-
-      var step, nodeData;
-      var result = [];
-
-      while (step = iterator.next(), step.done !== true) {
-        nodeData = step.value;
-        if (callback(nodeData.key, nodeData.attributes)) result.push(nodeData.key);
-      }
-
-      return result;
-    }
-    /**
-     * Method reducing nodes.
-     *
-     * @param  {function}  callback - Callback (accumulator, key, attributes).
-     */
-    ;
-
-    _proto.reduceNodes = function reduceNodes(callback, initialValue) {
-      if (typeof callback !== 'function') throw new InvalidArgumentsGraphError('Graph.reduceNodes: expecting a callback.');
-      if (arguments.length < 2) throw new InvalidArgumentsGraphError('Graph.reduceNodes: missing initial value. You must provide it because the callback takes more than one argument and we cannot infer the initial value from the first iteration, as you could with a simple array.');
-      var accumulator = initialValue;
-
-      var iterator = this._nodes.values();
-
-      var step, nodeData;
-
-      while (step = iterator.next(), step.done !== true) {
-        nodeData = step.value;
-        accumulator = callback(accumulator, nodeData.key, nodeData.attributes);
-      }
-
-      return accumulator;
-    }
-    /**
-     * Method returning an iterator over the graph's node entries.
-     *
-     * @return {Iterator}
-     */
-    ;
-
-    _proto.nodeEntries = function nodeEntries() {
-      var iterator$1 = this._nodes.values();
-
-      return new iterator(function () {
-        var step = iterator$1.next();
-        if (step.done) return step;
-        var data = step.value;
-        return {
-          value: {
-            node: data.key,
-            attributes: data.attributes
-          },
-          done: false
-        };
-      });
-    }
-    /**---------------------------------------------------------------------------
-     * Serialization
-     **---------------------------------------------------------------------------
-     */
-
-    /**
-     * Method used to export the whole graph.
-     *
-     * @return {object} - The serialized graph.
-     */
-    ;
-
-    _proto["export"] = function _export() {
-      var nodes = new Array(this._nodes.size);
-      var i = 0;
-
-      this._nodes.forEach(function (data, key) {
-        nodes[i++] = serializeNode(key, data);
-      });
-
-      var edges = new Array(this._edges.size);
-      i = 0;
-
-      this._edges.forEach(function (data, key) {
-        edges[i++] = serializeEdge(key, data);
-      });
-
-      return {
-        options: {
-          type: this.type,
-          multi: this.multi,
-          allowSelfLoops: this.allowSelfLoops
-        },
-        attributes: this.getAttributes(),
-        nodes: nodes,
-        edges: edges
-      };
-    }
-    /**
-     * Method used to import a serialized graph.
-     *
-     * @param  {object|Graph} data  - The serialized graph.
-     * @param  {boolean}      merge - Whether to merge data.
-     * @return {Graph}              - Returns itself for chaining.
-     */
-    ;
-
-    _proto["import"] = function _import(data) {
-      var _this2 = this;
-
-      var merge = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
-
-      // Importing a Graph instance directly
-      if (isGraph(data)) {
-        // Nodes
-        data.forEachNode(function (n, a) {
-          if (merge) _this2.mergeNode(n, a);else _this2.addNode(n, a);
-        }); // Edges
-
-        data.forEachEdge(function (e, a, s, t, _sa, _ta, u) {
-          if (merge) {
-            if (u) _this2.mergeUndirectedEdgeWithKey(e, s, t, a);else _this2.mergeDirectedEdgeWithKey(e, s, t, a);
-          } else {
-            if (u) _this2.addUndirectedEdgeWithKey(e, s, t, a);else _this2.addDirectedEdgeWithKey(e, s, t, a);
-          }
-        });
-        return this;
-      } // Importing a serialized graph
-
-
-      if (!isPlainObject(data)) throw new InvalidArgumentsGraphError('Graph.import: invalid argument. Expecting a serialized graph or, alternatively, a Graph instance.');
-
-      if (data.attributes) {
-        if (!isPlainObject(data.attributes)) throw new InvalidArgumentsGraphError('Graph.import: invalid attributes. Expecting a plain object.');
-        if (merge) this.mergeAttributes(data.attributes);else this.replaceAttributes(data.attributes);
-      }
-
-      var i, l, list, node, edge;
-
-      if (data.nodes) {
-        list = data.nodes;
-        if (!Array.isArray(list)) throw new InvalidArgumentsGraphError('Graph.import: invalid nodes. Expecting an array.');
-
-        for (i = 0, l = list.length; i < l; i++) {
-          node = list[i]; // Validating
-
-          validateSerializedNode(node); // Adding the node
-
-          var _node = node,
-              key = _node.key,
-              attributes = _node.attributes;
-          if (merge) this.mergeNode(key, attributes);else this.addNode(key, attributes);
-        }
-      }
-
-      if (data.edges) {
-        list = data.edges;
-        if (!Array.isArray(list)) throw new InvalidArgumentsGraphError('Graph.import: invalid edges. Expecting an array.');
-
-        for (i = 0, l = list.length; i < l; i++) {
-          edge = list[i]; // Validating
-
-          validateSerializedEdge(edge); // Adding the edge
-
-          var _edge = edge,
-              source = _edge.source,
-              target = _edge.target,
-              _attributes = _edge.attributes,
-              _edge$undirected = _edge.undirected,
-              undirected = _edge$undirected === void 0 ? false : _edge$undirected;
-          var method = void 0;
-
-          if ('key' in edge) {
-            method = merge ? undirected ? this.mergeUndirectedEdgeWithKey : this.mergeDirectedEdgeWithKey : undirected ? this.addUndirectedEdgeWithKey : this.addDirectedEdgeWithKey;
-            method.call(this, edge.key, source, target, _attributes);
-          } else {
-            method = merge ? undirected ? this.mergeUndirectedEdge : this.mergeDirectedEdge : undirected ? this.addUndirectedEdge : this.addDirectedEdge;
-            method.call(this, source, target, _attributes);
-          }
-        }
-      }
-
-      return this;
-    }
-    /**---------------------------------------------------------------------------
-     * Utils
-     **---------------------------------------------------------------------------
-     */
-
-    /**
-     * Method returning a null copy of the graph, i.e. a graph without nodes
-     * & edges but with the exact same options.
-     *
-     * @param  {object} options - Options to merge with the current ones.
-     * @return {Graph}          - The null copy.
-     */
-    ;
-
-    _proto.nullCopy = function nullCopy(options) {
-      var graph = new Graph(assign({}, this._options, options));
-      graph.replaceAttributes(assign({}, this.getAttributes()));
-      return graph;
-    }
-    /**
-     * Method returning an empty copy of the graph, i.e. a graph without edges but
-     * with the exact same options.
-     *
-     * @param  {object} options - Options to merge with the current ones.
-     * @return {Graph}          - The empty copy.
-     */
-    ;
-
-    _proto.emptyCopy = function emptyCopy(options) {
-      var graph = this.nullCopy(options);
-
-      this._nodes.forEach(function (nodeData, key) {
-        var attributes = assign({}, nodeData.attributes); // NOTE: no need to emit events since user cannot access the instance yet
-
-        nodeData = new graph.NodeDataClass(key, attributes);
-
-        graph._nodes.set(key, nodeData);
-      });
-
-      return graph;
-    }
-    /**
-     * Method returning an exact copy of the graph.
-     *
-     * @param  {object} options - Upgrade options.
-     * @return {Graph}          - The copy.
-     */
-    ;
-
-    _proto.copy = function copy(options) {
-      options = options || {};
-      if (typeof options.type === 'string' && options.type !== this.type && options.type !== 'mixed') throw new UsageGraphError("Graph.copy: cannot create an incompatible copy from \"".concat(this.type, "\" type to \"").concat(options.type, "\" because this would mean losing information about the current graph."));
-      if (typeof options.multi === 'boolean' && options.multi !== this.multi && options.multi !== true) throw new UsageGraphError('Graph.copy: cannot create an incompatible copy by downgrading a multi graph to a simple one because this would mean losing information about the current graph.');
-      if (typeof options.allowSelfLoops === 'boolean' && options.allowSelfLoops !== this.allowSelfLoops && options.allowSelfLoops !== true) throw new UsageGraphError('Graph.copy: cannot create an incompatible copy from a graph allowing self loops to one that does not because this would mean losing information about the current graph.');
-      var graph = this.emptyCopy(options);
-
-      var iterator = this._edges.values();
-
-      var step, edgeData;
-
-      while (step = iterator.next(), step.done !== true) {
-        edgeData = step.value; // NOTE: no need to emit events since user cannot access the instance yet
-
-        addEdge(graph, 'copy', false, edgeData.undirected, edgeData.key, edgeData.source.key, edgeData.target.key, assign({}, edgeData.attributes));
-      }
-
-      return graph;
-    }
-    /**---------------------------------------------------------------------------
-     * Known methods
-     **---------------------------------------------------------------------------
-     */
-
-    /**
-     * Method used by JavaScript to perform JSON serialization.
-     *
-     * @return {object} - The serialized graph.
-     */
-    ;
-
-    _proto.toJSON = function toJSON() {
-      return this["export"]();
-    }
-    /**
-     * Method returning [object Graph].
-     */
-    ;
-
-    _proto.toString = function toString() {
-      return '[object Graph]';
-    }
-    /**
-     * Method used internally by node's console to display a custom object.
-     *
-     * @return {object} - Formatted object representation of the graph.
-     */
-    ;
-
-    _proto.inspect = function inspect() {
-      var _this3 = this;
-
-      var nodes = {};
-
-      this._nodes.forEach(function (data, key) {
-        nodes[key] = data.attributes;
-      });
-
-      var edges = {},
-          multiIndex = {};
-
-      this._edges.forEach(function (data, key) {
-        var direction = data.undirected ? '--' : '->';
-        var label = '';
-        var source = data.source.key;
-        var target = data.target.key;
-        var tmp;
-
-        if (data.undirected && source > target) {
-          tmp = source;
-          source = target;
-          target = tmp;
-        }
-
-        var desc = "(".concat(source, ")").concat(direction, "(").concat(target, ")");
-
-        if (!key.startsWith('geid_')) {
-          label += "[".concat(key, "]: ");
-        } else if (_this3.multi) {
-          if (typeof multiIndex[desc] === 'undefined') {
-            multiIndex[desc] = 0;
-          } else {
-            multiIndex[desc]++;
-          }
-
-          label += "".concat(multiIndex[desc], ". ");
-        }
-
-        label += desc;
-        edges[label] = data.attributes;
-      });
-
-      var dummy = {};
-
-      for (var k in this) {
-        if (this.hasOwnProperty(k) && !EMITTER_PROPS.has(k) && typeof this[k] !== 'function' && _typeof(k) !== 'symbol') dummy[k] = this[k];
-      }
-
-      dummy.attributes = this._attributes;
-      dummy.nodes = nodes;
-      dummy.edges = edges;
-      privateProperty(dummy, 'constructor', this.constructor);
-      return dummy;
-    };
-
-    return Graph;
-  }(events.exports.EventEmitter);
-  if (typeof Symbol !== 'undefined') Graph.prototype[Symbol["for"]('nodejs.util.inspect.custom')] = Graph.prototype.inspect;
-  /**
-   * Related to edge addition.
-   */
-
-  EDGE_ADD_METHODS.forEach(function (method) {
-    ['add', 'merge', 'update'].forEach(function (verb) {
-      var name = method.name(verb);
-      var fn = verb === 'add' ? addEdge : mergeEdge;
-
-      if (method.generateKey) {
-        Graph.prototype[name] = function (source, target, attributes) {
-          return fn(this, name, true, (method.type || this.type) === 'undirected', null, source, target, attributes, verb === 'update');
-        };
-      } else {
-        Graph.prototype[name] = function (edge, source, target, attributes) {
-          return fn(this, name, false, (method.type || this.type) === 'undirected', edge, source, target, attributes, verb === 'update');
-        };
-      }
-    });
-  });
-  /**
-   * Attributes-related.
-   */
-
-  attachNodeAttributesMethods(Graph);
-  attachEdgeAttributesMethods(Graph);
-  /**
-   * Edge iteration-related.
-   */
-
-  attachEdgeIterationMethods(Graph);
-  /**
-   * Neighbor iteration-related.
-   */
-
-  attachNeighborIterationMethods(Graph);
-
-  /**
-   * Alternative constructors.
-   */
-
-  var DirectedGraph = /*#__PURE__*/function (_Graph) {
-    _inheritsLoose(DirectedGraph, _Graph);
-
-    function DirectedGraph(options) {
-      var finalOptions = assign({
-        type: 'directed'
-      }, options);
-      if ('multi' in finalOptions && finalOptions.multi !== false) throw new InvalidArgumentsGraphError('DirectedGraph.from: inconsistent indication that the graph should be multi in given options!');
-      if (finalOptions.type !== 'directed') throw new InvalidArgumentsGraphError('DirectedGraph.from: inconsistent "' + finalOptions.type + '" type in given options!');
-      return _Graph.call(this, finalOptions) || this;
-    }
-
-    return DirectedGraph;
-  }(Graph);
-
-  var UndirectedGraph = /*#__PURE__*/function (_Graph2) {
-    _inheritsLoose(UndirectedGraph, _Graph2);
-
-    function UndirectedGraph(options) {
-      var finalOptions = assign({
-        type: 'undirected'
-      }, options);
-      if ('multi' in finalOptions && finalOptions.multi !== false) throw new InvalidArgumentsGraphError('UndirectedGraph.from: inconsistent indication that the graph should be multi in given options!');
-      if (finalOptions.type !== 'undirected') throw new InvalidArgumentsGraphError('UndirectedGraph.from: inconsistent "' + finalOptions.type + '" type in given options!');
-      return _Graph2.call(this, finalOptions) || this;
-    }
-
-    return UndirectedGraph;
-  }(Graph);
-
-  var MultiGraph = /*#__PURE__*/function (_Graph3) {
-    _inheritsLoose(MultiGraph, _Graph3);
-
-    function MultiGraph(options) {
-      var finalOptions = assign({
-        multi: true
-      }, options);
-      if ('multi' in finalOptions && finalOptions.multi !== true) throw new InvalidArgumentsGraphError('MultiGraph.from: inconsistent indication that the graph should be simple in given options!');
-      return _Graph3.call(this, finalOptions) || this;
-    }
-
-    return MultiGraph;
-  }(Graph);
-
-  var MultiDirectedGraph = /*#__PURE__*/function (_Graph4) {
-    _inheritsLoose(MultiDirectedGraph, _Graph4);
-
-    function MultiDirectedGraph(options) {
-      var finalOptions = assign({
-        type: 'directed',
-        multi: true
-      }, options);
-      if ('multi' in finalOptions && finalOptions.multi !== true) throw new InvalidArgumentsGraphError('MultiDirectedGraph.from: inconsistent indication that the graph should be simple in given options!');
-      if (finalOptions.type !== 'directed') throw new InvalidArgumentsGraphError('MultiDirectedGraph.from: inconsistent "' + finalOptions.type + '" type in given options!');
-      return _Graph4.call(this, finalOptions) || this;
-    }
-
-    return MultiDirectedGraph;
-  }(Graph);
-
-  var MultiUndirectedGraph = /*#__PURE__*/function (_Graph5) {
-    _inheritsLoose(MultiUndirectedGraph, _Graph5);
-
-    function MultiUndirectedGraph(options) {
-      var finalOptions = assign({
-        type: 'undirected',
-        multi: true
-      }, options);
-      if ('multi' in finalOptions && finalOptions.multi !== true) throw new InvalidArgumentsGraphError('MultiUndirectedGraph.from: inconsistent indication that the graph should be simple in given options!');
-      if (finalOptions.type !== 'undirected') throw new InvalidArgumentsGraphError('MultiUndirectedGraph.from: inconsistent "' + finalOptions.type + '" type in given options!');
-      return _Graph5.call(this, finalOptions) || this;
-    }
-
-    return MultiUndirectedGraph;
-  }(Graph);
-  /**
-   * Attaching static #.from method to each of the constructors.
-   */
-
-
-  function attachStaticFromMethod(Class) {
-    /**
-     * Builds a graph from serialized data or another graph's data.
-     *
-     * @param  {Graph|SerializedGraph} data      - Hydratation data.
-     * @param  {object}                [options] - Options.
-     * @return {Class}
-     */
-    Class.from = function (data, options) {
-      // Merging given options with serialized ones
-      var finalOptions = assign({}, data.options, options);
-      var instance = new Class(finalOptions);
-      instance["import"](data);
-      return instance;
-    };
-  }
-
-  attachStaticFromMethod(Graph);
-  attachStaticFromMethod(DirectedGraph);
-  attachStaticFromMethod(UndirectedGraph);
-  attachStaticFromMethod(MultiGraph);
-  attachStaticFromMethod(MultiDirectedGraph);
-  attachStaticFromMethod(MultiUndirectedGraph);
-  Graph.Graph = Graph;
-  Graph.DirectedGraph = DirectedGraph;
-  Graph.UndirectedGraph = UndirectedGraph;
-  Graph.MultiGraph = MultiGraph;
-  Graph.MultiDirectedGraph = MultiDirectedGraph;
-  Graph.MultiUndirectedGraph = MultiUndirectedGraph;
-  Graph.InvalidArgumentsGraphError = InvalidArgumentsGraphError;
-  Graph.NotFoundGraphError = NotFoundGraphError;
-  Graph.UsageGraphError = UsageGraphError;
-
-  /**
-   * Graphology CommonJS Endoint
-   * ============================
-   *
-   * Endpoint for CommonJS modules consumers.
-   */
-
-  return Graph;
-
-}));
-//# sourceMappingURL=graphology.umd.js.map
diff --git a/libs/shared/graph-layouts/node_modules/graphology/dist/graphology.umd.min.js b/libs/shared/graph-layouts/node_modules/graphology/dist/graphology.umd.min.js
deleted file mode 100644
index 9cb5b8ff2..000000000
--- a/libs/shared/graph-layouts/node_modules/graphology/dist/graphology.umd.min.js
+++ /dev/null
@@ -1,2 +0,0 @@
-!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).graphology=e()}(this,(function(){"use strict";function t(e){return t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},t(e)}function e(t,e){t.prototype=Object.create(e.prototype),t.prototype.constructor=t,r(t,e)}function n(t){return n=Object.setPrototypeOf?Object.getPrototypeOf:function(t){return t.__proto__||Object.getPrototypeOf(t)},n(t)}function r(t,e){return r=Object.setPrototypeOf||function(t,e){return t.__proto__=e,t},r(t,e)}function i(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],(function(){}))),!0}catch(t){return!1}}function o(t,e,n){return o=i()?Reflect.construct:function(t,e,n){var i=[null];i.push.apply(i,e);var o=new(Function.bind.apply(t,i));return n&&r(o,n.prototype),o},o.apply(null,arguments)}function a(t){var e="function"==typeof Map?new Map:void 0;return a=function(t){if(null===t||(i=t,-1===Function.toString.call(i).indexOf("[native code]")))return t;var i;if("function"!=typeof t)throw new TypeError("Super expression must either be null or a function");if(void 0!==e){if(e.has(t))return e.get(t);e.set(t,a)}function a(){return o(t,arguments,n(this).constructor)}return a.prototype=Object.create(t.prototype,{constructor:{value:a,enumerable:!1,writable:!0,configurable:!0}}),r(a,t)},a(t)}function u(t){if(void 0===t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return t}var c=function(){for(var t=arguments[0],e=1,n=arguments.length;e<n;e++)if(arguments[e])for(var r in arguments[e])t[r]=arguments[e][r];return t};function s(t,e,n,r){var i=t._nodes.get(e),o=null;return i?o="mixed"===r?i.out&&i.out[n]||i.undirected&&i.undirected[n]:"directed"===r?i.out&&i.out[n]:i.undirected&&i.undirected[n]:o}function d(e){return null!==e&&"object"===t(e)&&"function"==typeof e.addUndirectedEdgeWithKey&&"function"==typeof e.dropNode}function h(e){return"object"===t(e)&&null!==e&&e.constructor===Object}function p(t){var e;for(e in t)return!1;return!0}function f(t,e,n){Object.defineProperty(t,e,{enumerable:!1,configurable:!1,writable:!0,value:n})}function l(t,e,n){var r={enumerable:!0,configurable:!0};"function"==typeof n?r.get=n:(r.value=n,r.writable=!1),Object.defineProperty(t,e,r)}function g(t){return!!h(t)&&!(t.attributes&&!Array.isArray(t.attributes))}"function"==typeof Object.assign&&(c=Object.assign);var y,w={exports:{}},v="object"==typeof Reflect?Reflect:null,b=v&&"function"==typeof v.apply?v.apply:function(t,e,n){return Function.prototype.apply.call(t,e,n)};y=v&&"function"==typeof v.ownKeys?v.ownKeys:Object.getOwnPropertySymbols?function(t){return Object.getOwnPropertyNames(t).concat(Object.getOwnPropertySymbols(t))}:function(t){return Object.getOwnPropertyNames(t)};var m=Number.isNaN||function(t){return t!=t};function k(){k.init.call(this)}w.exports=k,w.exports.once=function(t,e){return new Promise((function(n,r){function i(n){t.removeListener(e,o),r(n)}function o(){"function"==typeof t.removeListener&&t.removeListener("error",i),n([].slice.call(arguments))}N(t,e,o,{once:!0}),"error"!==e&&function(t,e,n){"function"==typeof t.on&&N(t,"error",e,n)}(t,i,{once:!0})}))},k.EventEmitter=k,k.prototype._events=void 0,k.prototype._eventsCount=0,k.prototype._maxListeners=void 0;var _=10;function G(t){if("function"!=typeof t)throw new TypeError('The "listener" argument must be of type Function. Received type '+typeof t)}function x(t){return void 0===t._maxListeners?k.defaultMaxListeners:t._maxListeners}function E(t,e,n,r){var i,o,a,u;if(G(n),void 0===(o=t._events)?(o=t._events=Object.create(null),t._eventsCount=0):(void 0!==o.newListener&&(t.emit("newListener",e,n.listener?n.listener:n),o=t._events),a=o[e]),void 0===a)a=o[e]=n,++t._eventsCount;else if("function"==typeof a?a=o[e]=r?[n,a]:[a,n]:r?a.unshift(n):a.push(n),(i=x(t))>0&&a.length>i&&!a.warned){a.warned=!0;var c=new Error("Possible EventEmitter memory leak detected. "+a.length+" "+String(e)+" listeners added. Use emitter.setMaxListeners() to increase limit");c.name="MaxListenersExceededWarning",c.emitter=t,c.type=e,c.count=a.length,u=c,console&&console.warn&&console.warn(u)}return t}function A(){if(!this.fired)return this.target.removeListener(this.type,this.wrapFn),this.fired=!0,0===arguments.length?this.listener.call(this.target):this.listener.apply(this.target,arguments)}function S(t,e,n){var r={fired:!1,wrapFn:void 0,target:t,type:e,listener:n},i=A.bind(r);return i.listener=n,r.wrapFn=i,i}function D(t,e,n){var r=t._events;if(void 0===r)return[];var i=r[e];return void 0===i?[]:"function"==typeof i?n?[i.listener||i]:[i]:n?function(t){for(var e=new Array(t.length),n=0;n<e.length;++n)e[n]=t[n].listener||t[n];return e}(i):U(i,i.length)}function L(t){var e=this._events;if(void 0!==e){var n=e[t];if("function"==typeof n)return 1;if(void 0!==n)return n.length}return 0}function U(t,e){for(var n=new Array(e),r=0;r<e;++r)n[r]=t[r];return n}function N(t,e,n,r){if("function"==typeof t.on)r.once?t.once(e,n):t.on(e,n);else{if("function"!=typeof t.addEventListener)throw new TypeError('The "emitter" argument must be of type EventEmitter. Received type '+typeof t);t.addEventListener(e,(function i(o){r.once&&t.removeEventListener(e,i),n(o)}))}}function j(t){if("function"!=typeof t)throw new Error("obliterator/iterator: expecting a function!");this.next=t}Object.defineProperty(k,"defaultMaxListeners",{enumerable:!0,get:function(){return _},set:function(t){if("number"!=typeof t||t<0||m(t))throw new RangeError('The value of "defaultMaxListeners" is out of range. It must be a non-negative number. Received '+t+".");_=t}}),k.init=function(){void 0!==this._events&&this._events!==Object.getPrototypeOf(this)._events||(this._events=Object.create(null),this._eventsCount=0),this._maxListeners=this._maxListeners||void 0},k.prototype.setMaxListeners=function(t){if("number"!=typeof t||t<0||m(t))throw new RangeError('The value of "n" is out of range. It must be a non-negative number. Received '+t+".");return this._maxListeners=t,this},k.prototype.getMaxListeners=function(){return x(this)},k.prototype.emit=function(t){for(var e=[],n=1;n<arguments.length;n++)e.push(arguments[n]);var r="error"===t,i=this._events;if(void 0!==i)r=r&&void 0===i.error;else if(!r)return!1;if(r){var o;if(e.length>0&&(o=e[0]),o instanceof Error)throw o;var a=new Error("Unhandled error."+(o?" ("+o.message+")":""));throw a.context=o,a}var u=i[t];if(void 0===u)return!1;if("function"==typeof u)b(u,this,e);else{var c=u.length,s=U(u,c);for(n=0;n<c;++n)b(s[n],this,e)}return!0},k.prototype.addListener=function(t,e){return E(this,t,e,!1)},k.prototype.on=k.prototype.addListener,k.prototype.prependListener=function(t,e){return E(this,t,e,!0)},k.prototype.once=function(t,e){return G(e),this.on(t,S(this,t,e)),this},k.prototype.prependOnceListener=function(t,e){return G(e),this.prependListener(t,S(this,t,e)),this},k.prototype.removeListener=function(t,e){var n,r,i,o,a;if(G(e),void 0===(r=this._events))return this;if(void 0===(n=r[t]))return this;if(n===e||n.listener===e)0==--this._eventsCount?this._events=Object.create(null):(delete r[t],r.removeListener&&this.emit("removeListener",t,n.listener||e));else if("function"!=typeof n){for(i=-1,o=n.length-1;o>=0;o--)if(n[o]===e||n[o].listener===e){a=n[o].listener,i=o;break}if(i<0)return this;0===i?n.shift():function(t,e){for(;e+1<t.length;e++)t[e]=t[e+1];t.pop()}(n,i),1===n.length&&(r[t]=n[0]),void 0!==r.removeListener&&this.emit("removeListener",t,a||e)}return this},k.prototype.off=k.prototype.removeListener,k.prototype.removeAllListeners=function(t){var e,n,r;if(void 0===(n=this._events))return this;if(void 0===n.removeListener)return 0===arguments.length?(this._events=Object.create(null),this._eventsCount=0):void 0!==n[t]&&(0==--this._eventsCount?this._events=Object.create(null):delete n[t]),this;if(0===arguments.length){var i,o=Object.keys(n);for(r=0;r<o.length;++r)"removeListener"!==(i=o[r])&&this.removeAllListeners(i);return this.removeAllListeners("removeListener"),this._events=Object.create(null),this._eventsCount=0,this}if("function"==typeof(e=n[t]))this.removeListener(t,e);else if(void 0!==e)for(r=e.length-1;r>=0;r--)this.removeListener(t,e[r]);return this},k.prototype.listeners=function(t){return D(this,t,!0)},k.prototype.rawListeners=function(t){return D(this,t,!1)},k.listenerCount=function(t,e){return"function"==typeof t.listenerCount?t.listenerCount(e):L.call(t,e)},k.prototype.listenerCount=L,k.prototype.eventNames=function(){return this._eventsCount>0?y(this._events):[]},"undefined"!=typeof Symbol&&(j.prototype[Symbol.iterator]=function(){return this}),j.of=function(){var t=arguments,e=t.length,n=0;return new j((function(){return n>=e?{done:!0}:{done:!1,value:t[n++]}}))},j.empty=function(){return new j((function(){return{done:!0}}))},j.fromSequence=function(t){var e=0,n=t.length;return new j((function(){return e>=n?{done:!0}:{done:!1,value:t[e++]}}))},j.is=function(t){return t instanceof j||"object"==typeof t&&null!==t&&"function"==typeof t.next};var O=j,C={};C.ARRAY_BUFFER_SUPPORT="undefined"!=typeof ArrayBuffer,C.SYMBOL_SUPPORT="undefined"!=typeof Symbol;var z=O,M=C,W=M.ARRAY_BUFFER_SUPPORT,P=M.SYMBOL_SUPPORT;var R=function(t){var e=function(t){return"string"==typeof t||Array.isArray(t)||W&&ArrayBuffer.isView(t)?z.fromSequence(t):"object"!=typeof t||null===t?null:P&&"function"==typeof t[Symbol.iterator]?t[Symbol.iterator]():"function"==typeof t.next?t:null}(t);if(!e)throw new Error("obliterator: target is not iterable nor a valid iterator.");return e},K=R,T=function(t,e){for(var n,r=arguments.length>1?e:1/0,i=r!==1/0?new Array(r):[],o=0,a=K(t);;){if(o===r)return i;if((n=a.next()).done)return o!==e&&(i.length=o),i;i[o++]=n.value}},B=function(t){function n(e){var n;return(n=t.call(this)||this).name="GraphError",n.message=e,n}return e(n,t),n}(a(Error)),F=function(t){function n(e){var r;return(r=t.call(this,e)||this).name="InvalidArgumentsGraphError","function"==typeof Error.captureStackTrace&&Error.captureStackTrace(u(r),n.prototype.constructor),r}return e(n,t),n}(B),I=function(t){function n(e){var r;return(r=t.call(this,e)||this).name="NotFoundGraphError","function"==typeof Error.captureStackTrace&&Error.captureStackTrace(u(r),n.prototype.constructor),r}return e(n,t),n}(B),Y=function(t){function n(e){var r;return(r=t.call(this,e)||this).name="UsageGraphError","function"==typeof Error.captureStackTrace&&Error.captureStackTrace(u(r),n.prototype.constructor),r}return e(n,t),n}(B);function q(t,e){this.key=t,this.attributes=e,this.clear()}function J(t,e){this.key=t,this.attributes=e,this.clear()}function V(t,e){this.key=t,this.attributes=e,this.clear()}function H(t,e,n,r,i){this.key=e,this.attributes=i,this.undirected=t,this.source=n,this.target=r}q.prototype.clear=function(){this.inDegree=0,this.outDegree=0,this.undirectedDegree=0,this.in={},this.out={},this.undirected={}},J.prototype.clear=function(){this.inDegree=0,this.outDegree=0,this.in={},this.out={}},V.prototype.clear=function(){this.undirectedDegree=0,this.undirected={}},H.prototype.attach=function(){var t="out",e="in";this.undirected&&(t=e="undirected");var n=this.source.key,r=this.target.key;this.source[t][r]=this,this.undirected&&n===r||(this.target[e][n]=this)},H.prototype.attachMulti=function(){var t="out",e="in",n=this.source.key,r=this.target.key;this.undirected&&(t=e="undirected");var i=this.source[t],o=i[r];if(void 0===o)return i[r]=this,void(this.undirected&&n===r||(this.target[e][n]=this));o.previous=this,this.next=o,i[r]=this,this.target[e][n]=this},H.prototype.detach=function(){var t=this.source.key,e=this.target.key,n="out",r="in";this.undirected&&(n=r="undirected"),delete this.source[n][e],delete this.target[r][t]},H.prototype.detachMulti=function(){var t=this.source.key,e=this.target.key,n="out",r="in";this.undirected&&(n=r="undirected"),void 0===this.previous?void 0===this.next?(delete this.source[n][e],delete this.target[r][t]):(this.next.previous=void 0,this.source[n][e]=this.next,this.target[r][t]=this.next):(this.previous.next=this.next,void 0!==this.next&&(this.next.previous=this.previous))};function Q(t,e,n,r,i,o,a){var u,c,s,d;if(r=""+r,0===n){if(!(u=t._nodes.get(r)))throw new I("Graph.".concat(e,': could not find the "').concat(r,'" node in the graph.'));s=i,d=o}else if(3===n){if(i=""+i,!(c=t._edges.get(i)))throw new I("Graph.".concat(e,': could not find the "').concat(i,'" edge in the graph.'));var h=c.source.key,p=c.target.key;if(r===h)u=c.target;else{if(r!==p)throw new I("Graph.".concat(e,': the "').concat(r,'" node is not attached to the "').concat(i,'" edge (').concat(h,", ").concat(p,")."));u=c.source}s=o,d=a}else{if(!(c=t._edges.get(r)))throw new I("Graph.".concat(e,': could not find the "').concat(r,'" edge in the graph.'));u=1===n?c.source:c.target,s=i,d=o}return[u,s,d]}var X=[{name:function(t){return"get".concat(t,"Attribute")},attacher:function(t,e,n){t.prototype[e]=function(t,r,i){var o=Q(this,e,n,t,r,i),a=o[0],u=o[1];return a.attributes[u]}}},{name:function(t){return"get".concat(t,"Attributes")},attacher:function(t,e,n){t.prototype[e]=function(t,r){return Q(this,e,n,t,r)[0].attributes}}},{name:function(t){return"has".concat(t,"Attribute")},attacher:function(t,e,n){t.prototype[e]=function(t,r,i){var o=Q(this,e,n,t,r,i),a=o[0],u=o[1];return a.attributes.hasOwnProperty(u)}}},{name:function(t){return"set".concat(t,"Attribute")},attacher:function(t,e,n){t.prototype[e]=function(t,r,i,o){var a=Q(this,e,n,t,r,i,o),u=a[0],c=a[1],s=a[2];return u.attributes[c]=s,this.emit("nodeAttributesUpdated",{key:u.key,type:"set",attributes:u.attributes,name:c}),this}}},{name:function(t){return"update".concat(t,"Attribute")},attacher:function(t,e,n){t.prototype[e]=function(t,r,i,o){var a=Q(this,e,n,t,r,i,o),u=a[0],c=a[1],s=a[2];if("function"!=typeof s)throw new F("Graph.".concat(e,": updater should be a function."));var d=u.attributes,h=s(d[c]);return d[c]=h,this.emit("nodeAttributesUpdated",{key:u.key,type:"set",attributes:u.attributes,name:c}),this}}},{name:function(t){return"remove".concat(t,"Attribute")},attacher:function(t,e,n){t.prototype[e]=function(t,r,i){var o=Q(this,e,n,t,r,i),a=o[0],u=o[1];return delete a.attributes[u],this.emit("nodeAttributesUpdated",{key:a.key,type:"remove",attributes:a.attributes,name:u}),this}}},{name:function(t){return"replace".concat(t,"Attributes")},attacher:function(t,e,n){t.prototype[e]=function(t,r,i){var o=Q(this,e,n,t,r,i),a=o[0],u=o[1];if(!h(u))throw new F("Graph.".concat(e,": provided attributes are not a plain object."));return a.attributes=u,this.emit("nodeAttributesUpdated",{key:a.key,type:"replace",attributes:a.attributes}),this}}},{name:function(t){return"merge".concat(t,"Attributes")},attacher:function(t,e,n){t.prototype[e]=function(t,r,i){var o=Q(this,e,n,t,r,i),a=o[0],u=o[1];if(!h(u))throw new F("Graph.".concat(e,": provided attributes are not a plain object."));return c(a.attributes,u),this.emit("nodeAttributesUpdated",{key:a.key,type:"merge",attributes:a.attributes,data:u}),this}}},{name:function(t){return"update".concat(t,"Attributes")},attacher:function(t,e,n){t.prototype[e]=function(t,r,i){var o=Q(this,e,n,t,r,i),a=o[0],u=o[1];if("function"!=typeof u)throw new F("Graph.".concat(e,": provided updater is not a function."));return a.attributes=u(a.attributes),this.emit("nodeAttributesUpdated",{key:a.key,type:"update",attributes:a.attributes}),this}}}];var Z=[{name:function(t){return"get".concat(t,"Attribute")},attacher:function(t,e,n){t.prototype[e]=function(t,r){var i;if("mixed"!==this.type&&"mixed"!==n&&n!==this.type)throw new Y("Graph.".concat(e,": cannot find this type of edges in your ").concat(this.type," graph."));if(arguments.length>2){if(this.multi)throw new Y("Graph.".concat(e,": cannot use a {source,target} combo when asking about an edge's attributes in a MultiGraph since we cannot infer the one you want information about."));var o=""+t,a=""+r;if(r=arguments[2],!(i=s(this,o,a,n)))throw new I("Graph.".concat(e,': could not find an edge for the given path ("').concat(o,'" - "').concat(a,'").'))}else{if("mixed"!==n)throw new Y("Graph.".concat(e,": calling this method with only a key (vs. a source and target) does not make sense since an edge with this key could have the other type."));if(t=""+t,!(i=this._edges.get(t)))throw new I("Graph.".concat(e,': could not find the "').concat(t,'" edge in the graph.'))}return i.attributes[r]}}},{name:function(t){return"get".concat(t,"Attributes")},attacher:function(t,e,n){t.prototype[e]=function(t){var r;if("mixed"!==this.type&&"mixed"!==n&&n!==this.type)throw new Y("Graph.".concat(e,": cannot find this type of edges in your ").concat(this.type," graph."));if(arguments.length>1){if(this.multi)throw new Y("Graph.".concat(e,": cannot use a {source,target} combo when asking about an edge's attributes in a MultiGraph since we cannot infer the one you want information about."));var i=""+t,o=""+arguments[1];if(!(r=s(this,i,o,n)))throw new I("Graph.".concat(e,': could not find an edge for the given path ("').concat(i,'" - "').concat(o,'").'))}else{if("mixed"!==n)throw new Y("Graph.".concat(e,": calling this method with only a key (vs. a source and target) does not make sense since an edge with this key could have the other type."));if(t=""+t,!(r=this._edges.get(t)))throw new I("Graph.".concat(e,': could not find the "').concat(t,'" edge in the graph.'))}return r.attributes}}},{name:function(t){return"has".concat(t,"Attribute")},attacher:function(t,e,n){t.prototype[e]=function(t,r){var i;if("mixed"!==this.type&&"mixed"!==n&&n!==this.type)throw new Y("Graph.".concat(e,": cannot find this type of edges in your ").concat(this.type," graph."));if(arguments.length>2){if(this.multi)throw new Y("Graph.".concat(e,": cannot use a {source,target} combo when asking about an edge's attributes in a MultiGraph since we cannot infer the one you want information about."));var o=""+t,a=""+r;if(r=arguments[2],!(i=s(this,o,a,n)))throw new I("Graph.".concat(e,': could not find an edge for the given path ("').concat(o,'" - "').concat(a,'").'))}else{if("mixed"!==n)throw new Y("Graph.".concat(e,": calling this method with only a key (vs. a source and target) does not make sense since an edge with this key could have the other type."));if(t=""+t,!(i=this._edges.get(t)))throw new I("Graph.".concat(e,': could not find the "').concat(t,'" edge in the graph.'))}return i.attributes.hasOwnProperty(r)}}},{name:function(t){return"set".concat(t,"Attribute")},attacher:function(t,e,n){t.prototype[e]=function(t,r,i){var o;if("mixed"!==this.type&&"mixed"!==n&&n!==this.type)throw new Y("Graph.".concat(e,": cannot find this type of edges in your ").concat(this.type," graph."));if(arguments.length>3){if(this.multi)throw new Y("Graph.".concat(e,": cannot use a {source,target} combo when asking about an edge's attributes in a MultiGraph since we cannot infer the one you want information about."));var a=""+t,u=""+r;if(r=arguments[2],i=arguments[3],!(o=s(this,a,u,n)))throw new I("Graph.".concat(e,': could not find an edge for the given path ("').concat(a,'" - "').concat(u,'").'))}else{if("mixed"!==n)throw new Y("Graph.".concat(e,": calling this method with only a key (vs. a source and target) does not make sense since an edge with this key could have the other type."));if(t=""+t,!(o=this._edges.get(t)))throw new I("Graph.".concat(e,': could not find the "').concat(t,'" edge in the graph.'))}return o.attributes[r]=i,this.emit("edgeAttributesUpdated",{key:o.key,type:"set",attributes:o.attributes,name:r}),this}}},{name:function(t){return"update".concat(t,"Attribute")},attacher:function(t,e,n){t.prototype[e]=function(t,r,i){var o;if("mixed"!==this.type&&"mixed"!==n&&n!==this.type)throw new Y("Graph.".concat(e,": cannot find this type of edges in your ").concat(this.type," graph."));if(arguments.length>3){if(this.multi)throw new Y("Graph.".concat(e,": cannot use a {source,target} combo when asking about an edge's attributes in a MultiGraph since we cannot infer the one you want information about."));var a=""+t,u=""+r;if(r=arguments[2],i=arguments[3],!(o=s(this,a,u,n)))throw new I("Graph.".concat(e,': could not find an edge for the given path ("').concat(a,'" - "').concat(u,'").'))}else{if("mixed"!==n)throw new Y("Graph.".concat(e,": calling this method with only a key (vs. a source and target) does not make sense since an edge with this key could have the other type."));if(t=""+t,!(o=this._edges.get(t)))throw new I("Graph.".concat(e,': could not find the "').concat(t,'" edge in the graph.'))}if("function"!=typeof i)throw new F("Graph.".concat(e,": updater should be a function."));return o.attributes[r]=i(o.attributes[r]),this.emit("edgeAttributesUpdated",{key:o.key,type:"set",attributes:o.attributes,name:r}),this}}},{name:function(t){return"remove".concat(t,"Attribute")},attacher:function(t,e,n){t.prototype[e]=function(t,r){var i;if("mixed"!==this.type&&"mixed"!==n&&n!==this.type)throw new Y("Graph.".concat(e,": cannot find this type of edges in your ").concat(this.type," graph."));if(arguments.length>2){if(this.multi)throw new Y("Graph.".concat(e,": cannot use a {source,target} combo when asking about an edge's attributes in a MultiGraph since we cannot infer the one you want information about."));var o=""+t,a=""+r;if(r=arguments[2],!(i=s(this,o,a,n)))throw new I("Graph.".concat(e,': could not find an edge for the given path ("').concat(o,'" - "').concat(a,'").'))}else{if("mixed"!==n)throw new Y("Graph.".concat(e,": calling this method with only a key (vs. a source and target) does not make sense since an edge with this key could have the other type."));if(t=""+t,!(i=this._edges.get(t)))throw new I("Graph.".concat(e,': could not find the "').concat(t,'" edge in the graph.'))}return delete i.attributes[r],this.emit("edgeAttributesUpdated",{key:i.key,type:"remove",attributes:i.attributes,name:r}),this}}},{name:function(t){return"replace".concat(t,"Attributes")},attacher:function(t,e,n){t.prototype[e]=function(t,r){var i;if("mixed"!==this.type&&"mixed"!==n&&n!==this.type)throw new Y("Graph.".concat(e,": cannot find this type of edges in your ").concat(this.type," graph."));if(arguments.length>2){if(this.multi)throw new Y("Graph.".concat(e,": cannot use a {source,target} combo when asking about an edge's attributes in a MultiGraph since we cannot infer the one you want information about."));var o=""+t,a=""+r;if(r=arguments[2],!(i=s(this,o,a,n)))throw new I("Graph.".concat(e,': could not find an edge for the given path ("').concat(o,'" - "').concat(a,'").'))}else{if("mixed"!==n)throw new Y("Graph.".concat(e,": calling this method with only a key (vs. a source and target) does not make sense since an edge with this key could have the other type."));if(t=""+t,!(i=this._edges.get(t)))throw new I("Graph.".concat(e,': could not find the "').concat(t,'" edge in the graph.'))}if(!h(r))throw new F("Graph.".concat(e,": provided attributes are not a plain object."));return i.attributes=r,this.emit("edgeAttributesUpdated",{key:i.key,type:"replace",attributes:i.attributes}),this}}},{name:function(t){return"merge".concat(t,"Attributes")},attacher:function(t,e,n){t.prototype[e]=function(t,r){var i;if("mixed"!==this.type&&"mixed"!==n&&n!==this.type)throw new Y("Graph.".concat(e,": cannot find this type of edges in your ").concat(this.type," graph."));if(arguments.length>2){if(this.multi)throw new Y("Graph.".concat(e,": cannot use a {source,target} combo when asking about an edge's attributes in a MultiGraph since we cannot infer the one you want information about."));var o=""+t,a=""+r;if(r=arguments[2],!(i=s(this,o,a,n)))throw new I("Graph.".concat(e,': could not find an edge for the given path ("').concat(o,'" - "').concat(a,'").'))}else{if("mixed"!==n)throw new Y("Graph.".concat(e,": calling this method with only a key (vs. a source and target) does not make sense since an edge with this key could have the other type."));if(t=""+t,!(i=this._edges.get(t)))throw new I("Graph.".concat(e,': could not find the "').concat(t,'" edge in the graph.'))}if(!h(r))throw new F("Graph.".concat(e,": provided attributes are not a plain object."));return c(i.attributes,r),this.emit("edgeAttributesUpdated",{key:i.key,type:"merge",attributes:i.attributes,data:r}),this}}},{name:function(t){return"update".concat(t,"Attributes")},attacher:function(t,e,n){t.prototype[e]=function(t,r){var i;if("mixed"!==this.type&&"mixed"!==n&&n!==this.type)throw new Y("Graph.".concat(e,": cannot find this type of edges in your ").concat(this.type," graph."));if(arguments.length>2){if(this.multi)throw new Y("Graph.".concat(e,": cannot use a {source,target} combo when asking about an edge's attributes in a MultiGraph since we cannot infer the one you want information about."));var o=""+t,a=""+r;if(r=arguments[2],!(i=s(this,o,a,n)))throw new I("Graph.".concat(e,': could not find an edge for the given path ("').concat(o,'" - "').concat(a,'").'))}else{if("mixed"!==n)throw new Y("Graph.".concat(e,": calling this method with only a key (vs. a source and target) does not make sense since an edge with this key could have the other type."));if(t=""+t,!(i=this._edges.get(t)))throw new I("Graph.".concat(e,': could not find the "').concat(t,'" edge in the graph.'))}if("function"!=typeof r)throw new F("Graph.".concat(e,": provided updater is not a function."));return i.attributes=r(i.attributes),this.emit("edgeAttributesUpdated",{key:i.key,type:"update",attributes:i.attributes}),this}}}];var $=O,tt=R,et=function(){var t=arguments,e=null,n=-1;return new $((function(){for(var r=null;;){if(null===e){if(++n>=t.length)return{done:!0};e=tt(t[n])}if(!0!==(r=e.next()).done)break;e=null}return r}))},nt=[{name:"edges",type:"mixed"},{name:"inEdges",type:"directed",direction:"in"},{name:"outEdges",type:"directed",direction:"out"},{name:"inboundEdges",type:"mixed",direction:"in"},{name:"outboundEdges",type:"mixed",direction:"out"},{name:"directedEdges",type:"directed"},{name:"undirectedEdges",type:"undirected"}];function rt(t,e,n,r){var i=!1;for(var o in e)if(o!==r){var a=e[o];if(i=n(a.key,a.attributes,a.source.key,a.target.key,a.source.attributes,a.target.attributes,a.undirected),t&&i)return a.key}}function it(t,e,n,r){var i,o,a,u=!1;for(var c in e)if(c!==r){i=e[c];do{if(o=i.source,a=i.target,u=n(i.key,i.attributes,o.key,a.key,o.attributes,a.attributes,i.undirected),t&&u)return i.key;i=i.next}while(void 0!==i)}}function ot(t,e){var n,r=Object.keys(t),i=r.length,o=0;return new O((function(){do{if(n)n=n.next;else{if(o>=i)return{done:!0};var a=r[o++];if(a===e){n=void 0;continue}n=t[a]}}while(!n);return{done:!1,value:{edge:n.key,attributes:n.attributes,source:n.source.key,target:n.target.key,sourceAttributes:n.source.attributes,targetAttributes:n.target.attributes,undirected:n.undirected}}}))}function at(t,e,n,r){var i=e[n];if(i){var o=i.source,a=i.target;return r(i.key,i.attributes,o.key,a.key,o.attributes,a.attributes,i.undirected)&&t?i.key:void 0}}function ut(t,e,n,r){var i=e[n];if(i){var o=!1;do{if(o=r(i.key,i.attributes,i.source.key,i.target.key,i.source.attributes,i.target.attributes,i.undirected),t&&o)return i.key;i=i.next}while(void 0!==i)}}function ct(t,e){var n=t[e];return void 0!==n.next?new O((function(){if(!n)return{done:!0};var t={edge:n.key,attributes:n.attributes,source:n.source.key,target:n.target.key,sourceAttributes:n.source.attributes,targetAttributes:n.target.attributes,undirected:n.undirected};return n=n.next,{done:!1,value:t}})):O.of({edge:n.key,attributes:n.attributes,source:n.source.key,target:n.target.key,sourceAttributes:n.source.attributes,targetAttributes:n.target.attributes,undirected:n.undirected})}function st(t,e){if(0===t.size)return[];if("mixed"===e||e===t.type)return"function"==typeof Array.from?Array.from(t._edges.keys()):T(t._edges.keys(),t._edges.size);for(var n,r,i="undirected"===e?t.undirectedSize:t.directedSize,o=new Array(i),a="undirected"===e,u=t._edges.values(),c=0;!0!==(n=u.next()).done;)(r=n.value).undirected===a&&(o[c++]=r.key);return o}function dt(t,e,n,r){if(0!==e.size)for(var i,o,a="mixed"!==n&&n!==e.type,u="undirected"===n,c=!1,s=e._edges.values();!0!==(i=s.next()).done;)if(o=i.value,!a||o.undirected===u){var d=o,h=d.key,p=d.attributes,f=d.source,l=d.target;if(c=r(h,p,f.key,l.key,f.attributes,l.attributes,o.undirected),t&&c)return h}}function ht(t,e){if(0===t.size)return O.empty();var n="mixed"!==e&&e!==t.type,r="undirected"===e,i=t._edges.values();return new O((function(){for(var t,e;;){if((t=i.next()).done)return t;if(e=t.value,!n||e.undirected===r)break}return{value:{edge:e.key,attributes:e.attributes,source:e.source.key,target:e.target.key,sourceAttributes:e.source.attributes,targetAttributes:e.target.attributes,undirected:e.undirected},done:!1}}))}function pt(t,e,n,r,i,o){var a,u=e?it:rt;if("undirected"!==n){if("out"!==r&&(a=u(t,i.in,o),t&&a))return a;if("in"!==r&&(a=u(t,i.out,o,r?void 0:i.key),t&&a))return a}if("directed"!==n&&(a=u(t,i.undirected,o),t&&a))return a}function ft(t,e,n,r){var i=[];return pt(!1,t,e,n,r,(function(t){i.push(t)})),i}function lt(t,e,n){var r=O.empty();return"undirected"!==t&&("out"!==e&&void 0!==n.in&&(r=et(r,ot(n.in))),"in"!==e&&void 0!==n.out&&(r=et(r,ot(n.out,e?void 0:n.key)))),"directed"!==t&&void 0!==n.undirected&&(r=et(r,ot(n.undirected))),r}function gt(t,e,n,r,i,o,a){var u,c=n?ut:at;if("undirected"!==e){if(void 0!==i.in&&"out"!==r&&(u=c(t,i.in,o,a),t&&u))return u;if(void 0!==i.out&&"in"!==r&&(r||i.key!==o)&&(u=c(t,i.out,o,a),t&&u))return u}if("directed"!==e&&void 0!==i.undirected&&(u=c(t,i.undirected,o,a),t&&u))return u}function yt(t,e,n,r,i){var o=[];return gt(!1,t,e,n,r,i,(function(t){o.push(t)})),o}function wt(t,e,n,r){var i=O.empty();return"undirected"!==t&&(void 0!==n.in&&"out"!==e&&r in n.in&&(i=et(i,ct(n.in,r))),void 0!==n.out&&"in"!==e&&r in n.out&&(e||n.key!==r)&&(i=et(i,ct(n.out,r)))),"directed"!==t&&void 0!==n.undirected&&r in n.undirected&&(i=et(i,ct(n.undirected,r))),i}var vt=[{name:"neighbors",type:"mixed"},{name:"inNeighbors",type:"directed",direction:"in"},{name:"outNeighbors",type:"directed",direction:"out"},{name:"inboundNeighbors",type:"mixed",direction:"in"},{name:"outboundNeighbors",type:"mixed",direction:"out"},{name:"directedNeighbors",type:"directed"},{name:"undirectedNeighbors",type:"undirected"}];function bt(){this.A=null,this.B=null}function mt(t,e,n,r,i){for(var o in r){var a=r[o],u=a.source,c=a.target,s=u===n?c:u;if(!e||!e.has(s.key)){var d=i(s.key,s.attributes);if(t&&d)return s.key}}}function kt(t,e,n,r,i){if("mixed"!==e){if("undirected"===e)return mt(t,null,r,r.undirected,i);if("string"==typeof n)return mt(t,null,r,r[n],i)}var o,a=new bt;if("undirected"!==e){if("out"!==n){if(o=mt(t,null,r,r.in,i),t&&o)return o;a.wrap(r.in)}if("in"!==n){if(o=mt(t,a,r,r.out,i),t&&o)return o;a.wrap(r.out)}}if("directed"!==e&&(o=mt(t,a,r,r.undirected,i),t&&o))return o}function _t(t,e,n){var r=Object.keys(n),i=r.length,o=0;return new O((function(){var a=null;do{if(o>=i)return t&&t.wrap(n),{done:!0};var u=n[r[o++]],c=u.source,s=u.target;a=c===e?s:c,t&&t.has(a.key)&&(a=null)}while(null===a);return{done:!1,value:{neighbor:a.key,attributes:a.attributes}}}))}function Gt(t,e){var n=e.name,r=e.type,i=e.direction;t.prototype[n]=function(t){if("mixed"!==r&&"mixed"!==this.type&&r!==this.type)return[];t=""+t;var e=this._nodes.get(t);if(void 0===e)throw new I("Graph.".concat(n,': could not find the "').concat(t,'" node in the graph.'));return function(t,e,n){if("mixed"!==t){if("undirected"===t)return Object.keys(n.undirected);if("string"==typeof e)return Object.keys(n[e])}var r=[];return kt(!1,t,e,n,(function(t){r.push(t)})),r}("mixed"===r?this.type:r,i,e)}}function xt(t,e){var n=e.name,r=e.type,i=e.direction,o=n.slice(0,-1)+"Entries";t.prototype[o]=function(t){if("mixed"!==r&&"mixed"!==this.type&&r!==this.type)return O.empty();t=""+t;var e=this._nodes.get(t);if(void 0===e)throw new I("Graph.".concat(o,': could not find the "').concat(t,'" node in the graph.'));return function(t,e,n){if("mixed"!==t){if("undirected"===t)return _t(null,n,n.undirected);if("string"==typeof e)return _t(null,n,n[e])}var r=O.empty(),i=new bt;return"undirected"!==t&&("out"!==e&&(r=et(r,_t(i,n,n.in))),"in"!==e&&(r=et(r,_t(i,n,n.out)))),"directed"!==t&&(r=et(r,_t(i,n,n.undirected))),r}("mixed"===r?this.type:r,i,e)}}function Et(t,e,n,r,i){for(var o,a,u,c,s,d,h,p=r._nodes.values(),f=r.type;!0!==(o=p.next()).done;){var l=!1;if(a=o.value,"undirected"!==f)for(u in c=a.out){s=c[u];do{if(d=s.target,l=!0,h=i(a.key,d.key,a.attributes,d.attributes,s.key,s.attributes,s.undirected),t&&h)return s;s=s.next}while(s)}if("directed"!==f)for(u in c=a.undirected)if(!(e&&a.key>u)){s=c[u];do{if((d=s.target).key!==u&&(d=s.source),l=!0,h=i(a.key,d.key,a.attributes,d.attributes,s.key,s.attributes,s.undirected),t&&h)return s;s=s.next}while(s)}if(n&&!l&&(h=i(a.key,null,a.attributes,null,null,null,null),t&&h))return null}}function At(t){if(!h(t))throw new F('Graph.import: invalid serialized node. A serialized node should be a plain object with at least a "key" property.');if(!("key"in t))throw new F("Graph.import: serialized node is missing its key.");if("attributes"in t&&(!h(t.attributes)||null===t.attributes))throw new F("Graph.import: invalid attributes. Attributes should be a plain object, null or omitted.")}function St(t){if(!h(t))throw new F('Graph.import: invalid serialized edge. A serialized edge should be a plain object with at least a "source" & "target" property.');if(!("source"in t))throw new F("Graph.import: serialized edge is missing its source.");if(!("target"in t))throw new F("Graph.import: serialized edge is missing its target.");if("attributes"in t&&(!h(t.attributes)||null===t.attributes))throw new F("Graph.import: invalid attributes. Attributes should be a plain object, null or omitted.");if("undirected"in t&&"boolean"!=typeof t.undirected)throw new F("Graph.import: invalid undirectedness information. Undirected should be boolean or omitted.")}bt.prototype.wrap=function(t){null===this.A?this.A=t:null===this.B&&(this.B=t)},bt.prototype.has=function(t){return null!==this.A&&t in this.A||null!==this.B&&t in this.B};var Dt,Lt=(Dt=255&Math.floor(256*Math.random()),function(){return Dt++}),Ut=new Set(["directed","undirected","mixed"]),Nt=new Set(["domain","_events","_eventsCount","_maxListeners"]),jt={allowSelfLoops:!0,multi:!1,type:"mixed"};function Ot(t,e,n){var r=new t.NodeDataClass(e,n);return t._nodes.set(e,r),t.emit("nodeAdded",{key:e,attributes:n}),r}function Ct(t,e,n,r,i,o,a,u){if(!r&&"undirected"===t.type)throw new Y("Graph.".concat(e,": you cannot add a directed edge to an undirected graph. Use the #.addEdge or #.addUndirectedEdge instead."));if(r&&"directed"===t.type)throw new Y("Graph.".concat(e,": you cannot add an undirected edge to a directed graph. Use the #.addEdge or #.addDirectedEdge instead."));if(u&&!h(u))throw new F("Graph.".concat(e,': invalid attributes. Expecting an object but got "').concat(u,'"'));if(o=""+o,a=""+a,u=u||{},!t.allowSelfLoops&&o===a)throw new Y("Graph.".concat(e,': source & target are the same ("').concat(o,"\"), thus creating a loop explicitly forbidden by this graph 'allowSelfLoops' option set to false."));var c=t._nodes.get(o),s=t._nodes.get(a);if(!c)throw new I("Graph.".concat(e,': source node "').concat(o,'" not found.'));if(!s)throw new I("Graph.".concat(e,': target node "').concat(a,'" not found.'));var d={key:null,undirected:r,source:o,target:a,attributes:u};if(n)i=t._edgeKeyGenerator();else if(i=""+i,t._edges.has(i))throw new Y("Graph.".concat(e,': the "').concat(i,'" edge already exists in the graph.'));if(!t.multi&&(r?void 0!==c.undirected[a]:void 0!==c.out[a]))throw new Y("Graph.".concat(e,': an edge linking "').concat(o,'" to "').concat(a,"\" already exists. If you really want to add multiple edges linking those nodes, you should create a multi graph by using the 'multi' option."));var p=new H(r,i,c,s,u);t._edges.set(i,p);var f=o===a;return r?(c.undirectedDegree++,s.undirectedDegree++,f&&t._undirectedSelfLoopCount++):(c.outDegree++,s.inDegree++,f&&t._directedSelfLoopCount++),t.multi?p.attachMulti():p.attach(),r?t._undirectedSize++:t._directedSize++,d.key=i,t.emit("edgeAdded",d),i}function zt(t,e,n,r,i,o,a,u,s){if(!r&&"undirected"===t.type)throw new Y("Graph.".concat(e,": you cannot merge/update a directed edge to an undirected graph. Use the #.mergeEdge/#.updateEdge or #.addUndirectedEdge instead."));if(r&&"directed"===t.type)throw new Y("Graph.".concat(e,": you cannot merge/update an undirected edge to a directed graph. Use the #.mergeEdge/#.updateEdge or #.addDirectedEdge instead."));if(u)if(s){if("function"!=typeof u)throw new F("Graph.".concat(e,': invalid updater function. Expecting a function but got "').concat(u,'"'))}else if(!h(u))throw new F("Graph.".concat(e,': invalid attributes. Expecting an object but got "').concat(u,'"'));var d;if(o=""+o,a=""+a,s&&(d=u,u=void 0),!t.allowSelfLoops&&o===a)throw new Y("Graph.".concat(e,': source & target are the same ("').concat(o,"\"), thus creating a loop explicitly forbidden by this graph 'allowSelfLoops' option set to false."));var p,f,l=t._nodes.get(o),g=t._nodes.get(a);if(!n&&(p=t._edges.get(i))){if(!(p.source.key===o&&p.target.key===a||r&&p.source.key===a&&p.target.key===o))throw new Y("Graph.".concat(e,': inconsistency detected when attempting to merge the "').concat(i,'" edge with "').concat(o,'" source & "').concat(a,'" target vs. ("').concat(p.source.key,'", "').concat(p.target.key,'").'));f=p}if(f||t.multi||!l||(f=r?l.undirected[a]:l.out[a]),f){var y=[f.key,!1,!1,!1];if(s?!d:!u)return y;if(s){var w=f.attributes;f.attributes=d(w),t.emit("edgeAttributesUpdated",{type:"replace",key:f.key,attributes:f.attributes})}else c(f.attributes,u),t.emit("edgeAttributesUpdated",{type:"merge",key:f.key,attributes:f.attributes,data:u});return y}u=u||{},s&&d&&(u=d(u));var v={key:null,undirected:r,source:o,target:a,attributes:u};if(n)i=t._edgeKeyGenerator();else if(i=""+i,t._edges.has(i))throw new Y("Graph.".concat(e,': the "').concat(i,'" edge already exists in the graph.'));var b=!1,m=!1;l||(l=Ot(t,o,{}),b=!0,o===a&&(g=l,m=!0)),g||(g=Ot(t,a,{}),m=!0),p=new H(r,i,l,g,u),t._edges.set(i,p);var k=o===a;return r?(l.undirectedDegree++,g.undirectedDegree++,k&&t._undirectedSelfLoopCount++):(l.outDegree++,g.inDegree++,k&&t._directedSelfLoopCount++),t.multi?p.attachMulti():p.attach(),r?t._undirectedSize++:t._directedSize++,v.key=i,t.emit("edgeAdded",v),[i,!0,b,m]}function Mt(t,e){t._edges.delete(e.key);var n=e.source,r=e.target,i=e.attributes,o=e.undirected,a=n===r;o?(n.undirectedDegree--,r.undirectedDegree--,a&&t._undirectedSelfLoopCount--):(n.outDegree--,r.inDegree--,a&&t._directedSelfLoopCount--),t.multi?e.detachMulti():e.detach(),o?t._undirectedSize--:t._directedSize--,t.emit("edgeDropped",{key:e.key,attributes:i,source:n.key,target:r.key,undirected:o})}var Wt=function(n){function r(t){var e;if(e=n.call(this)||this,"boolean"!=typeof(t=c({},jt,t)).multi)throw new F("Graph.constructor: invalid 'multi' option. Expecting a boolean but got \"".concat(t.multi,'".'));if(!Ut.has(t.type))throw new F('Graph.constructor: invalid \'type\' option. Should be one of "mixed", "directed" or "undirected" but got "'.concat(t.type,'".'));if("boolean"!=typeof t.allowSelfLoops)throw new F("Graph.constructor: invalid 'allowSelfLoops' option. Expecting a boolean but got \"".concat(t.allowSelfLoops,'".'));var r="mixed"===t.type?q:"directed"===t.type?J:V;f(u(e),"NodeDataClass",r);var i="geid_"+Lt()+"_",o=0;return f(u(e),"_attributes",{}),f(u(e),"_nodes",new Map),f(u(e),"_edges",new Map),f(u(e),"_directedSize",0),f(u(e),"_undirectedSize",0),f(u(e),"_directedSelfLoopCount",0),f(u(e),"_undirectedSelfLoopCount",0),f(u(e),"_edgeKeyGenerator",(function(){var t;do{t=i+o++}while(e._edges.has(t));return t})),f(u(e),"_options",t),Nt.forEach((function(t){return f(u(e),t,e[t])})),l(u(e),"order",(function(){return e._nodes.size})),l(u(e),"size",(function(){return e._edges.size})),l(u(e),"directedSize",(function(){return e._directedSize})),l(u(e),"undirectedSize",(function(){return e._undirectedSize})),l(u(e),"selfLoopCount",(function(){return e._directedSelfLoopCount+e._undirectedSelfLoopCount})),l(u(e),"directedSelfLoopCount",(function(){return e._directedSelfLoopCount})),l(u(e),"undirectedSelfLoopCount",(function(){return e._undirectedSelfLoopCount})),l(u(e),"multi",e._options.multi),l(u(e),"type",e._options.type),l(u(e),"allowSelfLoops",e._options.allowSelfLoops),l(u(e),"implementation",(function(){return"graphology"})),e}e(r,n);var i=r.prototype;return i._resetInstanceCounters=function(){this._directedSize=0,this._undirectedSize=0,this._directedSelfLoopCount=0,this._undirectedSelfLoopCount=0},i.hasNode=function(t){return this._nodes.has(""+t)},i.hasDirectedEdge=function(t,e){if("undirected"===this.type)return!1;if(1===arguments.length){var n=""+t,r=this._edges.get(n);return!!r&&!r.undirected}if(2===arguments.length){t=""+t,e=""+e;var i=this._nodes.get(t);if(!i)return!1;var o=i.out[e];return!!o&&(!this.multi||!!o.size)}throw new F("Graph.hasDirectedEdge: invalid arity (".concat(arguments.length,", instead of 1 or 2). You can either ask for an edge id or for the existence of an edge between a source & a target."))},i.hasUndirectedEdge=function(t,e){if("directed"===this.type)return!1;if(1===arguments.length){var n=""+t,r=this._edges.get(n);return!!r&&r.undirected}if(2===arguments.length){t=""+t,e=""+e;var i=this._nodes.get(t);if(!i)return!1;var o=i.undirected[e];return!!o&&(!this.multi||!!o.size)}throw new F("Graph.hasDirectedEdge: invalid arity (".concat(arguments.length,", instead of 1 or 2). You can either ask for an edge id or for the existence of an edge between a source & a target."))},i.hasEdge=function(t,e){if(1===arguments.length){var n=""+t;return this._edges.has(n)}if(2===arguments.length){t=""+t,e=""+e;var r=this._nodes.get(t);if(!r)return!1;var i=void 0!==r.out&&r.out[e];return i||(i=void 0!==r.undirected&&r.undirected[e]),!!i&&(!this.multi||!!i.size)}throw new F("Graph.hasEdge: invalid arity (".concat(arguments.length,", instead of 1 or 2). You can either ask for an edge id or for the existence of an edge between a source & a target."))},i.directedEdge=function(t,e){if("undirected"!==this.type){if(t=""+t,e=""+e,this.multi)throw new Y("Graph.directedEdge: this method is irrelevant with multigraphs since there might be multiple edges between source & target. See #.directedEdges instead.");var n=this._nodes.get(t);if(!n)throw new I('Graph.directedEdge: could not find the "'.concat(t,'" source node in the graph.'));if(!this._nodes.has(e))throw new I('Graph.directedEdge: could not find the "'.concat(e,'" target node in the graph.'));var r=n.out&&n.out[e]||void 0;return r?r.key:void 0}},i.undirectedEdge=function(t,e){if("directed"!==this.type){if(t=""+t,e=""+e,this.multi)throw new Y("Graph.undirectedEdge: this method is irrelevant with multigraphs since there might be multiple edges between source & target. See #.undirectedEdges instead.");var n=this._nodes.get(t);if(!n)throw new I('Graph.undirectedEdge: could not find the "'.concat(t,'" source node in the graph.'));if(!this._nodes.has(e))throw new I('Graph.undirectedEdge: could not find the "'.concat(e,'" target node in the graph.'));var r=n.undirected&&n.undirected[e]||void 0;return r?r.key:void 0}},i.edge=function(t,e){if(this.multi)throw new Y("Graph.edge: this method is irrelevant with multigraphs since there might be multiple edges between source & target. See #.edges instead.");t=""+t,e=""+e;var n=this._nodes.get(t);if(!n)throw new I('Graph.edge: could not find the "'.concat(t,'" source node in the graph.'));if(!this._nodes.has(e))throw new I('Graph.edge: could not find the "'.concat(e,'" target node in the graph.'));var r=n.out&&n.out[e]||n.undirected&&n.undirected[e]||void 0;if(r)return r.key},i.areDirectedNeighbors=function(t,e){t=""+t,e=""+e;var n=this._nodes.get(t);if(!n)throw new I('Graph.areDirectedNeighbors: could not find the "'.concat(t,'" node in the graph.'));return"undirected"!==this.type&&(e in n.in||e in n.out)},i.areOutNeighbors=function(t,e){t=""+t,e=""+e;var n=this._nodes.get(t);if(!n)throw new I('Graph.areOutNeighbors: could not find the "'.concat(t,'" node in the graph.'));return"undirected"!==this.type&&e in n.out},i.areInNeighbors=function(t,e){t=""+t,e=""+e;var n=this._nodes.get(t);if(!n)throw new I('Graph.areInNeighbors: could not find the "'.concat(t,'" node in the graph.'));return"undirected"!==this.type&&e in n.in},i.areUndirectedNeighbors=function(t,e){t=""+t,e=""+e;var n=this._nodes.get(t);if(!n)throw new I('Graph.areUndirectedNeighbors: could not find the "'.concat(t,'" node in the graph.'));return"directed"!==this.type&&e in n.undirected},i.areNeighbors=function(t,e){t=""+t,e=""+e;var n=this._nodes.get(t);if(!n)throw new I('Graph.areNeighbors: could not find the "'.concat(t,'" node in the graph.'));return"undirected"!==this.type&&(e in n.in||e in n.out)||"directed"!==this.type&&e in n.undirected},i.areInboundNeighbors=function(t,e){t=""+t,e=""+e;var n=this._nodes.get(t);if(!n)throw new I('Graph.areInboundNeighbors: could not find the "'.concat(t,'" node in the graph.'));return"undirected"!==this.type&&e in n.in||"directed"!==this.type&&e in n.undirected},i.areOutboundNeighbors=function(t,e){t=""+t,e=""+e;var n=this._nodes.get(t);if(!n)throw new I('Graph.areOutboundNeighbors: could not find the "'.concat(t,'" node in the graph.'));return"undirected"!==this.type&&e in n.out||"directed"!==this.type&&e in n.undirected},i.inDegree=function(t){t=""+t;var e=this._nodes.get(t);if(!e)throw new I('Graph.inDegree: could not find the "'.concat(t,'" node in the graph.'));return"undirected"===this.type?0:e.inDegree},i.outDegree=function(t){t=""+t;var e=this._nodes.get(t);if(!e)throw new I('Graph.outDegree: could not find the "'.concat(t,'" node in the graph.'));return"undirected"===this.type?0:e.outDegree},i.directedDegree=function(t){t=""+t;var e=this._nodes.get(t);if(!e)throw new I('Graph.directedDegree: could not find the "'.concat(t,'" node in the graph.'));return"undirected"===this.type?0:e.inDegree+e.outDegree},i.undirectedDegree=function(t){t=""+t;var e=this._nodes.get(t);if(!e)throw new I('Graph.undirectedDegree: could not find the "'.concat(t,'" node in the graph.'));return"directed"===this.type?0:e.undirectedDegree},i.inboundDegree=function(t){t=""+t;var e=this._nodes.get(t);if(!e)throw new I('Graph.inboundDegree: could not find the "'.concat(t,'" node in the graph.'));var n=0;return"directed"!==this.type&&(n+=e.undirectedDegree),"undirected"!==this.type&&(n+=e.inDegree),n},i.outboundDegree=function(t){t=""+t;var e=this._nodes.get(t);if(!e)throw new I('Graph.outboundDegree: could not find the "'.concat(t,'" node in the graph.'));var n=0;return"directed"!==this.type&&(n+=e.undirectedDegree),"undirected"!==this.type&&(n+=e.outDegree),n},i.degree=function(t){t=""+t;var e=this._nodes.get(t);if(!e)throw new I('Graph.degree: could not find the "'.concat(t,'" node in the graph.'));var n=0;return"directed"!==this.type&&(n+=e.undirectedDegree),"undirected"!==this.type&&(n+=e.inDegree+e.outDegree),n},i.inDegreeWithoutSelfLoops=function(t){t=""+t;var e=this._nodes.get(t);if(!e)throw new I('Graph.inDegreeWithoutSelfLoops: could not find the "'.concat(t,'" node in the graph.'));if("undirected"===this.type)return 0;var n=e.in[t],r=n?this.multi?n.size:1:0;return e.inDegree-r},i.outDegreeWithoutSelfLoops=function(t){t=""+t;var e=this._nodes.get(t);if(!e)throw new I('Graph.outDegreeWithoutSelfLoops: could not find the "'.concat(t,'" node in the graph.'));if("undirected"===this.type)return 0;var n=e.out[t],r=n?this.multi?n.size:1:0;return e.outDegree-r},i.directedDegreeWithoutSelfLoops=function(t){t=""+t;var e=this._nodes.get(t);if(!e)throw new I('Graph.directedDegreeWithoutSelfLoops: could not find the "'.concat(t,'" node in the graph.'));if("undirected"===this.type)return 0;var n=e.out[t],r=n?this.multi?n.size:1:0;return e.inDegree+e.outDegree-2*r},i.undirectedDegreeWithoutSelfLoops=function(t){t=""+t;var e=this._nodes.get(t);if(!e)throw new I('Graph.undirectedDegreeWithoutSelfLoops: could not find the "'.concat(t,'" node in the graph.'));if("directed"===this.type)return 0;var n=e.undirected[t],r=n?this.multi?n.size:1:0;return e.undirectedDegree-2*r},i.inboundDegreeWithoutSelfLoops=function(t){t=""+t;var e,n=this._nodes.get(t);if(!n)throw new I('Graph.inboundDegreeWithoutSelfLoops: could not find the "'.concat(t,'" node in the graph.'));var r=0,i=0;return"directed"!==this.type&&(r+=n.undirectedDegree,i+=2*((e=n.undirected[t])?this.multi?e.size:1:0)),"undirected"!==this.type&&(r+=n.inDegree,i+=(e=n.out[t])?this.multi?e.size:1:0),r-i},i.outboundDegreeWithoutSelfLoops=function(t){t=""+t;var e,n=this._nodes.get(t);if(!n)throw new I('Graph.outboundDegreeWithoutSelfLoops: could not find the "'.concat(t,'" node in the graph.'));var r=0,i=0;return"directed"!==this.type&&(r+=n.undirectedDegree,i+=2*((e=n.undirected[t])?this.multi?e.size:1:0)),"undirected"!==this.type&&(r+=n.outDegree,i+=(e=n.in[t])?this.multi?e.size:1:0),r-i},i.degreeWithoutSelfLoops=function(t){t=""+t;var e,n=this._nodes.get(t);if(!n)throw new I('Graph.degreeWithoutSelfLoops: could not find the "'.concat(t,'" node in the graph.'));var r=0,i=0;return"directed"!==this.type&&(r+=n.undirectedDegree,i+=2*((e=n.undirected[t])?this.multi?e.size:1:0)),"undirected"!==this.type&&(r+=n.inDegree+n.outDegree,i+=2*((e=n.out[t])?this.multi?e.size:1:0)),r-i},i.source=function(t){t=""+t;var e=this._edges.get(t);if(!e)throw new I('Graph.source: could not find the "'.concat(t,'" edge in the graph.'));return e.source.key},i.target=function(t){t=""+t;var e=this._edges.get(t);if(!e)throw new I('Graph.target: could not find the "'.concat(t,'" edge in the graph.'));return e.target.key},i.extremities=function(t){t=""+t;var e=this._edges.get(t);if(!e)throw new I('Graph.extremities: could not find the "'.concat(t,'" edge in the graph.'));return[e.source.key,e.target.key]},i.opposite=function(t,e){t=""+t,e=""+e;var n=this._edges.get(e);if(!n)throw new I('Graph.opposite: could not find the "'.concat(e,'" edge in the graph.'));var r=n.source.key,i=n.target.key;if(t===r)return i;if(t===i)return r;throw new I('Graph.opposite: the "'.concat(t,'" node is not attached to the "').concat(e,'" edge (').concat(r,", ").concat(i,")."))},i.hasExtremity=function(t,e){t=""+t,e=""+e;var n=this._edges.get(t);if(!n)throw new I('Graph.hasExtremity: could not find the "'.concat(t,'" edge in the graph.'));return n.source.key===e||n.target.key===e},i.isUndirected=function(t){t=""+t;var e=this._edges.get(t);if(!e)throw new I('Graph.isUndirected: could not find the "'.concat(t,'" edge in the graph.'));return e.undirected},i.isDirected=function(t){t=""+t;var e=this._edges.get(t);if(!e)throw new I('Graph.isDirected: could not find the "'.concat(t,'" edge in the graph.'));return!e.undirected},i.isSelfLoop=function(t){t=""+t;var e=this._edges.get(t);if(!e)throw new I('Graph.isSelfLoop: could not find the "'.concat(t,'" edge in the graph.'));return e.source===e.target},i.addNode=function(t,e){var n=function(t,e,n){if(n&&!h(n))throw new F('Graph.addNode: invalid attributes. Expecting an object but got "'.concat(n,'"'));if(e=""+e,n=n||{},t._nodes.has(e))throw new Y('Graph.addNode: the "'.concat(e,'" node already exist in the graph.'));var r=new t.NodeDataClass(e,n);return t._nodes.set(e,r),t.emit("nodeAdded",{key:e,attributes:n}),r}(this,t,e);return n.key},i.mergeNode=function(t,e){if(e&&!h(e))throw new F('Graph.mergeNode: invalid attributes. Expecting an object but got "'.concat(e,'"'));t=""+t,e=e||{};var n=this._nodes.get(t);return n?(e&&(c(n.attributes,e),this.emit("nodeAttributesUpdated",{type:"merge",key:t,attributes:n.attributes,data:e})),[t,!1]):(n=new this.NodeDataClass(t,e),this._nodes.set(t,n),this.emit("nodeAdded",{key:t,attributes:e}),[t,!0])},i.updateNode=function(t,e){if(e&&"function"!=typeof e)throw new F('Graph.updateNode: invalid updater function. Expecting a function but got "'.concat(e,'"'));t=""+t;var n=this._nodes.get(t);if(n){if(e){var r=n.attributes;n.attributes=e(r),this.emit("nodeAttributesUpdated",{type:"replace",key:t,attributes:n.attributes})}return[t,!1]}var i=e?e({}):{};return n=new this.NodeDataClass(t,i),this._nodes.set(t,n),this.emit("nodeAdded",{key:t,attributes:i}),[t,!0]},i.dropNode=function(t){t=""+t;var e,n=this._nodes.get(t);if(!n)throw new I('Graph.dropNode: could not find the "'.concat(t,'" node in the graph.'));if("undirected"!==this.type){for(var r in n.out){e=n.out[r];do{Mt(this,e),e=e.next}while(e)}for(var i in n.in){e=n.in[i];do{Mt(this,e),e=e.next}while(e)}}if("directed"!==this.type)for(var o in n.undirected){e=n.undirected[o];do{Mt(this,e),e=e.next}while(e)}this._nodes.delete(t),this.emit("nodeDropped",{key:t,attributes:n.attributes})},i.dropEdge=function(t){var e;if(arguments.length>1){var n=""+arguments[0],r=""+arguments[1];if(!(e=s(this,n,r,this.type)))throw new I('Graph.dropEdge: could not find the "'.concat(n,'" -> "').concat(r,'" edge in the graph.'))}else if(t=""+t,!(e=this._edges.get(t)))throw new I('Graph.dropEdge: could not find the "'.concat(t,'" edge in the graph.'));return Mt(this,e),this},i.dropDirectedEdge=function(t,e){if(arguments.length<2)throw new Y("Graph.dropDirectedEdge: it does not make sense to try and drop a directed edge by key. What if the edge with this key is undirected? Use #.dropEdge for this purpose instead.");if(this.multi)throw new Y("Graph.dropDirectedEdge: cannot use a {source,target} combo when dropping an edge in a MultiGraph since we cannot infer the one you want to delete as there could be multiple ones.");var n=s(this,t=""+t,e=""+e,"directed");if(!n)throw new I('Graph.dropDirectedEdge: could not find a "'.concat(t,'" -> "').concat(e,'" edge in the graph.'));return Mt(this,n),this},i.dropUndirectedEdge=function(t,e){if(arguments.length<2)throw new Y("Graph.dropUndirectedEdge: it does not make sense to drop a directed edge by key. What if the edge with this key is undirected? Use #.dropEdge for this purpose instead.");if(this.multi)throw new Y("Graph.dropUndirectedEdge: cannot use a {source,target} combo when dropping an edge in a MultiGraph since we cannot infer the one you want to delete as there could be multiple ones.");var n=s(this,t,e,"undirected");if(!n)throw new I('Graph.dropUndirectedEdge: could not find a "'.concat(t,'" -> "').concat(e,'" edge in the graph.'));return Mt(this,n),this},i.clear=function(){this._edges.clear(),this._nodes.clear(),this._resetInstanceCounters(),this.emit("cleared")},i.clearEdges=function(){for(var t,e=this._nodes.values();!0!==(t=e.next()).done;)t.value.clear();this._edges.clear(),this._resetInstanceCounters(),this.emit("edgesCleared")},i.getAttribute=function(t){return this._attributes[t]},i.getAttributes=function(){return this._attributes},i.hasAttribute=function(t){return this._attributes.hasOwnProperty(t)},i.setAttribute=function(t,e){return this._attributes[t]=e,this.emit("attributesUpdated",{type:"set",attributes:this._attributes,name:t}),this},i.updateAttribute=function(t,e){if("function"!=typeof e)throw new F("Graph.updateAttribute: updater should be a function.");var n=this._attributes[t];return this._attributes[t]=e(n),this.emit("attributesUpdated",{type:"set",attributes:this._attributes,name:t}),this},i.removeAttribute=function(t){return delete this._attributes[t],this.emit("attributesUpdated",{type:"remove",attributes:this._attributes,name:t}),this},i.replaceAttributes=function(t){if(!h(t))throw new F("Graph.replaceAttributes: provided attributes are not a plain object.");return this._attributes=t,this.emit("attributesUpdated",{type:"replace",attributes:this._attributes}),this},i.mergeAttributes=function(t){if(!h(t))throw new F("Graph.mergeAttributes: provided attributes are not a plain object.");return c(this._attributes,t),this.emit("attributesUpdated",{type:"merge",attributes:this._attributes,data:t}),this},i.updateAttributes=function(t){if("function"!=typeof t)throw new F("Graph.updateAttributes: provided updater is not a function.");return this._attributes=t(this._attributes),this.emit("attributesUpdated",{type:"update",attributes:this._attributes}),this},i.updateEachNodeAttributes=function(t,e){if("function"!=typeof t)throw new F("Graph.updateEachNodeAttributes: expecting an updater function.");if(e&&!g(e))throw new F("Graph.updateEachNodeAttributes: invalid hints. Expecting an object having the following shape: {attributes?: [string]}");for(var n,r,i=this._nodes.values();!0!==(n=i.next()).done;)(r=n.value).attributes=t(r.key,r.attributes);this.emit("eachNodeAttributesUpdated",{hints:e||null})},i.updateEachEdgeAttributes=function(t,e){if("function"!=typeof t)throw new F("Graph.updateEachEdgeAttributes: expecting an updater function.");if(e&&!g(e))throw new F("Graph.updateEachEdgeAttributes: invalid hints. Expecting an object having the following shape: {attributes?: [string]}");for(var n,r,i,o,a=this._edges.values();!0!==(n=a.next()).done;)i=(r=n.value).source,o=r.target,r.attributes=t(r.key,r.attributes,i.key,o.key,i.attributes,o.attributes,r.undirected);this.emit("eachEdgeAttributesUpdated",{hints:e||null})},i.forEachAdjacencyEntry=function(t){if("function"!=typeof t)throw new F("Graph.forEachAdjacencyEntry: expecting a callback.");Et(!1,!1,!1,this,t)},i.forEachAdjacencyEntryWithOrphans=function(t){if("function"!=typeof t)throw new F("Graph.forEachAdjacencyEntryWithOrphans: expecting a callback.");Et(!1,!1,!0,this,t)},i.forEachAssymetricAdjacencyEntry=function(t){if("function"!=typeof t)throw new F("Graph.forEachAssymetricAdjacencyEntry: expecting a callback.");Et(!1,!0,!1,this,t)},i.forEachAssymetricAdjacencyEntryWithOrphans=function(t){if("function"!=typeof t)throw new F("Graph.forEachAssymetricAdjacencyEntryWithOrphans: expecting a callback.");Et(!1,!0,!0,this,t)},i.nodes=function(){return"function"==typeof Array.from?Array.from(this._nodes.keys()):T(this._nodes.keys(),this._nodes.size)},i.forEachNode=function(t){if("function"!=typeof t)throw new F("Graph.forEachNode: expecting a callback.");for(var e,n,r=this._nodes.values();!0!==(e=r.next()).done;)t((n=e.value).key,n.attributes)},i.findNode=function(t){if("function"!=typeof t)throw new F("Graph.findNode: expecting a callback.");for(var e,n,r=this._nodes.values();!0!==(e=r.next()).done;)if(t((n=e.value).key,n.attributes))return n.key},i.mapNodes=function(t){if("function"!=typeof t)throw new F("Graph.mapNode: expecting a callback.");for(var e,n,r=this._nodes.values(),i=new Array(this.order),o=0;!0!==(e=r.next()).done;)n=e.value,i[o++]=t(n.key,n.attributes);return i},i.someNode=function(t){if("function"!=typeof t)throw new F("Graph.someNode: expecting a callback.");for(var e,n,r=this._nodes.values();!0!==(e=r.next()).done;)if(t((n=e.value).key,n.attributes))return!0;return!1},i.everyNode=function(t){if("function"!=typeof t)throw new F("Graph.everyNode: expecting a callback.");for(var e,n,r=this._nodes.values();!0!==(e=r.next()).done;)if(!t((n=e.value).key,n.attributes))return!1;return!0},i.filterNodes=function(t){if("function"!=typeof t)throw new F("Graph.filterNodes: expecting a callback.");for(var e,n,r=this._nodes.values(),i=[];!0!==(e=r.next()).done;)t((n=e.value).key,n.attributes)&&i.push(n.key);return i},i.reduceNodes=function(t,e){if("function"!=typeof t)throw new F("Graph.reduceNodes: expecting a callback.");if(arguments.length<2)throw new F("Graph.reduceNodes: missing initial value. You must provide it because the callback takes more than one argument and we cannot infer the initial value from the first iteration, as you could with a simple array.");for(var n,r,i=e,o=this._nodes.values();!0!==(n=o.next()).done;)i=t(i,(r=n.value).key,r.attributes);return i},i.nodeEntries=function(){var t=this._nodes.values();return new O((function(){var e=t.next();if(e.done)return e;var n=e.value;return{value:{node:n.key,attributes:n.attributes},done:!1}}))},i.export=function(){var t=new Array(this._nodes.size),e=0;this._nodes.forEach((function(n,r){t[e++]=function(t,e){var n={key:t};return p(e.attributes)||(n.attributes=c({},e.attributes)),n}(r,n)}));var n=new Array(this._edges.size);return e=0,this._edges.forEach((function(t,r){n[e++]=function(t,e){var n={key:t,source:e.source.key,target:e.target.key};return p(e.attributes)||(n.attributes=c({},e.attributes)),e.undirected&&(n.undirected=!0),n}(r,t)})),{options:{type:this.type,multi:this.multi,allowSelfLoops:this.allowSelfLoops},attributes:this.getAttributes(),nodes:t,edges:n}},i.import=function(t){var e,n,r,i,o,a=this,u=arguments.length>1&&void 0!==arguments[1]&&arguments[1];if(d(t))return t.forEachNode((function(t,e){u?a.mergeNode(t,e):a.addNode(t,e)})),t.forEachEdge((function(t,e,n,r,i,o,c){u?c?a.mergeUndirectedEdgeWithKey(t,n,r,e):a.mergeDirectedEdgeWithKey(t,n,r,e):c?a.addUndirectedEdgeWithKey(t,n,r,e):a.addDirectedEdgeWithKey(t,n,r,e)})),this;if(!h(t))throw new F("Graph.import: invalid argument. Expecting a serialized graph or, alternatively, a Graph instance.");if(t.attributes){if(!h(t.attributes))throw new F("Graph.import: invalid attributes. Expecting a plain object.");u?this.mergeAttributes(t.attributes):this.replaceAttributes(t.attributes)}if(t.nodes){if(r=t.nodes,!Array.isArray(r))throw new F("Graph.import: invalid nodes. Expecting an array.");for(e=0,n=r.length;e<n;e++){At(i=r[e]);var c=i,s=c.key,p=c.attributes;u?this.mergeNode(s,p):this.addNode(s,p)}}if(t.edges){if(r=t.edges,!Array.isArray(r))throw new F("Graph.import: invalid edges. Expecting an array.");for(e=0,n=r.length;e<n;e++){St(o=r[e]);var f=o,l=f.source,g=f.target,y=f.attributes,w=f.undirected,v=void 0!==w&&w;"key"in o?(u?v?this.mergeUndirectedEdgeWithKey:this.mergeDirectedEdgeWithKey:v?this.addUndirectedEdgeWithKey:this.addDirectedEdgeWithKey).call(this,o.key,l,g,y):(u?v?this.mergeUndirectedEdge:this.mergeDirectedEdge:v?this.addUndirectedEdge:this.addDirectedEdge).call(this,l,g,y)}}return this},i.nullCopy=function(t){var e=new r(c({},this._options,t));return e.replaceAttributes(c({},this.getAttributes())),e},i.emptyCopy=function(t){var e=this.nullCopy(t);return this._nodes.forEach((function(t,n){var r=c({},t.attributes);t=new e.NodeDataClass(n,r),e._nodes.set(n,t)})),e},i.copy=function(t){if("string"==typeof(t=t||{}).type&&t.type!==this.type&&"mixed"!==t.type)throw new Y('Graph.copy: cannot create an incompatible copy from "'.concat(this.type,'" type to "').concat(t.type,'" because this would mean losing information about the current graph.'));if("boolean"==typeof t.multi&&t.multi!==this.multi&&!0!==t.multi)throw new Y("Graph.copy: cannot create an incompatible copy by downgrading a multi graph to a simple one because this would mean losing information about the current graph.");if("boolean"==typeof t.allowSelfLoops&&t.allowSelfLoops!==this.allowSelfLoops&&!0!==t.allowSelfLoops)throw new Y("Graph.copy: cannot create an incompatible copy from a graph allowing self loops to one that does not because this would mean losing information about the current graph.");for(var e,n,r=this.emptyCopy(t),i=this._edges.values();!0!==(e=i.next()).done;)Ct(r,"copy",!1,(n=e.value).undirected,n.key,n.source.key,n.target.key,c({},n.attributes));return r},i.toJSON=function(){return this.export()},i.toString=function(){return"[object Graph]"},i.inspect=function(){var e=this,n={};this._nodes.forEach((function(t,e){n[e]=t.attributes}));var r={},i={};this._edges.forEach((function(t,n){var o,a=t.undirected?"--":"->",u="",c=t.source.key,s=t.target.key;t.undirected&&c>s&&(o=c,c=s,s=o);var d="(".concat(c,")").concat(a,"(").concat(s,")");n.startsWith("geid_")?e.multi&&(void 0===i[d]?i[d]=0:i[d]++,u+="".concat(i[d],". ")):u+="[".concat(n,"]: "),r[u+=d]=t.attributes}));var o={};for(var a in this)this.hasOwnProperty(a)&&!Nt.has(a)&&"function"!=typeof this[a]&&"symbol"!==t(a)&&(o[a]=this[a]);return o.attributes=this._attributes,o.nodes=n,o.edges=r,f(o,"constructor",this.constructor),o},r}(w.exports.EventEmitter);"undefined"!=typeof Symbol&&(Wt.prototype[Symbol.for("nodejs.util.inspect.custom")]=Wt.prototype.inspect),[{name:function(t){return"".concat(t,"Edge")},generateKey:!0},{name:function(t){return"".concat(t,"DirectedEdge")},generateKey:!0,type:"directed"},{name:function(t){return"".concat(t,"UndirectedEdge")},generateKey:!0,type:"undirected"},{name:function(t){return"".concat(t,"EdgeWithKey")}},{name:function(t){return"".concat(t,"DirectedEdgeWithKey")},type:"directed"},{name:function(t){return"".concat(t,"UndirectedEdgeWithKey")},type:"undirected"}].forEach((function(t){["add","merge","update"].forEach((function(e){var n=t.name(e),r="add"===e?Ct:zt;t.generateKey?Wt.prototype[n]=function(i,o,a){return r(this,n,!0,"undirected"===(t.type||this.type),null,i,o,a,"update"===e)}:Wt.prototype[n]=function(i,o,a,u){return r(this,n,!1,"undirected"===(t.type||this.type),i,o,a,u,"update"===e)}}))})),function(t){X.forEach((function(e){var n=e.name,r=e.attacher;r(t,n("Node"),0),r(t,n("Source"),1),r(t,n("Target"),2),r(t,n("Opposite"),3)}))}(Wt),function(t){Z.forEach((function(e){var n=e.name,r=e.attacher;r(t,n("Edge"),"mixed"),r(t,n("DirectedEdge"),"directed"),r(t,n("UndirectedEdge"),"undirected")}))}(Wt),function(t){nt.forEach((function(e){!function(t,e){var n=e.name,r=e.type,i=e.direction;t.prototype[n]=function(t,e){if("mixed"!==r&&"mixed"!==this.type&&r!==this.type)return[];if(!arguments.length)return st(this,r);if(1===arguments.length){t=""+t;var o=this._nodes.get(t);if(void 0===o)throw new I("Graph.".concat(n,': could not find the "').concat(t,'" node in the graph.'));return ft(this.multi,"mixed"===r?this.type:r,i,o)}if(2===arguments.length){t=""+t,e=""+e;var a=this._nodes.get(t);if(!a)throw new I("Graph.".concat(n,':  could not find the "').concat(t,'" source node in the graph.'));if(!this._nodes.has(e))throw new I("Graph.".concat(n,':  could not find the "').concat(e,'" target node in the graph.'));return yt(r,this.multi,i,a,e)}throw new F("Graph.".concat(n,": too many arguments (expecting 0, 1 or 2 and got ").concat(arguments.length,")."))}}(t,e),function(t,e){var n=e.name,r=e.type,i=e.direction,o="forEach"+n[0].toUpperCase()+n.slice(1,-1);t.prototype[o]=function(t,e,n){if("mixed"===r||"mixed"===this.type||r===this.type){if(1===arguments.length)return dt(!1,this,r,n=t);if(2===arguments.length){t=""+t,n=e;var a=this._nodes.get(t);if(void 0===a)throw new I("Graph.".concat(o,': could not find the "').concat(t,'" node in the graph.'));return pt(!1,this.multi,"mixed"===r?this.type:r,i,a,n)}if(3===arguments.length){t=""+t,e=""+e;var u=this._nodes.get(t);if(!u)throw new I("Graph.".concat(o,':  could not find the "').concat(t,'" source node in the graph.'));if(!this._nodes.has(e))throw new I("Graph.".concat(o,':  could not find the "').concat(e,'" target node in the graph.'));return gt(!1,r,this.multi,i,u,e,n)}throw new F("Graph.".concat(o,": too many arguments (expecting 1, 2 or 3 and got ").concat(arguments.length,")."))}};var a="map"+n[0].toUpperCase()+n.slice(1);t.prototype[a]=function(){var t,e=Array.prototype.slice.call(arguments),n=e.pop();if(0===e.length){var i=0;"directed"!==r&&(i+=this.undirectedSize),"undirected"!==r&&(i+=this.directedSize),t=new Array(i);var a=0;e.push((function(e,r,i,o,u,c,s){t[a++]=n(e,r,i,o,u,c,s)}))}else t=[],e.push((function(e,r,i,o,a,u,c){t.push(n(e,r,i,o,a,u,c))}));return this[o].apply(this,e),t};var u="filter"+n[0].toUpperCase()+n.slice(1);t.prototype[u]=function(){var t=Array.prototype.slice.call(arguments),e=t.pop(),n=[];return t.push((function(t,r,i,o,a,u,c){e(t,r,i,o,a,u,c)&&n.push(t)})),this[o].apply(this,t),n};var c="reduce"+n[0].toUpperCase()+n.slice(1);t.prototype[c]=function(){var t,e,n=Array.prototype.slice.call(arguments);if(n.length<2||n.length>4)throw new F("Graph.".concat(c,": invalid number of arguments (expecting 2, 3 or 4 and got ").concat(n.length,")."));if("function"==typeof n[n.length-1]&&"function"!=typeof n[n.length-2])throw new F("Graph.".concat(c,": missing initial value. You must provide it because the callback takes more than one argument and we cannot infer the initial value from the first iteration, as you could with a simple array."));2===n.length?(t=n[0],e=n[1],n=[]):3===n.length?(t=n[1],e=n[2],n=[n[0]]):4===n.length&&(t=n[2],e=n[3],n=[n[0],n[1]]);var r=e;return n.push((function(e,n,i,o,a,u,c){r=t(r,e,n,i,o,a,u,c)})),this[o].apply(this,n),r}}(t,e),function(t,e){var n=e.name,r=e.type,i=e.direction,o="find"+n[0].toUpperCase()+n.slice(1,-1);t.prototype[o]=function(t,e,n){if("mixed"!==r&&"mixed"!==this.type&&r!==this.type)return!1;if(1===arguments.length)return dt(!0,this,r,n=t);if(2===arguments.length){t=""+t,n=e;var a=this._nodes.get(t);if(void 0===a)throw new I("Graph.".concat(o,': could not find the "').concat(t,'" node in the graph.'));return pt(!0,this.multi,"mixed"===r?this.type:r,i,a,n)}if(3===arguments.length){t=""+t,e=""+e;var u=this._nodes.get(t);if(!u)throw new I("Graph.".concat(o,':  could not find the "').concat(t,'" source node in the graph.'));if(!this._nodes.has(e))throw new I("Graph.".concat(o,':  could not find the "').concat(e,'" target node in the graph.'));return gt(!0,r,this.multi,i,u,e,n)}throw new F("Graph.".concat(o,": too many arguments (expecting 1, 2 or 3 and got ").concat(arguments.length,")."))};var a="some"+n[0].toUpperCase()+n.slice(1,-1);t.prototype[a]=function(){var t=Array.prototype.slice.call(arguments),e=t.pop();return t.push((function(t,n,r,i,o,a,u){return e(t,n,r,i,o,a,u)})),!!this[o].apply(this,t)};var u="every"+n[0].toUpperCase()+n.slice(1,-1);t.prototype[u]=function(){var t=Array.prototype.slice.call(arguments),e=t.pop();return t.push((function(t,n,r,i,o,a,u){return!e(t,n,r,i,o,a,u)})),!this[o].apply(this,t)}}(t,e),function(t,e){var n=e.name,r=e.type,i=e.direction,o=n.slice(0,-1)+"Entries";t.prototype[o]=function(t,e){if("mixed"!==r&&"mixed"!==this.type&&r!==this.type)return O.empty();if(!arguments.length)return ht(this,r);if(1===arguments.length){t=""+t;var n=this._nodes.get(t);if(!n)throw new I("Graph.".concat(o,': could not find the "').concat(t,'" node in the graph.'));return lt(r,i,n)}if(2===arguments.length){t=""+t,e=""+e;var a=this._nodes.get(t);if(!a)throw new I("Graph.".concat(o,':  could not find the "').concat(t,'" source node in the graph.'));if(!this._nodes.has(e))throw new I("Graph.".concat(o,':  could not find the "').concat(e,'" target node in the graph.'));return wt(r,i,a,e)}throw new F("Graph.".concat(o,": too many arguments (expecting 0, 1 or 2 and got ").concat(arguments.length,")."))}}(t,e)}))}(Wt),function(t){vt.forEach((function(e){Gt(t,e),function(t,e){var n=e.name,r=e.type,i=e.direction,o="forEach"+n[0].toUpperCase()+n.slice(1,-1);t.prototype[o]=function(t,e){if("mixed"===r||"mixed"===this.type||r===this.type){t=""+t;var n=this._nodes.get(t);if(void 0===n)throw new I("Graph.".concat(o,': could not find the "').concat(t,'" node in the graph.'));kt(!1,"mixed"===r?this.type:r,i,n,e)}};var a="map"+n[0].toUpperCase()+n.slice(1);t.prototype[a]=function(t,e){var n=[];return this[o](t,(function(t,r){n.push(e(t,r))})),n};var u="filter"+n[0].toUpperCase()+n.slice(1);t.prototype[u]=function(t,e){var n=[];return this[o](t,(function(t,r){e(t,r)&&n.push(t)})),n};var c="reduce"+n[0].toUpperCase()+n.slice(1);t.prototype[c]=function(t,e,n){if(arguments.length<3)throw new F("Graph.".concat(c,": missing initial value. You must provide it because the callback takes more than one argument and we cannot infer the initial value from the first iteration, as you could with a simple array."));var r=n;return this[o](t,(function(t,n){r=e(r,t,n)})),r}}(t,e),function(t,e){var n=e.name,r=e.type,i=e.direction,o=n[0].toUpperCase()+n.slice(1,-1),a="find"+o;t.prototype[a]=function(t,e){if("mixed"===r||"mixed"===this.type||r===this.type){t=""+t;var n=this._nodes.get(t);if(void 0===n)throw new I("Graph.".concat(a,': could not find the "').concat(t,'" node in the graph.'));return kt(!0,"mixed"===r?this.type:r,i,n,e)}};var u="some"+o;t.prototype[u]=function(t,e){return!!this[a](t,e)};var c="every"+o;t.prototype[c]=function(t,e){return!this[a](t,(function(t,n){return!e(t,n)}))}}(t,e),xt(t,e)}))}(Wt);var Pt=function(t){function n(e){var n=c({type:"directed"},e);if("multi"in n&&!1!==n.multi)throw new F("DirectedGraph.from: inconsistent indication that the graph should be multi in given options!");if("directed"!==n.type)throw new F('DirectedGraph.from: inconsistent "'+n.type+'" type in given options!');return t.call(this,n)||this}return e(n,t),n}(Wt),Rt=function(t){function n(e){var n=c({type:"undirected"},e);if("multi"in n&&!1!==n.multi)throw new F("UndirectedGraph.from: inconsistent indication that the graph should be multi in given options!");if("undirected"!==n.type)throw new F('UndirectedGraph.from: inconsistent "'+n.type+'" type in given options!');return t.call(this,n)||this}return e(n,t),n}(Wt),Kt=function(t){function n(e){var n=c({multi:!0},e);if("multi"in n&&!0!==n.multi)throw new F("MultiGraph.from: inconsistent indication that the graph should be simple in given options!");return t.call(this,n)||this}return e(n,t),n}(Wt),Tt=function(t){function n(e){var n=c({type:"directed",multi:!0},e);if("multi"in n&&!0!==n.multi)throw new F("MultiDirectedGraph.from: inconsistent indication that the graph should be simple in given options!");if("directed"!==n.type)throw new F('MultiDirectedGraph.from: inconsistent "'+n.type+'" type in given options!');return t.call(this,n)||this}return e(n,t),n}(Wt),Bt=function(t){function n(e){var n=c({type:"undirected",multi:!0},e);if("multi"in n&&!0!==n.multi)throw new F("MultiUndirectedGraph.from: inconsistent indication that the graph should be simple in given options!");if("undirected"!==n.type)throw new F('MultiUndirectedGraph.from: inconsistent "'+n.type+'" type in given options!');return t.call(this,n)||this}return e(n,t),n}(Wt);function Ft(t){t.from=function(e,n){var r=c({},e.options,n),i=new t(r);return i.import(e),i}}return Ft(Wt),Ft(Pt),Ft(Rt),Ft(Kt),Ft(Tt),Ft(Bt),Wt.Graph=Wt,Wt.DirectedGraph=Pt,Wt.UndirectedGraph=Rt,Wt.MultiGraph=Kt,Wt.MultiDirectedGraph=Tt,Wt.MultiUndirectedGraph=Bt,Wt.InvalidArgumentsGraphError=F,Wt.NotFoundGraphError=I,Wt.UsageGraphError=Y,Wt}));
-//# sourceMappingURL=graphology.umd.min.js.map
diff --git a/libs/shared/graph-layouts/node_modules/graphology/package.json b/libs/shared/graph-layouts/node_modules/graphology/package.json
deleted file mode 100644
index 192894e7d..000000000
--- a/libs/shared/graph-layouts/node_modules/graphology/package.json
+++ /dev/null
@@ -1,84 +0,0 @@
-{
-  "name": "graphology",
-  "version": "0.24.1",
-  "description": "A robust and multipurpose Graph object for JavaScript.",
-  "main": "dist/graphology.cjs.js",
-  "module": "dist/graphology.esm.js",
-  "browser": "dist/graphology.umd.min.js",
-  "types": "dist/graphology.d.ts",
-  "scripts": {
-    "clean": "rimraf dist specs",
-    "build": "npm run clean && rollup -c && babel tests --out-dir specs && cp src/endpoint.esm.d.ts dist/graphology.d.ts",
-    "prepare": "npm run build",
-    "prepublishOnly": "npm test && npm run test:types && npm run build",
-    "test": "mocha -u exports --require @babel/register ./test.js",
-    "test:types": "tsc --lib es2015,dom --noEmit --noImplicitAny --noImplicitReturns --strictNullChecks ./test-types.ts"
-  },
-  "files": [
-    "dist/*.js",
-    "dist/*.ts",
-    "specs"
-  ],
-  "keywords": [
-    "graph",
-    "graph theory",
-    "directed",
-    "undirected",
-    "network"
-  ],
-  "repository": {
-    "type": "git",
-    "url": "git+https://github.com/graphology/graphology.git"
-  },
-  "contributors": [
-    {
-      "name": "Alexis Jacomy",
-      "url": "http://github.com/jacomyal"
-    },
-    {
-      "name": "Benjamin Ooghe-Tabanou",
-      "url": "http://github.com/boogheta"
-    },
-    {
-      "name": "Guillaume Plique",
-      "url": "http://github.com/Yomguithereal"
-    }
-  ],
-  "license": "MIT",
-  "bugs": {
-    "url": "https://github.com/graphology/graphology/issues"
-  },
-  "homepage": "https://github.com/graphology/graphology#readme",
-  "dependencies": {
-    "events": "^3.3.0",
-    "obliterator": "^2.0.2"
-  },
-  "peerDependencies": {
-    "graphology-types": ">=0.24.0"
-  },
-  "babel": {
-    "presets": [
-      "@babel/preset-env"
-    ],
-    "plugins": [
-      [
-        "@babel/transform-classes",
-        {
-          "loose": true
-        }
-      ],
-      [
-        "@babel/transform-destructuring",
-        {
-          "loose": true
-        }
-      ],
-      [
-        "@babel/transform-spread",
-        {
-          "loose": true
-        }
-      ]
-    ]
-  }
-}
diff --git a/libs/shared/graph-layouts/node_modules/graphology/specs/attributes.js b/libs/shared/graph-layouts/node_modules/graphology/specs/attributes.js
deleted file mode 100644
index f026c38ea..000000000
--- a/libs/shared/graph-layouts/node_modules/graphology/specs/attributes.js
+++ /dev/null
@@ -1,992 +0,0 @@
-"use strict";
-
-Object.defineProperty(exports, "__esModule", {
-  value: true
-});
-exports["default"] = attributes;
-
-var _assert = _interopRequireDefault(require("assert"));
-
-var _helpers = require("./helpers");
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
-
-function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
-
-function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
-
-function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
-
-function attributes(Graph, checkers) {
-  var invalid = checkers.invalid,
-      notFound = checkers.notFound,
-      usage = checkers.usage;
-
-  function commonTests(method) {
-    return _defineProperty({}, '#.' + method, {
-      'it should throw if the given path is not found.': function itShouldThrowIfTheGivenPathIsNotFound() {
-        if (!method.includes('Edge')) return;
-        var graph = new Graph();
-
-        _assert["default"]["throws"](function () {
-          graph[method]('source', 'target', 'name', 'value');
-        }, notFound());
-      },
-      'it should throw when using a path on a multi graph.': function itShouldThrowWhenUsingAPathOnAMultiGraph() {
-        if (!method.includes('Edge')) return;
-        var graph = new Graph({
-          multi: true
-        });
-
-        _assert["default"]["throws"](function () {
-          graph[method]('source', 'target', 'name', 'value');
-        }, usage());
-      },
-      'it should throw if the element is not found in the graph.': function itShouldThrowIfTheElementIsNotFoundInTheGraph() {
-        var graph = new Graph();
-
-        if (method.includes('Edge') && method.includes('Directed') || method.includes('Undirected')) {
-          _assert["default"]["throws"](function () {
-            graph[method]('Test');
-          }, usage());
-        } else {
-          _assert["default"]["throws"](function () {
-            graph[method]('Test');
-          }, notFound());
-        }
-      }
-    });
-  }
-
-  var tests = {};
-  var relevantMethods = Object.keys(Graph.prototype).filter(function (name) {
-    return (name.includes('NodeAttribute') || name.includes('EdgeAttribute') || name.includes('SourceAttribute') || name.includes('TargetAttribute') || name.includes('OppositeAttribute')) && !name.includes('Each');
-  });
-  relevantMethods.forEach(function (method) {
-    return (0, _helpers.deepMerge)(tests, commonTests(method));
-  });
-  return (0, _helpers.deepMerge)(tests, {
-    '#.getAttribute': {
-      'it should return the correct value.': function itShouldReturnTheCorrectValue() {
-        var graph = new Graph();
-        graph.setAttribute('name', 'graph');
-
-        _assert["default"].strictEqual(graph.getAttribute('name'), 'graph');
-      },
-      'it should return undefined if the attribute does not exist.': function itShouldReturnUndefinedIfTheAttributeDoesNotExist() {
-        var graph = new Graph();
-
-        _assert["default"].strictEqual(graph.getAttribute('name'), undefined);
-      }
-    },
-    '#.getNodeAttribute': {
-      'it should return the correct value.': function itShouldReturnTheCorrectValue() {
-        var graph = new Graph();
-        graph.addNode('Martha', {
-          age: 34
-        });
-
-        _assert["default"].strictEqual(graph.getNodeAttribute('Martha', 'age'), 34);
-      },
-      'it should return undefined if the attribute does not exist.': function itShouldReturnUndefinedIfTheAttributeDoesNotExist() {
-        var graph = new Graph();
-        graph.addNode('Martha');
-
-        _assert["default"].strictEqual(graph.getNodeAttribute('Martha', 'age'), undefined);
-      }
-    },
-    '#.getSourceAttribute': {
-      'it should return the correct value.': function itShouldReturnTheCorrectValue() {
-        var graph = new Graph();
-        graph.addNode('Martha', {
-          age: 34
-        });
-
-        var _graph$mergeEdge = graph.mergeEdge('Martha', 'Riwan'),
-            edge = _graph$mergeEdge[0];
-
-        _assert["default"].strictEqual(graph.getSourceAttribute(edge, 'age'), 34);
-      },
-      'it should return undefined if the attribute does not exist.': function itShouldReturnUndefinedIfTheAttributeDoesNotExist() {
-        var graph = new Graph();
-        graph.addNode('Martha');
-
-        var _graph$mergeEdge2 = graph.mergeEdge('Martha', 'Riwan'),
-            edge = _graph$mergeEdge2[0];
-
-        _assert["default"].strictEqual(graph.getSourceAttribute(edge, 'age'), undefined);
-      }
-    },
-    '#.getTargetAttribute': {
-      'it should return the correct value.': function itShouldReturnTheCorrectValue() {
-        var graph = new Graph();
-        graph.addNode('Martha', {
-          age: 34
-        });
-
-        var _graph$mergeEdge3 = graph.mergeEdge('Riwan', 'Martha'),
-            edge = _graph$mergeEdge3[0];
-
-        _assert["default"].strictEqual(graph.getTargetAttribute(edge, 'age'), 34);
-      },
-      'it should return undefined if the attribute does not exist.': function itShouldReturnUndefinedIfTheAttributeDoesNotExist() {
-        var graph = new Graph();
-        graph.addNode('Martha');
-
-        var _graph$mergeEdge4 = graph.mergeEdge('Riwan', 'Martha'),
-            edge = _graph$mergeEdge4[0];
-
-        _assert["default"].strictEqual(graph.getTargetAttribute(edge, 'age'), undefined);
-      }
-    },
-    '#.getOppositeAttribute': {
-      'it should return the correct value.': function itShouldReturnTheCorrectValue() {
-        var graph = new Graph();
-        graph.addNode('Martha', {
-          age: 34
-        });
-        graph.addNode('Riwan', {
-          age: 25
-        });
-
-        var _graph$mergeEdge5 = graph.mergeEdge('Riwan', 'Martha'),
-            edge = _graph$mergeEdge5[0];
-
-        _assert["default"].strictEqual(graph.getOppositeAttribute('Riwan', edge, 'age'), 34);
-
-        _assert["default"].strictEqual(graph.getOppositeAttribute('Martha', edge, 'age'), 25);
-      }
-    },
-    '#.getEdgeAttribute': {
-      'it should return the correct value.': function itShouldReturnTheCorrectValue() {
-        var graph = new Graph();
-        (0, _helpers.addNodesFrom)(graph, ['John', 'Thomas']);
-        var edge = graph.addEdge('John', 'Thomas', {
-          weight: 2
-        });
-
-        _assert["default"].strictEqual(graph.getEdgeAttribute(edge, 'weight'), 2);
-
-        _assert["default"].strictEqual(graph.getEdgeAttribute('John', 'Thomas', 'weight'), 2);
-      },
-      'it should also work with typed edges.': function itShouldAlsoWorkWithTypedEdges() {
-        var graph = new Graph();
-        (0, _helpers.addNodesFrom)(graph, ['John', 'Thomas']);
-        graph.addDirectedEdge('John', 'Thomas', {
-          weight: 2
-        });
-        graph.addUndirectedEdge('John', 'Thomas', {
-          weight: 3
-        });
-
-        _assert["default"].strictEqual(graph.getDirectedEdgeAttribute('John', 'Thomas', 'weight'), 2);
-
-        _assert["default"].strictEqual(graph.getUndirectedEdgeAttribute('John', 'Thomas', 'weight'), 3);
-      },
-      'it should return undefined if the attribute does not exist.': function itShouldReturnUndefinedIfTheAttributeDoesNotExist() {
-        var graph = new Graph();
-        (0, _helpers.addNodesFrom)(graph, ['John', 'Thomas']);
-        var edge = graph.addEdge('John', 'Thomas');
-
-        _assert["default"].strictEqual(graph.getEdgeAttribute(edge, 'weight'), undefined);
-      }
-    },
-    '#.getAttributes': {
-      'it should return the correct value.': function itShouldReturnTheCorrectValue() {
-        var graph = new Graph();
-        graph.setAttribute('name', 'graph');
-
-        _assert["default"].deepStrictEqual(graph.getAttributes(), {
-          name: 'graph'
-        });
-      },
-      'it should return an empty object if the node does not have attributes.': function itShouldReturnAnEmptyObjectIfTheNodeDoesNotHaveAttributes() {
-        var graph = new Graph();
-
-        _assert["default"].deepStrictEqual(graph.getAttributes(), {});
-      }
-    },
-    '#.getNodeAttributes': {
-      'it should return the correct value.': function itShouldReturnTheCorrectValue() {
-        var graph = new Graph();
-        graph.addNode('Martha', {
-          age: 34
-        });
-
-        _assert["default"].deepStrictEqual(graph.getNodeAttributes('Martha'), {
-          age: 34
-        });
-      },
-      'it should return an empty object if the node does not have attributes.': function itShouldReturnAnEmptyObjectIfTheNodeDoesNotHaveAttributes() {
-        var graph = new Graph();
-        graph.addNode('Martha');
-
-        _assert["default"].deepStrictEqual(graph.getNodeAttributes('Martha'), {});
-      }
-    },
-    '#.getEdgeAttributes': {
-      'it should return the correct value.': function itShouldReturnTheCorrectValue() {
-        var graph = new Graph();
-        (0, _helpers.addNodesFrom)(graph, ['John', 'Thomas']);
-        var edge = graph.addEdge('John', 'Thomas', {
-          weight: 2
-        });
-
-        _assert["default"].deepStrictEqual(graph.getEdgeAttributes(edge), {
-          weight: 2
-        });
-
-        _assert["default"].deepStrictEqual(graph.getEdgeAttributes('John', 'Thomas'), {
-          weight: 2
-        });
-      },
-      'it should also work with typed edges.': function itShouldAlsoWorkWithTypedEdges() {
-        var graph = new Graph();
-        (0, _helpers.addNodesFrom)(graph, ['John', 'Thomas']);
-        graph.addDirectedEdge('John', 'Thomas', {
-          weight: 2
-        });
-        graph.addUndirectedEdge('John', 'Thomas', {
-          weight: 3
-        });
-
-        _assert["default"].deepStrictEqual(graph.getDirectedEdgeAttributes('John', 'Thomas', 'weight'), {
-          weight: 2
-        });
-
-        _assert["default"].deepStrictEqual(graph.getUndirectedEdgeAttributes('John', 'Thomas', 'weight'), {
-          weight: 3
-        });
-      },
-      'it should return an empty object if the edge does not have attributes.': function itShouldReturnAnEmptyObjectIfTheEdgeDoesNotHaveAttributes() {
-        var graph = new Graph();
-        (0, _helpers.addNodesFrom)(graph, ['John', 'Thomas']);
-        var edge = graph.addEdge('John', 'Thomas');
-
-        _assert["default"].deepStrictEqual(graph.getEdgeAttributes(edge), {});
-      }
-    },
-    '#.hasAttribute': {
-      'it should correctly return whether the attribute is set.': function itShouldCorrectlyReturnWhetherTheAttributeIsSet() {
-        var graph = new Graph();
-        graph.setAttribute('name', 'graph');
-
-        _assert["default"].strictEqual(graph.hasAttribute('name'), true);
-
-        _assert["default"].strictEqual(graph.hasAttribute('info'), false);
-      },
-      'it does not fail with typical prototypal properties.': function itDoesNotFailWithTypicalPrototypalProperties() {
-        var graph = new Graph();
-
-        _assert["default"].strictEqual(graph.hasAttribute('toString'), false);
-      }
-    },
-    '#.hasNodeAttribute': {
-      'it should correctly return whether the attribute is set.': function itShouldCorrectlyReturnWhetherTheAttributeIsSet() {
-        var graph = new Graph();
-        graph.addNode('John', {
-          age: 20
-        });
-
-        _assert["default"].strictEqual(graph.hasNodeAttribute('John', 'age'), true);
-
-        _assert["default"].strictEqual(graph.hasNodeAttribute('John', 'eyes'), false);
-      },
-      'it does not fail with typical prototypal properties.': function itDoesNotFailWithTypicalPrototypalProperties() {
-        var graph = new Graph();
-        graph.addNode('John', {
-          age: 20
-        });
-
-        _assert["default"].strictEqual(graph.hasNodeAttribute('John', 'toString'), false);
-      }
-    },
-    '#.hasEdgeAttribute': {
-      'it should correctly return whether the attribute is set.': function itShouldCorrectlyReturnWhetherTheAttributeIsSet() {
-        var graph = new Graph();
-        (0, _helpers.addNodesFrom)(graph, ['John', 'Martha']);
-        graph.addEdgeWithKey('J->M', 'John', 'Martha', {
-          weight: 10
-        });
-
-        _assert["default"].strictEqual(graph.hasEdgeAttribute('J->M', 'weight'), true);
-
-        _assert["default"].strictEqual(graph.hasEdgeAttribute('J->M', 'type'), false);
-      },
-      'it should also work with typed edges.': function itShouldAlsoWorkWithTypedEdges() {
-        var graph = new Graph();
-        (0, _helpers.addNodesFrom)(graph, ['John', 'Thomas']);
-        graph.addDirectedEdge('John', 'Thomas', {
-          weight: 2
-        });
-        graph.addUndirectedEdge('John', 'Thomas');
-
-        _assert["default"].strictEqual(graph.hasDirectedEdgeAttribute('John', 'Thomas', 'weight'), true);
-
-        _assert["default"].strictEqual(graph.hasUndirectedEdgeAttribute('John', 'Thomas', 'weight'), false);
-      },
-      'it does not fail with typical prototypal properties.': function itDoesNotFailWithTypicalPrototypalProperties() {
-        var graph = new Graph();
-        (0, _helpers.addNodesFrom)(graph, ['John', 'Martha']);
-        graph.addEdgeWithKey('J->M', 'John', 'Martha', {
-          weight: 10
-        });
-
-        _assert["default"].strictEqual(graph.hasEdgeAttribute('J->M', 'toString'), false);
-      }
-    },
-    '#.setAttribute': {
-      "it should correctly set the graph's attribute.": function itShouldCorrectlySetTheGraphSAttribute() {
-        var graph = new Graph();
-        graph.setAttribute('name', 'graph');
-
-        _assert["default"].strictEqual(graph.getAttribute('name'), 'graph');
-      }
-    },
-    '#.setNodeAttribute': {
-      "it should correctly set the node's attribute.": function itShouldCorrectlySetTheNodeSAttribute() {
-        var graph = new Graph();
-        graph.addNode('John', {
-          age: 20
-        });
-        graph.setNodeAttribute('John', 'age', 45);
-
-        _assert["default"].strictEqual(graph.getNodeAttribute('John', 'age'), 45);
-      }
-    },
-    '#.setEdgeAttribute': {
-      "it should correctly set the edge's attribute.": function itShouldCorrectlySetTheEdgeSAttribute() {
-        var graph = new Graph();
-        (0, _helpers.addNodesFrom)(graph, ['John', 'Martha']);
-        var edge = graph.addEdge('John', 'Martha', {
-          weight: 3
-        });
-        graph.setEdgeAttribute(edge, 'weight', 40);
-
-        _assert["default"].strictEqual(graph.getEdgeAttribute(edge, 'weight'), 40);
-
-        graph.setEdgeAttribute('John', 'Martha', 'weight', 60);
-
-        _assert["default"].strictEqual(graph.getEdgeAttribute(edge, 'weight'), 60);
-      },
-      'it should also work with typed edges.': function itShouldAlsoWorkWithTypedEdges() {
-        var graph = new Graph();
-        (0, _helpers.addNodesFrom)(graph, ['John', 'Thomas']);
-        graph.addDirectedEdge('John', 'Thomas', {
-          weight: 0
-        });
-        graph.addUndirectedEdge('John', 'Thomas', {
-          weight: 0
-        });
-        graph.setDirectedEdgeAttribute('John', 'Thomas', 'weight', 2);
-        graph.setUndirectedEdgeAttribute('John', 'Thomas', 'weight', 3);
-
-        _assert["default"].strictEqual(graph.getDirectedEdgeAttribute('John', 'Thomas', 'weight'), 2);
-
-        _assert["default"].strictEqual(graph.getUndirectedEdgeAttribute('John', 'Thomas', 'weight'), 3);
-      }
-    },
-    '#.updateAttribute': {
-      'it should throw if the updater is not a function.': function itShouldThrowIfTheUpdaterIsNotAFunction() {
-        var graph = new Graph();
-        graph.setAttribute('count', 0);
-
-        _assert["default"]["throws"](function () {
-          graph.updateAttribute('count', {
-            hello: 'world'
-          });
-        }, invalid());
-      },
-      "it should correctly set the graph's attribute.": function itShouldCorrectlySetTheGraphSAttribute() {
-        var graph = new Graph();
-        graph.setAttribute('name', 'graph');
-        graph.updateAttribute('name', function (name) {
-          return name + '1';
-        });
-
-        _assert["default"].strictEqual(graph.getAttribute('name'), 'graph1');
-      },
-      'the given value should be undefined if not found.': function theGivenValueShouldBeUndefinedIfNotFound() {
-        var graph = new Graph();
-
-        var updater = function updater(x) {
-          _assert["default"].strictEqual(x, undefined);
-
-          return 'graph';
-        };
-
-        graph.updateAttribute('name', updater);
-
-        _assert["default"].strictEqual(graph.getAttribute('name'), 'graph');
-      }
-    },
-    '#.updateNodeAttribute': {
-      'it should throw if given an invalid updater.': function itShouldThrowIfGivenAnInvalidUpdater() {
-        var graph = new Graph();
-        graph.addNode('John', {
-          age: 20
-        });
-
-        _assert["default"]["throws"](function () {
-          graph.updateNodeAttribute('John', 'age', {
-            hello: 'world'
-          });
-        }, invalid());
-      },
-      'it should throw if not enough arguments are provided.': function itShouldThrowIfNotEnoughArgumentsAreProvided() {
-        var graph = new Graph();
-        graph.addNode('Lucy');
-
-        _assert["default"]["throws"](function () {
-          graph.updateNodeAttribute('Lucy', {
-            hello: 'world'
-          });
-        }, invalid());
-      },
-      "it should correctly set the node's attribute.": function itShouldCorrectlySetTheNodeSAttribute() {
-        var graph = new Graph();
-        graph.addNode('John', {
-          age: 20
-        });
-        graph.updateNodeAttribute('John', 'age', function (x) {
-          return x + 1;
-        });
-
-        _assert["default"].strictEqual(graph.getNodeAttribute('John', 'age'), 21);
-      },
-      'the given value should be undefined if not found.': function theGivenValueShouldBeUndefinedIfNotFound() {
-        var graph = new Graph();
-        graph.addNode('John');
-
-        var updater = function updater(x) {
-          _assert["default"].strictEqual(x, undefined);
-
-          return 10;
-        };
-
-        graph.updateNodeAttribute('John', 'age', updater);
-
-        _assert["default"].strictEqual(graph.getNodeAttribute('John', 'age'), 10);
-      }
-    },
-    '#.updateEdgeAttribute': {
-      'it should throw if given an invalid updater.': function itShouldThrowIfGivenAnInvalidUpdater() {
-        var graph = new Graph();
-        (0, _helpers.addNodesFrom)(graph, ['John', 'Martha']);
-        graph.addEdge('John', 'Martha', {
-          weight: 3
-        });
-
-        _assert["default"]["throws"](function () {
-          graph.updateEdgeAttribute('John', 'Martha', 'weight', {
-            hello: 'world'
-          });
-        }, invalid());
-      },
-      "it should correctly set the edge's attribute.": function itShouldCorrectlySetTheEdgeSAttribute() {
-        var graph = new Graph();
-        (0, _helpers.addNodesFrom)(graph, ['John', 'Martha']);
-        var edge = graph.addEdge('John', 'Martha', {
-          weight: 3
-        });
-        graph.updateEdgeAttribute(edge, 'weight', function (x) {
-          return x + 1;
-        });
-
-        _assert["default"].strictEqual(graph.getEdgeAttribute(edge, 'weight'), 4);
-
-        graph.updateEdgeAttribute('John', 'Martha', 'weight', function (x) {
-          return x + 2;
-        });
-
-        _assert["default"].strictEqual(graph.getEdgeAttribute(edge, 'weight'), 6);
-      },
-      'it should also work with typed edges.': function itShouldAlsoWorkWithTypedEdges() {
-        var graph = new Graph();
-        (0, _helpers.addNodesFrom)(graph, ['John', 'Thomas']);
-        graph.addDirectedEdge('John', 'Thomas', {
-          weight: 0
-        });
-        graph.addUndirectedEdge('John', 'Thomas', {
-          weight: 0
-        });
-        graph.updateDirectedEdgeAttribute('John', 'Thomas', 'weight', function (x) {
-          return x + 2;
-        });
-        graph.updateUndirectedEdgeAttribute('John', 'Thomas', 'weight', function (x) {
-          return x + 3;
-        });
-
-        _assert["default"].strictEqual(graph.getDirectedEdgeAttribute('John', 'Thomas', 'weight'), 2);
-
-        _assert["default"].strictEqual(graph.getUndirectedEdgeAttribute('John', 'Thomas', 'weight'), 3);
-      },
-      'the given value should be undefined if not found.': function theGivenValueShouldBeUndefinedIfNotFound() {
-        var graph = new Graph();
-        (0, _helpers.addNodesFrom)(graph, ['John', 'Martha']);
-        var edge = graph.addEdge('John', 'Martha');
-
-        var updater = function updater(x) {
-          _assert["default"].strictEqual(x, undefined);
-
-          return 10;
-        };
-
-        graph.updateEdgeAttribute(edge, 'weight', updater);
-
-        _assert["default"].strictEqual(graph.getEdgeAttribute(edge, 'weight'), 10);
-      }
-    },
-    '#.removeAttribute': {
-      'it should correctly remove the attribute.': function itShouldCorrectlyRemoveTheAttribute() {
-        var graph = new Graph();
-        graph.setAttribute('name', 'graph');
-        graph.removeAttribute('name');
-
-        _assert["default"].strictEqual(graph.hasAttribute('name'), false);
-
-        _assert["default"].deepStrictEqual(graph.getAttributes(), {});
-      }
-    },
-    '#.removeNodeAttribute': {
-      'it should correctly remove the attribute.': function itShouldCorrectlyRemoveTheAttribute() {
-        var graph = new Graph();
-        graph.addNode('Martha', {
-          age: 34
-        });
-        graph.removeNodeAttribute('Martha', 'age');
-
-        _assert["default"].strictEqual(graph.hasNodeAttribute('Martha', 'age'), false);
-
-        _assert["default"].deepStrictEqual(graph.getNodeAttributes('Martha'), {});
-      }
-    },
-    '#.removeEdgeAttribute': {
-      'it should correclty remove the attribute.': function itShouldCorrecltyRemoveTheAttribute() {
-        var graph = new Graph();
-
-        var _graph$mergeEdge6 = graph.mergeEdge('John', 'Martha', {
-          weight: 1,
-          size: 3
-        }),
-            edge = _graph$mergeEdge6[0];
-
-        graph.removeEdgeAttribute('John', 'Martha', 'weight');
-        graph.removeEdgeAttribute(edge, 'size');
-
-        _assert["default"].strictEqual(graph.hasEdgeAttribute(edge, 'weight'), false);
-
-        _assert["default"].strictEqual(graph.hasEdgeAttribute(edge, 'size'), false);
-
-        _assert["default"].deepStrictEqual(graph.getEdgeAttributes(edge), {});
-      },
-      'it should also work with typed edges.': function itShouldAlsoWorkWithTypedEdges() {
-        var graph = new Graph();
-        (0, _helpers.addNodesFrom)(graph, ['John', 'Thomas']);
-        graph.addDirectedEdge('John', 'Thomas', {
-          weight: 2
-        });
-        graph.addUndirectedEdge('John', 'Thomas', {
-          weight: 3
-        });
-        graph.removeDirectedEdgeAttribute('John', 'Thomas', 'weight');
-        graph.removeUndirectedEdgeAttribute('John', 'Thomas', 'weight');
-
-        _assert["default"].strictEqual(graph.hasDirectedEdgeAttribute('John', 'Thomas', 'weight'), false);
-
-        _assert["default"].strictEqual(graph.hasUndirectedEdgeAttribute('John', 'Thomas', 'weight'), false);
-      }
-    },
-    '#.replaceAttribute': {
-      'it should throw if given attributes are not a plain object.': function itShouldThrowIfGivenAttributesAreNotAPlainObject() {
-        var graph = new Graph();
-
-        _assert["default"]["throws"](function () {
-          graph.replaceAttributes(true);
-        }, invalid());
-      },
-      'it should correctly replace attributes.': function itShouldCorrectlyReplaceAttributes() {
-        var graph = new Graph();
-        graph.setAttribute('name', 'graph');
-        graph.replaceAttributes({
-          name: 'other graph'
-        });
-
-        _assert["default"].deepStrictEqual(graph.getAttributes(), {
-          name: 'other graph'
-        });
-      }
-    },
-    '#.replaceNodeAttributes': {
-      'it should throw if given attributes are not a plain object.': function itShouldThrowIfGivenAttributesAreNotAPlainObject() {
-        var graph = new Graph();
-        graph.addNode('John');
-
-        _assert["default"]["throws"](function () {
-          graph.replaceNodeAttributes('John', true);
-        }, invalid());
-      },
-      'it should correctly replace attributes.': function itShouldCorrectlyReplaceAttributes() {
-        var graph = new Graph();
-        graph.addNode('John', {
-          age: 45
-        });
-        graph.replaceNodeAttributes('John', {
-          age: 23,
-          eyes: 'blue'
-        });
-
-        _assert["default"].deepStrictEqual(graph.getNodeAttributes('John'), {
-          age: 23,
-          eyes: 'blue'
-        });
-      }
-    },
-    '#.replaceEdgeAttributes': {
-      'it should throw if given attributes are not a plain object.': function itShouldThrowIfGivenAttributesAreNotAPlainObject() {
-        var graph = new Graph();
-        (0, _helpers.addNodesFrom)(graph, ['John', 'Martha']);
-        var edge = graph.addEdge('John', 'Martha');
-
-        _assert["default"]["throws"](function () {
-          graph.replaceEdgeAttributes(edge, true);
-        }, invalid());
-      },
-      'it should also work with typed edges.': function itShouldAlsoWorkWithTypedEdges() {
-        var graph = new Graph();
-        (0, _helpers.addNodesFrom)(graph, ['John', 'Thomas']);
-        graph.addDirectedEdge('John', 'Thomas', {
-          test: 0
-        });
-        graph.addUndirectedEdge('John', 'Thomas', {
-          test: 0
-        });
-        graph.replaceDirectedEdgeAttributes('John', 'Thomas', {
-          weight: 2
-        });
-        graph.replaceUndirectedEdgeAttributes('John', 'Thomas', {
-          weight: 3
-        });
-
-        _assert["default"].deepStrictEqual(graph.getDirectedEdgeAttributes('John', 'Thomas'), {
-          weight: 2
-        });
-
-        _assert["default"].deepStrictEqual(graph.getUndirectedEdgeAttributes('John', 'Thomas'), {
-          weight: 3
-        });
-      },
-      'it should correctly replace attributes.': function itShouldCorrectlyReplaceAttributes() {
-        var graph = new Graph();
-        (0, _helpers.addNodesFrom)(graph, ['John', 'Martha']);
-        var edge = graph.addEdge('John', 'Martha', {
-          weight: 1
-        });
-        graph.replaceEdgeAttributes(edge, {
-          weight: 4,
-          type: 'KNOWS'
-        });
-
-        _assert["default"].deepStrictEqual(graph.getEdgeAttributes(edge), {
-          weight: 4,
-          type: 'KNOWS'
-        });
-      }
-    },
-    '#.mergeAttributes': {
-      'it should throw if given attributes are not a plain object.': function itShouldThrowIfGivenAttributesAreNotAPlainObject() {
-        var graph = new Graph();
-
-        _assert["default"]["throws"](function () {
-          graph.mergeAttributes(true);
-        }, invalid());
-      },
-      'it should correctly merge attributes.': function itShouldCorrectlyMergeAttributes() {
-        var graph = new Graph();
-        graph.setAttribute('name', 'graph');
-        graph.mergeAttributes({
-          color: 'blue'
-        });
-
-        _assert["default"].deepStrictEqual(graph.getAttributes(), {
-          name: 'graph',
-          color: 'blue'
-        });
-      }
-    },
-    '#.mergeNodeAttributes': {
-      'it should throw if given attributes are not a plain object.': function itShouldThrowIfGivenAttributesAreNotAPlainObject() {
-        var graph = new Graph();
-        graph.addNode('John');
-
-        _assert["default"]["throws"](function () {
-          graph.mergeNodeAttributes('John', true);
-        }, invalid());
-      },
-      'it should correctly merge attributes.': function itShouldCorrectlyMergeAttributes() {
-        var graph = new Graph();
-        graph.addNode('John', {
-          age: 45
-        });
-        graph.mergeNodeAttributes('John', {
-          eyes: 'blue'
-        });
-
-        _assert["default"].deepStrictEqual(graph.getNodeAttributes('John'), {
-          age: 45,
-          eyes: 'blue'
-        });
-      }
-    },
-    '#.mergeEdgeAttributes': {
-      'it should throw if given attributes are not a plain object.': function itShouldThrowIfGivenAttributesAreNotAPlainObject() {
-        var graph = new Graph();
-        (0, _helpers.addNodesFrom)(graph, ['John', 'Martha']);
-        var edge = graph.addEdge('John', 'Martha');
-
-        _assert["default"]["throws"](function () {
-          graph.mergeEdgeAttributes(edge, true);
-        }, invalid());
-      },
-      'it should also work with typed edges.': function itShouldAlsoWorkWithTypedEdges() {
-        var graph = new Graph();
-        (0, _helpers.addNodesFrom)(graph, ['John', 'Thomas']);
-        graph.addDirectedEdge('John', 'Thomas', {
-          test: 0
-        });
-        graph.addUndirectedEdge('John', 'Thomas', {
-          test: 0
-        });
-        graph.mergeDirectedEdgeAttributes('John', 'Thomas', {
-          weight: 2
-        });
-        graph.mergeUndirectedEdgeAttributes('John', 'Thomas', {
-          weight: 3
-        });
-
-        _assert["default"].deepStrictEqual(graph.getDirectedEdgeAttributes('John', 'Thomas'), {
-          weight: 2,
-          test: 0
-        });
-
-        _assert["default"].deepStrictEqual(graph.getUndirectedEdgeAttributes('John', 'Thomas'), {
-          weight: 3,
-          test: 0
-        });
-      },
-      'it should correctly merge attributes.': function itShouldCorrectlyMergeAttributes() {
-        var graph = new Graph();
-        (0, _helpers.addNodesFrom)(graph, ['John', 'Martha']);
-        var edge = graph.addEdge('John', 'Martha', {
-          weight: 1
-        });
-        graph.mergeEdgeAttributes(edge, {
-          type: 'KNOWS'
-        });
-
-        _assert["default"].deepStrictEqual(graph.getEdgeAttributes(edge), {
-          weight: 1,
-          type: 'KNOWS'
-        });
-      }
-    },
-    '#.updateAttributes': {
-      'it should throw if given updater is not a function.': function itShouldThrowIfGivenUpdaterIsNotAFunction() {
-        var graph = new Graph();
-
-        _assert["default"]["throws"](function () {
-          graph.updateAttribute(true);
-        }, invalid());
-      },
-      'it should correctly update attributes.': function itShouldCorrectlyUpdateAttributes() {
-        var graph = new Graph();
-        graph.setAttribute('name', 'graph');
-        graph.updateAttributes(function (attr) {
-          return _objectSpread(_objectSpread({}, attr), {}, {
-            color: 'blue'
-          });
-        });
-
-        _assert["default"].deepStrictEqual(graph.getAttributes(), {
-          name: 'graph',
-          color: 'blue'
-        });
-      }
-    },
-    '#.updateNodeAttributes': {
-      'it should throw if given updater is not a function': function itShouldThrowIfGivenUpdaterIsNotAFunction() {
-        var graph = new Graph();
-        graph.addNode('John');
-
-        _assert["default"]["throws"](function () {
-          graph.updateNodeAttributes('John', true);
-        }, invalid());
-      },
-      'it should correctly update attributes.': function itShouldCorrectlyUpdateAttributes() {
-        var graph = new Graph();
-        graph.addNode('John', {
-          age: 45
-        });
-        graph.updateNodeAttributes('John', function (attr) {
-          return _objectSpread(_objectSpread({}, attr), {}, {
-            eyes: 'blue'
-          });
-        });
-
-        _assert["default"].deepStrictEqual(graph.getNodeAttributes('John'), {
-          age: 45,
-          eyes: 'blue'
-        });
-      }
-    },
-    '#.updateEdgeAttributes': {
-      'it should throw if given updater is not a function.': function itShouldThrowIfGivenUpdaterIsNotAFunction() {
-        var graph = new Graph();
-        (0, _helpers.addNodesFrom)(graph, ['John', 'Martha']);
-        var edge = graph.addEdge('John', 'Martha');
-
-        _assert["default"]["throws"](function () {
-          graph.updateEdgeAttributes(edge, true);
-        }, invalid());
-      },
-      'it should also work with typed edges.': function itShouldAlsoWorkWithTypedEdges() {
-        var graph = new Graph();
-        (0, _helpers.addNodesFrom)(graph, ['John', 'Thomas']);
-        graph.addDirectedEdge('John', 'Thomas', {
-          test: 0
-        });
-        graph.addUndirectedEdge('John', 'Thomas', {
-          test: 0
-        });
-        graph.updateDirectedEdgeAttributes('John', 'Thomas', function (attr) {
-          return _objectSpread(_objectSpread({}, attr), {}, {
-            weight: 2
-          });
-        });
-        graph.updateUndirectedEdgeAttributes('John', 'Thomas', function (attr) {
-          return _objectSpread(_objectSpread({}, attr), {}, {
-            weight: 3
-          });
-        });
-
-        _assert["default"].deepStrictEqual(graph.getDirectedEdgeAttributes('John', 'Thomas'), {
-          weight: 2,
-          test: 0
-        });
-
-        _assert["default"].deepStrictEqual(graph.getUndirectedEdgeAttributes('John', 'Thomas'), {
-          weight: 3,
-          test: 0
-        });
-      },
-      'it should correctly update attributes.': function itShouldCorrectlyUpdateAttributes() {
-        var graph = new Graph();
-        (0, _helpers.addNodesFrom)(graph, ['John', 'Martha']);
-        var edge = graph.addEdge('John', 'Martha', {
-          weight: 1
-        });
-        graph.updateEdgeAttributes(edge, function (attr) {
-          return _objectSpread(_objectSpread({}, attr), {}, {
-            type: 'KNOWS'
-          });
-        });
-
-        _assert["default"].deepStrictEqual(graph.getEdgeAttributes(edge), {
-          weight: 1,
-          type: 'KNOWS'
-        });
-      }
-    },
-    '#.updateEachNodeAttributes': {
-      'it should throw when given invalid arguments.': function itShouldThrowWhenGivenInvalidArguments() {
-        var graph = new Graph();
-
-        _assert["default"]["throws"](function () {
-          graph.updateEachNodeAttributes(null);
-        }, invalid());
-
-        _assert["default"]["throws"](function () {
-          graph.updateEachNodeAttributes(Function.prototype, 'test');
-        }, invalid());
-
-        _assert["default"]["throws"](function () {
-          graph.updateEachNodeAttributes(Function.prototype, {
-            attributes: 'yes'
-          });
-        }, invalid());
-      },
-      "it should update each node's attributes.": function itShouldUpdateEachNodeSAttributes() {
-        var graph = new Graph();
-        graph.addNode('John', {
-          age: 34
-        });
-        graph.addNode('Mary', {
-          age: 56
-        });
-        graph.addNode('Suz', {
-          age: 13
-        });
-        graph.updateEachNodeAttributes(function (node, attr) {
-          return _objectSpread(_objectSpread({}, attr), {}, {
-            age: attr.age + 1
-          });
-        });
-
-        _assert["default"].deepStrictEqual(graph.nodes().map(function (n) {
-          return graph.getNodeAttributes(n);
-        }), [{
-          age: 35
-        }, {
-          age: 57
-        }, {
-          age: 14
-        }]);
-      }
-    },
-    '#.updateEachEdgeAttributes': {
-      'it should throw when given invalid arguments.': function itShouldThrowWhenGivenInvalidArguments() {
-        var graph = new Graph();
-
-        _assert["default"]["throws"](function () {
-          graph.updateEachEdgeAttributes(null);
-        }, invalid());
-
-        _assert["default"]["throws"](function () {
-          graph.updateEachEdgeAttributes(Function.prototype, 'test');
-        }, invalid());
-
-        _assert["default"]["throws"](function () {
-          graph.updateEachEdgeAttributes(Function.prototype, {
-            attributes: 'yes'
-          });
-        }, invalid());
-      },
-      "it should update each node's attributes.": function itShouldUpdateEachNodeSAttributes() {
-        var graph = new Graph();
-        graph.mergeEdgeWithKey(0, 'John', 'Lucy', {
-          weight: 1
-        });
-        graph.mergeEdgeWithKey(1, 'John', 'Mary', {
-          weight: 10
-        });
-        graph.updateEachEdgeAttributes(function (edge, attr, source, _t, _sa, _ta, undirected) {
-          _assert["default"].strictEqual(source, 'John');
-
-          _assert["default"].strictEqual(undirected, false);
-
-          return _objectSpread(_objectSpread({}, attr), {}, {
-            weight: attr.weight + 1
-          });
-        });
-
-        _assert["default"].deepStrictEqual(graph.mapEdges(function (_, attr) {
-          return attr;
-        }), [{
-          weight: 2
-        }, {
-          weight: 11
-        }]);
-      }
-    }
-  });
-}
\ No newline at end of file
diff --git a/libs/shared/graph-layouts/node_modules/graphology/specs/events.js b/libs/shared/graph-layouts/node_modules/graphology/specs/events.js
deleted file mode 100644
index df9c4c44f..000000000
--- a/libs/shared/graph-layouts/node_modules/graphology/specs/events.js
+++ /dev/null
@@ -1,426 +0,0 @@
-"use strict";
-
-Object.defineProperty(exports, "__esModule", {
-  value: true
-});
-exports["default"] = events;
-
-var _assert = _interopRequireDefault(require("assert"));
-
-var _helpers = require("./helpers");
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
-
-function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
-
-function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
-
-function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
-
-var VALID_TYPES = new Set(['set', 'merge', 'replace', 'remove']);
-
-function events(Graph) {
-  return {
-    nodeAdded: {
-      'it should fire when a node is added.': function itShouldFireWhenANodeIsAdded() {
-        var graph = new Graph();
-        var handler = (0, _helpers.spy)(function (data) {
-          _assert["default"].strictEqual(data.key, 'John');
-
-          _assert["default"].deepStrictEqual(data.attributes, {
-            age: 34
-          });
-        });
-        graph.on('nodeAdded', handler);
-        graph.addNode('John', {
-          age: 34
-        });
-        (0, _assert["default"])(handler.called);
-      }
-    },
-    edgeAdded: {
-      'it should fire when an edge is added.': function itShouldFireWhenAnEdgeIsAdded() {
-        var graph = new Graph();
-        var handler = (0, _helpers.spy)(function (data) {
-          _assert["default"].strictEqual(data.key, 'J->T');
-
-          _assert["default"].deepStrictEqual(data.attributes, {
-            weight: 1
-          });
-
-          _assert["default"].strictEqual(data.source, 'John');
-
-          _assert["default"].strictEqual(data.target, 'Thomas');
-
-          _assert["default"].strictEqual(data.undirected, false);
-        });
-        graph.on('edgeAdded', handler);
-        (0, _helpers.addNodesFrom)(graph, ['John', 'Thomas']);
-        graph.addEdgeWithKey('J->T', 'John', 'Thomas', {
-          weight: 1
-        });
-        (0, _assert["default"])(handler.called);
-      }
-    },
-    nodeDropped: {
-      'it should fire when a node is dropped.': function itShouldFireWhenANodeIsDropped() {
-        var graph = new Graph();
-        var handler = (0, _helpers.spy)(function (data) {
-          _assert["default"].strictEqual(data.key, 'John');
-
-          _assert["default"].deepStrictEqual(data.attributes, {
-            age: 34
-          });
-        });
-        graph.on('nodeDropped', handler);
-        graph.addNode('John', {
-          age: 34
-        });
-        graph.dropNode('John');
-        (0, _assert["default"])(handler.called);
-      }
-    },
-    edgeDropped: {
-      'it should fire when an edge is added.': function itShouldFireWhenAnEdgeIsAdded() {
-        var graph = new Graph();
-        var handler = (0, _helpers.spy)(function (data) {
-          _assert["default"].strictEqual(data.key, 'J->T');
-
-          _assert["default"].deepStrictEqual(data.attributes, {
-            weight: 1
-          });
-
-          _assert["default"].strictEqual(data.source, 'John');
-
-          _assert["default"].strictEqual(data.target, 'Thomas');
-
-          _assert["default"].strictEqual(data.undirected, false);
-        });
-        graph.on('edgeDropped', handler);
-        (0, _helpers.addNodesFrom)(graph, ['John', 'Thomas']);
-        graph.addEdgeWithKey('J->T', 'John', 'Thomas', {
-          weight: 1
-        });
-        graph.dropEdge('J->T');
-        (0, _assert["default"])(handler.called);
-      }
-    },
-    cleared: {
-      'it should fire when the graph is cleared.': function itShouldFireWhenTheGraphIsCleared() {
-        var graph = new Graph();
-        var handler = (0, _helpers.spy)();
-        graph.on('cleared', handler);
-        graph.clear();
-        (0, _assert["default"])(handler.called);
-      }
-    },
-    attributesUpdated: {
-      'it should fire when a graph attribute is updated.': function itShouldFireWhenAGraphAttributeIsUpdated() {
-        var graph = new Graph();
-        var handler = (0, _helpers.spy)(function (payload) {
-          (0, _assert["default"])(VALID_TYPES.has(payload.type));
-
-          if (payload.type === 'set') {
-            _assert["default"].strictEqual(payload.name, 'name');
-          } else if (payload.type === 'remove') {
-            _assert["default"].strictEqual(payload.name, 'name');
-          } else if (payload.type === 'merge') {
-            _assert["default"].deepStrictEqual(payload.data, {
-              author: 'John'
-            });
-          }
-
-          _assert["default"].deepStrictEqual(payload.attributes, graph.getAttributes());
-        });
-        graph.on('attributesUpdated', handler);
-        graph.setAttribute('name', 'Awesome graph');
-        graph.replaceAttributes({
-          name: 'Shitty graph'
-        });
-        graph.mergeAttributes({
-          author: 'John'
-        });
-        graph.removeAttribute('name');
-
-        _assert["default"].strictEqual(handler.times, 4);
-      }
-    },
-    nodeAttributesUpdated: {
-      "it should fire when a node's attributes are updated.": function itShouldFireWhenANodeSAttributesAreUpdated() {
-        var graph = new Graph();
-        var handler = (0, _helpers.spy)(function (payload) {
-          _assert["default"].strictEqual(payload.key, 'John');
-
-          (0, _assert["default"])(VALID_TYPES.has(payload.type));
-
-          if (payload.type === 'set') {
-            _assert["default"].strictEqual(payload.name, 'age');
-          } else if (payload.type === 'remove') {
-            _assert["default"].strictEqual(payload.name, 'eyes');
-          } else if (payload.type === 'merge') {
-            _assert["default"].deepStrictEqual(payload.data, {
-              eyes: 'blue'
-            });
-          }
-
-          _assert["default"].strictEqual(payload.attributes, graph.getNodeAttributes(payload.key));
-        });
-        graph.on('nodeAttributesUpdated', handler);
-        graph.addNode('John');
-        graph.setNodeAttribute('John', 'age', 34);
-        graph.replaceNodeAttributes('John', {
-          age: 56
-        });
-        graph.mergeNodeAttributes('John', {
-          eyes: 'blue'
-        });
-        graph.removeNodeAttribute('John', 'eyes');
-
-        _assert["default"].strictEqual(handler.times, 4);
-      },
-      'it should fire when a node is merged.': function itShouldFireWhenANodeIsMerged() {
-        var graph = new Graph();
-        var handler = (0, _helpers.spy)(function (payload) {
-          _assert["default"].deepStrictEqual(payload, {
-            type: 'merge',
-            key: 'John',
-            attributes: {
-              count: 2
-            },
-            data: {
-              count: 2
-            }
-          });
-
-          _assert["default"].deepStrictEqual(graph.getNodeAttributes(payload.key), {
-            count: 2
-          });
-        });
-        graph.on('nodeAttributesUpdated', handler);
-        graph.mergeNode('John', {
-          count: 1
-        });
-        graph.mergeNode('John', {
-          count: 2
-        });
-
-        _assert["default"].strictEqual(handler.times, 1);
-      },
-      'it should fire when a node is updated.': function itShouldFireWhenANodeIsUpdated() {
-        var graph = new Graph();
-        var handler = (0, _helpers.spy)(function (payload) {
-          _assert["default"].deepStrictEqual(payload, {
-            type: 'replace',
-            key: 'John',
-            attributes: {
-              count: 2
-            }
-          });
-
-          _assert["default"].deepStrictEqual(graph.getNodeAttributes(payload.key), {
-            count: 2
-          });
-        });
-        graph.on('nodeAttributesUpdated', handler);
-        graph.mergeNode('John', {
-          count: 1
-        });
-        graph.updateNode('John', function (attr) {
-          return _objectSpread(_objectSpread({}, attr), {}, {
-            count: attr.count + 1
-          });
-        });
-
-        _assert["default"].strictEqual(handler.times, 1);
-      }
-    },
-    edgeAttributesUpdated: {
-      "it should fire when an edge's attributes are updated.": function itShouldFireWhenAnEdgeSAttributesAreUpdated() {
-        var graph = new Graph();
-        var handler = (0, _helpers.spy)(function (payload) {
-          _assert["default"].strictEqual(payload.key, 'J->T');
-
-          (0, _assert["default"])(VALID_TYPES.has(payload.type));
-
-          if (payload.type === 'set') {
-            _assert["default"].strictEqual(payload.name, 'weight');
-          } else if (payload.type === 'remove') {
-            _assert["default"].strictEqual(payload.name, 'type');
-          } else if (payload.type === 'merge') {
-            _assert["default"].deepStrictEqual(payload.data, {
-              type: 'KNOWS'
-            });
-          }
-
-          _assert["default"].strictEqual(payload.attributes, graph.getEdgeAttributes(payload.key));
-        });
-        graph.on('edgeAttributesUpdated', handler);
-        (0, _helpers.addNodesFrom)(graph, ['John', 'Thomas']);
-        graph.addEdgeWithKey('J->T', 'John', 'Thomas');
-        graph.setEdgeAttribute('J->T', 'weight', 34);
-        graph.replaceEdgeAttributes('J->T', {
-          weight: 56
-        });
-        graph.mergeEdgeAttributes('J->T', {
-          type: 'KNOWS'
-        });
-        graph.removeEdgeAttribute('J->T', 'type');
-
-        _assert["default"].strictEqual(handler.times, 4);
-      },
-      'it should fire when an edge is merged.': function itShouldFireWhenAnEdgeIsMerged() {
-        var graph = new Graph();
-        var handler = (0, _helpers.spy)(function (payload) {
-          _assert["default"].deepStrictEqual(payload, {
-            type: 'merge',
-            key: graph.edge('John', 'Mary'),
-            attributes: {
-              weight: 2
-            },
-            data: {
-              weight: 2
-            }
-          });
-
-          _assert["default"].deepStrictEqual(graph.getEdgeAttributes(payload.key), {
-            weight: 2
-          });
-        });
-        graph.on('edgeAttributesUpdated', handler);
-        graph.mergeEdge('John', 'Mary', {
-          weight: 1
-        });
-        graph.mergeEdge('John', 'Mary', {
-          weight: 2
-        });
-
-        _assert["default"].strictEqual(handler.times, 1);
-      },
-      'it should fire when an edge is updated.': function itShouldFireWhenAnEdgeIsUpdated() {
-        var graph = new Graph();
-        var handler = (0, _helpers.spy)(function (payload) {
-          _assert["default"].deepStrictEqual(payload, {
-            type: 'replace',
-            key: 'j->m',
-            attributes: {
-              weight: 2
-            }
-          });
-
-          _assert["default"].deepStrictEqual(graph.getEdgeAttributes(payload.key), {
-            weight: 2
-          });
-        });
-        graph.on('edgeAttributesUpdated', handler);
-        graph.mergeEdgeWithKey('j->m', 'John', 'Mary', {
-          weight: 1
-        });
-        graph.updateEdgeWithKey('j->m', 'John', 'Mary', function (attr) {
-          return _objectSpread(_objectSpread({}, attr), {}, {
-            weight: attr.weight + 1
-          });
-        });
-
-        _assert["default"].strictEqual(handler.times, 1);
-      }
-    },
-    eachNodeAttributesUpdated: {
-      'it should fire when using #.updateEachNodeAttributes.': function itShouldFireWhenUsingUpdateEachNodeAttributes() {
-        var graph = new Graph();
-        graph.addNode('John', {
-          age: 34
-        });
-        graph.addNode('Mary', {
-          age: 56
-        });
-        graph.addNode('Suz', {
-          age: 13
-        });
-        var handler = (0, _helpers.spy)(function (payload) {
-          _assert["default"].strictEqual(payload.hints, null);
-        });
-        graph.on('eachNodeAttributesUpdated', handler);
-        graph.updateEachNodeAttributes(function (node, attr) {
-          return _objectSpread(_objectSpread({}, attr), {}, {
-            age: attr.age + 1
-          });
-        });
-
-        _assert["default"].strictEqual(handler.times, 1);
-      },
-      'it should provide hints when user gave them.': function itShouldProvideHintsWhenUserGaveThem() {
-        var graph = new Graph();
-        graph.addNode('John', {
-          age: 34
-        });
-        graph.addNode('Mary', {
-          age: 56
-        });
-        graph.addNode('Suz', {
-          age: 13
-        });
-        var handler = (0, _helpers.spy)(function (payload) {
-          _assert["default"].deepStrictEqual(payload.hints, {
-            attributes: ['age']
-          });
-        });
-        graph.on('eachNodeAttributesUpdated', handler);
-        graph.updateEachNodeAttributes(function (node, attr) {
-          return _objectSpread(_objectSpread({}, attr), {}, {
-            age: attr.age + 1
-          });
-        }, {
-          attributes: ['age']
-        });
-
-        _assert["default"].strictEqual(handler.times, 1);
-      }
-    },
-    eachEdgeAttributesUpdated: {
-      'it should fire when using #.updateEachEdgeAttributes.': function itShouldFireWhenUsingUpdateEachEdgeAttributes() {
-        var graph = new Graph();
-        graph.mergeEdgeWithKey(0, 'John', 'Lucy', {
-          weight: 1
-        });
-        graph.mergeEdgeWithKey(1, 'John', 'Mary', {
-          weight: 10
-        });
-        var handler = (0, _helpers.spy)(function (payload) {
-          _assert["default"].strictEqual(payload.hints, null);
-        });
-        graph.on('eachEdgeAttributesUpdated', handler);
-        graph.updateEachEdgeAttributes(function (node, attr) {
-          return _objectSpread(_objectSpread({}, attr), {}, {
-            age: attr.weight + 1
-          });
-        });
-
-        _assert["default"].strictEqual(handler.times, 1);
-      },
-      'it should provide hints when user gave them.': function itShouldProvideHintsWhenUserGaveThem() {
-        var graph = new Graph();
-        graph.mergeEdgeWithKey(0, 'John', 'Lucy', {
-          weight: 1
-        });
-        graph.mergeEdgeWithKey(1, 'John', 'Mary', {
-          weight: 10
-        });
-        var handler = (0, _helpers.spy)(function (payload) {
-          _assert["default"].deepStrictEqual(payload.hints, {
-            attributes: ['weight']
-          });
-        });
-        graph.on('eachEdgeAttributesUpdated', handler);
-        graph.updateEachEdgeAttributes(function (node, attr) {
-          return _objectSpread(_objectSpread({}, attr), {}, {
-            weight: attr.weight + 1
-          });
-        }, {
-          attributes: ['weight']
-        });
-
-        _assert["default"].strictEqual(handler.times, 1);
-      }
-    }
-  };
-}
\ No newline at end of file
diff --git a/libs/shared/graph-layouts/node_modules/graphology/specs/helpers.js b/libs/shared/graph-layouts/node_modules/graphology/specs/helpers.js
deleted file mode 100644
index 5198d01d9..000000000
--- a/libs/shared/graph-layouts/node_modules/graphology/specs/helpers.js
+++ /dev/null
@@ -1,101 +0,0 @@
-"use strict";
-
-Object.defineProperty(exports, "__esModule", {
-  value: true
-});
-exports.addNodesFrom = addNodesFrom;
-exports.capitalize = capitalize;
-exports.deepMerge = deepMerge;
-exports.sameMembers = sameMembers;
-exports.spy = spy;
-
-function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); }
-
-/**
- * Graphology Specs Helpers
- * =========================
- *
- * Miscellaneous helpers to test more easily.
- */
-
-/**
- * Capitalize function.
- */
-function capitalize(string) {
-  return string[0].toUpperCase() + string.slice(1);
-}
-/**
- * Simplistic deep merger function.
- */
-
-
-function deepMerge() {
-  for (var _len = arguments.length, objects = new Array(_len), _key = 0; _key < _len; _key++) {
-    objects[_key] = arguments[_key];
-  }
-
-  var o = objects[0];
-  var t, i, l, k;
-
-  for (i = 1, l = objects.length; i < l; i++) {
-    t = objects[i];
-
-    for (k in t) {
-      if (_typeof(t[k]) === 'object') {
-        o[k] = deepMerge(o[k] || {}, t[k]);
-      } else {
-        o[k] = t[k];
-      }
-    }
-  }
-
-  return o;
-}
-/**
- * Checking that two arrays have the same members.
- */
-
-
-function sameMembers(a1, a2) {
-  if (a1.length !== a2.length) return false;
-  var set = new Set(a1);
-
-  for (var i = 0, l = a2.length; i < l; i++) {
-    if (!set.has(a2[i])) return false;
-  }
-
-  return true;
-}
-/**
- * Function spying on the execution of the provided function to ease some
- * tests, notably related to event handling.
- *
- * @param {function} target - Target function.
- * @param {function}        - The spy.
- */
-
-
-function spy(target) {
-  var fn = function fn() {
-    fn.called = true;
-    fn.times++;
-    if (typeof target === 'function') return target.apply(null, arguments);
-  };
-
-  fn.called = false;
-  fn.times = 0;
-  return fn;
-}
-/**
- * Function adding multiple nodes from an array to the given graph.
- *
- * @param {Graph} graph - Target graph.
- * @param {array} nodes - Node array.
- */
-
-
-function addNodesFrom(graph, nodes) {
-  nodes.forEach(function (node) {
-    graph.addNode(node);
-  });
-}
\ No newline at end of file
diff --git a/libs/shared/graph-layouts/node_modules/graphology/specs/index.js b/libs/shared/graph-layouts/node_modules/graphology/specs/index.js
deleted file mode 100644
index 18b6595fc..000000000
--- a/libs/shared/graph-layouts/node_modules/graphology/specs/index.js
+++ /dev/null
@@ -1,78 +0,0 @@
-"use strict";
-
-Object.defineProperty(exports, "__esModule", {
-  value: true
-});
-exports["default"] = specs;
-
-var _instantiation = _interopRequireDefault(require("./instantiation"));
-
-var _properties = _interopRequireDefault(require("./properties"));
-
-var _read = _interopRequireDefault(require("./read"));
-
-var _mutation = _interopRequireDefault(require("./mutation"));
-
-var _attributes = _interopRequireDefault(require("./attributes"));
-
-var _iteration = _interopRequireDefault(require("./iteration"));
-
-var _serialization = _interopRequireDefault(require("./serialization"));
-
-var _events = _interopRequireDefault(require("./events"));
-
-var _utils = _interopRequireDefault(require("./utils"));
-
-var _known = _interopRequireDefault(require("./known"));
-
-var _misc = _interopRequireDefault(require("./misc"));
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
-
-/**
- * Graphology Specs
- * =================
- *
- * Unit tests factory taking the Graph object implementation.
- */
-var createErrorChecker = function createErrorChecker(name) {
-  return function () {
-    return function (error) {
-      return error && error.name === name;
-    };
-  };
-};
-/**
- * Returning the unit tests to run.
- *
- * @param  {string} path - Path to the implementation (should be absolute).
- * @return {object}      - The tests to run with Mocha.
- */
-
-
-function specs(Graph, implementation) {
-  var errors = [['invalid', 'InvalidArgumentsGraphError'], ['notFound', 'NotFoundGraphError'], ['usage', 'UsageGraphError']]; // Building error checkers
-
-  var errorCheckers = {};
-  errors.forEach(function (_ref) {
-    var fn = _ref[0],
-        name = _ref[1];
-    return errorCheckers[fn] = createErrorChecker(name);
-  });
-  var tests = {
-    Basic: {
-      Instantiation: (0, _instantiation["default"])(Graph, implementation, errorCheckers),
-      Properties: (0, _properties["default"])(Graph, errorCheckers),
-      Mutation: (0, _mutation["default"])(Graph, errorCheckers),
-      Read: (0, _read["default"])(Graph, errorCheckers),
-      Attributes: (0, _attributes["default"])(Graph, errorCheckers),
-      Iteration: (0, _iteration["default"])(Graph, errorCheckers),
-      Serialization: (0, _serialization["default"])(Graph, errorCheckers),
-      Events: (0, _events["default"])(Graph),
-      Utils: (0, _utils["default"])(Graph, errorCheckers),
-      'Known Methods': (0, _known["default"])(Graph, errorCheckers),
-      Miscellaneous: (0, _misc["default"])(Graph)
-    }
-  };
-  return tests;
-}
\ No newline at end of file
diff --git a/libs/shared/graph-layouts/node_modules/graphology/specs/instantiation.js b/libs/shared/graph-layouts/node_modules/graphology/specs/instantiation.js
deleted file mode 100644
index 45945a419..000000000
--- a/libs/shared/graph-layouts/node_modules/graphology/specs/instantiation.js
+++ /dev/null
@@ -1,211 +0,0 @@
-"use strict";
-
-Object.defineProperty(exports, "__esModule", {
-  value: true
-});
-exports["default"] = instantiation;
-
-var _assert = _interopRequireDefault(require("assert"));
-
-var _helpers = require("./helpers");
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
-
-/* eslint no-unused-vars: 0 */
-
-/**
- * Graphology Instantiation Specs
- * ===============================
- *
- * Testing the instantiation of the graph.
- */
-var CONSTRUCTORS = ['DirectedGraph', 'UndirectedGraph', 'MultiGraph', 'MultiDirectedGraph', 'MultiUndirectedGraph'];
-var OPTIONS = [{
-  multi: false,
-  type: 'directed'
-}, {
-  multi: false,
-  type: 'undirected'
-}, {
-  multi: true,
-  type: 'mixed'
-}, {
-  multi: true,
-  type: 'directed'
-}, {
-  multi: true,
-  type: 'undirected'
-}];
-
-function instantiation(Graph, implementation, checkers) {
-  var invalid = checkers.invalid;
-  return {
-    'Static #.from method': {
-      'it should be possible to create a Graph from a Graph instance.': function itShouldBePossibleToCreateAGraphFromAGraphInstance() {
-        var graph = new Graph();
-        (0, _helpers.addNodesFrom)(graph, ['John', 'Thomas']);
-        graph.addEdge('John', 'Thomas');
-        var other = Graph.from(graph);
-
-        _assert["default"].deepStrictEqual(graph.nodes(), other.nodes());
-
-        _assert["default"].deepStrictEqual(graph.edges(), other.edges());
-      },
-      'it should be possible to create a Graph from a serialized graph': function itShouldBePossibleToCreateAGraphFromASerializedGraph() {
-        var graph = Graph.from({
-          nodes: [{
-            key: 'John'
-          }, {
-            key: 'Thomas'
-          }],
-          edges: [{
-            source: 'John',
-            target: 'Thomas'
-          }]
-        });
-
-        _assert["default"].deepStrictEqual(graph.nodes(), ['John', 'Thomas']);
-
-        _assert["default"].strictEqual(graph.hasEdge('John', 'Thomas'), true);
-      },
-      'it should be possible to provide options.': function itShouldBePossibleToProvideOptions() {
-        var graph = Graph.from({
-          node: [{
-            key: 'John'
-          }],
-          attributes: {
-            name: 'Awesome graph'
-          }
-        }, {
-          type: 'directed'
-        });
-
-        _assert["default"].strictEqual(graph.type, 'directed');
-
-        _assert["default"].strictEqual(graph.getAttribute('name'), 'Awesome graph');
-      },
-      'it should be possible to take options from the serialized format.': function itShouldBePossibleToTakeOptionsFromTheSerializedFormat() {
-        var graph = Graph.from({
-          node: [{
-            key: 'John'
-          }],
-          attributes: {
-            name: 'Awesome graph'
-          },
-          options: {
-            type: 'directed',
-            multi: true
-          }
-        });
-
-        _assert["default"].strictEqual(graph.type, 'directed');
-
-        _assert["default"].strictEqual(graph.multi, true);
-
-        _assert["default"].strictEqual(graph.getAttribute('name'), 'Awesome graph');
-      },
-      'given options should take precedence over the serialization ones.': function givenOptionsShouldTakePrecedenceOverTheSerializationOnes() {
-        var graph = Graph.from({
-          node: [{
-            key: 'John'
-          }],
-          attributes: {
-            name: 'Awesome graph'
-          },
-          options: {
-            type: 'directed',
-            multi: true
-          }
-        }, {
-          type: 'undirected'
-        });
-
-        _assert["default"].strictEqual(graph.type, 'undirected');
-
-        _assert["default"].strictEqual(graph.multi, true);
-
-        _assert["default"].strictEqual(graph.getAttribute('name'), 'Awesome graph');
-      }
-    },
-    Options: {
-      /**
-       * allowSelfLoops
-       */
-      allowSelfLoops: {
-        'providing a non-boolean value should throw.': function providingANonBooleanValueShouldThrow() {
-          _assert["default"]["throws"](function () {
-            var graph = new Graph({
-              allowSelfLoops: 'test'
-            });
-          }, invalid());
-        }
-      },
-
-      /**
-       * multi
-       */
-      multi: {
-        'providing a non-boolean value should throw.': function providingANonBooleanValueShouldThrow() {
-          _assert["default"]["throws"](function () {
-            var graph = new Graph({
-              multi: 'test'
-            });
-          }, invalid());
-        }
-      },
-
-      /**
-       * type
-       */
-      type: {
-        'providing an invalid type should throw.': function providingAnInvalidTypeShouldThrow() {
-          _assert["default"]["throws"](function () {
-            var graph = new Graph({
-              type: 'test'
-            });
-          }, invalid());
-        }
-      }
-    },
-    Constructors: {
-      'all alternative constructors should be available.': function allAlternativeConstructorsShouldBeAvailable() {
-        CONSTRUCTORS.forEach(function (name) {
-          return (0, _assert["default"])(name in implementation);
-        });
-      },
-      'alternative constructors should have the correct options.': function alternativeConstructorsShouldHaveTheCorrectOptions() {
-        CONSTRUCTORS.forEach(function (name, index) {
-          var graph = new implementation[name]();
-          var _OPTIONS$index = OPTIONS[index],
-              multi = _OPTIONS$index.multi,
-              type = _OPTIONS$index.type;
-
-          _assert["default"].strictEqual(graph.multi, multi);
-
-          _assert["default"].strictEqual(graph.type, type);
-        });
-      },
-      'alternative constructors should throw if given inconsistent options.': function alternativeConstructorsShouldThrowIfGivenInconsistentOptions() {
-        CONSTRUCTORS.forEach(function (name, index) {
-          var _OPTIONS$index2 = OPTIONS[index],
-              multi = _OPTIONS$index2.multi,
-              type = _OPTIONS$index2.type;
-
-          _assert["default"]["throws"](function () {
-            var graph = new implementation[name]({
-              multi: !multi
-            });
-          }, invalid());
-
-          if (type === 'mixed') return;
-
-          _assert["default"]["throws"](function () {
-            var graph = new implementation[name]({
-              type: type === 'directed' ? 'undirected' : 'directed'
-            });
-          }, invalid());
-        });
-      }
-    }
-  };
-}
\ No newline at end of file
diff --git a/libs/shared/graph-layouts/node_modules/graphology/specs/iteration/edges.js b/libs/shared/graph-layouts/node_modules/graphology/specs/iteration/edges.js
deleted file mode 100644
index 8210ea7f2..000000000
--- a/libs/shared/graph-layouts/node_modules/graphology/specs/iteration/edges.js
+++ /dev/null
@@ -1,894 +0,0 @@
-"use strict";
-
-Object.defineProperty(exports, "__esModule", {
-  value: true
-});
-exports["default"] = edgesIteration;
-
-var _assert = _interopRequireDefault(require("assert"));
-
-var _take = _interopRequireDefault(require("obliterator/take"));
-
-var _map = _interopRequireDefault(require("obliterator/map"));
-
-var _helpers = require("../helpers");
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
-
-function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
-
-var METHODS = ['edges', 'inEdges', 'outEdges', 'inboundEdges', 'outboundEdges', 'directedEdges', 'undirectedEdges'];
-
-function edgesIteration(Graph, checkers) {
-  var invalid = checkers.invalid,
-      notFound = checkers.notFound;
-  var graph = new Graph({
-    multi: true
-  });
-  (0, _helpers.addNodesFrom)(graph, ['John', 'Thomas', 'Martha', 'Roger', 'Catherine', 'Alone', 'Forever']);
-  graph.replaceNodeAttributes('John', {
-    age: 13
-  });
-  graph.replaceNodeAttributes('Martha', {
-    age: 15
-  });
-  graph.addDirectedEdgeWithKey('J->T', 'John', 'Thomas', {
-    weight: 14
-  });
-  graph.addDirectedEdgeWithKey('J->M', 'John', 'Martha');
-  graph.addDirectedEdgeWithKey('C->J', 'Catherine', 'John');
-  graph.addUndirectedEdgeWithKey('M<->R', 'Martha', 'Roger');
-  graph.addUndirectedEdgeWithKey('M<->J', 'Martha', 'John');
-  graph.addUndirectedEdgeWithKey('J<->R', 'John', 'Roger');
-  graph.addUndirectedEdgeWithKey('T<->M', 'Thomas', 'Martha');
-  var ALL_EDGES = ['J->T', 'J->M', 'C->J', 'M<->R', 'M<->J', 'J<->R', 'T<->M'];
-  var ALL_DIRECTED_EDGES = ['J->T', 'J->M', 'C->J'];
-  var ALL_UNDIRECTED_EDGES = ['M<->R', 'M<->J', 'J<->R', 'T<->M'];
-  var TEST_DATA = {
-    edges: {
-      all: ALL_EDGES,
-      node: {
-        key: 'John',
-        edges: ['C->J', 'J->T', 'J->M', 'M<->J', 'J<->R']
-      },
-      path: {
-        source: 'John',
-        target: 'Martha',
-        edges: ['J->M', 'M<->J']
-      }
-    },
-    inEdges: {
-      all: ALL_DIRECTED_EDGES,
-      node: {
-        key: 'John',
-        edges: ['C->J']
-      },
-      path: {
-        source: 'John',
-        target: 'Martha',
-        edges: []
-      }
-    },
-    outEdges: {
-      all: ALL_DIRECTED_EDGES,
-      node: {
-        key: 'John',
-        edges: ['J->T', 'J->M']
-      },
-      path: {
-        source: 'John',
-        target: 'Martha',
-        edges: ['J->M']
-      }
-    },
-    inboundEdges: {
-      all: ALL_DIRECTED_EDGES.concat(ALL_UNDIRECTED_EDGES),
-      node: {
-        key: 'John',
-        edges: ['C->J', 'M<->J', 'J<->R']
-      },
-      path: {
-        source: 'John',
-        target: 'Martha',
-        edges: ['M<->J']
-      }
-    },
-    outboundEdges: {
-      all: ALL_DIRECTED_EDGES.concat(ALL_UNDIRECTED_EDGES),
-      node: {
-        key: 'John',
-        edges: ['J->T', 'J->M', 'M<->J', 'J<->R']
-      },
-      path: {
-        source: 'John',
-        target: 'Martha',
-        edges: ['J->M', 'M<->J']
-      }
-    },
-    directedEdges: {
-      all: ALL_DIRECTED_EDGES,
-      node: {
-        key: 'John',
-        edges: ['C->J', 'J->T', 'J->M']
-      },
-      path: {
-        source: 'John',
-        target: 'Martha',
-        edges: ['J->M']
-      }
-    },
-    undirectedEdges: {
-      all: ALL_UNDIRECTED_EDGES,
-      node: {
-        key: 'John',
-        edges: ['M<->J', 'J<->R']
-      },
-      path: {
-        source: 'John',
-        target: 'Martha',
-        edges: ['M<->J']
-      }
-    }
-  };
-
-  function commonTests(name) {
-    return _defineProperty({}, '#.' + name, {
-      'it should throw if too many arguments are provided.': function itShouldThrowIfTooManyArgumentsAreProvided() {
-        _assert["default"]["throws"](function () {
-          graph[name](1, 2, 3);
-        }, invalid());
-      },
-      'it should throw when the node is not found.': function itShouldThrowWhenTheNodeIsNotFound() {
-        _assert["default"]["throws"](function () {
-          graph[name]('Test');
-        }, notFound());
-      },
-      'it should throw if either source or target is not found.': function itShouldThrowIfEitherSourceOrTargetIsNotFound() {
-        _assert["default"]["throws"](function () {
-          graph[name]('Test', 'Alone');
-        }, notFound());
-
-        _assert["default"]["throws"](function () {
-          graph[name]('Alone', 'Test');
-        }, notFound());
-      }
-    });
-  }
-
-  function specificTests(name, data) {
-    var _ref2;
-
-    var capitalized = name[0].toUpperCase() + name.slice(1, -1);
-    var iteratorName = name.slice(0, -1) + 'Entries';
-    var forEachName = 'forEach' + capitalized;
-    var findName = 'find' + capitalized;
-    var mapName = 'map' + capitalized + 's';
-    var filterName = 'filter' + capitalized + 's';
-    var reduceName = 'reduce' + capitalized + 's';
-    var someName = 'some' + capitalized;
-    var everyName = 'every' + capitalized;
-    return _ref2 = {}, _defineProperty(_ref2, '#.' + name, {
-      'it should return all the relevant edges.': function itShouldReturnAllTheRelevantEdges() {
-        var edges = graph[name]().sort();
-
-        _assert["default"].deepStrictEqual(edges, data.all.slice().sort());
-      },
-      "it should return a node's relevant edges.": function itShouldReturnANodeSRelevantEdges() {
-        var edges = graph[name](data.node.key);
-
-        _assert["default"].deepStrictEqual(edges, data.node.edges);
-
-        _assert["default"].deepStrictEqual(graph[name]('Alone'), []);
-      },
-      'it should return all the relevant edges between source & target.': function itShouldReturnAllTheRelevantEdgesBetweenSourceTarget() {
-        var edges = graph[name](data.path.source, data.path.target);
-        (0, _assert["default"])((0, _helpers.sameMembers)(edges, data.path.edges));
-
-        _assert["default"].deepStrictEqual(graph[name]('Forever', 'Alone'), []);
-      }
-    }), _defineProperty(_ref2, '#.' + forEachName, {
-      'it should possible to use callback iterators.': function itShouldPossibleToUseCallbackIterators() {
-        var edges = [];
-        graph[forEachName](function (key, attributes, source, target, sA, tA, u) {
-          edges.push(key);
-
-          _assert["default"].deepStrictEqual(attributes, key === 'J->T' ? {
-            weight: 14
-          } : {});
-
-          _assert["default"].strictEqual(source, graph.source(key));
-
-          _assert["default"].strictEqual(target, graph.target(key));
-
-          _assert["default"].deepStrictEqual(graph.getNodeAttributes(source), sA);
-
-          _assert["default"].deepStrictEqual(graph.getNodeAttributes(target), tA);
-
-          _assert["default"].strictEqual(graph.isUndirected(key), u);
-        });
-        edges.sort();
-
-        _assert["default"].deepStrictEqual(edges, data.all.slice().sort());
-      },
-      "it should be possible to use callback iterators over a node's relevant edges.": function itShouldBePossibleToUseCallbackIteratorsOverANodeSRelevantEdges() {
-        var edges = [];
-        graph[forEachName](data.node.key, function (key, attributes, source, target, sA, tA, u) {
-          edges.push(key);
-
-          _assert["default"].deepStrictEqual(attributes, key === 'J->T' ? {
-            weight: 14
-          } : {});
-
-          _assert["default"].strictEqual(source, graph.source(key));
-
-          _assert["default"].strictEqual(target, graph.target(key));
-
-          _assert["default"].deepStrictEqual(graph.getNodeAttributes(source), sA);
-
-          _assert["default"].deepStrictEqual(graph.getNodeAttributes(target), tA);
-
-          _assert["default"].strictEqual(graph.isUndirected(key), u);
-        });
-        edges.sort();
-
-        _assert["default"].deepStrictEqual(edges, data.node.edges.slice().sort());
-      },
-      'it should be possible to use callback iterators over all the relevant edges between source & target.': function itShouldBePossibleToUseCallbackIteratorsOverAllTheRelevantEdgesBetweenSourceTarget() {
-        var edges = [];
-        graph[forEachName](data.path.source, data.path.target, function (key, attributes, source, target, sA, tA, u) {
-          edges.push(key);
-
-          _assert["default"].deepStrictEqual(attributes, key === 'J->T' ? {
-            weight: 14
-          } : {});
-
-          _assert["default"].strictEqual(source, graph.source(key));
-
-          _assert["default"].strictEqual(target, graph.target(key));
-
-          _assert["default"].deepStrictEqual(graph.getNodeAttributes(source), sA);
-
-          _assert["default"].deepStrictEqual(graph.getNodeAttributes(target), tA);
-
-          _assert["default"].strictEqual(graph.isUndirected(key), u);
-        });
-        (0, _assert["default"])((0, _helpers.sameMembers)(edges, data.path.edges));
-      }
-    }), _defineProperty(_ref2, '#.' + mapName, {
-      'it should possible to map edges.': function itShouldPossibleToMapEdges() {
-        var result = graph[mapName](function (key) {
-          return key;
-        });
-        result.sort();
-
-        _assert["default"].deepStrictEqual(result, data.all.slice().sort());
-      },
-      "it should be possible to map a node's relevant edges.": function itShouldBePossibleToMapANodeSRelevantEdges() {
-        var result = graph[mapName](data.node.key, function (key) {
-          return key;
-        });
-        result.sort();
-
-        _assert["default"].deepStrictEqual(result, data.node.edges.slice().sort());
-      },
-      'it should be possible to map the relevant edges between source & target.': function itShouldBePossibleToMapTheRelevantEdgesBetweenSourceTarget() {
-        var result = graph[mapName](data.path.source, data.path.target, function (key) {
-          return key;
-        });
-        result.sort();
-        (0, _assert["default"])((0, _helpers.sameMembers)(result, data.path.edges));
-      }
-    }), _defineProperty(_ref2, '#.' + filterName, {
-      'it should possible to filter edges.': function itShouldPossibleToFilterEdges() {
-        var result = graph[filterName](function (key) {
-          return data.all.includes(key);
-        });
-        result.sort();
-
-        _assert["default"].deepStrictEqual(result, data.all.slice().sort());
-      },
-      "it should be possible to filter a node's relevant edges.": function itShouldBePossibleToFilterANodeSRelevantEdges() {
-        var result = graph[filterName](data.node.key, function (key) {
-          return data.all.includes(key);
-        });
-        result.sort();
-
-        _assert["default"].deepStrictEqual(result, data.node.edges.slice().sort());
-      },
-      'it should be possible to filter the relevant edges between source & target.': function itShouldBePossibleToFilterTheRelevantEdgesBetweenSourceTarget() {
-        var result = graph[filterName](data.path.source, data.path.target, function (key) {
-          return data.all.includes(key);
-        });
-        result.sort();
-        (0, _assert["default"])((0, _helpers.sameMembers)(result, data.path.edges));
-      }
-    }), _defineProperty(_ref2, '#.' + reduceName, {
-      'it should throw when given bad arguments.': function itShouldThrowWhenGivenBadArguments() {
-        _assert["default"]["throws"](function () {
-          graph[reduceName]('test');
-        }, invalid());
-
-        _assert["default"]["throws"](function () {
-          graph[reduceName](1, 2, 3, 4, 5);
-        }, invalid());
-
-        _assert["default"]["throws"](function () {
-          graph[reduceName]('notafunction', 0);
-        }, TypeError);
-
-        _assert["default"]["throws"](function () {
-          graph[reduceName]('test', function () {
-            return true;
-          });
-        }, invalid());
-      },
-      'it should possible to reduce edges.': function itShouldPossibleToReduceEdges() {
-        var result = graph[reduceName](function (x) {
-          return x + 1;
-        }, 0);
-
-        _assert["default"].strictEqual(result, data.all.length);
-      },
-      "it should be possible to reduce a node's relevant edges.": function itShouldBePossibleToReduceANodeSRelevantEdges() {
-        var result = graph[reduceName](data.node.key, function (x) {
-          return x + 1;
-        }, 0);
-
-        _assert["default"].strictEqual(result, data.node.edges.length);
-      },
-      'it should be possible to reduce the relevant edges between source & target.': function itShouldBePossibleToReduceTheRelevantEdgesBetweenSourceTarget() {
-        var result = graph[reduceName](data.path.source, data.path.target, function (x) {
-          return x + 1;
-        }, 0);
-
-        _assert["default"].strictEqual(result, data.path.edges.length);
-      }
-    }), _defineProperty(_ref2, '#.' + findName, {
-      'it should possible to find an edge.': function itShouldPossibleToFindAnEdge() {
-        var edges = [];
-        var found = graph[findName](function (key, attributes, source, target, sA, tA, u) {
-          edges.push(key);
-
-          _assert["default"].deepStrictEqual(attributes, key === 'J->T' ? {
-            weight: 14
-          } : {});
-
-          _assert["default"].strictEqual(source, graph.source(key));
-
-          _assert["default"].strictEqual(target, graph.target(key));
-
-          _assert["default"].deepStrictEqual(graph.getNodeAttributes(source), sA);
-
-          _assert["default"].deepStrictEqual(graph.getNodeAttributes(target), tA);
-
-          _assert["default"].strictEqual(graph.isUndirected(key), u);
-
-          return true;
-        });
-
-        _assert["default"].strictEqual(found, edges[0]);
-
-        _assert["default"].strictEqual(edges.length, 1);
-
-        found = graph[findName](function () {
-          return false;
-        });
-
-        _assert["default"].strictEqual(found, undefined);
-      },
-      "it should be possible to find a node's edge.": function itShouldBePossibleToFindANodeSEdge() {
-        var edges = [];
-        var found = graph[findName](data.node.key, function (key, attributes, source, target, sA, tA, u) {
-          edges.push(key);
-
-          _assert["default"].deepStrictEqual(attributes, key === 'J->T' ? {
-            weight: 14
-          } : {});
-
-          _assert["default"].strictEqual(source, graph.source(key));
-
-          _assert["default"].strictEqual(target, graph.target(key));
-
-          _assert["default"].deepStrictEqual(graph.getNodeAttributes(source), sA);
-
-          _assert["default"].deepStrictEqual(graph.getNodeAttributes(target), tA);
-
-          _assert["default"].strictEqual(graph.isUndirected(key), u);
-
-          return true;
-        });
-
-        _assert["default"].strictEqual(found, edges[0]);
-
-        _assert["default"].strictEqual(edges.length, 1);
-
-        found = graph[findName](data.node.key, function () {
-          return false;
-        });
-
-        _assert["default"].strictEqual(found, undefined);
-      },
-      'it should be possible to find an edge between source & target.': function itShouldBePossibleToFindAnEdgeBetweenSourceTarget() {
-        var edges = [];
-        var found = graph[findName](data.path.source, data.path.target, function (key, attributes, source, target, sA, tA, u) {
-          edges.push(key);
-
-          _assert["default"].deepStrictEqual(attributes, key === 'J->T' ? {
-            weight: 14
-          } : {});
-
-          _assert["default"].strictEqual(source, graph.source(key));
-
-          _assert["default"].strictEqual(target, graph.target(key));
-
-          _assert["default"].deepStrictEqual(graph.getNodeAttributes(source), sA);
-
-          _assert["default"].deepStrictEqual(graph.getNodeAttributes(target), tA);
-
-          _assert["default"].strictEqual(graph.isUndirected(key), u);
-
-          return true;
-        });
-
-        _assert["default"].strictEqual(found, edges[0]);
-
-        _assert["default"].strictEqual(edges.length, graph[name](data.path.source, data.path.target).length ? 1 : 0);
-
-        found = graph[findName](data.path.source, data.path.target, function () {
-          return false;
-        });
-
-        _assert["default"].strictEqual(found, undefined);
-      }
-    }), _defineProperty(_ref2, '#.' + someName, {
-      'it should possible to assert whether any edge matches a predicate.': function itShouldPossibleToAssertWhetherAnyEdgeMatchesAPredicate() {
-        var edges = [];
-        var found = graph[someName](function (key, attributes, source, target, sA, tA, u) {
-          edges.push(key);
-
-          _assert["default"].deepStrictEqual(attributes, key === 'J->T' ? {
-            weight: 14
-          } : {});
-
-          _assert["default"].strictEqual(source, graph.source(key));
-
-          _assert["default"].strictEqual(target, graph.target(key));
-
-          _assert["default"].deepStrictEqual(graph.getNodeAttributes(source), sA);
-
-          _assert["default"].deepStrictEqual(graph.getNodeAttributes(target), tA);
-
-          _assert["default"].strictEqual(graph.isUndirected(key), u);
-
-          return true;
-        });
-
-        _assert["default"].strictEqual(found, true);
-
-        _assert["default"].strictEqual(edges.length, 1);
-
-        found = graph[someName](function () {
-          return false;
-        });
-
-        _assert["default"].strictEqual(found, false);
-      },
-      "it should possible to assert whether any node's edge matches a predicate.": function itShouldPossibleToAssertWhetherAnyNodeSEdgeMatchesAPredicate() {
-        var edges = [];
-        var found = graph[someName](data.node.key, function (key, attributes, source, target, sA, tA, u) {
-          edges.push(key);
-
-          _assert["default"].deepStrictEqual(attributes, key === 'J->T' ? {
-            weight: 14
-          } : {});
-
-          _assert["default"].strictEqual(source, graph.source(key));
-
-          _assert["default"].strictEqual(target, graph.target(key));
-
-          _assert["default"].deepStrictEqual(graph.getNodeAttributes(source), sA);
-
-          _assert["default"].deepStrictEqual(graph.getNodeAttributes(target), tA);
-
-          _assert["default"].strictEqual(graph.isUndirected(key), u);
-
-          return true;
-        });
-
-        _assert["default"].strictEqual(found, true);
-
-        _assert["default"].strictEqual(edges.length, 1);
-
-        found = graph[someName](data.node.key, function () {
-          return false;
-        });
-
-        _assert["default"].strictEqual(found, false);
-      },
-      'it should possible to assert whether any edge between source & target matches a predicate.': function itShouldPossibleToAssertWhetherAnyEdgeBetweenSourceTargetMatchesAPredicate() {
-        var edges = [];
-        var found = graph[someName](data.path.source, data.path.target, function (key, attributes, source, target, sA, tA, u) {
-          edges.push(key);
-
-          _assert["default"].deepStrictEqual(attributes, key === 'J->T' ? {
-            weight: 14
-          } : {});
-
-          _assert["default"].strictEqual(source, graph.source(key));
-
-          _assert["default"].strictEqual(target, graph.target(key));
-
-          _assert["default"].deepStrictEqual(graph.getNodeAttributes(source), sA);
-
-          _assert["default"].deepStrictEqual(graph.getNodeAttributes(target), tA);
-
-          _assert["default"].strictEqual(graph.isUndirected(key), u);
-
-          return true;
-        });
-
-        _assert["default"].strictEqual(found, graph[name](data.path.source, data.path.target).length !== 0);
-
-        _assert["default"].strictEqual(edges.length, graph[name](data.path.source, data.path.target).length ? 1 : 0);
-
-        found = graph[someName](data.path.source, data.path.target, function () {
-          return false;
-        });
-
-        _assert["default"].strictEqual(found, false);
-      },
-      'it should always return false on empty sets.': function itShouldAlwaysReturnFalseOnEmptySets() {
-        var empty = new Graph();
-
-        _assert["default"].strictEqual(empty[someName](function () {
-          return true;
-        }), false);
-      }
-    }), _defineProperty(_ref2, '#.' + everyName, {
-      'it should possible to assert whether all edges matches a predicate.': function itShouldPossibleToAssertWhetherAllEdgesMatchesAPredicate() {
-        var edges = [];
-        var found = graph[everyName](function (key, attributes, source, target, sA, tA, u) {
-          edges.push(key);
-
-          _assert["default"].deepStrictEqual(attributes, key === 'J->T' ? {
-            weight: 14
-          } : {});
-
-          _assert["default"].strictEqual(source, graph.source(key));
-
-          _assert["default"].strictEqual(target, graph.target(key));
-
-          _assert["default"].deepStrictEqual(graph.getNodeAttributes(source), sA);
-
-          _assert["default"].deepStrictEqual(graph.getNodeAttributes(target), tA);
-
-          _assert["default"].strictEqual(graph.isUndirected(key), u);
-
-          return true;
-        });
-
-        _assert["default"].strictEqual(found, true);
-
-        found = graph[everyName](function () {
-          return false;
-        });
-
-        _assert["default"].strictEqual(found, false);
-      },
-      "it should possible to assert whether all of a node's edges matches a predicate.": function itShouldPossibleToAssertWhetherAllOfANodeSEdgesMatchesAPredicate() {
-        var edges = [];
-        var found = graph[everyName](data.node.key, function (key, attributes, source, target, sA, tA, u) {
-          edges.push(key);
-
-          _assert["default"].deepStrictEqual(attributes, key === 'J->T' ? {
-            weight: 14
-          } : {});
-
-          _assert["default"].strictEqual(source, graph.source(key));
-
-          _assert["default"].strictEqual(target, graph.target(key));
-
-          _assert["default"].deepStrictEqual(graph.getNodeAttributes(source), sA);
-
-          _assert["default"].deepStrictEqual(graph.getNodeAttributes(target), tA);
-
-          _assert["default"].strictEqual(graph.isUndirected(key), u);
-
-          return true;
-        });
-
-        _assert["default"].strictEqual(found, true);
-
-        found = graph[everyName](data.node.key, function () {
-          return false;
-        });
-
-        _assert["default"].strictEqual(found, false);
-      },
-      'it should possible to assert whether all edges between source & target matches a predicate.': function itShouldPossibleToAssertWhetherAllEdgesBetweenSourceTargetMatchesAPredicate() {
-        var edges = [];
-        var found = graph[everyName](data.path.source, data.path.target, function (key, attributes, source, target, sA, tA, u) {
-          edges.push(key);
-
-          _assert["default"].deepStrictEqual(attributes, key === 'J->T' ? {
-            weight: 14
-          } : {});
-
-          _assert["default"].strictEqual(source, graph.source(key));
-
-          _assert["default"].strictEqual(target, graph.target(key));
-
-          _assert["default"].deepStrictEqual(graph.getNodeAttributes(source), sA);
-
-          _assert["default"].deepStrictEqual(graph.getNodeAttributes(target), tA);
-
-          _assert["default"].strictEqual(graph.isUndirected(key), u);
-
-          return true;
-        });
-        var isEmpty = graph[name](data.path.source, data.path.target).length === 0;
-
-        _assert["default"].strictEqual(found, true);
-
-        found = graph[everyName](data.path.source, data.path.target, function () {
-          return false;
-        });
-
-        _assert["default"].strictEqual(found, isEmpty ? true : false);
-      },
-      'it should always return true on empty sets.': function itShouldAlwaysReturnTrueOnEmptySets() {
-        var empty = new Graph();
-
-        _assert["default"].strictEqual(empty[everyName](function () {
-          return true;
-        }), true);
-      }
-    }), _defineProperty(_ref2, '#.' + iteratorName, {
-      'it should be possible to return an iterator over the relevant edges.': function itShouldBePossibleToReturnAnIteratorOverTheRelevantEdges() {
-        var iterator = graph[iteratorName]();
-
-        _assert["default"].deepStrictEqual((0, _take["default"])(iterator), data.all.map(function (edge) {
-          var _graph$extremities = graph.extremities(edge),
-              source = _graph$extremities[0],
-              target = _graph$extremities[1];
-
-          return {
-            edge: edge,
-            attributes: graph.getEdgeAttributes(edge),
-            source: source,
-            target: target,
-            sourceAttributes: graph.getNodeAttributes(source),
-            targetAttributes: graph.getNodeAttributes(target),
-            undirected: graph.isUndirected(edge)
-          };
-        }));
-      },
-      "it should be possible to return an iterator over a node's relevant edges.": function itShouldBePossibleToReturnAnIteratorOverANodeSRelevantEdges() {
-        var iterator = graph[iteratorName](data.node.key);
-
-        _assert["default"].deepStrictEqual((0, _take["default"])(iterator), data.node.edges.map(function (edge) {
-          var _graph$extremities2 = graph.extremities(edge),
-              source = _graph$extremities2[0],
-              target = _graph$extremities2[1];
-
-          return {
-            edge: edge,
-            attributes: graph.getEdgeAttributes(edge),
-            source: source,
-            target: target,
-            sourceAttributes: graph.getNodeAttributes(source),
-            targetAttributes: graph.getNodeAttributes(target),
-            undirected: graph.isUndirected(edge)
-          };
-        }));
-      },
-      'it should be possible to return an iterator over relevant edges between source & target.': function itShouldBePossibleToReturnAnIteratorOverRelevantEdgesBetweenSourceTarget() {
-        var iterator = graph[iteratorName](data.path.source, data.path.target);
-
-        _assert["default"].deepStrictEqual((0, _take["default"])(iterator), data.path.edges.map(function (edge) {
-          var _graph$extremities3 = graph.extremities(edge),
-              source = _graph$extremities3[0],
-              target = _graph$extremities3[1];
-
-          return {
-            edge: edge,
-            attributes: graph.getEdgeAttributes(edge),
-            source: source,
-            target: target,
-            sourceAttributes: graph.getNodeAttributes(source),
-            targetAttributes: graph.getNodeAttributes(target),
-            undirected: graph.isUndirected(edge)
-          };
-        }));
-      }
-    }), _ref2;
-  }
-
-  var tests = {
-    Miscellaneous: {
-      'simple graph indices should work.': function simpleGraphIndicesShouldWork() {
-        var simpleGraph = new Graph();
-        (0, _helpers.addNodesFrom)(simpleGraph, [1, 2, 3, 4]);
-        simpleGraph.addEdgeWithKey('1->2', 1, 2);
-        simpleGraph.addEdgeWithKey('1->3', 1, 3);
-        simpleGraph.addEdgeWithKey('1->4', 1, 4);
-
-        _assert["default"].deepStrictEqual(simpleGraph.edges(1), ['1->2', '1->3', '1->4']);
-      },
-      'it should also work with typed graphs.': function itShouldAlsoWorkWithTypedGraphs() {
-        var undirected = new Graph({
-          type: 'undirected'
-        }),
-            directed = new Graph({
-          type: 'directed'
-        });
-        undirected.mergeEdgeWithKey('1--2', 1, 2);
-        directed.mergeEdgeWithKey('1->2', 1, 2);
-
-        _assert["default"].deepStrictEqual(undirected.edges(1, 2), ['1--2']);
-
-        _assert["default"].deepStrictEqual(directed.edges(1, 2), ['1->2']);
-      },
-      'self loops should appear when using #.inEdges and should appear only once with #.edges.': function selfLoopsShouldAppearWhenUsingInEdgesAndShouldAppearOnlyOnceWithEdges() {
-        var directed = new Graph({
-          type: 'directed'
-        });
-        directed.addNode('Lucy');
-        directed.addEdgeWithKey('Lucy', 'Lucy', 'Lucy');
-
-        _assert["default"].deepStrictEqual(directed.inEdges('Lucy'), ['Lucy']);
-
-        _assert["default"].deepStrictEqual(Array.from(directed.inEdgeEntries('Lucy')).map(function (x) {
-          return x.edge;
-        }), ['Lucy']);
-
-        var edges = [];
-        directed.forEachInEdge('Lucy', function (edge) {
-          edges.push(edge);
-        });
-
-        _assert["default"].deepStrictEqual(edges, ['Lucy']);
-
-        _assert["default"].deepStrictEqual(directed.edges('Lucy'), ['Lucy']);
-
-        edges = [];
-        directed.forEachEdge('Lucy', function (edge) {
-          edges.push(edge);
-        });
-
-        _assert["default"].deepStrictEqual(edges, ['Lucy']);
-
-        _assert["default"].deepStrictEqual(Array.from(directed.edgeEntries('Lucy')).map(function (x) {
-          return x.edge;
-        }), ['Lucy']);
-      },
-      'it should be possible to retrieve self loops.': function itShouldBePossibleToRetrieveSelfLoops() {
-        var loopy = new Graph();
-        loopy.addNode('John');
-        loopy.addEdgeWithKey('d', 'John', 'John');
-        loopy.addUndirectedEdgeWithKey('u', 'John', 'John');
-
-        _assert["default"].deepStrictEqual(new Set(loopy.edges('John', 'John')), new Set(['d', 'u']));
-
-        _assert["default"].deepStrictEqual(loopy.directedEdges('John', 'John'), ['d']);
-
-        _assert["default"].deepStrictEqual(loopy.undirectedEdges('John', 'John'), ['u']);
-
-        var edges = [];
-        loopy.forEachDirectedEdge('John', 'John', function (edge) {
-          edges.push(edge);
-        });
-
-        _assert["default"].deepStrictEqual(edges, ['d']);
-
-        edges = [];
-        loopy.forEachUndirectedEdge('John', 'John', function (edge) {
-          edges.push(edge);
-        });
-
-        _assert["default"].deepStrictEqual(edges, ['u']);
-      },
-      'self loops in multi graphs should work properly (#352).': function selfLoopsInMultiGraphsShouldWorkProperly352() {
-        var loopy = new Graph({
-          multi: true
-        });
-        loopy.addNode('n');
-        loopy.addEdgeWithKey('e1', 'n', 'n');
-        loopy.addEdgeWithKey('e2', 'n', 'n');
-        loopy.addUndirectedEdgeWithKey('e3', 'n', 'n'); // Arrays
-
-        _assert["default"].deepStrictEqual(loopy.edges('n'), ['e2', 'e1', 'e3']);
-
-        _assert["default"].deepStrictEqual(loopy.outboundEdges('n'), ['e2', 'e1', 'e3']);
-
-        _assert["default"].deepStrictEqual(loopy.inboundEdges('n'), ['e2', 'e1', 'e3']);
-
-        _assert["default"].deepStrictEqual(loopy.outEdges('n'), ['e2', 'e1']);
-
-        _assert["default"].deepStrictEqual(loopy.inEdges('n'), ['e2', 'e1']);
-
-        _assert["default"].deepStrictEqual(loopy.undirectedEdges('n'), ['e3']);
-
-        _assert["default"].deepStrictEqual(loopy.directedEdges('n'), ['e2', 'e1']);
-
-        _assert["default"].deepStrictEqual(loopy.edges('n', 'n'), ['e2', 'e1', 'e3']);
-
-        _assert["default"].deepStrictEqual(loopy.outboundEdges('n', 'n'), ['e2', 'e1', 'e3']);
-
-        _assert["default"].deepStrictEqual(loopy.inboundEdges('n', 'n'), ['e2', 'e1', 'e3']);
-
-        _assert["default"].deepStrictEqual(loopy.outEdges('n', 'n'), ['e2', 'e1']);
-
-        _assert["default"].deepStrictEqual(loopy.inEdges('n', 'n'), ['e2', 'e1']);
-
-        _assert["default"].deepStrictEqual(loopy.undirectedEdges('n', 'n'), ['e3']);
-
-        _assert["default"].deepStrictEqual(loopy.directedEdges('n', 'n'), ['e2', 'e1']); // Iterators
-
-
-        var mapKeys = function mapKeys(it) {
-          return (0, _take["default"])((0, _map["default"])(it, function (e) {
-            return e.edge;
-          }));
-        };
-
-        _assert["default"].deepStrictEqual(mapKeys(loopy.edgeEntries('n')), ['e2', 'e1', 'e3']);
-
-        _assert["default"].deepStrictEqual(mapKeys(loopy.outboundEdgeEntries('n')), ['e2', 'e1', 'e3']);
-
-        _assert["default"].deepStrictEqual(mapKeys(loopy.inboundEdgeEntries('n')), ['e2', 'e1', 'e3']);
-
-        _assert["default"].deepStrictEqual(mapKeys(loopy.outEdgeEntries('n')), ['e2', 'e1']);
-
-        _assert["default"].deepStrictEqual(mapKeys(loopy.inEdgeEntries('n')), ['e2', 'e1']);
-
-        _assert["default"].deepStrictEqual(mapKeys(loopy.undirectedEdgeEntries('n')), ['e3']);
-
-        _assert["default"].deepStrictEqual(mapKeys(loopy.directedEdgeEntries('n')), ['e2', 'e1']);
-
-        _assert["default"].deepStrictEqual(mapKeys(loopy.edgeEntries('n', 'n')), ['e2', 'e1', 'e3']);
-
-        _assert["default"].deepStrictEqual(mapKeys(loopy.outboundEdgeEntries('n', 'n')), ['e2', 'e1', 'e3']);
-
-        _assert["default"].deepStrictEqual(mapKeys(loopy.inboundEdgeEntries('n', 'n')), ['e2', 'e1', 'e3']);
-
-        _assert["default"].deepStrictEqual(mapKeys(loopy.outEdgeEntries('n', 'n')), ['e2', 'e1']);
-
-        _assert["default"].deepStrictEqual(mapKeys(loopy.inEdgeEntries('n', 'n')), ['e2', 'e1']);
-
-        _assert["default"].deepStrictEqual(mapKeys(loopy.undirectedEdgeEntries('n', 'n')), ['e3']);
-
-        _assert["default"].deepStrictEqual(mapKeys(loopy.directedEdgeEntries('n', 'n')), ['e2', 'e1']);
-      },
-      'findOutboundEdge should work on multigraphs (#319).': function findOutboundEdgeShouldWorkOnMultigraphs319() {
-        var loopy = new Graph({
-          multi: true
-        });
-        loopy.mergeEdgeWithKey('e1', 'n', 'm');
-        loopy.mergeEdgeWithKey('e2', 'n', 'n');
-
-        _assert["default"].strictEqual(loopy.findOutboundEdge(function (_e, _a, s, t) {
-          return s === t;
-        }), 'e2');
-
-        _assert["default"].strictEqual(loopy.findOutboundEdge('n', function (_e, _a, s, t) {
-          return s === t;
-        }), 'e2');
-
-        _assert["default"].strictEqual(loopy.findOutboundEdge('n', 'n', function (_e, _a, s, t) {
-          return s === t;
-        }), 'e2');
-      }
-    }
-  }; // Common tests
-
-  METHODS.forEach(function (name) {
-    return (0, _helpers.deepMerge)(tests, commonTests(name));
-  }); // Specific tests
-
-  for (var name in TEST_DATA) {
-    (0, _helpers.deepMerge)(tests, specificTests(name, TEST_DATA[name]));
-  }
-
-  return tests;
-}
\ No newline at end of file
diff --git a/libs/shared/graph-layouts/node_modules/graphology/specs/iteration/index.js b/libs/shared/graph-layouts/node_modules/graphology/specs/iteration/index.js
deleted file mode 100644
index bf2e892c5..000000000
--- a/libs/shared/graph-layouts/node_modules/graphology/specs/iteration/index.js
+++ /dev/null
@@ -1,161 +0,0 @@
-"use strict";
-
-Object.defineProperty(exports, "__esModule", {
-  value: true
-});
-exports["default"] = iteration;
-
-var _assert = _interopRequireDefault(require("assert"));
-
-var _nodes = _interopRequireDefault(require("./nodes"));
-
-var _edges = _interopRequireDefault(require("./edges"));
-
-var _neighbors = _interopRequireDefault(require("./neighbors"));
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
-
-/**
- * Graphology Iteration Specs
- * ===========================
- *
- * Testing the iteration-related methods of the graph.
- */
-function iteration(Graph, checkers) {
-  return {
-    Adjacency: {
-      '#.forEachAdjacencyEntry': {
-        'it should iterate over the relevant elements.': function itShouldIterateOverTheRelevantElements() {
-          function test(multi) {
-            var graph = new Graph({
-              multi: multi
-            });
-            graph.addNode('John', {
-              hello: 'world'
-            });
-
-            var _graph$mergeUndirecte = graph.mergeUndirectedEdge('John', 'Mary', {
-              weight: 3
-            }),
-                e1 = _graph$mergeUndirecte[0];
-
-            graph.mergeUndirectedEdge('Thomas', 'John');
-            graph.mergeDirectedEdge('John', 'Thomas');
-            var count = 0;
-            graph.forEachAdjacencyEntry(function (node, neighbor, attr, neighborAttr, edge, edgeAttr, undirected) {
-              count++;
-
-              if (node === 'John') {
-                _assert["default"].deepStrictEqual(attr, {
-                  hello: 'world'
-                });
-              } else {
-                _assert["default"].deepStrictEqual(attr, {});
-              }
-
-              if (neighbor === 'John') {
-                _assert["default"].deepStrictEqual(neighborAttr, {
-                  hello: 'world'
-                });
-              } else {
-                _assert["default"].deepStrictEqual(neighborAttr, {});
-              }
-
-              if (edge === e1) {
-                _assert["default"].deepStrictEqual(edgeAttr, {
-                  weight: 3
-                });
-              } else {
-                _assert["default"].deepStrictEqual(edgeAttr, {});
-              }
-
-              _assert["default"].strictEqual(graph.isUndirected(edge), undirected);
-            });
-
-            _assert["default"].strictEqual(count, graph.directedSize + graph.undirectedSize * 2);
-
-            graph.addNode('Disconnected');
-            count = 0;
-            graph.forEachAdjacencyEntryWithOrphans(function (node, neighbor, attr, neighborAttr, edge, edgeAttr, undirected) {
-              count++;
-              if (node !== 'Disconnected') return;
-
-              _assert["default"].strictEqual(neighbor, null);
-
-              _assert["default"].strictEqual(neighborAttr, null);
-
-              _assert["default"].strictEqual(edge, null);
-
-              _assert["default"].strictEqual(edgeAttr, null);
-
-              _assert["default"].strictEqual(undirected, null);
-            }, true);
-
-            _assert["default"].strictEqual(count, graph.directedSize + graph.undirectedSize * 2 + 1);
-          }
-
-          test(false);
-          test(true);
-        }
-      },
-      '#.forEachAssymetricAdjacencyEntry': {
-        'it should iterate over the relevant elements.': function itShouldIterateOverTheRelevantElements() {
-          function test(multi) {
-            var graph = new Graph({
-              multi: multi
-            });
-            graph.addNode('John', {
-              hello: 'world'
-            });
-            graph.mergeUndirectedEdge('John', 'Mary', {
-              weight: 3
-            });
-            graph.mergeUndirectedEdge('Thomas', 'John');
-            graph.mergeDirectedEdge('John', 'Thomas');
-            var edges = [];
-            graph.forEachAssymetricAdjacencyEntry(function (node, neighbor, attr, neighborAttr, edge, edgeAttr, undirected) {
-              if (undirected) {
-                _assert["default"].strictEqual(node < neighbor, true);
-              }
-
-              edges.push(edge);
-            });
-
-            _assert["default"].strictEqual(edges.length, graph.directedSize + graph.undirectedSize);
-
-            _assert["default"].deepStrictEqual(new Set(edges).size, edges.length);
-
-            graph.addNode('Disconnected');
-            var count = 0;
-            var nulls = 0;
-            graph.forEachAssymetricAdjacencyEntryWithOrphans(function (node, neighbor, attr, neighborAttr, edge, edgeAttr, undirected) {
-              count++;
-              if (neighbor) return;
-              nulls++;
-
-              _assert["default"].strictEqual(neighbor, null);
-
-              _assert["default"].strictEqual(neighborAttr, null);
-
-              _assert["default"].strictEqual(edge, null);
-
-              _assert["default"].strictEqual(edgeAttr, null);
-
-              _assert["default"].strictEqual(undirected, null);
-            }, true);
-
-            _assert["default"].strictEqual(count, graph.directedSize + graph.undirectedSize + 3);
-
-            _assert["default"].strictEqual(nulls, 3);
-          }
-
-          test(false);
-          test(true);
-        }
-      }
-    },
-    Nodes: (0, _nodes["default"])(Graph, checkers),
-    Edges: (0, _edges["default"])(Graph, checkers),
-    Neighbors: (0, _neighbors["default"])(Graph, checkers)
-  };
-}
\ No newline at end of file
diff --git a/libs/shared/graph-layouts/node_modules/graphology/specs/iteration/neighbors.js b/libs/shared/graph-layouts/node_modules/graphology/specs/iteration/neighbors.js
deleted file mode 100644
index 7948bd77c..000000000
--- a/libs/shared/graph-layouts/node_modules/graphology/specs/iteration/neighbors.js
+++ /dev/null
@@ -1,284 +0,0 @@
-"use strict";
-
-Object.defineProperty(exports, "__esModule", {
-  value: true
-});
-exports["default"] = neighborsIteration;
-
-var _assert = _interopRequireDefault(require("assert"));
-
-var _take = _interopRequireDefault(require("obliterator/take"));
-
-var _helpers = require("../helpers");
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
-
-function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
-
-var METHODS = ['neighbors', 'inNeighbors', 'outNeighbors', 'inboundNeighbors', 'outboundNeighbors', 'directedNeighbors', 'undirectedNeighbors'];
-
-function neighborsIteration(Graph, checkers) {
-  var notFound = checkers.notFound,
-      invalid = checkers.invalid;
-  var graph = new Graph({
-    multi: true
-  });
-  (0, _helpers.addNodesFrom)(graph, ['John', 'Thomas', 'Martha', 'Roger', 'Catherine', 'Alone', 'Forever']);
-  graph.replaceNodeAttributes('John', {
-    age: 34
-  });
-  graph.replaceNodeAttributes('Martha', {
-    age: 35
-  });
-  graph.addDirectedEdgeWithKey('J->T', 'John', 'Thomas');
-  graph.addDirectedEdgeWithKey('J->M', 'John', 'Martha');
-  graph.addDirectedEdgeWithKey('C->J', 'Catherine', 'John');
-  graph.addUndirectedEdgeWithKey('M<->R', 'Martha', 'Roger');
-  graph.addUndirectedEdgeWithKey('M<->J', 'Martha', 'John');
-  graph.addUndirectedEdgeWithKey('J<->R', 'John', 'Roger');
-  graph.addUndirectedEdgeWithKey('T<->M', 'Thomas', 'Martha');
-  var TEST_DATA = {
-    neighbors: {
-      node: {
-        key: 'John',
-        neighbors: ['Catherine', 'Thomas', 'Martha', 'Roger']
-      }
-    },
-    inNeighbors: {
-      node: {
-        key: 'John',
-        neighbors: ['Catherine']
-      }
-    },
-    outNeighbors: {
-      node: {
-        key: 'John',
-        neighbors: ['Thomas', 'Martha']
-      }
-    },
-    inboundNeighbors: {
-      node: {
-        key: 'John',
-        neighbors: ['Catherine', 'Martha', 'Roger']
-      }
-    },
-    outboundNeighbors: {
-      node: {
-        key: 'John',
-        neighbors: ['Thomas', 'Martha', 'Roger']
-      }
-    },
-    directedNeighbors: {
-      node: {
-        key: 'John',
-        neighbors: ['Catherine', 'Thomas', 'Martha']
-      }
-    },
-    undirectedNeighbors: {
-      node: {
-        key: 'John',
-        neighbors: ['Martha', 'Roger']
-      }
-    }
-  };
-
-  function commonTests(name) {
-    return _defineProperty({}, '#.' + name, {
-      'it should throw when the node is not found.': function itShouldThrowWhenTheNodeIsNotFound() {
-        _assert["default"]["throws"](function () {
-          graph[name]('Test');
-        }, notFound());
-
-        if (~name.indexOf('count')) return;
-
-        _assert["default"]["throws"](function () {
-          graph[name]('Test', 'SecondTest');
-        }, notFound());
-      }
-    });
-  }
-
-  function specificTests(name, data) {
-    var _ref2;
-
-    var capitalized = name[0].toUpperCase() + name.slice(1, -1);
-    var forEachName = 'forEach' + capitalized;
-    var findName = 'find' + capitalized;
-    var iteratorName = name.slice(0, -1) + 'Entries';
-    var areName = 'are' + capitalized + 's';
-    var mapName = 'map' + capitalized + 's';
-    var filterName = 'filter' + capitalized + 's';
-    var reduceName = 'reduce' + capitalized + 's';
-    var someName = 'some' + capitalized;
-    var everyName = 'every' + capitalized;
-    return _ref2 = {}, _defineProperty(_ref2, '#.' + name, {
-      'it should return the correct neighbors array.': function itShouldReturnTheCorrectNeighborsArray() {
-        var neighbors = graph[name](data.node.key);
-
-        _assert["default"].deepStrictEqual(neighbors, data.node.neighbors);
-
-        _assert["default"].deepStrictEqual(graph[name]('Alone'), []);
-      }
-    }), _defineProperty(_ref2, '#.' + forEachName, {
-      'it should be possible to iterate over neighbors using a callback.': function itShouldBePossibleToIterateOverNeighborsUsingACallback() {
-        var neighbors = [];
-        graph[forEachName](data.node.key, function (target, attrs) {
-          neighbors.push(target);
-
-          _assert["default"].deepStrictEqual(graph.getNodeAttributes(target), attrs);
-
-          _assert["default"].strictEqual(graph[areName](data.node.key, target), true);
-        });
-
-        _assert["default"].deepStrictEqual(neighbors, data.node.neighbors);
-      }
-    }), _defineProperty(_ref2, '#.' + mapName, {
-      'it should be possible to map neighbors using a callback.': function itShouldBePossibleToMapNeighborsUsingACallback() {
-        var result = graph[mapName](data.node.key, function (target) {
-          return target;
-        });
-
-        _assert["default"].deepStrictEqual(result, data.node.neighbors);
-      }
-    }), _defineProperty(_ref2, '#.' + filterName, {
-      'it should be possible to filter neighbors using a callback.': function itShouldBePossibleToFilterNeighborsUsingACallback() {
-        var result = graph[filterName](data.node.key, function () {
-          return true;
-        });
-
-        _assert["default"].deepStrictEqual(result, data.node.neighbors);
-
-        result = graph[filterName](data.node.key, function () {
-          return false;
-        });
-
-        _assert["default"].deepStrictEqual(result, []);
-      }
-    }), _defineProperty(_ref2, '#.' + reduceName, {
-      'it sould throw if not given an initial value.': function itSouldThrowIfNotGivenAnInitialValue() {
-        _assert["default"]["throws"](function () {
-          graph[reduceName]('node', function () {
-            return true;
-          });
-        }, invalid());
-      },
-      'it should be possible to reduce neighbors using a callback.': function itShouldBePossibleToReduceNeighborsUsingACallback() {
-        var result = graph[reduceName](data.node.key, function (acc, key) {
-          return acc.concat(key);
-        }, []);
-
-        _assert["default"].deepStrictEqual(result, data.node.neighbors);
-      }
-    }), _defineProperty(_ref2, '#.' + findName, {
-      'it should be possible to find neighbors.': function itShouldBePossibleToFindNeighbors() {
-        var neighbors = [];
-        var found = graph[findName](data.node.key, function (target, attrs) {
-          neighbors.push(target);
-
-          _assert["default"].deepStrictEqual(graph.getNodeAttributes(target), attrs);
-
-          _assert["default"].strictEqual(graph[areName](data.node.key, target), true);
-
-          return true;
-        });
-
-        _assert["default"].strictEqual(found, neighbors[0]);
-
-        _assert["default"].deepStrictEqual(neighbors, data.node.neighbors.slice(0, 1));
-
-        found = graph[findName](data.node.key, function () {
-          return false;
-        });
-
-        _assert["default"].strictEqual(found, undefined);
-      }
-    }), _defineProperty(_ref2, '#.' + someName, {
-      'it should always return false on empty set.': function itShouldAlwaysReturnFalseOnEmptySet() {
-        var loneGraph = new Graph();
-        loneGraph.addNode('alone');
-
-        _assert["default"].strictEqual(loneGraph[someName]('alone', function () {
-          return true;
-        }), false);
-      },
-      'it should be possible to assert whether any neighbor matches a predicate.': function itShouldBePossibleToAssertWhetherAnyNeighborMatchesAPredicate() {
-        _assert["default"].strictEqual(graph[someName](data.node.key, function () {
-          return true;
-        }), data.node.neighbors.length > 0);
-      }
-    }), _defineProperty(_ref2, '#.' + everyName, {
-      'it should always return true on empty set.': function itShouldAlwaysReturnTrueOnEmptySet() {
-        var loneGraph = new Graph();
-        loneGraph.addNode('alone');
-
-        _assert["default"].strictEqual(loneGraph[everyName]('alone', function () {
-          return true;
-        }), true);
-      },
-      'it should be possible to assert whether any neighbor matches a predicate.': function itShouldBePossibleToAssertWhetherAnyNeighborMatchesAPredicate() {
-        _assert["default"].strictEqual(graph[everyName](data.node.key, function () {
-          return true;
-        }), data.node.neighbors.length > 0);
-      }
-    }), _defineProperty(_ref2, '#.' + iteratorName, {
-      'it should be possible to create an iterator over neighbors.': function itShouldBePossibleToCreateAnIteratorOverNeighbors() {
-        var iterator = graph[iteratorName](data.node.key);
-
-        _assert["default"].deepStrictEqual((0, _take["default"])(iterator), data.node.neighbors.map(function (neighbor) {
-          return {
-            neighbor: neighbor,
-            attributes: graph.getNodeAttributes(neighbor)
-          };
-        }));
-      }
-    }), _ref2;
-  }
-
-  var tests = {
-    Miscellaneous: {
-      'self loops should appear when using #.inNeighbors and should appear only once with #.neighbors.': function selfLoopsShouldAppearWhenUsingInNeighborsAndShouldAppearOnlyOnceWithNeighbors() {
-        var directed = new Graph({
-          type: 'directed'
-        });
-        directed.addNode('Lucy');
-        directed.addEdgeWithKey('test', 'Lucy', 'Lucy');
-
-        _assert["default"].deepStrictEqual(directed.inNeighbors('Lucy'), ['Lucy']);
-
-        _assert["default"].deepStrictEqual(Array.from(directed.inNeighborEntries('Lucy')).map(function (x) {
-          return x.neighbor;
-        }), ['Lucy']);
-
-        var neighbors = [];
-        directed.forEachInNeighbor('Lucy', function (neighbor) {
-          neighbors.push(neighbor);
-        });
-
-        _assert["default"].deepStrictEqual(neighbors, ['Lucy']);
-
-        _assert["default"].deepStrictEqual(directed.neighbors('Lucy'), ['Lucy']);
-
-        neighbors = [];
-        directed.forEachNeighbor('Lucy', function (neighbor) {
-          neighbors.push(neighbor);
-        });
-
-        _assert["default"].deepStrictEqual(neighbors, ['Lucy']);
-
-        _assert["default"].deepStrictEqual(Array.from(directed.neighborEntries('Lucy')).map(function (x) {
-          return x.neighbor;
-        }), ['Lucy']);
-      }
-    }
-  }; // Common tests
-
-  METHODS.forEach(function (name) {
-    return (0, _helpers.deepMerge)(tests, commonTests(name));
-  }); // Specific tests
-
-  for (var name in TEST_DATA) {
-    (0, _helpers.deepMerge)(tests, specificTests(name, TEST_DATA[name]));
-  }
-
-  return tests;
-}
\ No newline at end of file
diff --git a/libs/shared/graph-layouts/node_modules/graphology/specs/iteration/nodes.js b/libs/shared/graph-layouts/node_modules/graphology/specs/iteration/nodes.js
deleted file mode 100644
index 33298820d..000000000
--- a/libs/shared/graph-layouts/node_modules/graphology/specs/iteration/nodes.js
+++ /dev/null
@@ -1,248 +0,0 @@
-"use strict";
-
-Object.defineProperty(exports, "__esModule", {
-  value: true
-});
-exports["default"] = nodesIteration;
-
-var _assert = _interopRequireDefault(require("assert"));
-
-var _helpers = require("../helpers");
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
-
-/**
- * Graphology Nodes Iteration Specs
- * =================================
- *
- * Testing the nodes iteration-related methods of the graph.
- */
-function nodesIteration(Graph, checkers) {
-  var invalid = checkers.invalid;
-  return {
-    '#.nodes': {
-      'it should return the list of nodes of the graph.': function itShouldReturnTheListOfNodesOfTheGraph() {
-        var graph = new Graph();
-        (0, _helpers.addNodesFrom)(graph, ['one', 'two', 'three']);
-
-        _assert["default"].deepStrictEqual(graph.nodes(), ['one', 'two', 'three']);
-      }
-    },
-    '#.forEachNode': {
-      'it should throw if given callback is not a function.': function itShouldThrowIfGivenCallbackIsNotAFunction() {
-        var graph = new Graph();
-
-        _assert["default"]["throws"](function () {
-          graph.forEachNode(null);
-        }, invalid());
-      },
-      'it should be possible to iterate over nodes and their attributes.': function itShouldBePossibleToIterateOverNodesAndTheirAttributes() {
-        var graph = new Graph();
-        graph.addNode('John', {
-          age: 34
-        });
-        graph.addNode('Martha', {
-          age: 33
-        });
-        var count = 0;
-        graph.forEachNode(function (key, attributes) {
-          _assert["default"].strictEqual(key, count ? 'Martha' : 'John');
-
-          _assert["default"].deepStrictEqual(attributes, count ? {
-            age: 33
-          } : {
-            age: 34
-          });
-
-          count++;
-        });
-
-        _assert["default"].strictEqual(count, 2);
-      }
-    },
-    '#.findNode': {
-      'it should throw if given callback is not a function.': function itShouldThrowIfGivenCallbackIsNotAFunction() {
-        var graph = new Graph();
-
-        _assert["default"]["throws"](function () {
-          graph.findNode(null);
-        }, invalid());
-      },
-      'it should be possible to find a node in the graph.': function itShouldBePossibleToFindANodeInTheGraph() {
-        var graph = new Graph();
-        graph.addNode('John', {
-          age: 34
-        });
-        graph.addNode('Martha', {
-          age: 33
-        });
-        var count = 0;
-        var found = graph.findNode(function (key, attributes) {
-          _assert["default"].strictEqual(key, 'John');
-
-          _assert["default"].deepStrictEqual(attributes, {
-            age: 34
-          });
-
-          count++;
-          if (key === 'John') return true;
-        });
-
-        _assert["default"].strictEqual(found, 'John');
-
-        _assert["default"].strictEqual(count, 1);
-
-        found = graph.findNode(function () {
-          return false;
-        });
-
-        _assert["default"].strictEqual(found, undefined);
-      }
-    },
-    '#.mapNodes': {
-      'it should be possible to map nodes.': function itShouldBePossibleToMapNodes() {
-        var graph = new Graph();
-        graph.addNode('one', {
-          weight: 2
-        });
-        graph.addNode('two', {
-          weight: 3
-        });
-        var result = graph.mapNodes(function (node, attr) {
-          return attr.weight * 2;
-        });
-
-        _assert["default"].deepStrictEqual(result, [4, 6]);
-      }
-    },
-    '#.someNode': {
-      'it should always return false on empty sets.': function itShouldAlwaysReturnFalseOnEmptySets() {
-        var graph = new Graph();
-
-        _assert["default"].strictEqual(graph.someNode(function () {
-          return true;
-        }), false);
-      },
-      'it should be possible to find if some node matches a predicate.': function itShouldBePossibleToFindIfSomeNodeMatchesAPredicate() {
-        var graph = new Graph();
-        graph.addNode('one', {
-          weight: 2
-        });
-        graph.addNode('two', {
-          weight: 3
-        });
-
-        _assert["default"].strictEqual(graph.someNode(function (node, attr) {
-          return attr.weight > 6;
-        }), false);
-
-        _assert["default"].strictEqual(graph.someNode(function (node, attr) {
-          return attr.weight > 2;
-        }), true);
-      }
-    },
-    '#.everyNode': {
-      'it should always return true on empty sets.': function itShouldAlwaysReturnTrueOnEmptySets() {
-        var graph = new Graph();
-
-        _assert["default"].strictEqual(graph.everyNode(function () {
-          return true;
-        }), true);
-      },
-      'it should be possible to find if all node matches a predicate.': function itShouldBePossibleToFindIfAllNodeMatchesAPredicate() {
-        var graph = new Graph();
-        graph.addNode('one', {
-          weight: 2
-        });
-        graph.addNode('two', {
-          weight: 3
-        });
-
-        _assert["default"].strictEqual(graph.everyNode(function (node, attr) {
-          return attr.weight > 2;
-        }), false);
-
-        _assert["default"].strictEqual(graph.everyNode(function (node, attr) {
-          return attr.weight > 1;
-        }), true);
-      }
-    },
-    '#.filterNodes': {
-      'it should be possible to filter nodes.': function itShouldBePossibleToFilterNodes() {
-        var graph = new Graph();
-        graph.addNode('one', {
-          weight: 2
-        });
-        graph.addNode('two', {
-          weight: 3
-        });
-        graph.addNode('three', {
-          weight: 4
-        });
-        var result = graph.filterNodes(function (node, _ref) {
-          var weight = _ref.weight;
-          return weight >= 3;
-        });
-
-        _assert["default"].deepStrictEqual(result, ['two', 'three']);
-      }
-    },
-    '#.reduceNodes': {
-      'it should throw if initial value is not given.': function itShouldThrowIfInitialValueIsNotGiven() {
-        var graph = new Graph();
-
-        _assert["default"]["throws"](function () {
-          graph.reduceNodes(function (x, _, attr) {
-            return x + attr.weight;
-          });
-        }, invalid());
-      },
-      'it should be possible to reduce nodes.': function itShouldBePossibleToReduceNodes() {
-        var graph = new Graph();
-        graph.addNode('one', {
-          weight: 2
-        });
-        graph.addNode('two', {
-          weight: 3
-        });
-        graph.addNode('three', {
-          weight: 4
-        });
-        var result = graph.reduceNodes(function (x, _, attr) {
-          return x + attr.weight;
-        }, 0);
-
-        _assert["default"].strictEqual(result, 9);
-      }
-    },
-    '#.nodeEntries': {
-      'it should be possible to create a nodes iterator.': function itShouldBePossibleToCreateANodesIterator() {
-        var graph = new Graph();
-        (0, _helpers.addNodesFrom)(graph, ['one', 'two', 'three']);
-        graph.replaceNodeAttributes('two', {
-          hello: 'world'
-        });
-        var iterator = graph.nodeEntries();
-
-        _assert["default"].deepStrictEqual(iterator.next().value, {
-          node: 'one',
-          attributes: {}
-        });
-
-        _assert["default"].deepStrictEqual(iterator.next().value, {
-          node: 'two',
-          attributes: {
-            hello: 'world'
-          }
-        });
-
-        _assert["default"].deepStrictEqual(iterator.next().value, {
-          node: 'three',
-          attributes: {}
-        });
-
-        _assert["default"].strictEqual(iterator.next().done, true);
-      }
-    }
-  };
-}
\ No newline at end of file
diff --git a/libs/shared/graph-layouts/node_modules/graphology/specs/known.js b/libs/shared/graph-layouts/node_modules/graphology/specs/known.js
deleted file mode 100644
index 040ffb036..000000000
--- a/libs/shared/graph-layouts/node_modules/graphology/specs/known.js
+++ /dev/null
@@ -1,50 +0,0 @@
-"use strict";
-
-Object.defineProperty(exports, "__esModule", {
-  value: true
-});
-exports["default"] = knownMethods;
-
-var _assert = _interopRequireDefault(require("assert"));
-
-var _helpers = require("./helpers");
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
-
-/**
- * Graphology Known Methods Specs
- * ===============================
- *
- * Testing the known methods of the graph.
- */
-function knownMethods(Graph) {
-  return {
-    '#.toJSON': {
-      'it should return the serialized graph.': function itShouldReturnTheSerializedGraph() {
-        var graph = new Graph({
-          multi: true
-        });
-        (0, _helpers.addNodesFrom)(graph, ['John', 'Jack', 'Martha']);
-        graph.setNodeAttribute('John', 'age', 34);
-        graph.addEdgeWithKey('J->J•1', 'John', 'Jack');
-        graph.addEdgeWithKey('J->J•2', 'John', 'Jack', {
-          weight: 2
-        });
-        graph.addEdgeWithKey('J->J•3', 'John', 'Jack');
-        graph.addUndirectedEdgeWithKey('J<->J•1', 'John', 'Jack');
-        graph.addUndirectedEdgeWithKey('J<->J•2', 'John', 'Jack', {
-          weight: 3
-        });
-
-        _assert["default"].deepStrictEqual(graph.toJSON(), graph["export"]());
-      }
-    },
-    '#.toString': {
-      'it should return "[object Graph]".': function itShouldReturnObjectGraph() {
-        var graph = new Graph();
-
-        _assert["default"].strictEqual(graph.toString(), '[object Graph]');
-      }
-    }
-  };
-}
\ No newline at end of file
diff --git a/libs/shared/graph-layouts/node_modules/graphology/specs/misc.js b/libs/shared/graph-layouts/node_modules/graphology/specs/misc.js
deleted file mode 100644
index c0044b1a2..000000000
--- a/libs/shared/graph-layouts/node_modules/graphology/specs/misc.js
+++ /dev/null
@@ -1,112 +0,0 @@
-"use strict";
-
-Object.defineProperty(exports, "__esModule", {
-  value: true
-});
-exports["default"] = misc;
-
-var _assert = _interopRequireDefault(require("assert"));
-
-var _helpers = require("./helpers");
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
-
-/**
- * Graphology Misc Specs
- * ======================
- *
- * Testing the miscellaneous things about the graph.
- */
-function misc(Graph) {
-  return {
-    Structure: {
-      'a simple mixed graph can have A->B, B->A & A<->B': function aSimpleMixedGraphCanHaveABBAAB() {
-        var graph = new Graph();
-        (0, _helpers.addNodesFrom)(graph, ['Audrey', 'Benjamin']);
-
-        _assert["default"].doesNotThrow(function () {
-          graph.addEdge('Audrey', 'Benjamin');
-          graph.addEdge('Benjamin', 'Audrey');
-          graph.addUndirectedEdge('Benjamin', 'Audrey');
-        });
-      },
-      'deleting the last edge between A & B should correctly clear neighbor index.': function deletingTheLastEdgeBetweenABShouldCorrectlyClearNeighborIndex() {
-        var graph = new Graph({
-          multi: true
-        });
-        graph.addNode('A');
-        graph.addNode('B');
-        graph.addEdge('A', 'B');
-        graph.addEdge('A', 'B');
-        graph.forEachEdge('A', function (edge) {
-          return graph.dropEdge(edge);
-        });
-
-        _assert["default"].deepStrictEqual(graph.neighbors('A'), []);
-
-        _assert["default"].deepStrictEqual(graph.neighbors('B'), []);
-      },
-      'exhaustive deletion use-cases should not break doubly-linked lists implementation of multigraph edge storage.': function exhaustiveDeletionUseCasesShouldNotBreakDoublyLinkedListsImplementationOfMultigraphEdgeStorage() {
-        var graph = new Graph({
-          multi: true
-        });
-        graph.mergeEdgeWithKey('1', 'A', 'B');
-        graph.mergeEdgeWithKey('2', 'A', 'B');
-        graph.mergeEdgeWithKey('3', 'A', 'B');
-        graph.mergeEdgeWithKey('4', 'A', 'B');
-        graph.dropEdge('1');
-        graph.dropEdge('2');
-        graph.dropEdge('3');
-        graph.dropEdge('4');
-
-        _assert["default"].strictEqual(graph.size, 0);
-
-        _assert["default"].strictEqual(graph.areNeighbors('A', 'B'), false);
-
-        graph.mergeEdgeWithKey('1', 'A', 'B');
-        graph.mergeEdgeWithKey('2', 'A', 'B');
-        graph.mergeEdgeWithKey('3', 'A', 'B');
-        graph.mergeEdgeWithKey('4', 'A', 'B');
-
-        _assert["default"].strictEqual(graph.size, 4);
-
-        _assert["default"].strictEqual(graph.areNeighbors('A', 'B'), true);
-
-        graph.dropEdge('2');
-        graph.dropEdge('3');
-
-        _assert["default"].strictEqual(graph.size, 2);
-
-        _assert["default"].strictEqual(graph.areNeighbors('A', 'B'), true);
-
-        graph.dropEdge('4');
-        graph.dropEdge('1');
-
-        _assert["default"].strictEqual(graph.size, 0);
-
-        _assert["default"].strictEqual(graph.areNeighbors('A', 'B'), false);
-      }
-    },
-    'Key coercion': {
-      'keys should be correctly coerced to strings.': function keysShouldBeCorrectlyCoercedToStrings() {
-        var graph = new Graph();
-        graph.addNode(1);
-        graph.addNode('2');
-
-        _assert["default"].strictEqual(graph.hasNode(1), true);
-
-        _assert["default"].strictEqual(graph.hasNode('1'), true);
-
-        _assert["default"].strictEqual(graph.hasNode(2), true);
-
-        _assert["default"].strictEqual(graph.hasNode('2'), true);
-
-        graph.addEdgeWithKey(3, 1, 2);
-
-        _assert["default"].strictEqual(graph.hasEdge(3), true);
-
-        _assert["default"].strictEqual(graph.hasEdge('3'), true);
-      }
-    }
-  };
-}
\ No newline at end of file
diff --git a/libs/shared/graph-layouts/node_modules/graphology/specs/mutation.js b/libs/shared/graph-layouts/node_modules/graphology/specs/mutation.js
deleted file mode 100644
index c6a114c1b..000000000
--- a/libs/shared/graph-layouts/node_modules/graphology/specs/mutation.js
+++ /dev/null
@@ -1,883 +0,0 @@
-"use strict";
-
-Object.defineProperty(exports, "__esModule", {
-  value: true
-});
-exports["default"] = mutation;
-
-var _assert = _interopRequireDefault(require("assert"));
-
-var _helpers = require("./helpers");
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
-
-function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
-
-function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
-
-function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
-
-function mutation(Graph, checkers) {
-  var invalid = checkers.invalid,
-      notFound = checkers.notFound,
-      usage = checkers.usage;
-  return {
-    '#.addNode': {
-      'it should throw if given attributes is not an object.': function itShouldThrowIfGivenAttributesIsNotAnObject() {
-        var graph = new Graph();
-
-        _assert["default"]["throws"](function () {
-          graph.addNode('test', true);
-        }, invalid());
-      },
-      'it should throw if the given node already exist.': function itShouldThrowIfTheGivenNodeAlreadyExist() {
-        var graph = new Graph();
-        graph.addNode('Martha');
-
-        _assert["default"]["throws"](function () {
-          graph.addNode('Martha');
-        }, usage());
-      },
-      'it should return the added node.': function itShouldReturnTheAddedNode() {
-        var graph = new Graph();
-
-        _assert["default"].strictEqual(graph.addNode('John'), 'John');
-      }
-    },
-    '#.mergeNode': {
-      'it should add the node if it does not exist yet.': function itShouldAddTheNodeIfItDoesNotExistYet() {
-        var graph = new Graph();
-        graph.mergeNode('John');
-
-        _assert["default"].deepStrictEqual(graph.nodes(), ['John']);
-      },
-      'it should do nothing if the node already exists.': function itShouldDoNothingIfTheNodeAlreadyExists() {
-        var graph = new Graph();
-        graph.addNode('John');
-        graph.mergeNode('John');
-
-        _assert["default"].deepStrictEqual(graph.nodes(), ['John']);
-      },
-      'it should merge the attributes.': function itShouldMergeTheAttributes() {
-        var graph = new Graph();
-        graph.addNode('John', {
-          eyes: 'blue'
-        });
-        graph.mergeNode('John', {
-          age: 15
-        });
-
-        _assert["default"].deepStrictEqual(graph.nodes(), ['John']);
-
-        _assert["default"].deepStrictEqual(graph.getNodeAttributes('John'), {
-          eyes: 'blue',
-          age: 15
-        });
-      },
-      'it should coerce keys to string.': function itShouldCoerceKeysToString() {
-        var graph = new Graph();
-        graph.addNode(4);
-
-        _assert["default"].doesNotThrow(function () {
-          return graph.mergeNode(4);
-        });
-      },
-      'it should return useful information.': function itShouldReturnUsefulInformation() {
-        var graph = new Graph();
-
-        var _graph$mergeNode = graph.mergeNode('Jack'),
-            key = _graph$mergeNode[0],
-            wasAdded = _graph$mergeNode[1];
-
-        _assert["default"].strictEqual(key, 'Jack');
-
-        _assert["default"].strictEqual(wasAdded, true);
-
-        var _graph$mergeNode2 = graph.mergeNode('Jack');
-
-        key = _graph$mergeNode2[0];
-        wasAdded = _graph$mergeNode2[1];
-
-        _assert["default"].strictEqual(key, 'Jack');
-
-        _assert["default"].strictEqual(wasAdded, false);
-      }
-    },
-    '#.updateNode': {
-      'it should add the node if it does not exist yet.': function itShouldAddTheNodeIfItDoesNotExistYet() {
-        var graph = new Graph();
-        graph.updateNode('John');
-
-        _assert["default"].deepStrictEqual(graph.nodes(), ['John']);
-      },
-      'it should do nothing if the node already exists.': function itShouldDoNothingIfTheNodeAlreadyExists() {
-        var graph = new Graph();
-        graph.addNode('John');
-        graph.updateNode('John');
-
-        _assert["default"].deepStrictEqual(graph.nodes(), ['John']);
-      },
-      'it should update the attributes.': function itShouldUpdateTheAttributes() {
-        var graph = new Graph();
-        graph.addNode('John', {
-          eyes: 'blue',
-          count: 1
-        });
-        graph.updateNode('John', function (attr) {
-          return _objectSpread(_objectSpread({}, attr), {}, {
-            count: attr.count + 1
-          });
-        });
-
-        _assert["default"].deepStrictEqual(graph.nodes(), ['John']);
-
-        _assert["default"].deepStrictEqual(graph.getNodeAttributes('John'), {
-          eyes: 'blue',
-          count: 2
-        });
-      },
-      'it should be possible to start from blank attributes.': function itShouldBePossibleToStartFromBlankAttributes() {
-        var graph = new Graph();
-        graph.updateNode('John', function () {
-          return {
-            count: 2
-          };
-        });
-
-        _assert["default"].deepStrictEqual(graph.getNodeAttributes('John'), {
-          count: 2
-        });
-      },
-      'it should coerce keys to string.': function itShouldCoerceKeysToString() {
-        var graph = new Graph();
-        graph.addNode(4);
-
-        _assert["default"].doesNotThrow(function () {
-          return graph.updateNode(4);
-        });
-      },
-      'it should return useful information.': function itShouldReturnUsefulInformation() {
-        var graph = new Graph();
-
-        var _graph$updateNode = graph.updateNode('Jack'),
-            key = _graph$updateNode[0],
-            wasAdded = _graph$updateNode[1];
-
-        _assert["default"].strictEqual(key, 'Jack');
-
-        _assert["default"].strictEqual(wasAdded, true);
-
-        var _graph$updateNode2 = graph.updateNode('Jack');
-
-        key = _graph$updateNode2[0];
-        wasAdded = _graph$updateNode2[1];
-
-        _assert["default"].strictEqual(key, 'Jack');
-
-        _assert["default"].strictEqual(wasAdded, false);
-      }
-    },
-    '#.addDirectedEdge': {
-      'it should throw if given attributes is not an object.': function itShouldThrowIfGivenAttributesIsNotAnObject() {
-        var graph = new Graph();
-
-        _assert["default"]["throws"](function () {
-          graph.addDirectedEdge('source', 'target', true);
-        }, invalid());
-      },
-      'it should throw if the graph is undirected.': function itShouldThrowIfTheGraphIsUndirected() {
-        var graph = new Graph({
-          type: 'undirected'
-        });
-
-        _assert["default"]["throws"](function () {
-          graph.addDirectedEdge('source', 'target');
-        }, usage());
-      },
-      'it should throw if either the source or the target does not exist.': function itShouldThrowIfEitherTheSourceOrTheTargetDoesNotExist() {
-        var graph = new Graph();
-        graph.addNode('Martha');
-
-        _assert["default"]["throws"](function () {
-          graph.addDirectedEdge('Thomas', 'Eric');
-        }, notFound());
-
-        _assert["default"]["throws"](function () {
-          graph.addDirectedEdge('Martha', 'Eric');
-        }, notFound());
-      },
-      'it should throw if the edge is a loop and the graph does not allow it.': function itShouldThrowIfTheEdgeIsALoopAndTheGraphDoesNotAllowIt() {
-        var graph = new Graph({
-          allowSelfLoops: false
-        });
-        graph.addNode('Thomas');
-
-        _assert["default"]["throws"](function () {
-          graph.addDirectedEdge('Thomas', 'Thomas');
-        }, usage());
-      },
-      'it should be possible to add self loops.': function itShouldBePossibleToAddSelfLoops() {
-        var graph = new Graph();
-        graph.addNode('Thomas');
-        var loop = graph.addDirectedEdge('Thomas', 'Thomas');
-
-        _assert["default"].deepStrictEqual(graph.extremities(loop), ['Thomas', 'Thomas']);
-      },
-      'it should throw if the graph is not multi & we try to add twice the same edge.': function itShouldThrowIfTheGraphIsNotMultiWeTryToAddTwiceTheSameEdge() {
-        var graph = new Graph();
-        graph.addNode('Thomas');
-        graph.addNode('Martha');
-        graph.addDirectedEdge('Thomas', 'Martha');
-
-        _assert["default"]["throws"](function () {
-          graph.addDirectedEdge('Thomas', 'Martha');
-        }, usage());
-
-        _assert["default"]["throws"](function () {
-          graph.addDirectedEdgeWithKey('T->M', 'Thomas', 'Martha');
-        }, usage());
-      },
-      "it should return the generated edge's key.": function itShouldReturnTheGeneratedEdgeSKey() {
-        var graph = new Graph();
-        graph.addNode('Thomas');
-        graph.addNode('Martha');
-        var edge = graph.addDirectedEdge('Thomas', 'Martha');
-        (0, _assert["default"])(typeof edge === 'string' || typeof edge === 'number');
-        (0, _assert["default"])(!(edge instanceof Graph));
-      }
-    },
-    '#.addEdge': {
-      'it should add a directed edge if the graph is directed or mixed.': function itShouldAddADirectedEdgeIfTheGraphIsDirectedOrMixed() {
-        var graph = new Graph(),
-            directedGraph = new Graph({
-          type: 'directed'
-        });
-        graph.addNode('John');
-        graph.addNode('Martha');
-        var mixedEdge = graph.addEdge('John', 'Martha');
-        directedGraph.addNode('John');
-        directedGraph.addNode('Martha');
-        var directedEdge = directedGraph.addEdge('John', 'Martha');
-        (0, _assert["default"])(graph.isDirected(mixedEdge));
-        (0, _assert["default"])(directedGraph.isDirected(directedEdge));
-      },
-      'it should add an undirected edge if the graph is undirected.': function itShouldAddAnUndirectedEdgeIfTheGraphIsUndirected() {
-        var graph = new Graph({
-          type: 'undirected'
-        });
-        graph.addNode('John');
-        graph.addNode('Martha');
-        var edge = graph.addEdge('John', 'Martha');
-        (0, _assert["default"])(graph.isUndirected(edge));
-      }
-    },
-    '#.addDirectedEdgeWithKey': {
-      'it should throw if an edge with the same key already exists.': function itShouldThrowIfAnEdgeWithTheSameKeyAlreadyExists() {
-        var graph = new Graph();
-        graph.addNode('Thomas');
-        graph.addNode('Martha');
-        graph.addDirectedEdgeWithKey('T->M', 'Thomas', 'Martha');
-
-        _assert["default"]["throws"](function () {
-          graph.addDirectedEdgeWithKey('T->M', 'Thomas', 'Martha');
-        }, usage());
-
-        _assert["default"]["throws"](function () {
-          graph.addUndirectedEdgeWithKey('T->M', 'Thomas', 'Martha');
-        }, usage());
-      }
-    },
-    '#.addUndirectedEdgeWithKey': {
-      'it should throw if an edge with the same key already exists.': function itShouldThrowIfAnEdgeWithTheSameKeyAlreadyExists() {
-        var graph = new Graph();
-        graph.addNode('Thomas');
-        graph.addNode('Martha');
-        graph.addUndirectedEdgeWithKey('T<->M', 'Thomas', 'Martha');
-
-        _assert["default"]["throws"](function () {
-          graph.addUndirectedEdgeWithKey('T<->M', 'Thomas', 'Martha');
-        }, usage());
-
-        _assert["default"]["throws"](function () {
-          graph.addDirectedEdgeWithKey('T<->M', 'Thomas', 'Martha');
-        }, usage());
-      }
-    },
-    '#.addEdgeWithKey': {
-      'it should add a directed edge if the graph is directed or mixed.': function itShouldAddADirectedEdgeIfTheGraphIsDirectedOrMixed() {
-        var graph = new Graph(),
-            directedGraph = new Graph({
-          type: 'directed'
-        });
-        graph.addNode('John');
-        graph.addNode('Martha');
-        var mixedEdge = graph.addEdgeWithKey('J->M', 'John', 'Martha');
-        directedGraph.addNode('John');
-        directedGraph.addNode('Martha');
-        var directedEdge = directedGraph.addEdgeWithKey('J->M', 'John', 'Martha');
-        (0, _assert["default"])(graph.isDirected(mixedEdge));
-        (0, _assert["default"])(directedGraph.isDirected(directedEdge));
-      },
-      'it should add an undirected edge if the graph is undirected.': function itShouldAddAnUndirectedEdgeIfTheGraphIsUndirected() {
-        var graph = new Graph({
-          type: 'undirected'
-        });
-        graph.addNode('John');
-        graph.addNode('Martha');
-        var edge = graph.addEdgeWithKey('J<->M', 'John', 'Martha');
-        (0, _assert["default"])(graph.isUndirected(edge));
-      }
-    },
-    '#.mergeEdge': {
-      'it should add the edge if it does not yet exist.': function itShouldAddTheEdgeIfItDoesNotYetExist() {
-        var graph = new Graph();
-        (0, _helpers.addNodesFrom)(graph, ['John', 'Martha']);
-        graph.mergeEdge('John', 'Martha');
-
-        _assert["default"].strictEqual(graph.size, 1);
-
-        _assert["default"].strictEqual(graph.hasEdge('John', 'Martha'), true);
-      },
-      'it should do nothing if the edge already exists.': function itShouldDoNothingIfTheEdgeAlreadyExists() {
-        var graph = new Graph();
-        (0, _helpers.addNodesFrom)(graph, ['John', 'Martha']);
-        graph.addEdge('John', 'Martha');
-        graph.mergeEdge('John', 'Martha');
-
-        _assert["default"].strictEqual(graph.size, 1);
-
-        _assert["default"].strictEqual(graph.hasEdge('John', 'Martha'), true);
-      },
-      'it should merge existing attributes if any.': function itShouldMergeExistingAttributesIfAny() {
-        var graph = new Graph();
-        (0, _helpers.addNodesFrom)(graph, ['John', 'Martha']);
-        graph.addEdge('John', 'Martha', {
-          type: 'KNOWS'
-        });
-        graph.mergeEdge('John', 'Martha', {
-          weight: 2
-        });
-
-        _assert["default"].strictEqual(graph.size, 1);
-
-        _assert["default"].strictEqual(graph.hasEdge('John', 'Martha'), true);
-
-        _assert["default"].deepStrictEqual(graph.getEdgeAttributes('John', 'Martha'), {
-          type: 'KNOWS',
-          weight: 2
-        });
-      },
-      'it should add missing nodes in the path.': function itShouldAddMissingNodesInThePath() {
-        var graph = new Graph();
-        graph.mergeEdge('John', 'Martha');
-
-        _assert["default"].strictEqual(graph.order, 2);
-
-        _assert["default"].strictEqual(graph.size, 1);
-
-        _assert["default"].deepStrictEqual(graph.nodes(), ['John', 'Martha']);
-      },
-      'it should throw in case of inconsistencies.': function itShouldThrowInCaseOfInconsistencies() {
-        var graph = new Graph();
-        graph.mergeEdgeWithKey('J->M', 'John', 'Martha');
-
-        _assert["default"]["throws"](function () {
-          graph.mergeEdgeWithKey('J->M', 'John', 'Thomas');
-        }, usage());
-      },
-      'it should be able to merge undirected edges in both directions.': function itShouldBeAbleToMergeUndirectedEdgesInBothDirections() {
-        _assert["default"].doesNotThrow(function () {
-          var graph = new Graph();
-          graph.mergeUndirectedEdgeWithKey('J<->M', 'John', 'Martha');
-          graph.mergeUndirectedEdgeWithKey('J<->M', 'John', 'Martha');
-          graph.mergeUndirectedEdgeWithKey('J<->M', 'Martha', 'John');
-        }, usage());
-      },
-      'it should distinguish between typed edges.': function itShouldDistinguishBetweenTypedEdges() {
-        var graph = new Graph();
-        graph.mergeEdge('John', 'Martha', {
-          type: 'LIKES'
-        });
-        graph.mergeUndirectedEdge('John', 'Martha', {
-          weight: 34
-        });
-
-        _assert["default"].strictEqual(graph.size, 2);
-      },
-      'it should be possible to merge a self loop.': function itShouldBePossibleToMergeASelfLoop() {
-        var graph = new Graph();
-        graph.mergeEdge('John', 'John', {
-          type: 'IS'
-        });
-
-        _assert["default"].strictEqual(graph.order, 1);
-
-        _assert["default"].strictEqual(graph.size, 1);
-      },
-      'it should return useful information.': function itShouldReturnUsefulInformation() {
-        var graph = new Graph();
-        var info = graph.mergeEdge('John', 'Jack');
-
-        _assert["default"].deepStrictEqual(info, [graph.edge('John', 'Jack'), true, true, true]);
-
-        info = graph.mergeEdge('John', 'Jack');
-
-        _assert["default"].deepStrictEqual(info, [graph.edge('John', 'Jack'), false, false, false]);
-
-        graph.addNode('Mary');
-        info = graph.mergeEdge('Mary', 'Sue');
-
-        _assert["default"].deepStrictEqual(info, [graph.edge('Mary', 'Sue'), true, false, true]);
-
-        info = graph.mergeEdge('Gwladys', 'Mary');
-
-        _assert["default"].deepStrictEqual(info, [graph.edge('Gwladys', 'Mary'), true, true, false]);
-
-        graph.addNode('Quintin');
-        info = graph.mergeEdge('Quintin', 'Mary');
-
-        _assert["default"].deepStrictEqual(info, [graph.edge('Quintin', 'Mary'), true, false, false]);
-      }
-    },
-    '#.updateEdge': {
-      'it should add the edge if it does not yet exist.': function itShouldAddTheEdgeIfItDoesNotYetExist() {
-        var graph = new Graph();
-        (0, _helpers.addNodesFrom)(graph, ['John', 'Martha']);
-        graph.updateEdge('John', 'Martha');
-
-        _assert["default"].strictEqual(graph.size, 1);
-
-        _assert["default"].strictEqual(graph.hasEdge('John', 'Martha'), true);
-      },
-      'it should do nothing if the edge already exists.': function itShouldDoNothingIfTheEdgeAlreadyExists() {
-        var graph = new Graph();
-        (0, _helpers.addNodesFrom)(graph, ['John', 'Martha']);
-        graph.addEdge('John', 'Martha');
-        graph.updateEdge('John', 'Martha');
-
-        _assert["default"].strictEqual(graph.size, 1);
-
-        _assert["default"].strictEqual(graph.hasEdge('John', 'Martha'), true);
-      },
-      'it should be possible to start from blank attributes.': function itShouldBePossibleToStartFromBlankAttributes() {
-        var graph = new Graph();
-        (0, _helpers.addNodesFrom)(graph, ['John', 'Martha']);
-        graph.updateEdge('John', 'Martha', function (attr) {
-          return _objectSpread(_objectSpread({}, attr), {}, {
-            weight: 3
-          });
-        });
-
-        _assert["default"].strictEqual(graph.size, 1);
-
-        _assert["default"].strictEqual(graph.hasEdge('John', 'Martha'), true);
-
-        _assert["default"].deepStrictEqual(graph.getEdgeAttributes('John', 'Martha'), {
-          weight: 3
-        });
-      },
-      'it should update existing attributes if any.': function itShouldUpdateExistingAttributesIfAny() {
-        var graph = new Graph();
-        (0, _helpers.addNodesFrom)(graph, ['John', 'Martha']);
-        graph.addEdge('John', 'Martha', {
-          type: 'KNOWS'
-        });
-        graph.updateEdge('John', 'Martha', function (attr) {
-          return _objectSpread(_objectSpread({}, attr), {}, {
-            weight: 2
-          });
-        });
-
-        _assert["default"].strictEqual(graph.size, 1);
-
-        _assert["default"].strictEqual(graph.hasEdge('John', 'Martha'), true);
-
-        _assert["default"].deepStrictEqual(graph.getEdgeAttributes('John', 'Martha'), {
-          type: 'KNOWS',
-          weight: 2
-        });
-      },
-      'it should add missing nodes in the path.': function itShouldAddMissingNodesInThePath() {
-        var graph = new Graph();
-        graph.updateEdge('John', 'Martha');
-
-        _assert["default"].strictEqual(graph.order, 2);
-
-        _assert["default"].strictEqual(graph.size, 1);
-
-        _assert["default"].deepStrictEqual(graph.nodes(), ['John', 'Martha']);
-      },
-      'it should throw in case of inconsistencies.': function itShouldThrowInCaseOfInconsistencies() {
-        var graph = new Graph();
-        graph.updateEdgeWithKey('J->M', 'John', 'Martha');
-
-        _assert["default"]["throws"](function () {
-          graph.updateEdgeWithKey('J->M', 'John', 'Thomas');
-        }, usage());
-      },
-      'it should distinguish between typed edges.': function itShouldDistinguishBetweenTypedEdges() {
-        var graph = new Graph();
-        graph.updateEdge('John', 'Martha', function () {
-          return {
-            type: 'LIKES'
-          };
-        });
-        graph.updateUndirectedEdge('John', 'Martha', function () {
-          return {
-            weight: 34
-          };
-        });
-
-        _assert["default"].strictEqual(graph.size, 2);
-      },
-      'it should be possible to merge a self loop.': function itShouldBePossibleToMergeASelfLoop() {
-        var graph = new Graph();
-        graph.updateEdge('John', 'John', function () {
-          return {
-            type: 'IS'
-          };
-        });
-
-        _assert["default"].strictEqual(graph.order, 1);
-
-        _assert["default"].strictEqual(graph.size, 1);
-      },
-      'it should return useful information.': function itShouldReturnUsefulInformation() {
-        var graph = new Graph();
-        var info = graph.updateEdge('John', 'Jack');
-
-        _assert["default"].deepStrictEqual(info, [graph.edge('John', 'Jack'), true, true, true]);
-
-        info = graph.updateEdge('John', 'Jack');
-
-        _assert["default"].deepStrictEqual(info, [graph.edge('John', 'Jack'), false, false, false]);
-
-        graph.addNode('Mary');
-        info = graph.updateEdge('Mary', 'Sue');
-
-        _assert["default"].deepStrictEqual(info, [graph.edge('Mary', 'Sue'), true, false, true]);
-
-        info = graph.updateEdge('Gwladys', 'Mary');
-
-        _assert["default"].deepStrictEqual(info, [graph.edge('Gwladys', 'Mary'), true, true, false]);
-
-        graph.addNode('Quintin');
-        info = graph.updateEdge('Quintin', 'Mary');
-
-        _assert["default"].deepStrictEqual(info, [graph.edge('Quintin', 'Mary'), true, false, false]);
-      }
-    },
-    '#.dropEdge': {
-      'it should throw if the edge or nodes in the path are not found in the graph.': function itShouldThrowIfTheEdgeOrNodesInThePathAreNotFoundInTheGraph() {
-        var graph = new Graph();
-        (0, _helpers.addNodesFrom)(graph, ['John', 'Martha']);
-
-        _assert["default"]["throws"](function () {
-          graph.dropEdge('Test');
-        }, notFound());
-
-        _assert["default"]["throws"](function () {
-          graph.dropEdge('Forever', 'Alone');
-        }, notFound());
-
-        _assert["default"]["throws"](function () {
-          graph.dropEdge('John', 'Test');
-        }, notFound());
-
-        _assert["default"]["throws"](function () {
-          graph.dropEdge('John', 'Martha');
-        }, notFound());
-      },
-      'it should correctly remove the given edge from the graph.': function itShouldCorrectlyRemoveTheGivenEdgeFromTheGraph() {
-        var graph = new Graph();
-        (0, _helpers.addNodesFrom)(graph, ['John', 'Margaret']);
-        var edge = graph.addEdge('John', 'Margaret');
-        graph.dropEdge(edge);
-
-        _assert["default"].strictEqual(graph.order, 2);
-
-        _assert["default"].strictEqual(graph.size, 0);
-
-        _assert["default"].strictEqual(graph.degree('John'), 0);
-
-        _assert["default"].strictEqual(graph.degree('Margaret'), 0);
-
-        _assert["default"].strictEqual(graph.hasEdge(edge), false);
-
-        _assert["default"].strictEqual(graph.hasDirectedEdge('John', 'Margaret'), false);
-      },
-      'it should be possible to remove an edge using source & target.': function itShouldBePossibleToRemoveAnEdgeUsingSourceTarget() {
-        var graph = new Graph();
-        (0, _helpers.addNodesFrom)(graph, ['John', 'Margaret']);
-        graph.addEdge('John', 'Margaret');
-        graph.dropEdge('John', 'Margaret');
-
-        _assert["default"].strictEqual(graph.order, 2);
-
-        _assert["default"].strictEqual(graph.size, 0);
-
-        _assert["default"].strictEqual(graph.degree('John'), 0);
-
-        _assert["default"].strictEqual(graph.degree('Margaret'), 0);
-
-        _assert["default"].strictEqual(graph.hasEdge('John', 'Margaret'), false);
-
-        _assert["default"].strictEqual(graph.hasDirectedEdge('John', 'Margaret'), false);
-      },
-      'it should work with self loops.': function itShouldWorkWithSelfLoops() {
-        var graph = new Graph();
-        graph.mergeEdge('John', 'John');
-        graph.dropEdge('John', 'John');
-
-        _assert["default"].deepStrictEqual(graph.edges(), []);
-
-        _assert["default"].deepStrictEqual(graph.edges('John'), []);
-
-        _assert["default"].strictEqual(graph.size, 0);
-
-        var multiGraph = new Graph({
-          multi: true
-        });
-        multiGraph.mergeEdgeWithKey('j', 'John', 'John');
-        multiGraph.mergeEdgeWithKey('k', 'John', 'John');
-        multiGraph.dropEdge('j');
-
-        _assert["default"].deepStrictEqual(multiGraph.edges(), ['k']);
-
-        _assert["default"].deepStrictEqual(multiGraph.edges('John'), ['k']);
-
-        _assert["default"].strictEqual(multiGraph.size, 1);
-      }
-    },
-    '#.dropNode': {
-      'it should throw if the edge is not found in the graph.': function itShouldThrowIfTheEdgeIsNotFoundInTheGraph() {
-        var graph = new Graph();
-
-        _assert["default"]["throws"](function () {
-          graph.dropNode('Test');
-        }, notFound());
-      },
-      'it should correctly remove the given node from the graph.': function itShouldCorrectlyRemoveTheGivenNodeFromTheGraph() {
-        var graph = new Graph();
-        (0, _helpers.addNodesFrom)(graph, ['John', 'Margaret']);
-        var edge = graph.addEdge('John', 'Margaret');
-        graph.mergeEdge('Jack', 'Trudy');
-        graph.dropNode('Margaret');
-
-        _assert["default"].strictEqual(graph.order, 3);
-
-        _assert["default"].strictEqual(graph.size, 1);
-
-        _assert["default"].strictEqual(graph.hasNode('Margaret'), false);
-
-        _assert["default"].strictEqual(graph.hasEdge(edge), false);
-
-        _assert["default"].strictEqual(graph.degree('John'), 0);
-
-        _assert["default"].strictEqual(graph.hasDirectedEdge('John', 'Margaret'), false);
-      },
-      'it should also work with mixed, multi graphs and self loops.': function itShouldAlsoWorkWithMixedMultiGraphsAndSelfLoops() {
-        var graph = new Graph({
-          multi: true
-        });
-        graph.mergeEdge('A', 'B');
-        graph.mergeEdge('A', 'B');
-        graph.mergeEdge('B', 'A');
-        graph.mergeEdge('A', 'B');
-        graph.mergeEdge('A', 'A');
-        graph.mergeUndirectedEdge('A', 'B');
-        graph.mergeUndirectedEdge('A', 'B');
-        graph.mergeUndirectedEdge('A', 'A');
-        var copy = graph.copy();
-        graph.dropNode('B');
-
-        _assert["default"].strictEqual(graph.size, 2);
-
-        _assert["default"].strictEqual(graph.directedSelfLoopCount, 1);
-
-        _assert["default"].strictEqual(graph.undirectedSelfLoopCount, 1);
-
-        copy.dropNode('A');
-
-        _assert["default"].strictEqual(copy.size, 0);
-
-        _assert["default"].strictEqual(copy.directedSelfLoopCount, 0);
-
-        _assert["default"].strictEqual(copy.undirectedSelfLoopCount, 0);
-      },
-      'it should also coerce keys as strings.': function itShouldAlsoCoerceKeysAsStrings() {
-        function Key(name) {
-          this.name = name;
-        }
-
-        Key.prototype.toString = function () {
-          return this.name;
-        };
-
-        var graph = new Graph();
-        var key = new Key('test');
-        graph.addNode(key);
-        graph.dropNode(key);
-
-        _assert["default"].strictEqual(graph.order, 0);
-
-        _assert["default"].strictEqual(graph.hasNode(key), false);
-      }
-    },
-    '#.dropDirectedEdge': {
-      'it should throw if given incorrect arguments.': function itShouldThrowIfGivenIncorrectArguments() {
-        _assert["default"]["throws"](function () {
-          var graph = new Graph({
-            multi: true
-          });
-          graph.mergeEdge('a', 'b');
-          graph.dropDirectedEdge('a', 'b');
-        }, usage());
-
-        _assert["default"]["throws"](function () {
-          var graph = new Graph({
-            multi: true
-          });
-          graph.mergeEdgeWithKey('1', 'a', 'b');
-          graph.dropDirectedEdge('1');
-        }, usage());
-
-        _assert["default"]["throws"](function () {
-          var graph = new Graph();
-          graph.dropDirectedEdge('a', 'b');
-        }, notFound());
-      },
-      'it should correctly drop the relevant edge.': function itShouldCorrectlyDropTheRelevantEdge() {
-        var graph = new Graph();
-        graph.mergeUndirectedEdge('a', 'b');
-        graph.mergeDirectedEdge('a', 'b');
-        graph.dropDirectedEdge('a', 'b');
-
-        _assert["default"].strictEqual(graph.directedSize, 0);
-
-        _assert["default"].strictEqual(graph.hasDirectedEdge('a', 'b'), false);
-
-        _assert["default"].strictEqual(graph.hasUndirectedEdge('a', 'b'), true);
-      }
-    },
-    '#.dropUndirectedEdge': {
-      'it should throw if given incorrect arguments.': function itShouldThrowIfGivenIncorrectArguments() {
-        _assert["default"]["throws"](function () {
-          var graph = new Graph({
-            multi: true,
-            type: 'undirected'
-          });
-          graph.mergeEdge('a', 'b');
-          graph.dropUndirectedEdge('a', 'b');
-        }, usage());
-
-        _assert["default"]["throws"](function () {
-          var graph = new Graph({
-            multi: true,
-            type: 'undirected'
-          });
-          graph.mergeEdgeWithKey('1', 'a', 'b');
-          graph.dropUndirectedEdge('1');
-        }, usage());
-
-        _assert["default"]["throws"](function () {
-          var graph = new Graph({
-            type: 'undirected'
-          });
-          graph.dropUndirectedEdge('a', 'b');
-        }, notFound());
-      },
-      'it should correctly drop the relevant edge.': function itShouldCorrectlyDropTheRelevantEdge() {
-        var graph = new Graph();
-        graph.mergeUndirectedEdge('a', 'b');
-        graph.mergeDirectedEdge('a', 'b');
-        graph.dropUndirectedEdge('a', 'b');
-
-        _assert["default"].strictEqual(graph.undirectedSize, 0);
-
-        _assert["default"].strictEqual(graph.hasUndirectedEdge('a', 'b'), false);
-
-        _assert["default"].strictEqual(graph.hasDirectedEdge('a', 'b'), true);
-      }
-    },
-    '#.clear': {
-      'it should empty the graph.': function itShouldEmptyTheGraph() {
-        var graph = new Graph();
-        (0, _helpers.addNodesFrom)(graph, ['Lindsay', 'Martha']);
-        var edge = graph.addEdge('Lindsay', 'Martha');
-        graph.clear();
-
-        _assert["default"].strictEqual(graph.order, 0);
-
-        _assert["default"].strictEqual(graph.size, 0);
-
-        _assert["default"].strictEqual(graph.hasNode('Lindsay'), false);
-
-        _assert["default"].strictEqual(graph.hasNode('Martha'), false);
-
-        _assert["default"].strictEqual(graph.hasEdge(edge), false);
-      },
-      'it should be possible to use the graph normally afterwards.': function itShouldBePossibleToUseTheGraphNormallyAfterwards() {
-        var graph = new Graph();
-        (0, _helpers.addNodesFrom)(graph, ['Lindsay', 'Martha']);
-        graph.addEdge('Lindsay', 'Martha');
-        graph.clear();
-        (0, _helpers.addNodesFrom)(graph, ['Lindsay', 'Martha']);
-        var edge = graph.addEdge('Lindsay', 'Martha');
-
-        _assert["default"].strictEqual(graph.order, 2);
-
-        _assert["default"].strictEqual(graph.size, 1);
-
-        _assert["default"].strictEqual(graph.hasNode('Lindsay'), true);
-
-        _assert["default"].strictEqual(graph.hasNode('Martha'), true);
-
-        _assert["default"].strictEqual(graph.hasEdge(edge), true);
-      }
-    },
-    '#.clearEdges': {
-      'it should drop every edge from the graph.': function itShouldDropEveryEdgeFromTheGraph() {
-        var graph = new Graph();
-        (0, _helpers.addNodesFrom)(graph, ['Lindsay', 'Martha']);
-        var edge = graph.addEdge('Lindsay', 'Martha');
-        graph.clearEdges();
-
-        _assert["default"].strictEqual(graph.order, 2);
-
-        _assert["default"].strictEqual(graph.size, 0);
-
-        _assert["default"].strictEqual(graph.hasNode('Lindsay'), true);
-
-        _assert["default"].strictEqual(graph.hasNode('Martha'), true);
-
-        _assert["default"].strictEqual(graph.hasEdge(edge), false);
-      },
-      'it should properly reset instance counters.': function itShouldProperlyResetInstanceCounters() {
-        var graph = new Graph();
-        graph.mergeEdge(0, 1);
-
-        _assert["default"].strictEqual(graph.directedSize, 1);
-
-        graph.clearEdges();
-
-        _assert["default"].strictEqual(graph.directedSize, 0);
-
-        graph.mergeEdge(0, 1);
-        graph.clear();
-
-        _assert["default"].strictEqual(graph.directedSize, 0);
-      },
-      'it should properly clear node indices, regarding self loops notably.': function itShouldProperlyClearNodeIndicesRegardingSelfLoopsNotably() {
-        var graph = new Graph();
-        graph.mergeEdge(1, 1);
-
-        _assert["default"].strictEqual(graph.degree(1), 2);
-
-        graph.clearEdges();
-
-        _assert["default"].strictEqual(graph.degree(1), 0);
-      }
-    }
-  };
-}
\ No newline at end of file
diff --git a/libs/shared/graph-layouts/node_modules/graphology/specs/properties.js b/libs/shared/graph-layouts/node_modules/graphology/specs/properties.js
deleted file mode 100644
index 4babe3dc5..000000000
--- a/libs/shared/graph-layouts/node_modules/graphology/specs/properties.js
+++ /dev/null
@@ -1,214 +0,0 @@
-"use strict";
-
-Object.defineProperty(exports, "__esModule", {
-  value: true
-});
-exports["default"] = properties;
-
-var _assert = _interopRequireDefault(require("assert"));
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
-
-function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); }
-
-var PROPERTIES = ['order', 'size', 'directedSize', 'undirectedSize', 'type', 'multi', 'allowSelfLoops', 'implementation', 'selfLoopCount', 'directedSelfLoopCount', 'undirectedSelfLoopCount'];
-
-function properties(Graph) {
-  return {
-    /**
-     * Regarding all properties.
-     */
-    misc: {
-      'all expected properties should be set.': function allExpectedPropertiesShouldBeSet() {
-        var graph = new Graph();
-        PROPERTIES.forEach(function (property) {
-          (0, _assert["default"])(property in graph, property);
-        });
-      },
-      'properties should be read-only.': function propertiesShouldBeReadOnly() {
-        var graph = new Graph(); // Attempting to mutate the properties
-
-        PROPERTIES.forEach(function (property) {
-          _assert["default"]["throws"](function () {
-            graph[property] = 'test';
-          }, TypeError);
-        });
-      }
-    },
-
-    /**
-     * Order.
-     */
-    '#.order': {
-      'it should be 0 if the graph is empty.': function itShouldBe0IfTheGraphIsEmpty() {
-        var graph = new Graph();
-
-        _assert["default"].strictEqual(graph.order, 0);
-      },
-      'adding nodes should increase order.': function addingNodesShouldIncreaseOrder() {
-        var graph = new Graph();
-        graph.addNode('John');
-        graph.addNode('Jack');
-
-        _assert["default"].strictEqual(graph.order, 2);
-      }
-    },
-
-    /**
-     * Size.
-     */
-    '#.size': {
-      'it should be 0 if the graph is empty.': function itShouldBe0IfTheGraphIsEmpty() {
-        var graph = new Graph();
-
-        _assert["default"].strictEqual(graph.size, 0);
-      },
-      'adding & dropping edges should affect size.': function addingDroppingEdgesShouldAffectSize() {
-        var graph = new Graph();
-        graph.addNode('John');
-        graph.addNode('Jack');
-        graph.addDirectedEdge('John', 'Jack');
-
-        _assert["default"].strictEqual(graph.size, 1);
-
-        graph.dropEdge('John', 'Jack');
-
-        _assert["default"].strictEqual(graph.size, 0);
-      }
-    },
-
-    /**
-     * Directed Size.
-     */
-    '#.directedSize': {
-      'it should be 0 if the graph is empty.': function itShouldBe0IfTheGraphIsEmpty() {
-        var graph = new Graph();
-
-        _assert["default"].strictEqual(graph.directedSize, 0);
-      },
-      'adding & dropping edges should affect directed size.': function addingDroppingEdgesShouldAffectDirectedSize() {
-        var graph = new Graph();
-        graph.addNode('John');
-        graph.addNode('Jack');
-        var directedEdge = graph.addDirectedEdge('John', 'Jack');
-
-        _assert["default"].strictEqual(graph.directedSize, 1);
-
-        var undirectedEdge = graph.addUndirectedEdge('John', 'Jack');
-
-        _assert["default"].strictEqual(graph.directedSize, 1);
-
-        graph.dropEdge(directedEdge);
-
-        _assert["default"].strictEqual(graph.directedSize, 0);
-
-        graph.dropEdge(undirectedEdge);
-
-        _assert["default"].strictEqual(graph.directedSize, 0);
-      }
-    },
-
-    /**
-     * Undirected Size.
-     */
-    '#.undirectedSize': {
-      'it should be 0 if the graph is empty.': function itShouldBe0IfTheGraphIsEmpty() {
-        var graph = new Graph();
-
-        _assert["default"].strictEqual(graph.undirectedSize, 0);
-      },
-      'adding & dropping edges should affect undirected size.': function addingDroppingEdgesShouldAffectUndirectedSize() {
-        var graph = new Graph();
-        graph.addNode('John');
-        graph.addNode('Jack');
-        var directedEdge = graph.addDirectedEdge('John', 'Jack');
-
-        _assert["default"].strictEqual(graph.undirectedSize, 0);
-
-        var undirectedEdge = graph.addUndirectedEdge('John', 'Jack');
-
-        _assert["default"].strictEqual(graph.undirectedSize, 1);
-
-        graph.dropEdge(directedEdge);
-
-        _assert["default"].strictEqual(graph.undirectedSize, 1);
-
-        graph.dropEdge(undirectedEdge);
-
-        _assert["default"].strictEqual(graph.undirectedSize, 0);
-      }
-    },
-
-    /**
-     * Multi.
-     */
-    '#.multi': {
-      'it should be false by default.': function itShouldBeFalseByDefault() {
-        var graph = new Graph();
-
-        _assert["default"].strictEqual(graph.multi, false);
-      }
-    },
-
-    /**
-     * Type.
-     */
-    '#.type': {
-      'it should be "mixed" by default.': function itShouldBeMixedByDefault() {
-        var graph = new Graph();
-
-        _assert["default"].strictEqual(graph.type, 'mixed');
-      }
-    },
-
-    /**
-     * Self loops.
-     */
-    '#.allowSelfLoops': {
-      'it should be true by default.': function itShouldBeTrueByDefault() {
-        var graph = new Graph();
-
-        _assert["default"].strictEqual(graph.allowSelfLoops, true);
-      }
-    },
-
-    /**
-     * Implementation.
-     */
-    '#.implementation': {
-      'it should exist and be a string.': function itShouldExistAndBeAString() {
-        var graph = new Graph();
-
-        _assert["default"].strictEqual(_typeof(graph.implementation), 'string');
-      }
-    },
-
-    /**
-     * Self Loop Count.
-     */
-    '#.selfLoopCount': {
-      'it should exist and be correct.': function itShouldExistAndBeCorrect() {
-        var graph = new Graph();
-        graph.mergeDirectedEdge('John', 'John');
-        graph.mergeDirectedEdge('Lucy', 'Lucy');
-        graph.mergeUndirectedEdge('Joana', 'Joana');
-
-        _assert["default"].strictEqual(graph.selfLoopCount, 3);
-
-        _assert["default"].strictEqual(graph.directedSelfLoopCount, 2);
-
-        _assert["default"].strictEqual(graph.undirectedSelfLoopCount, 1);
-
-        graph.forEachEdge(function (edge) {
-          return graph.dropEdge(edge);
-        });
-
-        _assert["default"].strictEqual(graph.selfLoopCount, 0);
-
-        _assert["default"].strictEqual(graph.directedSelfLoopCount, 0);
-
-        _assert["default"].strictEqual(graph.undirectedSelfLoopCount, 0);
-      }
-    }
-  };
-}
\ No newline at end of file
diff --git a/libs/shared/graph-layouts/node_modules/graphology/specs/read.js b/libs/shared/graph-layouts/node_modules/graphology/specs/read.js
deleted file mode 100644
index afe9f1c66..000000000
--- a/libs/shared/graph-layouts/node_modules/graphology/specs/read.js
+++ /dev/null
@@ -1,909 +0,0 @@
-"use strict";
-
-Object.defineProperty(exports, "__esModule", {
-  value: true
-});
-exports["default"] = read;
-
-var _assert = _interopRequireDefault(require("assert"));
-
-var _helpers = require("./helpers");
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
-
-/**
- * Graphology Read Specs
- * ======================
- *
- * Testing the read methods of the graph.
- */
-function read(Graph, checkers) {
-  var invalid = checkers.invalid,
-      notFound = checkers.notFound,
-      usage = checkers.usage;
-  return {
-    '#.hasNode': {
-      'it should correctly return whether the given node is found in the graph.': function itShouldCorrectlyReturnWhetherTheGivenNodeIsFoundInTheGraph() {
-        var graph = new Graph();
-
-        _assert["default"].strictEqual(graph.hasNode('John'), false);
-
-        graph.addNode('John');
-
-        _assert["default"].strictEqual(graph.hasNode('John'), true);
-      }
-    },
-    '#.hasDirectedEdge': {
-      'it should throw if invalid arguments are provided.': function itShouldThrowIfInvalidArgumentsAreProvided() {
-        var graph = new Graph();
-
-        _assert["default"]["throws"](function () {
-          graph.hasDirectedEdge(1, 2, 3);
-        }, invalid());
-      },
-      'it should correctly return whether a matching edge exists in the graph.': function itShouldCorrectlyReturnWhetherAMatchingEdgeExistsInTheGraph() {
-        var graph = new Graph();
-        graph.addNode('Martha');
-        graph.addNode('Catherine');
-        graph.addNode('John');
-        graph.addDirectedEdgeWithKey('M->C', 'Martha', 'Catherine');
-        graph.addUndirectedEdgeWithKey('C<->J', 'Catherine', 'John');
-
-        _assert["default"].strictEqual(graph.hasDirectedEdge('M->C'), true);
-
-        _assert["default"].strictEqual(graph.hasDirectedEdge('C<->J'), false);
-
-        _assert["default"].strictEqual(graph.hasDirectedEdge('test'), false);
-
-        _assert["default"].strictEqual(graph.hasDirectedEdge('Martha', 'Catherine'), true);
-
-        _assert["default"].strictEqual(graph.hasDirectedEdge('Martha', 'Thomas'), false);
-
-        _assert["default"].strictEqual(graph.hasDirectedEdge('Catherine', 'John'), false);
-
-        _assert["default"].strictEqual(graph.hasDirectedEdge('John', 'Catherine'), false);
-      },
-      'it should work with self loops.': function itShouldWorkWithSelfLoops() {
-        var graph = new Graph();
-        graph.mergeDirectedEdge('Lucy', 'Lucy');
-
-        _assert["default"].strictEqual(graph.hasDirectedEdge('Lucy', 'Lucy'), true);
-
-        _assert["default"].strictEqual(graph.hasUndirectedEdge('Lucy', 'Lucy'), false);
-      }
-    },
-    '#.hasUndirectedEdge': {
-      'it should throw if invalid arguments are provided.': function itShouldThrowIfInvalidArgumentsAreProvided() {
-        var graph = new Graph();
-
-        _assert["default"]["throws"](function () {
-          graph.hasUndirectedEdge(1, 2, 3);
-        }, invalid());
-      },
-      'it should correctly return whether a matching edge exists in the graph.': function itShouldCorrectlyReturnWhetherAMatchingEdgeExistsInTheGraph() {
-        var graph = new Graph();
-        graph.addNode('Martha');
-        graph.addNode('Catherine');
-        graph.addNode('John');
-        graph.addDirectedEdgeWithKey('M->C', 'Martha', 'Catherine');
-        graph.addUndirectedEdgeWithKey('C<->J', 'Catherine', 'John');
-
-        _assert["default"].strictEqual(graph.hasUndirectedEdge('M->C'), false);
-
-        _assert["default"].strictEqual(graph.hasUndirectedEdge('C<->J'), true);
-
-        _assert["default"].strictEqual(graph.hasUndirectedEdge('test'), false);
-
-        _assert["default"].strictEqual(graph.hasUndirectedEdge('Martha', 'Catherine'), false);
-
-        _assert["default"].strictEqual(graph.hasUndirectedEdge('Martha', 'Thomas'), false);
-
-        _assert["default"].strictEqual(graph.hasUndirectedEdge('Catherine', 'John'), true);
-
-        _assert["default"].strictEqual(graph.hasUndirectedEdge('John', 'Catherine'), true);
-      },
-      'it should work with self loops.': function itShouldWorkWithSelfLoops() {
-        var graph = new Graph();
-        graph.mergeUndirectedEdge('Lucy', 'Lucy');
-
-        _assert["default"].strictEqual(graph.hasDirectedEdge('Lucy', 'Lucy'), false);
-
-        _assert["default"].strictEqual(graph.hasUndirectedEdge('Lucy', 'Lucy'), true);
-      }
-    },
-    '#.hasEdge': {
-      'it should throw if invalid arguments are provided.': function itShouldThrowIfInvalidArgumentsAreProvided() {
-        var graph = new Graph();
-
-        _assert["default"]["throws"](function () {
-          graph.hasEdge(1, 2, 3);
-        }, invalid());
-      },
-      'it should correctly return whether a matching edge exists in the graph.': function itShouldCorrectlyReturnWhetherAMatchingEdgeExistsInTheGraph() {
-        var graph = new Graph();
-        graph.addNode('Martha');
-        graph.addNode('Catherine');
-        graph.addNode('John');
-        graph.addDirectedEdgeWithKey('M->C', 'Martha', 'Catherine');
-        graph.addUndirectedEdgeWithKey('C<->J', 'Catherine', 'John');
-
-        _assert["default"].strictEqual(graph.hasEdge('M->C'), true);
-
-        _assert["default"].strictEqual(graph.hasEdge('C<->J'), true);
-
-        _assert["default"].strictEqual(graph.hasEdge('test'), false);
-
-        _assert["default"].strictEqual(graph.hasEdge('Martha', 'Catherine'), true);
-
-        _assert["default"].strictEqual(graph.hasEdge('Martha', 'Thomas'), false);
-
-        _assert["default"].strictEqual(graph.hasEdge('Catherine', 'John'), true);
-
-        _assert["default"].strictEqual(graph.hasEdge('John', 'Catherine'), true);
-      },
-      'it should work properly with typed graphs.': function itShouldWorkProperlyWithTypedGraphs() {
-        var directedGraph = new Graph({
-          type: 'directed'
-        }),
-            undirectedGraph = new Graph({
-          type: 'undirected'
-        });
-        (0, _helpers.addNodesFrom)(directedGraph, [1, 2]);
-        (0, _helpers.addNodesFrom)(undirectedGraph, [1, 2]);
-
-        _assert["default"].strictEqual(directedGraph.hasEdge(1, 2), false);
-
-        _assert["default"].strictEqual(undirectedGraph.hasEdge(1, 2), false);
-      },
-      'it should work with self loops.': function itShouldWorkWithSelfLoops() {
-        var graph = new Graph();
-        graph.mergeUndirectedEdge('Lucy', 'Lucy');
-
-        _assert["default"].strictEqual(graph.hasDirectedEdge('Lucy', 'Lucy'), false);
-
-        _assert["default"].strictEqual(graph.hasUndirectedEdge('Lucy', 'Lucy'), true);
-
-        _assert["default"].strictEqual(graph.hasEdge('Lucy', 'Lucy'), true);
-      }
-    },
-    '#.directedEdge': {
-      'it should throw if invalid arguments are provided.': function itShouldThrowIfInvalidArgumentsAreProvided() {
-        var graph = new Graph(),
-            multiGraph = new Graph({
-          multi: true
-        });
-        graph.addNode('John');
-
-        _assert["default"]["throws"](function () {
-          multiGraph.directedEdge(1, 2);
-        }, usage());
-
-        _assert["default"]["throws"](function () {
-          graph.directedEdge('Jack', 'John');
-        }, notFound());
-
-        _assert["default"]["throws"](function () {
-          graph.directedEdge('John', 'Jack');
-        }, notFound());
-      },
-      'it should return the correct edge.': function itShouldReturnTheCorrectEdge() {
-        var graph = new Graph();
-        (0, _helpers.addNodesFrom)(graph, ['Jack', 'Lucy']);
-        graph.addDirectedEdgeWithKey('J->L', 'Jack', 'Lucy');
-        graph.addUndirectedEdgeWithKey('J<->L', 'Jack', 'Lucy');
-
-        _assert["default"].strictEqual(graph.directedEdge('Lucy', 'Jack'), undefined);
-
-        _assert["default"].strictEqual(graph.directedEdge('Jack', 'Lucy'), 'J->L');
-
-        var undirectedGraph = new Graph({
-          type: 'undirected'
-        });
-        undirectedGraph.mergeEdge('Jack', 'Lucy');
-
-        _assert["default"].strictEqual(undirectedGraph.directedEdge('Jack', 'Lucy'), undefined);
-      },
-      'it should return the correct self loop.': function itShouldReturnTheCorrectSelfLoop() {
-        var graph = new Graph();
-        graph.addNode('John');
-        graph.addEdgeWithKey('d', 'John', 'John');
-        graph.addUndirectedEdgeWithKey('u', 'John', 'John');
-
-        _assert["default"].strictEqual(graph.directedEdge('John', 'John'), 'd');
-      }
-    },
-    '#.undirectedEdge': {
-      'it should throw if invalid arguments are provided.': function itShouldThrowIfInvalidArgumentsAreProvided() {
-        var graph = new Graph(),
-            multiGraph = new Graph({
-          multi: true
-        });
-        graph.addNode('John');
-
-        _assert["default"]["throws"](function () {
-          multiGraph.undirectedEdge(1, 2);
-        }, usage());
-
-        _assert["default"]["throws"](function () {
-          graph.undirectedEdge('Jack', 'John');
-        }, notFound());
-
-        _assert["default"]["throws"](function () {
-          graph.undirectedEdge('John', 'Jack');
-        }, notFound());
-      },
-      'it should return the correct edge.': function itShouldReturnTheCorrectEdge() {
-        var graph = new Graph();
-        (0, _helpers.addNodesFrom)(graph, ['Jack', 'Lucy']);
-        graph.addDirectedEdgeWithKey('J->L', 'Jack', 'Lucy');
-        graph.addUndirectedEdgeWithKey('J<->L', 'Jack', 'Lucy');
-
-        _assert["default"].strictEqual(graph.undirectedEdge('Lucy', 'Jack'), 'J<->L');
-
-        _assert["default"].strictEqual(graph.undirectedEdge('Jack', 'Lucy'), 'J<->L');
-
-        var directedGraph = new Graph({
-          type: 'directed'
-        });
-        directedGraph.mergeEdge('Jack', 'Lucy');
-
-        _assert["default"].strictEqual(directedGraph.undirectedEdge('Jack', 'Lucy'), undefined);
-      },
-      'it should return the correct self loop.': function itShouldReturnTheCorrectSelfLoop() {
-        var graph = new Graph();
-        graph.addNode('John');
-        graph.addEdgeWithKey('d', 'John', 'John');
-        graph.addUndirectedEdgeWithKey('u', 'John', 'John');
-
-        _assert["default"].strictEqual(graph.undirectedEdge('John', 'John'), 'u');
-      }
-    },
-    '#.edge': {
-      'it should throw if invalid arguments are provided.': function itShouldThrowIfInvalidArgumentsAreProvided() {
-        var graph = new Graph(),
-            multiGraph = new Graph({
-          multi: true
-        });
-        graph.addNode('John');
-
-        _assert["default"]["throws"](function () {
-          multiGraph.edge(1, 2);
-        }, usage());
-
-        _assert["default"]["throws"](function () {
-          graph.edge('Jack', 'John');
-        }, notFound());
-
-        _assert["default"]["throws"](function () {
-          graph.edge('John', 'Jack');
-        }, notFound());
-      },
-      'it should return the correct edge.': function itShouldReturnTheCorrectEdge() {
-        var graph = new Graph();
-        (0, _helpers.addNodesFrom)(graph, ['Jack', 'Lucy']);
-        graph.addDirectedEdgeWithKey('J->L', 'Jack', 'Lucy');
-        graph.addUndirectedEdgeWithKey('J<->L', 'Jack', 'Lucy');
-
-        _assert["default"].strictEqual(graph.edge('Lucy', 'Jack'), 'J<->L');
-
-        _assert["default"].strictEqual(graph.edge('Jack', 'Lucy'), 'J->L');
-      },
-      'it should return the correct self loop.': function itShouldReturnTheCorrectSelfLoop() {
-        var graph = new Graph();
-        graph.addNode('John');
-        graph.addEdgeWithKey('d', 'John', 'John');
-        graph.addUndirectedEdgeWithKey('u', 'John', 'John');
-
-        _assert["default"].strictEqual(graph.edge('John', 'John'), 'd');
-      }
-    },
-    '#.areDirectedNeighbors': {
-      'it should throw if node is not in the graph.': function itShouldThrowIfNodeIsNotInTheGraph() {
-        var graph = new Graph();
-
-        _assert["default"]["throws"](function () {
-          graph.areDirectedNeighbors('source', 'target');
-        }, notFound());
-      },
-      'it should correctly return whether two nodes are neighbors.': function itShouldCorrectlyReturnWhetherTwoNodesAreNeighbors() {
-        var graph = new Graph();
-        graph.mergeDirectedEdge('Mary', 'Joseph');
-        graph.mergeUndirectedEdge('Martha', 'Mary');
-
-        _assert["default"].strictEqual(graph.areDirectedNeighbors('Mary', 'Joseph'), true);
-
-        _assert["default"].strictEqual(graph.areDirectedNeighbors('Joseph', 'Mary'), true);
-
-        _assert["default"].strictEqual(graph.areDirectedNeighbors('Martha', 'Mary'), false);
-
-        var undirectedGraph = new Graph({
-          type: 'undirected'
-        });
-        undirectedGraph.mergeEdge('Mary', 'Martha');
-
-        _assert["default"].strictEqual(undirectedGraph.areDirectedNeighbors('Mary', 'Martha'), false);
-      }
-    },
-    '#.areInNeighbors': {
-      'it should throw if node is not in the graph.': function itShouldThrowIfNodeIsNotInTheGraph() {
-        var graph = new Graph();
-
-        _assert["default"]["throws"](function () {
-          graph.areInNeighbors('source', 'target');
-        }, notFound());
-      },
-      'it should correctly return whether two nodes are neighbors.': function itShouldCorrectlyReturnWhetherTwoNodesAreNeighbors() {
-        var graph = new Graph();
-        graph.mergeDirectedEdge('Mary', 'Joseph');
-        graph.mergeUndirectedEdge('Martha', 'Mary');
-
-        _assert["default"].strictEqual(graph.areInNeighbors('Mary', 'Joseph'), false);
-
-        _assert["default"].strictEqual(graph.areInNeighbors('Joseph', 'Mary'), true);
-
-        _assert["default"].strictEqual(graph.areInNeighbors('Martha', 'Mary'), false);
-
-        var undirectedGraph = new Graph({
-          type: 'undirected'
-        });
-        undirectedGraph.mergeEdge('Mary', 'Martha');
-
-        _assert["default"].strictEqual(undirectedGraph.areInNeighbors('Mary', 'Martha'), false);
-      }
-    },
-    '#.areOutNeighbors': {
-      'it should throw if node is not in the graph.': function itShouldThrowIfNodeIsNotInTheGraph() {
-        var graph = new Graph();
-
-        _assert["default"]["throws"](function () {
-          graph.areOutNeighbors('source', 'target');
-        }, notFound());
-      },
-      'it should correctly return whether two nodes are neighbors.': function itShouldCorrectlyReturnWhetherTwoNodesAreNeighbors() {
-        var graph = new Graph();
-        graph.mergeDirectedEdge('Mary', 'Joseph');
-        graph.mergeUndirectedEdge('Martha', 'Mary');
-
-        _assert["default"].strictEqual(graph.areOutNeighbors('Mary', 'Joseph'), true);
-
-        _assert["default"].strictEqual(graph.areOutNeighbors('Joseph', 'Mary'), false);
-
-        _assert["default"].strictEqual(graph.areOutNeighbors('Martha', 'Mary'), false);
-
-        var undirectedGraph = new Graph({
-          type: 'undirected'
-        });
-        undirectedGraph.mergeEdge('Mary', 'Martha');
-
-        _assert["default"].strictEqual(undirectedGraph.areOutNeighbors('Mary', 'Martha'), false);
-      }
-    },
-    '#.areOutboundNeighbors': {
-      'it should throw if node is not in the graph.': function itShouldThrowIfNodeIsNotInTheGraph() {
-        var graph = new Graph();
-
-        _assert["default"]["throws"](function () {
-          graph.areOutboundNeighbors('source', 'target');
-        }, notFound());
-      },
-      'it should correctly return whether two nodes are neighbors.': function itShouldCorrectlyReturnWhetherTwoNodesAreNeighbors() {
-        var graph = new Graph();
-        graph.mergeDirectedEdge('Mary', 'Joseph');
-        graph.mergeUndirectedEdge('Martha', 'Mary');
-
-        _assert["default"].strictEqual(graph.areOutboundNeighbors('Mary', 'Joseph'), true);
-
-        _assert["default"].strictEqual(graph.areOutboundNeighbors('Joseph', 'Mary'), false);
-
-        _assert["default"].strictEqual(graph.areOutboundNeighbors('Martha', 'Mary'), true);
-
-        var undirectedGraph = new Graph({
-          type: 'undirected'
-        });
-        undirectedGraph.mergeEdge('Mary', 'Martha');
-
-        _assert["default"].strictEqual(undirectedGraph.areOutboundNeighbors('Mary', 'Martha'), true);
-      }
-    },
-    '#.areInboundNeighbors': {
-      'it should throw if node is not in the graph.': function itShouldThrowIfNodeIsNotInTheGraph() {
-        var graph = new Graph();
-
-        _assert["default"]["throws"](function () {
-          graph.areInboundNeighbors('source', 'target');
-        }, notFound());
-      },
-      'it should correctly return whether two nodes are neighbors.': function itShouldCorrectlyReturnWhetherTwoNodesAreNeighbors() {
-        var graph = new Graph();
-        graph.mergeDirectedEdge('Mary', 'Joseph');
-        graph.mergeUndirectedEdge('Martha', 'Mary');
-
-        _assert["default"].strictEqual(graph.areInboundNeighbors('Mary', 'Joseph'), false);
-
-        _assert["default"].strictEqual(graph.areInboundNeighbors('Joseph', 'Mary'), true);
-
-        _assert["default"].strictEqual(graph.areInboundNeighbors('Martha', 'Mary'), true);
-
-        var undirectedGraph = new Graph({
-          type: 'undirected'
-        });
-        undirectedGraph.mergeEdge('Mary', 'Martha');
-
-        _assert["default"].strictEqual(undirectedGraph.areInboundNeighbors('Mary', 'Martha'), true);
-      }
-    },
-    '#.areUndirectedNeighbors': {
-      'it should throw if node is not in the graph.': function itShouldThrowIfNodeIsNotInTheGraph() {
-        var graph = new Graph();
-
-        _assert["default"]["throws"](function () {
-          graph.areUndirectedNeighbors('source', 'target');
-        }, notFound());
-      },
-      'it should correctly return whether two nodes are neighbors.': function itShouldCorrectlyReturnWhetherTwoNodesAreNeighbors() {
-        var graph = new Graph();
-        graph.mergeDirectedEdge('Mary', 'Joseph');
-        graph.mergeUndirectedEdge('Martha', 'Mary');
-
-        _assert["default"].strictEqual(graph.areUndirectedNeighbors('Mary', 'Joseph'), false);
-
-        _assert["default"].strictEqual(graph.areUndirectedNeighbors('Joseph', 'Mary'), false);
-
-        _assert["default"].strictEqual(graph.areUndirectedNeighbors('Martha', 'Mary'), true);
-
-        var directedGraph = new Graph({
-          type: 'directed'
-        });
-        directedGraph.mergeEdge('Mary', 'Martha');
-
-        _assert["default"].strictEqual(directedGraph.areUndirectedNeighbors('Mary', 'Martha'), false);
-      }
-    },
-    '#.areNeighbors': {
-      'it should throw if node is not in the graph.': function itShouldThrowIfNodeIsNotInTheGraph() {
-        var graph = new Graph();
-
-        _assert["default"]["throws"](function () {
-          graph.areNeighbors('source', 'target');
-        }, notFound());
-      },
-      'it should correctly return whether two nodes are neighbors.': function itShouldCorrectlyReturnWhetherTwoNodesAreNeighbors() {
-        var graph = new Graph();
-        graph.mergeDirectedEdge('Mary', 'Joseph');
-        graph.mergeUndirectedEdge('Martha', 'Mary');
-
-        _assert["default"].strictEqual(graph.areNeighbors('Mary', 'Joseph'), true);
-
-        _assert["default"].strictEqual(graph.areNeighbors('Joseph', 'Mary'), true);
-
-        _assert["default"].strictEqual(graph.areNeighbors('Martha', 'Mary'), true);
-
-        _assert["default"].strictEqual(graph.areNeighbors('Joseph', 'Martha'), false);
-
-        var undirectedGraph = new Graph({
-          type: 'undirected'
-        });
-        undirectedGraph.mergeEdge('Mary', 'Martha');
-
-        _assert["default"].strictEqual(undirectedGraph.areNeighbors('Mary', 'Martha'), true);
-      }
-    },
-    '#.source': {
-      'it should throw if the edge is not in the graph.': function itShouldThrowIfTheEdgeIsNotInTheGraph() {
-        var graph = new Graph();
-
-        _assert["default"]["throws"](function () {
-          graph.source('test');
-        }, notFound());
-      },
-      'it should return the correct source.': function itShouldReturnTheCorrectSource() {
-        var graph = new Graph();
-        graph.addNode('John');
-        graph.addNode('Martha');
-        var edge = graph.addDirectedEdge('John', 'Martha');
-
-        _assert["default"].strictEqual(graph.source(edge), 'John');
-      }
-    },
-    '#.target': {
-      'it should throw if the edge is not in the graph.': function itShouldThrowIfTheEdgeIsNotInTheGraph() {
-        var graph = new Graph();
-
-        _assert["default"]["throws"](function () {
-          graph.target('test');
-        }, notFound());
-      },
-      'it should return the correct target.': function itShouldReturnTheCorrectTarget() {
-        var graph = new Graph();
-        graph.addNode('John');
-        graph.addNode('Martha');
-        var edge = graph.addDirectedEdge('John', 'Martha');
-
-        _assert["default"].strictEqual(graph.target(edge), 'Martha');
-      }
-    },
-    '#.extremities': {
-      'it should throw if the edge is not in the graph.': function itShouldThrowIfTheEdgeIsNotInTheGraph() {
-        var graph = new Graph();
-
-        _assert["default"]["throws"](function () {
-          graph.extremities('test');
-        }, notFound());
-      },
-      'it should return the correct extremities.': function itShouldReturnTheCorrectExtremities() {
-        var graph = new Graph();
-        graph.addNode('John');
-        graph.addNode('Martha');
-        var edge = graph.addDirectedEdge('John', 'Martha');
-
-        _assert["default"].deepStrictEqual(graph.extremities(edge), ['John', 'Martha']);
-      }
-    },
-    '#.opposite': {
-      'it should throw if either the node or the edge is not found in the graph.': function itShouldThrowIfEitherTheNodeOrTheEdgeIsNotFoundInTheGraph() {
-        var graph = new Graph();
-        graph.addNode('Thomas');
-
-        _assert["default"]["throws"](function () {
-          graph.opposite('Jeremy', 'T->J');
-        }, notFound());
-
-        _assert["default"]["throws"](function () {
-          graph.opposite('Thomas', 'T->J');
-        }, notFound());
-      },
-      'it should throw if the node & the edge are not related.': function itShouldThrowIfTheNodeTheEdgeAreNotRelated() {
-        var graph = new Graph();
-        (0, _helpers.addNodesFrom)(graph, ['Thomas', 'Isabella', 'Estelle']);
-        graph.addEdgeWithKey('I->E', 'Isabella', 'Estelle');
-
-        _assert["default"]["throws"](function () {
-          graph.opposite('Thomas', 'I->E');
-        }, notFound());
-      },
-      'it should return the correct node.': function itShouldReturnTheCorrectNode() {
-        var graph = new Graph();
-        (0, _helpers.addNodesFrom)(graph, ['Thomas', 'Estelle']);
-        var edge = graph.addEdge('Thomas', 'Estelle');
-
-        _assert["default"].strictEqual(graph.opposite('Thomas', edge), 'Estelle');
-      }
-    },
-    '#.hasExtremity': {
-      'it should throw if either the edge is not found in the graph.': function itShouldThrowIfEitherTheEdgeIsNotFoundInTheGraph() {
-        var graph = new Graph();
-        graph.mergeEdge('Thomas', 'Laura');
-
-        _assert["default"]["throws"](function () {
-          graph.hasExtremity('inexisting-edge', 'Thomas');
-        }, notFound());
-      },
-      'it should return the correct answer.': function itShouldReturnTheCorrectAnswer() {
-        var graph = new Graph();
-        graph.addNode('Jack');
-
-        var _graph$mergeEdge = graph.mergeEdge('Thomas', 'Estelle'),
-            edge = _graph$mergeEdge[0];
-
-        _assert["default"].strictEqual(graph.hasExtremity(edge, 'Thomas'), true);
-
-        _assert["default"].strictEqual(graph.hasExtremity(edge, 'Estelle'), true);
-
-        _assert["default"].strictEqual(graph.hasExtremity(edge, 'Jack'), false);
-
-        _assert["default"].strictEqual(graph.hasExtremity(edge, 'Who?'), false);
-      }
-    },
-    '#.isDirected': {
-      'it should throw if the edge is not in the graph.': function itShouldThrowIfTheEdgeIsNotInTheGraph() {
-        var graph = new Graph();
-
-        _assert["default"]["throws"](function () {
-          graph.isDirected('test');
-        }, notFound());
-      },
-      'it should correctly return whether the edge is directed or not.': function itShouldCorrectlyReturnWhetherTheEdgeIsDirectedOrNot() {
-        var graph = new Graph();
-        graph.addNode('John');
-        graph.addNode('Rachel');
-        graph.addNode('Suzan');
-        var directedEdge = graph.addDirectedEdge('John', 'Rachel'),
-            undirectedEdge = graph.addUndirectedEdge('Rachel', 'Suzan');
-
-        _assert["default"].strictEqual(graph.isDirected(directedEdge), true);
-
-        _assert["default"].strictEqual(graph.isDirected(undirectedEdge), false);
-      }
-    },
-    '#.isUndirected': {
-      'it should throw if the edge is not in the graph.': function itShouldThrowIfTheEdgeIsNotInTheGraph() {
-        var graph = new Graph();
-
-        _assert["default"]["throws"](function () {
-          graph.isUndirected('test');
-        }, notFound());
-      },
-      'it should correctly return whether the edge is undirected or not.': function itShouldCorrectlyReturnWhetherTheEdgeIsUndirectedOrNot() {
-        var graph = new Graph();
-        graph.addNode('John');
-        graph.addNode('Rachel');
-        graph.addNode('Suzan');
-        var directedEdge = graph.addDirectedEdge('John', 'Rachel'),
-            undirectedEdge = graph.addUndirectedEdge('Rachel', 'Suzan');
-
-        _assert["default"].strictEqual(graph.isUndirected(directedEdge), false);
-
-        _assert["default"].strictEqual(graph.isUndirected(undirectedEdge), true);
-      }
-    },
-    '#.isSelfLoop': {
-      'it should throw if the edge is not in the graph.': function itShouldThrowIfTheEdgeIsNotInTheGraph() {
-        var graph = new Graph();
-
-        _assert["default"]["throws"](function () {
-          graph.isSelfLoop('test');
-        }, notFound());
-      },
-      'it should correctly return whether the edge is a self-loop or not.': function itShouldCorrectlyReturnWhetherTheEdgeIsASelfLoopOrNot() {
-        var graph = new Graph();
-        graph.addNode('John');
-        graph.addNode('Rachel');
-        var selfLoop = graph.addDirectedEdge('John', 'John'),
-            edge = graph.addUndirectedEdge('John', 'Rachel');
-
-        _assert["default"].strictEqual(graph.isSelfLoop(selfLoop), true);
-
-        _assert["default"].strictEqual(graph.isSelfLoop(edge), false);
-      }
-    },
-    Degree: {
-      '#.inDegree': {
-        'it should throw if the node is not found in the graph.': function itShouldThrowIfTheNodeIsNotFoundInTheGraph() {
-          var graph = new Graph();
-
-          _assert["default"]["throws"](function () {
-            graph.inDegree('Test');
-          }, notFound());
-        },
-        'it should return the correct in degree.': function itShouldReturnTheCorrectInDegree() {
-          var graph = new Graph();
-          (0, _helpers.addNodesFrom)(graph, ['Helen', 'Sue', 'William', 'John']);
-          graph.addDirectedEdge('Helen', 'Sue');
-          graph.addDirectedEdge('William', 'Sue');
-
-          _assert["default"].strictEqual(graph.inDegree('Sue'), 2);
-
-          graph.addDirectedEdge('Sue', 'Sue');
-
-          _assert["default"].strictEqual(graph.inDegree('Sue'), 3);
-
-          _assert["default"].strictEqual(graph.inDegreeWithoutSelfLoops('Sue'), 2);
-        },
-        'it should always return 0 in an undirected graph.': function itShouldAlwaysReturn0InAnUndirectedGraph() {
-          var graph = new Graph({
-            type: 'undirected'
-          });
-          (0, _helpers.addNodesFrom)(graph, ['Helen', 'Sue']);
-          graph.addEdge('Helen', 'Sue');
-
-          _assert["default"].strictEqual(graph.inDegree('Helen'), 0);
-        }
-      },
-      '#.inboundDegree': {
-        'it should throw if the node is not found in the graph.': function itShouldThrowIfTheNodeIsNotFoundInTheGraph() {
-          var graph = new Graph();
-
-          _assert["default"]["throws"](function () {
-            graph.inboundDegree('Test');
-          }, notFound());
-        },
-        'it should return the correct in degree.': function itShouldReturnTheCorrectInDegree() {
-          var graph = new Graph();
-          (0, _helpers.addNodesFrom)(graph, ['Helen', 'Sue', 'William', 'John']);
-          graph.addDirectedEdge('Helen', 'Sue');
-          graph.addDirectedEdge('William', 'Sue');
-          graph.addUndirectedEdge('Helen', 'Sue');
-
-          _assert["default"].strictEqual(graph.inboundDegree('Sue'), 3);
-
-          graph.addDirectedEdge('Sue', 'Sue');
-
-          _assert["default"].strictEqual(graph.inboundDegree('Sue'), 4);
-
-          _assert["default"].strictEqual(graph.inboundDegreeWithoutSelfLoops('Sue'), 3);
-        },
-        'it should always the undirected degree in an undirected graph.': function itShouldAlwaysTheUndirectedDegreeInAnUndirectedGraph() {
-          var graph = new Graph({
-            type: 'undirected'
-          });
-          (0, _helpers.addNodesFrom)(graph, ['Helen', 'Sue']);
-          graph.addEdge('Helen', 'Sue');
-
-          _assert["default"].strictEqual(graph.inboundDegree('Helen'), 1);
-        }
-      },
-      '#.outDegree': {
-        'it should throw if the node is not found in the graph.': function itShouldThrowIfTheNodeIsNotFoundInTheGraph() {
-          var graph = new Graph();
-
-          _assert["default"]["throws"](function () {
-            graph.outDegree('Test');
-          }, notFound());
-        },
-        'it should return the correct out degree.': function itShouldReturnTheCorrectOutDegree() {
-          var graph = new Graph();
-          (0, _helpers.addNodesFrom)(graph, ['Helen', 'Sue', 'William', 'John']);
-          graph.addDirectedEdge('Helen', 'Sue');
-          graph.addDirectedEdge('Helen', 'William');
-
-          _assert["default"].strictEqual(graph.outDegree('Helen'), 2);
-
-          graph.addDirectedEdge('Helen', 'Helen');
-
-          _assert["default"].strictEqual(graph.outDegree('Helen'), 3);
-
-          _assert["default"].strictEqual(graph.outDegreeWithoutSelfLoops('Helen'), 2);
-        },
-        'it should always return 0 in an undirected graph.': function itShouldAlwaysReturn0InAnUndirectedGraph() {
-          var graph = new Graph({
-            type: 'undirected'
-          });
-          (0, _helpers.addNodesFrom)(graph, ['Helen', 'Sue']);
-          graph.addEdge('Helen', 'Sue');
-
-          _assert["default"].strictEqual(graph.outDegree('Sue'), 0);
-        }
-      },
-      '#.outboundDegree': {
-        'it should throw if the node is not found in the graph.': function itShouldThrowIfTheNodeIsNotFoundInTheGraph() {
-          var graph = new Graph();
-
-          _assert["default"]["throws"](function () {
-            graph.outboundDegree('Test');
-          }, notFound());
-        },
-        'it should return the correct out degree.': function itShouldReturnTheCorrectOutDegree() {
-          var graph = new Graph();
-          (0, _helpers.addNodesFrom)(graph, ['Helen', 'Sue', 'William', 'John']);
-          graph.addDirectedEdge('Helen', 'Sue');
-          graph.addDirectedEdge('Helen', 'William');
-          graph.addUndirectedEdge('Helen', 'Sue');
-
-          _assert["default"].strictEqual(graph.outboundDegree('Helen'), 3);
-
-          graph.addDirectedEdge('Helen', 'Helen');
-
-          _assert["default"].strictEqual(graph.outboundDegree('Helen'), 4);
-
-          _assert["default"].strictEqual(graph.outboundDegreeWithoutSelfLoops('Helen'), 3);
-        },
-        'it should always the undirected degree in an undirected graph.': function itShouldAlwaysTheUndirectedDegreeInAnUndirectedGraph() {
-          var graph = new Graph({
-            type: 'undirected'
-          });
-          (0, _helpers.addNodesFrom)(graph, ['Helen', 'Sue']);
-          graph.addEdge('Helen', 'Sue');
-
-          _assert["default"].strictEqual(graph.outboundDegree('Sue'), 1);
-        }
-      },
-      '#.directedDegree': {
-        'it should throw if the node is not found in the graph.': function itShouldThrowIfTheNodeIsNotFoundInTheGraph() {
-          var graph = new Graph();
-
-          _assert["default"]["throws"](function () {
-            graph.directedDegree('Test');
-          }, notFound());
-        },
-        'it should return the correct directed degree.': function itShouldReturnTheCorrectDirectedDegree() {
-          var graph = new Graph();
-          (0, _helpers.addNodesFrom)(graph, ['Helen', 'Sue', 'William', 'John', 'Martha']);
-          graph.addDirectedEdge('Helen', 'Sue');
-          graph.addDirectedEdge('Helen', 'William');
-          graph.addDirectedEdge('Martha', 'Helen');
-          graph.addUndirectedEdge('Helen', 'John');
-
-          _assert["default"].strictEqual(graph.directedDegree('Helen'), 3);
-
-          _assert["default"].strictEqual(graph.directedDegree('Helen'), graph.inDegree('Helen') + graph.outDegree('Helen'));
-
-          graph.addDirectedEdge('Helen', 'Helen');
-
-          _assert["default"].strictEqual(graph.directedDegree('Helen'), 5);
-
-          _assert["default"].strictEqual(graph.directedDegreeWithoutSelfLoops('Helen'), 3);
-        },
-        'it should always return 0 in an undirected graph.': function itShouldAlwaysReturn0InAnUndirectedGraph() {
-          var graph = new Graph({
-            type: 'undirected'
-          });
-          (0, _helpers.addNodesFrom)(graph, ['Helen', 'Sue']);
-          graph.addEdge('Helen', 'Sue');
-
-          _assert["default"].strictEqual(graph.inDegree('Helen'), 0);
-        }
-      },
-      '#.undirectedDegree': {
-        'it should throw if the node is not found in the graph.': function itShouldThrowIfTheNodeIsNotFoundInTheGraph() {
-          var graph = new Graph();
-
-          _assert["default"]["throws"](function () {
-            graph.undirectedDegree('Test');
-          }, notFound());
-        },
-        'it should return the correct undirected degree.': function itShouldReturnTheCorrectUndirectedDegree() {
-          var graph = new Graph();
-          (0, _helpers.addNodesFrom)(graph, ['Helen', 'Sue', 'William', 'John']);
-          graph.addDirectedEdge('Helen', 'Sue');
-          graph.addDirectedEdge('Helen', 'William');
-          graph.addUndirectedEdge('Helen', 'John');
-
-          _assert["default"].strictEqual(graph.undirectedDegree('Helen'), 1);
-
-          graph.addUndirectedEdge('Helen', 'Helen');
-
-          _assert["default"].strictEqual(graph.undirectedDegree('Helen'), 3);
-
-          _assert["default"].strictEqual(graph.undirectedDegreeWithoutSelfLoops('Helen'), 1);
-        },
-        'it should always return 0 in a directed graph.': function itShouldAlwaysReturn0InADirectedGraph() {
-          var graph = new Graph({
-            type: 'directed'
-          });
-          (0, _helpers.addNodesFrom)(graph, ['Helen', 'Sue']);
-          graph.addEdge('Helen', 'Sue');
-
-          _assert["default"].strictEqual(graph.undirectedDegree('Helen'), 0);
-        }
-      },
-      '#.degree': {
-        'it should throw if the node is not found in the graph.': function itShouldThrowIfTheNodeIsNotFoundInTheGraph() {
-          var graph = new Graph();
-
-          _assert["default"]["throws"](function () {
-            graph.degree('Test');
-          }, notFound());
-        },
-        'it should return the correct degree.': function itShouldReturnTheCorrectDegree() {
-          var graph = new Graph();
-          (0, _helpers.addNodesFrom)(graph, ['Helen', 'Sue', 'William', 'John', 'Martha']);
-          graph.addDirectedEdge('Helen', 'Sue');
-          graph.addDirectedEdge('Helen', 'William');
-          graph.addDirectedEdge('Martha', 'Helen');
-          graph.addUndirectedEdge('Helen', 'John');
-
-          _assert["default"].strictEqual(graph.degree('Helen'), 4);
-
-          _assert["default"].strictEqual(graph.degree('Helen'), graph.directedDegree('Helen') + graph.undirectedDegree('Helen'));
-
-          graph.addUndirectedEdge('Helen', 'Helen');
-
-          _assert["default"].strictEqual(graph.degree('Helen'), 6);
-
-          _assert["default"].strictEqual(graph.degreeWithoutSelfLoops('Helen'), 4);
-        }
-      },
-      'it should also work with typed graphs.': function itShouldAlsoWorkWithTypedGraphs() {
-        var directedGraph = new Graph({
-          type: 'directed'
-        }),
-            undirectedGraph = new Graph({
-          type: 'undirected'
-        });
-        (0, _helpers.addNodesFrom)(directedGraph, [1, 2]);
-        (0, _helpers.addNodesFrom)(undirectedGraph, [1, 2]);
-
-        _assert["default"].strictEqual(directedGraph.degree(1), 0);
-
-        _assert["default"].strictEqual(undirectedGraph.degree(1), 0);
-
-        directedGraph.addDirectedEdge(1, 2);
-        undirectedGraph.addUndirectedEdge(1, 2);
-
-        _assert["default"].strictEqual(directedGraph.degree(1), 1);
-
-        _assert["default"].strictEqual(undirectedGraph.degree(1), 1);
-      }
-    }
-  };
-}
\ No newline at end of file
diff --git a/libs/shared/graph-layouts/node_modules/graphology/specs/serialization.js b/libs/shared/graph-layouts/node_modules/graphology/specs/serialization.js
deleted file mode 100644
index fc9318ae9..000000000
--- a/libs/shared/graph-layouts/node_modules/graphology/specs/serialization.js
+++ /dev/null
@@ -1,171 +0,0 @@
-"use strict";
-
-Object.defineProperty(exports, "__esModule", {
-  value: true
-});
-exports["default"] = serialization;
-
-var _assert = _interopRequireDefault(require("assert"));
-
-var _helpers = require("./helpers");
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
-
-/**
- * Graphology Serializaton Specs
- * ==============================
- *
- * Testing the serialization methods of the graph.
- */
-function serialization(Graph, checkers) {
-  var invalid = checkers.invalid,
-      notFound = checkers.notFound;
-  return {
-    '#.export': {
-      'it should correctly return the serialized graph.': function itShouldCorrectlyReturnTheSerializedGraph() {
-        var graph = new Graph({
-          multi: true
-        });
-        graph.setAttribute('name', 'graph');
-        (0, _helpers.addNodesFrom)(graph, ['John', 'Jack', 'Martha']);
-        graph.setNodeAttribute('John', 'age', 34);
-        graph.addEdgeWithKey('J->J•1', 'John', 'Jack');
-        graph.addEdgeWithKey('J->J•2', 'John', 'Jack', {
-          weight: 2
-        });
-        graph.addEdgeWithKey('J->J•3', 'John', 'Jack');
-        graph.addUndirectedEdgeWithKey('J<->J•1', 'John', 'Jack');
-        graph.addUndirectedEdgeWithKey('J<->J•2', 'John', 'Jack', {
-          weight: 3
-        });
-
-        _assert["default"].deepStrictEqual(graph["export"](), {
-          attributes: {
-            name: 'graph'
-          },
-          nodes: [{
-            key: 'John',
-            attributes: {
-              age: 34
-            }
-          }, {
-            key: 'Jack'
-          }, {
-            key: 'Martha'
-          }],
-          edges: [{
-            key: 'J->J•1',
-            source: 'John',
-            target: 'Jack'
-          }, {
-            key: 'J->J•2',
-            source: 'John',
-            target: 'Jack',
-            attributes: {
-              weight: 2
-            }
-          }, {
-            key: 'J->J•3',
-            source: 'John',
-            target: 'Jack'
-          }, {
-            key: 'J<->J•1',
-            source: 'John',
-            target: 'Jack',
-            undirected: true
-          }, {
-            key: 'J<->J•2',
-            source: 'John',
-            target: 'Jack',
-            attributes: {
-              weight: 3
-            },
-            undirected: true
-          }],
-          options: {
-            allowSelfLoops: true,
-            multi: true,
-            type: 'mixed'
-          }
-        });
-      }
-    },
-    '#.import': {
-      'it should throw if the given data is invalid.': function itShouldThrowIfTheGivenDataIsInvalid() {
-        var graph = new Graph();
-
-        _assert["default"]["throws"](function () {
-          graph["import"](true);
-        }, invalid());
-      },
-      'it should be possible to import a graph instance.': function itShouldBePossibleToImportAGraphInstance() {
-        var graph = new Graph();
-        (0, _helpers.addNodesFrom)(graph, ['John', 'Thomas']);
-        graph.addEdge('John', 'Thomas');
-        var other = new Graph();
-        other["import"](graph);
-
-        _assert["default"].deepStrictEqual(graph.nodes(), other.nodes());
-
-        _assert["default"].deepStrictEqual(graph.edges(), other.edges());
-      },
-      'it should be possible to import a serialized graph.': function itShouldBePossibleToImportASerializedGraph() {
-        var graph = new Graph();
-        graph["import"]({
-          nodes: [{
-            key: 'John'
-          }, {
-            key: 'Thomas'
-          }],
-          edges: [{
-            source: 'John',
-            target: 'Thomas'
-          }]
-        });
-
-        _assert["default"].deepStrictEqual(graph.nodes(), ['John', 'Thomas']);
-
-        _assert["default"].strictEqual(graph.hasEdge('John', 'Thomas'), true);
-      },
-      'it should be possible to import only edges when merging.': function itShouldBePossibleToImportOnlyEdgesWhenMerging() {
-        var graph = new Graph();
-        graph["import"]({
-          edges: [{
-            source: 'John',
-            target: 'Thomas'
-          }]
-        }, true);
-
-        _assert["default"].deepStrictEqual(graph.nodes(), ['John', 'Thomas']);
-
-        _assert["default"].strictEqual(graph.size, 1);
-
-        _assert["default"].strictEqual(graph.hasEdge('John', 'Thomas'), true);
-      },
-      'it should be possible to import attributes.': function itShouldBePossibleToImportAttributes() {
-        var graph = new Graph();
-        graph["import"]({
-          attributes: {
-            name: 'graph'
-          }
-        });
-
-        _assert["default"].deepStrictEqual(graph.getAttributes(), {
-          name: 'graph'
-        });
-      },
-      'it should throw if nodes are absent, edges are present and we merge.': function itShouldThrowIfNodesAreAbsentEdgesArePresentAndWeMerge() {
-        var graph = new Graph();
-
-        _assert["default"]["throws"](function () {
-          graph["import"]({
-            edges: [{
-              source: '1',
-              target: '2'
-            }]
-          });
-        }, notFound());
-      }
-    }
-  };
-}
\ No newline at end of file
diff --git a/libs/shared/graph-layouts/node_modules/graphology/specs/utils.js b/libs/shared/graph-layouts/node_modules/graphology/specs/utils.js
deleted file mode 100644
index 6b7158a8a..000000000
--- a/libs/shared/graph-layouts/node_modules/graphology/specs/utils.js
+++ /dev/null
@@ -1,249 +0,0 @@
-"use strict";
-
-Object.defineProperty(exports, "__esModule", {
-  value: true
-});
-exports["default"] = utils;
-
-var _assert = _interopRequireDefault(require("assert"));
-
-var _helpers = require("./helpers");
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
-
-/**
- * Graphology Utils Specs
- * =======================
- *
- * Testing the utils methods.
- */
-var PROPERTIES = ['type', 'multi', 'map', 'selfLoops'];
-
-function utils(Graph, checkers) {
-  var usage = checkers.usage;
-  return {
-    '#.nullCopy': {
-      'it should create an null copy of the graph.': function itShouldCreateAnNullCopyOfTheGraph() {
-        var graph = new Graph();
-        (0, _helpers.addNodesFrom)(graph, ['John', 'Thomas']);
-        graph.addEdge('John', 'Thomas');
-        var copy = graph.nullCopy();
-
-        _assert["default"].deepStrictEqual(copy.nodes(), []);
-
-        _assert["default"].strictEqual(copy.order, 0);
-
-        _assert["default"].strictEqual(copy.size, 0);
-
-        PROPERTIES.forEach(function (property) {
-          _assert["default"].strictEqual(graph[property], copy[property]);
-        });
-      },
-      'it should be possible to pass options to merge.': function itShouldBePossibleToPassOptionsToMerge() {
-        var graph = new Graph({
-          type: 'directed'
-        });
-        var copy = graph.nullCopy({
-          type: 'undirected'
-        });
-
-        _assert["default"].strictEqual(copy.type, 'undirected');
-
-        _assert["default"]["throws"](function () {
-          copy.addDirectedEdge('one', 'two');
-        }, /addDirectedEdge/);
-      },
-      'copying the graph should conserve its attributes.': function copyingTheGraphShouldConserveItsAttributes() {
-        var graph = new Graph();
-        graph.setAttribute('title', 'The Graph');
-        var copy = graph.nullCopy();
-
-        _assert["default"].deepStrictEqual(graph.getAttributes(), copy.getAttributes());
-      }
-    },
-    '#.emptyCopy': {
-      'it should create an empty copy of the graph.': function itShouldCreateAnEmptyCopyOfTheGraph() {
-        var graph = new Graph();
-        (0, _helpers.addNodesFrom)(graph, ['John', 'Thomas']);
-        graph.addEdge('John', 'Thomas');
-        var copy = graph.emptyCopy();
-
-        _assert["default"].deepStrictEqual(copy.nodes(), ['John', 'Thomas']);
-
-        _assert["default"].strictEqual(copy.order, 2);
-
-        _assert["default"].strictEqual(copy.size, 0);
-
-        PROPERTIES.forEach(function (property) {
-          _assert["default"].strictEqual(graph[property], copy[property]);
-        });
-        copy.mergeEdge('Mary', 'Thomas');
-        copy.setNodeAttribute('John', 'age', 32);
-
-        _assert["default"].strictEqual(copy.order, 3);
-
-        _assert["default"].strictEqual(copy.size, 1);
-
-        _assert["default"].deepStrictEqual(copy.getNodeAttributes('John'), {
-          age: 32
-        });
-
-        _assert["default"].deepStrictEqual(graph.getNodeAttributes('John'), {});
-      },
-      'it should be possible to pass options to merge.': function itShouldBePossibleToPassOptionsToMerge() {
-        var graph = new Graph({
-          type: 'directed'
-        });
-        var copy = graph.emptyCopy({
-          type: 'undirected'
-        });
-
-        _assert["default"].strictEqual(copy.type, 'undirected');
-
-        _assert["default"]["throws"](function () {
-          copy.addDirectedEdge('one', 'two');
-        }, /addDirectedEdge/);
-      },
-      'copying the graph should conserve its attributes.': function copyingTheGraphShouldConserveItsAttributes() {
-        var graph = new Graph();
-        graph.setAttribute('title', 'The Graph');
-        var copy = graph.emptyCopy();
-
-        _assert["default"].deepStrictEqual(graph.getAttributes(), copy.getAttributes());
-      }
-    },
-    '#.copy': {
-      'it should create a full copy of the graph.': function itShouldCreateAFullCopyOfTheGraph() {
-        var graph = new Graph();
-        (0, _helpers.addNodesFrom)(graph, ['John', 'Thomas']);
-        graph.addEdge('John', 'Thomas');
-        var copy = graph.copy();
-
-        _assert["default"].deepStrictEqual(copy.nodes(), graph.nodes());
-
-        _assert["default"].deepStrictEqual(copy.edges(), graph.edges());
-
-        _assert["default"].strictEqual(copy.order, 2);
-
-        _assert["default"].strictEqual(copy.size, 1);
-
-        PROPERTIES.forEach(function (property) {
-          _assert["default"].strictEqual(graph[property], graph[property]);
-        });
-      },
-      'it should not break when copying a graph with wrangled edge ids (issue #213).': function itShouldNotBreakWhenCopyingAGraphWithWrangledEdgeIdsIssue213() {
-        var graph = new Graph();
-        graph.addNode('n0');
-        graph.addNode('n1');
-        graph.addNode('n2');
-        graph.addNode('n3');
-        graph.addEdge('n0', 'n1');
-        graph.addEdge('n1', 'n2');
-        graph.addEdge('n2', 'n3');
-        graph.addEdge('n3', 'n0');
-
-        _assert["default"].doesNotThrow(function () {
-          graph.copy();
-        }); // Do surgery on second edge
-
-
-        var edgeToSplit = graph.edge('n1', 'n2');
-        var newNode = 'n12';
-        graph.addNode(newNode);
-        graph.dropEdge('n1', 'n2');
-        graph.addEdge('n1', newNode);
-        graph.addEdgeWithKey(edgeToSplit, newNode, 'n2');
-        var copy = graph.copy();
-
-        _assert["default"].deepStrictEqual(new Set(graph.nodes()), new Set(copy.nodes()));
-
-        _assert["default"].deepStrictEqual(new Set(graph.edges()), new Set(copy.edges()));
-
-        _assert["default"].notStrictEqual(graph.getNodeAttributes('n1'), copy.getNodeAttributes('n1'));
-
-        _assert["default"].doesNotThrow(function () {
-          copy.addEdge('n0', 'n12');
-        });
-      },
-      'it should not break on adversarial inputs.': function itShouldNotBreakOnAdversarialInputs() {
-        var graph = new Graph();
-        graph.mergeEdge(0, 1);
-        graph.mergeEdge(1, 2);
-        graph.mergeEdge(2, 0);
-        var copy = graph.copy();
-        copy.mergeEdge(3, 4);
-        var serializedCopy = Graph.from(graph["export"]());
-
-        _assert["default"].doesNotThrow(function () {
-          serializedCopy.mergeEdge(3, 4);
-        });
-
-        _assert["default"].strictEqual(serializedCopy.size, 4);
-      },
-      'copying the graph should conserve its attributes.': function copyingTheGraphShouldConserveItsAttributes() {
-        var graph = new Graph();
-        graph.setAttribute('title', 'The Graph');
-        var copy = graph.copy();
-
-        _assert["default"].deepStrictEqual(graph.getAttributes(), copy.getAttributes());
-      },
-      'it should be possible to upgrade a graph.': function itShouldBePossibleToUpgradeAGraph() {
-        var strict = new Graph({
-          type: 'directed',
-          allowSelfLoops: false
-        });
-        var loose = new Graph({
-          multi: true
-        });
-
-        _assert["default"].strictEqual(strict.copy({
-          type: 'directed'
-        }).type, 'directed');
-
-        _assert["default"].strictEqual(strict.copy({
-          multi: false
-        }).multi, false);
-
-        _assert["default"].strictEqual(strict.copy({
-          allowSelfLoops: false
-        }).allowSelfLoops, false);
-
-        _assert["default"].strictEqual(strict.copy({
-          type: 'mixed'
-        }).type, 'mixed');
-
-        _assert["default"].strictEqual(strict.copy({
-          multi: true
-        }).multi, true);
-
-        _assert["default"].strictEqual(strict.copy({
-          allowSelfLoops: true
-        }).allowSelfLoops, true);
-
-        _assert["default"]["throws"](function () {
-          strict.copy({
-            type: 'undirected'
-          });
-        }, usage());
-
-        _assert["default"]["throws"](function () {
-          loose.copy({
-            type: 'undirected'
-          });
-        }, usage());
-
-        _assert["default"]["throws"](function () {
-          loose.copy({
-            multi: false
-          });
-        }, usage());
-
-        _assert["default"]["throws"](function () {
-          loose.copy({
-            allowSelfLoops: false
-          });
-        }, usage());
-      }
-    }
-  };
-}
\ No newline at end of file
diff --git a/libs/shared/graph-layouts/node_modules/obliterator/LICENSE.txt b/libs/shared/graph-layouts/node_modules/obliterator/LICENSE.txt
deleted file mode 100644
index df12ee58e..000000000
--- a/libs/shared/graph-layouts/node_modules/obliterator/LICENSE.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2017-2021 Guillaume Plique (Yomguithereal)
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
diff --git a/libs/shared/graph-layouts/node_modules/obliterator/README.md b/libs/shared/graph-layouts/node_modules/obliterator/README.md
deleted file mode 100644
index 8f3fc6656..000000000
--- a/libs/shared/graph-layouts/node_modules/obliterator/README.md
+++ /dev/null
@@ -1,415 +0,0 @@
-[![Build Status](https://github.com/Yomguithereal/obliterator/workflows/Tests/badge.svg)](https://github.com/Yomguithereal/obliterator/actions)
-
-# Obliterator
-
-Obliterator is a dead simple JavaScript/TypeScript library providing miscellaneous higher-order iterator/iterable functions such as combining two or more iterators into a single one.
-
-Note that when possible, `obliterator` also consider sequences such as arrays, strings etc. as valid iterables (although they are not proper ES6 iterables values), for convenience.
-
-# Installation
-
-```
-npm install --save obliterator
-```
-
-Note that `obliterator` comes along with its TypeScript declarations.
-
-# Usage
-
-## Summary
-
-_Classes_
-
-- [Iterator](#iterator)
-
-_Functions_
-
-- [chain](#chain)
-- [combinations](#combinations)
-- [consume](#consume)
-- [every](#every)
-- [filter](#filter)
-- [find](#find)
-- [forEach](#foreach)
-- [forEachWithNullKeys](#foreachwithnullkeys)
-- [includes](#includes)
-- [iter](#iter)
-- [map](#map)
-- [match](#match)
-- [permutations](#permutations)
-- [powerSet](#powerSet)
-- [some](#some)
-- [split](#split)
-- [take](#take)
-
-## Iterator
-
-A handy Iterator class easily usable with ES2015's `for ... of` loop constructs & spread operator.
-
-```js
-import Iterator from 'obliterator/iterator';
-// Or
-import {Iterator} from 'obliterator';
-
-const iterator = new Iterator(function () {
-  // Define what the `next` function does
-  return {done: false, value: 34};
-});
-
-// Checking that the given value is an iterator (native or else)
-Iterator.is(value);
-
-// Creating an empty iterator
-const emptyIterator = Iterator.empty();
-
-// Creating a simple iterator from a single value
-const simpleIterator = Iterator.of(34);
-
-// Creating a simple iterator from multiple values
-const multipleIterator = Iterator.of(1, 2, 3);
-```
-
-## chain
-
-Variadic function chaining all the given iterable-like values.
-
-```js
-import chain from 'obliterator/chain';
-// Or
-import {chain} from 'obliterator';
-
-const set1 = new Set('a');
-const set2 = new Set('bc');
-
-const chained = chain(set1.values(), set2);
-
-chained.next();
->>> {done: false, value: 'a'}
-chained.next();
->>> {done: false, value: 'b'}
-```
-
-## combinations
-
-Returns an iterator of combinations of the given array and of the given size.
-
-Note that for performance reasons, the yielded combination is always the same object.
-
-```js
-import combinations from 'obliterator/combinations';
-// Or
-import {combinations} from 'obliterator';
-
-const iterator = combinations(['A', 'B', 'C', 'D'], 2);
-
-iterator.next().value;
->>> ['A', 'B']
-iterator.next().value;
->>> ['A', 'C']
-```
-
-## consume
-
-Function consuming the given iterator fully or for n steps.
-
-```js
-import consume from 'obliterator/consume';
-// Or
-import {consume} from 'obliterator';
-
-const set = new Set([1, 2, 3]);
-
-// Consuming the whole iterator
-let iterator = set.values();
-consume(iterator);
-iterator.next().done >>> true;
-
-// Consuming n steps
-let iterator = set.values();
-consume(iterator, 2);
-iterator.next().value >>> 3;
-```
-
-## every
-
-Function returning whether all items of an iterable-like match the given predicate function.
-
-```js
-import every from 'obliterator/every';
-// Or
-import {every} from 'obliterator';
-
-every([2, 4, 6], n => n % 2 === 0);
->>> true
-
-every([1, 2, 3], n => n % 2 === 0);
->>> false
-```
-
-## filter
-
-Function returning an iterator filtering another one's values using the given predicate function.
-
-```js
-import filter from 'obliterator/filter';
-// Or
-import {filter} from 'obliterator';
-
-const set = new Set([1, 2, 3, 4, 5]);
-
-const even = x => x % 2 === 0;
-
-const iterator = filter(set.values(), even);
-
-iterator.next().value >>> 2;
-iterator.next().value >>> 4;
-```
-
-## find
-
-Function returning the next item matching given predicate function in an iterable-like.
-
-```js
-import find from 'obliterator/find';
-// Or
-import {find} from 'obliterator';
-
-const set = new Set([1, 2, 3, 4, 5]);
-
-const even = x => x % 2 === 0;
-
-const values = set.values();
-
-find(values, even);
->>> 2
-
-find(values, even);
->>> 4
-
-find(values, even);
->>> undefined
-```
-
-## forEach
-
-Function able to iterate over almost any JavaScript iterable value using a callback.
-
-Supported values range from arrays, typed arrays, sets, maps, objects, strings, arguments, iterators, arbitrary iterables etc.
-
-```js
-import forEach from 'obliterator/foreach';
-// Or
-import {forEach} from 'obliterator';
-
-const set = new Set(['apple', 'banana']);
-
-forEach(set.values(), (value, i) => {
-  console.log(i, value);
-});
-
-// Iterating over a string
-forEach('abc', (char, i) => ...);
-
-// Iterating over a map
-forEach(map, (value, key) => ...);
-```
-
-## forEachWithNullKeys
-
-Variant of [forEach](#foreach) one can use to iterate over mixed values but with the twist that iterables without proper keys (lists, sets etc.), will yield `null` instead of an index key.
-
-Supported values range from arrays, typed arrays, sets, maps, objects, strings, arguments, iterators, arbitrary iterables etc.
-
-```js
-import {forEachWithNullKeys} from 'obliterator/foreach';
-
-const set = new Set(['apple', 'banana']);
-
-forEach(set, (value, key) => {
-  console.log(key, value);
-});
->>> null, 'apple'
->>> null, 'banana'
-```
-
-## includes
-
-Function returning whether the given value can be found in given iterable-like.
-
-```js
-import {includes} from 'obliterator';
-// Or
-import includes from 'obliterator/includes';
-
-includes([1, 2, 3], 3);
->>> true;
-
-includes('test', 'a');
->>> false;
-```
-
-## iter
-
-Function casting any iterable-like value to a proper iterator. Will throw an error if the given value cannot be cast as an iterator.
-
-```js
-import {iter} from 'obliterator';
-// Or
-import iter from 'obliterator/iter';
-
-iter('test');
-iter(new Set([1, 2, 3]));
-
-// This will throw:
-iter(null);
-```
-
-## map
-
-Function returning an iterator mapping another one's values using the given function.
-
-```js
-import map from 'obliterator/map';
-// Or
-import {map} from 'obliterator';
-
-const set = new Set([1, 2, 3, 4, 5]);
-
-const triple = x => x * 3;
-
-const iterator = map(set.values(), triple);
-
-iterator.next().value >>> 3;
-iterator.next().value >>> 6;
-```
-
-## match
-
-Function returning an iterator over the matches of a given regex applied to the target string.
-
-```js
-import match from 'obliterator/match';
-// Or
-import {match} from 'obliterator';
-
-const iterator = match(/t/, 'test');
-
-iterator.next().value.index >>> 0;
-iterator.next().value.index >>> 3;
-```
-
-## permutations
-
-Returns an iterator of permutations of the given array and of the given size.
-
-Note that for performance reasons, the yielded permutation is always the same object.
-
-```js
-import permutations from 'obliterator/permutations';
-// Or
-import {permutations} from 'obliterator';
-
-let iterator = permutations([1, 2, 3]);
-
-iterator.next().value
->>> [1, 2, 3]
-iterator.next().value
->>> [1, 3, 2]
-
-iterator = permutations(['A', 'B', 'C', 'D'], 2);
-
-iterator.next().value;
->>> ['A', 'B']
-iterator.next().value;
->>> ['A', 'C']
-```
-
-## powerSet
-
-Returns an iterator of sets composing the power set of the given array.
-
-```js
-import powerSet from 'obliterator/power-set';
-// Or
-import {powerSet} from 'obliterator';
-
-const iterator = powerSet(['A', 'B', 'C']);
-
-iterator.next().value;
->>> []
-iterator.next().value;
->>> ['A']
-```
-
-## some
-
-Returns whether the given iterable-like has some item matching the given predicate function.
-
-```js
-import some from 'obliterator/some';
-// Or
-import {some} from 'obliterator';
-
-some(new Set([1, 2, 3]), n => n % 2 === 0);
->>> true
-
-some('test', c => c === 'a');
->>> false
-```
-
-## split
-
-Returns an iterator over the splits of the target string, according to the given RegExp pattern.
-
-```js
-import split from 'obliterator/split';
-// Or
-import {split} from 'obliterator';
-
-const iterator = split(/;/g, 'hello;world;super');
-
-iterator.next().value;
->>> 'hello'
-iterator.next().value;
->>> 'world'
-```
-
-## take
-
-Function taking values from given iterator and returning them in an array.
-
-```js
-import take from 'obliterator/take';
-// Or
-import {take} from 'obliterator';
-
-const set = new Set([1, 2, 3]);
-
-// To take n values from the iterator
-take(set.values(), 2);
->>> [1, 2]
-
-// To convert the full iterator into an array
-take(set.values());
->>> [1, 2, 3]
-```
-
-# Contribution
-
-Contributions are obviously welcome. Please be sure to lint the code & add the relevant unit tests before submitting any PR.
-
-```
-git clone git@github.com:Yomguithereal/obliterator.git
-cd obliterator
-npm install
-
-# To lint the code
-npm run lint
-
-# To run the unit tests
-npm test
-```
-
-# License
-
-[MIT](LICENSE.txt)
diff --git a/libs/shared/graph-layouts/node_modules/obliterator/chain.d.ts b/libs/shared/graph-layouts/node_modules/obliterator/chain.d.ts
deleted file mode 100644
index 7cc4c78db..000000000
--- a/libs/shared/graph-layouts/node_modules/obliterator/chain.d.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-import type {IntoInterator} from './types';
-
-export default function chain<T>(
-  ...iterables: IntoInterator<T>[]
-): IterableIterator<T>;
diff --git a/libs/shared/graph-layouts/node_modules/obliterator/chain.js b/libs/shared/graph-layouts/node_modules/obliterator/chain.js
deleted file mode 100644
index 00eb68dce..000000000
--- a/libs/shared/graph-layouts/node_modules/obliterator/chain.js
+++ /dev/null
@@ -1,46 +0,0 @@
-/**
- * Obliterator Chain Function
- * ===========================
- *
- * Variadic function combining the given iterables.
- */
-var Iterator = require('./iterator.js');
-var iter = require('./iter.js');
-
-/**
- * Chain.
- *
- * @param  {...Iterator} iterables - Target iterables.
- * @return {Iterator}
- */
-module.exports = function chain() {
-  var iterables = arguments;
-  var current = null;
-  var i = -1;
-
-  /* eslint-disable no-constant-condition */
-  return new Iterator(function next() {
-    var step = null;
-
-    do {
-      if (current === null) {
-        i++;
-
-        if (i >= iterables.length) return {done: true};
-
-        current = iter(iterables[i]);
-      }
-
-      step = current.next();
-
-      if (step.done === true) {
-        current = null;
-        continue;
-      }
-
-      break;
-    } while (true);
-
-    return step;
-  });
-};
diff --git a/libs/shared/graph-layouts/node_modules/obliterator/combinations.d.ts b/libs/shared/graph-layouts/node_modules/obliterator/combinations.d.ts
deleted file mode 100644
index 901a0eaa9..000000000
--- a/libs/shared/graph-layouts/node_modules/obliterator/combinations.d.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-export default function combinations<T>(
-  array: Array<T>,
-  r: number
-): IterableIterator<Array<T>>;
diff --git a/libs/shared/graph-layouts/node_modules/obliterator/combinations.js b/libs/shared/graph-layouts/node_modules/obliterator/combinations.js
deleted file mode 100644
index c60099d32..000000000
--- a/libs/shared/graph-layouts/node_modules/obliterator/combinations.js
+++ /dev/null
@@ -1,76 +0,0 @@
-/**
- * Obliterator Combinations Function
- * ==================================
- *
- * Iterator returning combinations of the given array.
- */
-var Iterator = require('./iterator.js');
-
-/**
- * Helper mapping indices to items.
- */
-function indicesToItems(target, items, indices, r) {
-  for (var i = 0; i < r; i++) target[i] = items[indices[i]];
-}
-
-/**
- * Combinations.
- *
- * @param  {array}    array - Target array.
- * @param  {number}   r     - Size of the subsequences.
- * @return {Iterator}
- */
-module.exports = function combinations(array, r) {
-  if (!Array.isArray(array))
-    throw new Error(
-      'obliterator/combinations: first argument should be an array.'
-    );
-
-  var n = array.length;
-
-  if (typeof r !== 'number')
-    throw new Error(
-      'obliterator/combinations: second argument should be omitted or a number.'
-    );
-
-  if (r > n)
-    throw new Error(
-      'obliterator/combinations: the size of the subsequences should not exceed the length of the array.'
-    );
-
-  if (r === n) return Iterator.of(array.slice());
-
-  var indices = new Array(r),
-    subsequence = new Array(r),
-    first = true,
-    i;
-
-  for (i = 0; i < r; i++) indices[i] = i;
-
-  return new Iterator(function next() {
-    if (first) {
-      first = false;
-
-      indicesToItems(subsequence, array, indices, r);
-      return {value: subsequence, done: false};
-    }
-
-    if (indices[r - 1]++ < n - 1) {
-      indicesToItems(subsequence, array, indices, r);
-      return {value: subsequence, done: false};
-    }
-
-    i = r - 2;
-
-    while (i >= 0 && indices[i] >= n - (r - i)) --i;
-
-    if (i < 0) return {done: true};
-
-    indices[i]++;
-
-    while (++i < r) indices[i] = indices[i - 1] + 1;
-
-    indicesToItems(subsequence, array, indices, r);
-    return {value: subsequence, done: false};
-  });
-};
diff --git a/libs/shared/graph-layouts/node_modules/obliterator/consume.d.ts b/libs/shared/graph-layouts/node_modules/obliterator/consume.d.ts
deleted file mode 100644
index 16812ee0e..000000000
--- a/libs/shared/graph-layouts/node_modules/obliterator/consume.d.ts
+++ /dev/null
@@ -1 +0,0 @@
-export default function consume<T>(iterator: Iterator<T>, steps?: number): void;
diff --git a/libs/shared/graph-layouts/node_modules/obliterator/consume.js b/libs/shared/graph-layouts/node_modules/obliterator/consume.js
deleted file mode 100644
index 1fa700749..000000000
--- a/libs/shared/graph-layouts/node_modules/obliterator/consume.js
+++ /dev/null
@@ -1,29 +0,0 @@
-/* eslint no-constant-condition: 0 */
-/**
- * Obliterator Consume Function
- * =============================
- *
- * Function consuming the given iterator for n or every steps.
- */
-
-/**
- * Consume.
- *
- * @param  {Iterator} iterator - Target iterator.
- * @param  {number}   [steps]  - Optional steps.
- */
-module.exports = function consume(iterator, steps) {
-  var step,
-    l = arguments.length > 1 ? steps : Infinity,
-    i = 0;
-
-  while (true) {
-    if (i === l) return;
-
-    step = iterator.next();
-
-    if (step.done) return;
-
-    i++;
-  }
-};
diff --git a/libs/shared/graph-layouts/node_modules/obliterator/every.d.ts b/libs/shared/graph-layouts/node_modules/obliterator/every.d.ts
deleted file mode 100644
index 361fd48e2..000000000
--- a/libs/shared/graph-layouts/node_modules/obliterator/every.d.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import type {IntoInterator} from './types';
-
-type PredicateFunction<T> = (item: T) => boolean;
-
-export default function every<T>(
-  target: IntoInterator<T>,
-  predicate: PredicateFunction<T>
-): boolean;
diff --git a/libs/shared/graph-layouts/node_modules/obliterator/every.js b/libs/shared/graph-layouts/node_modules/obliterator/every.js
deleted file mode 100644
index f2d296c94..000000000
--- a/libs/shared/graph-layouts/node_modules/obliterator/every.js
+++ /dev/null
@@ -1,27 +0,0 @@
-/**
- * Obliterator Every Function
- * ==========================
- *
- * Function taking an iterable and a predicate and returning whether all
- * its items match the given predicate.
- */
-var iter = require('./iter.js');
-
-/**
- * Every.
- *
- * @param  {Iterable} iterable  - Target iterable.
- * @param  {function} predicate - Predicate function.
- * @return {boolean}
- */
-module.exports = function every(iterable, predicate) {
-  var iterator = iter(iterable);
-
-  var step;
-
-  while (((step = iterator.next()), !step.done)) {
-    if (!predicate(step.value)) return false;
-  }
-
-  return true;
-};
diff --git a/libs/shared/graph-layouts/node_modules/obliterator/filter.d.ts b/libs/shared/graph-layouts/node_modules/obliterator/filter.d.ts
deleted file mode 100644
index 91982950c..000000000
--- a/libs/shared/graph-layouts/node_modules/obliterator/filter.d.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import type {IntoInterator} from './types';
-
-type PredicateFunction<T> = (item: T) => boolean;
-
-export default function filter<T>(
-  target: IntoInterator<T>,
-  predicate: PredicateFunction<T>
-): IterableIterator<T>;
diff --git a/libs/shared/graph-layouts/node_modules/obliterator/filter.js b/libs/shared/graph-layouts/node_modules/obliterator/filter.js
deleted file mode 100644
index b17945e0e..000000000
--- a/libs/shared/graph-layouts/node_modules/obliterator/filter.js
+++ /dev/null
@@ -1,28 +0,0 @@
-/**
- * Obliterator Filter Function
- * ===========================
- *
- * Function returning a iterator filtering the given iterator.
- */
-var Iterator = require('./iterator.js');
-var iter = require('./iter.js');
-
-/**
- * Filter.
- *
- * @param  {Iterable} target    - Target iterable.
- * @param  {function} predicate - Predicate function.
- * @return {Iterator}
- */
-module.exports = function filter(target, predicate) {
-  var iterator = iter(target);
-  var step;
-
-  return new Iterator(function () {
-    do {
-      step = iterator.next();
-    } while (!step.done && !predicate(step.value));
-
-    return step;
-  });
-};
diff --git a/libs/shared/graph-layouts/node_modules/obliterator/find.d.ts b/libs/shared/graph-layouts/node_modules/obliterator/find.d.ts
deleted file mode 100644
index e3dea30c8..000000000
--- a/libs/shared/graph-layouts/node_modules/obliterator/find.d.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import type {IntoInterator} from './types';
-
-type PredicateFunction<T> = (item: T) => boolean;
-
-export default function find<T>(
-  target: IntoInterator<T>,
-  predicate: PredicateFunction<T>
-): T | undefined;
diff --git a/libs/shared/graph-layouts/node_modules/obliterator/find.js b/libs/shared/graph-layouts/node_modules/obliterator/find.js
deleted file mode 100644
index d7641cebf..000000000
--- a/libs/shared/graph-layouts/node_modules/obliterator/find.js
+++ /dev/null
@@ -1,27 +0,0 @@
-/**
- * Obliterator Find Function
- * ==========================
- *
- * Function taking an iterable and a predicate and returning the first item
- * matching the given predicate.
- */
-var iter = require('./iter.js');
-
-/**
- * Find.
- *
- * @param  {Iterable} iterable  - Target iterable.
- * @param  {function} predicate - Predicate function.
- * @return {boolean}
- */
-module.exports = function find(iterable, predicate) {
-  var iterator = iter(iterable);
-
-  var step;
-
-  while (((step = iterator.next()), !step.done)) {
-    if (predicate(step.value)) return step.value;
-  }
-
-  return;
-};
diff --git a/libs/shared/graph-layouts/node_modules/obliterator/foreach-with-null-keys.d.ts b/libs/shared/graph-layouts/node_modules/obliterator/foreach-with-null-keys.d.ts
deleted file mode 100644
index 0b3073826..000000000
--- a/libs/shared/graph-layouts/node_modules/obliterator/foreach-with-null-keys.d.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-import type {Sequence} from './types';
-
-interface ForEachTrait<K, V> {
-  forEach(callback: (value: V, key: K, self: this) => void): void;
-}
-
-interface PlainObject<T> {
-  [key: string]: T;
-}
-
-export default function forEachWithNullKeys<V>(
-  iterable: Set<V>,
-  callback: (value: V, key: null) => void
-): void;
-
-export default function forEachWithNullKeys<K, V>(
-  iterable: ForEachTrait<K, V>,
-  callback: (value: V, key: K) => void
-): void;
-
-export default function forEachWithNullKeys<T>(
-  iterable: Iterator<T> | Iterable<T> | Sequence<T>,
-  callback: (item: T, key: null) => void
-): void;
-
-export default function forEachWithNullKeys<T>(
-  object: PlainObject<T>,
-  callback: (value: T, key: string) => void
-): void;
diff --git a/libs/shared/graph-layouts/node_modules/obliterator/foreach-with-null-keys.js b/libs/shared/graph-layouts/node_modules/obliterator/foreach-with-null-keys.js
deleted file mode 100644
index 97135add1..000000000
--- a/libs/shared/graph-layouts/node_modules/obliterator/foreach-with-null-keys.js
+++ /dev/null
@@ -1,83 +0,0 @@
-/**
- * Obliterator ForEachWithNullKeys Function
- * =========================================
- *
- * Helper function used to easily iterate over mixed values.
- */
-var support = require('./support.js');
-
-var ARRAY_BUFFER_SUPPORT = support.ARRAY_BUFFER_SUPPORT;
-var SYMBOL_SUPPORT = support.SYMBOL_SUPPORT;
-
-/**
- * Same function as the `forEach` but will yield `null` when the target
- * does not have keys.
- *
- * @param  {any}      iterable - Iterable value.
- * @param  {function} callback - Callback function.
- */
-module.exports = function forEachWithNullKeys(iterable, callback) {
-  var iterator, k, i, l, s;
-
-  if (!iterable)
-    throw new Error('obliterator/forEachWithNullKeys: invalid iterable.');
-
-  if (typeof callback !== 'function')
-    throw new Error('obliterator/forEachWithNullKeys: expecting a callback.');
-
-  // The target is an array or a string or function arguments
-  if (
-    Array.isArray(iterable) ||
-    (ARRAY_BUFFER_SUPPORT && ArrayBuffer.isView(iterable)) ||
-    typeof iterable === 'string' ||
-    iterable.toString() === '[object Arguments]'
-  ) {
-    for (i = 0, l = iterable.length; i < l; i++) callback(iterable[i], null);
-    return;
-  }
-
-  // The target is a Set
-  if (iterable instanceof Set) {
-    iterable.forEach(function (value) {
-      callback(value, null);
-    });
-    return;
-  }
-
-  // The target has a #.forEach method
-  if (typeof iterable.forEach === 'function') {
-    iterable.forEach(callback);
-    return;
-  }
-
-  // The target is iterable
-  if (
-    SYMBOL_SUPPORT &&
-    Symbol.iterator in iterable &&
-    typeof iterable.next !== 'function'
-  ) {
-    iterable = iterable[Symbol.iterator]();
-  }
-
-  // The target is an iterator
-  if (typeof iterable.next === 'function') {
-    iterator = iterable;
-    i = 0;
-
-    while (((s = iterator.next()), s.done !== true)) {
-      callback(s.value, null);
-      i++;
-    }
-
-    return;
-  }
-
-  // The target is a plain object
-  for (k in iterable) {
-    if (iterable.hasOwnProperty(k)) {
-      callback(iterable[k], k);
-    }
-  }
-
-  return;
-};
diff --git a/libs/shared/graph-layouts/node_modules/obliterator/foreach.d.ts b/libs/shared/graph-layouts/node_modules/obliterator/foreach.d.ts
deleted file mode 100644
index db0bac77e..000000000
--- a/libs/shared/graph-layouts/node_modules/obliterator/foreach.d.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-import type {Sequence} from './types';
-
-interface ForEachTrait<K, V> {
-  forEach(callback: (value: V, key: K, self: this) => void): void;
-}
-
-interface PlainObject<T> {
-  [key: string]: T;
-}
-
-export default function forEach<K, V>(
-  iterable: ForEachTrait<K, V>,
-  callback: (value: V, key: K) => void
-): void;
-
-export default function forEach<T>(
-  iterable: Iterator<T> | Iterable<T> | Sequence<T>,
-  callback: (item: T, index: number) => void
-): void;
-
-export default function forEach<T>(
-  object: PlainObject<T>,
-  callback: (value: T, key: string) => void
-): void;
diff --git a/libs/shared/graph-layouts/node_modules/obliterator/foreach.js b/libs/shared/graph-layouts/node_modules/obliterator/foreach.js
deleted file mode 100644
index 84af94fe9..000000000
--- a/libs/shared/graph-layouts/node_modules/obliterator/foreach.js
+++ /dev/null
@@ -1,73 +0,0 @@
-/**
- * Obliterator ForEach Function
- * =============================
- *
- * Helper function used to easily iterate over mixed values.
- */
-var support = require('./support.js');
-
-var ARRAY_BUFFER_SUPPORT = support.ARRAY_BUFFER_SUPPORT;
-var SYMBOL_SUPPORT = support.SYMBOL_SUPPORT;
-
-/**
- * Function able to iterate over almost any iterable JS value.
- *
- * @param  {any}      iterable - Iterable value.
- * @param  {function} callback - Callback function.
- */
-module.exports = function forEach(iterable, callback) {
-  var iterator, k, i, l, s;
-
-  if (!iterable) throw new Error('obliterator/forEach: invalid iterable.');
-
-  if (typeof callback !== 'function')
-    throw new Error('obliterator/forEach: expecting a callback.');
-
-  // The target is an array or a string or function arguments
-  if (
-    Array.isArray(iterable) ||
-    (ARRAY_BUFFER_SUPPORT && ArrayBuffer.isView(iterable)) ||
-    typeof iterable === 'string' ||
-    iterable.toString() === '[object Arguments]'
-  ) {
-    for (i = 0, l = iterable.length; i < l; i++) callback(iterable[i], i);
-    return;
-  }
-
-  // The target has a #.forEach method
-  if (typeof iterable.forEach === 'function') {
-    iterable.forEach(callback);
-    return;
-  }
-
-  // The target is iterable
-  if (
-    SYMBOL_SUPPORT &&
-    Symbol.iterator in iterable &&
-    typeof iterable.next !== 'function'
-  ) {
-    iterable = iterable[Symbol.iterator]();
-  }
-
-  // The target is an iterator
-  if (typeof iterable.next === 'function') {
-    iterator = iterable;
-    i = 0;
-
-    while (((s = iterator.next()), s.done !== true)) {
-      callback(s.value, i);
-      i++;
-    }
-
-    return;
-  }
-
-  // The target is a plain object
-  for (k in iterable) {
-    if (iterable.hasOwnProperty(k)) {
-      callback(iterable[k], k);
-    }
-  }
-
-  return;
-};
diff --git a/libs/shared/graph-layouts/node_modules/obliterator/includes.d.ts b/libs/shared/graph-layouts/node_modules/obliterator/includes.d.ts
deleted file mode 100644
index 1a8f9de2b..000000000
--- a/libs/shared/graph-layouts/node_modules/obliterator/includes.d.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-import type {IntoInterator} from './types';
-
-export default function includes<T>(
-  target: IntoInterator<T>,
-  value: T
-): boolean;
diff --git a/libs/shared/graph-layouts/node_modules/obliterator/includes.js b/libs/shared/graph-layouts/node_modules/obliterator/includes.js
deleted file mode 100644
index 01c788b57..000000000
--- a/libs/shared/graph-layouts/node_modules/obliterator/includes.js
+++ /dev/null
@@ -1,27 +0,0 @@
-/**
- * Obliterator Includes Function
- * ==============================
- *
- * Function taking an iterable and returning whether the given item can be
- * found in it.
- */
-var iter = require('./iter.js');
-
-/**
- * Includes.
- *
- * @param  {Iterable} iterable  - Target iterable.
- * @param  {function} value     - Searched value.
- * @return {boolean}
- */
-module.exports = function includes(iterable, value) {
-  var iterator = iter(iterable);
-
-  var step;
-
-  while (((step = iterator.next()), !step.done)) {
-    if (step.value === value) return true;
-  }
-
-  return false;
-};
diff --git a/libs/shared/graph-layouts/node_modules/obliterator/index.d.ts b/libs/shared/graph-layouts/node_modules/obliterator/index.d.ts
deleted file mode 100644
index 4a0371419..000000000
--- a/libs/shared/graph-layouts/node_modules/obliterator/index.d.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-export {default as Iterator} from './iterator';
-export {default as iter} from './iter';
-export {default as chain} from './chain';
-export {default as combinations} from './combinations';
-export {default as consume} from './consume';
-export {default as every} from './every';
-export {default as filter} from './filter';
-export {default as find} from './find';
-export {default as forEach} from './foreach';
-export {default as forEachWithNullKeys} from './foreach-with-null-keys';
-export {default as includes} from './includes';
-export {default as map} from './map';
-export {default as match} from './match';
-export {default as permutations} from './permutations';
-export {default as powerSet} from './power-set';
-export {default as range} from './range';
-export {default as some} from './some';
-export {default as split} from './split';
-export {default as take} from './take';
-export {default as takeInto} from './take-into';
diff --git a/libs/shared/graph-layouts/node_modules/obliterator/index.js b/libs/shared/graph-layouts/node_modules/obliterator/index.js
deleted file mode 100644
index a55393a5d..000000000
--- a/libs/shared/graph-layouts/node_modules/obliterator/index.js
+++ /dev/null
@@ -1,26 +0,0 @@
-/**
- * Obliterator Library Endpoint
- * =============================
- *
- * Exporting the library's functions.
- */
-exports.Iterator = require('./iterator.js');
-exports.iter = require('./iter.js');
-exports.chain = require('./chain.js');
-exports.combinations = require('./combinations.js');
-exports.consume = require('./consume.js');
-exports.every = require('./every.js');
-exports.filter = require('./filter.js');
-exports.find = require('./find.js');
-exports.forEach = require('./foreach.js');
-exports.forEachWithNullKeys = require('./foreach-with-null-keys.js');
-exports.includes = require('./includes.js');
-exports.map = require('./map.js');
-exports.match = require('./match.js');
-exports.permutations = require('./permutations.js');
-exports.powerSet = require('./power-set.js');
-exports.range = require('./range.js');
-exports.some = require('./some.js');
-exports.split = require('./split.js');
-exports.take = require('./take.js');
-exports.takeInto = require('./take-into.js');
diff --git a/libs/shared/graph-layouts/node_modules/obliterator/iter.d.ts b/libs/shared/graph-layouts/node_modules/obliterator/iter.d.ts
deleted file mode 100644
index 55377454d..000000000
--- a/libs/shared/graph-layouts/node_modules/obliterator/iter.d.ts
+++ /dev/null
@@ -1 +0,0 @@
-export default function iter<T>(target: unknown): Iterator<T>;
diff --git a/libs/shared/graph-layouts/node_modules/obliterator/iter.js b/libs/shared/graph-layouts/node_modules/obliterator/iter.js
deleted file mode 100644
index 12ab82f30..000000000
--- a/libs/shared/graph-layouts/node_modules/obliterator/iter.js
+++ /dev/null
@@ -1,46 +0,0 @@
-/**
- * Obliterator Iter Function
- * ==========================
- *
- * Function coercing values to an iterator. It can be quite useful when needing
- * to handle iterables and iterators the same way.
- */
-var Iterator = require('./iterator.js');
-var support = require('./support.js');
-
-var ARRAY_BUFFER_SUPPORT = support.ARRAY_BUFFER_SUPPORT;
-var SYMBOL_SUPPORT = support.SYMBOL_SUPPORT;
-
-function iterOrNull(target) {
-  // Indexed sequence
-  if (
-    typeof target === 'string' ||
-    Array.isArray(target) ||
-    (ARRAY_BUFFER_SUPPORT && ArrayBuffer.isView(target))
-  )
-    return Iterator.fromSequence(target);
-
-  // Invalid value
-  if (typeof target !== 'object' || target === null) return null;
-
-  // Iterable
-  if (SYMBOL_SUPPORT && typeof target[Symbol.iterator] === 'function')
-    return target[Symbol.iterator]();
-
-  // Iterator duck-typing
-  if (typeof target.next === 'function') return target;
-
-  // Invalid object
-  return null;
-}
-
-module.exports = function iter(target) {
-  var iterator = iterOrNull(target);
-
-  if (!iterator)
-    throw new Error(
-      'obliterator: target is not iterable nor a valid iterator.'
-    );
-
-  return iterator;
-};
diff --git a/libs/shared/graph-layouts/node_modules/obliterator/iterator.d.ts b/libs/shared/graph-layouts/node_modules/obliterator/iterator.d.ts
deleted file mode 100644
index 8b10451a6..000000000
--- a/libs/shared/graph-layouts/node_modules/obliterator/iterator.d.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-import type {Sequence} from './types';
-
-type NextFunction<V> = () => IteratorResult<V>;
-
-export default class ObliteratorIterator<V> implements IterableIterator<V> {
-  // Constructor
-  constructor(next: NextFunction<V>);
-
-  // Well-known methods
-  next(): IteratorResult<V>;
-  [Symbol.iterator](): IterableIterator<V>;
-
-  // Static methods
-  static of<T>(...args: T[]): ObliteratorIterator<T>;
-  static empty<T>(): ObliteratorIterator<T>;
-  static is(value: any): boolean;
-  static fromSequence<T>(sequence: Sequence<T>): ObliteratorIterator<T>;
-}
diff --git a/libs/shared/graph-layouts/node_modules/obliterator/iterator.js b/libs/shared/graph-layouts/node_modules/obliterator/iterator.js
deleted file mode 100644
index aa2418924..000000000
--- a/libs/shared/graph-layouts/node_modules/obliterator/iterator.js
+++ /dev/null
@@ -1,96 +0,0 @@
-/**
- * Obliterator Iterator Class
- * ===========================
- *
- * Simple class representing the library's iterators.
- */
-
-/**
- * Iterator class.
- *
- * @constructor
- * @param {function} next - Next function.
- */
-function Iterator(next) {
-  if (typeof next !== 'function')
-    throw new Error('obliterator/iterator: expecting a function!');
-
-  this.next = next;
-}
-
-/**
- * If symbols are supported, we add `next` to `Symbol.iterator`.
- */
-if (typeof Symbol !== 'undefined')
-  Iterator.prototype[Symbol.iterator] = function () {
-    return this;
-  };
-
-/**
- * Returning an iterator of the given values.
- *
- * @param  {any...} values - Values.
- * @return {Iterator}
- */
-Iterator.of = function () {
-  var args = arguments,
-    l = args.length,
-    i = 0;
-
-  return new Iterator(function () {
-    if (i >= l) return {done: true};
-
-    return {done: false, value: args[i++]};
-  });
-};
-
-/**
- * Returning an empty iterator.
- *
- * @return {Iterator}
- */
-Iterator.empty = function () {
-  var iterator = new Iterator(function () {
-    return {done: true};
-  });
-
-  return iterator;
-};
-
-/**
- * Returning an iterator over the given indexed sequence.
- *
- * @param  {string|Array} sequence - Target sequence.
- * @return {Iterator}
- */
-Iterator.fromSequence = function (sequence) {
-  var i = 0,
-    l = sequence.length;
-
-  return new Iterator(function () {
-    if (i >= l) return {done: true};
-
-    return {done: false, value: sequence[i++]};
-  });
-};
-
-/**
- * Returning whether the given value is an iterator.
- *
- * @param  {any} value - Value.
- * @return {boolean}
- */
-Iterator.is = function (value) {
-  if (value instanceof Iterator) return true;
-
-  return (
-    typeof value === 'object' &&
-    value !== null &&
-    typeof value.next === 'function'
-  );
-};
-
-/**
- * Exporting.
- */
-module.exports = Iterator;
diff --git a/libs/shared/graph-layouts/node_modules/obliterator/map.d.ts b/libs/shared/graph-layouts/node_modules/obliterator/map.d.ts
deleted file mode 100644
index bf087aae5..000000000
--- a/libs/shared/graph-layouts/node_modules/obliterator/map.d.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import type {IntoInterator} from './types';
-
-type MapFunction<S, T> = (item: S) => T;
-
-export default function map<S, T>(
-  target: IntoInterator<S>,
-  predicate: MapFunction<S, T>
-): IterableIterator<T>;
diff --git a/libs/shared/graph-layouts/node_modules/obliterator/map.js b/libs/shared/graph-layouts/node_modules/obliterator/map.js
deleted file mode 100644
index 9efb94100..000000000
--- a/libs/shared/graph-layouts/node_modules/obliterator/map.js
+++ /dev/null
@@ -1,29 +0,0 @@
-/**
- * Obliterator Map Function
- * ===========================
- *
- * Function returning a iterator mapping the given iterator's values.
- */
-var Iterator = require('./iterator.js');
-var iter = require('./iter.js');
-
-/**
- * Map.
- *
- * @param  {Iterator} target - Target iterable.
- * @param  {function} mapper - Map function.
- * @return {Iterator}
- */
-module.exports = function map(target, mapper) {
-  var iterator = iter(target);
-
-  return new Iterator(function next() {
-    var step = iterator.next();
-
-    if (step.done) return step;
-
-    return {
-      value: mapper(step.value)
-    };
-  });
-};
diff --git a/libs/shared/graph-layouts/node_modules/obliterator/match.d.ts b/libs/shared/graph-layouts/node_modules/obliterator/match.d.ts
deleted file mode 100644
index 3ff382efd..000000000
--- a/libs/shared/graph-layouts/node_modules/obliterator/match.d.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-export default function match(
-  pattern: RegExp,
-  string: string
-): IterableIterator<string>;
diff --git a/libs/shared/graph-layouts/node_modules/obliterator/match.js b/libs/shared/graph-layouts/node_modules/obliterator/match.js
deleted file mode 100644
index 86c17fce5..000000000
--- a/libs/shared/graph-layouts/node_modules/obliterator/match.js
+++ /dev/null
@@ -1,43 +0,0 @@
-/**
- * Obliterator Match Function
- * ===========================
- *
- * Function returning an iterator over the matches of the given regex on the
- * target string.
- */
-var Iterator = require('./iterator.js');
-
-/**
- * Match.
- *
- * @param  {RegExp}   pattern - Regular expression to use.
- * @param  {string}   string  - Target string.
- * @return {Iterator}
- */
-module.exports = function match(pattern, string) {
-  var executed = false;
-
-  if (!(pattern instanceof RegExp))
-    throw new Error(
-      'obliterator/match: invalid pattern. Expecting a regular expression.'
-    );
-
-  if (typeof string !== 'string')
-    throw new Error('obliterator/match: invalid target. Expecting a string.');
-
-  return new Iterator(function () {
-    if (executed && !pattern.global) {
-      pattern.lastIndex = 0;
-      return {done: true};
-    }
-
-    executed = true;
-
-    var m = pattern.exec(string);
-
-    if (m) return {value: m};
-
-    pattern.lastIndex = 0;
-    return {done: true};
-  });
-};
diff --git a/libs/shared/graph-layouts/node_modules/obliterator/package.json b/libs/shared/graph-layouts/node_modules/obliterator/package.json
deleted file mode 100644
index c36cb964f..000000000
--- a/libs/shared/graph-layouts/node_modules/obliterator/package.json
+++ /dev/null
@@ -1,46 +0,0 @@
-{
-  "name": "obliterator",
-  "version": "2.0.2",
-  "description": "Higher order iterator library for JavaScript/TypeScript.",
-  "main": "index.js",
-  "types": "index.d.ts",
-  "scripts": {
-    "lint": "eslint *.js",
-    "prepublishOnly": "npm run lint && npm test",
-    "prettier": "prettier --write '*.js' '*.ts'",
-    "test": "mocha test.js && npm run test:types",
-    "test:types": "tsc --lib es2015,dom --noEmit --noImplicitAny --noImplicitReturns ./test-types.ts"
-  },
-  "repository": {
-    "type": "git",
-    "url": "git+https://github.com/yomguithereal/obliterator.git"
-  },
-  "keywords": [
-    "iterator"
-  ],
-  "author": {
-    "name": "Guillaume Plique",
-    "url": "http://github.com/Yomguithereal"
-  },
-  "license": "MIT",
-  "bugs": {
-    "url": "https://github.com/yomguithereal/obliterator/issues"
-  },
-  "homepage": "https://github.com/yomguithereal/obliterator#readme",
-  "devDependencies": {
-    "@yomguithereal/eslint-config": "^4.4.0",
-    "@yomguithereal/prettier-config": "^1.2.0",
-    "eslint": "^8.2.0",
-    "eslint-config-prettier": "^8.3.0",
-    "mocha": "^9.1.3",
-    "prettier": "^2.4.1",
-    "typescript": "^4.4.4"
-  },
-  "eslintConfig": {
-    "extends": [
-      "@yomguithereal/eslint-config",
-      "eslint-config-prettier"
-    ]
-  },
-  "prettier": "@yomguithereal/prettier-config"
-}
diff --git a/libs/shared/graph-layouts/node_modules/obliterator/permutations.d.ts b/libs/shared/graph-layouts/node_modules/obliterator/permutations.d.ts
deleted file mode 100644
index 2e8ef37b6..000000000
--- a/libs/shared/graph-layouts/node_modules/obliterator/permutations.d.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-export default function permutations<T>(
-  array: Array<T>,
-  r: number
-): IterableIterator<Array<T>>;
diff --git a/libs/shared/graph-layouts/node_modules/obliterator/permutations.js b/libs/shared/graph-layouts/node_modules/obliterator/permutations.js
deleted file mode 100644
index 3410ca42c..000000000
--- a/libs/shared/graph-layouts/node_modules/obliterator/permutations.js
+++ /dev/null
@@ -1,94 +0,0 @@
-/**
- * Obliterator Permutations Function
- * ==================================
- *
- * Iterator returning permutations of the given array.
- */
-var Iterator = require('./iterator.js');
-
-/**
- * Helper mapping indices to items.
- */
-function indicesToItems(target, items, indices, r) {
-  for (var i = 0; i < r; i++) target[i] = items[indices[i]];
-}
-
-/**
- * Permutations.
- *
- * @param  {array}    array - Target array.
- * @param  {number}   r     - Size of the subsequences.
- * @return {Iterator}
- */
-module.exports = function permutations(array, r) {
-  if (!Array.isArray(array))
-    throw new Error(
-      'obliterator/permutations: first argument should be an array.'
-    );
-
-  var n = array.length;
-
-  if (arguments.length < 2) r = n;
-
-  if (typeof r !== 'number')
-    throw new Error(
-      'obliterator/permutations: second argument should be omitted or a number.'
-    );
-
-  if (r > n)
-    throw new Error(
-      'obliterator/permutations: the size of the subsequences should not exceed the length of the array.'
-    );
-
-  var indices = new Uint32Array(n),
-    subsequence = new Array(r),
-    cycles = new Uint32Array(r),
-    first = true,
-    i;
-
-  for (i = 0; i < n; i++) {
-    indices[i] = i;
-
-    if (i < r) cycles[i] = n - i;
-  }
-
-  i = r;
-
-  return new Iterator(function next() {
-    if (first) {
-      first = false;
-      indicesToItems(subsequence, array, indices, r);
-      return {value: subsequence, done: false};
-    }
-
-    var tmp, j;
-
-    i--;
-
-    if (i < 0) return {done: true};
-
-    cycles[i]--;
-
-    if (cycles[i] === 0) {
-      tmp = indices[i];
-
-      for (j = i; j < n - 1; j++) indices[j] = indices[j + 1];
-
-      indices[n - 1] = tmp;
-
-      cycles[i] = n - i;
-      return next();
-    } else {
-      j = cycles[i];
-      tmp = indices[i];
-
-      indices[i] = indices[n - j];
-      indices[n - j] = tmp;
-
-      i = r;
-
-      indicesToItems(subsequence, array, indices, r);
-      return {value: subsequence, done: false};
-    }
-  });
-};
diff --git a/libs/shared/graph-layouts/node_modules/obliterator/power-set.d.ts b/libs/shared/graph-layouts/node_modules/obliterator/power-set.d.ts
deleted file mode 100644
index 254094ad7..000000000
--- a/libs/shared/graph-layouts/node_modules/obliterator/power-set.d.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export default function powerSet<T>(
-  array: Array<T>
-): IterableIterator<Array<T>>;
diff --git a/libs/shared/graph-layouts/node_modules/obliterator/power-set.js b/libs/shared/graph-layouts/node_modules/obliterator/power-set.js
deleted file mode 100644
index cd63f9574..000000000
--- a/libs/shared/graph-layouts/node_modules/obliterator/power-set.js
+++ /dev/null
@@ -1,27 +0,0 @@
-/**
- * Obliterator Power Set Function
- * ===============================
- *
- * Iterator returning the power set of the given array.
- */
-var Iterator = require('./iterator.js'),
-  combinations = require('./combinations.js'),
-  chain = require('./chain.js');
-
-/**
- * Power set.
- *
- * @param  {array}    array - Target array.
- * @return {Iterator}
- */
-module.exports = function powerSet(array) {
-  var n = array.length;
-
-  var iterators = new Array(n + 1);
-
-  iterators[0] = Iterator.of([]);
-
-  for (var i = 1; i < n + 1; i++) iterators[i] = combinations(array, i);
-
-  return chain.apply(null, iterators);
-};
diff --git a/libs/shared/graph-layouts/node_modules/obliterator/range.d.ts b/libs/shared/graph-layouts/node_modules/obliterator/range.d.ts
deleted file mode 100644
index bff37072d..000000000
--- a/libs/shared/graph-layouts/node_modules/obliterator/range.d.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-export default function range(end: number): IterableIterator<number>;
-export default function range(
-  start: number,
-  end: number
-): IterableIterator<number>;
-export default function range(
-  start: number,
-  end: number,
-  step: number
-): IterableIterator<number>;
diff --git a/libs/shared/graph-layouts/node_modules/obliterator/range.js b/libs/shared/graph-layouts/node_modules/obliterator/range.js
deleted file mode 100644
index b00f9f02b..000000000
--- a/libs/shared/graph-layouts/node_modules/obliterator/range.js
+++ /dev/null
@@ -1,44 +0,0 @@
-/**
- * Obliterator Range Function
- * ===========================
- *
- * Function returning a range iterator.
- */
-var Iterator = require('./iterator.js');
-
-/**
- * Range.
- *
- * @param  {number} start - Start.
- * @param  {number} end   - End.
- * @param  {number} step  - Step.
- * @return {Iterator}
- */
-module.exports = function range(start, end, step) {
-  if (arguments.length === 1) {
-    end = start;
-    start = 0;
-  }
-
-  if (arguments.length < 3) step = 1;
-
-  var i = start;
-
-  var iterator = new Iterator(function () {
-    if (i < end) {
-      var value = i;
-
-      i += step;
-
-      return {value: value, done: false};
-    }
-
-    return {done: true};
-  });
-
-  iterator.start = start;
-  iterator.end = end;
-  iterator.step = step;
-
-  return iterator;
-};
diff --git a/libs/shared/graph-layouts/node_modules/obliterator/some.d.ts b/libs/shared/graph-layouts/node_modules/obliterator/some.d.ts
deleted file mode 100644
index cccd35f13..000000000
--- a/libs/shared/graph-layouts/node_modules/obliterator/some.d.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import type {IntoInterator} from './types';
-
-type PredicateFunction<T> = (item: T) => boolean;
-
-export default function some<T>(
-  target: IntoInterator<T>,
-  predicate: PredicateFunction<T>
-): boolean;
diff --git a/libs/shared/graph-layouts/node_modules/obliterator/some.js b/libs/shared/graph-layouts/node_modules/obliterator/some.js
deleted file mode 100644
index b7923ee45..000000000
--- a/libs/shared/graph-layouts/node_modules/obliterator/some.js
+++ /dev/null
@@ -1,27 +0,0 @@
-/**
- * Obliterator Some Function
- * ==========================
- *
- * Function taking an iterable and a predicate and returning whether a
- * matching item can be found.
- */
-var iter = require('./iter.js');
-
-/**
- * Some.
- *
- * @param  {Iterable} iterable  - Target iterable.
- * @param  {function} predicate - Predicate function.
- * @return {boolean}
- */
-module.exports = function some(iterable, predicate) {
-  var iterator = iter(iterable);
-
-  var step;
-
-  while (((step = iterator.next()), !step.done)) {
-    if (predicate(step.value)) return true;
-  }
-
-  return false;
-};
diff --git a/libs/shared/graph-layouts/node_modules/obliterator/split.d.ts b/libs/shared/graph-layouts/node_modules/obliterator/split.d.ts
deleted file mode 100644
index 5f54145b4..000000000
--- a/libs/shared/graph-layouts/node_modules/obliterator/split.d.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-export default function split(
-  pattern: RegExp,
-  string: string
-): IterableIterator<string>;
diff --git a/libs/shared/graph-layouts/node_modules/obliterator/split.js b/libs/shared/graph-layouts/node_modules/obliterator/split.js
deleted file mode 100644
index 9a765c0e9..000000000
--- a/libs/shared/graph-layouts/node_modules/obliterator/split.js
+++ /dev/null
@@ -1,68 +0,0 @@
-/**
- * Obliterator Split Function
- * ===========================
- *
- * Function returning an iterator over the pieces of a regex split.
- */
-var Iterator = require('./iterator.js');
-
-/**
- * Function used to make the given pattern global.
- *
- * @param  {RegExp} pattern - Regular expression to make global.
- * @return {RegExp}
- */
-function makeGlobal(pattern) {
-  var flags = 'g';
-
-  if (pattern.multiline) flags += 'm';
-  if (pattern.ignoreCase) flags += 'i';
-  if (pattern.sticky) flags += 'y';
-  if (pattern.unicode) flags += 'u';
-
-  return new RegExp(pattern.source, flags);
-}
-
-/**
- * Split.
- *
- * @param  {RegExp}   pattern - Regular expression to use.
- * @param  {string}   string  - Target string.
- * @return {Iterator}
- */
-module.exports = function split(pattern, string) {
-  if (!(pattern instanceof RegExp))
-    throw new Error(
-      'obliterator/split: invalid pattern. Expecting a regular expression.'
-    );
-
-  if (typeof string !== 'string')
-    throw new Error('obliterator/split: invalid target. Expecting a string.');
-
-  // NOTE: cloning the pattern has a performance cost but side effects for not
-  // doing so might be worse.
-  pattern = makeGlobal(pattern);
-
-  var consumed = false,
-    current = 0;
-
-  return new Iterator(function () {
-    if (consumed) return {done: true};
-
-    var match = pattern.exec(string),
-      value,
-      length;
-
-    if (match) {
-      length = match.index + match[0].length;
-
-      value = string.slice(current, match.index);
-      current = length;
-    } else {
-      consumed = true;
-      value = string.slice(current);
-    }
-
-    return {value: value, done: false};
-  });
-};
diff --git a/libs/shared/graph-layouts/node_modules/obliterator/support.js b/libs/shared/graph-layouts/node_modules/obliterator/support.js
deleted file mode 100644
index 0c00649ae..000000000
--- a/libs/shared/graph-layouts/node_modules/obliterator/support.js
+++ /dev/null
@@ -1,2 +0,0 @@
-exports.ARRAY_BUFFER_SUPPORT = typeof ArrayBuffer !== 'undefined';
-exports.SYMBOL_SUPPORT = typeof Symbol !== 'undefined';
diff --git a/libs/shared/graph-layouts/node_modules/obliterator/take-into.d.ts b/libs/shared/graph-layouts/node_modules/obliterator/take-into.d.ts
deleted file mode 100644
index cb1d4dbe1..000000000
--- a/libs/shared/graph-layouts/node_modules/obliterator/take-into.d.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import type {IntoInterator} from './types';
-
-// Requires a resolution of https://github.com/microsoft/TypeScript/issues/1213
-// export default function takeInto<C<~>, T>(ArrayClass: new <T>(n: number) => C<T>, iterator: Iterator<T>, n: number): C<T>;
-export default function takeInto<T>(
-  ArrayClass: new <T>(arrayLength: number) => T[],
-  iterator: IntoInterator<T>,
-  n: number
-): T[];
diff --git a/libs/shared/graph-layouts/node_modules/obliterator/take-into.js b/libs/shared/graph-layouts/node_modules/obliterator/take-into.js
deleted file mode 100644
index cc2db1875..000000000
--- a/libs/shared/graph-layouts/node_modules/obliterator/take-into.js
+++ /dev/null
@@ -1,39 +0,0 @@
-/* eslint no-constant-condition: 0 */
-/**
- * Obliterator Take Into Function
- * ===============================
- *
- * Same as the take function but enables the user to select an array class
- * in which to insert the retrieved values.
- */
-var iter = require('./iter.js');
-
-/**
- * Take Into.
- *
- * @param  {function} ArrayClass - Array class to use.
- * @param  {Iterable} iterable   - Target iterable.
- * @param  {number}   n          - Number of items to take.
- * @return {array}
- */
-module.exports = function takeInto(ArrayClass, iterable, n) {
-  var array = new ArrayClass(n),
-    step,
-    i = 0;
-
-  var iterator = iter(iterable);
-
-  while (true) {
-    if (i === n) return array;
-
-    step = iterator.next();
-
-    if (step.done) {
-      if (i !== n) return array.slice(0, i);
-
-      return array;
-    }
-
-    array[i++] = step.value;
-  }
-};
diff --git a/libs/shared/graph-layouts/node_modules/obliterator/take.d.ts b/libs/shared/graph-layouts/node_modules/obliterator/take.d.ts
deleted file mode 100644
index 346084841..000000000
--- a/libs/shared/graph-layouts/node_modules/obliterator/take.d.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-import type {IntoInterator} from './types';
-
-export default function take<T>(
-  iterator: IntoInterator<T>,
-  n: number
-): Array<T>;
diff --git a/libs/shared/graph-layouts/node_modules/obliterator/take.js b/libs/shared/graph-layouts/node_modules/obliterator/take.js
deleted file mode 100644
index defe775aa..000000000
--- a/libs/shared/graph-layouts/node_modules/obliterator/take.js
+++ /dev/null
@@ -1,39 +0,0 @@
-/* eslint no-constant-condition: 0 */
-/**
- * Obliterator Take Function
- * ==========================
- *
- * Function taking n or every value of the given iterator and returns them
- * into an array.
- */
-var iter = require('./iter.js');
-
-/**
- * Take.
- *
- * @param  {Iterable} iterable - Target iterable.
- * @param  {number}   [n]      - Optional number of items to take.
- * @return {array}
- */
-module.exports = function take(iterable, n) {
-  var l = arguments.length > 1 ? n : Infinity,
-    array = l !== Infinity ? new Array(l) : [],
-    step,
-    i = 0;
-
-  var iterator = iter(iterable);
-
-  while (true) {
-    if (i === l) return array;
-
-    step = iterator.next();
-
-    if (step.done) {
-      if (i !== n) array.length = i;
-
-      return array;
-    }
-
-    array[i++] = step.value;
-  }
-};
diff --git a/libs/shared/graph-layouts/node_modules/obliterator/types.d.ts b/libs/shared/graph-layouts/node_modules/obliterator/types.d.ts
deleted file mode 100644
index be9cca50e..000000000
--- a/libs/shared/graph-layouts/node_modules/obliterator/types.d.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-export interface Sequence<T> {
-  length: number;
-  slice(from: number, to?: number): Sequence<T>;
-  [index: number]: T;
-}
-
-export type IntoInterator<T> = Iterable<T> | Iterator<T> | Sequence<T>;
diff --git a/libs/shared/graph-layouts/package.json b/libs/shared/graph-layouts/package.json
deleted file mode 100644
index 0833b5d4c..000000000
--- a/libs/shared/graph-layouts/package.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-  "name": "@graphpolaris/graph-layouts",
-  "version": "0.0.1",
-  "type": "commonjs",
-  "dependencies": {
-    "graphology": "^0.24.1"
-  }
-}
diff --git a/libs/shared/graph-layouts/project.json b/libs/shared/graph-layouts/project.json
deleted file mode 100644
index 3f2eab403..000000000
--- a/libs/shared/graph-layouts/project.json
+++ /dev/null
@@ -1,33 +0,0 @@
-{
-  "root": "libs/shared/graph-layouts",
-  "sourceRoot": "libs/shared/graph-layouts/src",
-  "projectType": "library",
-  "targets": {
-    "build": {
-      "executor": "@nrwl/js:tsc",
-      "outputs": ["{options.outputPath}"],
-      "options": {
-        "outputPath": "dist/libs/shared/graph-layouts",
-        "main": "libs/shared/graph-layouts/src/index.ts",
-        "tsConfig": "libs/shared/graph-layouts/tsconfig.lib.json",
-        "assets": ["libs/shared/graph-layouts/*.md"]
-      }
-    },
-    "lint": {
-      "executor": "@nrwl/linter:eslint",
-      "outputs": ["{options.outputFile}"],
-      "options": {
-        "lintFilePatterns": ["libs/shared/graph-layouts/**/*.ts"]
-      }
-    },
-    "test": {
-      "executor": "@nrwl/jest:jest",
-      "outputs": ["coverage/libs/shared/graph-layouts"],
-      "options": {
-        "jestConfig": "libs/shared/graph-layouts/jest.config.js",
-        "passWithNoTests": true
-      }
-    }
-  },
-  "tags": []
-}
diff --git a/libs/shared/graph-layouts/src/index.ts b/libs/shared/graph-layouts/src/index.ts
deleted file mode 100644
index 61989a30a..000000000
--- a/libs/shared/graph-layouts/src/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export * from './lib/shared-graph-layouts';
diff --git a/libs/shared/graph-layouts/src/lib/cytoscape-layouts.ts b/libs/shared/graph-layouts/src/lib/cytoscape-layouts.ts
deleted file mode 100644
index 325377b8f..000000000
--- a/libs/shared/graph-layouts/src/lib/cytoscape-layouts.ts
+++ /dev/null
@@ -1,54 +0,0 @@
-import { Layout } from './layout';
-import { ILayoutFactory, LayoutAlgorithm } from './layout-creator-usecase';
-
-export type CytoscapeProvider = 'Cytoscape';
-
-export type CytoscapeLayoutAlgorithms =
-  | `${CytoscapeProvider}_coupe`
-  | `${CytoscapeProvider}_i4`;
-
-/**
- * This is a ConcreteCreator
- */
-export class CytoscapeFactory
-  implements ILayoutFactory<CytoscapeLayoutAlgorithms>
-{
-  createLayout(LayoutAlgorithm: CytoscapeLayoutAlgorithms): Cytoscape | null {
-    switch (LayoutAlgorithm) {
-      case 'Cytoscape_coupe':
-        return new CytoscapeCoupe();
-      case 'Cytoscape_i4':
-        return new CytoscapeI4();
-      default:
-        return null;
-    }
-  }
-}
-
-export abstract class Cytoscape extends Layout<CytoscapeProvider> {
-  constructor(public override algorithm: LayoutAlgorithm<CytoscapeProvider>) {
-    super('Cytoscape', algorithm);
-  }
-
-  public specialCytoscapeFunction() {
-    console.log('Only Cytoscape Layouts can do this.');
-  }
-}
-
-/**
- * This is a ConcreteProduct
- */
-class CytoscapeI4 extends Cytoscape {
-  constructor() {
-    super('Cytoscape_i4');
-  }
-}
-
-/**
- * This is a ConcreteProduct
- */
-class CytoscapeCoupe extends Cytoscape {
-  constructor() {
-    super('Cytoscape_coupe');
-  }
-}
diff --git a/libs/shared/graph-layouts/src/lib/graphology-layouts.ts b/libs/shared/graph-layouts/src/lib/graphology-layouts.ts
deleted file mode 100644
index 1e609bbe5..000000000
--- a/libs/shared/graph-layouts/src/lib/graphology-layouts.ts
+++ /dev/null
@@ -1,170 +0,0 @@
-import Graph from 'graphology';
-import { circular, random } from 'graphology-layout';
-import forceAtlas2, {
-  ForceAtlas2Settings,
-} from 'graphology-layout-forceatlas2';
-import noverlap from 'graphology-layout-noverlap';
-import { RandomLayoutOptions } from 'graphology-layout/random';
-import { NoverlapSettings } from 'graphology-library/layout-noverlap';
-import { Attributes } from 'graphology-types';
-import { Layout } from './layout';
-import { ILayoutFactory, LayoutAlgorithm } from './layout-creator-usecase';
-
-export type GraphologyProvider = 'Graphology';
-
-export type GraphologyLayoutAlgorithms =
-  | `${GraphologyProvider}_circular`
-  | `${GraphologyProvider}_random`
-  | `${GraphologyProvider}_noverlap`
-  | `${GraphologyProvider}_forceAtlas2`;
-
-/**
- * This is the Graphology Constructor for the main layouts available at
- * https://graphology.github.io/
- */
-export class GraphologyFactory
-  implements ILayoutFactory<GraphologyLayoutAlgorithms>
-{
-  createLayout(layoutAlgorithm: GraphologyLayoutAlgorithms): Graphology | null {
-    switch (layoutAlgorithm) {
-      case 'Graphology_random':
-        return new GraphologyRandom();
-      case 'Graphology_circular':
-        return new GraphologyCircular();
-      case 'Graphology_noverlap':
-        return new GraphologyNoverlap();
-      case 'Graphology_forceAtlas2':
-        return new GraphologyForceAtlas2();
-      default:
-        return null;
-    }
-  }
-}
-
-export abstract class Graphology extends Layout<GraphologyProvider> {
-  height: number = 100;
-  width: number = 100;
-  constructor(public override algorithm: LayoutAlgorithm<GraphologyProvider>) {
-    super('Graphology', algorithm);
-    this.setDimensions(100, 200);
-  }
-
-  public specialGraphologyFunction() {
-    // graph.forEachNode((node, attr) => {
-    //   graph.setNodeAttribute(node, 'x', 0);
-    //   graph.setNodeAttribute(node, 'y', 0);
-    // });
-  }
-
-  public setDimensions(width = 100, height = 100) {
-    this.width = width;
-    this.height = height;
-  }
-}
-
-/**
- * This is a ConcreteProduct
- */
-export class GraphologyCircular extends Graphology {
-  constructor() {
-    super('Graphology_circular');
-  }
-
-  public override layout(
-    graph: Graph<Attributes, Attributes, Attributes>
-  ): void {
-    // To directly assign the positions to the nodes:
-    circular.assign(graph, {
-      scale: 100,
-    });
-  }
-}
-
-const DEFAULT_RANDOM_SETTINGS: RandomLayoutOptions = {
-  scale: 250,
-};
-/**
- * This is a ConcreteProduct
- */
-export class GraphologyRandom extends Graphology {
-  constructor() {
-    super('Graphology_random');
-  }
-
-  public override layout(
-    graph: Graph<Attributes, Attributes, Attributes>
-  ): void {
-    // const positions = random(graph);
-
-    // To directly assign the positions to the nodes:
-    random.assign(graph, DEFAULT_RANDOM_SETTINGS);
-  }
-}
-
-const DEFAULT_NOVERLAP_SETTINGS: NoverlapSettings = {
-  margin: 40,
-  ratio: 40,
-  // gridSize: 50,
-
-  // gridSize ?number 20: number of grid cells horizontally and vertically subdivising the graph’s space. This is used as an optimization scheme. Set it to 1 and you will have O(n²) time complexity, which can sometimes perform better with very few nodes.
-  // margin ?number 5: margin to keep between nodes.
-  // expansion ?number 1.1: percentage of current space that nodes could attempt to move outside of.
-  // ratio ?number 1.0: ratio scaling node sizes.
-  // speed ?number 3: dampening factor that will slow down node movements to ease the overall process.
-};
-
-/**
- * This is a ConcreteProduct
- */
-export class GraphologyNoverlap extends Graphology {
-  constructor() {
-    super('Graphology_noverlap');
-  }
-
-  public override layout(
-    graph: Graph<Attributes, Attributes, Attributes>
-  ): void {
-    // // // To directly assign the positions to the nodes:
-    noverlap.assign(graph, {
-      maxIterations: 5000,
-      settings: DEFAULT_NOVERLAP_SETTINGS,
-    });
-  }
-}
-
-const DEFAULT_FORCEATLAS2_SETTINGS: ForceAtlas2Settings = {
-  gravity: 10,
-  adjustSizes: true,
-  linLogMode: true,
-
-  // adjustSizes ?boolean false: should the node’s sizes be taken into account?
-  // barnesHutOptimize ?boolean false: whether to use the Barnes-Hut approximation to compute repulsion in O(n*log(n)) rather than default O(n^2), n being the number of nodes.
-  // barnesHutTheta ?number 0.5: Barnes-Hut approximation theta parameter.
-  // edgeWeightInfluence ?number 1: influence of the edge’s weights on the layout. To consider edge weight, don’t forget to pass weighted as true when applying the synchronous layout or when instantiating the worker.
-  // gravity ?number 1: strength of the layout’s gravity.
-  // linLogMode ?boolean false: whether to use Noack’s LinLog model.
-  // outboundAttractionDistribution ?boolean false
-  // scalingRatio ?number 1
-  // slowDown ?number 1
-  // strongGravityMode ?boolean false
-};
-
-/**
- * This is a ConcreteProduct
- */
-export class GraphologyForceAtlas2 extends Graphology {
-  constructor() {
-    super('Graphology_forceAtlas2');
-  }
-
-  public override layout(
-    graph: Graph<Attributes, Attributes, Attributes>
-  ): void {
-    // To directly assign the positions to the nodes:
-
-    forceAtlas2.assign(graph, {
-      iterations: 500000,
-      settings: DEFAULT_FORCEATLAS2_SETTINGS,
-    });
-  }
-}
diff --git a/libs/shared/graph-layouts/src/lib/layout-creator-usecase.spec.ts b/libs/shared/graph-layouts/src/lib/layout-creator-usecase.spec.ts
deleted file mode 100644
index 95e16ec4d..000000000
--- a/libs/shared/graph-layouts/src/lib/layout-creator-usecase.spec.ts
+++ /dev/null
@@ -1,140 +0,0 @@
-import {
-  movieSchemaRaw,
-  northWindSchemaRaw,
-  simpleSchemaRaw,
-  twitterSchemaRaw,
-} from '@graphpolaris/shared/mock-data';
-// import Graph, { MultiGraph } from 'graphology';
-
-// import ladder from 'graphology-generators/classic/ladder';
-// import { LayoutFactory } from './layout-creator-usecase';
-
-// /**
-//  * @jest-environment jsdom
-//  */
-// describe('LayoutFactory', () => {
-//   /**
-//    * @jest-environment jsdom
-//    */
-//   it('should work with noverlap from graphology ', () => {
-//     const graph = new MultiGraph();
-
-//     // Adding some nodes
-//     // graph.addNode('John', { x: 0, y: 0, width: 200, height: 200 });
-//     // graph.addNode('Martha', { x: 0, y: 0 });
-//     graph.addNode('John');
-//     graph.addNode('Martha');
-
-//     // Adding an edge
-//     graph.addEdge('John', 'Martha');
-
-//     const layoutFactory = new LayoutFactory();
-//     const layoutAlgorithm = layoutFactory.createLayout(
-//       'Graphology_forceAtlas2'
-//     );
-//     layoutAlgorithm?.layout(graph);
-
-//     graph.forEachNode((node, attr) => {
-//       console.log(node, attr);
-//     });
-//   });
-
-//   test('should work with noverlap from graphology on generated graph', () => {
-//     // Creating a ladder graph
-//     const graph = ladder(Graph, 10);
-
-//     graph.forEachNode((node, attr) => {
-//       graph.setNodeAttribute(node, 'x', 0);
-//       graph.setNodeAttribute(node, 'y', 0);
-//     });
-
-//     const layoutFactory = new LayoutFactory();
-
-//     const layout = layoutFactory.createLayout('Graphology_noverlap');
-//     layout?.layout(graph);
-
-//     graph.forEachNode((node, attr) => {
-//       console.log(node, attr);
-//     });
-//   });
-
-//   test('should work with random from graphology on generated graph', () => {
-//     // Creating a ladder graph
-//     const graph = ladder(Graph, 10);
-
-//     graph.forEachNode((node, attr) => {
-//       graph.setNodeAttribute(node, 'x', 0);
-//       graph.setNodeAttribute(node, 'y', 0);
-//     });
-
-//     const layoutFactory = new LayoutFactory();
-
-//     const layout = layoutFactory.createLayout('Graphology_random');
-//     layout?.setDimensions(100, 100);
-//     layout?.layout(graph);
-
-//     graph.forEachNode((node, attr) => {
-//       console.log(node, attr);
-//     });
-//   });
-
-//   test('should work with circular from graphology on generated graph', () => {
-//     // Creating a ladder graph
-//     const graph = ladder(Graph, 100);
-
-//     graph.forEachNode((node, attr) => {
-//       graph.setNodeAttribute(node, 'x', 0);
-//       graph.setNodeAttribute(node, 'y', 0);
-//     });
-
-//     const layoutFactory = new LayoutFactory();
-
-//     const layout = layoutFactory.createLayout('Graphology_circular');
-//     layout?.setDimensions(100, 100);
-//     layout?.layout(graph);
-
-//     graph.forEachNode((node, attr) => {
-//       console.log(node, attr);
-//     });
-//   });
-
-//   test('should work with circular from graphology on generated graph', () => {
-//     // Creating a ladder graph
-//     const graph = ladder(Graph, 100);
-
-//     graph.forEachNode((node, attr) => {
-//       graph.setNodeAttribute(node, 'x', 0);
-//       graph.setNodeAttribute(node, 'y', 0);
-//     });
-
-//     const layoutFactory = new LayoutFactory();
-//     const layout = layoutFactory.createLayout('Graphology_forceAtlas2');
-//     layout?.setDimensions(100, 100);
-//     layout?.layout(graph);
-
-//     graph.forEachNode((node, attr) => {
-//       console.log(node, attr);
-//     });
-//   });
-
-//   test('should add x,y for graphology layouts if not existing', () => {
-//     // console.log(Object.keys(AllLayoutAlgorithms))
-
-//     const graph = ladder(Graph, 100);
-
-//     graph.forEachNode((node, attr) => {
-//       expect(graph.getNodeAttribute(node, 'x')).toBeUndefined();
-//       expect(graph.getNodeAttribute(node, 'y')).toBeUndefined();
-//     });
-
-//     const layoutFactory = new LayoutFactory();
-//     const layout = layoutFactory.createLayout('Graphology_forceAtlas2');
-//     layout?.setDimensions(100, 100);
-//     layout?.layout(graph);
-
-//     graph.forEachNode((node, attr) => {
-//       expect(graph.getNodeAttribute(node, 'x')).toBeDefined();
-//       expect(graph.getNodeAttribute(node, 'y')).toBeDefined();
-//     });
-//   });
-// });
diff --git a/libs/shared/graph-layouts/src/lib/layout-creator-usecase.ts b/libs/shared/graph-layouts/src/lib/layout-creator-usecase.ts
deleted file mode 100644
index 930200eea..000000000
--- a/libs/shared/graph-layouts/src/lib/layout-creator-usecase.ts
+++ /dev/null
@@ -1,77 +0,0 @@
-import {
-  Cytoscape,
-  CytoscapeFactory,
-  CytoscapeLayoutAlgorithms,
-  CytoscapeProvider,
-} from './cytoscape-layouts';
-import {
-  Graphology,
-  GraphologyFactory,
-  GraphologyLayoutAlgorithms,
-  GraphologyProvider,
-} from './graphology-layouts';
-import { Layout } from './layout';
-
-export type Providers = GraphologyProvider | CytoscapeProvider;
-export type LayoutAlgorithm<Provider extends Providers> =
-  `${Provider}_${string}`;
-
-export type AllLayoutAlgorithms =
-  | GraphologyLayoutAlgorithms
-  | CytoscapeLayoutAlgorithms;
-
-export type AlgorithmToLayoutProvider<Algorithm extends AllLayoutAlgorithms> =
-  Algorithm extends GraphologyLayoutAlgorithms
-    ? Graphology
-    : Algorithm extends CytoscapeLayoutAlgorithms
-    ? Cytoscape
-    : Cytoscape | Graphology;
-
-export interface ILayoutFactory<Algorithm extends AllLayoutAlgorithms> {
-  createLayout: (
-    Algorithm: Algorithm
-  ) => AlgorithmToLayoutProvider<Algorithm> | null;
-}
-
-/**
- * This is our Creator
- */
-export class LayoutFactory implements ILayoutFactory<AllLayoutAlgorithms> {
-  private graphologyFactory = new GraphologyFactory();
-  private cytoscapeFactory = new CytoscapeFactory();
-
-  private isSpecificAlgorithm<Algorithm extends AllLayoutAlgorithms>(
-    LayoutAlgorithm: AllLayoutAlgorithms,
-    startsWith: string
-  ): LayoutAlgorithm is Algorithm {
-    return LayoutAlgorithm.startsWith(startsWith);
-  }
-
-  createLayout<Algorithm extends AllLayoutAlgorithms>(
-    layoutAlgorithm: Algorithm
-  ): AlgorithmToLayoutProvider<Algorithm> | null {
-    if (
-      this.isSpecificAlgorithm<GraphologyLayoutAlgorithms>(
-        layoutAlgorithm,
-        'Graphology'
-      )
-    ) {
-      return this.graphologyFactory.createLayout(
-        layoutAlgorithm
-      ) as AlgorithmToLayoutProvider<Algorithm>;
-    }
-
-    if (
-      this.isSpecificAlgorithm<CytoscapeLayoutAlgorithms>(
-        layoutAlgorithm,
-        'Cytoscape'
-      )
-    ) {
-      return this.cytoscapeFactory.createLayout(
-        layoutAlgorithm
-      ) as AlgorithmToLayoutProvider<Algorithm>;
-    }
-
-    return null;
-  }
-}
diff --git a/libs/shared/graph-layouts/src/lib/layout.ts b/libs/shared/graph-layouts/src/lib/layout.ts
deleted file mode 100644
index 06f4da35e..000000000
--- a/libs/shared/graph-layouts/src/lib/layout.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-import Graph from 'graphology';
-import { Providers, LayoutAlgorithm } from './layout-creator-usecase';
-
-/**
- * This is our Product
- */
-
-export abstract class Layout<provider extends Providers> {
-  constructor(
-    public provider: provider,
-    public algorithm: LayoutAlgorithm<provider>
-  ) {
-    console.log(
-      `Created the following Layout: ${provider} - ${this.algorithm}`
-    );
-  }
-
-  public layout(graph: Graph) {
-    console.log(`${this.provider} [${this.algorithm}] layouting now`);
-  }
-}
diff --git a/libs/shared/graph-layouts/tsconfig.json b/libs/shared/graph-layouts/tsconfig.json
deleted file mode 100644
index 47e7fa539..000000000
--- a/libs/shared/graph-layouts/tsconfig.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
-  "extends": "../../../tsconfig.base.json",
-  "compilerOptions": {
-    "module": "CommonJS",
-    "forceConsistentCasingInFileNames": true,
-    "strict": true,
-    "noImplicitOverride": true,
-    "noPropertyAccessFromIndexSignature": true,
-    "noImplicitReturns": true,
-    "noFallthroughCasesInSwitch": true,
-    "composite": true
-  },
-  "files": [],
-  "include": [],
-  "references": [
-    {
-      "path": "./tsconfig.lib.json"
-    },
-    {
-      "path": "./tsconfig.spec.json"
-    }
-  ]
-}
diff --git a/libs/shared/graph-layouts/tsconfig.lib.json b/libs/shared/graph-layouts/tsconfig.lib.json
deleted file mode 100644
index efdd77fbf..000000000
--- a/libs/shared/graph-layouts/tsconfig.lib.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
-  "extends": "./tsconfig.json",
-  "compilerOptions": {
-    "outDir": "../../../dist/out-tsc",
-    "declaration": true,
-    "types": []
-  },
-  "include": ["**/*.ts"],
-  "exclude": ["**/*.spec.ts"]
-}
diff --git a/libs/shared/graph-layouts/tsconfig.spec.json b/libs/shared/graph-layouts/tsconfig.spec.json
deleted file mode 100644
index cdccf0f19..000000000
--- a/libs/shared/graph-layouts/tsconfig.spec.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
-  "extends": "./tsconfig.json",
-  "compilerOptions": {
-    "outDir": "../../../dist/out-tsc",
-    "module": "commonjs",
-    "types": ["jest", "node"],
-    "composite": true
-  },
-  "include": ["**/*.test.ts", "**/*.spec.ts", "**/*.d.ts"]
-}
diff --git a/libs/shared/graph-layouts/yarn.lock b/libs/shared/graph-layouts/yarn.lock
deleted file mode 100644
index 8992e29d7..000000000
--- a/libs/shared/graph-layouts/yarn.lock
+++ /dev/null
@@ -1,21 +0,0 @@
-# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
-# yarn lockfile v1
-
-
-events@^3.3.0:
-  version "3.3.0"
-  resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400"
-  integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==
-
-graphology@^0.24.1:
-  version "0.24.1"
-  resolved "https://registry.yarnpkg.com/graphology/-/graphology-0.24.1.tgz#035e452e294b01168cf5c85d5dd0a4b7e4837d87"
-  integrity sha512-6lNz1PNTAe9Q6ioHKrXu0Lp047sgvOoHa4qmP/8mnJWCGv2iIZPQkuHPUb2/OWDWCqHpw2hKgJLJ55X/66xmHg==
-  dependencies:
-    events "^3.3.0"
-    obliterator "^2.0.2"
-
-obliterator@^2.0.2:
-  version "2.0.2"
-  resolved "https://registry.yarnpkg.com/obliterator/-/obliterator-2.0.2.tgz#25f50dc92e1181371b9d8209d11890f1a3c2fc21"
-  integrity sha512-g0TrA7SbUggROhDPK8cEu/qpItwH2LSKcNl4tlfBNT54XY+nOsqrs0Q68h1V9b3HOSpIWv15jb1lax2hAggdIg==
-- 
GitLab