PageRenderTime 148ms CodeModel.GetById 6ms app.highlight 119ms RepoModel.GetById 1ms app.codeStats 1ms

/js/vendor/dagre.js

https://github.com/marthlab/iseqtools-portal
JavaScript | 4047 lines | 3579 code | 262 blank | 206 comment | 250 complexity | 18735894fa52e88fd37884823f2dd51d MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/*
   2Copyright (c) 2012 Chris Pettitt
   3
   4Permission is hereby granted, free of charge, to any person obtaining a copy
   5of this software and associated documentation files (the "Software"), to deal
   6in the Software without restriction, including without limitation the rights
   7to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   8copies of the Software, and to permit persons to whom the Software is
   9furnished to do so, subject to the following conditions:
  10
  11The above copyright notice and this permission notice shall be included in
  12all copies or substantial portions of the Software.
  13
  14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20THE SOFTWARE.
  21*/
  22(function() {
  23  dagre = {};
  24dagre.version = "0.0.6";
  25/*
  26 * Directed multi-graph used during layout.
  27 */
  28dagre.graph = {};
  29
  30/*
  31 * Creates a new directed multi-graph. This should be invoked with
  32 * `var g = dagre.graph()` and _not_ `var g = new dagre.graph()`.
  33 */
  34dagre.graph = function() {
  35  var nodes = {},
  36      inEdges = {},
  37      outEdges = {},
  38      edges = {},
  39      graph = {},
  40      idCounter = 0;
  41
  42  graph.addNode = function(u, value) {
  43    if (graph.hasNode(u)) {
  44      throw new Error("Graph already has node '" + u + "':\n" + graph.toString());
  45    }
  46    nodes[u] = { id: u, value: value };
  47    inEdges[u] = {};
  48    outEdges[u] = {};
  49  }
  50
  51  graph.delNode = function(u) {
  52    strictGetNode(u);
  53
  54    graph.edges(u).forEach(function(e) { graph.delEdge(e); });
  55
  56    delete inEdges[u];
  57    delete outEdges[u];
  58    delete nodes[u];
  59  }
  60
  61  graph.node = function(u) {
  62    return strictGetNode(u).value;
  63  }
  64
  65  graph.hasNode = function(u) {
  66    return u in nodes;
  67  }
  68
  69  graph.addEdge = function(e, source, target, value) {
  70    strictGetNode(source);
  71    strictGetNode(target);
  72
  73    if (e === null) {
  74      e = "_ANON-" + ++idCounter;
  75    }
  76    else if (graph.hasEdge(e)) {
  77      throw new Error("Graph already has edge '" + e + "':\n" + graph.toString());
  78    }
  79
  80    edges[e] = { id: e, source: source, target: target, value: value };
  81    addEdgeToMap(inEdges[target], source, e);
  82    addEdgeToMap(outEdges[source], target, e);
  83  }
  84
  85  graph.delEdge = function(e) {
  86    var edge = strictGetEdge(e);
  87    delEdgeFromMap(inEdges[edge.target], edge.source, e)
  88    delEdgeFromMap(outEdges[edge.source], edge.target, e)
  89    delete edges[e];
  90  }
  91
  92  graph.edge = function(e) {
  93    return strictGetEdge(e).value;
  94  }
  95
  96  graph.source = function(e) {
  97    return strictGetEdge(e).source;
  98  }
  99
 100  graph.target = function(e) {
 101    return strictGetEdge(e).target;
 102  }
 103
 104  graph.hasEdge = function(e) {
 105    return e in edges;
 106  }
 107
 108  graph.successors = function(u) {
 109    strictGetNode(u);
 110    return keys(outEdges[u]).map(function(v) { return nodes[v].id; });
 111  }
 112
 113  graph.predecessors = function(u) {
 114    strictGetNode(u);
 115    return keys(inEdges[u]).map(function(v) { return nodes[v].id; });
 116  }
 117
 118  graph.neighbors = function(u) {
 119    strictGetNode(u);
 120    var vs = {};
 121    keys(outEdges[u]).map(function(v) { vs[v] = true; });
 122    keys(inEdges[u]).map(function(v) { vs[v] = true; });
 123    return keys(vs).map(function(v) { return nodes[v].id; });
 124  }
 125
 126  graph.nodes = function() {
 127    var nodes = [];
 128    graph.eachNode(function(id, _) { nodes.push(id); });
 129    return nodes;
 130  }
 131
 132  graph.eachNode = function(func) {
 133    for (var k in nodes) {
 134      var node = nodes[k];
 135      func(node.id, node.value);
 136    }
 137  }
 138
 139  /*
 140   * Return all edges with no arguments,
 141   * the ones that are incident on a node (one argument),
 142   * or all edges from a source to a target (two arguments)
 143   */
 144  graph.edges = function(u, v) {
 145    var es, sourceEdges;
 146    if (!arguments.length) {
 147      es = [];
 148      graph.eachEdge(function(id) { es.push(id); });
 149      return es;
 150    } else if (arguments.length === 1) {
 151      return union([graph.inEdges(u), graph.outEdges(u)]);
 152    } else if (arguments.length === 2) {
 153      strictGetNode(u);
 154      strictGetNode(v);
 155      sourceEdges = outEdges[u];
 156      es = (v in sourceEdges) ? keys(sourceEdges[v].edges) : [];
 157      return es.map(function(e) { return edges[e].id });
 158    }
 159  };
 160
 161  graph.eachEdge = function(func) {
 162    for (var k in edges) {
 163      var edge = edges[k];
 164      func(edge.id, edge.source, edge.target, edge.value);
 165    }
 166  }
 167
 168  /*
 169   * Return all in edges to a target node
 170   */
 171  graph.inEdges = function(target) {
 172    strictGetNode(target);
 173    return concat(values(inEdges[target]).map(function(es) { return keys(es.edges); }));
 174  };
 175
 176  /*
 177   * Return all out edges from a source node
 178   */
 179  graph.outEdges = function(source) {
 180    strictGetNode(source);
 181    return concat(values(outEdges[source]).map(function(es) { return keys(es.edges); }));
 182  };
 183
 184  graph.subgraph = function(us) {
 185    var g = dagre.graph();
 186    us.forEach(function(u) {
 187      g.addNode(u, graph.node(u));
 188    });
 189    values(edges).forEach(function(e) {
 190      if (g.hasNode(e.source) && g.hasNode(e.target)) {
 191        g.addEdge(e.id, e.source, e.target, graph.edge(e.id));
 192      }
 193    });
 194    return g;
 195  };
 196
 197  graph.toString = function() {
 198    var str = "GRAPH:\n";
 199    str += "    Nodes:\n";
 200    keys(nodes).forEach(function(u) {
 201      str += "        " + u + ": " + JSON.stringify(nodes[u].value) + "\n";
 202    });
 203    str += "    Edges:\n";
 204    keys(edges).forEach(function(e) {
 205      var edge = edges[e];
 206      str += "        " + e + " (" + edge.source + " -> " + edge.target + "): " + JSON.stringify(edges[e].value) + "\n";
 207    });
 208    return str;
 209  };
 210
 211  function addEdgeToMap(map, v, e) {
 212    var vEntry = map[v];
 213    if (!vEntry) {
 214      vEntry = map[v] = { count: 0, edges: {} };
 215    }
 216    vEntry.count++;
 217    vEntry.edges[e] = true;
 218  }
 219
 220  function delEdgeFromMap(map, v, e) {
 221    var vEntry = map[v];
 222    if (--vEntry.count == 0) {
 223      delete map[v];
 224    } else {
 225      delete vEntry.edges[e];
 226    }
 227  }
 228
 229  function strictGetNode(u) {
 230    var node = nodes[u];
 231    if (!(u in nodes)) {
 232      throw new Error("Node '" + u + "' is not in graph:\n" + graph.toString());
 233    }
 234    return node;
 235  }
 236
 237  function strictGetEdge(e) {
 238    var edge = edges[e];
 239    if (!edge) {
 240      throw new Error("Edge '" + e + "' is not in graph:\n" + graph.toString());
 241    }
 242    return edge;
 243  }
 244
 245  return graph;
 246}
 247dagre.layout = function() {
 248  // External configuration
 249  var config = {
 250      // Nodes to lay out. At minimum must have `width` and `height` attributes.
 251      nodes: [],
 252      // Edges to lay out. At mimimum must have `source` and `target` attributes.
 253      edges: [],
 254      // How much debug information to include?
 255      debugLevel: 0,
 256  };
 257
 258  var timer = createTimer();
 259
 260  // Phase functions
 261  var
 262      acyclic = dagre.layout.acyclic(),
 263      rank = dagre.layout.rank(),
 264      order = dagre.layout.order(),
 265      position = dagre.layout.position();
 266
 267  // This layout object
 268  var self = {};
 269
 270  self.nodes = propertyAccessor(self, config, "nodes");
 271  self.edges = propertyAccessor(self, config, "edges");
 272
 273  self.orderIters = delegateProperty(order.iterations);
 274
 275  self.nodeSep = delegateProperty(position.nodeSep);
 276  self.edgeSep = delegateProperty(position.edgeSep);
 277  self.rankSep = delegateProperty(position.rankSep);
 278  self.rankDir = delegateProperty(position.rankDir);
 279  self.debugAlignment = delegateProperty(position.debugAlignment);
 280
 281  self.debugLevel = propertyAccessor(self, config, "debugLevel", function(x) {
 282    timer.enabled(x);
 283    acyclic.debugLevel(x);
 284    rank.debugLevel(x);
 285    order.debugLevel(x);
 286    position.debugLevel(x);
 287  });
 288
 289  self.run = timer.wrap("Total layout", run);
 290
 291  return self;
 292
 293  // Build graph and save mapping of generated ids to original nodes and edges
 294  function init() {
 295    var g = dagre.graph();
 296    var nextId = 0;
 297
 298    // Tag each node so that we can properly represent relationships when
 299    // we add edges. Also copy relevant dimension information.
 300    config.nodes.forEach(function(u) {
 301      var id = "id" in u ? u.id : "_N" + nextId++;
 302      u.dagre = { id: id, width: u.width, height: u.height, offsetwidth: u.offsetwidth || u.width/2, offsetheight: u.offsetheight || u.height/2};
 303      g.addNode(id, u.dagre);
 304    });
 305
 306    config.edges.forEach(function(e) {
 307      var source = e.source.dagre.id;
 308      if (!g.hasNode(source)) {
 309        throw new Error("Source node for '" + e + "' not in node list");
 310      }
 311
 312      var target = e.target.dagre.id;
 313      if (!g.hasNode(target)) {
 314        throw new Error("Target node for '" + e + "' not in node list");
 315      }
 316
 317      e.dagre = {
 318        points: []
 319      };
 320
 321      // Track edges that aren't self loops - layout does nothing for self
 322      // loops, so they can be skipped.
 323      if (source !== target) {
 324        var id = "id" in e ? e.id : "_E" + nextId++;
 325        e.dagre.id = id;
 326        e.dagre.minLen = e.minLen || 1;
 327        e.dagre.width = e.width || 0;
 328        e.dagre.height = e.height || 0;
 329        g.addEdge(id, source, target, e.dagre);
 330      }
 331    });
 332
 333    return g;
 334  }
 335
 336  function run () {
 337    var rankSep = self.rankSep();
 338    try {
 339      if (!config.nodes.length) {
 340        return;
 341      }
 342
 343      // Build internal graph
 344      var g = init();
 345
 346      // Make space for edge labels
 347      g.eachEdge(function(e, s, t, a) {
 348        a.minLen *= 2;
 349      });
 350      self.rankSep(rankSep / 2);
 351
 352      // Reverse edges to get an acyclic graph, we keep the graph in an acyclic
 353      // state until the very end.
 354      acyclic.run(g);
 355
 356      // Determine the rank for each node. Nodes with a lower rank will appear
 357      // above nodes of higher rank.
 358      rank.run(g);
 359
 360      // Normalize the graph by ensuring that every edge is proper (each edge has
 361      // a length of 1). We achieve this by adding dummy nodes to long edges,
 362      // thus shortening them.
 363      normalize(g);
 364
 365      // Order the nodes so that edge crossings are minimized.
 366      order.run(g);
 367
 368      // Find the x and y coordinates for every node in the graph.
 369      position.run(g);
 370
 371      // De-normalize the graph by removing dummy nodes and augmenting the
 372      // original long edges with coordinate information.
 373      undoNormalize(g);
 374
 375      // Reverses points for edges that are in a reversed state.
 376      fixupEdgePoints(g);
 377
 378      // Reverse edges that were revered previously to get an acyclic graph.
 379      acyclic.undo(g);
 380    } finally {
 381      self.rankSep(rankSep);
 382    }
 383
 384    return self;
 385  }
 386
 387  // Assumes input graph has no self-loops and is otherwise acyclic.
 388  function normalize(g) {
 389    var dummyCount = 0;
 390    g.eachEdge(function(e, s, t, a) {
 391      var sourceRank = g.node(s).rank;
 392      var targetRank = g.node(t).rank;
 393      if (sourceRank + 1 < targetRank) {
 394        for (var u = s, rank = sourceRank + 1, i = 0; rank < targetRank; ++rank, ++i) {
 395          var v = "_D" + ++dummyCount;
 396          var node = {
 397            width: a.width,
 398            height: a.height,
 399            offsetwidth: a.width/2,
 400            offsetheight: a.height/2,
 401            edge: { id: e, source: s, target: t, attrs: a },
 402            rank: rank,
 403            dummy: true
 404          };
 405
 406          // If this node represents a bend then we will use it as a control
 407          // point. For edges with 2 segments this will be the center dummy
 408          // node. For edges with more than two segments, this will be the
 409          // first and last dummy node.
 410          if (i === 0) node.index = 0;
 411          else if (rank + 1 === targetRank) node.index = 1;
 412
 413          g.addNode(v, node);
 414          g.addEdge(null, u, v, {});
 415          u = v;
 416        }
 417        g.addEdge(null, u, t, {});
 418        g.delEdge(e);
 419      }
 420    });
 421  }
 422
 423  function undoNormalize(g) {
 424    var visited = {};
 425
 426    g.eachNode(function(u, a) {
 427      if (a.dummy && "index" in a) {
 428        var edge = a.edge;
 429        if (!g.hasEdge(edge.id)) {
 430          g.addEdge(edge.id, edge.source, edge.target, edge.attrs);
 431        }
 432        var points = g.edge(edge.id).points;
 433        points[a.index] = { x: a.x, y: a.y };
 434        g.delNode(u);
 435      }
 436    });
 437  }
 438
 439  function fixupEdgePoints(g) {
 440    g.eachEdge(function(e, s, t, a) { if (a.reversed) a.points.reverse(); });
 441  }
 442
 443  function delegateProperty(f) {
 444    return function() {
 445      if (!arguments.length) return f();
 446      f.apply(null, arguments);
 447      return self;
 448    }
 449  }
 450}
 451dagre.layout.acyclic = function() {
 452  // External configuration
 453  var config = {
 454    debugLevel: 0
 455  }
 456
 457  var timer = createTimer();
 458
 459  var self = {};
 460
 461  self.debugLevel = propertyAccessor(self, config, "debugLevel", function(x) {
 462    timer.enabled(x);
 463  });
 464
 465  self.run = timer.wrap("Acyclic Phase", run);
 466
 467  self.undo = function(g) {
 468    g.eachEdge(function(e, s, t, a) {
 469      if (a.reversed) {
 470        delete a.reversed;
 471        g.delEdge(e);
 472        g.addEdge(e, t, s, a);
 473      }
 474    });
 475  }
 476
 477  return self;
 478
 479  function run(g) {
 480    var onStack = {},
 481        visited = {},
 482        reverseCount = 0;
 483
 484    function dfs(u) {
 485      if (u in visited) return;
 486
 487      visited[u] = onStack[u] = true;
 488      g.outEdges(u).forEach(function(e) {
 489        var t = g.target(e),
 490            a;
 491
 492        if (t in onStack) {
 493          a = g.edge(e);
 494          g.delEdge(e);
 495          a.reversed = true;
 496          ++reverseCount;
 497          g.addEdge(e, t, u, a);
 498        } else {
 499          dfs(t);
 500        }
 501      });
 502
 503      delete onStack[u];
 504    }
 505
 506    g.eachNode(function(u) { dfs(u); });
 507
 508    if (config.debugLevel >= 2) console.log("Acyclic Phase: reversed " + reverseCount + " edge(s)");
 509  }
 510};
 511dagre.layout.rank = function() {
 512  // External configuration
 513  var config = {
 514    debugLevel: 0
 515  };
 516
 517  var timer = createTimer();
 518
 519  var self = {};
 520
 521  self.debugLevel = propertyAccessor(self, config, "debugLevel", function(x) {
 522    timer.enabled(x);
 523  });
 524
 525  self.run = timer.wrap("Rank Phase", run);
 526
 527  return self;
 528
 529  function run(g) {
 530    initRank(g);
 531    components(g).forEach(function(cmpt) {
 532      var subgraph = g.subgraph(cmpt);
 533      feasibleTree(subgraph);
 534      normalize(subgraph);
 535    });
 536  };
 537
 538
 539  function initRank(g) {
 540    var minRank = {};
 541    var pq = priorityQueue();
 542
 543    g.eachNode(function(u) {
 544      pq.add(u, g.inEdges(u).length);
 545      minRank[u] = 0;
 546    });
 547
 548    while (pq.size() > 0) {
 549      var minId = pq.min();
 550      if (pq.priority(minId) > 0) {
 551        throw new Error("Input graph is not acyclic: " + g.toString());
 552      }
 553      pq.removeMin();
 554
 555      var rank = minRank[minId];
 556      g.node(minId).rank = rank;
 557
 558      g.outEdges(minId).forEach(function(e) {
 559        var target = g.target(e);
 560        minRank[target] = Math.max(minRank[target], rank + (g.edge(e).minLen || 1));
 561        pq.decrease(target, pq.priority(target) - 1);
 562      });
 563    }
 564  }
 565
 566  function feasibleTree(g) {
 567    // Precompute minimum lengths for each directed edge
 568    var minLen = {};
 569    g.eachEdge(function(e, source, target, edge) {
 570      var id = incidenceId(source, target);
 571      minLen[id] = Math.max(minLen[id] || 1, edge.minLen || 1);
 572    });
 573
 574    var tree = dagre.util.prim(g, function(u, v) {
 575      return Math.abs(g.node(u).rank - g.node(v).rank) - minLen[incidenceId(u, v)];
 576    });
 577
 578    var visited = {};
 579    function dfs(u, rank) {
 580      visited[u] = true;
 581      g.node(u).rank = rank;
 582
 583      tree[u].forEach(function(v) {
 584        if (!(v in visited)) {
 585          var delta = minLen[incidenceId(u, v)];
 586          dfs(v, rank + (g.edges(u, v).length ? delta : -delta));
 587        }
 588      });
 589    }
 590
 591    dfs(g.nodes()[0], 0);
 592
 593    return tree;
 594  }
 595
 596  function normalize(g) {
 597    var m = min(g.nodes().map(function(u) { return g.node(u).rank; }));
 598    g.eachNode(function(u, node) { node.rank -= m; });
 599  }
 600
 601  /*
 602   * This id can be used to group (in an undirected manner) multi-edges
 603   * incident on the same two nodes.
 604   */
 605  function incidenceId(u, v) {
 606    return u < v ?  u.length + ":" + u + "-" + v : v.length + ":" + v + "-" + u;
 607  }
 608}
 609dagre.layout.order = function() {
 610  var config = {
 611    iterations: 24, // max number of iterations
 612    debugLevel: 0
 613  };
 614
 615  var timer = createTimer();
 616
 617  var self = {};
 618
 619  self.iterations = propertyAccessor(self, config, "iterations");
 620
 621  self.debugLevel = propertyAccessor(self, config, "debugLevel", function(x) {
 622    timer.enabled(x);
 623  });
 624
 625  self.run = timer.wrap("Order Phase", run);
 626
 627  return self;
 628
 629  function run(g) {
 630    var layering = initOrder(g);
 631    var bestLayering = copyLayering(layering);
 632    var bestCC = crossCount(g, layering);
 633
 634    if (config.debugLevel >= 2) {
 635      console.log("Order phase start cross count: " + bestCC);
 636    }
 637
 638    var cc, i, lastBest;
 639    for (i = 0, lastBest = 0; lastBest < 4 && i < config.iterations; ++i, ++lastBest) {
 640      cc = sweep(g, i, layering);
 641      if (cc < bestCC) {
 642        bestLayering = copyLayering(layering);
 643        bestCC = cc;
 644        lastBest = 0;
 645      }
 646      if (config.debugLevel >= 3) {
 647        console.log("Order phase iter " + i + " cross count: " + bestCC);
 648      }
 649    }
 650
 651    bestLayering.forEach(function(layer) {
 652      layer.forEach(function(u, i) {
 653        g.node(u).order = i;
 654      });
 655    });
 656
 657    if (config.debugLevel >= 2) {
 658      console.log("Order iterations: " + i);
 659      console.log("Order phase best cross count: " + bestCC);
 660    }
 661
 662    return bestLayering;
 663  }
 664
 665  function initOrder(g) {
 666    var layering = [];
 667    g.eachNode(function(n, a) {
 668      var layer = layering[a.rank] || (layering[a.rank] = []);
 669      layer.push(n);
 670    });
 671    return layering;
 672  }
 673
 674  /*
 675   * Returns a function that will return the predecessors for a node. This
 676   * function differs from `g.predecessors(u)` in that a predecessor appears
 677   * for each incident edge (`g.predecessors(u)` treats predecessors as a set).
 678   * This allows pseudo-weighting of predecessor nodes.
 679   */
 680  function multiPredecessors(g) {
 681    return function(u) {
 682      var preds = [];
 683      g.inEdges(u).forEach(function(e) {
 684        preds.push(g.source(e));
 685      });
 686      return preds;
 687    }
 688  }
 689
 690  /*
 691   * Same as `multiPredecessors(g)` but for successors.
 692   */
 693  function multiSuccessors(g) {
 694    return function(u) {
 695      var sucs = [];
 696      g.outEdges(u).forEach(function(e) {
 697        sucs.push(g.target(e));
 698      });
 699      return sucs;
 700    }
 701  }
 702
 703  function sweep(g, iter, layering) {
 704    if (iter % 2 === 0) {
 705      for (var i = 1; i < layering.length; ++i) {
 706        barycenterLayer(layering[i - 1], layering[i], multiPredecessors(g));
 707      }
 708    } else {
 709      for (var i = layering.length - 2; i >= 0; --i) {
 710        barycenterLayer(layering[i + 1], layering[i], multiSuccessors(g));
 711      }
 712    }
 713    return crossCount(g, layering);
 714  }
 715
 716  /*
 717   * Given a fixed layer and a movable layer in a graph this function will
 718   * attempt to find an improved ordering for the movable layer such that
 719   * edge crossings may be reduced.
 720   *
 721   * This algorithm is based on the barycenter method.
 722   */
 723  function barycenterLayer(fixed, movable, predecessors) {
 724    var pos = layerPos(movable);
 725    var bs = barycenters(fixed, movable, predecessors);
 726
 727    var toSort = movable.slice(0).sort(function(x, y) {
 728      return bs[x] - bs[y] || pos[x] - pos[y];
 729    });
 730
 731    for (var i = movable.length - 1; i >= 0; --i) {
 732      if (bs[movable[i]] !== -1) {
 733        movable[i] = toSort.pop();
 734      }
 735    }
 736  }
 737
 738  /*
 739   * Given a fixed layer and a movable layer in a graph, this function will
 740   * return weights for the movable layer that can be used to reorder the layer
 741   * for potentially reduced edge crossings.
 742   */
 743  function barycenters(fixed, movable, predecessors) {
 744    var pos = layerPos(fixed), // Position of node in fixed list
 745        bs = {};               // Barycenters for each node
 746
 747    movable.forEach(function(u) {
 748      var b = -1;
 749      var preds = predecessors(u);
 750      if (preds.length > 0) {
 751        b = 0;
 752        preds.forEach(function(v) { b += pos[v]; });
 753        b = b / preds.length;
 754      }
 755      bs[u] = b;
 756    });
 757
 758    return bs;
 759  }
 760
 761  function copyLayering(layering) {
 762    return layering.map(function(l) { return l.slice(0); });
 763  }
 764}
 765
 766var crossCount = dagre.layout.order.crossCount = function(g, layering) {
 767  var cc = 0;
 768  var prevLayer;
 769  layering.forEach(function(layer) {
 770    if (prevLayer) {
 771      cc += bilayerCrossCount(g, prevLayer, layer);
 772    }
 773    prevLayer = layer;
 774  });
 775  return cc;
 776}
 777
 778/*
 779 * This function searches through a ranked and ordered graph and counts the
 780 * number of edges that cross. This algorithm is derived from:
 781 *
 782 *    W. Barth et al., Bilayer Cross Counting, JGAA, 8(2) 179–194 (2004)
 783 */
 784var bilayerCrossCount = dagre.layout.order.bilayerCrossCount = function(g, layer1, layer2) {
 785  var layer2Pos = layerPos(layer2);
 786
 787  var indices = [];
 788  layer1.forEach(function(u) {
 789    var nodeIndices = [];
 790    g.outEdges(u).forEach(function(e) { nodeIndices.push(layer2Pos[g.target(e)]); });
 791    nodeIndices.sort(function(x, y) { return x - y; });
 792    indices = indices.concat(nodeIndices);
 793  });
 794
 795  var firstIndex = 1;
 796  while (firstIndex < layer2.length) firstIndex <<= 1;
 797
 798  var treeSize = 2 * firstIndex - 1;
 799  firstIndex -= 1;
 800
 801  var tree = [];
 802  for (var i = 0; i < treeSize; ++i) { tree[i] = 0; }
 803
 804  var cc = 0;
 805  indices.forEach(function(i) {
 806    var treeIndex = i + firstIndex;
 807    ++tree[treeIndex];
 808    var weightSum = 0;
 809    while (treeIndex > 0) {
 810      if (treeIndex % 2) {
 811        cc += tree[treeIndex + 1];
 812      }
 813      treeIndex = (treeIndex - 1) >> 1;
 814      ++tree[treeIndex];
 815    }
 816  });
 817
 818  return cc;
 819}
 820
 821function layerPos(layer) {
 822  var pos = {};
 823  layer.forEach(function(u, i) { pos[u] = i; });
 824  return pos;
 825}
 826/*
 827 * The algorithms here are based on Brandes and KĂśpf, "Fast and Simple
 828 * Horizontal Coordinate Assignment".
 829 */
 830dagre.layout.position = function() {
 831  // External configuration
 832  var config = {
 833    nodeSep: 50,
 834    edgeSep: 10,
 835    rankSep: 30,
 836    rankDir: "TB",
 837    debugAlignment: null,
 838    debugLevel: 0
 839  };
 840
 841  var timer = createTimer();
 842
 843  var self = {};
 844
 845  self.nodeSep = propertyAccessor(self, config, "nodeSep");
 846  self.edgeSep = propertyAccessor(self, config, "edgeSep");
 847  self.rankSep = propertyAccessor(self, config, "rankSep");
 848  self.rankDir = propertyAccessor(self, config, "rankDir");
 849  self.debugAlignment = propertyAccessor(self, config, "debugAlignment");
 850  self.debugLevel = propertyAccessor(self, config, "debugLevel", function(x) {
 851    timer.enabled(x);
 852  });
 853
 854  self.run = timer.wrap("Position Phase", run);
 855
 856  return self;
 857
 858  function run(g) {
 859    var layering = [];
 860    g.eachNode(function(u, node) {
 861      var layer = layering[node.rank] || (layering[node.rank] = []);
 862      layer[node.order] = u;
 863    });
 864
 865    var conflicts = findConflicts(g, layering);
 866
 867    var xss = {};
 868    ["up", "down"].forEach(function(vertDir) {
 869      if (vertDir === "down") layering.reverse();
 870
 871      ["left", "right"].forEach(function(horizDir) {
 872        if (horizDir === "right") reverseInnerOrder(layering);
 873
 874        var dir = vertDir + "-" + horizDir;
 875        if (!config.debugAlignment || config.debugAlignment === dir) {
 876          var align = verticalAlignment(g, layering, conflicts, vertDir === "up" ? "predecessors" : "successors");
 877          xss[dir]= horizontalCompaction(g, layering, align.pos, align.root, align.align);
 878          if (horizDir === "right") flipHorizontally(layering, xss[dir]);
 879        }
 880
 881        if (horizDir === "right") reverseInnerOrder(layering);
 882      });
 883
 884      if (vertDir === "down") layering.reverse();
 885    });
 886
 887    if (config.debugAlignment) {
 888      // In debug mode we allow forcing layout to a particular alignment.
 889      g.eachNode(function(u, node) { x(g, u, xss[config.debugAlignment][u]); });
 890    } else {
 891      balance(g, layering, xss);
 892    }
 893
 894    balance(g, layering, xss);
 895
 896    //g.eachNode(function(u) { x(g, u, x(g, u) + offsetWidth(g, u) - width(g,u)/2); });
 897
 898
 899    // Translate layout so left edge of bounding rectangle has coordinate 0
 900    var minX = min(g.nodes().map(function(u) { return x(g, u) - width(g, u) / 2; }));
 901    g.eachNode(function(u) { x(g, u, x(g, u) - minX); });
 902
 903    // Align y coordinates with ranks
 904    var posY = 0;
 905    layering.forEach(function(layer) {
 906      var maxHeight = max(layer.map(function(u) { return height(g, u); }));
 907      posY += maxHeight / 2;
 908      layer.forEach(function(u) { y(g, u, posY); });
 909      posY += maxHeight / 2 + config.rankSep;
 910    });
 911  };
 912
 913  /*
 914   * Generate an ID that can be used to represent any undirected edge that is
 915   * incident on `u` and `v`.
 916   */
 917  function undirEdgeId(u, v) {
 918    return u < v
 919      ? u.toString().length + ":" + u + "-" + v
 920      : v.toString().length + ":" + v + "-" + u;
 921  }
 922
 923  function findConflicts(g, layering) {
 924    var conflicts = {}, // Set of conflicting edge ids
 925        pos = {};       // Position of node in its layer
 926
 927    if (layering.length <= 2) return conflicts;
 928
 929    layering[1].forEach(function(u, i) { pos[u] = i; });
 930    for (var i = 1; i < layering.length - 1; ++i) {
 931      prevLayer = layering[i];
 932      currLayer = layering[i+1];
 933      var k0 = 0; // Position of the last inner segment in the previous layer
 934      var l = 0;  // Current position in the current layer (for iteration up to `l1`)
 935
 936      // Scan current layer for next node that is incident to an inner segement
 937      // between layering[i+1] and layering[i].
 938      for (var l1 = 0; l1 < currLayer.length; ++l1) {
 939        var u = currLayer[l1]; // Next inner segment in the current layer or
 940                               // last node in the current layer
 941        pos[u] = l1;
 942
 943        var k1 = undefined; // Position of the next inner segment in the previous layer or
 944                            // the position of the last element in the previous layer
 945        if (g.node(u).dummy) {
 946          var uPred = g.predecessors(u)[0];
 947          if (g.node(uPred).dummy)
 948            k1 = pos[uPred];
 949        }
 950        if (k1 === undefined && l1 === currLayer.length - 1)
 951          k1 = prevLayer.length - 1;
 952
 953        if (k1 !== undefined) {
 954          for (; l <= l1; ++l) {
 955            g.predecessors(currLayer[l]).forEach(function(v) {
 956              var k = pos[v];
 957              if (k < k0 || k > k1)
 958                conflicts[undirEdgeId(currLayer[l], v)] = true;
 959            });
 960          }
 961          k0 = k1;
 962        }
 963      }
 964    }
 965
 966    return conflicts;
 967  }
 968
 969  function verticalAlignment(g, layering, conflicts, relationship) {
 970    var pos = {},   // Position for a node in its layer
 971        root = {},  // Root of the block that the node participates in
 972        align = {}; // Points to the next node in the block or, if the last
 973                    // element in the block, points to the first block's root
 974
 975    layering.forEach(function(layer) {
 976      layer.forEach(function(u, i) {
 977        root[u] = u;
 978        align[u] = u;
 979        pos[u] = i;
 980      });
 981    });
 982
 983    layering.forEach(function(layer) {
 984      var prevIdx = -1;
 985      layer.forEach(function(v) {
 986        var related = g[relationship](v), // Adjacent nodes from the previous layer
 987            m;                            // The mid point in the related array
 988
 989        if (related.length > 0) {
 990          related.sort(function(x, y) { return pos[x] - pos[y]; });
 991          mid = (related.length - 1) / 2;
 992          related.slice(Math.floor(mid), Math.ceil(mid) + 1).forEach(function(u) {
 993            if (align[v] === v) {
 994              if (!conflicts[undirEdgeId(u, v)] && prevIdx < pos[u]) {
 995                align[u] = v;
 996                align[v] = root[v] = root[u];
 997                prevIdx = pos[u];
 998              }
 999            }
1000          });
1001        }
1002      });
1003    });
1004
1005    return { pos: pos, root: root, align: align };
1006  }
1007
1008  /*
1009   * Determines how much spacing u needs from its origin (center) to satisfy
1010   * width and node separation.
1011   */
1012  function deltaX(g, u) {
1013    var sep = g.node(u).dummy ? config.edgeSep : config.nodeSep;
1014    return width(g, u) / 2 + sep / 2;
1015  }
1016
1017  // This function deviates from the standard BK algorithm in two ways. First
1018  // it takes into account the size of the nodes. Second it includes a fix to
1019  // the original algorithm that is described in Carstens, "Node and Label
1020  // Placement in a Layered Layout Algorithm".
1021  function horizontalCompaction(g, layering, pos, root, align) {
1022    var sink = {},  // Mapping of node id -> sink node id for class
1023        shift = {}, // Mapping of sink node id -> x delta
1024        pred = {},  // Mapping of node id -> predecessor node (or null)
1025        xs = {};    // Calculated X positions
1026
1027    layering.forEach(function(layer) {
1028      layer.forEach(function(u, i) {
1029        sink[u] = u;
1030        if (i > 0)
1031          pred[u] = layer[i - 1];
1032      });
1033    });
1034
1035    function placeBlock(v) {
1036      if (!(v in xs)) {
1037        xs[v] = 0;
1038        var w = v;
1039        do {
1040          if (pos[w] > 0) {
1041            var u = root[pred[w]];
1042            placeBlock(u);
1043            if (sink[v] === v) {
1044              sink[v] = sink[u];
1045            }
1046            var delta = deltaX(g, pred[w]) + deltaX(g, w);
1047            if (sink[v] !== sink[u]) {
1048              shift[sink[u]] = Math.min(shift[sink[u]] || Number.POSITIVE_INFINITY, xs[v] - xs[u] - delta);
1049            } else {
1050              xs[v] = Math.max(xs[v], xs[u] + delta);
1051            }
1052          }
1053          w = align[w];
1054        } while (w !== v);
1055      }
1056    }
1057
1058    // Root coordinates relative to sink
1059    values(root).forEach(function(v) {
1060      placeBlock(v);
1061    });
1062
1063    // Absolute coordinates
1064    layering.forEach(function(layer) {
1065      layer.forEach(function(v) {
1066        xs[v] = xs[root[v]];
1067        var xDelta = shift[sink[v]];
1068        if (root[v] === v && xDelta < Number.POSITIVE_INFINITY)
1069          xs[v] += xDelta;
1070      });
1071    });
1072
1073    return xs;
1074  }
1075
1076  function findMinCoord(g, layering, xs) {
1077    return min(layering.map(function(layer) {
1078      var u = layer[0];
1079      return xs[u] - width(g, u) / 2;
1080    }));
1081  }
1082
1083  function findMaxCoord(g, layering, xs) {
1084    return max(layering.map(function(layer) {
1085      var u = layer[layer.length - 1];
1086      return xs[u] - width(g, u) / 2;
1087    }));
1088  }
1089
1090  function balance(g, layering, xss) {
1091    var min = {},                            // Min coordinate for the alignment
1092        max = {},                            // Max coordinate for the alginment
1093        smallestAlignment,
1094        shift = {};                          // Amount to shift a given alignment
1095
1096    var smallest = Number.POSITIVE_INFINITY;
1097    for (var alignment in xss) {
1098      var xs = xss[alignment];
1099      min[alignment] = findMinCoord(g, layering, xs);
1100      max[alignment] = findMaxCoord(g, layering, xs);
1101      var w = max[alignment] - min[alignment];
1102      if (w < smallest) {
1103        smallest = w;
1104        smallestAlignment = alignment;
1105      }
1106    }
1107
1108    // Determine how much to adjust positioning for each alignment
1109    ["up", "down"].forEach(function(vertDir) {
1110      ["left", "right"].forEach(function(horizDir) {
1111        var alignment = vertDir + "-" + horizDir;
1112        shift[alignment] = horizDir === "left"
1113            ? min[smallestAlignment] - min[alignment]
1114            : max[smallestAlignment] - max[alignment];
1115      });
1116    });
1117
1118    // Find average of medians for xss array
1119    g.eachNode(function(v) {
1120      var xs = [];
1121      for (alignment in xss)
1122        xs.push(xss[alignment][v] + shift[alignment]);
1123      xs.sort(function(x, y) { return x - y; });
1124      x(g, v, (xs[1] + xs[2]) / 2);
1125    });
1126  }
1127
1128  function flipHorizontally(layering, xs) {
1129    var maxCenter = max(values(xs));
1130    Object.keys(xs).forEach(function(u) {
1131      xs[u] = maxCenter - xs[u];
1132    });
1133  }
1134
1135  function reverseInnerOrder(layering) {
1136    layering.forEach(function(layer) {
1137      layer.reverse();
1138    });
1139  }
1140
1141  function width(g, u) {
1142    switch (config.rankDir) {
1143      case "LR": return g.node(u).height;
1144      default:   return g.node(u).width;
1145    }
1146  }
1147
1148  function offsetWidth(g, u) {
1149    //console.log(g.node(u));
1150    switch (config.rankDir) {
1151      case "LR": return g.node(u).offsetheight;
1152      default:   return g.node(u).offsetwidth;
1153    }
1154  }
1155
1156  function height(g, u) {
1157    switch(config.rankDir) {
1158      case "LR": return g.node(u).width;
1159      default:   return g.node(u).height;
1160    }
1161  }
1162
1163  function x(g, u, x) {
1164    switch (config.rankDir) {
1165      case "LR":
1166        if (arguments.length < 3) {
1167          return g.node(u).y;
1168        } else {
1169          g.node(u).y = x;
1170        }
1171        break;
1172      default:
1173        if (arguments.length < 3) {
1174          return g.node(u).x;
1175        } else {
1176          g.node(u).x = x;
1177        }
1178    }
1179  }
1180
1181  function y(g, u, y) {
1182    switch (config.rankDir) {
1183      case "LR":
1184        if (arguments.length < 3) {
1185          return g.node(u).x;
1186        } else {
1187          g.node(u).x = y;
1188        }
1189        break;
1190      default:
1191        if (arguments.length < 3) {
1192          return g.node(u).y;
1193        } else {
1194          g.node(u).y = y;
1195        }
1196    }
1197  }
1198}
1199dagre.util = {};
1200
1201/*
1202 * Copies attributes from `src` to `dst`. If an attribute name is in both
1203 * `src` and `dst` then the attribute value from `src` takes precedence.
1204 */
1205function mergeAttributes(src, dst) {
1206  Object.keys(src).forEach(function(k) { dst[k] = src[k]; });
1207}
1208
1209function min(values) {
1210  return Math.min.apply(null, values);
1211}
1212
1213function max(values) {
1214  return Math.max.apply(null, values);
1215}
1216
1217function concat(arrays) {
1218  return Array.prototype.concat.apply([], arrays);
1219}
1220
1221var keys = dagre.util.keys = Object.keys;
1222
1223/*
1224 * Returns an array of all values in the given object.
1225 */
1226function values(obj) {
1227  return Object.keys(obj).map(function(k) { return obj[k]; });
1228}
1229
1230function union(arrays) {
1231  var obj = {};
1232  for (var i = 0; i < arrays.length; ++i) {
1233    var a = arrays[i];
1234    for (var j = 0; j < a.length; ++j) {
1235      var v = a[j];
1236      obj[v] = v;
1237    }
1238  }
1239
1240  var results = [];
1241  for (var k in obj) {
1242    results.push(obj[k]);
1243  }
1244
1245  return results;
1246}
1247
1248/*
1249 * Returns all components in the graph using undirected navigation.
1250 */
1251var components = dagre.util.components = function(g) {
1252  var results = [];
1253  var visited = {};
1254
1255  function dfs(u, component) {
1256    if (!(u in visited)) {
1257      visited[u] = true;
1258      component.push(u);
1259      g.neighbors(u).forEach(function(v) {
1260        dfs(v, component);
1261      });
1262    }
1263  };
1264
1265  g.eachNode(function(u) {
1266    var component = [];
1267    dfs(u, component);
1268    if (component.length > 0) {
1269      results.push(component);
1270    }
1271  });
1272
1273  return results;
1274};
1275
1276/*
1277 * This algorithm uses undirected traversal to find a miminum spanning tree
1278 * using the supplied weight function. The algorithm is described in
1279 * Cormen, et al., "Introduction to Algorithms". The returned structure
1280 * is an array of node id to an array of adjacent nodes.
1281 */
1282var prim = dagre.util.prim = function(g, weight) {
1283  var result = {};
1284  var parent = {};
1285  var q = priorityQueue();
1286
1287  if (g.nodes().length === 0) {
1288    return result;
1289  }
1290
1291  g.eachNode(function(u) {
1292    q.add(u, Number.POSITIVE_INFINITY);
1293    result[u] = [];
1294  });
1295
1296  // Start from arbitrary node
1297  q.decrease(g.nodes()[0], 0);
1298
1299  var u;
1300  var init = false;
1301  while (q.size() > 0) {
1302    u = q.removeMin();
1303    if (u in parent) {
1304      result[u].push(parent[u]);
1305      result[parent[u]].push(u);
1306    } else if (init) {
1307      throw new Error("Input graph is not connected:\n" + g.toString());
1308    } else {
1309      init = true;
1310    }
1311
1312    g.neighbors(u).forEach(function(v) {
1313      var pri = q.priority(v);
1314      if (pri !== undefined) {
1315        var edgeWeight = weight(u, v);
1316        if (edgeWeight < pri) {
1317          parent[v] = u;
1318          q.decrease(v, edgeWeight);
1319        }
1320      }
1321    });
1322  }
1323
1324  return result;
1325};
1326
1327var intersectRect = dagre.util.intersectRect = function(rect, point) {
1328  var x = rect.x;
1329  var y = rect.y;
1330
1331  // For now we only support rectangles
1332
1333  // Rectangle intersection algorithm from:
1334  // http://math.stackexchange.com/questions/108113/find-edge-between-two-boxes
1335  var dx = point.x - x;
1336  var dy = point.y - y;
1337  var w = rect.width / 2;
1338  var h = rect.height / 2;
1339
1340  var sx, sy;
1341  if (Math.abs(dy) * w > Math.abs(dx) * h) {
1342    // Intersection is top or bottom of rect.
1343    if (dy < 0) {
1344      h = -h;
1345    }
1346    sx = dy === 0 ? 0 : h * dx / dy;
1347    sy = h;
1348  } else {
1349    // Intersection is left or right of rect.
1350    if (dx < 0) {
1351      w = -w;
1352    }
1353    sx = w;
1354    sy = dx === 0 ? 0 : w * dy / dx;
1355  }
1356
1357  return {x: x + sx, y: y + sy};
1358}
1359
1360var pointStr = dagre.util.pointStr = function(point) {
1361  return point.x + "," + point.y;
1362}
1363
1364var createTimer = function() {
1365  var self = {},
1366      enabled = false;
1367
1368  self.enabled = function(x) {
1369    if (!arguments.length) return enabled;
1370    enabled = x;
1371    return self;
1372  };
1373
1374  self.wrap = function(name, func) {
1375    return function() {
1376      var start = enabled ? new Date().getTime() : null;
1377      try {
1378        return func.apply(null, arguments);
1379      } finally {
1380        if (start) console.log(name + " time: " + (new Date().getTime() - start) + "ms");
1381      }
1382    }
1383  };
1384
1385  return self;
1386}
1387
1388function propertyAccessor(self, config, field, setHook) {
1389  return function(x) {
1390    if (!arguments.length) return config[field];
1391    config[field] = x;
1392    if (setHook) setHook(x);
1393    return self;
1394  };
1395}
1396function priorityQueue() {
1397  var _arr = [];
1398  var _keyIndices = {};
1399
1400  function _heapify(i) {
1401    var arr = _arr;
1402    var l = 2 * i,
1403        r = l + 1,
1404        largest = i;
1405    if (l < arr.length) {
1406      largest = arr[l].pri < arr[largest].pri ? l : largest;
1407      if (r < arr.length) {
1408        largest = arr[r].pri < arr[largest].pri ? r : largest;
1409      }
1410      if (largest !== i) {
1411        _swap(i, largest);
1412        _heapify(largest);
1413      }
1414    }
1415  }
1416
1417  function _decrease(index) {
1418    var arr = _arr;
1419    var pri = arr[index].pri;
1420    var parent;
1421    while (index > 0) {
1422      parent = index >> 1;
1423      if (arr[parent].pri < pri) {
1424        break;
1425      }
1426      _swap(index, parent);
1427      index = parent;
1428    }
1429  }
1430
1431  function _swap(i, j) {
1432    var arr = _arr;
1433    var keyIndices = _keyIndices;
1434    var tmp = arr[i];
1435    arr[i] = arr[j];
1436    arr[j] = tmp;
1437    keyIndices[arr[i].key] = i;
1438    keyIndices[arr[j].key] = j;
1439  }
1440
1441  function size() { return _arr.length; }
1442
1443  function keys() { return Object.keys(_keyIndices); }
1444
1445  function has(key) { return key in _keyIndices; }
1446
1447  function priority(key) {
1448    var index = _keyIndices[key];
1449    if (index !== undefined) {
1450      return _arr[index].pri;
1451    }
1452  }
1453
1454  function add(key, pri) {
1455    if (!(key in _keyIndices)) {
1456      var entry = {key: key, pri: pri};
1457      var index = _arr.length;
1458      _keyIndices[key] = index;
1459      _arr.push(entry);
1460      _decrease(index);
1461      return true;
1462    }
1463    return false;
1464  }
1465
1466  function min() {
1467    if (size() > 0) {
1468      return _arr[0].key;
1469    }
1470  }
1471
1472  function removeMin() {
1473    _swap(0, _arr.length - 1);
1474    var min = _arr.pop();
1475    delete _keyIndices[min.key];
1476    _heapify(0);
1477    return min.key;
1478  }
1479
1480  function decrease(key, pri) {
1481    var index = _keyIndices[key];
1482    if (pri > _arr[index].pri) {
1483      throw new Error("New priority is greater than current priority. " +
1484          "Key: " + key + " Old: " + _arr[index].pri + " New: " + pri);
1485    }
1486    _arr[index].pri = pri;
1487    _decrease(index);
1488  }
1489
1490  return {
1491    size: size,
1492    keys: keys,
1493    has: has,
1494    priority: priority,
1495    add: add,
1496    min: min,
1497    removeMin: removeMin,
1498    decrease: decrease
1499  };
1500}
1501dagre.dot = {};
1502
1503dagre.dot.toGraph = function(str) {
1504  var parseTree = dot_parser.parse(str);
1505  var g = dagre.graph();
1506  var undir = parseTree.type === "graph";
1507
1508  function createNode(id, attrs) {
1509    if (!(g.hasNode(id))) {
1510      g.addNode(id, { id: id, label: id });
1511    }
1512    if (attrs) {
1513      mergeAttributes(attrs, g.node(id));
1514    }
1515  }
1516
1517  var edgeCount = {};
1518  function createEdge(source, target, attrs) {
1519    var edgeKey = source + "-" + target;
1520    var count = edgeCount[edgeKey];
1521    if (!count) {
1522      count = edgeCount[edgeKey] = 0;
1523    }
1524    edgeCount[edgeKey]++;
1525
1526    var id = attrs.id || edgeKey + "-" + count;
1527    var edge = {};
1528    mergeAttributes(attrs, edge);
1529    mergeAttributes({ id: id }, edge);
1530    g.addEdge(id, source, target, edge);
1531  }
1532
1533  function handleStmt(stmt) {
1534    switch (stmt.type) {
1535      case "node":
1536        createNode(stmt.id, stmt.attrs);
1537        break;
1538      case "edge":
1539        var prev;
1540        stmt.elems.forEach(function(elem) {
1541          handleStmt(elem);
1542
1543          switch(elem.type) {
1544            case "node":
1545              var curr = elem.id;
1546
1547              if (prev) {
1548                createEdge(prev, curr, stmt.attrs);
1549                if (undir) {
1550                  createEdge(curr, prev, stmt.attrs);
1551                }
1552              }
1553              prev = curr;
1554              break;
1555            default:
1556              // We don't currently support subgraphs incident on an edge
1557              throw new Error("Unsupported type incident on edge: " + elem.type);
1558          }
1559        });
1560        break;
1561      case "attr":
1562        // Ignore for now
1563        break;
1564      default:
1565        throw new Error("Unsupported statement type: " + stmt.type);
1566    }
1567  }
1568
1569  if (parseTree.stmts) {
1570    parseTree.stmts.forEach(function(stmt) {
1571      handleStmt(stmt);
1572    });
1573  }
1574
1575  return g;
1576};
1577
1578dagre.dot.toObjects = function(str) {
1579  var g = dagre.dot.toGraph(str);
1580  var nodes = g.nodes().map(function(u) { return g.node(u); });
1581  var edges = g.edges().map(function(e) {
1582    var edge = g.edge(e);
1583    edge.source = g.node(g.source(e));
1584    edge.target = g.node(g.target(e));
1585    return edge;
1586  });
1587  return { nodes: nodes, edges: edges };
1588};
1589dot_parser = (function(){
1590  /*
1591   * Generated by PEG.js 0.7.0.
1592   *
1593   * http://pegjs.majda.cz/
1594   */
1595  
1596  function quote(s) {
1597    /*
1598     * ECMA-262, 5th ed., 7.8.4: All characters may appear literally in a
1599     * string literal except for the closing quote character, backslash,
1600     * carriage return, line separator, paragraph separator, and line feed.
1601     * Any character may appear in the form of an escape sequence.
1602     *
1603     * For portability, we also escape escape all control and non-ASCII
1604     * characters. Note that "\0" and "\v" escape sequences are not used
1605     * because JSHint does not like the first and IE the second.
1606     */
1607     return '"' + s
1608      .replace(/\\/g, '\\\\')  // backslash
1609      .replace(/"/g, '\\"')    // closing quote character
1610      .replace(/\x08/g, '\\b') // backspace
1611      .replace(/\t/g, '\\t')   // horizontal tab
1612      .replace(/\n/g, '\\n')   // line feed
1613      .replace(/\f/g, '\\f')   // form feed
1614      .replace(/\r/g, '\\r')   // carriage return
1615      .replace(/[\x00-\x07\x0B\x0E-\x1F\x80-\uFFFF]/g, escape)
1616      + '"';
1617  }
1618  
1619  var result = {
1620    /*
1621     * Parses the input with a generated parser. If the parsing is successfull,
1622     * returns a value explicitly or implicitly specified by the grammar from
1623     * which the parser was generated (see |PEG.buildParser|). If the parsing is
1624     * unsuccessful, throws |PEG.parser.SyntaxError| describing the error.
1625     */
1626    parse: function(input, startRule) {
1627      var parseFunctions = {
1628        "start": parse_start,
1629        "stmtList": parse_stmtList,
1630        "stmt": parse_stmt,
1631        "attrStmt": parse_attrStmt,
1632        "inlineAttrStmt": parse_inlineAttrStmt,
1633        "nodeStmt": parse_nodeStmt,
1634        "edgeStmt": parse_edgeStmt,
1635        "subgraphStmt": parse_subgraphStmt,
1636        "attrList": parse_attrList,
1637        "attrListBlock": parse_attrListBlock,
1638        "aList": parse_aList,
1639        "edgeRHS": parse_edgeRHS,
1640        "idDef": parse_idDef,
1641        "nodeIdOrSubgraph": parse_nodeIdOrSubgraph,
1642        "nodeId": parse_nodeId,
1643        "port": parse_port,
1644        "compassPt": parse_compassPt,
1645        "id": parse_id,
1646        "node": parse_node,
1647        "edge": parse_edge,
1648        "graph": parse_graph,
1649        "digraph": parse_digraph,
1650        "subgraph": parse_subgraph,
1651        "strict": parse_strict,
1652        "graphType": parse_graphType,
1653        "whitespace": parse_whitespace,
1654        "comment": parse_comment,
1655        "_": parse__
1656      };
1657      
1658      if (startRule !== undefined) {
1659        if (parseFunctions[startRule] === undefined) {
1660          throw new Error("Invalid rule name: " + quote(startRule) + ".");
1661        }
1662      } else {
1663        startRule = "start";
1664      }
1665      
1666      var pos = 0;
1667      var reportFailures = 0;
1668      var rightmostFailuresPos = 0;
1669      var rightmostFailuresExpected = [];
1670      
1671      function padLeft(input, padding, length) {
1672        var result = input;
1673        
1674        var padLength = length - input.length;
1675        for (var i = 0; i < padLength; i++) {
1676          result = padding + result;
1677        }
1678        
1679        return result;
1680      }
1681      
1682      function escape(ch) {
1683        var charCode = ch.charCodeAt(0);
1684        var escapeChar;
1685        var length;
1686        
1687        if (charCode <= 0xFF) {
1688          escapeChar = 'x';
1689          length = 2;
1690        } else {
1691          escapeChar = 'u';
1692          length = 4;
1693        }
1694        
1695        return '\\' + escapeChar + padLeft(charCode.toString(16).toUpperCase(), '0', length);
1696      }
1697      
1698      function matchFailed(failure) {
1699        if (pos < rightmostFailuresPos) {
1700          return;
1701        }
1702        
1703        if (pos > rightmostFailuresPos) {
1704          rightmostFailuresPos = pos;
1705          rightmostFailuresExpected = [];
1706        }
1707        
1708        rightmostFailuresExpected.push(failure);
1709      }
1710      
1711      function parse_start() {
1712        var result0, result1, result2, result3, result4, result5, result6, result7, result8, result9, result10, result11, result12;
1713        var pos0, pos1, pos2;
1714        
1715        pos0 = pos;
1716        pos1 = pos;
1717        result0 = [];
1718        result1 = parse__();
1719        while (result1 !== null) {
1720          result0.push(result1);
1721          result1 = parse__();
1722        }
1723        if (result0 !== null) {
1724          pos2 = pos;
1725          result1 = parse_strict();
1726          if (result1 !== null) {
1727            result2 = parse__();
1728            if (result2 !== null) {
1729              result1 = [result1, result2];
1730            } else {
1731              result1 = null;
1732              pos = pos2;
1733            }
1734          } else {
1735            result1 = null;
1736            pos = pos2;
1737          }
1738          result1 = result1 !== null ? result1 : "";
1739          if (result1 !== null) {
1740            result2 = parse_graphType();
1741            if (result2 !== null) {
1742              result3 = [];
1743              result4 = parse__();
1744              while (result4 !== null) {
1745                result3.push(result4);
1746                result4 = parse__();
1747              }
1748              if (result3 !== null) {
1749                result4 = parse_id();
1750                result4 = result4 !== null ? result4 : "";
1751                if (result4 !== null) {
1752                  result5 = [];
1753                  result6 = parse__();
1754                  while (result6 !== null) {
1755                    result5.push(result6);
1756                    result6 = parse__();
1757                  }
1758                  if (result5 !== null) {
1759                    if (input.charCodeAt(pos) === 123) {
1760                      result6 = "{";
1761                      pos++;
1762                    } else {
1763                      result6 = null;
1764                      if (reportFailures === 0) {
1765                        matchFailed("\"{\"");
1766                      }
1767                    }
1768                    if (result6 !== null) {
1769                      result7 = [];
1770                      result8 = parse__();
1771                      while (result8 !== null) {
1772                        result7.push(result8);
1773                        result8 = parse__();
1774                      }
1775                      if (result7 !== null) {
1776                        result8 = parse_stmtList();
1777                        result8 = result8 !== null ? result8 : "";
1778                        if (result8 !== null) {
1779                          result9 = [];
1780                          result10 = parse__();
1781                          while (result10 !== null) {
1782                            result9.push(result10);
1783                            result10 = parse__();
1784                          }
1785                          if (result9 !== null) {
1786                            if (input.charCodeAt(pos) === 125) {
1787                              result10 = "}";
1788                              pos++;
1789                            } else {
1790                              result10 = null;
1791                              if (reportFailures === 0) {
1792                                matchFailed("\"}\"");
1793                              }
1794                            }
1795                            if (result10 !== null) {
1796                              result11 = [];
1797                              result12 = parse__();
1798                              while (result12 !== null) {
1799                                result11.push(result12);
1800                                result12 = parse__();
1801                              }
1802                              if (result11 !== null) {
1803                                result0 = [result0, result1, result2, result3, result4, result5, result6, result7, result8, result9, result10, result11];
1804                              } else {
1805                                result0 = null;
1806                                pos = pos1;
1807                              }
1808                            } else {
1809                              result0 = null;
1810                              pos = pos1;
1811                            }
1812                          } else {
1813                            result0 = null;
1814                            pos = pos1;
1815                          }
1816                        } else {
1817                          result0 = null;
1818                          pos = pos1;
1819                        }
1820                      } else {
1821                        result0 = null;
1822                        pos = pos1;
1823                     

Large files files are truncated, but you can click here to view the full file